Merge branch 'master' into bug4482

Change-Id: I0fc27971051b7c75ca3191b91b71b0c197076f17
This commit is contained in:
Axel Uhl committed 2018-03-19 14:53:39 +01:00
commit 193466c741
24 files changed
+476 -252

No files matched your search

+26 -15
View File
@@ -81,6 +81,11 @@ fi
init_resources
if $force; then
error "--force option is currently not working."
safeExit
fi
if $instance_scenario; then
instance_start
safeExit
@@ -96,6 +101,11 @@ if $master_instance_scenario; then
safeExit
fi
if $replica_instance_scenario; then
replica_instance_start
safeExit
fi
if $associate_alb_scenario; then
associate_alb_start
safeExit
@@ -123,43 +133,40 @@ usage() {
-p, --public-dns-name Dns name of instance (e.g. \"ec2-35-176...amazonaws.com\")
-z, --super-instance Dns name of superior instance (e.g. base instance for sub instances)
-m, --event-name Name of event
-x, --mongodb-host Ip adress or dns of mongodb host
-y --mongodb-port Port of mongodb
-b, --build Build version to use (leave empty for latest)
-w, --description Description of sub instance
-c, --contact-person Contact person
-e, --contact-email Email of contact person
-f, --force Skip user input and use default variables
-d, --debug Debug mode
${bold}Scenarios:${reset}
--instance Create instance
--shared-instance Create sub instance
--master-instance Create master instance
--associate-alb Associate instance with existing application load balancer whos
listener is defined in variables_aws.sh. Automatically
create necessary target group and host name rule.
--replica-instance Create replica instance
--associate-alb Associate instance with existing application load balancer.
${bold}Other:${reset}
--version Output version information and exit
--version Output version information and exit
${bold}Examples:${reset}
Create instance:
> ./aws-setup.sh --instance
Associate application load balancer:
> ./aws-setup.sh --instance --associate-alb
Create shared instance:
> ./aws-setup.sh --shared-instance
Associate instance with application load balancer:
> ./aws-setup.sh --instance --associate-alb
Create instance and use default values:
> ./aws-setup.sh --instance --force
Create instance and use default values except instance name
and instance short name. Also activate debug mode.
> ./aws-setup.sh --instance --instance-name Test --instance-short-name t --force -d
> ./aws-setup.sh --associate-alb
Create master instance:
> ./aws-setup.sh --master-instance
Create replica instance:
> ./aws-setup.sh --replica-instance
"
}
@@ -208,6 +215,7 @@ associate_alb_scenario=false
instance_scenario=false
shared_instance_scenario=false
master_instance_scenario=false
replica_instance_scenario=false
# Read the options and set variables
while [[ $1 = -?* ]]; do
@@ -227,6 +235,8 @@ while [[ $1 = -?* ]]; do
-p|--public-dns-name) shift; public_dns_name_param=${1} ;;
-b|--super-instance) shift; super_instance_param=${1} ;;
-m|--event-name) shift; event_name_param=${1} ;;
-x|--mongodb-host) shift; mongodb_host_param=${1} ;;
-y|--mongodb-port) shift; mongodb_name_param=${1} ;;
-z|--build) shift; build_version_param=${1} ;;
-w|--description) shift; description_param=${1} ;;
-c|--contact-person) shift; contact_person_param=${1} ;;
@@ -236,6 +246,7 @@ while [[ $1 = -?* ]]; do
--instance) instance_scenario=true ;;
--shared-instance) shared_instance_scenario=true ;;
--master-instance) master_instance_scenario=true ;;
--replica-instance) replica_instance_scenario=true ;;
--associate-alb) associate_alb_scenario=true ;;
--endopts) shift; break ;;
*) die "invalid option: '$1'." ;;
@@ -1,5 +1,9 @@
#!/bin/bash
#
# -----------------------------------------------------------
# Scrpt for reading and writing variables to a file.
# -----------------------------------------------------------
# https://github.com/brbsix/bash-config
# Read and write config files from Bash
@@ -1,5 +1,11 @@
#!/usr/bin/env bash
# -----------------------------------------------------------
# Functions that are relevant for the configuration of the sap instance.
# -----------------------------------------------------------
# -----------------------------------------------------------
# Get latest release build from releases.sapsailing.com
# @return latest build
@@ -38,11 +44,11 @@ function get_access_token(){
# -----------------------------------------------------------
# Creates a new event with event name = instance name, no regatta and venuename="Default"
# @param $1 access token of privileged user
# @param $1 access token
# @param $2 dns name of instance
# @param $3 port
# @param $4 event name
# @return event_id of created event
# @return event id of event
# -----------------------------------------------------------
function create_event(){
local_echo -n "Creating event with name $4..."
@@ -52,7 +58,7 @@ function create_event(){
# -----------------------------------------------------------
# Changes password of user
# @param $1 access token of privileged user
# @param $1 access token
# @param $2 dns name of instance
# @param $3 port
# @param $4 admin username
@@ -65,7 +71,7 @@ function change_admin_password(){
# -----------------------------------------------------------
# Creates new user
# @param $1 access token of privileged user
# @param $1 access token
# @param $2 dns name of instance
# @param $3 port
# @param $4 user username
@@ -77,7 +83,7 @@ function create_new_user(){
}
# -----------------------------------------------------------
# Creates event, changes admin password, creates user
# Creates event, changes admin password, creates user if parameters are not empty.
# @param $1 public dns name
# @param $2 port of application instance
# @param $3 event name
@@ -105,11 +111,11 @@ function configure_application(){
user=$(create_new_user $access_token $1 $2 $5 $6)
fi
echo ${$event_id:-""}
echo ${event_id:-""}
}
# -----------------------------------------------------------
# Patch 001-events.conf with ssl macros
# Patch 001-events.conf with Even-SSL macro if event id is not empty. Else use Home-SSL macro.
# @param $1 domain
# @param $2 event id
# @param $3 ssh user
@@ -129,6 +135,40 @@ function append_macro_to_001_events_conf(){
ssh_wrapper $3@$4 echo "$patched_content >> $events_conf"
}
# -----------------------------------------------------------
# Append specified environment to env.sh.
# @param $1 environment
# @param $2 ssh user
# @param $3 dns name of instance
# @param $4 path to env.sh file
# -----------------------------------------------------------
function append_environment_to_env_sh(){
local env_file=${4:-'/home/sailing/servers/server/env.sh'}
local_echo "Appending environment '$1' to env.sh..."
env_content=$(wget -qO- http://releases.sapsailing.com/environments/$1)
exit_on_fail ssh_wrapper $2@$3 "echo -e \"# START Environment: $1 \" >> $env_file"
exit_on_fail ssh_wrapper $2@$3 "export ADDITIONAL_JAVA_ARGS='\$ADDITIONAL_JAVA_ARGS'; export MEMORY='$MEMORY'; echo \"$env_content\" >> $env_file"
exit_on_fail ssh_wrapper $2@$3 "echo -e \"# END Environment: $1 \" >> $env_file"
}
# -----------------------------------------------------------
# Append string to env.sh
# @param $1 ssh user
# @param $2 dns name of instance
# @param $3 string value
# @param $4 path to env.sh file
# -----------------------------------------------------------
function append_to_env_sh(){
local env_file=${4:-'/home/sailing/servers/server/env.sh'}
exit_on_fail ssh_wrapper $1@$2 "echo -e \"$3\" >> $env_file"
}
# -----------------------------------------------------------
# Reloads httpd service after executing apachectl configtest.
# @param $1 ssh user
# @param $2 dns name of instance
# -----------------------------------------------------------
function reload_httpd(){
local_echo "Reloading httpd..."
ssh_wrapper $1@$2 "apachectl configtest >/dev/null 2>&1"
@@ -1,7 +1,11 @@
#!/usr/bin/env bash
# -----------------------------------------------------------
# Query for public dns name of instance
# Functions that are relevant for the configuration of the ec2 instance.
# -----------------------------------------------------------
# -----------------------------------------------------------
# Get public dns name of instance
# @param $1 instance id
# @return public dns name
# -----------------------------------------------------------
@@ -12,14 +16,30 @@ function get_public_dns_name(){
# -----------------------------------------------------------
# Get resources that should be automatically discovered
# @return array of resource ids
# Get resources all resources from aws
# @return json array of resourceARNs
# -----------------------------------------------------------
function get_resources(){
aws resourcegroupstaggingapi get-resources | jq -c ".ResourceTagMappingList[] | select(.ResourceARN)" -r | sanitize
function get_array_with_resource_of_type(){
disable_aws_success_output
# RESOURCE_ARRAY=($(aws_wrapper resourcegroupstaggingapi get-resources --resource-type-filters elasticloadbalancing:loadbalancer ec2:instance ec2:image ec2:security-group acm:certificate | jq -c ".ResourceTagMappingList[] | select(.ResourceARN)" -r | sanitize))
aws_wrapper resourcegroupstaggingapi get-resources --resource-type-filters $1 | jq -c ".ResourceTagMappingList[] | select(.ResourceARN)" -r | sanitize
enable_aws_success_output
}
# -----------------------------------------------------------
# Get launch templates as json
# param $1 public dns name
# @return json array of launch templates
# -----------------------------------------------------------
function get_array_with_launch_templates(){
disable_aws_success_output
aws_wrapper ec2 describe-launch-templates | jq -c ".LaunchTemplates[]" -r | sanitize
enable_aws_success_output
}
# -----------------------------------------------------------
# Get tag value of specified key of instance
# @param1 instance id
# @param2 tag key
# @return tag value
@@ -29,7 +49,7 @@ function get_tag_value_for_key(){
}
# -----------------------------------------------------------
# Query for default vpc id
# Get default vpc id
# @return default vpc id
# -----------------------------------------------------------
function get_default_vpc_id(){
@@ -47,19 +67,14 @@ function get_instance_id(){
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 id part of arn
# -----------------------------------------------------------
function get_resource_id(){
cut -d/ -f2 <<< $1
}
function get_public_ip(){
local_echo "Querying for the public ip of $1..."
local ip_address=$(aws_wrapper ec2 describe-instances --query "Reservations[*].Instances[?PublicIpAddress=='$1'].InstanceId" --output text)
exit_on_fail validate_ipaddress $ip_address
echo "${1##*/}"
}
# -----------------------------------------------------------
@@ -107,6 +122,11 @@ function wait_for_ssh_connection(){
do_until_true ssh_prewrapper -q $1@$2 true 1>&2
}
# -----------------------------------------------------------
# Runs instance with specified user data. All other variables user inside function have to be initialized already.
# @param $1 user data
# @return instance id
# -----------------------------------------------------------
function run_instance(){
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" \
@@ -114,6 +134,16 @@ function run_instance(){
exit_on_fail validate_instance_id $instance_id
}
# -----------------------------------------------------------
# Runs instance from specified launch template.
# @param $1 launch template id
# @return instance id
# -----------------------------------------------------------
function run_instance_from_launch_template(){
local instance_id=$(aws_wrapper ec2 run-instances --launch-template LaunchTemplateId="$1" | 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
@@ -131,12 +161,16 @@ 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"
instance_id=$(run_instance "$1")
wait_instance_exists $instance_id
print_instance_description $instance_id
null=$(print_instance_description $instance_id)
echo $instance_id
}
# -----------------------------------------------------------
# Prints instance description to screen.
# @param $1 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
--output table
}
@@ -1,5 +1,9 @@
#!/usr/bin/env bash
# -----------------------------------------------------------
# Functions that are relevant for the configuration of load balancers.
# -----------------------------------------------------------
# -----------------------------------------------------------
# Create target group for load balancer
# @param $1 target group name
@@ -1,10 +1,8 @@
#!/usr/bin/env bash
CHOOSE_FROM_INSTANCES=":instance"
CHOOSE_FROM_SECURITY_GROUPS=":security-group"
CHOOSE_FROM_IMAGES=":image"
CHOOSE_FROM_CERTIFICATES=":certificate"
CHOOSE_FROM_LOAD_BALANCERS=":loadbalancer"
# -----------------------------------------------------------
# Functions that are relevant for the treatment of user input and user configuration.
# -----------------------------------------------------------
# -----------------------------------------------------------
# Prompt user for input and save value to variable
@@ -12,53 +10,37 @@ CHOOSE_FROM_LOAD_BALANCERS=":loadbalancer"
# @param $2 default value
# @param $3 variable that is receiving the value
# @param $4 hide text
# @param $5 filter
# -----------------------------------------------------------
function require_input(){
if [ ! -z "$5" ]; then
declare -a option_keys=()
declare -a option_values=()
number_of_tagged_resources=0
default_tagged_resource=""
o=0
for key in "${!RESOURCE_MAP[@]}"; do
if [[ $key = *"$5"* ]]; then
# if resource is tagged
option_keys[o]=$key
local tagged=$(echo ${RESOURCE_MAP[$key]} | cut -d, -f2)
local name=$(echo ${RESOURCE_MAP[$key]} | cut -d, -f1)
if [ $tagged == "true" ]; then
option_values[o]="$(tput setaf 3)$name ($key)$(tput sgr0)"
default_tagged_resource=$key
((number_of_tagged_resources++))
else
option_values[o]="$name ($key)"
fi
fi
((o++))
done
if [ $number_of_tagged_resources -eq 1 ] && [ "$force" == "true" ] || [ ${#option_keys[@]} -eq 1 ]; then
read -r $3 <<< $default_tagged_resource
return 0
elif [ $number_of_tagged_resources -gt 0 ]; then
if [ ${#RESOURCE_MAP[@]} -eq 0 ]; then
if [[ ( $NUMBER_OF_TAGGED_RESOURCES -eq 1 || ${#OPTION_KEYS[@]} -eq 1 ) && "$force" == "true" ]]; then
local_echo "$1"
if [ ! -z "$DEFAULT_TAGGED_RESOURCE" ]; then
read -r $3 <<< $DEFAULT_TAGGED_RESOURCE
else
read -r $3 <<< ${OPTION_KEYS[0]}
fi
elif [ ${#OPTION_KEYS[@]} -gt 0 ]; then
local_echo "$1"
selectedValue=""
select option in ${option_values[@]}; do
select option in ${OPTION_VALUES[@]}; do
selectedValue=$option
break
break
done
# workaround cant access option_keys from within select
read -r $3 <<< $(echo $selectedValue | sed 's/.*(\(.*\)).*/\1/')
return 0
else
read_input_normal "$1" "$2" $3 $4
return 0
fi
else
read_input_normal "$1" "$2" $3 $4
fi
unset OPTION_KEYS
unset OPTION_VALUES
unset RESOURCE_MAP
}
function read_input_normal(){
@@ -92,7 +74,7 @@ function require_variable(){
# if required variable value is empty
if [ -z "${!2}" ]; then
# if force is enabled
if [ "$force" = true ] && [ -z "$7" ]; then
if [ "$force" = true ] && [ ${#RESOURCE_MAP[@]} -eq 0 ]; then
# if variable is optional
if [ "$5" == "true" ]; then
# variable should be empty
@@ -107,12 +89,12 @@ function require_variable(){
# if force not enabled or filter is set
# if variable value is optional, then value of "" is possible
if [ "$5" == "true" ]; then
require_input "$4" "$3" $2 $6 $7
require_input "$4" "$3" $2 $6
else
# if variable value is not optional, repeat until value is set for variable
while [[ -z "${!2}" ]]
do
require_input "$4" "$3" $2 $6 $7
require_input "$4" "$3" $2 $6
done
fi
fi
@@ -123,6 +105,61 @@ function require_variable(){
fi
}
function fill_resource_map_with_resources_of_type(){
declare -a RESOURCE_ARRAY
if [ "$1" == "ec2:launch-template" ]; then
RESOURCE_ARRAY=($(get_array_with_launch_templates))
else
RESOURCE_ARRAY=($(get_array_with_resource_of_type $1))
fi
NUMBER_OF_TAGGED_RESOURCES=0
DEFAULT_TAGGED_RESOURCE=""
local o=0
declare -A RESOURCE_MAP
for resource in "${RESOURCE_ARRAY[@]}"; do
local id=""
if [ "$1" == "ec2:launch-template" ]; then
id=$(echo "$resource" | jq -c ".LaunchTemplateId" -r | sanitize)
tmp_name=$(echo "$resource" | jq -c ".LaunchTemplateName" -r | sanitize)
else
id=$(echo $resource | jq -c ".ResourceARN" -r | sanitize)
tmp_name=$(echo $resource | jq -c ".Tags[] | select(.Key==\"Name\") | .Value" -r | sanitize)
fi
local name=${tmp_name:-"Unnamed"}
local tagged=$(echo $resource | jq -c ".Tags[] | select(.Key==\"AutoDiscover\") | .Value" -r | sanitize)
local display_name="$name ($id)"
OPTION_KEYS[$o]=$id
if [ ! -z "$tagged" ] && [ "$tagged" == "true" ] || [ "$tagged" == "True" ]; then
DEFAULT_TAGGED_RESOURCE=$id
option_value=$(highlight $display_name)
((NUMBER_OF_TAGGED_RESOURCES++))
else
tagged="false"
option_value=$display_name
fi
OPTION_VALUES[$o]=$option_value
((o++))
RESOURCE_MAP[$id]="$name,$tagged"
done
}
function highlight(){
local highlight_start=$(tput setaf 3)
local reset=$(tput sgr0)
echo $highlight_start$1$reset
}
# -----------------------------------------------------------
# Workaround: use stderr stream for console output
# @param $1 message
@@ -131,45 +168,7 @@ function local_echo(){
echo "$@" >&2
}
function update_resources(){
local resources_file=./lib/resources-$region.sh
> $resources_file
OLD_RESOURCE_JSON=$RESOURCE_JSON
typeset -p OLD_RESOURCE_JSON >> $resources_file
RESOURCES_ARRAY=($(get_resources))
declare -A RESOURCE_MAP
for resource in ${RESOURCES_ARRAY[@]}; do
local arn=$(echo $resource | jq -c ".ResourceARN" -r | sanitize)
local name=$(echo $resource | jq -c ".Tags[] | select(.Key==\"Name\") | .Value" -r | sanitize)
local tagged=$(echo $resource | jq -c ".Tags[] | select(.Key==\"AutoDiscover\") | .Value" -r | sanitize)
if [ ! -z "$tagged" ] && [ "$tagged" == "true" ] || [ "$tagged" == "True" ]; then
tagged="true"
else
tagged="false"
fi
RESOURCE_MAP[$arn]="${name:-"Unnamed"},$tagged"
done
typeset -p RESOURCE_MAP >> $resources_file
}
function init_resources(){
local_echo "Checking if aws resources with tag key 'AutoDiscover' and value 'true' were added or removed in region $region..."
RESOURCE_JSON=$(get_resources)
if [ "$RESOURCE_JSON" != "$OLD_RESOURCE_JSON" ]; then
local_echo "Updating tagged aws resources..."
update_resources
else
local_echo "Stored aws resources are up to date."
fi
if ! is_exists ~/.aws-automation/config-$region; then
local_echo "Creating ~/.aws-automation/config-$region..."
create_region_configuration
@@ -1,6 +1,10 @@
#!/usr/bin/env bash
declare -g DISPLAY_SUCCESS_FOR_THIS_COMMAND="true"
# -----------------------------------------------------------
# Functions that encapsulate error checking or looping logic whilst calling other functions.
# -----------------------------------------------------------
DISPLAY_SUCCESS_FOR_THIS_COMMAND="true"
HTTP_RETRY_INTERVAL=5
TIMEOUT=300
@@ -1,9 +1,19 @@
#!/usr/bin/env bash
# -----------------------------------------------------------
# Define variable properties and user messages here.
# -----------------------------------------------------------
# -----------------------------------------------------------
# Messages for user input.
# -----------------------------------------------------------
image_ask_message="Please select an image to use: "
instance_ask_message="Please enter an instance to use: "
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 dns name: "
event_name_ask_message="Please enter an event name (leave blank to skip event creation): "
instance_security_group_ask_message="Please select the security group for the instance: "
load_balancer_ask_message="Please select or 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 user for the instance (e.g. leon-keypair). "
@@ -11,8 +21,8 @@ instance_name_ask_message="Please enter a name for the instance: (e.g \"WC Santa
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: "
new_admin_password_ask_message="Please enter a new password for the admin user (leave blank to skip password change): "
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: "
mongodb_host_ask_message="Please enter the ip adress/dns of the mongo db: "
mongodb_port_ask_message="Please enter the port of the mongo db: "
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): "
ssh_user_ask_message="Please enter the ssh user to connect to the instance: "
@@ -21,88 +31,118 @@ description_message="Please enter a description for the server (leave blank to s
contact_person_message="Please enter the name of a contact person (leave blank to skip): "
contact_email_message="Please enter the email of the contact person (leave blank to skip): "
build_version_message="Please enter a build version to use (releases.sapsailing.com): "
launch_tempate_ask_message="Please select the launch template for the replica: "
IS_OPTIONAL="true"
IS_NOT_OPTIONAL="false"
SHOW_INPUT="false"
HIDE_INPUT="true"
NO_DEFAULT_VALUE=""
NOT_A_PARAMETER=""
function require_image_id(){
require_variable "" image_id "" "$image_id_ask_message" "false" "false" $CHOOSE_FROM_IMAGES
# -----------------------------------------------------------
# Functions that are responsible for: Connection of variable to respective use rmessage. Setting if variable is required or can be left empty.
# Set the variables default value. Choose if user input will be shown or hidden (e.g. passwords). Choose whether the variable is a aws resources
# and can be selected. If yes then append a regex as last parameter (e.g. ValidImageARNRegex). Then the selection will be limited to resources
# of the associative array RESOURCE_MAP (functions_io.sh) that have a key matching the regex.
# -----------------------------------------------------------
function require_launch_template(){
fill_resource_map_with_resources_of_type "ec2:launch-template"
require_variable "$launch_template_param" launch_template "$NO_DEFAULT_VALUE" "$launch_tempate_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_image(){
fill_resource_map_with_resources_of_type "ec2:image"
require_variable "$image_param" image "$NO_DEFAULT_VALUE" "$image_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_event_name(){
require_variable "$event_name_param" event_name "" "$event_name_ask_message" "true" "false"
require_variable "$event_name_param" event_name "$NO_DEFAULT_VALUE" "$event_name_ask_message" "$IS_OPTIONAL" "$SHOW_INPUT"
}
function require_instance_security_group_id(){
require_variable "" instance_security_group_id "" "$instance_security_group_id_ask_message" "false" "false" $CHOOSE_FROM_SECURITY_GROUPS
function require_instance_security_group(){
fill_resource_map_with_resources_of_type "ec2:security-group"
require_variable "$security_group_param" instance_security_group "$NO_DEFAULT_VALUE" "$instance_security_group_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_load_balancer(){
require_variable "" load_balancer "" "$load_balancer_ask_message" "false" "false" $CHOOSE_FROM_LOAD_BALANCERS
fill_resource_map_with_resources_of_type "elasticloadbalancing:loadbalancer"
require_variable "$load_balancer_param" load_balancer "$NO_DEFAULT_VALUE" "$load_balancer_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT" $ValidLoadBalancerARNRegex
}
function require_instance(){
require_variable "" instance "" "$instance_ask_message" "false" "false" $CHOOSE_FROM_INSTANCES
fill_resource_map_with_resources_of_type "ec2:instance"
require_variable "$instance_param" instance "$NO_DEFAULT_VALUE" "$instance_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_region(){
require_variable "$region_param" region "$default_region" "$region_ask_message" "false" "false"
require_variable "$region_param" region "$default_region" "$region_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_instance_type(){
require_variable "$instance_type_param" instance_type "$default_instance_type" "$instance_type_ask_message" "false" "false"
require_variable "$instance_type_param" instance_type "$default_instance_type" "$instance_type_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_instance_name(){
require_variable "$instance_name_param" instance_name "$script_start_time" "$instance_name_ask_message" "false" "false"
require_variable "$instance_name_param" instance_name "$script_start_time" "$instance_name_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_instance_short_name(){
require_variable "$instance_short_name_param" instance_short_name "$timestamp" "$instance_short_name_ask_message" "false" "false"
require_variable "$instance_short_name_param" instance_short_name "$timestamp" "$instance_short_name_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_key_name(){
require_variable "$key_name_param" key_name "$default_key_name" "$key_name_ask_message" "false" "false"
require_variable "$key_name_param" key_name "$default_key_name" "$key_name_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_key_file(){
require_variable "$key_file_param" key_file "$default_key_file" "$key_file_ask_message" "true" "false"
require_variable "$key_file_param" key_file "$default_key_file" "$key_file_ask_message" "$IS_OPTIONAL" "$SHOW_INPUT"
}
function require_new_admin_password(){
require_variable "$new_admin_password_param" new_admin_password "$default_new_admin_password" "$new_admin_password_ask_message" "true" "true"
require_variable "$new_admin_password_param" new_admin_password "$default_new_admin_password" "$new_admin_password_ask_message" "$IS_OPTIONAL" "$HIDE_INPUT"
}
function require_user_username(){
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
require_variable "$user_username_param" user_username "$default_user_username" "$user_username_ask_message" "$IS_OPTIONAL" "$SHOW_INPUT"
}
function require_mongodb_port(){
require_variable "$mongodb_port_param" mongodb_port "$default_mongodb_port" "$mongodb_port_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_mongodb_host(){
require_variable "$mongodb_host_param" mongodb_host "$default_mongodb_host" "$mongodb_host_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_user_password(){
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
require_variable "$user_password_param" user_password "$default_user_password" "$user_password_ask_message" "$IS_OPTIONAL" "$HIDE_INPUT"
}
function require_ssh_user(){
require_variable "$ssh_user_param" ssh_user "$default_ssh_user" "$ssh_user_ask_message" "false" "false"
require_variable "$ssh_user_param" ssh_user "root" "$ssh_user_ask_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_super_instance(){
require_variable "$super_instance_param" super_instance "$default_super_instance" "$super_instance_message" "false" "false" $CHOOSE_FROM_INSTANCES
fill_resource_map_with_resources_of_type "ec2:instance"
require_variable "$super_instance_param" super_instance "$NO_DEFAULT_VALUE" "$super_instance_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
function require_description(){
require_variable "$description_param" description "" "$description_message" "true" "false"
require_variable "$description_param" description "" "$description_message" "$IS_OPTIONAL" "$SHOW_INPUT"
}
function require_contact_person(){
require_variable "$contact_person_param" contact_person "$default_contact_person" "$contact_person_message" "true" "false"
require_variable "$contact_person_param" contact_person "$default_contact_person" "$contact_person_message" "$IS_OPTIONAL" "$SHOW_INPUT"
}
function require_contact_email(){
require_variable "$contact_email_param" contact_email "$default_contact_email" "$contact_email_message" "true" "false"
require_variable "$contact_email_param" contact_email "$default_contact_email" "$contact_email_message" "$IS_OPTIONAL" "$SHOW_INPUT"
}
function require_build_version(){
require_variable "$build_version_param" build_version "$latest_release" "$build_version_message" "false" "false"
require_variable "$build_version_param" build_version "$latest_release" "$build_version_message" "$IS_NOT_OPTIONAL" "$SHOW_INPUT"
}
@@ -1,11 +0,0 @@
declare -- OLD_RESOURCES="{ \"ResourceTagMappingList\": [ { \"ResourceARN\": \"arn:aws:acm:eu-west-1:017363970217:certificate/67a1515a-81be-472d-9459-85746d030564\", \"Tags\": [ { \"Value\": \"true\", \"Key\": \"AutoDiscover\" }, { \"Value\": \"sapsailing.com-2017\", \"Key\": \"Name\" } ] }, { \"ResourceARN\": \"arn:aws:ec2:eu-west-1:017363970217:instance/i-07344e3c868f46f85\", \"Tags\": [ { \"Value\": \"true\", \"Key\": \"AutoDiscover\" }, { \"Value\": \"SL Multi-Instance Sailling Server\", \"Key\": \"Name\" }, { \"Value\": \"Sailing\", \"Key\": \"function\" }, { \"Value\": \"sailing\", \"Key\": \"ssh_user\" } ] }, { \"ResourceARN\": \"arn:aws:ec2:eu-west-1:017363970217:image/ami-8ce485f5\", \"Tags\": [ { \"Value\": \"true\", \"Key\": \"AutoDiscover\" } ] }, { \"ResourceARN\": \"arn:aws:ec2:eu-west-1:017363970217:security-group/sg-eaf31e85\", \"Tags\": [ { \"Value\": \"true\", \"Key\": \"AutoDiscover\" } ] }, { \"ResourceARN\": \"arn:aws:elasticloadbalancing:eu-west-1:017363970217:loadbalancer/app/Sailing-eu-west-1/32b89dbfe7f75097\", \"Tags\": [ { \"Value\": \"true\", \"Key\": \"AutoDiscover\" } ] } ] }"
declare -a TAGGED_SECURITY_GROUP_NAMES=([0]="[Unnamed]")
declare -a TAGGED_SECURITY_GROUP_ARNS=([0]="arn:aws:ec2:eu-west-1:017363970217:security-group/sg-eaf31e85")
declare -a TAGGED_IMAGE_NAMES=([0]="[Unnamed]")
declare -a TAGGED_IMAGE_ARNS=([0]="arn:aws:ec2:eu-west-1:017363970217:image/ami-8ce485f5")
declare -a TAGGED_INSTANCE_NAMES=([0]="SL" [1]="Multi-Instance" [2]="Sailling" [3]="Server")
declare -a TAGGED_INSTANCE_ARNS=([0]="arn:aws:ec2:eu-west-1:017363970217:instance/i-07344e3c868f46f85")
declare -a TAGGED_CERTIFICATE_NAMES=([0]="sapsailing.com-2017")
declare -a TAGGED_CERTIFICATE_ARNS=([0]="arn:aws:acm:eu-west-1:017363970217:certificate/67a1515a-81be-472d-9459-85746d030564")
declare -a TAGGED_LOADBALANCER_NAMES=([0]="[Unnamed]")
declare -a TAGGED_LOADBALANCER_ARNS=([0]="arn:aws:elasticloadbalancing:eu-west-1:017363970217:loadbalancer/app/Sailing-eu-west-1/32b89dbfe7f75097")
@@ -1,20 +0,0 @@
declare -- OLD_RESOURCE_JSON="{\"ResourceARN\":\"arn:aws:acm:eu-west-2:017363970217:certificate/d2ae17b0-75ed-4b56-ac12-a80f9e5c493d\",\"Tags\":[{\"Value\":\"true\",\"Key\":\"AutoDiscover\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:image/ami-39f3e25d\",\"Tags\":[{\"Value\":\"true\",\"Key\":\"AutoDiscover\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-02abdf10071ce9ce6\",\"Tags\":[{\"Value\":\"2018-02-14 06:57:30\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-04eeb1346463540c5\",\"Tags\":[{\"Value\":\"123\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-05f2fda5ce72c2b36\",\"Tags\":[{\"Value\":\"2018-02-14 07:22:33\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-068b644ad5fbe6e5f\",\"Tags\":[{\"Value\":\"12\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-08803ecb16560b18a\",\"Tags\":[{\"Value\":\"2018-02-14 07:15:26\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-08e4a99e69f6d8dce\",\"Tags\":[{\"Value\":\"2018-02-14 07:07:20\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-09330d7744ebef9b3\",\"Tags\":[{\"Value\":\"123\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-096a32ca8c28bedbb\",\"Tags\":[{\"Value\":\"MongoDB\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-0a65849491dfc8562\",\"Tags\":[{\"Value\":\"yxc\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-0c57f03afc68de24c\",\"Tags\":[{\"Value\":\"true\",\"Key\":\"AutoDiscover\"},{\"Value\":\"Multi Instance\",\"Key\":\"Name\"},{\"Value\":\"root\",\"Key\":\"ssh_user\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-0f2e26f9a7860e680\",\"Tags\":[{\"Value\":\"123\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:instance/i-0f5308bf09c42d7f9\",\"Tags\":[{\"Value\":\"123\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:security-group/sg-74c92d1c\",\"Tags\":[{\"Value\":\"true\",\"Key\":\"AutoDiscover\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:security-group/sg-7f0c2916\",\"Tags\":[{\"Value\":\"Database and Messaging\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:security-group/sg-871732ee\",\"Tags\":[{\"Value\":\"true\",\"Key\":\"AutoDiscover\"},{\"Value\":\"appSecurityGroup\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:ec2:eu-west-2:017363970217:security-group/sg-9732d6ff\",\"Tags\":[{\"Value\":\"test\",\"Key\":\"Name\"}]}
{\"ResourceARN\":\"arn:aws:elasticloadbalancing:eu-west-2:017363970217:loadbalancer/app/DummyALB/da70f61a914fc50a\",\"Tags\":[{\"Value\":\"true\",\"Key\":\"AutoDiscover\"}]}"
declare -A RESOURCE_MAP=([arn:aws:ec2:eu-west-2:017363970217:instance/i-096a32ca8c28bedbb]="MongoDB,false" [arn:aws:ec2:eu-west-2:017363970217:instance/i-08803ecb16560b18a]="2018-02-14 07:15:26,false" [arn:aws:ec2:eu-west-2:017363970217:instance/i-04eeb1346463540c5]="123,false" [arn:aws:ec2:eu-west-2:017363970217:instance/i-09330d7744ebef9b3]="123,false" [arn:aws:ec2:eu-west-2:017363970217:instance/i-02abdf10071ce9ce6]="2018-02-14 06:57:30,false" [arn:aws:ec2:eu-west-2:017363970217:instance/i-0f2e26f9a7860e680]="123,false" [arn:aws:acm:eu-west-2:017363970217:certificate/d2ae17b0-75ed-4b56-ac12-a80f9e5c493d]="Unnamed,true" [arn:aws:elasticloadbalancing:eu-west-2:017363970217:loadbalancer/app/DummyALB/da70f61a914fc50a]="Unnamed,true" [arn:aws:ec2:eu-west-2:017363970217:image/ami-39f3e25d]="Unnamed,true" [arn:aws:ec2:eu-west-2:017363970217:instance/i-05f2fda5ce72c2b36]="2018-02-14 07:22:33,false" [arn:aws:ec2:eu-west-2:017363970217:security-group/sg-74c92d1c]="Unnamed,true" [arn:aws:ec2:eu-west-2:017363970217:security-group/sg-871732ee]="appSecurityGroup,true" [arn:aws:ec2:eu-west-2:017363970217:instance/i-0a65849491dfc8562]="yxc,false" [arn:aws:ec2:eu-west-2:017363970217:security-group/sg-9732d6ff]="test,false" [arn:aws:ec2:eu-west-2:017363970217:instance/i-068b644ad5fbe6e5f]="12,false" [arn:aws:ec2:eu-west-2:017363970217:instance/i-0f5308bf09c42d7f9]="123,false" [arn:aws:ec2:eu-west-2:017363970217:instance/i-0c57f03afc68de24c]="Multi Instance,true" [arn:aws:ec2:eu-west-2:017363970217:instance/i-08e4a99e69f6d8dce]="2018-02-14 07:07:20,false" [arn:aws:ec2:eu-west-2:017363970217:security-group/sg-7f0c2916]="Database and Messaging,false" )
@@ -1,7 +1,16 @@
#!/usr/bin/env bash
# Add instance to application load balancer
# ------------------------------------------------------
# -----------------------------------------------------------
# Associates a chosen instance with a chosen application load balancer.
#
# Steps:
# Creates target group for instance.
# Configures health check of target group.
# Creates rule inside https listener of application load balancer.
# Registers target within target group.
# Configures apache of ec2 instance to revere proxy.
# -----------------------------------------------------------
function associate_alb_start(){
associate_alb_require
@@ -14,20 +23,20 @@ function associate_alb_start(){
# the user will be prompted to enter a value
# -----------------------------------------------------------
function associate_alb_require(){
# will only be executed after instance creation
require_instance
require_instance_short_name
require_load_balancer
require_key_file
require_ssh_user
}
function associate_alb_execute() {
disable_aws_success_output
instance_id=$(get_resource_id $instance)
public_dns_name=$(get_public_dns_name $instance_id)
enable_aws_success_output
}
function associate_alb_execute() {
# create target group for instance
local target_group_arn=$(exit_on_fail create_target_group "S-dedicated-$instance_short_name")
exit_on_fail set_target_group_health_check "$target_group_arn" "HTTP" "/index.html" "80" "5" "4" "2" "2"
@@ -1,6 +1,9 @@
#!/usr/bin/env bash
# Scenario for creating an instance
# Scenario for creating an ec2 instance
#
# Steps:
# Creates ec2 instance
# ------------------------------------------------------
function instance_start(){
@@ -17,10 +20,12 @@ function instance_start(){
function instance_require(){
require_region
require_instance_type
require_instance_security_group_id
require_image_id
require_instance_security_group
require_image
require_instance_name
require_instance_short_name
require_mongodb_host
require_mongodb_port
require_ssh_user
require_build_version
require_key_name
@@ -33,14 +38,16 @@ function instance_require(){
function instance_preview(){
header "Preview"
image_id=$(get_resource_id $image)
instance_security_group_id=$(get_resource_id $instance_security_group)
user_data=$(build_user_data)
local_echo "An instance will be created with the following specifications: "
local_echo "To be implemented..."
seek_confirmation "Do you want to continue?"
if is_confirmed; then
break
:
else
break
safeExit
fi
}
@@ -63,11 +70,11 @@ function instance_execute() {
header "Conclusion"
success "Instance should be reachable through $public_dns_name."
success "Instance should be reachable through $public_dns_name:8888."
}
function build_user_data(){
build_configuration "MONGODB_HOST=$default_mongodb_host" "MONGODB_PORT=$default_mongodb_port" "MONGODB_NAME=$(alphanumeric $instance_name)" \
build_configuration "MONGODB_HOST=$mongodb_host" "MONGODB_PORT=$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"
}
@@ -18,8 +18,12 @@ function master_instance_start(){
function master_instance_require(){
require_region
require_instance_type
require_image
require_instance_name
require_instance_short_name
require_mongodb_host
require_mongodb_port
require_instance_security_group
require_ssh_user
require_build_version
require_key_name
@@ -35,8 +39,9 @@ function master_instance_require(){
# -----------------------------------------------------------
function master_instance_execute() {
header "Master Instance Initialization"
ssh_user=$image_ssh_user
event_name=$instance_name
image_id=$(get_resource_id $image)
instance_security_group_id=$(get_resource_id $instance_security_group)
local user_data_master=$(build_configuration "MONGODB_HOST=$mongodb_host" "MONGODB_PORT=$mongodb_port" "MONGODB_NAME=$(alphanumeric $instance_name)" \
"REPLICATION_CHANNEL=$(alphanumeric $instance_name)" "SERVER_NAME=$(alphanumeric $instance_name)" "USE_ENVIRONMENT=live-master-server" \
@@ -50,9 +55,7 @@ function master_instance_execute() {
header "Event and user creation"
port="8888"
configure_application $public_dns_name $port $event_name $new_admin_password $user_username $user_password
public_ip=$(get_public_ip $public_dns_name)
event_id=$(configure_application $public_dns_name $port $event_name $new_admin_password $user_username $user_password)
local user_data_replica=$(build_configuration "MONGODB_HOST=$mongodb_host" "MONGODB_PORT=$mongodb_port" "MONGODB_NAME=$(alphanumeric $instance_name)-replica" \
"REPLICATION_CHANNEL=$(alphanumeric $instance_name)" "SERVER_NAME=$(alphanumeric $instance_name)" "USE_ENVIRONMENT=live-replica-server" \
@@ -0,0 +1,42 @@
#!/usr/bin/env bash
#!/usr/bin/env bash
# Scenario for creating an instance
# ------------------------------------------------------
function replica_instance_start(){
replica_instance_require
replica_instance_execute
}
# -----------------------------------------------------------
# All these variables are needed for this scenario
# If one variable is not assigned or passed by parameter
# the user will be prompted to enter a value
# -----------------------------------------------------------
function replica_instance_require(){
require_region
require_launch_template
require_ssh_user
require_key_file
}
# -----------------------------------------------------------
# Execute instance scenario
# @param $1 user data
# -----------------------------------------------------------
function replica_instance_execute() {
header "Replica Instance Initialization"
instance_id=$(run_instance_from_launch_template $launch_template)
wait_instance_exists $instance_id
public_dns_name=$(get_public_dns_name $instance_id)
user_data=$(get_user_data_from_instance $instance_id | base64 --decode)
echo "$user_data"
header "Conclusion"
success "Instance should be reachable through $public_dns_name:8888."
}
@@ -20,6 +20,8 @@ function shared_instance_require(){
require_instance_name
require_instance_short_name
require_mongodb_host
require_mongodb_port
require_build_version
require_key_file
require_event_name
@@ -98,13 +100,10 @@ function shared_instance_execute() {
local_echo "Commenting out $comment_out_line_in_env_with_pattern inside $server_env_file..."
execute_remote "sed -i '/$comment_out_line_in_env_with_pattern/s/^/#/g' $server_env_file"
local_echo "Configuring $server_env_file..."
environment="live-server"
env_content=$(wget -qO- http://releases.sapsailing.com/environments/$environment)
local MEMORY="10000m"
exit_on_fail execute_remote "echo -e \"MEMORY=$MEMORY\" >> $server_env_file"
exit_on_fail execute_remote "echo -e \"# START Environment: $environment \" >> $server_env_file"
exit_on_fail execute_remote "echo -e \"$env_content\" >> $server_env_file"
exit_on_fail execute_remote "echo -e \"# END Environment: $environment \" >> $server_env_file"
append_environment_to_env_sh "live-server" $ssh_user $super_instance $server_env_file $env_file
local env_patch=$(build_configuration "# START Script $script_start_time" "SERVER_NAME=$(alphanumeric $instance_name)" "TELNET_PORT=$telnet_port" \
"SERVER_PORT=$server_port" "EXPEDITION_PORT=$expedition_port" "MONGODB_NAME=$(alphanumeric $instance_name)" "MONGODB_HOST=$default_mongodb_host" \
@@ -113,8 +112,7 @@ function shared_instance_execute() {
exit_on_fail execute_remote "echo -e \"$env_patch\" >> $server_env_file"
local memory="10000m"
exit_on_fail execute_remote "echo -e \"MEMORY=$memory\" >> $server_env_file"
local_echo "Creating README file if it does not exist already..."
execute_remote touch $readme_file
@@ -144,7 +142,7 @@ function shared_instance_execute() {
execute_remote_root "echo -e \"\n# $instance_short_name (${description:-"Unknown"}, ${contact_person:-"Unknown"}, ${contact_email:-"Unknown"})\" >> $events_conf"
append_macro_to_001_events_conf "$domain" "$event_id" "root" "$super_instance" "$server_port"
reload_httpd "root" $super_instance
header "Conclusion"
success "Sub instance should be reachable through https://$domain."
@@ -75,6 +75,13 @@ while [ -h "${SOURCE}" ]; do # resolve ${SOURCE} until the file is no longer a s
done
SOURCEPATH="$( cd -P "$( dirname "${SOURCE}" )" && pwd )"
wget -q --spider releases.sapsailing.com --timeout=5
if [ ! $? -eq 0 ]; then
error "No internet connection. Exiting."
safeExit
fi
if [ ! -d "${SOURCEPATH}" ]
then
die "Failed to find library files expected in: ${SOURCEPATH}"
+11 -1
View File
@@ -3,7 +3,13 @@
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:.+"
ValidLaunchTemplateIdRegex='lt-[a-zA-Z0-9]{17}'
ValidResourceARNRegex="arn:.+:.+:.+:.+:.+\/.+"
ValidInstanceARNRegex="arn:.+:.+:.+:.+:instance\/.+"
ValidSecurityGroupARNRegex="arn:.+:.+:.+:.+:security-group\/.+"
ValidImageARNRegex="arn:.+:.+:.+:.+:image\/.+"
ValidCertificateARNRegex="arn:.+:.+:.+:.+:certificate\/.+"
ValidLoadBalancerARNRegex="arn:.+:.+:.+:.+:loadbalancer\/.+"
function validate_resource_arn(){
[[ "$1" =~ $ValidResourceARNRegex ]] && echo "$1" || error_message "ResourceARN \"$1\" not valid."
@@ -13,6 +19,10 @@ function validate_instance_id(){
[[ "$1" =~ $ValidInstanceIdRegex ]] && echo "$1" || error_message "Instance id \"$1\" not valid."
}
function validate_launch_template_id(){
[[ "$1" =~ $ValidLaunchTemplateIdRegex ]] && echo "$1" || error_message "Launch template id \"$1\" not valid."
}
function validate_hostname(){
[[ "$1" =~ $ValidHostnameRegex ]] && echo "$1" || error_message "Hostname \"$1\" not valid."
}
@@ -4,6 +4,15 @@
<div id="mainContent">
<h4 class="articleHeadline">What's New - SAP Sailing Analytics</h4>
<div class="innerContent">
<h5 class="articleSubheadline">March 2018</h5>
<ul class="bulletList">
<li>Zooming in on a competitor chart in the race viewer will now adjust the
time resolution to that selected in the settings if before zooming the
resolution had to be reduced to remain under the limit of data points that
can be requested from the server in one round trip.
</li>
</ul>
<h5 class="articleSubheadline">January 2018</h5>
<ul class="bulletList">
<li>Coordinate display (lat/lng), e.g., in pop-ups for marks and wind sensors
@@ -75,7 +75,7 @@ public abstract class AbstractCompetitorLeaderboardChart<SettingsType extends Ge
private final List<String> raceColumnNamesWithData;
protected final String leaderboardName;
protected final StringMessages stringMessages;
public AbstractCompetitorLeaderboardChart(Component<?> parent, ComponentContext<?> context,
SailingServiceAsync sailingService,
AsyncActionsExecutor asyncActionsExecutor, String leaderboardName,
@@ -102,6 +102,17 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
private final TimingHolder primary = new TimingHolder();
private final TimingHolder secondary = new TimingHolder();
/**
* Whenever data is received from the server, the effective step size of that data is captured
* in this field. Ideally, it would equal the {@link #getStepSizeInMillis() desired step size}, but
* long time ranges covered by the chart and the lack of zoom may require increasing the effective step size
* so as to reduce the number of fixes requested from the server.<p>
*
* However, when zooming this will be re-evaluated, and a more fine-grained request to the server, limited to
* the zoom range, may then be issued.
*/
private long effectiveStepSize = -1;
AbstractCompetitorRaceChart(Component<?> parent, ComponentContext<?> context, SailingServiceAsync sailingService,
AsyncActionsExecutor asyncActionsExecutor,
CompetitorSelectionProvider competitorSelectionProvider, RegattaAndRaceIdentifier selectedRaceIdentifier,
@@ -237,25 +248,38 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
// If the time interval is too long and the step size too small, the number of fixes the query would have to
// produce may exceed any reasonable limit. Therefore, we limit the number of fixes that such a query may ask
// for:
doLoadDataForCompetitorsAndDataType(from, to, append, competitorsToLoad, getSelectedFirstDetailType(),primary);
doLoadDataForCompetitorsAndDataType(from, to, append, competitorsToLoad, getSelectedFirstDetailType(), primary);
if (getSelectedSecondDetailType() != null) {
doLoadDataForCompetitorsAndDataType(from, to, append, competitorsToLoad, getSelectedSecondDetailType(),secondary);
doLoadDataForCompetitorsAndDataType(from, to, append, competitorsToLoad, getSelectedSecondDetailType(), secondary);
}
}
}
private void doLoadDataForCompetitorsAndDataType(final Date from, final Date to, final boolean append,
ArrayList<CompetitorDTO> competitorsToLoad, final DetailType selectedDataTypeToRetrieve,final TimingHolder tholder) {
long stepSize = Math.max(getStepSizeInMillis(),
from==null||to==null ? 0 : Math.abs(to.getTime()-from.getTime())/SailingServiceConstants.MAX_NUMBER_OF_FIXES_TO_QUERY);
GetCompetitorsRaceDataAction getCompetitorsRaceDataAction = new GetCompetitorsRaceDataAction(sailingService,
selectedRaceIdentifier, competitorsToLoad, from, to, stepSize, selectedDataTypeToRetrieve,
leaderboardGroupName, leaderboardName);
@Override
protected void changeMinMaxAndExtremesInterval(Date minTimepoint, Date maxTimepoint, boolean redraw) {
super.changeMinMaxAndExtremesInterval(minTimepoint, maxTimepoint, redraw);
updateChartIfEffectiveStepSizeChanged(minTimepoint, maxTimepoint);
}
protected void updateChartIfEffectiveStepSizeChanged(Date minTimepoint, Date maxTimepoint) {
long effectiveStepSize = getEffectiveStepSize(minTimepoint, maxTimepoint);
if (this.effectiveStepSize != -1 && this.effectiveStepSize != effectiveStepSize) {
// the change has had an impact on the effective step size; trigger a re-load
updateChart(minTimepoint, maxTimepoint, /* append==false means replace points in chart by the new ones */ false);
}
}
private void doLoadDataForCompetitorsAndDataType(final Date from, final Date to, final boolean append,
ArrayList<CompetitorDTO> competitorsToLoad, final DetailType selectedDataTypeToRetrieve, final TimingHolder tholder) {
long effectiveStepSize = getEffectiveStepSize(from, to);
GetCompetitorsRaceDataAction getCompetitorsRaceDataAction = new GetCompetitorsRaceDataAction(sailingService,
selectedRaceIdentifier, competitorsToLoad, from, to, effectiveStepSize, selectedDataTypeToRetrieve,
leaderboardGroupName, leaderboardName);
AsyncCallback<CompetitorsRaceDataDTO> dataLoadedCallback = new AsyncCallback<CompetitorsRaceDataDTO>() {
@Override
public void onSuccess(final CompetitorsRaceDataDTO result) {
hideLoading();
AbstractCompetitorRaceChart.this.effectiveStepSize = effectiveStepSize;
if (result != null) {
if (result.isEmpty() && chartContainsNoData()) {
setWidget(noDataFoundLabel);
@@ -276,7 +300,6 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
timer.getPlayMode() == PlayModes.Live);
}
};
if (append) {
// this call is repeated, allow it to be throttled and dropped
asyncActionsExecutor.execute(getCompetitorsRaceDataAction, LOAD_COMPETITOR_CHART_DATA_CATEGORY,
@@ -286,7 +309,21 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
// asyncActionExecutor
getCompetitorsRaceDataAction.execute(dataLoadedCallback);
}
}
/**
* Based on a time range and a {@link #getStepSizeInMillis() desired step size} computes an effective
* step size that observes a maximum number of fixes that may be queried in one request from the server
* ({@link SailingServiceConstants#MAX_NUMBER_OF_FIXES_TO_QUERY}). If the time range and the desired step
* size do not exceed this limit, the step size desired will be returned. Otherwise, the step size will be
* extended such that {@link SailingServiceConstants#MAX_NUMBER_OF_FIXES_TO_QUERY} fixes will be requested
* for the time range between {@code from} and {@code to}.
*
* @return the effective step size in milliseconds
*/
private long getEffectiveStepSize(final Date from, final Date to) {
return Math.max(getStepSizeInMillis(),
from==null||to==null ? 0 : Math.abs(to.getTime()-from.getTime())/SailingServiceConstants.MAX_NUMBER_OF_FIXES_TO_QUERY);
}
private boolean chartContainsNoData() {
@@ -347,14 +384,12 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
* Fills the series for the selected competitors with the data in {@link AbstractCompetitorRaceChart#chartData}.<br />
*/
private synchronized void updateChartSeries(CompetitorsRaceDataDTO chartData, DetailType retrievedDataType,
boolean append,TimingHolder tholder) {
boolean append, TimingHolder tholder) {
// Make sure the busy indicator is removed at this point, or plotting the data results in an exception
setWidget(chart);
for (CompetitorDTO competitor : chartData.getCompetitors()) {
Series competitorDataSeries = getOrCreateCompetitorDataSeries(retrievedDataType, competitor);
Series markPassingSeries = getOrCreateCompetitorMarkPassingSeries(competitorDataSeries, retrievedDataType,
competitor);
Series markPassingSeries = getOrCreateCompetitorMarkPassingSeries(competitorDataSeries, retrievedDataType, competitor);
CompetitorRaceDataDTO competitorData = chartData.getCompetitorData(competitor);
if (competitorData != null) {
Date toDate = timer.getLiveTimePointAsDate();
@@ -371,23 +406,20 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
}
}
markPassingSeries.setPoints(markPassingPoints.toArray(new Point[0]), false);
Point[] oldRaceDataPoints = competitorDataSeries.getPoints();
List<com.sap.sse.common.Util.Pair<Date, Double>> raceData = competitorData.getRaceData();
Point[] raceDataPointsToAdd = new Point[raceData.size()];
int currentPointIndex = 0;
for (com.sap.sse.common.Util.Pair<Date, Double> raceDataPoint : raceData) {
Double dataPointValue = raceDataPoint.getB();
if(dataPointValue != null) {
if (dataPointValue != null) {
long dataPointTimeAsMillis = raceDataPoint.getA().getTime();
if(append == false || (tholder.timeOfEarliestRequestInMillis == null || dataPointTimeAsMillis < tholder.timeOfEarliestRequestInMillis) ||
if (append == false || (tholder.timeOfEarliestRequestInMillis == null || dataPointTimeAsMillis < tholder.timeOfEarliestRequestInMillis) ||
tholder.timeOfLatestRequestInMillis == null || dataPointTimeAsMillis > tholder.timeOfLatestRequestInMillis) {
raceDataPointsToAdd[currentPointIndex++] = new Point(dataPointTimeAsMillis, dataPointValue);
}
}
}
Point[] newRaceDataPoints;
if (append) {
newRaceDataPoints = new Point[oldRaceDataPoints.length + currentPointIndex];
@@ -397,16 +429,14 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
newRaceDataPoints = new Point[currentPointIndex];
System.arraycopy(raceDataPointsToAdd, 0, newRaceDataPoints, 0, currentPointIndex);
}
setSeriesPoints(competitorDataSeries, newRaceDataPoints);
setSeriesPoints(competitorDataSeries, newRaceDataPoints, /* manageZoom */ append);
// Adding the series if chart doesn't contain it
List<Series> chartSeries = Arrays.asList(chart.getSeries());
if (!chartSeries.contains(competitorDataSeries)) {
chart.addSeries(competitorDataSeries);
chart.addSeries(markPassingSeries);
//this is to prevent a bug, that will prohibit the initial rendering
// this is to prevent a bug, that will prohibit the initial rendering
chart.setSizeToMatchContainer();
}
}
}
@@ -775,11 +805,9 @@ public abstract class AbstractCompetitorRaceChart<SettingsType extends ChartSett
if (!isVisible()) {
return;
}
if (allowTimeAdjust) {
updateTimePlotLine(newTime);
}
switch (timer.getPlayMode()) {
case Live: {
// is date before first cache entry or is cache empty?
@@ -184,13 +184,13 @@ public abstract class AbstractRaceChart<SettingsType extends Settings> extends A
if (!isZoomed) {
isZoomed = true;
}
//Set a minute as max time zoom just as for chart
// Set a minute as max time zoom just as for chart
if (xAxisMax - xAxisMin > MINUTE_IN_MILLIS) {
Date rangeStart = new Date(xAxisMin);
Date rangeEnd = new Date(xAxisMax);
timeRangeWithZoomProvider.setTimeZoom(rangeStart, rangeEnd, this);
updateChartIfEffectiveStepSizeChanged(rangeStart, rangeEnd);
fireEvent(new ChartZoomChangedEvent(rangeStart, rangeEnd));
} else {
fireEvent(new ChartZoomResetEvent());
return false;
@@ -199,7 +199,7 @@ public abstract class AbstractRaceChart<SettingsType extends Settings> extends A
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
// in case the user clicks the "reset zoom" button chartSelectionEvent.getXAxisMinAsLong() throws in exception
// in case the user clicks the "reset zoom" button chartSelectionEvent.getXAxisMinAsLong() throws an exception
isZoomed = false;
timeRangeWithZoomProvider.resetTimeZoom();
// redraw is triggered by the call to onTimeZoomReset() and therefore not necessary again here
@@ -223,6 +223,13 @@ public abstract class AbstractRaceChart<SettingsType extends Settings> extends A
}
return true;
}
/**
* Does nothing here; subclasses have the possibility to override if they need to re-load data
* based on changes in the visible area that may lead to step size / resolution adjustments
*/
protected void updateChartIfEffectiveStepSizeChanged(Date minTimepoint, Date maxTimepoint) {
}
protected void changeMinMaxAndExtremesInterval(Date minTimepoint, Date maxTimepoint, boolean redraw) {
if (chart != null) {
@@ -246,14 +253,14 @@ public abstract class AbstractRaceChart<SettingsType extends Settings> extends A
}
}
protected void setSeriesPoints(Series series, Point[] points) {
if (timeRangeWithZoomProvider.isZoomed()) {
protected void setSeriesPoints(Series series, Point[] points, boolean manageZoom) {
if (manageZoom && timeRangeWithZoomProvider.isZoomed()) {
com.sap.sse.common.Util.Pair<Date, Date> timeZoom = timeRangeWithZoomProvider.getTimeZoom();
resetMinMaxAndExtremesInterval(/* redraw */ false);
series.setPoints(points, false);
series.setPoints(points, /* redraw */ false);
changeMinMaxAndExtremesInterval(timeZoom.getA(), timeZoom.getB(), /* redraw */ false);
} else {
series.setPoints(points, false);
series.setPoints(points, /* redraw */ false);
}
}
@@ -515,7 +515,7 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
Point[] points = markSeries.getPoints();
if (points.length > index) {
setRedPoint(points, index);
setSeriesPoints(markSeries, points);
setSeriesPoints(markSeries, points, /* manageZoom */ true);
}
}
@@ -524,7 +524,7 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
Point[] points = getSeriesPoints(marks.get(selectedMark).keySet());
if (points.length > index) {
setRedPoint(points, index);
setSeriesPoints(markSeries, points);
setSeriesPoints(markSeries, points, /* manageZoom */ true);
chart.redraw();
}
}
@@ -534,7 +534,7 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
Point[] points = markSeries.getPoints();
if (points.length > index) {
points[index].setMarker(new Marker().setFillColor(selectedMark.color==null?null:selectedMark.color.getAsHtml()));
setSeriesPoints(markSeries, points);
setSeriesPoints(markSeries, points, /* manageZoom */ true);
}
}
@@ -701,11 +701,11 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
}
private void setSeriesPoints(MarkDTO mark) {
setSeriesPoints(markSeries, getSeriesPoints(marks.get(mark).keySet()));
setSeriesPoints(markSeries, getSeriesPoints(marks.get(mark).keySet()), /* manageZoom */ true);
}
public void setSeriesPoints(Point[] points) {
setSeriesPoints(markSeries, points);
setSeriesPoints(markSeries, points, /* manageZoom */ true);
}
public void setVisible(boolean visible) {
@@ -79,16 +79,15 @@ public class MultiCompetitorRaceChart extends AbstractCompetitorRaceChart<MultiC
boolean settingsChanged = updateSettingsOnly(newSettings);
DetailType firstType = newSettings.getFirstDetailType();
DetailType secondType = newSettings.getSecondDetailType();
if(!lifecycle.getAllowedDetailTypes().contains(firstType)){
//if the first type is not allowed here, choose a different valid value
if (!lifecycle.getAllowedDetailTypes().contains(firstType)){
// if the first type is not allowed here, choose a different valid value
firstType = DetailType.WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD;
}
if(!lifecycle.getAllowedDetailTypes().contains(firstType)){
if (!lifecycle.getAllowedDetailTypes().contains(firstType)){
//if the second type is not allowed here, do not set it.
secondType = null;
}
boolean selectedDetailTypeChanged = setSelectedDetailTypes(firstType,
secondType);
boolean selectedDetailTypeChanged = setSelectedDetailTypes(firstType, secondType);
if (selectedDetailTypeChanged || settingsChanged) {
clearChart();
timeChanged(timer.getTime(), null);
@@ -447,10 +447,10 @@ public class WindChart extends AbstractRaceChart<WindChartSettings> implements R
newDirectionPoints = directionPoints;
newSpeedPoints = speedPoints;
}
setSeriesPoints(directionSeries, newDirectionPoints);
setSeriesPoints(directionSeries, newDirectionPoints, /* manageZoom */ true);
windSourceDirectionPoints.put(windSource, newDirectionPoints);
if (windSource.getType().useSpeed()) {
setSeriesPoints(speedSeries, newSpeedPoints);
setSeriesPoints(speedSeries, newSpeedPoints, /* manageZoom */ true);
windSourceSpeedPoints.put(windSource, newSpeedPoints);
}