diff --git a/.travis.yml b/.travis.yml index 85ad22c..fb75df6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,14 +33,16 @@ script: - aws cloudformation validate-template --template-body file://templates/solace.template - aws cloudformation validate-template --template-body file://templates/nodecreate.template - yaml-lint -n templates/ - - #sed -i "s@SolaceDockerImageParameterValue@${SOLACE_DOCKER_URL_PARAMETER_VALUE}@g" ci/solace-aws-ha-3az-prod-travistest.json - - sed -i "s@SolaceDockerImageParameterValue@solace/solace-pubsub-standard:latest@g" ci/solace-aws-ha-3az-prod-travistest.json + - sed -i "s@SolaceDockerImageParameterValue@${SOLACE_DOCKER_URL_PARAMETER_VALUE}@g" ci/solace-aws-ha-3az-prod-travistest.json + - #sed -i "s@SolaceDockerImageParameterValue@solace/solace-pubsub-standard:latest@g" ci/solace-aws-ha-3az-prod-travistest.json - sed -i "s@EventBrokerNodeInstanceTypeParameterValue@${MESSAGEBROKERNODEINSTANCETYPE}@g" ci/solace-aws-ha-3az-prod-travistest.json - - sed -i "s@SolaceStackRegionNAME@${AWS_DEFAULT_REGION}@g" ci/solace-aws-ha-3az-prod-travistest.json - aws s3 mb s3://solace-cf-quickstart-travistest || echo "s3 bucket already existed" + - export BUCKETREGION=`aws s3api get-bucket-location --bucket solace-cf-quickstart-travistest | grep LocationConstraint | awk -F' ' '{print $NF}' | tr -d '"'` + - sed -i "s@SolaceStackRegionNAME@${AWS_DEFAULT_REGION}@g" ci/solace-aws-ha-3az-prod-travistest.json + - sed -i "s@SolaceBucketRegionNAME@${BUCKETREGION}@g" ci/solace-aws-ha-3az-prod-travistest.json - aws s3 sync . s3://solace-cf-quickstart-travistest/solace/eventbroker/latest --acl public-read - export TESTSTACKPREFIX=T`echo "$(date +%s)" | rev`; export TESTSTACKNAME="$TESTSTACKPREFIX-sol-aws-travistest"; - - aws cloudformation create-stack --stack-name $TESTSTACKNAME --template-body file://templates/solace-master.template --parameters file://ci/solace-aws-ha-3az-prod-travistest.json --on-failure DO_NOTHING --capabilities CAPABILITY_IAM + - aws cloudformation create-stack --stack-name $TESTSTACKNAME --template-body file://templates/solace-master.template --parameters file://ci/solace-aws-ha-3az-prod-travistest.json --on-failure DO_NOTHING --capabilities CAPABILITY_NAMED_IAM - echo "Waiting for stack create complete" - "travis_wait 30 sleep 1800 &" - until aws cloudformation describe-stacks --stack-name $TESTSTACKNAME | grep -m 1 -E 'CREATE_COMPLETE|DELETE_IN_PROGRESS'; do sleep 10; done @@ -54,9 +56,8 @@ script: - sleep 30 - curl -sS -u admin:admin http://$url:8080/SEMP -d "" - curl -sS -u admin:admin http://$url:8080/SEMP -d "" - - bash -c 'if [[ -z `curl -sS -u admin:admin http://$url:8080/SEMP -d "" - | grep "Up"` ]] ; then echo "config-sync not up!"; exit - 1; fi' + - #bash -c 'if [[ -z `curl -sS -u admin:admin http://$url:8080/SEMP -d "" | grep "Up"` ]] ; then echo "config-sync not up!"; exit 1; fi' + - if [[ -z `curl -sS -u admin:admin http://$url:8080/SEMP -d "" | grep "Up"` ]] ; then echo "config-sync not up!"; exit; fi - pubSubTools/sdkperf_c -cip=$url -mn=100000 -mr=0 -ptl=t1 -stl=t1 | grep "Total Messages" - aws cloudformation delete-stack --stack-name $TESTSTACKNAME - echo "Waiting for stack delete complete" @@ -65,7 +66,7 @@ script: - # Now test No Private Subnet - export TESTSTACKNAME="$TESTSTACKNAME-1" - sed -i "s@true@false@g" ci/solace-aws-ha-3az-prod-travistest.json - - aws cloudformation create-stack --stack-name $TESTSTACKNAME --template-body file://templates/solace-master.template --parameters file://ci/solace-aws-ha-3az-prod-travistest.json --on-failure DO_NOTHING --capabilities CAPABILITY_IAM + - aws cloudformation create-stack --stack-name $TESTSTACKNAME --template-body file://templates/solace-master.template --parameters file://ci/solace-aws-ha-3az-prod-travistest.json --on-failure DO_NOTHING --capabilities CAPABILITY_NAMED_IAM - echo "Waiting for stack create complete" - "travis_wait 30 sleep 1800 &" - until aws cloudformation describe-stacks --stack-name $TESTSTACKNAME | grep -m 1 -E 'CREATE_COMPLETE|DELETE_IN_PROGRESS'; do sleep 10; done diff --git a/README.md b/README.md index 6583cef..92002a6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ # Install and Configure Solace PubSub+ Software Event Broker in an HA Tuple using AWS Cloud Formation +This document provides a quick getting started guide to install a Solace PubSub+ software event broker deployment in Amazon Web Services cloud computing platform. + +The supported event broker version is 9.7 or later. For earlier broker releases use [this GitHub version of the QuickStart](https://github.com/SolaceProducts/pubsubplus-aws-ha-quickstart/tree/v2.0.1). + ![alt text](/images/Solace-AWS-HA-Prod-3AZ.png "Production Environment for Solace PubSub+") This Quick Start template installs Solace PubSub+ Software Event Broker in fault tolerant high-availability (HA) redundancy groups. HA redundancy provides 1:1 event broker redundancy to increase overall service availability. If one of the event brokers fails, or is taken out of service, the other one automatically takes over and provides service to the clients that were previously served by the now out-of-service event broker. To increase availability, the event brokers are deployed across 3 availability zones. @@ -98,9 +102,14 @@ The next screen will allow you to fill in the details for the selected launch op | Parameter label (name) | Default | Description | |----------------------------|-----------|--------------------------------------------------------------------| | Stack name | Solace-HA | Any globally unique name | -| **PubSub+ Configuration** | | | +| **PubSub+ Event Broker Configuration** | | | | PubSub+ Docker image reference (SolaceDockerImage) | solace/solace-pubsub-standard:latest | A reference to the Solace PubSub+ event broker Docker image, from step 1. Either the image name with optional tag in an accessible Docker registry or a download URL. The download URL can be obtained from http://dev.solace.com/downloads/ or it can be a URL to a remotely hosted image version, e.g. on S3 | | Password to access PubSub+ admin console and SEMP (AdminPassword) | _Requires_ _input_ | Password to allow PubSub+ admin access to configure the event broker instances | +| Maximum Number of Client Connections (MaxClientConnections)| 100 | Broker system scaling: the maximum supported number of client connections | +| Maximum Number of Queue Messages (MaxQueueMessages) | 100 | Broker system scaling: the maximum number of queue messages, in millions | +| Instance Type (WorkerNodeInstanceType) | m4.large | The EC2 instance type for the PubSub+ event broker primary and backup instances in Availability Zones 1 and 2. The m series are recommended for production use.
Ensure adequate CPU and Memory resources are available to support the selected broker system scaling parameters. For requirements, check the [Solace documentation](//docs.solace.com/Configuring-and-Managing/SW-Broker-Specific-Config/System-Scaling-Parameters.htm). | +| Persistent Storage (WorkerNodeStorage) | 0 | Amazon event broker storage allocated for each block device, in GiBs. The Quick Start supports up to 640 GiB per device. For sizing requirements, check the [Solace documentation](//docs.solace.com/Configuring-and-Managing/SW-Broker-Specific-Config/System-Scaling-Parameters.htm). The default value of 0 (zero) indicates ephemeral storage only. A non-zero value will cause a new Provisioned IOPS SSD (io1) disk to be created for message-spool. This disk will not be deleted on stack termination. | +| Instance Type (MonitorNodeInstanceType) | t2.small | The EC2 instance type for the PubSub+ event broker monitor instance in Availability Zone 3 (or Availability Zone 2, if you’re using only two zones). | | Container logging format (ContainerLoggingFormat) | graylog | The format of the logs sent by the event broker to the CloudWatch service (see [documentation](https://docs.solace.com/Configuring-and-Managing/SW-Broker-Specific-Config/Docker-Tasks/Configuring-VMR-Container-Logging.htm?Highlight=logging#Config-Out-Form ) for details) | | **Network Configuration** | | | | Number of Availability Zones (NumberOfAZs) | 3 | The number of Availability Zones (2 may be used for Proof-of-Concept testing or 3 for Production) you want to use in your deployment. This count must match the number of selections in the Availability Zones parameter; otherwise, your deployment will fail with an AWS CloudFormation template validation error. (Note that some regions provide only one or two Availability Zones.) | @@ -111,11 +120,6 @@ The next screen will allow you to fill in the details for the selected launch op | **Common Amazon EC2 Configuration** | | | | Key Pair Name (KeyPairName) | _Requires_ _input_ | A new or an existing public/private key pair within the AWS Region, which allows you to connect securely to your instances after launch. | | Boot Disk Capacity (BootDiskSize) | 24 | Amazon event broker storage allocated for the boot disk, in GiBs. The Quick Start supports 8-128 GiB. | -| **Event Broker Instance Configuration** | | | -| Instance Type (EventBrokerNodeInstanceType) | m4.large | The EC2 instance type for the PubSub+ event broker primary and backup instances in Availability Zones 1 and 2. The m series are recommended for production use.
The available CPU and memory of the selected machine type will limit the maximum connection scaling tier for the PubSub+ event broker. For requirements, refer to the [Solace documentation](https://docs.solace.com/Solace-SW-Broker-Set-Up/SW-Broker-Rel-Compat.htm#Connecti) | -| Persistent Storage (EventBrokerNodeStorage) | 0 | Amazon event broker storage allocated for each block device, in GiBs. The Quick Start supports up to 640 GiB per device. The default value of 0 (zero) indicates ephemeral storage only. A non-zero value will cause a new Provisioned IOPS SSD (io1) disk to be created for message-spool. This disk will not be deleted on stack termination. | -| **Monitor Instance Configuration** | | | -| Instance Type (MonitorNodeInstanceType) | t2.micro | The EC2 instance type for the PubSub+ event broker monitor instance in Availability Zone 3 (or Availability Zone 2, if you’re using only two zones). | | **AWS Quick Start Configuration** | | | | Quick Start S3 Bucket Name (QSS3BucketName) | solace-products | S3 bucket where the Quick Start templates and scripts are installed. Change this parameter to specify the S3 bucket name you’ve created for your copy of Quick Start assets, if you decide to customize or extend the Quick Start for your own use. | | Quick Start S3 bucket region (QSS3BucketRegion) | us-east-1 | The AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. When using your own bucket, you must specify this value. | diff --git a/ci/solace-aws-ha-3az-prod-travistest.json b/ci/solace-aws-ha-3az-prod-travistest.json index e75106e..a920278 100644 --- a/ci/solace-aws-ha-3az-prod-travistest.json +++ b/ci/solace-aws-ha-3az-prod-travistest.json @@ -28,16 +28,16 @@ "ParameterValue": "24" }, { - "ParameterKey": "EventBrokerNodeInstanceType", + "ParameterKey": "WorkerNodeInstanceType", "ParameterValue": "EventBrokerNodeInstanceTypeParameterValue" }, { - "ParameterKey": "EventBrokerNodeStorage", + "ParameterKey": "WorkerNodeStorage", "ParameterValue": "20" }, { "ParameterKey": "MonitorNodeInstanceType", - "ParameterValue": "t2.micro" + "ParameterValue": "t2.small" }, { "ParameterKey": "KeyPairName", @@ -57,7 +57,7 @@ }, { "ParameterKey": "QSS3BucketRegion", - "ParameterValue": "SolaceStackRegionNAME" + "ParameterValue": "SolaceBucketRegionNAME" }, { "ParameterKey": "QSS3KeyPrefix", diff --git a/scripts/install-direct-lvm.sh b/scripts/install-direct-lvm.sh deleted file mode 100644 index d6ef173..0000000 --- a/scripts/install-direct-lvm.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -OPTIND=1 # Reset in case getopts has been used previously in the shell. - -# Initialize our own variables: -volume="" -disk_size="" -DEBUG="-vvvv" - -verbose=0 - -while getopts "d:p:u:" opt; do - case "$opt" in - d) disk_size=$OPTARG - ;; - v) volume=$OPTARG - ;; - esac -done - -shift $((OPTIND-1)) -[ "$1" = "--" ] && shift - -verbose=1 -echo "disk_size==$disk_size= ,volume=$volume ,Leftovers: $@" - -if [ $disk_size == "0" ]; then - echo "`date` No persistent disk here, exiting" - exit 0 -fi - -echo "`date` Create a physical volume and a volume group called vg01DockerPool" -sudo pvcreate ${volume} -sudo vgcreate vg01DockerPool ${volume} - -echo "`date` Create a logical volume called vg01DockerPool, and then convert it to a thin pool" -sudo lvcreate --wipesignatures y -n thinpool vg01DockerPool -l 95%VG -sudo lvcreate --wipesignatures y -n thinpoolmetadata vg01DockerPool -l 1%VG -sudo lvconvert -y --zero n -c 512K --thinpool vg01DockerPool/thinpool \ - --poolmetadata vg01DockerPool/thinpoolmetadata - - -echo "`date` Create a file called vg01DockerPoolThinpool.profile in /etc/lvm/profile/ for use as the new lvm profile" -sudo mkdir /etc/lvm/profile/ -sudo tee /etc/lvm/profile/vg01DockerPoolThinpool.profile <<-EOF -activation { -thin_pool_autoextend_threshold=80 -thin_pool_autoextend_percent=20 -} -EOF - -sudo lvchange --metadataprofile vg01DockerPoolThinpool vg01DockerPool/thinpool - -# Tjis does not work, it overwrites not appends. -echo "`date` Make a file called docker.service. This version of docker.service configures Docker to make use of the thin pool" -sudo tee /etc/sysconfig/docker <<-EOF ---storage-opt=dm.fs=xfs \ ---storage-opt=dm.thinpooldev=/dev/mapper/vg01DockerPool-thinpool \ ---storage-opt=dm.use_deferred_removal=true \ ---storage-opt=dm.use_deferred_deletion=true \ ---storage-opt=dm.basesize=6G -EOF - -echo "`date` Move the existing graph driver directory if the Docker daemon was previously started" -sudo service docker stop -sudo mkdir /var/lib/docker.bk -sudo sh -c 'mv /var/lib/docker/* /var/lib/docker.bk' - -echo "`date` Start Docker Service" -sudo service docker start - - diff --git a/scripts/install-solace.sh b/scripts/install-solace.sh index 8f3404e..e425a45 100644 --- a/scripts/install-solace.sh +++ b/scripts/install-solace.sh @@ -35,12 +35,15 @@ solace_uri="solace/solace-pubsub-standard:latest" # default to pull latest Pub admin_password_file="" disk_size="" disk_volume="" +ha_deployment="true" is_primary="false" logging_format="" logging_group="" logging_stream="" +max_connections="100" +max_queue_messages="100" -while getopts "c:d:p:s:u:v:f:g:r:" opt; do +while getopts "c:d:p:s:u:v:h:f:g:r:n:q:" opt; do case "$opt" in c) config_file=$OPTARG ;; @@ -54,21 +57,27 @@ while getopts "c:d:p:s:u:v:f:g:r:" opt; do ;; v) disk_volume=$OPTARG ;; + h) ha_deployment=$OPTARG + ;; f) logging_format=$OPTARG ;; g) logging_group=$OPTARG ;; r) logging_stream=$OPTARG ;; + n) max_connections=$OPTARG + ;; + q) max_queue_messages=$OPTARG + ;; esac done shift $((OPTIND-1)) [ "$1" = "--" ] && shift -echo "config_file=$config_file , solace_directory=$solace_directory , admin_password_file=$admin_password_file , \ - solace_uri=$solace_uri , disk_size=$disk_size , volume=$disk_volume , logging_format=$logging_format , \ - logging_group=$logging_group , logging_stream=$logging_stream , Leftovers: $@" +echo "config_file=$config_file, solace_directory=$solace_directory, admin_password_file=$admin_password_file, \ + solace_uri=$solace_uri, disk_size=$disk_size, volume=$disk_volume, ha_deployment=$ha_deployment, logging_format=$logging_format, \ + logging_group=$logging_group, logging_stream=$logging_stream, max_connections=$max_connections, max_queue_messages=$max_queue_messages, Leftovers: $@" export admin_password=`cat ${admin_password_file}` # Create working dir if needed @@ -143,41 +152,13 @@ fi echo "`date` INFO: Successfully loaded ${solace_uri} to local docker repo" echo "`date` INFO: Solace message broker image and tag: `docker images | grep solace | awk '{print $1,":",$2}'`" -# Decide which scaling tier applies based on system memory -# and set maxconnectioncount, ulimit, devshm and swap accordingly -MEM_SIZE=`cat /proc/meminfo | grep MemTotal | tr -dc '0-9'` -if [ ${MEM_SIZE} -lt 6600000 ]; then - # 100 if mem<6,325MiB - maxconnectioncount="100" - shmsize="1g" - ulimit_nofile="2448:6592" - SWAP_SIZE="1024" -elif [ ${MEM_SIZE} -lt 14500000 ]; then - # 1000 if 6,325MiB<=mem<13,916MiB - maxconnectioncount="1000" - shmsize="2g" - ulimit_nofile="2448:10192" - SWAP_SIZE="2048" -elif [ ${MEM_SIZE} -lt 30600000 ]; then - # 10000 if 13,916MiB<=mem<29,215MiB - maxconnectioncount="10000" - shmsize="2g" - ulimit_nofile="2448:42192" - SWAP_SIZE="2048" -elif [ ${MEM_SIZE} -lt 57500000 ]; then - # 100000 if 29,215MiB<=mem<54,840MiB - maxconnectioncount="100000" - shmsize="3380m" - ulimit_nofile="2448:222192" - SWAP_SIZE="2048" -else - # 200000 if 54,840MiB<=mem - maxconnectioncount="200000" - shmsize="3380m" - ulimit_nofile="2448:422192" - SWAP_SIZE="2048" -fi -echo "`date` INFO: Based on memory size of ${MEM_SIZE}KiB, determined maxconnectioncount: ${maxconnectioncount}, shmsize: ${shmsize}, ulimit_nofile: ${ulimit_nofile}, SWAP_SIZE: ${SWAP_SIZE}" + +# Common for all scalings +shmsize="1g" +ulimit_nofile="2448:422192" +SWAP_SIZE="2048" + +echo "`date` INFO: Using shmsize: ${shmsize}, ulimit_nofile: ${ulimit_nofile}, SWAP_SIZE: ${SWAP_SIZE}" echo "`date` INFO: Creating Swap space" mkdir /var/lib/solace @@ -187,7 +168,7 @@ chmod 0600 /var/lib/solace/swap swapon -f /var/lib/solace/swap grep -q 'solace\/swap' /etc/fstab || sudo sh -c 'echo "/var/lib/solace/swap none swap sw 0 0" >> /etc/fstab' -echo "`date` INFO: Applying TCP for WAN optimizations" &>> ${LOG_FILE} +echo "`date` INFO: Applying TCP for WAN optimizations" echo ' net.core.rmem_max = 134217728 net.core.wmem_max = 134217728 @@ -198,6 +179,123 @@ sudo sysctl -p /etc/sysctl.d/98-solace-sysctl.conf cd ${solace_directory} +# Setup password file permissions +chown -R 1000001 $(dirname ${admin_password_file}) +chmod 700 $(dirname ${admin_password_file}) + +if [[ ${disk_size} == "0" ]]; then + echo "`date` Using ephemeral volumes" + #Create new volumes that the PubSub+ Message Broker container can use to consume and store data. + docker volume create --name=jail + docker volume create --name=var + docker volume create --name=adb + docker volume create --name=softAdb + docker volume create --name=diagnostics + docker volume create --name=internalSpool + SPOOL_MOUNT="-v jail:/usr/sw/jail -v var:/usr/sw/var -v softAdb:/usr/sw/internalSpool/softAdb -v adb:/usr/sw/adb -v diagnostics:/var/lib/solace/diags -v internalSpool:/usr/sw/internalSpool" +else + echo "`date` Using persistent volumes" + echo "`date` Create primary partition on new disk" + ( + echo n # Add a new partition + echo p # Primary partition + echo 1 # Partition number + echo # First sector (Accept default: 1) + echo # Last sector (Accept default: varies) + echo w # Write changes + ) | sudo fdisk $disk_volume + + mkfs.xfs ${disk_volume}1 -m crc=0 + UUID=`blkid -s UUID -o value ${disk_volume}1` + echo "UUID=${UUID} /opt/pubsubplus xfs defaults 0 0" >> /etc/fstab + mkdir /opt/pubsubplus + mount -a + mkdir /opt/pubsubplus/jail + mkdir /opt/pubsubplus/var + mkdir /opt/pubsubplus/adb + mkdir /opt/pubsubplus/softAdb + mkdir /opt/pubsubplus/diagnostics + mkdir /opt/pubsubplus/internalSpool + chown 1000001 -R /opt/pubsubplus/ + #chmod -R 777 /opt/pubsubplus + + SPOOL_MOUNT="-v /opt/pubsubplus/jail:/usr/sw/jail -v /opt/pubsubplus/var:/usr/sw/var -v /opt/pubsubplus/adb:/usr/sw/adb -v /opt/pubsubplus/softAdb:/usr/sw/internalSpool/softAdb -v /opt/pubsubplus/diagnostics:/var/lib/solace/diags -v /opt/pubsubplus/internalSpool:/usr/sw/internalSpool" +fi + +############# From here execution path is different for nonHA and HA + +if [[ $ha_deployment != "true" ]]; then +############# non-HA setup begins + echo "`date` Continuing single-node setup in a non-HA deployment" + #Define a create script + tee ~/docker-create <<- EOF + #!/bin/bash + docker create \ + --uts=host \ + --shm-size ${shmsize} \ + --ulimit core=-1 \ + --ulimit memlock=-1 \ + --ulimit nofile=${ulimit_nofile} \ + --env "system_scaling_maxconnectioncount=${max_connections}" \ + --env "system_scaling_maxqueuemessagecount=${max_queue_messages}" \ + --net=host \ + --restart=always \ + -v /mnt/pubsubplus/secrets:/run/secrets \ + ${SPOOL_MOUNT} \ + --env "username_admin_globalaccesslevel=admin" \ + --env "username_admin_passwordfilepath=$(basename ${admin_password_file})" \ + --env "service_ssh_port=2222" \ + --env "service_webtransport_port=8008" \ + --env "service_webtransport_tlsport=1443" \ + --env "service_semp_tlsport=1943" \ + --name=solace ${SOLACE_IMAGE_ID} +EOF + + #Make the file executable + chmod +x ~/docker-create + + echo "`date` INFO: Creating the broker container" + ~/docker-create + + # Start the solace service and enable it at system start up. + chkconfig --add solace-pubsubplus + echo "`date` INFO: Starting Solace service" + service solace-pubsubplus start + + # Remove all message broker Secrets from the host; at this point, the message broker should have come up + # and it won't be needing those files anymore + rm ${admin_password_file} + + # Poll the broker Message-Spool + loop_guard=30 + pause=10 + count=0 + echo "`date` INFO: Wait for the broker message-spool service to be guaranteed-active" + while [ ${count} -lt ${loop_guard} ]; do + health_result=`curl -s -o /dev/null -w "%{http_code}" http://localhost:5550/health-check/guaranteed-active` + run_time=$((${count} * ${pause})) + if [ "${health_result}" = "200" ]; then + echo "`date` INFO: broker message-spool is guaranteed-active, after ${run_time} seconds" + break + fi + ((count++)) + echo "`date` INFO: Waited ${run_time} seconds, broker message-spool not yet guaranteed-active. State: ${health_result}" + sleep ${pause} + done + if [ ${count} -eq ${loop_guard} ]; then + echo "`date` ERROR: broker message-spool never came guaranteed-active" | tee /dev/stderr + exit 1 + fi + + echo "`date` INFO: PubSub+ non-HA node bringup complete" + exit +############# non-HA setup ends +fi + +############# From here it's all HA setup +echo "`date` Continuing node setup in an HA deployment" + +# Determine components host_name=`hostname` host_info=`grep ${host_name} ${config_file}` local_role=`echo $host_info | grep -o -E 'Monitor|EventBrokerPrimary|EventBrokerBackup'` @@ -244,94 +342,58 @@ case $local_role in ;; esac -# Setup password file permissions -chown -R 1000001 $(dirname ${admin_password_file}) -chmod 700 $(dirname ${admin_password_file}) - -if [[ ${disk_size} == "0" ]]; then - #Create new volumes that the PubSub+ Message Broker container can use to consume and store data. - docker volume create --name=jail - docker volume create --name=var - docker volume create --name=softAdb - docker volume create --name=diagnostics - docker volume create --name=internalSpool - SPOOL_MOUNT="-v jail:/usr/sw/jail -v var:/usr/sw/var -v softAdb:/usr/sw/internalSpool/softAdb -v diagnostics:/var/lib/solace/diags -v internalSpool:/usr/sw/internalSpool" -else - echo "`date` Create primary partition on new disk" - ( - echo n # Add a new partition - echo p # Primary partition - echo 1 # Partition number - echo # First sector (Accept default: 1) - echo # Last sector (Accept default: varies) - echo w # Write changes - ) | sudo fdisk $disk_volume - - mkfs.xfs ${disk_volume}1 -m crc=0 - UUID=`blkid -s UUID -o value ${disk_volume}1` - echo "UUID=${UUID} /opt/pubsubplus xfs defaults,uid=1000001 0 0" >> /etc/fstab - mkdir /opt/pubsubplus - mkdir /opt/pubsubplus/jail - mkdir /opt/pubsubplus/var - mkdir /opt/pubsubplus/softAdb - mkdir /opt/pubsubplus/diagnostics - mkdir /opt/pubsubplus/internalSpool - mount -a - chown 1000001 -R /opt/pubsubplus/ - SPOOL_MOUNT="-v /opt/pubsubplus/jail:/usr/sw/jail -v /opt/pubsubplus/var:/usr/sw/var -v /opt/pubsubplus/softAdb:/usr/sw/internalSpool/softAdb -v /opt/pubsubplus/diagnostics:/var/lib/solace/diags -v /opt/pubsubplus/internalSpool:/usr/sw/internalSpool" -fi - #Define a create script -tee ~/docker-create <<-EOF +tee ~/docker-create <<- EOF #!/bin/bash docker create \ - --uts=host \ - --shm-size=${shmsize} \ - --ulimit core=-1 \ - --ulimit memlock=-1 \ - --ulimit nofile=${ulimit_nofile} \ - --net=host \ - --restart=always \ - -v /mnt/pubsubplus/secrets:/run/secrets \ - ${SPOOL_MOUNT} \ - --log-driver awslogs \ - --log-opt awslogs-group=${logging_group} \ - --log-opt awslogs-stream=${logging_stream} \ - --env "system_scaling_maxconnectioncount=${maxconnectioncount}" \ - --env "logging_debug_output=all" \ - --env "logging_debug_format=${logging_format}" \ - --env "logging_command_output=all" \ - --env "logging_command_format=${logging_format}" \ - --env "logging_system_output=all" \ - --env "logging_system_format=${logging_format}" \ - --env "logging_event_output=all" \ - --env "logging_event_format=${logging_format}" \ - --env "logging_kernel_output=all" \ - --env "logging_kernel_format=${logging_format}" \ - --env "nodetype=${NODE_TYPE}" \ - --env "routername=${ROUTER_NAME}" \ - --env "username_admin_globalaccesslevel=admin" \ - --env "username_admin_passwordfilepath=$(basename ${admin_password_file})" \ - --env "service_ssh_port=2222" \ - --env "service_webtransport_port=8008" \ - --env "service_webtransport_tlsport=1443" \ - --env "service_semp_tlsport=1943" \ - ${REDUNDANCY_CFG} \ - --env "redundancy_authentication_presharedkey_key=`cat ${admin_password_file} | awk '{x=$0;for(i=length;i<51;i++)x=x "0";}END{print x}' | base64`" \ - --env "redundancy_enable=yes" \ + --uts=host \ + --shm-size=${shmsize} \ + --ulimit core=-1 \ + --ulimit memlock=-1 \ + --ulimit nofile=${ulimit_nofile} \ + --net=host \ + --restart=always \ + -v /mnt/pubsubplus/secrets:/run/secrets \ + ${SPOOL_MOUNT} \ + --log-driver awslogs \ + --log-opt awslogs-group=${logging_group} \ + --log-opt awslogs-stream=${logging_stream} \ + --env "system_scaling_maxconnectioncount=${max_connections}" \ + --env "system_scaling_maxqueuemessagecount=${max_queue_messages}" \ + --env "logging_debug_output=all" \ + --env "logging_debug_format=${logging_format}" \ + --env "logging_command_output=all" \ + --env "logging_command_format=${logging_format}" \ + --env "logging_system_output=all" \ + --env "logging_system_format=${logging_format}" \ + --env "logging_event_output=all" \ + --env "logging_event_format=${logging_format}" \ + --env "logging_kernel_output=all" \ + --env "logging_kernel_format=${logging_format}" \ + --env "nodetype=${NODE_TYPE}" \ + --env "routername=${ROUTER_NAME}" \ + --env "username_admin_globalaccesslevel=admin" \ + --env "username_admin_passwordfilepath=$(basename ${admin_password_file})" \ + --env "service_ssh_port=2222" \ + --env "service_webtransport_port=8008" \ + --env "service_webtransport_tlsport=1443" \ + --env "service_semp_tlsport=1943" \ + ${REDUNDANCY_CFG} \ + --env "redundancy_authentication_presharedkey_key=`cat ${admin_password_file} | awk '{x=$0;for(i=length;i<51;i++)x=x "0";}END{print x}' | base64`" \ + --env "redundancy_enable=yes" \ --env "redundancy_group_node_primary${primary_stack}_nodetype=message_routing" \ --env "redundancy_group_node_primary${primary_stack}_connectvia=${PRIMARY_IP}" \ --env "redundancy_group_node_backup${backup_stack}_nodetype=message_routing" \ --env "redundancy_group_node_backup${backup_stack}_connectvia=${BACKUP_IP}" \ --env "redundancy_group_node_monitor${monitor_stack}_nodetype=monitoring" \ --env "redundancy_group_node_monitor${monitor_stack}_connectvia=${MONITOR_IP}" \ - --name=solace ${SOLACE_IMAGE_ID} + --name=solace ${SOLACE_IMAGE_ID} EOF #Make the file executable chmod +x ~/docker-create -echo "`date` INFO: Creating the Solace container" +echo "`date` INFO: Creating the broker container" ~/docker-create # Start the solace service and enable it at system start up. @@ -346,7 +408,7 @@ count=0 echo "`date` INFO: Wait for the Solace SEMP service to be enabled" while [ ${count} -lt ${loop_guard} ]; do online_results=`/tmp/semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ - -q "" \ + -q "" \ -v "/rpc-reply/rpc/show/service/services/service[name='SEMP']/enabled[text()]"` is_messagebroker_up=`echo ${online_results} | jq '.valueSearchResult' -` @@ -375,7 +437,7 @@ if [ "${is_primary}" = "true" ]; then echo "`date` INFO: Wait for Primary to be 'Local Active' or 'Mate Active'" while [ ${count} -lt ${loop_guard} ]; do online_results=`/tmp/semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ - -q "" \ + -q "" \ -v "/rpc-reply/rpc/show/redundancy/virtual-routers/primary/status/activity[text()]"` local_activity=`echo ${online_results} | jq '.valueSearchResult' -` @@ -410,7 +472,7 @@ if [ "${is_primary}" = "true" ]; then echo "`date` INFO: Wait for Backup to be 'Active' or 'Standby'" while [ ${count} -lt ${loop_guard} ]; do online_results=`/tmp/semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ - -q "" \ + -q "" \ -v "/rpc-reply/rpc/show/redundancy/virtual-routers/primary/status/detail/priority-reported-by-mate/summary[text()]"` mate_activity=`echo ${online_results} | jq '.valueSearchResult' -` @@ -439,14 +501,60 @@ if [ "${is_primary}" = "true" ]; then exit 1 fi + echo "`date` INFO: Initiating config-sync for router" /tmp/semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ - -q "" + -q "" + echo "`date` INFO: Initiating config-sync for default vpn" /tmp/semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ - -q "default" -fi + -q "default" + + # Wait for config-sync results + count=0 + echo "`date` INFO: Waiting for config-sync connected" + while [ ${count} -lt ${loop_guard} ]; do + online_results=`/tmp/semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ + -q "" \ + -v "/rpc-reply/rpc/show/config-sync/status/oper-status"` + + confsyncstatus_results=`echo ${online_results} | jq '.valueSearchResult' -` + echo "`date` INFO: Config-sync is: ${confsyncstatus_results}" + + run_time=$((${count} * ${pause})) + case "${confsyncstatus_results}" in + "\"Up\"") + echo "`date` INFO: Config-sync is Up, after ${run_time} seconds" + break + ;; + esac + ((count++)) + echo "`date` INFO: Waited ${run_time} seconds, Config-sync is not yet Up" + sleep ${pause} + done + + if [ ${count} -eq ${loop_guard} ]; then + echo "`date` ERROR: Config-sync never reached state \"Up\" - exiting." | tee /dev/stderr + exit 1 + fi + + # Poll the broker Message-Spool + count=0 + echo "`date` INFO: Wait for the broker message-spool service to be guaranteed-active" + while [ ${count} -lt ${loop_guard} ]; do + health_result=`curl -s -o /dev/null -w "%{http_code}" http://localhost:5550/health-check/guaranteed-active` + run_time=$((${count} * ${pause})) + if [ "${health_result}" = "200" ]; then + echo "`date` INFO: broker message-spool is guaranteed-active, after ${run_time} seconds" + break + fi + ((count++)) + echo "`date` INFO: Waited ${run_time} seconds, broker message-spool not yet guaranteed-active. State: ${health_result}" + sleep ${pause} + done + if [ ${count} -eq ${loop_guard} ]; then + echo "`date` ERROR: broker message-spool never came guaranteed-active" | tee /dev/stderr + exit 1 + fi -if [ ${count} -eq ${loop_guard} ]; then - echo "`date` ERROR: Solace bringup failed" | tee /dev/stderr - exit 1 fi -echo "`date` INFO: Solace bringup complete" + +echo "`date` INFO: PubSub+ HA-node bringup complete" diff --git a/scripts/semp_query.sh b/scripts/semp_query.sh index 873703e..37bdc8e 100644 --- a/scripts/semp_query.sh +++ b/scripts/semp_query.sh @@ -40,12 +40,12 @@ if [[ ${url} = "" || ${name} = "" || ${password} = "" || ${query} = "" ]]; then echo "{\"errorInfo\":\"missing parameter\"}" exit 1 fi -if [ `curl --write-out '%{http_code}' --silent --output /dev/null -u ${name}:${password} ${url} -d "` != "200" ] ; then +if [ `curl --write-out '%{http_code}' --silent --output /dev/null -u ${name}:${password} ${url} -d ""` != "200" ] ; then echo "{\"errorInfo\":\"management host is not responding\"}" exit 1 fi -query_response=`curl -u ${name}:${password} ${url} -d "${query}"` +query_response=`curl -sS -u ${name}:${password} ${url} -d "${query}"` # Validate first char of response is "<", otherwise no hope of being valid xml if [[ ${query_response:0:1} != "<" ]] ; then echo "{\"errorInfo\":\"no valid xml returned\"}" diff --git a/scripts/wait-for-resource.sh b/scripts/wait-for-resource.sh deleted file mode 100644 index 81609c6..0000000 --- a/scripts/wait-for-resource.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Simple script to wait for a Cloudformation resource -# -# usage: -# $0 [ stack-name ] ResourceName -# -# If no stack is given, we try to figure out out from tags of this -# instance. -# - -murl_top=http://169.254.169.254/latest/meta-data - -ThisInstance=$(curl -f $murl_top/instance-id 2> /dev/null) -if [ -z "$ThisInstance" ] ; then - ThisInstance="unknown" -fi - -ThisRegion=$(curl -f $murl_top/placement/availability-zone 2> /dev/null) -if [ -z "$ThisRegion" ] ; then - ThisRegion="us-east-1" -else - ThisRegion="${ThisRegion%[a-z]}" -fi - -if [ -n "${1}" ] ; then - if [ -z "${2}" ] ; then - ThisStack=$(aws ec2 describe-instances --region $ThisRegion --output text --instance-ids $ThisInstance --query 'Reservations[].Instances[].Tags[?Key==`aws:cloudformation:stack-name`].Value ') - ThisResource=$1 - else - ThisStack=$1 - ThisResource=$2 - fi -fi - -if [ -z "$ThisStack" ] ; then - echo "No AWS Cloudformation Stack specified; aborting script" - exit 1 -elif [ -z "$ThisRegion" ] ; then - echo "Failed to determine AWS region; aborthing script" - exit 1 -fi - -# Validate that the resource actually exists before waiting for it to come up -# -resourceStatus=$(aws cloudformation describe-stack-resources \ - --output text \ - --region $ThisRegion \ - --stack-name $ThisStack \ - --logical-resource-id $ThisResource \ - --query StackResources[].ResourceStatus) - -if [ -z "$resourceStatus" ] ; then - echo "$ThisResource has does not exist in $ThisStack" - exit 0 -fi - -## TBD ... add timeout (optional, since CFT will enforce timeout) -# -while [ $resourceStatus != "CREATE_COMPLETE" ] -do - sleep 30 - resourceStatus=$(aws cloudformation describe-stack-resources \ - --output text \ - --region $ThisRegion \ - --stack-name $ThisStack \ - --logical-resource-id $ThisResource \ - --query StackResources[].ResourceStatus) -done - -echo "$ThisResource has status $resourceStatus" - diff --git a/templates/nodecreate.template b/templates/nodecreate.template index 0b0b647..9277210 100644 --- a/templates/nodecreate.template +++ b/templates/nodecreate.template @@ -5,8 +5,9 @@ Parameters: SolaceDockerImage: Description: >- Solace PubSub+ event broker docker image reference: a docker registry name + Solace PubSub+ event broker Docker image reference: a Docker registry name with optional tag or a download URL. The download URL can be obtained from http://dev.solace.com/downloads/ - or it can be a url to a remotely hosted load version + or it can be a url to an image in a registry or a url to a tar.gz image on a web server Default: solace/solace-pubsub-standard:latest Type: String AdminPassword: @@ -31,32 +32,57 @@ Parameters: MinValue: '8' Type: Number ClusterInfoHandle: - Description: '' - Type: String - InstanceProfile: - Description: IAM Profile for the deployment + Description: Leave this blank for non-HA deployment Type: String + Default: '' KeyPairName: Description: Name of an existing EC2 key pair within the AWS region; all instances will launch with this key pair Type: AWS::EC2::KeyPair::KeyName NodeDesignation: - Default: unspecified - Description: Tag for deployed instances + Default: 'event-broker-singlenode' + Description: Purpose of the deployed instance. Will create a single-node non-HA deployment if set to default "event-broker-singlenode". + Type: String + MaxClientConnections: + AllowedValues: + - '100' + - '1000' + - '10000' + - '100000' + - '200000' + ConstraintDescription: Must be a valid value from the list. + Default: '100' + Description: 'Broker system scaling: the maximum supported number of client connections' + Type: String + MaxQueueMessages: + AllowedValues: + - '100' + - '240' + - '3000' + ConstraintDescription: Must be a valid EC2 instance type. + Default: '100' + Description: 'Broker system scaling: the maximum number of queue messages, in millions' Type: String NodeInstanceType: ConstraintDescription: Must be a valid EC2 instance type. Default: m4.large Description: Instance Type for Solace PubSub+ event broker nodes Type: String + SubnetID: + Description: >- + Comma separated list of VPC subnet IDs for the cluster deployment (e.g. subnet-4b8d329f,subnet-bd73afc8); + VPC must exist with proper configuration for Solacet cluster access (internal + and external) and the subnets must be in the same VPC as the security groups + Type: AWS::EC2::Subnet::Id NodeSecurityGroup: Description: Comma separated list of security groups for the members of the cluster (e.g. sg-7f16e910,sg-4be93ca2); The security groups must be in the same VPC as the subnets Type: List ParentStackName: - Description: Wrapper stack for this deployment + Description: Leave this blank for non-HA deployemnt. For HA, the wrapper stack for this deployment. Type: String + Default: '' PersistentStorage: ConstraintDescription: No more than 1024 GB per device (4 TB per node). Default: '0' @@ -90,18 +116,12 @@ Parameters: QSS3KeyPrefix: AllowedPattern: ^[0-9a-zA-Z-/]*$ ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters, - uppercase letters, hyphens (-), and forward slash (/). + uppercase letters, hyphens (-), and forward slash (/). Must end with a / Default: pubsubplus-aws-ha-quickstart/latest/ Description: S3 key prefix for the Quick Start assets. Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Type: String - SubnetID: - Description: >- - Comma separated list of VPC subnet IDs for the cluster deployment (e.g. subnet-4b8d329f,subnet-bd73afc8); - VPC must exist with proper configuration for Solacet cluster access (internal - and external) and the subnets must be in the same VPC as the security groups - Type: AWS::EC2::Subnet::Id Mappings: AWSAMIRegionMap: AMI: @@ -164,10 +184,8 @@ Conditions: EphemeralStorage: !Equals - !Ref 'PersistentStorage' - '0' - GovCloudCondition: !Equals - - !Ref 'AWS::Region' - - us-gov-west-1 UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] + NonHA: !Equals [!Ref NodeDesignation, 'event-broker-singlenode'] Resources: CloudFormationLogs: Type: AWS::Logs::LogGroup @@ -181,10 +199,10 @@ Resources: Namespace: AWS/EC2 MetricName: StatusCheckFailed_System Statistic: Minimum - Period: '60' - EvaluationPeriods: '3' + Period: 60 + EvaluationPeriods: 3 ComparisonOperator: GreaterThanThreshold - Threshold: '0' + Threshold: 0 AlarmActions: - !Join - '' @@ -193,7 +211,7 @@ Resources: - :ec2:recover Dimensions: - Name: InstanceId - Value: !Ref 'NodeLaunchConfig' + Value: !Ref 'BrokerNodeInstance' NodeRole: Type: AWS::IAM::Role Properties: @@ -244,7 +262,7 @@ Resources: Roles: - !Ref NodeRole Path: / - NodeLaunchConfig: + BrokerNodeInstance: Type: AWS::EC2::Instance Metadata: AWS::CloudFormation::Authentication: @@ -398,14 +416,6 @@ Resources: mode: '000755' owner: root group: root - /tmp/wait-for-resource.sh: - source: !Sub - - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}scripts/wait-for-resource.sh - - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] - S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] - mode: '000755' - owner: root - group: root /etc/init.d/solace-pubsubplus: source: !Sub - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}scripts/init.d/solace-pubsubplus @@ -477,83 +487,137 @@ Resources: - Key: Name Value: !Join - '-' - - - !Ref 'ParentStackName' + - - !If [NonHA, !Ref 'AWS::StackName', !Ref ParentStackName] - !Ref 'NodeDesignation' - Key: ParentStack - Value: !Ref 'ParentStackName' + Value: !If [NonHA, !Ref 'AWS::StackName', !Ref ParentStackName] - Key: HARole - Value: !Ref 'NodeDesignation' - UserData: !Base64 - Fn::Join: - - '' - - - "#!/bin/bash -xe\n" - - "AMI_SBIN=/tmp\n" - - "yum install -y aws-cfn-bootstrap\n" - - "\n" - - "## Retrieve scripts to deploy PubSub+ on the instances \n" - - '/opt/aws/bin/cfn-init -v ' - - ' --stack ' - - !Ref 'AWS::StackName' - - ' --resource NodeLaunchConfig ' - - ' --configsets install_all ' - - ' --region ' - - !Ref 'AWS::Region' - - "\n" - - "## Wait for all nodes to come on-line\n" - - '$AMI_SBIN/wait-for-child-resource.sh ' - - !Ref 'ParentStackName' - - " MonitorStack NodeLaunchConfig\n" - - "\n" - - '$AMI_SBIN/wait-for-child-resource.sh ' - - !Ref 'ParentStackName' - - " EventBrokerPrimaryStack NodeLaunchConfig\n" - - "\n" - - '$AMI_SBIN/wait-for-child-resource.sh ' - - !Ref 'ParentStackName' - - " EventBrokerBackupStack NodeLaunchConfig\n" - - "\n" - - "## Now find the private IP addresses of all deployed nodes\n" - - "## (generating /tmp/solacehosts and /tmp/ files)\n" - - '$AMI_SBIN/gen-cluster-hosts.sh ' - - !Ref 'ParentStackName' - - "\n" - - "## Tag the instance (now that we're sure of launch index)\n" - - "instance_id=$(curl -f http://169.254.169.254/latest/meta-data/instance-id)\n" - - instance_tag= - - !Ref 'ParentStackName' - - '-' - - !Ref 'NodeDesignation' - - "\n" - - " \n" - - aws ec2 create-tags - - ' --region ' - - !Ref 'AWS::Region' - - " --resources $instance_id --tags Key=Name,Value=$instance_tag\n" - - "\n" - - "cd /tmp\n" - - "# Install PubSub+\n" - - $AMI_SBIN/install-solace.sh -c /tmp/solacehosts -d /tmp/solace - - ' -u ' - - !Ref 'SolaceDockerImage' - - ' -p /mnt/pubsubplus/secrets/solOSpasswd' - - ' -s ' - - !Ref 'PersistentStorage' - - ' -v /dev/xvdb' - - ' -f ' - - !Ref 'ContainerLoggingFormat' - - ' -g ' - - !Ref 'CloudFormationLogs' - - ' -r ${instance_id}/solace.log' - - " \n" - - "## Signal back information for outputs (now that all nodes are up)\ - \ \n" - - /opt/aws/bin/cfn-signal -e 0 -r 'PubSub+ HA deployment complete' ' - - !Ref 'ClusterInfoHandle' - - "'\n" - - "\n" + Value: !If [NonHA, 'non-ha', !Ref NodeDesignation] + UserData: + !If + - NonHA + - !Base64 # Simplified setup for non-HA deployment + Fn::Join: + - '' + - - "#!/bin/bash -xe\n" + - "AMI_SBIN=/tmp\n" + - "yum install -y aws-cfn-bootstrap\n" + - "\n" + - "## Retrieve scripts to deploy PubSub+ on the instances \n" + - '/opt/aws/bin/cfn-init -v ' + - ' --stack ' + - !Ref 'AWS::StackName' + - ' --resource BrokerNodeInstance ' + - ' --configsets install_all ' + - ' --region ' + - !Ref 'AWS::Region' + - "\n" + - "cd /tmp\n" + - "# Install PubSub+\n" + - $AMI_SBIN/install-solace.sh -c /tmp/solacehosts -d /tmp/solace + - ' -h false' # specifying non-HA deployment + - ' -u ' + - !Ref 'SolaceDockerImage' + - ' -p /mnt/pubsubplus/secrets/solOSpasswd' + - ' -s ' + - !Ref 'PersistentStorage' + - ' -v /dev/xvdb' + - ' -f ' + - !Ref 'ContainerLoggingFormat' + - ' -g ' + - !Ref 'CloudFormationLogs' + - ' -r ${instance_id}/solace.log' + - ' -n ' + - !Ref 'MaxClientConnections' + - ' -q ' + - !Ref 'MaxQueueMessages' + - "\n" + - !Base64 # Full setup for HA deployment + Fn::Join: + - '' + - - "#!/bin/bash -xe\n" + - "AMI_SBIN=/tmp\n" + - "yum install -y aws-cfn-bootstrap\n" + - "\n" + - "## Retrieve scripts to deploy PubSub+ on the instances \n" + - '/opt/aws/bin/cfn-init -v ' + - ' --stack ' + - !Ref 'AWS::StackName' + - ' --resource BrokerNodeInstance ' + - ' --configsets install_all ' + - ' --region ' + - !Ref 'AWS::Region' + - "\n" + - "## Wait for all nodes to come on-line\n" + - '$AMI_SBIN/wait-for-child-resource.sh ' + - !Ref 'ParentStackName' + - " MonitorStack BrokerNodeInstance\n" + - "\n" + - '$AMI_SBIN/wait-for-child-resource.sh ' + - !Ref 'ParentStackName' + - " EventBrokerPrimaryStack BrokerNodeInstance\n" + - "\n" + - '$AMI_SBIN/wait-for-child-resource.sh ' + - !Ref 'ParentStackName' + - " EventBrokerBackupStack BrokerNodeInstance\n" + - "\n" + - "## Now find the private IP addresses of all deployed nodes\n" + - "## (generating /tmp/solacehosts and /tmp/ files)\n" + - '$AMI_SBIN/gen-cluster-hosts.sh ' + - !Ref 'ParentStackName' + - "\n" + - "## Tag the instance (now that we're sure of launch index)\n" + - "instance_id=$(curl -f http://169.254.169.254/latest/meta-data/instance-id)\n" + - instance_tag= + - !Ref 'ParentStackName' + - '-' + - !Ref 'NodeDesignation' + - "\n" + - " \n" + - aws ec2 create-tags + - ' --region ' + - !Ref 'AWS::Region' + - " --resources $instance_id --tags Key=Name,Value=$instance_tag\n" + - "\n" + - "cd /tmp\n" + - "# Install PubSub+\n" + - $AMI_SBIN/install-solace.sh -c /tmp/solacehosts -d /tmp/solace + - ' -h true' # specifying HA deployment + - ' -u ' + - !Ref 'SolaceDockerImage' + - ' -p /mnt/pubsubplus/secrets/solOSpasswd' + - ' -s ' + - !Ref 'PersistentStorage' + - ' -v /dev/xvdb' + - ' -f ' + - !Ref 'ContainerLoggingFormat' + - ' -g ' + - !Ref 'CloudFormationLogs' + - ' -r ${instance_id}/solace.log' + - ' -n ' + - !Ref 'MaxClientConnections' + - ' -q ' + - !Ref 'MaxQueueMessages' + - " \n" + - "## Signal back information for outputs (now that all nodes are up)\ + \ \n" + - /opt/aws/bin/cfn-signal -e 0 -r 'PubSub+ HA deployment complete' ' + - !Ref 'ClusterInfoHandle' + - "'\n" + - "\n" Outputs: EC2ID: Description: Reference to created ec2 instance - Value: !Ref 'NodeLaunchConfig' + Value: !Ref BrokerNodeInstance Export: Name: !Sub '${AWS::StackName}-EC2ID' + PrivateDnsName: + Description: Private DNS name of the created ec2 instance + Value: !GetAtt BrokerNodeInstance.PrivateDnsName + Export: + Name: !Sub '${AWS::StackName}-PrivateDnsName' + PublicDNSName: + Description: Public DNS name of the created ec2 instance + Value: !GetAtt BrokerNodeInstance.PublicDnsName + Export: + Name: !Sub '${AWS::StackName}-PublicDNSName' diff --git a/templates/solace-master.template b/templates/solace-master.template index 5755546..1445f81 100644 --- a/templates/solace-master.template +++ b/templates/solace-master.template @@ -8,10 +8,15 @@ Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: - default: PubSub+ Configuration + default: PubSub+ Event Broker Configuration Parameters: - SolaceDockerImage - AdminPassword + - MaxClientConnections + - MaxQueueMessages + - WorkerNodeInstanceType + - WorkerNodeStorage + - MonitorNodeInstanceType - ContainerLoggingFormat - Label: default: Network Configuration @@ -26,15 +31,6 @@ Metadata: Parameters: - KeyPairName - BootDiskSize - - Label: - default: Event Broker Instance Configuration - Parameters: - - EventBrokerNodeInstanceType - - EventBrokerNodeStorage - - Label: - default: Monitor Instance Configuration - Parameters: - - MonitorNodeInstanceType - Label: default: AWS Quick Start Configuration Parameters: @@ -54,12 +50,16 @@ Metadata: default: Number of Availability Zones BootDiskSize: default: Boot Disk Capacity (GiB) - EventBrokerNodeInstanceType: - default: Instance Type - EventBrokerNodeStorage: + MaxClientConnections: + default: Maximum Number of Client Connections + MaxQueueMessages: + default: Maximum Number of Queue Messages + WorkerNodeInstanceType: + default: Message Routing Node Instance Type + WorkerNodeStorage: default: Persistent Storage MonitorNodeInstanceType: - default: Instance Type + default: Monitor Node Instance Type KeyPairName: default: Key Pair Name SSHAccessCIDR: @@ -67,7 +67,7 @@ Metadata: RemoteAccessCIDR: default: Allowed External Access CIDR CreatePrivateSubnets: - default: Create production ready enviroment + default: Create production ready environment QSS3BucketName: default: Quick Start S3 Bucket Name QSS3BucketRegion: @@ -79,7 +79,7 @@ Parameters: Description: >- Solace PubSub+ event broker Docker image reference: a Docker registry name with optional tag or a download URL. The download URL can be obtained from http://dev.solace.com/downloads/ - or it can be a url to a remotely hosted load version + or it can be a url to an image in a registry or a url to a tar.gz image on a web server Default: solace/solace-pubsub-standard:latest Type: String AdminPassword: @@ -103,10 +103,10 @@ Parameters: to ''Number of Availability Zones'' previously specified' Type: List NumberOfAZs: - ConstraintDescription: 3 means each node in own az, 2 puts monitor and backup - in one az + ConstraintDescription: Valid numbers are 3 or 2 Default: '3' - Description: Number of availability zones to use + Description: Number of availability zones, based on availability in the target region, valid numbers are 3 or 2. 3 means each node in own AZ, 2 puts monitor and backup + in one AZ. AllowedValues: - '2' - '3' @@ -118,15 +118,33 @@ Parameters: MaxValue: '128' MinValue: '8' Type: Number - EventBrokerNodeInstanceType: + MaxClientConnections: + AllowedValues: + - '100' + - '1000' + - '10000' + - '100000' + - '200000' + ConstraintDescription: Must be a valid value from the list. + Default: '100' + Description: 'Broker system scaling: the maximum supported number of client connections' + Type: String + MaxQueueMessages: + AllowedValues: + - '100' + - '240' + - '3000' + ConstraintDescription: Must be a valid EC2 instance type. + Default: '100' + Description: 'Broker system scaling: the maximum number of queue messages, in millions' + Type: String + WorkerNodeInstanceType: AllowedValues: - t2.small - t2.medium - t2.large - t2.xlarge - t2.2xlarge - - m3.large - - m3.xlarge - m4.large - m4.xlarge - m4.2xlarge @@ -137,10 +155,11 @@ Parameters: - m5.4xlarge ConstraintDescription: Must be a valid EC2 instance type. Default: m4.large - Description: 'Instance Type for PubSub+ event broker message routing nodes. Note: - Make sure that your region supports the selected instance type before continuing' + Description: 'Instance Type for PubSub+ event broker message routing nodes. Important: ensure adequate CPU and Memory resources + are available to support the selected system scaling parameters. For requirements check https://docs.solace.com/. + Also make sure that your region supports the selected instance type before continuing.' Type: String - EventBrokerNodeStorage: + WorkerNodeStorage: ConstraintDescription: No more than 640 GiB per device. Default: '0' Description: Allocated EBS storage for each block device (in GiB); 0 indicates @@ -178,16 +197,13 @@ Parameters: Type: String MonitorNodeInstanceType: AllowedValues: - - t2.micro - t2.small - t2.medium - - t2.large - - t2.xlarge - m4.large - m5.large ConstraintDescription: Must be a valid EC2 instance type. - Default: t2.micro - Description: 'Instance Type for PubSub+ event broker monitoring node. Note: Make + Default: t2.medium + Description: 'Instance Type for PubSub+ event broker monitoring node. For requirements check https://docs.solace.com/. Note: Make sure that your region supports the selected instance type before continuing' Type: String QSS3BucketName: @@ -221,9 +237,6 @@ Conditions: UsePrivateSubnets: !Equals - !Ref 'CreatePrivateSubnets' - 'true' - GovCloudCondition: !Equals - - !Ref 'AWS::Region' - - us-gov-west-1 UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] Resources: VPCStack: @@ -244,8 +257,6 @@ Resources: BastionStack: Type: AWS::CloudFormation::Stack Condition: UsePrivateSubnets - DependsOn: - - VPCStack Properties: TemplateURL: !Sub @@ -283,8 +294,10 @@ Resources: ContainerLoggingFormat: !Ref 'ContainerLoggingFormat' NumberOfAZs: !Ref 'NumberOfAZs' BootDiskSize: !Ref 'BootDiskSize' - EventBrokerNodeInstanceType: !Ref 'EventBrokerNodeInstanceType' - EventBrokerNodeStorage: !Ref 'EventBrokerNodeStorage' + MaxClientConnections: !Ref 'MaxClientConnections' + MaxQueueMessages: !Ref 'MaxQueueMessages' + WorkerNodeInstanceType: !Ref 'WorkerNodeInstanceType' + WorkerNodeStorage: !Ref 'WorkerNodeStorage' MonitorNodeInstanceType: !Ref 'MonitorNodeInstanceType' KeyPairName: !Ref 'KeyPairName' QSS3BucketName: !Ref 'QSS3BucketName' diff --git a/templates/solace.template b/templates/solace.template index de73b64..02203e5 100644 --- a/templates/solace.template +++ b/templates/solace.template @@ -5,10 +5,15 @@ Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: - default: Solace Configuration + default: PubSub+ Event Broker Configuration Parameters: - SolaceDockerImage - AdminPassword + - MaxClientConnections + - MaxQueueMessages + - WorkerNodeInstanceType + - WorkerNodeStorage + - MonitorNodeInstanceType - ContainerLoggingFormat - Label: default: Network Configuration @@ -25,15 +30,6 @@ Metadata: Parameters: - KeyPairName - BootDiskSize - - Label: - default: Event Broker Instance Configuration - Parameters: - - EventBrokerNodeInstanceType - - EventBrokerNodeStorage - - Label: - default: Monitor Instance Configuration - Parameters: - - MonitorNodeInstanceType - Label: default: AWS Quick Start Configuration Parameters: @@ -42,27 +38,31 @@ Metadata: - QSS3KeyPrefix ParameterLabels: SolaceDockerImage: - default: Solace Docker image reference + default: PubSub+ Docker image reference AdminPassword: - default: Password to access Solace admin console and SEMP + default: Password to access PubSub+ admin console and SEMP ContainerLoggingFormat: default: Container logging format + NumberOfAZs: + default: Number of Availability Zones BootDiskSize: default: Boot Disk Capacity (GiB) - EventBrokerNodeInstanceType: - default: Instance Type - EventBrokerNodeStorage: + MaxClientConnections: + default: Maximum Number of Client Connections + MaxQueueMessages: + default: Maximum Number of Queue Messages + WorkerNodeInstanceType: + default: Message Routing Node Instance Type + WorkerNodeStorage: default: Persistent Storage MonitorNodeInstanceType: - default: Instance Type + default: Monitor Node Instance Type KeyPairName: default: Key Pair Name - NumberOfAZs: - default: Number of Availability Zones to use RemoteAccessCIDR: default: Allowed External Access CIDR SSHSecurityGroupID: - default: Security group allowed to access console SSH + default: Security group allowed to access console SSH. Ignored if not using private subnets. UsePrivateSubnets: default: Use private subnets VPCID: @@ -80,13 +80,14 @@ Metadata: Parameters: SolaceDockerImage: Description: >- - Solace PubSub+ event broker docker image reference: a docker registry name + Solace PubSub+ event broker Docker image reference: a Docker registry name with optional tag or a download URL. The download URL can be obtained from http://dev.solace.com/downloads/ - or it can be a url to a remotely hosted load version + or it can be a url to an image in a registry or a url to a tar.gz image on a web server Default: solace/solace-pubsub-standard:latest Type: String AdminPassword: - Description: Required password to access Solace admin console and SEMP + Description: Password to allow Solace admin access to configure the event broker + instances Type: String NoEcho: 'True' ContainerLoggingFormat: @@ -99,6 +100,15 @@ Parameters: Default: graylog Description: PubSub+ event broker logging format in CloudWatch Type: String + NumberOfAZs: + ConstraintDescription: Valid numbers are 3 or 2 + Default: '3' + Description: Number of availability zones, based on availability in the target region, valid numbers are 3 or 2. 3 means each node in own AZ, 2 puts monitor and backup + in one AZ. + AllowedValues: + - '2' + - '3' + Type: Number BootDiskSize: ConstraintDescription: Deployment supports 8 to 128 GB for boot volumes Default: '24' @@ -106,15 +116,33 @@ Parameters: MaxValue: '128' MinValue: '8' Type: Number - EventBrokerNodeInstanceType: + MaxClientConnections: + AllowedValues: + - '100' + - '1000' + - '10000' + - '100000' + - '200000' + ConstraintDescription: Must be a valid value from the list. + Default: '100' + Description: 'Broker system scaling: the maximum supported number of client connections' + Type: String + MaxQueueMessages: + AllowedValues: + - '100' + - '240' + - '3000' + ConstraintDescription: Must be a valid EC2 instance type. + Default: '100' + Description: 'Broker system scaling: the maximum number of queue messages, in millions' + Type: String + WorkerNodeInstanceType: AllowedValues: - t2.small - t2.medium - t2.large - t2.xlarge - t2.2xlarge - - m3.large - - m3.xlarge - m4.large - m4.xlarge - m4.2xlarge @@ -125,10 +153,11 @@ Parameters: - m5.4xlarge ConstraintDescription: Must be a valid EC2 instance type. Default: m4.large - Description: 'Instance Type for PubSub+ event broker message routing nodes. Note: - Make sure that your region supports the selected instance type before continuing' + Description: 'Instance Type for PubSub+ event broker message routing nodes. Important: ensure adequate CPU and Memory resources + are available to support the selected system scaling parameters. For requirements check https://docs.solace.com/. + Also make sure that your region supports the selected instance type before continuing.' Type: String - EventBrokerNodeStorage: + WorkerNodeStorage: ConstraintDescription: No more than 640 GiB per device. Default: '0' Description: Allocated EBS storage for each block device (in GiB); 0 indicates @@ -143,49 +172,37 @@ Parameters: - '320' - '640' Type: Number - MonitorNodeInstanceType: - AllowedValues: - - t2.micro - - t2.small - - t2.medium - - t2.large - - t2.xlarge - - m4.large - - m5.large - ConstraintDescription: Must be a valid EC2 instance type. - Default: t2.micro - Description: 'Instance Type for PubSub+ event broker monitoring node. Note: Make - sure that your region supports the selected instance type before continuing' - Type: String KeyPairName: Description: Name of an existing EC2 key pair within the AWS region; all instances will launch with this key pair Type: AWS::EC2::KeyPair::KeyName - NumberOfAZs: - ConstraintDescription: 3 means each node in own az, 2 puts monitor and backup - in one az - Default: '3' - Description: Number of availability zones to use + UsePrivateSubnets: AllowedValues: - - '2' - - '3' - Type: Number + - 'true' + - 'false' + Default: 'true' + Description: Whether to use Private Subnets with fronting Bastion Servers + Type: String RemoteAccessCIDR: AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/x Description: Allowed CIDR block for external access to cluster nodes Type: String + MonitorNodeInstanceType: + AllowedValues: + - t2.small + - t2.medium + - m4.large + - m5.large + ConstraintDescription: Must be a valid EC2 instance type. + Default: t2.medium + Description: 'Instance Type for PubSub+ event broker monitoring node. For requirements check https://docs.solace.com/. Note: Make + sure that your region supports the selected instance type before continuing' + Type: String SSHSecurityGroupID: Description: 'ID of the SSH Security Group (e.g., sg-7f16e910). Note: This will be ignored if ''Use private subnets'' is set to ''false''' Type: String - UsePrivateSubnets: - AllowedValues: - - 'true' - - 'false' - Default: 'true' - Description: Whether to use Private Subnets with fronting Bastion Servers - Type: String PrivateSubnetIDs: Description: >- Comma separated list of VPC private subnet IDs for the cluster deployment (e.g. @@ -224,50 +241,6 @@ Parameters: can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Type: String -Mappings: - AWSInfoRegionMap: - ap-northeast-1: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - ap-northeast-2: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - ap-south-1: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - ap-southeast-1: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - ap-southeast-2: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - ca-central-1: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - eu-central-1: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - eu-west-1: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - eu-west-2: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - sa-east-1: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - us-east-1: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - us-east-2: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - us-west-1: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com - us-west-2: - Partition: aws - QuickStartS3URL: https://s3.amazonaws.com Conditions: EnableWaitConditions: !Equals - '1' @@ -278,62 +251,8 @@ Conditions: UsePrivateSubnetsCondition: !Equals - !Ref 'UsePrivateSubnets' - 'true' - GovCloudCondition: !Equals - - !Ref 'AWS::Region' - - us-gov-west-1 UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] Resources: - SolaceVMRRole: - Type: AWS::IAM::Role - Properties: - Policies: - - PolicyDocument: - Version: '2012-10-17' - Statement: - - Action: - - s3:GetObject - Resource: "*" - Effect: Allow - PolicyName: s3-policy - - PolicyDocument: - Version: '2012-10-17' - Statement: - - Action: - - cloudformation:DescribeStackResources - - ec2:DescribeInstances - - ec2:CreateTags - Resource: - - '*' - Effect: Allow - PolicyName: ec2-policy - - PolicyDocument: - Version: '2012-10-17' - Statement: - - Action: - - logs:CreateLogGroup - - logs:CreateLogStream - - logs:PutLogEvents - - logs:DescribeLogStreams - Resource: - - arn:aws:logs:*:*:* - Effect: Allow - PolicyName: cloudwatch-policy - Path: / - AssumeRolePolicyDocument: - Statement: - - Action: - - sts:AssumeRole - Principal: - Service: - - ec2.amazonaws.com - Effect: Allow - Version: '2012-10-17' - InstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: / - Roles: - - !Ref 'SolaceVMRRole' EventBrokerPrimaryStack: Type: AWS::CloudFormation::Stack Properties: @@ -348,18 +267,19 @@ Resources: ContainerLoggingFormat: !Ref 'ContainerLoggingFormat' BootDiskSize: !Ref 'BootDiskSize' ClusterInfoHandle: !Ref 'ClusterInfoHandle' - InstanceProfile: !Ref 'InstanceProfile' KeyPairName: !Ref 'KeyPairName' - NodeDesignation: message-router-primary - NodeInstanceType: !Ref 'EventBrokerNodeInstanceType' + NodeDesignation: event-broker-primary + MaxClientConnections: !Ref 'MaxClientConnections' + MaxQueueMessages: !Ref 'MaxQueueMessages' + NodeInstanceType: !Ref 'WorkerNodeInstanceType' NodeSecurityGroup: !Join - ',' - - !Ref 'EventBrokerSecurityGroup' - !Ref 'SolaceInternalSecurityGroup' - - !Ref 'SolaceInternalSecurityGroupMember' + - !Ref 'BrokerMemberNodesSecurityGroup' - !Ref 'RemoteMgmtSecurityGroup' ParentStackName: !Ref 'AWS::StackName' - PersistentStorage: !Ref 'EventBrokerNodeStorage' + PersistentStorage: !Ref 'WorkerNodeStorage' QSS3BucketName: !Ref 'QSS3BucketName' QSS3BucketRegion: !Ref 'QSS3BucketRegion' QSS3KeyPrefix: !Ref 'QSS3KeyPrefix' @@ -383,18 +303,19 @@ Resources: ContainerLoggingFormat: !Ref 'ContainerLoggingFormat' BootDiskSize: !Ref 'BootDiskSize' ClusterInfoHandle: !Ref 'ClusterInfoHandle' - InstanceProfile: !Ref 'InstanceProfile' KeyPairName: !Ref 'KeyPairName' - NodeDesignation: message-router-backup - NodeInstanceType: !Ref 'EventBrokerNodeInstanceType' + NodeDesignation: event-broker-backup + MaxClientConnections: !Ref 'MaxClientConnections' + MaxQueueMessages: !Ref 'MaxQueueMessages' + NodeInstanceType: !Ref 'WorkerNodeInstanceType' NodeSecurityGroup: !Join - ',' - - !Ref 'EventBrokerSecurityGroup' - !Ref 'SolaceInternalSecurityGroup' - - !Ref 'SolaceInternalSecurityGroupMember' + - !Ref 'BrokerMemberNodesSecurityGroup' - !Ref 'RemoteMgmtSecurityGroup' ParentStackName: !Ref 'AWS::StackName' - PersistentStorage: !Ref 'EventBrokerNodeStorage' + PersistentStorage: !Ref 'WorkerNodeStorage' QSS3BucketName: !Ref 'QSS3BucketName' QSS3BucketRegion: !Ref 'QSS3BucketRegion' QSS3KeyPrefix: !Ref 'QSS3KeyPrefix' @@ -418,14 +339,13 @@ Resources: ContainerLoggingFormat: !Ref 'ContainerLoggingFormat' BootDiskSize: !Ref 'BootDiskSize' ClusterInfoHandle: !Ref 'ClusterInfoHandle' - InstanceProfile: !Ref 'InstanceProfile' KeyPairName: !Ref 'KeyPairName' NodeDesignation: monitor NodeInstanceType: !Ref 'MonitorNodeInstanceType' NodeSecurityGroup: !Join - ',' - - !Ref 'SolaceInternalSecurityGroup' - - !Ref 'SolaceInternalSecurityGroupMember' + - !Ref 'BrokerMemberNodesSecurityGroup' - !Ref 'RemoteMgmtSecurityGroup' ParentStackName: !Ref 'AWS::StackName' PersistentStorage: '0' @@ -433,87 +353,79 @@ Resources: QSS3BucketRegion: !Ref 'QSS3BucketRegion' QSS3KeyPrefix: !Ref 'QSS3KeyPrefix' SubnetID: !Select - - !If - - Use3AZs - - 2 - - 1 - - !If - - UsePrivateSubnetsCondition - - !Ref 'PrivateSubnetIDs' - - !Ref 'PublicSubnetIDs' - SolaceInternalSecurityGroupMember: + - !If [Use3AZs, 2, 1] + - !If [UsePrivateSubnetsCondition, !Ref PrivateSubnetIDs, !Ref PublicSubnetIDs] + BrokerMemberNodesSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref 'VPCID' - GroupDescription: All Solace Nodes + GroupDescription: Internal group, includes broker node members only SolaceInternalSecurityGroup: Type: AWS::EC2::SecurityGroup - DependsOn: - - SolaceInternalSecurityGroupMember Properties: VpcId: !Ref 'VPCID' - GroupDescription: All Solace Nodes + GroupDescription: Controls internal traffic between broker member nodes SecurityGroupIngress: - IpProtocol: tcp - FromPort: '8741' - ToPort: '8741' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 8741 + ToPort: 8741 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '8300' - ToPort: '8302' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 8300 + ToPort: 8302 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: udp - FromPort: '8300' - ToPort: '8302' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 8300 + ToPort: 8302 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '55555' - ToPort: '55555' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 55555 + ToPort: 55555 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '55003' - ToPort: '55003' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 55003 + ToPort: 55003 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '55443' - ToPort: '55443' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 55443 + ToPort: 55443 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '1443' - ToPort: '1443' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 1443 + ToPort: 1443 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '8000' - ToPort: '8000' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 8000 + ToPort: 8000 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '5672' - ToPort: '5672' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 5672 + ToPort: 5672 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '9000' - ToPort: '9000' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 9000 + ToPort: 9000 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '1883' - ToPort: '1883' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 1883 + ToPort: 1883 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '8008' - ToPort: '8008' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 8008 + ToPort: 8008 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '8080' - ToPort: '8080' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 8080 + ToPort: 8080 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '1943' - ToPort: '1943' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 1943 + ToPort: 1943 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' - IpProtocol: tcp - FromPort: '5550' - ToPort: '5550' - SourceSecurityGroupId: !Ref 'SolaceInternalSecurityGroupMember' + FromPort: 5550 + ToPort: 5550 + SourceSecurityGroupId: !Ref 'BrokerMemberNodesSecurityGroup' RemoteMgmtSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: @@ -523,12 +435,12 @@ Resources: - !If - UsePrivateSubnetsCondition - IpProtocol: tcp - FromPort: '22' - ToPort: '22' + FromPort: 22 + ToPort: 22 SourceSecurityGroupId: !Ref 'SSHSecurityGroupID' - IpProtocol: tcp - FromPort: '22' - ToPort: '22' + FromPort: 22 + ToPort: 22 CidrIp: !Ref 'RemoteAccessCIDR' EventBrokerSecurityGroup: Type: AWS::EC2::SecurityGroup @@ -537,52 +449,52 @@ Resources: GroupDescription: Event Broker Security Group SecurityGroupIngress: - IpProtocol: tcp - FromPort: '5550' - ToPort: '5550' + FromPort: 5550 + ToPort: 5550 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '55555' - ToPort: '55555' + FromPort: 55555 + ToPort: 55555 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '55003' - ToPort: '55003' + FromPort: 55003 + ToPort: 55003 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '55443' - ToPort: '55443' + FromPort: 55443 + ToPort: 55443 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '1443' - ToPort: '1443' + FromPort: 1443 + ToPort: 1443 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '8000' - ToPort: '8000' + FromPort: 8000 + ToPort: 8000 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '5672' - ToPort: '5672' + FromPort: 5672 + ToPort: 5672 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '9000' - ToPort: '9000' + FromPort: 9000 + ToPort: 9000 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '1883' - ToPort: '1883' + FromPort: 1883 + ToPort: 1883 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '8008' - ToPort: '8008' + FromPort: 8008 + ToPort: 8008 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '8080' - ToPort: '8080' + FromPort: 8080 + ToPort: 8080 CidrIp: !Ref 'RemoteAccessCIDR' - IpProtocol: tcp - FromPort: '1943' - ToPort: '1943' + FromPort: 1943 + ToPort: 1943 CidrIp: !Ref 'RemoteAccessCIDR' ClusterInfoHandle: Type: AWS::CloudFormation::WaitConditionHandle @@ -596,7 +508,7 @@ Resources: Properties: Handle: !Ref 'ClusterInfoHandle' Timeout: '600' - Count: '1' + Count: 1 ELB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer DependsOn: @@ -617,7 +529,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -634,7 +546,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -651,7 +563,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -668,7 +580,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -685,7 +597,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -702,7 +614,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -719,7 +631,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -736,7 +648,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -753,7 +665,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -770,7 +682,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -787,7 +699,7 @@ Resources: Protocol: TCP VpcId: !Ref 'VPCID' HealthCheckPath: '/health-check/guaranteed-active' - HealthCheckPort: 5550 + HealthCheckPort: '5550' HealthCheckProtocol: 'HTTP' Targets: - Id: !GetAtt 'EventBrokerPrimaryStack.Outputs.EC2ID' @@ -796,133 +708,122 @@ Resources: Port: 1943 Port55555NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port55555NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '55555' + Port: 55555 Protocol: TCP Port55003NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port55003NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '55003' + Port: 55003 Protocol: TCP Port55443NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port55443NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '55443' + Port: 55443 Protocol: TCP Port1443NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port1443NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '1443' + Port: 1443 Protocol: TCP Port8000NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port8000NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '8000' + Port: 8000 Protocol: TCP Port5672NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port5672NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '5672' + Port: 5672 Protocol: TCP Port9000NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port9000NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '9000' + Port: 9000 Protocol: TCP Port1883NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port1883NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '1883' + Port: 1883 Protocol: TCP Port8008NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port8008NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '8008' + Port: 8008 Protocol: TCP Port8080NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port8080NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '8080' + Port: 8080 Protocol: TCP Port1943NetworkLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - ELB Condition: UsePrivateSubnetsCondition Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'Port1943NetworkLoadBalancerTargetGroup' LoadBalancerArn: !Ref 'ELB' - Port: '1943' + Port: 1943 Protocol: TCP +Outputs: + BrokerMemberNodesSecurityGroup: + Value: !Ref BrokerMemberNodesSecurityGroup + Description: Internal closed Security Group with only broker nodes as members + Export: + Name: !Sub '${AWS::StackName}-BrokerMemberNodesSecurityGroup' + LoadBalancerDNS: + Value: !If [UsePrivateSubnetsCondition, !GetAtt ELB.DNSName, 'No LB available, access EC2s through public addresses'] + Description: The DNS name for the load balancer for external access + Export: + Name: !Sub '${AWS::StackName}-LoadBalancerDNS'