diff --git a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/004-git.conf b/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/004-git.conf deleted file mode 100644 index 97270e6d056..00000000000 --- a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/004-git.conf +++ /dev/null @@ -1,25 +0,0 @@ - -ServerName git.sapsailing.com -SetEnv GIT_PROJECT_ROOT /home/trac/git -SetEnv GIT_HTTP_EXPORT_ALL -ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/ -ScriptAlias /hooks/ /var/www/cgi-bin/ - - - Options +ExecCGI - AuthType Basic - AuthName 'Git' - AuthUserFile '/etc/httpd/conf/passwd.git' - Require valid-user - - - - AllowOverride None - Options FollowSymLinks - Order allow,deny - Allow from all - - -SetEnvIf User-Agent ".*MSIE.*" \ - downgrade-1.0 force-response-1.0 - diff --git a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/006-docker-registry.conf b/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/006-docker-registry.conf deleted file mode 100644 index a8a59f71935..00000000000 --- a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/006-docker-registry.conf +++ /dev/null @@ -1,39 +0,0 @@ - - ServerName docker.sapsailing.com - ProxyPreserveHost on - ProxyPass / http://127.0.0.1:5000/ - ProxyPassReverse / http://127.0.0.1:5000/ - - Order deny,allow - Allow from all - AuthName "Docker Registry Authentication" - AuthType basic - AuthUserFile '/etc/httpd/conf/passwd.git' - Require valid-user - - # Use separate log files for the SSL virtual host; note that LogLevel - # is not inherited from httpd.conf. - ErrorLog logs/docker_error_log - TransferLog logs/docker_access_log - LogLevel warn - - - - ServerName docker-registry.sapsailing.com - ProxyPreserveHost on - ProxyPass /v2 http://127.0.0.1:5001/v2 - ProxyPassReverse /v2 http://127.0.0.1:5001/v2 - - Order deny,allow - Allow from all - AuthName "Docker Registry Authentication" - AuthType basic - AuthUserFile '/etc/httpd/conf/passwd.git' - Require valid-user - - # Use separate log files for the SSL virtual host; note that LogLevel - # is not inherited from httpd.conf. - ErrorLog logs/docker_error_log - TransferLog logs/docker_access_log - LogLevel warn - diff --git a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/007-sail-insight.conf b/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/007-sail-insight.conf deleted file mode 100644 index 99512acd0c0..00000000000 --- a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/007-sail-insight.conf +++ /dev/null @@ -1,14 +0,0 @@ -# sail-insight.com - - ServerName sail-insight.com - ServerAlias www.sail-insight.com - CustomLog logs/services_log combined env=!original_client_ip - CustomLog logs/services_log first_forwarded_for_ip env=original_client_ip - Alias / /home/trac/sail-insight-website/ - - Options Indexes FollowSymLinks MultiViews - AllowOverride All - Order allow,deny - allow from all - - diff --git a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/awstats.conf b/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/awstats.conf deleted file mode 100644 index 71f8ca03299..00000000000 --- a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/awstats.conf +++ /dev/null @@ -1,56 +0,0 @@ -# -# Content of this file, with correct values, can be automatically added to -# your Apache server by using the AWStats configure.pl tool. -# - - -# If using Windows and Perl ActiveStat, this is to enable Perl script as CGI. -#ScriptInterpreterSource registry - - -# -# Directives to add to your Apache conf file to allow use of AWStats as a CGI. -# Note that path "/usr/share/awstats/" must reflect your AWStats install path. -# -Alias /awstatsclasses "/usr/share/awstats/wwwroot/classes/" -Alias /awstatscss "/usr/share/awstats/wwwroot/css/" -Alias /awstatsicons "/usr/share/awstats/wwwroot/icon/" -ScriptAlias /awstats/ "/usr/share/awstats/wwwroot/cgi-bin/" - -# Adding access to /var/log/old/cache/unique-ips-per-referrer/stats: -Alias /unique-visitors/ "/var/log/old/cache/unique-ips-per-referrer/stats/" - -# -# This is to permit URL access to scripts/files in AWStats directory. -# - - ServerName awstats.sapsailing.com - CustomLog logs/awstats_access_log combined - ErrorLog logs/awstats_error_log - - - Options None -# AllowOverride None -# Order allow,deny -# Allow from 127.0.0.1 - AuthType Basic - AuthName 'awstats' - AuthUserFile /etc/httpd/conf/passwd.awstats - Require valid-user - - - - Options Indexes -# AllowOverride None -# Order allow,deny -# Allow from 127.0.0.1 - AuthType Basic - AuthName 'awstats' - AuthUserFile /etc/httpd/conf/passwd.awstats - Require valid-user - -# Additional Perl modules - - SetEnv PERL5LIB /usr/share/awstats/lib:/usr/share/awstats/plugins:/root/perl5/lib/perl5 - - diff --git a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/central-only-virtual-hosts.conf b/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/central-only-virtual-hosts.conf deleted file mode 100644 index ddd678ce2a4..00000000000 --- a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/central-only-virtual-hosts.conf +++ /dev/null @@ -1,78 +0,0 @@ - - ServerName jobs.sapsailing.com - CustomLog logs/jobs_log combined env=!original_client_ip - CustomLog logs/jobs_log first_forwarded_for_ip env=original_client_ip - DocumentRoot /home/trac/static/jobs - - Options Indexes FollowSymLinks MultiViews - AllowOverride All - Order allow,deny - allow from all - - - -# P2 repository - - ServerName p2.sapsailing.com - CustomLog logs/services_log combined env=!original_client_ip - CustomLog logs/services_log first_forwarded_for_ip env=original_client_ip - Alias /p2 /home/trac/p2-repositories - - Options Indexes FollowSymLinks MultiViews - AllowOverride None - Order allow,deny - allow from all - - - - - ServerName bugzilla.sapsailing.com - RewriteEngine On - RewriteRule ^/?$ http://bugzilla.sapsailing.com/bugzilla [L] - CustomLog logs/services_log combined env=!original_client_ip - CustomLog logs/services_log first_forwarded_for_ip env=original_client_ip - Alias /bugzilla /usr/share/bugzilla - - AddHandler cgi-script .cgi - Options +Indexes +ExecCGI +FollowSymLinks - DirectoryIndex index.cgi - AllowOverride Limit Options FileInfo Indexes AuthConfig - - # Additional Perl modules - - SetEnv PERL5LIB /root/perl5/lib/perl5:/root/perl5/lib/perl5/x86_64-linux-thread-multi - - - -# Wiki --> - - ServerName wiki.sapsailing.com - RewriteEngine on - RewriteRule ^/(.*) http://localhost:4567/$1 [P,L] - ProxyPassReverse / http://localhost:4567/ - CustomLog logs/services_log combined env=!original_client_ip - CustomLog logs/services_log first_forwarded_for_ip env=original_client_ip - - - - ServerName releases.sapsailing.com - DocumentRoot /home/trac/releases - - Options +Indexes +FollowSymLinks - - CustomLog logs/services_log combined env=!original_client_ip - CustomLog logs/services_log first_forwarded_for_ip env=original_client_ip - - - - ServerName static.sapsailing.com - DocumentRoot /var/www/static - - Order Deny,Allow - Allow from all - Options -Indexes +FollowSymLinks -ExecCGI - AllowOverride All - - CustomLog logs/services_log combined env=!original_client_ip - CustomLog logs/services_log first_forwarded_for_ip env=original_client_ip - diff --git a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/loadPhp.conf b/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/loadPhp.conf deleted file mode 100644 index 67a415dca06..00000000000 --- a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/loadPhp.conf +++ /dev/null @@ -1 +0,0 @@ -LoadModule php7_module modules/libphp-7.1.so diff --git a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/perl.conf b/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/perl.conf deleted file mode 100644 index 30d5d16f3bd..00000000000 --- a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/perl.conf +++ /dev/null @@ -1,48 +0,0 @@ -# -# Mod_perl incorporates a Perl interpreter into the Apache web server, -# so that the Apache web server can directly execute Perl code. -# Mod_perl links the Perl runtime library into the Apache web server -# and provides an object-oriented Perl interface for Apache's C -# language API. The end result is a quicker CGI script turnaround -# process, since no external Perl interpreter has to be started. -# - -# Uncomment this line to globally enable warnings, which will be -# written to the server's error log. Warnings should be enabled -# during the development process, but should be disabled on a -# production server as they affect performance. -# -#PerlSwitches -w - -# Uncomment this line to enable taint checking globally. When Perl is -# running in taint mode various checks are performed to reduce the -# risk of insecure data being passed to a subshell or being used to -# modify the filesystem. Unfortunately many Perl modules are not -# taint-safe, so you should exercise care before enabling it on a -# production server. -# -#PerlSwitches -T - -# This will allow execution of mod_perl to compile your scripts to -# subroutines which it will execute directly, avoiding the costly -# compile process for most requests. -# -#Alias /perl /var/www/perl -# -# SetHandler perl-script -# PerlResponseHandler ModPerl::Registry -# PerlOptions +ParseHeaders -# Options +ExecCGI -# - -# This will allow remote server configuration reports, with the URL of -# http://servername/perl-status -# Change the ".example.com" to match your domain to enable. -# -# -# SetHandler perl-script -# PerlResponseHandler Apache2::Status -# Order deny,allow -# Deny from all -# Allow from .example.com -# diff --git a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/php-conf.7.1 b/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/php-conf.7.1 deleted file mode 100644 index 2c8064ed7f1..00000000000 --- a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/php-conf.7.1 +++ /dev/null @@ -1,57 +0,0 @@ -# -# The following lines prevent .user.ini files from being viewed by Web clients. -# - - Require all denied - - -# -# Allow php to handle Multiviews -# -AddType text/html .php - -# -# Add index.php to the list of files that will be served as directory -# indexes. -# -DirectoryIndex index.php - -# mod_php options - - # - # Cause the PHP interpreter to handle files with a .php extension. - # - - SetHandler application/x-httpd-php - - - # - # Uncomment the following lines to allow PHP to pretty-print .phps - # files as PHP source code: - # - # - # SetHandler application/x-httpd-php-source - # - - # - # Apache specific PHP configuration options - # those can be override in each configured vhost - # - php_value session.save_handler "files" - php_value session.save_path "/var/lib/php/7.1/session" - php_value soap.wsdl_cache_dir "/var/lib/php/7.1/wsdlcache" - - #php_value opcache.file_cache "/var/lib/php/7.1/opcache" - - -# Redirect to local php-fpm if mod_php is not available - - - # Enable http authorization headers - SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1 - - - SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost" - - - diff --git a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/php.conf b/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/php.conf deleted file mode 100644 index 2c8064ed7f1..00000000000 --- a/configuration/environments_scripts/central_reverse_proxy/files/etc/httpd/central-config.d/php.conf +++ /dev/null @@ -1,57 +0,0 @@ -# -# The following lines prevent .user.ini files from being viewed by Web clients. -# - - Require all denied - - -# -# Allow php to handle Multiviews -# -AddType text/html .php - -# -# Add index.php to the list of files that will be served as directory -# indexes. -# -DirectoryIndex index.php - -# mod_php options - - # - # Cause the PHP interpreter to handle files with a .php extension. - # - - SetHandler application/x-httpd-php - - - # - # Uncomment the following lines to allow PHP to pretty-print .phps - # files as PHP source code: - # - # - # SetHandler application/x-httpd-php-source - # - - # - # Apache specific PHP configuration options - # those can be override in each configured vhost - # - php_value session.save_handler "files" - php_value session.save_path "/var/lib/php/7.1/session" - php_value soap.wsdl_cache_dir "/var/lib/php/7.1/wsdlcache" - - #php_value opcache.file_cache "/var/lib/php/7.1/opcache" - - -# Redirect to local php-fpm if mod_php is not available - - - # Enable http authorization headers - SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1 - - - SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost" - - - diff --git a/configuration/environments_scripts/central_reverse_proxy/files/home/httpdConf/repo.git/hooks/post-receive b/configuration/environments_scripts/central_reverse_proxy/files/home/httpdConf/repo.git/hooks/post-receive index 16c1bfee771..2f40ad43553 100644 --- a/configuration/environments_scripts/central_reverse_proxy/files/home/httpdConf/repo.git/hooks/post-receive +++ b/configuration/environments_scripts/central_reverse_proxy/files/home/httpdConf/repo.git/hooks/post-receive @@ -5,22 +5,55 @@ # after the merge completes. The user, in which the bare repo and hook are installed, must have aws credentials, that # don't need mfa. (These may need to be installed manually -- within the correct user -- if starting from a clean instance.) -TAG="ReverseProxy" +DISPOSABLE_TAG="DisposableProxy" +CENTRAL_TAG="CentralReverseProxy" DIR="/etc/httpd" COMMAND="sudo service httpd reload" MAIN_BRANCH_NAME="main" +DISPOSABLE_BRANCH_NAME="disposable" +CENTRAL_BRANCH_NAME="central" +CHECKED_OUT_WORKSPACE_NAME="checked-out" # Assumes it is in the root user. +sync_repo() { + #$1 tag key to use + #$2 branch to check out + # Gets all public ips for the instances with the chosen tag and iterates over the IPs. + for IP in $(aws ec2 describe-instances --filters Name=tag-key,Values="${1}" | jq -r '.Reservations[].Instances[].PublicIpAddress'); do + # strictHostKey... means no authenticity check. The sync-repo... script must be installed in the root user's home. + echo $IP + ssh -o "StrictHostKeyChecking=no" -o "ConnectTimeout=10" root@${IP} "cd ~ && sync-repo-and-execute-cmd.sh '${DIR}' '${COMMAND}' '${2}'"; + done; +} +merge_main_into_branch() { + #$1 branch name. Assumes you are in the git repo. + git checkout "${1}" + git pull + echo "merging ${MAIN_BRANCH_NAME} into ${1}" + git merge ${MAIN_BRANCH_NAME} + git push +} while read oldrev newrev refname; do # These vars are passed on stdin to this hook. # Check if the update is on a branch if [[ $refname == "refs/heads/"* ]]; then branch_name=$(echo $refname | sed "s|refs/heads/\(.*\)$|\1|") echo "Update on branch: $branch_name" - if [[ "$branch_name" == "$MAIN_BRANCH_NAME" ]]; then - # Gets all public ips for the instances with the chosen tag and iterates over the IPs. - for IP in $(aws ec2 describe-instances --filters Name=tag-key,Values="${TAG}" | jq -r '.Reservations[].Instances[].PublicIpAddress'); do - # strictHostKey... means no authenticity check. The sync-repo... script must be installed in the root user's home. - echo "Connecting to $IP" - ssh -o "StrictHostKeyChecking=no" root@${IP} "cd ~ && /usr/local/bin/sync-repo-and-execute-cmd.sh '${DIR}' '${COMMAND}' "; - done + if [[ "$branch_name" == "$DISPOSABLE_BRANCH_NAME" ]]; then + echo "All the disposables pull the disposable branch" + sync_repo "${DISPOSABLE_TAG}" "${DISPOSABLE_BRANCH_NAME}" + elif [[ "$branch_name" == "$CENTRAL_BRANCH_NAME" ]]; then + echo "The central pulls the central branch" + sync_repo "${CENTRAL_TAG}" "${CENTRAL_BRANCH_NAME}" + elif [[ "$branch_name" == "$MAIN_BRANCH_NAME" ]]; then + cd ~ + unset GIT_DIR + cd ${CHECKED_OUT_WORKSPACE_NAME} + # get the latest main + git checkout ${MAIN_BRANCH_NAME} + git pull + # get the latest diposable branch and merge in changes + merge_main_into_branch "$DISPOSABLE_BRANCH_NAME" + # get the latest central branch and merge in changes + merge_main_into_branch "$CENTRAL_BRANCH_NAME" + git checkout ${MAIN_BRANCH_NAME} fi fi done \ No newline at end of file diff --git a/configuration/environments_scripts/repo/usr/local/bin/sync-repo-and-execute-cmd.sh b/configuration/environments_scripts/repo/usr/local/bin/sync-repo-and-execute-cmd.sh index e7b62c7dcaf..ba09a4f63d2 100755 --- a/configuration/environments_scripts/repo/usr/local/bin/sync-repo-and-execute-cmd.sh +++ b/configuration/environments_scripts/repo/usr/local/bin/sync-repo-and-execute-cmd.sh @@ -1,20 +1,27 @@ #!/bin/bash -# Purpose: This script goes to a given git dir (eg. httpd); fetches any new commits to -# the repo; and - if new commits are found - merges them into the branch and runs a command. +# Purpose: This script goes to a given git dir (eg. httpd); checks out a given branch; fetches any new commits to +# that given branch; and - if new commits are found - merges them into the branch and runs a command. if [ $# -eq 0 ]; then - echo "$0 PATH_TO_GIT_REPO COMMAND_TO_RUN_ON_COMPLETION_IN_REPO" + echo "$0 PATH_TO_GIT_REPO COMMAND_TO_RUN_ON_COMPLETION_IN_REPO BRANCH_TO_CHECK_OUT" echo "" echo "EXAMPLE: sync-repo-and-execute-cmd.sh \"/etc/httpd\" \"sudo service httpd reload\"" - echo "This script is used to automatically fetch from a git repo and, if there are new commits, merge the changes." - echo "And then run a command, passed as an argument." + echo "This script is used to automatically fetch the latest changes to a given branch of a git repo and," + echo "if there are new commits, merge the changes into that branch." + echo "And then run a command, passed as an argument. This leaves the repo checked out to the branch in the argument." exit 2 fi GIT_PATH=$1 COMMAND_ON_COMPLETION=$2 +GIT_BRANCH=$3 cd ${GIT_PATH} +git checkout ${GIT_BRANCH} >/dev/null 2>&1 +if [[ "$?" -ne 0 ]]; then + echo "Error encountered: issue checking out branch" + exit 1 +fi # Rev-parse gets the commit hash of given reference. CURRENT_HEAD=$(git rev-parse HEAD) GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no" git fetch @@ -22,17 +29,17 @@ if [[ "$?" -ne 0 ]]; then echo "Error encountered: issue with fetching or there is no repo." exit 1 fi -if [[ $CURRENT_HEAD != $(git rev-parse origin/main) ]] # Checks if there are new commits +if [[ $CURRENT_HEAD != "$(git rev-parse origin/${GIT_BRANCH})" ]] # Checks if there are new commits then logger -t httpd "Changes found; merging now" - cd ${GIT_PATH} && git merge origin/main + cd ${GIT_PATH} && git merge origin/${GIT_BRANCH} if [[ $? -eq 0 ]]; then logger -t httpdMerge "Merge succeeded: different files edited." else logger -t httpdMerge "First merge unsuccessful: same file modified." git merge --abort # Returns to pre-merge state. git stash - git merge origin/main # This should be a fast-forward merge. + git merge origin/${GIT_BRANCH} # This should be a fast-forward merge. git stash apply # Keeps stash on top of stack, in case the apply fails. if [[ $? -eq 0 ]]; then logger -t httpdMerge "Second merge success: merge of httpd remote to local successful, and previous working directory changes restored." @@ -47,6 +54,9 @@ then fi fi sleep 2 - ${COMMAND_ON_COMPLETION} -fi - + if httpd -t ; then + ${COMMAND_ON_COMPLETION} + else + logger -t httpdMerge "Config error" + fi +fi \ No newline at end of file diff --git a/configuration/environments_scripts/reverse_proxy/files/etc/systemd/system/get-latest-httpd-conf.service b/configuration/environments_scripts/reverse_proxy/files/etc/systemd/system/get-latest-httpd-conf.service index 57cf7ade0b9..f970e58daba 100644 --- a/configuration/environments_scripts/reverse_proxy/files/etc/systemd/system/get-latest-httpd-conf.service +++ b/configuration/environments_scripts/reverse_proxy/files/etc/systemd/system/get-latest-httpd-conf.service @@ -11,4 +11,4 @@ WantedBy=httpd.service [Service] Type=oneshot RemainAfterExit=true -ExecStart=/usr/local/bin/sync-repo-and-execute-cmd.sh "/etc/httpd" "echo synced" +ExecStart=/usr/local/bin/sync-repo-and-execute-cmd.sh "/etc/httpd" "echo synced" disposable diff --git a/configuration/environments_scripts/reverse_proxy/files/root/setupHttpdGitLocal.sh b/configuration/environments_scripts/reverse_proxy/files/root/setupHttpdGitLocal.sh index 0bf91980f16..fc3471db9de 100755 --- a/configuration/environments_scripts/reverse_proxy/files/root/setupHttpdGitLocal.sh +++ b/configuration/environments_scripts/reverse_proxy/files/root/setupHttpdGitLocal.sh @@ -12,7 +12,7 @@ if ! git status; then git init git remote add origin "${REMOTE}" GIT_SSH_COMMAND="ssh -A -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" git fetch - git checkout main + git checkout disposable fi echo "Use Status ${SELF_IP} internal-server-status" > /etc/httpd/conf.d/${STATUS_DEFINITION_FILE} cd /etc/httpd diff --git a/configuration/environments_scripts/reverse_proxy/files/usr/local/bin/register-deregister-from-nlb-target-group.sh b/configuration/environments_scripts/reverse_proxy/files/usr/local/bin/register-deregister-from-nlb-target-group.sh index ebabac1bf77..10af3444d70 100755 --- a/configuration/environments_scripts/reverse_proxy/files/usr/local/bin/register-deregister-from-nlb-target-group.sh +++ b/configuration/environments_scripts/reverse_proxy/files/usr/local/bin/register-deregister-from-nlb-target-group.sh @@ -10,7 +10,8 @@ if [[ -z "$selfIp" || -z "$availabilityZone" ]]; then availabilityZone=$(cat /var/cache/availability-zone) fi nlbName="HTTP-to-sapsailing-dot-com" -targetGroupArn=$(aws elbv2 describe-target-groups --name "${nlbName}" | jq -r ".TargetGroups[].TargetGroupArn") +# First we describe the target groups which are served by a load balancer, which has an ARN containing the substring "loadbalancer/net". Then, we get the tags of these target groups and iterate over the tag descriptions (a list of resourceArns paired with tags), selecting those resources which have a key "allReverseProxies". Finally we extract the resource ARN. Note: .[] means to iterate over an array. +targetGroupArn=$(aws elbv2 describe-tags --resource-arns $(aws elbv2 describe-target-groups | jq -r '.TargetGroups | .[] | select(.LoadBalancerArns | .[] | contains("loadbalancer/net") ) | .TargetGroupArn') | jq -r '.TagDescriptions | .[] | select(.Tags | any(.Key=="allReverseProxies") ) | .ResourceArn') if [[ "$#" -eq 0 ]];then echo "Use add-to-nlb OR remove-from-nlb as the first and only argument." exit 2 diff --git a/configuration/on-site-scripts/paris2024/compare-secondary-to-primary-master b/configuration/on-site-scripts/paris2024/compare-secondary-to-primary-master index 1b68603a143..a50632a7a84 100755 --- a/configuration/on-site-scripts/paris2024/compare-secondary-to-primary-master +++ b/configuration/on-site-scripts/paris2024/compare-secondary-to-primary-master @@ -1,6 +1,6 @@ #!/bin/bash -PRIMARY_MASTER=https://paris2024-master.sapsailing.com:9443 -SECONDARY_MASTER=https://paris2024-secondary-master.sapsailing.com:9443 +PRIMARY_MASTER=https://palma2024-master.sailing.omegatiming.com:9443 +SECONDARY_MASTER=https://palma2024-secondary-master.sailing.omegatiming.com:9443 COMPARE_OUTPUT=$( /home/sailing/code/java/target/compareServers -ael ${SECONDARY_MASTER} ${PRIMARY_MASTER} ) if [ "$?" != "0" ]; then echo "Comparing ${SECONDARY_MASTER} with ${PRIMARY_MASTER} showed differences: diff --git a/configuration/on-site-scripts/paris2024/monitor-paris2024-reachability-from-regions b/configuration/on-site-scripts/paris2024/monitor-paris2024-reachability-from-regions new file mode 100755 index 00000000000..419c7a684bd --- /dev/null +++ b/configuration/on-site-scripts/paris2024/monitor-paris2024-reachability-from-regions @@ -0,0 +1,34 @@ +#!/bin/bash +# Probe for valid AWS MFA token +EXPIRY_MARKER_FILE=/tmp/aws-mfa-token-expired +aws ec2 describe-instances >/dev/null 2>/dev/null +EXIT_CODE=$? +if [ "${EXIT_CODE}" = "255" ]; then + if [ ! -f "${EXPIRY_MARKER_FILE}" ]; then + message="AWS MFA token seems to have expired. aws ec2 describe-instances exited with code ${EXIT_CODE}. Not messaging you again. Try another awsmfa as root@sapsailing.com's tmux." + echo "${message}" | notify-operators "AWS MFA token expired" + touch "${EXPIRY_MARKER_FILE}" + else + echo "AWS MFA token expired, but we had sent e-mail already." + fi +else + # Discover replicas + IPs="" + for i in $( cat `dirname $0`/regions.txt ); do + IPs="$( aws --region $i ec2 describe-instances --filters Name=instance-state-name,Values=running Name=tag:sailing-analytics-server,Values=paris2024 | jq .Reservations[].Instances[].PublicIpAddress -r )" + if [ -z "${IPs}" ]; then + echo "Couldn't find a running replica in region $i" >&2 + message="Couldn't find a running replica in region $i" + echo "${message}" | notify-operators "${message}" + else + read first others <<<"${IPs}" + if ! ssh -o StrictHostKeyChecking=no root@${first} "curl https://palma2024.sailing.omegatiming.com/gwt/status 2>/dev/null >/dev/null"; then + echo "Problem reaching palma2024.sailing.omegatiming.com from instance ${first} in region ${i}" >&2 + message="Problem reaching palma2024.sailing.omegatiming.com from instance ${first} in region ${i}" + echo "${message}" | notify-operators "${message}" + else + echo "Access from region ${i}, IP ${first} OK." >&2 + fi + fi + done +fi diff --git a/configuration/on-site-scripts/paris2024/notify-operators b/configuration/on-site-scripts/paris2024/notify-operators index 37a0e26dea6..3d4cd41865d 100755 --- a/configuration/on-site-scripts/paris2024/notify-operators +++ b/configuration/on-site-scripts/paris2024/notify-operators @@ -1,5 +1,5 @@ #!/bin/bash #OPERATORS="axel.uhl@sap.com jan.hamann@sapsailing.com alessandro.stoltenberg@sap.com alstolten@gmail.com" -OPERATORS="axel.uhl@sap.com jan.hamann@sapsailing.com heather.allard@sap.com finn.huelsbusch@sap.com fabian.kallenbach@sap.com" +OPERATORS="axel.uhl@sap.com" logger -t sailing "Sending notification e-mail with subject $1 to ${OPERATORS}" mail -s "$1" ${OPERATORS} diff --git a/configuration/on-site-scripts/paris2024/upgrade-landscape.sh b/configuration/on-site-scripts/paris2024/upgrade-landscape.sh index 8b375cda21a..3f937e3ac78 100755 --- a/configuration/on-site-scripts/paris2024/upgrade-landscape.sh +++ b/configuration/on-site-scripts/paris2024/upgrade-landscape.sh @@ -1,9 +1,9 @@ #!/bin/bash # Upgrades the entire landscape of servers to a new release ${RELEASE} # The procedure works in the following steps: -# - patch *.conf files in sap-p1-1:servers/[master|security_service] and sap-p1-2:servers/[secondary_master|replica|master|security_service] so +# - patch *.conf files in sap-p1-1:servers/[master|security_service] and sap-p1-2:servers/[secondary_master|master|security_service] so # their INSTALL_FROM_RELEASE points to the new ${RELEASE} -# - Install new releases to sap-p1-1:servers/[master|security_service] and sap-p1-2:servers/[secondary_master|replica|master|security_service] +# - Install new releases to sap-p1-1:servers/[master|security_service] and sap-p1-2:servers/[secondary_master|master|security_service] # - Update all launch configurations and auto-scaling groups in the cloud (update-launch-configuration.sh) # - Tell all replicas in the cloud to stop replicating (stop-all-cloud-replicas.sh) # - Tell sap-p1-2 secondary_master to restart (./stop; ./start) @@ -29,9 +29,9 @@ if [ $# -eq 0 ]; then echo "Example: $0 -R build-202106041327 -k Jan" echo "The procedure works in the following steps:" - echo " - patch *.conf files in sap-p1-1:servers/[master|security_service] and sap-p1-2:servers/[secondary_master|replica|master|security_service] so" + echo " - patch *.conf files in sap-p1-1:servers/[master|security_service] and sap-p1-2:servers/[secondary_master|master|security_service] so" echo " their INSTALL_FROM_RELEASE points to the new ${RELEASE}" - echo " - Install new releases to sap-p1-1:servers/[master|security_service] and sap-p1-2:servers/[secondary_master|replica|master|security_service]" + echo " - Install new releases to sap-p1-1:servers/[master|security_service] and sap-p1-2:servers/[secondary_master|master|security_service]" echo " - Update all launch configurations and auto-scaling groups in the cloud (update-launch-configuration.sh)" echo " - Tell all replicas in the cloud to stop replicating (stop-all-cloud-replicas.sh)" echo " - Tell sap-p1-2 secondary_master to restart (./stop; ./start)" @@ -76,7 +76,6 @@ echo " * Patching configurations on sap-p1-1 and sap-p1-2 to new release ${RELEA patch_conf_and_install sap-p1-1 master patch_conf_and_install sap-p1-1 security_service patch_conf_and_install sap-p1-2 secondary_master -patch_conf_and_install sap-p1-2 replica patch_conf_and_install sap-p1-2 master patch_conf_and_install sap-p1-2 security_service echo " * Updating launch configurations and auto-scaling groups" diff --git a/java/com.amazon.aws.aws-java-api.updatesite/features/aws-sdk/feature.xml b/java/com.amazon.aws.aws-java-api.updatesite/features/aws-sdk/feature.xml index bd6f05f04c4..b0c630542b0 100755 --- a/java/com.amazon.aws.aws-java-api.updatesite/features/aws-sdk/feature.xml +++ b/java/com.amazon.aws.aws-java-api.updatesite/features/aws-sdk/feature.xml @@ -2,21 +2,21 @@ diff --git a/java/com.amazon.aws.aws-java-api.updatesite/site.xml b/java/com.amazon.aws.aws-java-api.updatesite/site.xml index 59efaa49f54..89de24f3c6b 100755 --- a/java/com.amazon.aws.aws-java-api.updatesite/site.xml +++ b/java/com.amazon.aws.aws-java-api.updatesite/site.xml @@ -1,6 +1,6 @@ - + diff --git a/java/com.amazon.aws.aws-java-api/build.gradle b/java/com.amazon.aws.aws-java-api/build.gradle index 200850cb831..0e2b52c5004 100644 --- a/java/com.amazon.aws.aws-java-api/build.gradle +++ b/java/com.amazon.aws.aws-java-api/build.gradle @@ -5,7 +5,7 @@ repositories { } dependencies { - implementation platform('software.amazon.awssdk:bom:2.20.59') + implementation platform('software.amazon.awssdk:bom:2.25.11') implementation 'software.amazon.awssdk:s3' implementation 'software.amazon.awssdk:lambda' implementation 'software.amazon.awssdk:ec2' diff --git a/java/com.amazon.aws.aws-java-api/pom.xml b/java/com.amazon.aws.aws-java-api/pom.xml index 9d3b9d04299..b4e4179ead1 100644 --- a/java/com.amazon.aws.aws-java-api/pom.xml +++ b/java/com.amazon.aws.aws-java-api/pom.xml @@ -16,7 +16,7 @@ com.amazon.aws com.amazon.aws.aws-java-api - 2.20.59 + 2.25.11 eclipse-plugin diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceFetcher.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceFetcher.java index f653a004445..b4c003a4b5a 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceFetcher.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceFetcher.java @@ -8,6 +8,8 @@ public interface RaceFetcher { /** * Not for execution on the client; on the server, returns a TrackedRace object. + * The method will not block or wait for the tracked race to appear. If it isn't found (see also + * bug 5982) then {@code null} is returned. */ Object getTrackedRace(RegattaAndRaceIdentifier regattaNameAndRaceName); diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceIdentifier.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceIdentifier.java index eec7eb20fe6..64726099842 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceIdentifier.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceIdentifier.java @@ -9,11 +9,6 @@ public interface RaceIdentifier extends Serializable { Object getRace(RaceFetcher raceFetcher); - /** - * Blocks and waits if the tracked race for this race identifier doesn't exist yet. - */ - Object getTrackedRace(RaceFetcher raceFetcher); - /** * Immediately returns null if the tracked race for this race identifier doesn't exist yet. */ diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RegattaNameAndRaceName.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RegattaNameAndRaceName.java index bb92cbe9810..9e9be86c82b 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RegattaNameAndRaceName.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RegattaNameAndRaceName.java @@ -24,10 +24,6 @@ public class RegattaNameAndRaceName extends RegattaName implements RegattaAndRac return raceFetcher.getRace(this); } @Override - public Object getTrackedRace(RaceFetcher raceFetcher) { - return raceFetcher.getTrackedRace(this); - } - @Override public Object getExistingTrackedRace(RaceFetcher raceFetcher) { return raceFetcher.getExistingTrackedRace(this); } diff --git a/java/com.sap.sailing.domain.tractracadapter.persistence/src/com/sap/sailing/domain/tractracadapter/persistence/impl/TracTracConnectivityParamsHandler.java b/java/com.sap.sailing.domain.tractracadapter.persistence/src/com/sap/sailing/domain/tractracadapter/persistence/impl/TracTracConnectivityParamsHandler.java index 4c0c9a182a1..86fa9a41358 100644 --- a/java/com.sap.sailing.domain.tractracadapter.persistence/src/com/sap/sailing/domain/tractracadapter/persistence/impl/TracTracConnectivityParamsHandler.java +++ b/java/com.sap.sailing.domain.tractracadapter.persistence/src/com/sap/sailing/domain/tractracadapter/persistence/impl/TracTracConnectivityParamsHandler.java @@ -154,6 +154,7 @@ public class TracTracConnectivityParamsHandler extends AbstractRaceTrackingConne } else { final String creatorName = SessionUtils.getPrincipal().toString(); final TracTracConfigurationImpl tracTracConfiguration = new TracTracConfigurationImpl(creatorName, tractracRace.getEvent().getName(), jsonURL, + // FIXME bug5983: stored/live URIs should be captured in the configuration only if they were specified explicitly when the parameters were created (params.getLiveURI() == null ? null : params.getLiveURI().toString()), /* stored URI */ params.isReplayRace(tractracRace) ? null // we mainly want to enable the user to list the event's races again in case they are removed; : (params.getStoredURI() == null ? null : params.getStoredURI().toString()), // live/stored stuff comes from the tracking params diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java index 7b34172e5d6..e5a27ec8902 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java @@ -219,12 +219,16 @@ public abstract class TrackedRegattaImpl implements TrackedRegatta { public void raceAdded(TrackedRace trackedRace) { synchronized (mutex) { // TODO possible improvement: only notify if trackedRace.getRace() == race; otherwise it cannot have made a difference for getExistingTrackedRace(race)... mutex.notifyAll(); - } // TODO can't we remove the listener again here? + } } }; addRaceListener(listener, Optional.empty(), /* synchronous */ false); try { synchronized (mutex) { + if (getRegatta().getRaceByName(race.getName()) == null) { + throw new IllegalStateException("Race "+race.getName()+" not in regatta "+getRegatta().getName()+ + "; not blocking for it to appear. It most likely won't"); + } result = getExistingTrackedRace(race); while (!interrupted && result == null) { try { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/sixtyinch/GetSixtyInchStatisticAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/sixtyinch/GetSixtyInchStatisticAction.java index fd1f38db42b..2f39aa6d0c8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/sixtyinch/GetSixtyInchStatisticAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/sixtyinch/GetSixtyInchStatisticAction.java @@ -55,19 +55,19 @@ public class GetSixtyInchStatisticAction implements SailingAction competitorIterator = trace.getCompetitorsFromBestToWorst(trace.getEndOfRace()).iterator(); + final Iterator competitorIterator = trackedRace.getCompetitorsFromBestToWorst(trackedRace.getEndOfRace()).iterator(); if (competitorIterator.hasNext()) { - distance = trace.getDistanceTraveled(competitorIterator.next(), trace.getEndOfRace()); - duration = trace.getStartOfRace().until(trace.getEndOfRace()); + distance = trackedRace.getDistanceTraveled(competitorIterator.next(), trackedRace.getEndOfRace()); + duration = trackedRace.getStartOfRace().until(trackedRace.getEndOfRace()); } } return new GetSixtyInchStatisticDTO(competitors, legs, duration, distance); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/QuickRanksLiveCache.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/QuickRanksLiveCache.java index c1c5b94f764..c51cc24e208 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/QuickRanksLiveCache.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/QuickRanksLiveCache.java @@ -128,7 +128,7 @@ public class QuickRanksLiveCache { public QuickRanksDTO get(RegattaAndRaceIdentifier raceIdentifier) { QuickRanksDTO result = cache.get(raceIdentifier, false); if (result == null) { - TrackedRace trackedRace = service.getExistingTrackedRace(raceIdentifier); + final TrackedRace trackedRace = service.getExistingTrackedRace(raceIdentifier); if (trackedRace != null) { trackedRace.addListener(new Listener(raceIdentifier)); // register for all changes that may affect the quick ranks cache.triggerUpdate(raceIdentifier, CalculateOrPurge.CALCULATE); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 49a1890747a..c816dcfb732 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -662,7 +662,6 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet * Stops this service and frees its resources. In particular, caching services and threads owned by this service will be * notified to stop their jobs. */ - //UNCLEAR public void stop() { quickRanksLiveCache.stop(); } @@ -1632,7 +1631,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet @Override public SimulatorResultsDTO getSimulatorResults(LegIdentifier legIdentifier) { - DynamicTrackedRace trackedRace = getService().getTrackedRace(legIdentifier.getRaceIdentifier()); + final DynamicTrackedRace trackedRace = getService().getTrackedRace(legIdentifier.getRaceIdentifier()); if (trackedRace == null) { throw new IllegalArgumentException("Race for leg " + legIdentifier + " not found!"); } @@ -3346,10 +3345,12 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet @Override public DynamicTrackedRace getTrackedRace(RegattaAndRaceIdentifier regattaNameAndRaceName) { - Regatta regatta = getService().getRegattaByName(regattaNameAndRaceName.getRegattaName()); - RaceDefinition race = getRaceByName(regatta, regattaNameAndRaceName.getRaceName()); - DynamicTrackedRace trackedRace = getService().getOrCreateTrackedRegatta(regatta).getTrackedRace(race); - getSecurityService().checkCurrentUserReadPermission(trackedRace); + final Regatta regatta = getService().getRegattaByName(regattaNameAndRaceName.getRegattaName()); + final RaceDefinition race = getRaceByName(regatta, regattaNameAndRaceName.getRaceName()); + final DynamicTrackedRace trackedRace = getService().getOrCreateTrackedRegatta(regatta).getExistingTrackedRace(race); + if (trackedRace != null) { + getSecurityService().checkCurrentUserReadPermission(trackedRace); + } return trackedRace; } @@ -5637,9 +5638,9 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet public Boolean checkIfRaceIsTracking(RegattaAndRaceIdentifier race) { getSecurityService().checkCurrentUserReadPermission(race); boolean result = false; - DynamicTrackedRace trace = getService().getTrackedRace(race); - if (trace != null) { - final TrackedRaceStatusEnum status = trace.getStatus().getStatus(); + DynamicTrackedRace trackedRace = getService().getTrackedRace(race); + if (trackedRace != null) { + final TrackedRaceStatusEnum status = trackedRace.getStatus().getStatus(); if (status == TrackedRaceStatusEnum.LOADING || status == TrackedRaceStatusEnum.TRACKING) { result = true; } @@ -6387,22 +6388,25 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet @Override public boolean canSliceRace(RegattaAndRaceIdentifier raceIdentifier) { + final boolean result; final Regatta regatta = getService().getRegattaByName(raceIdentifier.getRegattaName()); final Leaderboard regattaLeaderboard = getService().getLeaderboardByName(raceIdentifier.getRegattaName()); final DynamicTrackedRace trackedRace = getService().getTrackedRace(raceIdentifier); - getSecurityService().checkCurrentUserUpdatePermission(raceIdentifier); - getSecurityService().checkCurrentUserUpdatePermission(regattaLeaderboard); - getSecurityService().checkCurrentUserUpdatePermission(regatta); - - final boolean result; - if (regatta == null || !(regattaLeaderboard instanceof RegattaLeaderboard) || trackedRace == null - || trackedRace.getStartOfTracking() == null || !isSmartphoneTrackingEnabled(trackedRace)) { + if (trackedRace == null ) { result = false; } else { - final Pair raceColumnAndFleetOfRaceToSlice = regattaLeaderboard - .getRaceColumnAndFleet(trackedRace); - result = (raceColumnAndFleetOfRaceToSlice != null); // is the TrackedRace associated to the given - // RegattaLeaderboard? + getSecurityService().checkCurrentUserUpdatePermission(raceIdentifier); + getSecurityService().checkCurrentUserUpdatePermission(regattaLeaderboard); + getSecurityService().checkCurrentUserUpdatePermission(regatta); + if (regatta == null || !(regattaLeaderboard instanceof RegattaLeaderboard) || trackedRace == null + || trackedRace.getStartOfTracking() == null || !isSmartphoneTrackingEnabled(trackedRace)) { + result = false; + } else { + final Pair raceColumnAndFleetOfRaceToSlice = regattaLeaderboard + .getRaceColumnAndFleet(trackedRace); + result = (raceColumnAndFleetOfRaceToSlice != null); // is the TrackedRace associated to the given + // RegattaLeaderboard? + } } return result; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceWriteImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceWriteImpl.java index 3394f9b076b..2866553efc0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceWriteImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceWriteImpl.java @@ -2105,11 +2105,13 @@ public class SailingServiceWriteImpl extends SailingServiceImpl implements Saili final List trackedRaces = new ArrayList<>(); if (selectedRaces != null && !selectedRaces.isEmpty()) { for (RaceDTO raceDTO : selectedRaces) { - DynamicTrackedRace trackedRace = getTrackedRace(raceDTO.getRaceIdentifier()); - // In case the user selected a distinct set of races, we want the call to completely fail if - // tracking wind isn't allowed for at least one race - getSecurityService().checkCurrentUserUpdatePermission(trackedRace); - trackedRaces.add(trackedRace); + final DynamicTrackedRace trackedRace = getTrackedRace(raceDTO.getRaceIdentifier()); + if (trackedRace != null) { + // In case the user selected a distinct set of races, we want the call to completely fail if + // tracking wind isn't allowed for at least one race + getSecurityService().checkCurrentUserUpdatePermission(trackedRace); + trackedRaces.add(trackedRace); + } } } else { for (DynamicTrackedRace race : getAllTrackedRaces()) { @@ -2601,11 +2603,13 @@ public class SailingServiceWriteImpl extends SailingServiceImpl implements Saili public RaceDTO setStartTimeReceivedForRace(RaceIdentifier raceIdentifier, Date newStartTimeReceived) { RegattaNameAndRaceName regattaAndRaceIdentifier = new RegattaNameAndRaceName(raceIdentifier.getRegattaName(), raceIdentifier.getRaceName()); - DynamicTrackedRace trackedRace = getService().getTrackedRace(regattaAndRaceIdentifier); - getSecurityService().checkCurrentUserUpdatePermission(trackedRace); - trackedRace.setStartTimeReceived( - newStartTimeReceived == null ? null : new MillisecondsTimePoint(newStartTimeReceived)); - return baseDomainFactory.createRaceDTO(getService(), false, regattaAndRaceIdentifier, trackedRace); + final DynamicTrackedRace trackedRace = getService().getTrackedRace(regattaAndRaceIdentifier); + if (trackedRace != null) { + getSecurityService().checkCurrentUserUpdatePermission(trackedRace); + trackedRace.setStartTimeReceived( + newStartTimeReceived == null ? null : new MillisecondsTimePoint(newStartTimeReceived)); + } + return trackedRace == null ? null : baseDomainFactory.createRaceDTO(getService(), false, regattaAndRaceIdentifier, trackedRace); } @Override @@ -2958,6 +2962,8 @@ public class SailingServiceWriteImpl extends SailingServiceImpl implements Saili throw new ServiceException(serverStringMessages.get(locale, "slicingRaceColumnAlreadyUsedThe")); } final DynamicTrackedRace trackedRaceToSlice = getService().getTrackedRace(raceIdentifier); + // If tracked race isn't found, a NullPointerException will be thrown next, and that's okay because + // it's a bit unusual to not find a race that is just about to be sliced. We couldn't continue anyway. final TimePoint startOfTrackingOfRaceToSlice = trackedRaceToSlice.getStartOfTracking(); final TimePoint endOfTrackingOfRaceToSlice = trackedRaceToSlice.getEndOfTracking(); if (sliceFrom == null || sliceTo == null || startOfTrackingOfRaceToSlice.after(sliceFrom) @@ -2997,7 +3003,6 @@ public class SailingServiceWriteImpl extends SailingServiceImpl implements Saili hasFinishingTime = false; hasFinishedTime = false; } - // Only wind fixes in the new tracking interval as well as the best fallback fixes are added to the new RaceLog final LogEventTimeRangeWithFallbackFilter windFixEvents = new LogEventTimeRangeWithFallbackFilter<>( timeRange); diff --git a/java/com.sap.sailing.ingestion/META-INF/MANIFEST.MF b/java/com.sap.sailing.ingestion/META-INF/MANIFEST.MF index 5b97d82cb5a..5861f3d60eb 100644 --- a/java/com.sap.sailing.ingestion/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.ingestion/META-INF/MANIFEST.MF @@ -8,7 +8,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Require-Bundle: com.sap.sailing.domain.common, org.junit;bundle-version="4.8.2", com.amazon.aws.aws-java-api;bundle-version="2.17.124", - redisson;bundle-version="3.17.7", + redisson;bundle-version="3.27.1", com.amazonaws.aws-lambda-java-core;bundle-version="1.2.1" Bundle-ActivationPolicy: lazy Import-Package: javax.servlet;version="3.1.0" diff --git a/java/com.sap.sailing.ingestion/pom.xml b/java/com.sap.sailing.ingestion/pom.xml index bdbcbac498c..e97a851dc47 100755 --- a/java/com.sap.sailing.ingestion/pom.xml +++ b/java/com.sap.sailing.ingestion/pom.xml @@ -64,7 +64,7 @@ org.redisson redisson - 3.14.0 + 3.27.1 software.amazon.awssdk diff --git a/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/Configuration.java b/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/Configuration.java index fa3d07a47c1..ee5ce2e412d 100644 --- a/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/Configuration.java +++ b/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/Configuration.java @@ -7,11 +7,11 @@ public interface Configuration { * This host is only reachable through VPC and therefore one needs to ensure that the Lambda has all relevant * permissions */ - String[] REDIS_ENDPOINTS = { "redis://fixingestionrediscache-serverless-cvoblp.serverless.euw2.cache.amazonaws.com:6379" }; + String[] REDIS_ENDPOINTS = { "rediss://fixingestionrediscache-serverless-cvoblp.serverless.euw2.cache.amazonaws.com:6379" }; String REDIS_MAP_NAME = "endpoints"; Region S3_REGION = Region.EU_WEST_2; String S3_BUCKET_NAME = "sapsailing-gps-fixes"; - int TIMEOUT_IN_SECONDS_WHEN_DISPATCHING_TO_ENDPOINT = 3; + int TIMEOUT_IN_SECONDS_WHEN_DISPATCHING_TO_ENDPOINT = 30; } diff --git a/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/EndpointRegistrationLambda.java b/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/EndpointRegistrationLambda.java index 054f3c209fd..70d411906c2 100644 --- a/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/EndpointRegistrationLambda.java +++ b/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/EndpointRegistrationLambda.java @@ -82,7 +82,7 @@ public class EndpointRegistrationLambda implements RequestStreamHandler { outputAsStream.write(successResponse.getBytes()); } catch (ParseException | JsonDeserializationException e) { context.getLogger().log("Exception trying to deserialize JSON input: " + e.getMessage()); - } catch (IOException ex) { + } catch (Exception ex) { context.getLogger().log(ex.getMessage()); } finally { try { diff --git a/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/FixIngestionLambda.java b/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/FixIngestionLambda.java index 1a6c66b6b69..f2b0da5e7a2 100644 --- a/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/FixIngestionLambda.java +++ b/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/FixIngestionLambda.java @@ -70,20 +70,19 @@ public class FixIngestionLambda implements RequestStreamHandler { }); final List listOfEndpointsToTrigger = cacheMap.get(deviceIdentifier.getStringRepresentation()); if (listOfEndpointsToTrigger != null) { - final List endpointsToTrigger = listOfEndpointsToTrigger; - for (final EndpointDTO endpoint : endpointsToTrigger) { + for (final EndpointDTO endpoint : listOfEndpointsToTrigger) { dispatchToSubscribersTask.submit(() -> { dispatchToSubscribers(endpoint, bodyAsBytes); }); } - // wait for tasks to complete for *+ - dispatchToSubscribersTask.awaitQuiescence( - (endpointsToTrigger.size() * Configuration.TIMEOUT_IN_SECONDS_WHEN_DISPATCHING_TO_ENDPOINT) + 2, - TimeUnit.SECONDS); } else { - logger.info("No endpoint has been configured for Identifier " + deviceIdentifier.getStringRepresentation()); + logger.info("No endpoint has been configured for identifier " + deviceIdentifier.getStringRepresentation()); } - String successResponse = awsInOut.createJsonResponse(deviceIdentifier.getStringRepresentation()).toJSONString(); + // wait for tasks to complete for *+ + dispatchToSubscribersTask.awaitQuiescence( + (listOfEndpointsToTrigger==null?0:listOfEndpointsToTrigger.size() * Configuration.TIMEOUT_IN_SECONDS_WHEN_DISPATCHING_TO_ENDPOINT) + 2, + TimeUnit.SECONDS); + final String successResponse = awsInOut.createJsonResponse(deviceIdentifier.getStringRepresentation()).toJSONString(); logger.info(successResponse); outputAsStream.write(successResponse.getBytes()); } catch (ParseException | JsonDeserializationException e) { @@ -106,9 +105,8 @@ public class FixIngestionLambda implements RequestStreamHandler { private void dispatchToSubscribers(final EndpointDTO endpoint, final byte[] jsonAsBytes) { logger.info("Connecting to endpoint " + endpoint.getEndpointCallbackUrl() + " with ID " + endpoint.getEndpointUuid()); - URL endpointUrl; try { - endpointUrl = new URL(endpoint.getEndpointCallbackUrl()); + final URL endpointUrl = new URL(endpoint.getEndpointCallbackUrl()); try { final HttpURLConnection connectionToEndpoint = (HttpURLConnection) endpointUrl.openConnection(); connectionToEndpoint.setRequestMethod("POST"); @@ -134,16 +132,21 @@ public class FixIngestionLambda implements RequestStreamHandler { private void storeFixFileToS3(final DeviceIdentifier deviceIdentifier, final List newFixes) throws IOException { - final String dataAsString = newFixes.toString(); - logger.info("Data to write: " + dataAsString); - for (GPSFixMoving fix : newFixes) { - final String destinationKey = s3FixStorageStructure.generateKeyForSingleFix(deviceIdentifier, fix.getTimePoint()); - logger.info("Location: " + destinationKey); - final PutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(Configuration.S3_BUCKET_NAME) - .key(destinationKey).contentType("application/json").build(); - final JSONObject serializedFix = gpsFixSerializer.serialize(fix); - s3Client.putObject(putObjectRequest, RequestBody.fromString(serializedFix.toJSONString())); + try { + final String dataAsString = newFixes.toString(); + logger.info("Data to write: " + dataAsString); + for (GPSFixMoving fix : newFixes) { + final String destinationKey = s3FixStorageStructure.generateKeyForSingleFix(deviceIdentifier, fix.getTimePoint()); + logger.info("Location: " + destinationKey); + final PutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(Configuration.S3_BUCKET_NAME) + .key(destinationKey).contentType("application/json").build(); + final JSONObject serializedFix = gpsFixSerializer.serialize(fix); + s3Client.putObject(putObjectRequest, RequestBody.fromString(serializedFix.toJSONString())); + } + logger.info("Finished putting object into S3"); + } catch (Throwable e) { + logger.log(Level.SEVERE, "Error writing GPS fix to S3: "+e.getMessage(), e); + throw e; } - logger.info("Finished putting object into S3"); } } diff --git a/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/RedisUtils.java b/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/RedisUtils.java index ef698e7b1fa..9945258e8c7 100644 --- a/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/RedisUtils.java +++ b/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/RedisUtils.java @@ -1,5 +1,6 @@ package com.sap.sailing.ingestion; +import java.util.Arrays; import java.util.List; import org.redisson.Redisson; @@ -14,7 +15,7 @@ public class RedisUtils { static { final Config redisConfiguration = new Config(); - redisConfiguration.useReplicatedServers().addNodeAddress(Configuration.REDIS_ENDPOINTS); + redisConfiguration.useClusterServers().setNodeAddresses(Arrays.asList(Configuration.REDIS_ENDPOINTS)); redisClient = Redisson.create(redisConfiguration); } diff --git a/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/S3FixStorageStructure.java b/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/S3FixStorageStructure.java index c26671c747e..4a2a89f9108 100644 --- a/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/S3FixStorageStructure.java +++ b/java/com.sap.sailing.ingestion/src/main/java/com/sap/sailing/ingestion/S3FixStorageStructure.java @@ -10,9 +10,10 @@ import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimeRange; -import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.TimeRangeImpl; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; + /** * This class defines the organization structure of fixes on the S3 storage and is the foundation for all the AWS Lambda * operations. The basic structure distinguishes single fixes which are inserted by the {@link FixIngestionLambda} and @@ -35,7 +36,7 @@ public class S3FixStorageStructure { private static final String SINGLE_FIX_PREFIX = "ingestion"; private static final String COLLECTION_PREFIX = "collection"; private static final String S3_DELIMITER = "/"; - private static final Duration COLLECTION_DURATION = new MillisecondsDurationImpl(600_000); + private static final Duration COLLECTION_DURATION = Duration.ONE_MINUTE.times(10l); private static final int SINGLE_FIX_BATCH_SIZE = 10; /** @@ -205,7 +206,7 @@ public class S3FixStorageStructure { final String collectionName = String.format("%02d:%02d:%02d.%03d-UTC.json", calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND), calendar.get(Calendar.MILLISECOND)); final String year = String.format("%04d", calendar.get(Calendar.YEAR)); - final String month = String.format("%02d", calendar.get(Calendar.MONTH)); + final String month = String.format("%02d", calendar.get(Calendar.MONTH)+1); final String dayOfMonth = String.format("%02d", calendar.get(Calendar.DATE)); final String generatedKey = combineElementsToKey(prefix, deviceIdentifier.getStringRepresentation(), year, month, dayOfMonth, collectionName); diff --git a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/LandscapeServiceImpl.java b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/LandscapeServiceImpl.java index be6cde462e9..b190df864a4 100644 --- a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/LandscapeServiceImpl.java +++ b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/LandscapeServiceImpl.java @@ -480,7 +480,7 @@ public class LandscapeServiceImpl implements LandscapeService { Util.addAll(eids, eventIDs); } final ReverseProxy, RotatingFileBasedLog> reverseProxyCluster = - getLandscape().getReverseProxyCluster(region); + getLandscape().getCentralReverseProxy(region); // TODO bug5311: when refactoring this for general scope migration, moving to a dedicated replica set will not require this // TODO bug5311: when refactoring this for general scope migration, moving into a cold storage server other than ARCHIVE will require ALBToReverseProxyRedirectMapper instead logger.info("Adding reverse proxy rules for migrated content pointing to ARCHIVE"); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/SailingServerHttpServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/SailingServerHttpServlet.java index 65c34508e89..febc4d94aef 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/SailingServerHttpServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/SailingServerHttpServlet.java @@ -10,7 +10,6 @@ import org.osgi.util.tracker.ServiceTracker; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; -import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tractracadapter.TracTracAdapterFactory; import com.sap.sailing.server.interfaces.RacingEventService; import com.sap.sse.InvalidDateException; @@ -135,16 +134,6 @@ public abstract class SailingServerHttpServlet extends HttpServlet { return timePoint; } - protected TrackedRace getTrackedRace(HttpServletRequest req) { - Regatta regatta = getRegatta(req); - RaceDefinition race = getRaceDefinition(req); - TrackedRace trackedRace = null; - if (regatta != null && race != null) { - trackedRace = getService().getOrCreateTrackedRegatta(regatta).getTrackedRace(race); - } - return trackedRace; - } - protected TypeBasedServiceFinderFactory getServiceFinderFactory() { return serviceFinderFactory; } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java index 699336cad22..a43617be1a3 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -1429,7 +1429,7 @@ public class RegattasResource extends AbstractSailingServerResource { if (race == null) { response = getBadRaceErrorResponse(regattaName, raceName); } else { - DynamicTrackedRace trackedRace = getService().getTrackedRace(regatta, race); + final DynamicTrackedRace trackedRace = getService().getTrackedRace(regatta, race); if (trackedRace != null) { TargetTimeInfo targetTime; try { diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/WindResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/WindResource.java index 9a0eb035c9a..84c0f029d82 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/WindResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/WindResource.java @@ -107,7 +107,10 @@ public class WindResource extends AbstractSailingServerResource { RegattaNameAndRaceName identifier = new RegattaNameAndRaceName(regattaName, raceName); // add wind only to those races the subject is permitted to update if (getSecurityService().hasCurrentUserUpdatePermission(identifier)) { - result.add(new RaceIdentifierAndTrackedRace(identifier, getService().getTrackedRace(identifier))); + final DynamicTrackedRace trackedRace = getService().getTrackedRace(identifier); + if (trackedRace != null) { + result.add(new RaceIdentifierAndTrackedRace(identifier, trackedRace)); + } } } } else { diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/ExpeditionAllInOneImporter.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/ExpeditionAllInOneImporter.java index 5664844308b..12fa5926002 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/ExpeditionAllInOneImporter.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/ExpeditionAllInOneImporter.java @@ -365,31 +365,34 @@ public class ExpeditionAllInOneImporter { securityService.checkCurrentUserExplicitPermissions(service.getRegatta(new RegattaName(regattaNameAndleaderboardName)), DefaultActions.UPDATE); securityService.checkCurrentUserExplicitPermissions(service.getLeaderboardByName(regattaNameAndleaderboardName), DefaultActions.UPDATE); if (importMode == ImportMode.NEW_COMPETITOR) { - securityService.checkCurrentUserExplicitPermissions(service.getTrackedRace(new RegattaNameAndRaceName(regattaNameAndleaderboardName, trackedRaceName)), DefaultActions.UPDATE); - final TimePointsOfFirstAndLastFix firstAndLastFixAt = importFixes(filenameWithSuffix, fileItem, jsonHolderForGpsFixImport, jsonHolderForSensorFixImport, errors); - ensureEventLongEnough(firstAndLastFixAt.getFirstFixAt(), firstAndLastFixAt.getLastFixAt(), eventId); - final Iterable raceColumns = regattaLeaderboard.getRaceColumns(); - if (Util.isEmpty(raceColumns)) { - return new ImporterResult(serverStringMessages.get(uiLocale, "allInOneErrorInvalidRace")); - } - try { - for (RaceColumn raceColumn : raceColumns) { - final Iterable fleets = raceColumn.getFleets(); - if (Util.size(fleets) != 1) { - return new ImporterResult(serverStringMessages.get(uiLocale, "allInOneErrorSplitFleetNotSupported")); + final DynamicTrackedRace trackedRace = service.getTrackedRace(new RegattaNameAndRaceName(regattaNameAndleaderboardName, trackedRaceName)); + if (trackedRace != null) { + securityService.checkCurrentUserExplicitPermissions(trackedRace, DefaultActions.UPDATE); + final TimePointsOfFirstAndLastFix firstAndLastFixAt = importFixes(filenameWithSuffix, fileItem, jsonHolderForGpsFixImport, jsonHolderForSensorFixImport, errors); + ensureEventLongEnough(firstAndLastFixAt.getFirstFixAt(), firstAndLastFixAt.getLastFixAt(), eventId); + final Iterable raceColumns = regattaLeaderboard.getRaceColumns(); + if (Util.isEmpty(raceColumns)) { + return new ImporterResult(serverStringMessages.get(uiLocale, "allInOneErrorInvalidRace")); + } + try { + for (RaceColumn raceColumn : raceColumns) { + final Iterable fleets = raceColumn.getFleets(); + if (Util.size(fleets) != 1) { + return new ImporterResult(serverStringMessages.get(uiLocale, "allInOneErrorSplitFleetNotSupported")); + } + final Fleet fleet = fleets.iterator().next(); + DynamicTrackedRace trackedRaceForColumn = (DynamicTrackedRace) raceColumn.getTrackedRace(fleet); + if (trackedRaceForColumn == null) { + trackedRaceForColumn = trackRace(regattaLeaderboard, raceColumn, fleet); + } + trackedRaces.add(trackedRaceForColumn); + raceNameRaceColumnNameFleetnameList + .add(new Triple<>(trackedRaceForColumn.getRaceIdentifier().getRaceName(), + raceColumn.getName(), fleet.getName())); } - final Fleet fleet = fleets.iterator().next(); - DynamicTrackedRace trackedRaceForColumn = (DynamicTrackedRace) raceColumn.getTrackedRace(fleet); - if (trackedRaceForColumn == null) { - trackedRaceForColumn = trackRace(regattaLeaderboard, raceColumn, fleet); - } - trackedRaces.add(trackedRaceForColumn); - raceNameRaceColumnNameFleetnameList - .add(new Triple<>(trackedRaceForColumn.getRaceIdentifier().getRaceName(), - raceColumn.getName(), fleet.getName())); + } catch (Exception e) { + throw new AllInOneImportException(e, errors); } - } catch (Exception e) { - throw new AllInOneImportException(e, errors); } } else if (importMode == ImportMode.NEW_RACE) { // When uploading files with identical name, the second RaceColumn will be named with the upload time in its name diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/TrackFilesExportPostServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/TrackFilesExportPostServlet.java index 2dcab62e67a..7ff55f296e2 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/TrackFilesExportPostServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/TrackFilesExportPostServlet.java @@ -28,32 +28,34 @@ public class TrackFilesExportPostServlet extends SailingServerHttpServlet { private static final Logger log = Logger.getLogger(TrackFilesExportPostServlet.class.toString()); private TrackedRace getTrackedRace(String regattaString, String raceString) { - Regatta regatta = getService().getRegattaByName(regattaString); - if (regatta == null) - return null; - RaceDefinition race = regatta.getRaceByName(raceString); - if (race == null) - return null; - - return getService().getTrackedRace(regatta, race); + final TrackedRace result; + final Regatta regatta = getService().getRegattaByName(regattaString); + if (regatta == null) { + result = null; + } else { + final RaceDefinition race = regatta.getRaceByName(raceString); + if (race == null) { + result = null; + } else { + result = getService().getTrackedRace(regatta, race); + } + } + return result; } private List getTrackedRaces(String[] regattaRaces) { - List races = new ArrayList(); - + final List races = new ArrayList(); for (String regattaRace : regattaRaces) { - String[] split = regattaRace.split(":"); - if (split.length == 0) - continue; - String regattaString = split[0]; - String raceString = split[1]; - TrackedRace trackedRace = getTrackedRace(regattaString, raceString); - if (trackedRace == null) - continue; - - races.add(trackedRace); + final String[] split = regattaRace.split(":"); + if (split.length != 0) { + final String regattaString = split[0]; + final String raceString = split[1]; + final TrackedRace trackedRace = getTrackedRace(regattaString, raceString); + if (trackedRace != null) { + races.add(trackedRace); + } + } } - return races; } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/windimport/AbstractWindImporter.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/windimport/AbstractWindImporter.java index 5866d27cc1e..ff00ee14b05 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/windimport/AbstractWindImporter.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/windimport/AbstractWindImporter.java @@ -144,17 +144,17 @@ public abstract class AbstractWindImporter { if (uploadRequest.races.size() > 0) { for (RegattaAndRaceIdentifier raceEntry : uploadRequest.races) { DynamicTrackedRace trackedRace = service.getTrackedRace(raceEntry); - SecurityUtils.getSubject() - .checkPermission(trackedRace.getIdentifier().getStringPermission(DefaultActions.UPDATE)); if (trackedRace != null) { + SecurityUtils.getSubject() + .checkPermission(trackedRace.getIdentifier().getStringPermission(DefaultActions.UPDATE)); trackedRaces.add(trackedRace); } } } else { for (Regatta regatta : service.getAllRegattas()) { for (RaceDefinition raceDefinition : regatta.getAllRaces()) { - final DynamicTrackedRace trackedRace = service.getTrackedRegatta(regatta).getTrackedRace(raceDefinition); - if (SecurityUtils.getSubject() + final DynamicTrackedRace trackedRace = service.getTrackedRegatta(regatta).getExistingTrackedRace(raceDefinition); + if (trackedRace != null && SecurityUtils.getSubject() .isPermitted(trackedRace.getIdentifier().getStringPermission(DefaultActions.UPDATE))) { trackedRaces.add(trackedRace); } diff --git a/java/com.sap.sailing.server.interface/src/com/sap/sailing/server/interfaces/RacingEventService.java b/java/com.sap.sailing.server.interface/src/com/sap/sailing/server/interfaces/RacingEventService.java index 4fca1ee8738..86837313f9d 100644 --- a/java/com.sap.sailing.server.interface/src/com/sap/sailing/server/interfaces/RacingEventService.java +++ b/java/com.sap.sailing.server.interface/src/com/sap/sailing/server/interfaces/RacingEventService.java @@ -161,11 +161,18 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch @Override RaceDefinition getRace(RegattaAndRaceIdentifier raceIdentifier); + /** + * Looks for a {@link DynamicTrackedRace} inside the {@link TrackedRegatta} identified by {@code regatta}, + * keyed by the race definition {@code race}. If no such race is found, e.g., because it is still in its "loading" + * phase and the {@link TrackedRace} hasn't been created and added to the {@link TrackedRegatta} yet, or because + * it is in the process of being removed, with the {@link TrackedRace} already gone but the {@link RaceDefinition} + * still available (see also bug 5982), this method will return {@code null} without any waiting or blocking. + */ DynamicTrackedRace getTrackedRace(Regatta regatta, RaceDefinition race); /** - * When the regatta, tracked regatta and race definition are found, this method waits for the - * tracked race to appear. + * This method does not for the tracked race to appear. If any of regatta, race definition or tracked race are not + * found, {@code null} is returned. */ DynamicTrackedRace getTrackedRace(RegattaAndRaceIdentifier raceIdentifier); diff --git a/java/com.sap.sailing.server.interface/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java b/java/com.sap.sailing.server.interface/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java index b228f1ded1a..610131f46fc 100755 --- a/java/com.sap.sailing.server.interface/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java +++ b/java/com.sap.sailing.server.interface/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java @@ -475,6 +475,8 @@ public class ImportMasterDataOperation extends DynamicTrackedRace trackedRace = toState .getTrackedRace((RegattaAndRaceIdentifier) raceIdentifier); raceColumn.setTrackedRace(fleet, trackedRace); + // in case the TrackedRace wasn't found (see also bug 5982), at least record the race identifier + raceColumn.setRaceIdentifier(fleet, raceIdentifier); } } } @@ -708,7 +710,7 @@ public class ImportMasterDataOperation extends RaceHandle raceHandle = toState.addRace(/* default */ null, paramToStartTracking, /* do not wait */ -1); final RaceDefinition race = raceHandle.getRace(RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS); if (race != null) { - final DynamicTrackedRace trackedRace = raceHandle.getTrackedRegatta().getTrackedRace(race); + final DynamicTrackedRace trackedRace = raceHandle.getTrackedRegatta().getTrackedRace(race); // wait/block for tracked race to show up result.add(trackedRace); ensureOwnership(trackedRace.getIdentifier(), securityService); creationCount.addOneTrackedRace(race.getId().toString()); diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy).launch b/java/com.sap.sailing.server/SailingServer (No Proxy).launch index ef3783d42b9..e0419f41108 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy).launch @@ -34,295 +34,291 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch index 24883be90b5..a5ec63402f3 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch @@ -25,295 +25,291 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 631cfd03daf..6752f7a0b07 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -3054,7 +3054,7 @@ Replicator { * already have been removed by the stopAllTrackersForWhichRaceIsLastReachable(...) above; maybe a * Java memory model idiosyncrasy with the queue thread not "seeing" the change to dataTrackers?). * We must make sure to not block its execution, e.g., by synchronization, because otherwise - * the the removedTrackedRegatta(regatta) call below may not return, either, as it waits for + * the removedTrackedRegatta(regatta) call below may not return, either, as it waits for * tasks it may enqueue after the task enqueued here. See bug 5879. */ trackedRegatta.removeTrackedRace(trackedRace, Optional.of( @@ -3104,6 +3104,9 @@ Replicator { } } } + // FIXME bug5982: when the TrackedRace is removed already, queries for the RaceDefinition would still be satisfied up to this point, with a RaceDefinition that is about to disappear; + // FIXME bug5982: no TrackedRace will ever appear again for that RaceDefinition; we should consider introducing a locking pattern around the transaction of removing TrackedRace+RaceDefinition + // FIXME bug5982: and synchronize accordingly with TrackedRegattaImpl.getTrackedRace(RaceDefinition). // remove the race from the (default) regatta if the regatta is not persistently stored regatta.removeRace(race); if (!regatta.isPersistent() && Util.isEmpty(regatta.getAllRaces())) { @@ -3170,7 +3173,7 @@ Replicator { @Override public DynamicTrackedRace getTrackedRace(Regatta regatta, RaceDefinition race) { - return getOrCreateTrackedRegatta(regatta).getTrackedRace(race); + return getOrCreateTrackedRegatta(regatta).getExistingTrackedRace(race); } private DynamicTrackedRace getExistingTrackedRace(Regatta regatta, RaceDefinition race) { @@ -3234,9 +3237,9 @@ Replicator { if (regatta != null) { DynamicTrackedRegatta trackedRegatta = regattaTrackingCache.get(regatta); if (trackedRegatta != null) { - RaceDefinition race = getRace(raceIdentifier); + RaceDefinition race = regatta.getRaceByName(raceIdentifier.getRaceName()); if (race != null) { - result = trackedRegatta.getTrackedRace(race); + result = trackedRegatta.getExistingTrackedRace(race); } } } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java index abd77caff7e..e35230bbfe0 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java @@ -404,7 +404,7 @@ public class SimulationServiceImpl implements SimulationService { }); } if (!legListeners.containsKey(legIdentifier.getRaceIdentifier())) { - TrackedRace trackedRace = racingEventService.getTrackedRace(legIdentifier); + final TrackedRace trackedRace = racingEventService.getTrackedRace(legIdentifier); if (trackedRace != null) { LegChangeListener listener = new LegChangeListener(trackedRace); legListeners.put(legIdentifier.getRaceIdentifier(), listener); diff --git a/java/com.sap.sailing.targetplatform.base/features/target-base/feature.xml b/java/com.sap.sailing.targetplatform.base/features/target-base/feature.xml index 70a582766eb..aa640d5fa8d 100755 --- a/java/com.sap.sailing.targetplatform.base/features/target-base/feature.xml +++ b/java/com.sap.sailing.targetplatform.base/features/target-base/feature.xml @@ -37,28 +37,28 @@ id="slf4j.api" download-size="0" install-size="0" - version="1.7.30" + version="2.0.12" unpack="false"/> + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.targetplatform.base/features/target-jackson/feature.xml b/java/com.sap.sailing.targetplatform.base/features/target-jackson/feature.xml index 238b26ab32e..bae1ad7ef2a 100644 --- a/java/com.sap.sailing.targetplatform.base/features/target-jackson/feature.xml +++ b/java/com.sap.sailing.targetplatform.base/features/target-jackson/feature.xml @@ -40,4 +40,137 @@ version="1.9.13" unpack="false"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-1.14.12-sources.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-1.14.12-sources.jar new file mode 100644 index 00000000000..065cf43af9e Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-1.14.12-sources.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-1.14.12.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-1.14.12.jar new file mode 100644 index 00000000000..f9c0f47cd1a Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-1.14.12.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-agent-1.14.12-sources.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-agent-1.14.12-sources.jar new file mode 100644 index 00000000000..f34aea936ef Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-agent-1.14.12-sources.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-agent-1.14.12.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-agent-1.14.12.jar new file mode 100644 index 00000000000..944046543c3 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/byte-buddy-agent-1.14.12.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/com.diffplug.osgi.extension.sun.misc-0.0.0.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/com.diffplug.osgi.extension.sun.misc-0.0.0.jar new file mode 100644 index 00000000000..735b6fa92fa Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/com.diffplug.osgi.extension.sun.misc-0.0.0.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/jackson-annotations-2.16.1.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jackson-annotations-2.16.1.jar new file mode 100644 index 00000000000..b9c48e69ccd Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jackson-annotations-2.16.1.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/jboss-marshalling-osgi-2.1.4.SP1.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jboss-marshalling-osgi-2.1.4.SP1.jar new file mode 100644 index 00000000000..c74d8f35e97 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jboss-marshalling-osgi-2.1.4.SP1.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/jcl-over-slf4j-1.7.30.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jcl-over-slf4j-1.7.30.jar deleted file mode 100755 index 44e9f63976d..00000000000 Binary files a/java/com.sap.sailing.targetplatform.base/plugins/target-base/jcl-over-slf4j-1.7.30.jar and /dev/null differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/jcl-over-slf4j-2.0.12.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jcl-over-slf4j-2.0.12.jar new file mode 100644 index 00000000000..bbf40bf5bf6 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jcl-over-slf4j-2.0.12.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/jodd-bean-5.1.6.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jodd-bean-5.1.6.jar new file mode 100644 index 00000000000..2292c7c12c2 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jodd-bean-5.1.6.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/jul-to-slf4j-1.7.30.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jul-to-slf4j-1.7.30.jar deleted file mode 100755 index 7dea58b2b3e..00000000000 Binary files a/java/com.sap.sailing.targetplatform.base/plugins/target-base/jul-to-slf4j-1.7.30.jar and /dev/null differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/jul-to-slf4j-2.0.12.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jul-to-slf4j-2.0.12.jar new file mode 100644 index 00000000000..443a35674d1 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/jul-to-slf4j-2.0.12.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/kryo-5.6.0.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/kryo-5.6.0.jar new file mode 100644 index 00000000000..b5fd41f7ed3 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/kryo-5.6.0.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/minlog-1.3.1.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/minlog-1.3.1.jar new file mode 100644 index 00000000000..9a1557092e6 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/minlog-1.3.1.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/reactor-core-3.6.4.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/reactor-core-3.6.4.jar new file mode 100644 index 00000000000..24fd60252d3 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/reactor-core-3.6.4.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/redisson-3.17.7.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/redisson-3.17.7.jar deleted file mode 100644 index eb4f7a210b1..00000000000 Binary files a/java/com.sap.sailing.targetplatform.base/plugins/target-base/redisson-3.17.7.jar and /dev/null differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/redisson-3.27.2.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/redisson-3.27.2.jar new file mode 100644 index 00000000000..fed698e94dd Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/redisson-3.27.2.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/reflectasm-1.11.9.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/reflectasm-1.11.9.jar new file mode 100644 index 00000000000..050129b5429 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/reflectasm-1.11.9.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-api-1.7.30.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-api-1.7.30.jar deleted file mode 100755 index 29ac26fb8ca..00000000000 Binary files a/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-api-1.7.30.jar and /dev/null differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-api-2.0.12.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-api-2.0.12.jar new file mode 100644 index 00000000000..bfa1de399dd Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-api-2.0.12.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-jdk14-1.7.30.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-jdk14-1.7.30.jar deleted file mode 100755 index 6254c48716a..00000000000 Binary files a/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-jdk14-1.7.30.jar and /dev/null differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-jdk14-2.0.12.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-jdk14-2.0.12.jar new file mode 100644 index 00000000000..7ea39fff396 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-base/slf4j-jdk14-2.0.12.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/cache-api-1.1.1.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/cache-api-1.1.1.jar new file mode 100644 index 00000000000..53665d2351c Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/cache-api-1.1.1.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-core-2.16.1.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-core-2.16.1.jar new file mode 100644 index 00000000000..a8ff5e3cc74 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-core-2.16.1.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-databind-2.16.1.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-databind-2.16.1.jar new file mode 100644 index 00000000000..5171b7a422b Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-databind-2.16.1.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-dataformat-yaml-2.16.1.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-dataformat-yaml-2.16.1.jar new file mode 100644 index 00000000000..956ccef9572 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/jackson-dataformat-yaml-2.16.1.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-buffer-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-buffer-4.1.107.Final.jar new file mode 100644 index 00000000000..f0b84319c70 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-buffer-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-codec-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-codec-4.1.107.Final.jar new file mode 100644 index 00000000000..07a9c95cf19 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-codec-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-codec-dns-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-codec-dns-4.1.107.Final.jar new file mode 100644 index 00000000000..d94797911d1 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-codec-dns-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-common-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-common-4.1.107.Final.jar new file mode 100644 index 00000000000..98e1e0c0a99 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-common-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-handler-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-handler-4.1.107.Final.jar new file mode 100644 index 00000000000..34abc5cbb65 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-handler-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-incubator-transport-classes-io_uring-0.0.25.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-incubator-transport-classes-io_uring-0.0.25.Final.jar new file mode 100644 index 00000000000..967020be87a Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-incubator-transport-classes-io_uring-0.0.25.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-resolver-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-resolver-4.1.107.Final.jar new file mode 100644 index 00000000000..6e4d4542afe Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-resolver-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-resolver-dns-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-resolver-dns-4.1.107.Final.jar new file mode 100644 index 00000000000..be4ca2feb1b Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-resolver-dns-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-4.1.107.Final.jar new file mode 100644 index 00000000000..76526931df7 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-classes-epoll-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-classes-epoll-4.1.107.Final.jar new file mode 100644 index 00000000000..7df2464d6ca Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-classes-epoll-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-classes-kqueue-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-classes-kqueue-4.1.107.Final.jar new file mode 100644 index 00000000000..c2b5bb065c0 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-classes-kqueue-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-native-unix-common-4.1.107.Final.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-native-unix-common-4.1.107.Final.jar new file mode 100644 index 00000000000..a7d37a3d47e Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/netty-transport-native-unix-common-4.1.107.Final.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/reactive-streams-1.0.4.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/reactive-streams-1.0.4.jar new file mode 100644 index 00000000000..e58c483f975 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/reactive-streams-1.0.4.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/rxjava-3.1.8.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/rxjava-3.1.8.jar new file mode 100644 index 00000000000..fb8448ff9bd Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/rxjava-3.1.8.jar differ diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/snakeyaml-2.2.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/snakeyaml-2.2.jar new file mode 100644 index 00000000000..275dd5700a3 Binary files /dev/null and b/java/com.sap.sailing.targetplatform.base/plugins/target-jackson/snakeyaml-2.2.jar differ diff --git a/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-remote.target b/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-remote.target index 0f258f7cb7f..ae8075af31e 100755 --- a/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-remote.target +++ b/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-remote.target @@ -20,10 +20,6 @@ - - - - @@ -146,7 +142,7 @@ - + @@ -174,6 +170,7 @@ + @@ -393,6 +390,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sse.feature.runtime/feature.xml b/java/com.sap.sse.feature.runtime/feature.xml index eac25726a6f..66da331593e 100644 --- a/java/com.sap.sse.feature.runtime/feature.xml +++ b/java/com.sap.sse.feature.runtime/feature.xml @@ -84,7 +84,7 @@ id="slf4j.jdk14" download-size="0" install-size="0" - version="1.7.30" + version="2.0.12" fragment="true" unpack="false"/> @@ -316,7 +316,7 @@ id="slf4j.api" download-size="0" install-size="0" - version="1.7.30" + version="2.0.12" unpack="false"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/ApacheReverseProxy.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/ApacheReverseProxy.java index fb5580882c9..f58b0bb40b5 100755 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/ApacheReverseProxy.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/ApacheReverseProxy.java @@ -49,10 +49,15 @@ implements com.sap.sse.landscape.Process { */ private static final String RELATIVE_CONFIG_PATH = "conf.d"; + /** + * The user which contains the checked-out copy of the httpd configuration git. + */ + private static final String CONFIG_USER = "httpdConf"; + /** * The absolute path to the "httpd config" git repo which stores all httpd configuration files. */ - private static final String CONFIG_REPO_PATH = "/etc/httpd"; + private static final String CONFIG_REPO_PATH = "~" + CONFIG_USER + "/checked-out"; /** * The branch name that contains the production httpd configuration. @@ -123,13 +128,14 @@ implements com.sap.sse.landscape.Process { private void setRedirect(String configFileNameForHostname, String macroName, String hostname, Optional optionalKeyName, byte[] privateKeyEncryptionPassphrase, boolean doCommit, boolean doPush, String... macroArguments) throws Exception { - String command = "echo \"Use " + macroName + " " + hostname + " " + String.join(" ", macroArguments) - + "\" > " + getAbsoluteConfigFilePath(configFileNameForHostname) + "; service httpd reload" ; + String command = "su - " + CONFIG_USER + " -c 'cd " + CONFIG_REPO_PATH + " && git checkout " + CONFIG_REPO_MAIN_BRANCH_NAME + " && echo \"Use " + macroName + " " + hostname + " " + String.join(" ", macroArguments) + "\" > " + + getAbsoluteConfigFilePath(configFileNameForHostname); if (doCommit) { command = command + " && cd " + CONFIG_REPO_PATH + " && " + createCommitAndPushString(configFileNameForHostname, "Set " + configFileNameForHostname + " redirect", doPush); } + command = command + "'; service httpd reload"; // Concludes the su. And reloads as the root user. logger.info("Standard output from setting up the re-direct for " + hostname + " and reloading the Apache httpd server: " + runCommandAndReturnStdoutAndStderr(command, @@ -158,7 +164,7 @@ implements com.sap.sse.landscape.Process { /** * Creates a command, that can be ran on an instance to commit, and optionally push, changes to a file (within a git repository). ASSUMES the command is ran from within the repository. - * @param editedFileName The file name edited, created or deleted to commit. This includes the {@link #CONFIG_FILE_EXTENSION}, but not a path. + * @param editedFileName The file name edited, created or deleted to commit. This includes the {@link #CONFIG_FILE_EXTENSION}, but not a path. The method appends the relative path. * @param commitMsg The commit message, without escaped speech marks. * @param performPush Boolean indicating whether to push changes or not. True for performing a push. * @return Returns the created command (in String form) to perform a commit and optional push. @@ -262,10 +268,19 @@ implements com.sap.sse.landscape.Process { */ private void removeRedirect(String configFileName, String hostname, Optional optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception { - final String command = "rm " + getAbsoluteConfigFilePath(configFileName) + "; service httpd reload" + " && cd " + CONFIG_REPO_PATH + ";" + createCommitAndPushString(configFileName, "Removed " + hostname, true); + StringBuilder command = new StringBuilder("su - " + CONFIG_USER + " -c '"); // The Git commit must be ran as the CONFIG_USER. + command.append("cd "); + command.append(CONFIG_REPO_PATH); + command.append(" && git checkout "); + command.append(CONFIG_REPO_MAIN_BRANCH_NAME); + command.append(" && rm "); + command.append(getRelativeConfigFilePath(configFileName)); + command.append("; "); + command.append(createCommitAndPushString(configFileName, "Removed " + hostname, /* Perform push */ true)); + command.append("'; service httpd reload;"); // ' closes the su. The reload must be run as the root user. logger.info("Standard output from removing the re-direct for " + hostname + " and reloading the Apache httpd server: " - + runCommandAndReturnStdoutAndStderr(command, + + runCommandAndReturnStdoutAndStderr(command.toString(), "Standard error from removing the re-direct for " + hostname + " and reloading the Apache httpd server: ", Level.INFO, optionalKeyName, privateKeyEncryptionPassphrase)); diff --git a/wiki/info/landscape/amazon-ec2.md b/wiki/info/landscape/amazon-ec2.md index a705a4ee2f7..730b0736088 100644 --- a/wiki/info/landscape/amazon-ec2.md +++ b/wiki/info/landscape/amazon-ec2.md @@ -19,9 +19,9 @@ Our default region in AWS EC2 is eu-west-1 (Ireland). Tests are currently run in In Route53 (the AWS DNS) we have registered the sapsailing.com domain and can manage records for any sub-domains. The "apex" record for sapsailing.com points to a Network Load Balancer (NLB), currently ``NLB-sapsailing-dot-com-f937a5b33246d221.elb.eu-west-1.amazonaws.com``, which does the following things: -* accept SSH connects on port 22; these are forwarded to the internal IP of the web server through the target group ``SSH-to-sapsailing-dot-com``, currently with the internal IP target ``172.31.28.212`` -* accept HTTP connections for ``sapsailing.com:80``, forwarding them to the target group ``HTTP-to-sapsailing-dot-com`` which is a TCP target group for port 80 with ip-based targets (instance-based was unfortunately not possible for the old ``m3`` instance type of our web server), again pointing to ``172.31.28.212``, the internal IP of our web server -* accept HTTPS/TLS connections on port 443, using the ACM-managed certificate for ``*.sapsailing.com`` and ``sapsailing.com`` and also forwarding to the ``HTTP-to-sapsailing-dot-com`` target group +* accept SSH connects on port 22; these are forwarded to the internal IP of the web server through the target group ``SSH-to-sapsailing-dot-com-2``, currently with the internal IP target ``172.31.28.212`` +* accept HTTP connections for ``sapsailing.com:80``, forwarding them to the target group ``HTTP-to-sapsailing-dot-com-2`` which is a TCP target group for port 80 with ip-based targets (instance-based was unfortunately not possible for the old ``m3`` instance type of our web server), again pointing to ``172.31.28.212``, the internal IP of our web server +* accept HTTPS/TLS connections on port 443, using the ACM-managed certificate for ``*.sapsailing.com`` and ``sapsailing.com`` and also forwarding to the ``HTTP-to-sapsailing-dot-com-2`` target group * optionally, this NLB could be extended by UDP port mappings in case we see a use case for UDP-based data streams that need forwarding to specific applications, such as the Expedition data typically sent on ports 2010 and following Additionally, we have created a CNAME record for ``*.sapsailing.com`` pointing at a default application load balancer (ALB) (currently ``DefDynsapsailing-com-1492504005.eu-west-1.elb.amazonaws.com``) in our default region (eu-west-1). Thie default ALB is also called our "dynamic ALB" because it doesn't depend on DNS rules other than the default one for ``*.sapsailing.com``, so other than changes to the DNS which can take minutes to hours to propagate through the world-wide DNS, changes to the default ALB's rule set take effect immediately. Like all ALBs, this one also has a default rule that refers all traffic not matched by other rules to a target group that forwards traffic to an (in the future probably multiple) Apache httpd webserver. All these ALBs handle SSL termination by means of an ACM-managed certificate that AWS automatically renews before it expires. The traffic routed to the target groups is always HTTP only. @@ -38,6 +38,8 @@ The IPs for all reverse proxies will automatically be added to the `CentralWebSe and to the `DDNSMapped-x-HTTP` (in all the DDNSMapped servers). These are the target groups for the default rules and it ensures availability to the ARCHIVE especially. Currently, the new approach tags instances with `disposableProxy` to indicate it hosts no vital services. `ReverseProxy` also identifies any reverse proxies. The health check for the target groups would change to trigger a script which returns different error codes: healthy/200 if in the same AZ as the archive (or if the failover archive is in use), whilst unhealthy/503 if in different AZs. This will reduce cross-AZ, archive traffic costs, but maintain availability and load balancing. +For security groups of the central reverse proxy, we want Webserver, as well as Disposable Reverse Proxy. The diposables just have the latter. + There is hope to also deploy the httpd on already existing instances, which have free resources and a certain tag permitting this co-deployment. Most of sapsailing.com no longer cares about SSL and does not need to have an SSL certificate. Sail-insight still does though. The central reverse proxy offers the following services: @@ -64,8 +66,8 @@ If you see ``Syntax OK`` then reload the configuration using The webserver is registered as target in various locations: * As DNS record with its internal IP address (e.g., 172.31.19.129) for the two DNS entries ``logfiles.internal.sapsailing.com`` used by various NFS mounts, and ``smtp.internal.sapsailing.com`` for e-mail traffic sent within the landscape and not requiring the AWS SES -* as IP target with its internal IP address for the ``HTTP-to-sapsailing-dot-com`` target group, accepting the HTTP traffic sent straight to ``sapsailing.com`` (not ``www.sapsailing.com``) -* as IP target with its internal IP address for the ``SSH-to-sapsailing-dot-com`` target group, accepting the SSH traffic for ``sapsailing.com`` +* as IP target with its internal IP address for the ``HTTP-to-sapsailing-dot-com-2`` target group, accepting the HTTP traffic sent straight to ``sapsailing.com`` (not ``www.sapsailing.com``) +* as IP target with its internal IP address for the ``SSH-to-sapsailing-dot-com-2`` target group, accepting the SSH traffic for ``sapsailing.com`` * as regular instance target in all load balancers' default rule's target group, such as ``DefDynsapsailing-com``, ``DNSMapped-0``, ``DNSMapped-1``, and so on; the names of the target groups are ``CentralWebServerHTTP-Dyn``, ``DDNSMapped-0-HTTP``, ``DDNSMapped-1-HTTP``, and so on, respectively * as regular instance target in ``DNSMapped-0``'s target group ``DNSMapped0-Central-HTTP`` to which requests for services available only on the *central* reverse proxy are forwarded to, such as ``releases.sapsailing.com``, ``bugzilla.sapsailing.com``, and so on * as target of the elastic IP address ``54.229.94.254`` diff --git a/wiki/info/landscape/paris2024/olympic-setup.md b/wiki/info/landscape/paris2024/olympic-setup.md index a6b2423041e..f48aa3d3697 100644 --- a/wiki/info/landscape/paris2024/olympic-setup.md +++ b/wiki/info/landscape/paris2024/olympic-setup.md @@ -563,6 +563,12 @@ REPLICATION_HOST=localhost REPLICATION_PORT=5673 USE_ENVIRONMENT=live-master-server ADDITIONAL_JAVA_ARGS="${ADDITIONAL_JAVA_ARGS} -Dcom.sap.sse.debranding=true -Dpolardata.source.url=https://www.sapsailing.com:22443 -Dwindestimation.source.url=https://www.sapsailing.com:22443" +ADDITIONAL_JAVA_ARGS="$ADDITIONAL_JAVA_ARGS -Dsecurity.sharedAcrossSubdomainsOf=sailing.omegatiming.com -Dsecurity.baseUrlForCrossDomainStorage=https://security-service.sapsailing.com -Dgwt.acceptableCrossDomainStorageRequestOriginRegexp=https?://(.*\.)?sailing\.omegatiming\.com(:[0-9]*)?$" +# Place additional secrets here, e.g., from root@sapsailing.com:secrets +MANAGE2SAIL_ACCESS_TOKEN=... +IGTIMI_CLIENT_ID=... +IGTIMI_CLIENT_SECRET=... +GOOGLE_MAPS_AUTHENTICATION_PARAMS="..." ``` ### Secondary Master @@ -591,6 +597,12 @@ REPLICATION_HOST=localhost REPLICATION_PORT=5673 USE_ENVIRONMENT=live-master-server ADDITIONAL_JAVA_ARGS="${ADDITIONAL_JAVA_ARGS} -Dcom.sap.sse.debranding=true -Dpolardata.source.url=https://www.sapsailing.com:22443 -Dwindestimation.source.url=https://www.sapsailing.com:22443" +ADDITIONAL_JAVA_ARGS="$ADDITIONAL_JAVA_ARGS -Dsecurity.sharedAcrossSubdomainsOf=sailing.omegatiming.com -Dsecurity.baseUrlForCrossDomainStorage=https://security-service.sapsailing.com -Dgwt.acceptableCrossDomainStorageRequestOriginRegexp=https?://(.*\.)?sailing\.omegatiming\.com(:[0-9]*)?$" +# Place additional secrets here, e.g., from root@sapsailing.com:secrets +MANAGE2SAIL_ACCESS_TOKEN=... +IGTIMI_CLIENT_ID=... +IGTIMI_CLIENT_SECRET=... +GOOGLE_MAPS_AUTHENTICATION_PARAMS="..." ``` @@ -622,6 +634,9 @@ REPLICATION_PORT=5672 REPLICATION_CHANNEL=${SERVER_NAME}-replica USE_ENVIRONMENT=live-replica-server ADDITIONAL_JAVA_ARGS="${ADDITIONAL_JAVA_ARGS} -Dcom.sap.sse.debranding=true" +ADDITIONAL_JAVA_ARGS="$ADDITIONAL_JAVA_ARGS -Dsecurity.sharedAcrossSubdomainsOf=sailing.omegatiming.com -Dsecurity.baseUrlForCrossDomainStorage=https://security-service.sapsailing.com -Dgwt.acceptableCrossDomainStorageRequestOriginRegexp=https?://(.*\.)?sailing\.omegatiming\.com(:[0-9]*)?$" +# Place additional secrets here, e.g., from root@sapsailing.com:secrets +GOOGLE_MAPS_AUTHENTICATION_PARAMS="..." ``` (Adjust the release accordingly, of course). (NOTE: During the first production days of the event we noticed that it was really a BAD IDEA to have all replicas use the same DB set-up, all writing to the MongoDB PRIMARY of the "live" replica set in eu-west-1. With tens of replicas running concurrently, this led to a massive block-up based on MongoDB not writing fast enough. This gave rise to a new application server AMI which now has a MongoDB set-up included, using "replica" as the MongoDB replica set name. Now, each replica hence can write into its own MongoDB instance, isolated from all others and scaling linearly.) @@ -641,6 +656,9 @@ REPLICATE_MASTER_EXCHANGE_NAME=paris2024 REPLICATE_MASTER_QUEUE_HOST=rabbit-eu-west-3.sapsailing.com REPLICATE_MASTER_BEARER_TOKEN="***" ADDITIONAL_JAVA_ARGS="${ADDITIONAL_JAVA_ARGS} -Dcom.sap.sse.debranding=true" +ADDITIONAL_JAVA_ARGS="$ADDITIONAL_JAVA_ARGS -Dsecurity.sharedAcrossSubdomainsOf=sailing.omegatiming.com -Dsecurity.baseUrlForCrossDomainStorage=https://security-service.sapsailing.com -Dgwt.acceptableCrossDomainStorageRequestOriginRegexp=https?://(.*\.)?sailing\.omegatiming\.com(:[0-9]*)?$" +# Place additional secrets here, e.g., from root@sapsailing.com:secrets +GOOGLE_MAPS_AUTHENTICATION_PARAMS="..." ``` ### Application Servers