AWSTemplateFormatVersion: '2010-09-09' Description: CloudFormation sub-template for Single Node EC2 deployment within Solace HA Cluster. (qs-1nm1r54hd) Metadata: cfn-lint: config: ignore_checks: - W9002 # temporary to get rid of warnings - W9003 # temporary to get rid of warnings - W9006 # temporary to get rid of warnings 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 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: Password to access PubSub+ admin console and SEMP Type: String NoEcho: 'True' ContainerLoggingFormat: AllowedValues: - graylog - legacy - raw - rfc5424 ConstraintDescription: Must be a valid container logging format. Default: graylog Description: PubSub+ event broker logging format in CloudWatch Type: String BootDiskSize: ConstraintDescription: Deployment supports 8 to 128 GB for boot volumes Default: '24' Description: Allocated EBS storage for boot disk MaxValue: '128' MinValue: '8' Type: Number ClusterInfoHandle: 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: '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 Solace cluster access (internal and external) and the subnets must be in the same VPC as the security groups Type: AWS::EC2::Subnet::Id AssociatePublicIP: AllowedValues: - 'true' - 'false' Default: 'true' Description: Whether to associate a public IP address to this instance Type: String 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: 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' Description: >- Allocated EBS storage for each block device (in GB; 4 devs per node); 0 indicates ephemeral storage only. Non-zero will cause a new io1 disk creation for message-spool which will NOT be deleted on stack termination AllowedValues: - '0' - '20' - '40' - '80' - '160' - '320' - '640' Type: Number PersistentStorageType: Default: 'gp2' Description: Storage volume type provided by Amazon EBS. "io1" is recommended for Production environments (better performance, more expensive) and is required for large storage size. AllowedValues: - 'gp2' - 'io1' Type: String QSS3BucketName: AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ ConstraintDescription: Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Default: aws-quickstart Description: S3 bucket name for the Quick Start assets. Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String QSS3BucketRegion: Default: 'us-east-1' Description: 'The AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. When using your own bucket, you must specify this value.' Type: String QSS3KeyPrefix: AllowedPattern: ^[0-9a-zA-Z-/]*$ ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Must end with a / Default: quickstart-solace-pubsub/ 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 Mappings: AWSAMIRegionMap: AMI: AMZNLINUXHVM: amzn-ami-hvm-2018.03.0.20190611-x86_64-gp2 ap-northeast-1: AMZNLINUXHVM: ami-02ddf94e5edc8e904 ap-northeast-2: AMZNLINUXHVM: ami-0ecd78c22823e02ef ap-south-1: AMZNLINUXHVM: ami-05695932c5299858a ap-southeast-1: AMZNLINUXHVM: ami-043afc2b8b6cfba5c ap-southeast-2: AMZNLINUXHVM: ami-01393ce9a3ca55d67 ca-central-1: AMZNLINUXHVM: ami-0fa94ecf2fef3420b eu-central-1: AMZNLINUXHVM: ami-0ba441bdd9e494102 eu-west-1: AMZNLINUXHVM: ami-0e61341fa75fcaa18 eu-west-2: AMZNLINUXHVM: ami-050b8344d77081f4b eu-west-3: AMZNLINUXHVM: ami-053418e626d0549fc eu-north-1: AMZNLINUXHVM: ami-8c169ef2 sa-east-1: AMZNLINUXHVM: ami-05b7dbc290217250d us-east-1: AMZNLINUXHVM: ami-0e2ff28bfb72a4e45 us-east-2: AMZNLINUXHVM: ami-0998bf58313ab53da us-west-1: AMZNLINUXHVM: ami-021bb9f371690f97a us-west-2: AMZNLINUXHVM: ami-079f731edfe27c29c LinuxAMINameMap: Amazon-Linux-HVM: Code: AMZNLINUXHVM Linux2BootDisk: Amazon-Linux-HVM: BootDisk: /dev/xvda Linux2SpoolDisk: Amazon-Linux-HVM: SpoolDisk: /dev/xvdb IOPsMap: '0': IOPs: '0' '20': IOPs: '1000' '40': IOPs: '2000' '80': IOPs: '4000' '160': IOPs: '8000' '320': IOPs: '16000' '640': IOPs: '20000' Conditions: EphemeralStorage: !Equals - !Ref 'PersistentStorage' - '0' IOStorageType: !Equals - !Ref 'PersistentStorageType' - 'io1' UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] NonHA: !Equals [!Ref NodeDesignation, 'event-broker-singlenode'] AssociatePublicIPCondition: !Equals - !Ref 'AssociatePublicIP' - 'true' Resources: CloudFormationLogs: Type: AWS::Logs::LogGroup Properties: RetentionInDays: 7 RecoveryTestAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: Trigger a recovery when instance status check fails for 3 consecutive minutes. Namespace: AWS/EC2 MetricName: StatusCheckFailed_System Statistic: Minimum Period: 60 EvaluationPeriods: 3 ComparisonOperator: GreaterThanThreshold Threshold: 0 AlarmActions: - !Join - '' - - 'arn:aws:automate:' - !Ref 'AWS::Region' - :ec2:recover Dimensions: - Name: InstanceId Value: !Ref 'BrokerNodeInstance' NodeRole: Type: AWS::IAM::Role Properties: Policies: - PolicyName: aws-quick-start-s3-policy PolicyDocument: Version: '2012-10-17' Statement: - Action: - s3:GetObject Resource: !Sub - arn:${AWS::Partition}:s3:::${S3Bucket}/${QSS3KeyPrefix}* - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref 'QSS3BucketName' Effect: Allow - PolicyName: cfn-policy PolicyDocument: Version: '2012-10-17' Statement: - Action: - cloudformation:DescribeStackResources Resource: !Sub arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/* Effect: Allow - PolicyName: ec2-policy PolicyDocument: Version: '2012-10-17' Statement: - Action: - ec2:DescribeInstances Resource: '*' Effect: Allow - PolicyName: ec2-tags-policy PolicyDocument: Version: '2012-10-17' Statement: - Action: - ec2:CreateTags Resource: !Sub arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:instance/* Effect: Allow - PolicyName: cloudwatch-policy PolicyDocument: Version: '2012-10-17' Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - logs:DescribeLogStreams Resource: - !Sub arn:${AWS::Partition}:logs:*:*:* Effect: Allow Path: / AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Principal: Service: - ec2.amazonaws.com Effect: Allow Version: '2012-10-17' NodeProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref NodeRole Path: / BrokerNodeInstance: Type: AWS::EC2::Instance Metadata: AWS::CloudFormation::Authentication: S3AccessCreds: type: S3 roleName: !Ref NodeRole buckets: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] AWS::CloudFormation::Init: configSets: install_all: - install_awscli - install_logs - install_docker - install_extras - install_solace install_awscli: packages: python: awscli: [] install_logs: packages: yum: awslogs: [] files: /etc/awslogs/awslogs.conf: content: !Join - '' - - "[general]\n" - "state_file= /var/awslogs/state/agent-state\n" - "[/var/log/cloud-init.log]\n" - "file = /var/log/cloud-init.log\n" - 'log_group_name = ' - !Ref 'CloudFormationLogs' - "\n" - "log_stream_name = {instance_id}/cloud-init.log\n" - "datetime_format = \n" - "[/var/log/cloud-init-output.log]\n" - "file = /var/log/cloud-init-output.log\n" - 'log_group_name = ' - !Ref 'CloudFormationLogs' - "\n" - "log_stream_name = {instance_id}/cloud-init-output.log\n" - "datetime_format = \n" - "[/var/log/cfn-init.log]\n" - "file = /var/log/cfn-init.log\n" - 'log_group_name = ' - !Ref 'CloudFormationLogs' - "\n" - "log_stream_name = {instance_id}/cfn-init.log\n" - "datetime_format = \n" - "[/var/log/cfn-hup.log]\n" - "file = /var/log/cfn-hup.log\n" - 'log_group_name = ' - !Ref 'CloudFormationLogs' - "\n" - "log_stream_name = {instance_id}/cfn-hup.log\n" - "datetime_format = \n" - "[/var/log/cfn-wire.log]\n" - "file = /var/log/cfn-wire.log\n" - 'log_group_name = ' - !Ref 'CloudFormationLogs' - "\n" - "log_stream_name = {instance_id}/cfn-wire.log\n" - "datetime_format = \n" - "[/var/log/solace.log]\n" - "file = /var/log/solace.log\n" - 'log_group_name = ' - !Ref 'CloudFormationLogs' - "\n" - "log_stream_name = {instance_id}/solace.log\n" - "datetime_format = \n" mode: '000444' owner: root group: root /etc/awslogs/awscli.conf: content: !Join - '' - - "[plugins]\n" - "cwlogs = cwlogs\n" - "[default]\n" - 'region = ' - !Ref 'AWS::Region' - "\n" mode: '000444' owner: root group: root commands: '01_create_state_directory': command: mkdir -p /var/awslogs/state services: sysvinit: awslogs: enabled: 'true' ensureRunning: 'true' files: - /etc/awslogs/awslogs.conf install_docker: packages: yum: docker: [] wget: [] lvm2: [] files: /etc/sysconfig/docker: content: !Join - '' - - "DAEMON_PIDFILE_TIMEOUT=10\n" - "OPTIONS=\"--default-ulimit nofile=1024:4096 --iptables=false\ \ --storage-driver overlay2\"\n" mode: '000444' owner: root group: root commands: '01_add_ec2-user_to_docker_group': command: usermod -a -G docker ec2-user services: sysvinit: docker: enabled: 'true' ensureRunning: 'true' files: - /etc/sysconfig/docker install_extras: packages: yum: epel-release: [] jq: [] install_solace: commands: '01_create_secrets_directory': command: mkdir -p /mnt/pubsubplus/secrets files: /mnt/pubsubplus/secrets/solOSpasswd: content: !Join - '' - - !Ref 'AdminPassword' - "\n" /tmp/gen-cluster-hosts.sh: source: !Sub - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}scripts/gen-cluster-hosts.sh - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] mode: '000755' owner: root group: root /tmp/wait-for-child-resource.sh: source: !Sub - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}scripts/wait-for-child-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 - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] mode: '000755' owner: root group: root /tmp/install-solace.sh: source: !Sub - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}scripts/install-solace.sh - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] mode: '000755' owner: root group: root /tmp/semp_query.sh: source: !Sub - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}scripts/semp_query.sh - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] mode: '000755' owner: root group: root Properties: BlockDeviceMappings: !If - EphemeralStorage - - DeviceName: !FindInMap - Linux2BootDisk - Amazon-Linux-HVM - BootDisk Ebs: VolumeSize: !Ref 'BootDiskSize' DeleteOnTermination: 'True' - - DeviceName: !FindInMap - Linux2BootDisk - Amazon-Linux-HVM - BootDisk Ebs: VolumeSize: !Ref 'BootDiskSize' DeleteOnTermination: 'False' - DeviceName: !FindInMap - Linux2SpoolDisk - Amazon-Linux-HVM - SpoolDisk Ebs: VolumeSize: !Ref 'PersistentStorage' DeleteOnTermination: 'False' VolumeType: !Ref 'PersistentStorageType' Iops: !If - IOStorageType - !FindInMap - IOPsMap - !Ref 'PersistentStorage' - IOPs - !Ref 'AWS::NoValue' ImageId: !FindInMap - AWSAMIRegionMap - !Ref 'AWS::Region' - AMZNLINUXHVM InstanceType: !Ref 'NodeInstanceType' KeyName: !Ref 'KeyPairName' NetworkInterfaces: - AssociatePublicIpAddress: true DeleteOnTermination: true Description: Main interface DeviceIndex: '0' GroupSet: !Ref 'NodeSecurityGroup' SubnetId: !Ref 'SubnetID' IamInstanceProfile: !Ref NodeProfile Tags: - Key: Name Value: !Join - '-' - - !If [NonHA, !Ref 'AWS::StackName', !Ref ParentStackName] - !Ref 'NodeDesignation' - Key: ParentStack Value: !If [NonHA, !Ref 'AWS::StackName', !Ref ParentStackName] - Key: HARole 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 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: !If [AssociatePublicIPCondition, !GetAtt BrokerNodeInstance.PublicDnsName, 'Public DNS name not available'] Export: Name: !Sub '${AWS::StackName}-PublicDNSName'