From 9e70032cce24831f54f5f735fcbb38317ecb4ac2 Mon Sep 17 00:00:00 2001 From: bczoma Date: Thu, 10 May 2018 14:57:09 -0400 Subject: [PATCH 01/14] readme and image updates, added scaling tiers, enabled small size for monitor, enabled docker image fetch from server, improved logs --- README.md | 83 ++--- azuredeploy.json | 28 +- images/{single-vmr.png => single-node.png} | Bin loadbalancer-shared-resources.json | 4 +- metadata.json | 10 +- scripts/{deploy_vmr.sh => deploy_solace.sh} | 325 +++++++++++--------- security-shared-resources.json | 6 +- 7 files changed, 242 insertions(+), 214 deletions(-) rename images/{single-vmr.png => single-node.png} (100%) rename scripts/{deploy_vmr.sh => deploy_solace.sh} (53%) diff --git a/README.md b/README.md index 7ad1de9..cbfc229 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,39 @@ -# Deploy either a standalone Solace Message Router or a three node High Availability cluster of Solace Message Routers onto Azure Linux VM(s). +# How to Deploy Standalone or HA Clusters of Solace PubSub+ Software Message Brokers onto Azure -The Solace Virtual Message Router (VMR) is enterprise-grade messaging middleware that meets the needs of big data, cloud migration, and internet of things initiatives, and enables microservices and event-driven architecture. Capabilities include topic-based publish/subscribe, request/reply, message queues/queueing, and data streaming for IoT devices and mobile/web apps. The VMR supports open APIs and standard protocols including AMQP, JMS, MQTT, REST, and WebSocket. The VMR can be deployed in on-premise datacenters, natively within private and public clouds, and across complex hybrid cloud environments. +The Solace PubSub+ software message broker meets the needs of big data, cloud migration, and Internet-of-Things initiatives, and enables microservices and event-driven architecture. Capabilities include topic-based publish/subscribe, request/reply, message queues/queueing, and data streaming for IoT devices and mobile/web apps. The message broker supports open APIs and standard protocols including AMQP, JMS, MQTT, REST, and WebSocket. As well, it can be deployed in on-premise datacenters, natively within private and public clouds, and across complex hybrid cloud environments. -How to Deploy a VMR +How to Deploy a Solace PubSub+ Software Message Broker ------------------- -VMRs can either be deployed as a three node HA cluster or a single node. For simple test environments that need to validate application functionality, a single instance will suffice. +Message brokers can be deployed in three node HA clusters or as single, standalone nodes. For simple test environments that only need to validate application functionality, a single instance will suffice. -![alt text](images/single-vmr.png "Single Node Deployment") +![alt text](images/single-node.png "Single Node Deployment") -Note that in production or any environment where message loss can not be tolerated, an HA cluster is required. +Note that in production, or any environment where message loss cannot be tolerated, an HA cluster is required. ![alt text](images/ha-cluster.png "HA Cluster Deployment") This is a two step process: -* Go to the Solace Developer portal and request a Solace Community edition VMR or Evaluation edition VMR. This process will send you an email with a Download link. Right click "Copy Hyperlink" on the "Download the VMR for Docker" hyperlink. This URL will be needed in the following section. The link below will take you to the correct version of the VMR you require depending on whether you want a single instance or an HA Cluster. +### Step 1: -| COMMUNITY EDITION FOR SINGLE NODE | EVALUATION EDITION FOR HA CLUSTER -| --- | --- | - - - +Go to the Solace Developer Portal and request a Solace PubSub+ software message broker. This process will return an email with a Download link. To get going, right click "Copy Hyperlink" on the "Download the Solace PubSub+ Software Message Broker for Docker" hyperlink. This will be needed in the following section. - - - +You can use this quick start template with either PubSub+ `Standard` or PubSub+ `Enterprise Evaluation Edition`. +| PubSub+ Standard | PubSub+ Enterprise Evaluation Edition +| :---: | :---: | +| Free, up to 1k simultaneous connections,
up to 100k messages per second | 90-day trial version, unlimited | +| | | + +
+
+ +### Step 2: -* Hit the "Deploy to Azure" button, and in the deployment template add the link to the VMR provided by Solace. +Hit the "Deploy to Azure" button, and in the deployment template add the link to the Solace PubSub+ software message broker. @@ -39,7 +42,7 @@ This is a two step process: -The fields that you need to fill out are: +You need to fill in the following fields: | Field | Value | |----------------------------|--------------------------------------------------------------------------------| @@ -49,64 +52,64 @@ The fields that you need to fill out are: | **SETTINGS** | | | Storage Account Name | New or existing storage account, where your VHD will be stored. | | Admin Username | Username for the virtual Machine(s). Do not use special characters. | -| Admin Password | Password for the virtual Machine(s) and for the 'admin' SolOS CLI user. | -| Security Group Name | New or existing security group, where VMR default ports will be made publicly available. | +| Admin Password | Password for the virtual Machine(s) and for the 'admin' management user. | +| Security Group Name | New or existing security group, where message broker default ports will be made publicly available. | | Workspace Name | New or existing OMS Log Analytics workspace, where logs and diagnostics are monitored. | | Workspace Region | Select region to deploy OMS Log Analytics workspace. | | DNS Label for LB IP | Used for the public DNS name of the Load Balancer. | -| DNS Label for VM IP | Used for the public DNS name of each Virtual Machine(s). | +| DNS Label for VM IP | Used for the public DNS name of each Virtual Machine. | | CentOS Version | The CentOS version for deploying the Docker containers. Use CentOS 7.2, 7.3, or 7.4. | -| Message Routing VM Size | The size of the VM for the Solace Message Routing Nodes. Use Standard_D2_v2, Standard_DS2_v2, Standard_D2_v3, or Standard_D2s_v3. Note that not all regions support all these VM sizes. | -| Monitor VM Size | The size of the VM for the Solace Monitor Node. Use Standard_D2_v2, Standard_DS2_v2, Standard_D2_v3, or Standard_D2s_v3. Note that not all regions support all these VM sizes. | -| Data Disk Size | The size of the data disk in GB for diagnostics and message spooling on the Solace Message Routing Nodes. Use 0, 20, 40, 80, or 160. | -| Solace VMR URI | The URI link from the registration email received during Step 1 of the install process. | +| Message Broker VM Size | The size of the VM for the message brokers. Use Standard_D2_v2, Standard_DS2_v2, Standard_D2_v3, or Standard_D2s_v3. Note that not all regions support all these VM sizes. | +| Monitor VM Size | The size of the VM for the monitoring node. Use Standard_D2_v2, Standard_DS2_v2, Standard_D2_v3, or Standard_D2s_v3. Note that not all regions support all these VM sizes. | +| Data Disk Size | The size of the data disk in GB for diagnostics and message spooling on the message brokers. Use 0, 20, 40, 80, or 160. | +| Solace PubSub+ software message broker URI | URL from the registration email. Can also use load versions hosted remotely (if so, a .md5 file needs to be created in the same remote directory). | | Deployment Model | High Availability or Single Node. | After completing the template fields and accepting the legal terms, you need to purchase the deployment. The cost will only be related to the Azure instance and storage costs. Once the deployment has started, you can view its progress under the Resource Groups tab. Select the resource group you have deployed into, then select the correct deployment across the top. You can then scroll down and see its progress. -In this example, the resource group is `testvmr3` and the `Microsoft.Template` template is in progress. You can see the VMs `SolaceVMR0`, `SolaceVMR1`, and `SolaceVMR2` have started, the Docker Extensions have been installed on each VM, and the VMR configurations are taking place. Once the VMRs are configured, the Primary VMR validates the cluster and signals the deployment as completed. At this point, you can access the VMRs. +In this example, the resource group is `testmessagebroker3` and the `Microsoft.Template` template is in progress. You can see the VMs `SolaceMessageBroker0`, `SolaceMessageBroker1`, and `SolaceMessageBroker2` have started, the Docker Extensions have been installed on each VM, and the message broker configurations are taking place. Once the message brokers are configured, the primary message broker validates the cluster and signals the deployment as completed. At this point, you can access the message brokers. ![alt text](images/deployment.png "deployment progress") -In addition to the above resources, the deployment creates an Azure Load Balancer that gives you management and data access to the currently AD-Active VMR. +In addition to the above resources, the deployment creates an Azure Load Balancer that gives you management and data access to the currently AD-Active message broker. -Microsoft OMS (Operations Management Suite) Agents are also installed on each VMR using the OMS Agent Extension. They collect and send logs to a new or existing Azure Log Analytics workspace resource that aggregates logs and diagnostics from each virtual machine in the deployment. +Microsoft OMS (Operations Management Suite) Agents are also installed on each message broker using the OMS Agent Extension. They collect and send logs to a new or existing Azure Log Analytics workspace resource that aggregates logs and diagnostics from each virtual machine in the deployment. -# Gaining admin access to the VMR +# Gaining admin access to the message broker -If you are used to working with console access to the Solace message router, this is available with the Azure instance. The [connect] button at the upper left of the `SolaceVMR0`, `SolaceVMR1`, or `SolaceVMR2` resource view displays this information: +If you are used to working with console access to Solace PubSub+, this is available with the Azure instance. The [connect] button at the upper left of the `SolaceMessageBroker0`, `SolaceMessageBroker1`, or `SolaceMessageBroker2` resource view displays this information: -![alt text](images/remote_access.png "console with SolOS cli") +![alt text](images/remote_access.png "console with Solace cli") -Use the specified "Admin Username" and "Admin Password" to log in. Once you have access to the base OS command line you can access the SolOS CLI with the following command: +Use the specified "Admin Username" and "Admin Password" to log in. Once you have access to the base OS command line you can access the Solace CLI with the following command: ``` sudo docker exec -it solace /usr/sw/loads/currentload/bin/cli -A ``` -If you are unfamiliar with the Solace message router, or would prefer an administration application, the SolAdmin management application is available. For more information on SolAdmin see the [SolAdmin page](http://dev.solace.com/tech/soladmin/). To get SolAdmin, visit the Solace [download page](http://dev.solace.com/downloads/) and select the OS version desired. The Management IP would be the external Public IP associated with your Azure instance and the port would be 8080 by default. +If you are unfamiliar with Solace PubSub+ message brokers, or would prefer an administration application, the SolAdmin management application is available. For more information on SolAdmin see the [SolAdmin page](http://dev.solace.com/tech/soladmin/). To get SolAdmin, visit the Solace [download page](http://dev.solace.com/downloads/) and select the OS version desired. The Management IP would be the external Public IP associated with your Azure instance and the port would be 8080 by default. ![alt text](images/azure-soladmin.png "soladmin connection to gce") -To manage the currently AD-Active VMR, you can open a CLI SSH connection (on port 2222) or connect SolAdmin (on port 8080) to the Public IP Address associated with the Load Balancer as the 'admin' user. From the Resource Group view for your deployment on the Azure Portal, the Load Balancer is the resource named `myLB`, and its Public IP Address is the resource named `myLBPublicIPD`, which has an IP address and a DNS name that you can connect to. +To manage the currently AD-Active message broker, you can open a CLI SSH connection (on port 2222) or connect SolAdmin (on port 8080) to the Public IP Address associated with the Load Balancer as the 'admin' user. From the Resource Group view for your deployment on the Azure Portal, the Load Balancer is the resource named `myLB`, and its Public IP Address is the resource named `myLBPublicIPD`, which has an IP address and a DNS name that you can connect to. -# Testing data access to the VMR +# Testing data access to the message broker -To test data traffic though the newly created VMR instance, visit the Solace developer portal and and select your preferred programming language to [send and receive messages](http://dev.solace.com/get-started/send-receive-messages/). Under each language there is a Publish/Subscribe tutorial that will help you get started. +To test data traffic though the newly created message broker instance, visit the Solace developer portal and select your preferred programming language to [send and receive messages](http://dev.solace.com/get-started/send-receive-messages/). Under each language there is a Publish/Subscribe tutorial that will help you get started. -To connect to the currently AD-Active VMR for messaging, use the Public IP Address associated with the Load Balancer. From the Resource Group view for your deployment on the Azure Portal, the Load Balancer is the resource named `myLB`, and its Public IP Address is the resource named `myLBPublicIPD`, which has an IP address and a DNS name that you can connect to. +To connect to the currently AD-Active message broker for messaging, use the Public IP Address associated with the Load Balancer. From the Resource Group view for your deployment on the Azure Portal, the Load Balancer is the resource named `myLB`, and its Public IP Address is the resource named `myLBPublicIPD`, which has an IP address and a DNS name that you can connect to. ![alt text](images/solace_tutorial.png "getting started publish/subscribe") -# Troubleshouting VMR startup +# Troubleshooting message broker startup All startup logs are located on the host under this path: `/var/lib/waagent/custom-script/download/0/` and are readable by root only. -Host and Container logs and diagnostics are collected and aggregated in a Azure Log Analytics workspace that can be viewed and analyzed from the Azure Portal. The Log Analytics resource can be found under the Resource Groups tab > your Resource Group or under More services > Intelligence + Analytics. The Container Monitoring Solution and the Log Search solution are installed as part of the deployment. VMR container logs are collected under the `Syslog` Type. +Host and Container logs and diagnostics are collected and aggregated in an Azure Log Analytics workspace that can be viewed and analyzed from the Azure Portal. The Log Analytics resource can be found under the Resource Groups tab > your Resource Group or under More services > Intelligence + Analytics. The Container Monitoring Solution and the Log Search solution are installed as part of the deployment. Message broker container logs are collected under the `Syslog` Type. ## Contributing @@ -122,7 +125,7 @@ This project is licensed under the Apache License, Version 2.0. - See the [LICEN ## Resources -For more information about writing Azure Resource Manager(ARM) templates and Azure quickstart templates try these resources: +For more information about writing Azure Resource Manager(ARM) templates and Azure Quickstart templates try these resources: - [Authoring Azure Resource Manager templates](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authoring-templates) - [Azure Quickstart Templates](https://azure.microsoft.com/en-us/resources/templates/) @@ -131,4 +134,4 @@ For more information about Solace technology in general please visit these resou - [Solace Developer Portal](http://dev.solace.com) - [Intro Solace technology](http://dev.solace.com/tech/) -- [Solace community on Stack Overflow](http://dev.solace.com/community/). +- [Solace community on Stack Overflow](http://dev.solace.com/community/). \ No newline at end of file diff --git a/azuredeploy.json b/azuredeploy.json index 0321702..1ef02bf 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -22,9 +22,9 @@ }, "securityGroupName": { "type": "string", - "defaultValue": "vmr-security", + "defaultValue": "solace-security", "metadata": { - "description": "Security group defined to support VMR system level and default message vpn ports." + "description": "Security group defined to support PubSub+ message broker system level and default message vpn ports." } }, "workspaceName": { @@ -89,11 +89,13 @@ }, "monitorVmSize": { "type": "string", - "defaultValue": "Standard_D2_v2", + "defaultValue": "Standard_D1_v2", "metadata": { - "description": "The size of the Solace Monitor Node VM. Requires at least 2 cores and 4GB of memory. Allowed values: D2_v2, DS2_v2, D2_v3, D2s_v3" + "description": "The size of the Solace Monitor Node VM. Requires at least 1 core and 1GB of memory. Allowed values: D1_v2, DS1_v2, D2_v2, DS2_v2, D2_v3, D2s_v3" }, "allowedValues": [ + "Standard_D1_v2", + "Standard_DS1_v2", "Standard_D2_v2", "Standard_DS2_v2", "Standard_D2_v3", @@ -114,10 +116,10 @@ "160" ] }, - "solaceVmrUri": { + "solaceDockerImageUri": { "type": "string", "metadata": { - "description": "The URI location of the Solace VMR Docker container tarball" + "description": "The URI location of the PubSub+ message broker Docker container tarball" } }, "deploymentModel": { @@ -140,21 +142,21 @@ "OSDiskName": "osdiskfordockersimple", "dataDiskName": "datadiskfordockersimple", "nicName": "myVMNicD", - "scriptUrl": "https://raw.githubusercontent.com/SolaceProducts/solace-azure-quickstart-template/master/", + "scriptUrl": "https://raw.githubusercontent.com/SolaceDev/solace-azure-quickstart-template/Rebranding-updates/", "solaceSecurityName": "SolaceSecurity.Template", "securitySharedTemplateName": "security-shared-resources.json", "solaceLoadBalancerName": "SolaceLoadBalancer.Template", "loadBalancerSharedTemplateName": "loadbalancer-shared-resources.json", "solaceWorkspaceName": "SolaceWorkspace.Template", "workspaceSharedTemplateName": "workspace-shared-resources.json", - "solaceInstallScriptName": "deploy_vmr.sh", + "solaceInstallScriptName": "deploy_solace.sh", "sempQueryScriptName": "semp_query.sh", "publicIPAddressName": "myPublicIPD", "publicIPAddressNameLB": "myLBPublicIPD", "publicIPAddressType": "Dynamic", "vmStorageAccountVHDsName": "vhds", "vmStorageAccountContainersName": "containers", - "vmName": "SolaceVMR", + "vmName": "SolaceVM", "addressPrefix": "10.0.0.0/16", "subnetPrefix": "10.0.0.0/24", "nodeAddressPrefix": "10.0.0.10", @@ -169,7 +171,7 @@ "monitorNodeIndex": 2, "lbName" : "myLB", "lbID": "[resourceId('Microsoft.Network/loadBalancers',variables('lbName'))]", - "lbPoolName": "vmr-ha-group", + "lbPoolName": "solace-ha-group", "lbPoolID": "[concat(variables('lbID'),'/backendAddressPools/',variables('lbPoolName'))]", "dataDiskVolume" : "/dev/sdc", "dataDisksChoices": { @@ -476,7 +478,7 @@ { "apiVersion": "2016-03-30", "type": "Microsoft.Compute/virtualMachines/extensions", - "name": "[concat(variables('vmName'), copyindex(), '/configureVMRContainer')]", + "name": "[concat(variables('vmName'), copyindex(), '/configureSolaceContainer')]", "location": "[resourceGroup().location]", "copy": { "name": "SolaceLoop", @@ -492,13 +494,13 @@ "autoUpgradeMinorVersion": true, "settings": { "fileUris": [ - "[parameters('solaceVmrUri')]", + "[parameters('solaceDockerImageUri')]", "[concat(variables('scriptUrl'), 'scripts/', variables('solaceInstallScriptName'))]", "[concat(variables('scriptUrl'), 'scripts/', variables('sempQueryScriptName'))]" ] }, "protectedSettings": { - "commandToExecute": "[concat('mkdir -p -m 600 ', variables('adminPasswordDir'), '; echo ', parameters('adminPassword'), ' > ', variables('adminPasswordFile'), '; bash ', variables('solaceInstallScriptName'), ' -c ', copyindex(), ' -i ', variables('nodeAddressPrefix'), ' -n ', variables('numberOfInstances'), ' -p ', variables('adminPasswordFile'), ' -s ', if(equals(copyindex(), variables('monitorNodeIndex')), '0', parameters('dataDiskSize')), if(equals(copyindex(), variables('monitorNodeIndex')), '', concat(' -v ', variables('dataDiskVolume'))), ' -u ', parameters('solaceVmrUri'))]" + "commandToExecute": "[concat('mkdir -p -m 600 ', variables('adminPasswordDir'), '; echo ', parameters('adminPassword'), ' > ', variables('adminPasswordFile'), '; bash ', variables('solaceInstallScriptName'), ' -c ', copyindex(), ' -i ', variables('nodeAddressPrefix'), ' -n ', variables('numberOfInstances'), ' -p ', variables('adminPasswordFile'), ' -s ', if(equals(copyindex(), variables('monitorNodeIndex')), '0', parameters('dataDiskSize')), if(equals(copyindex(), variables('monitorNodeIndex')), '', concat(' -v ', variables('dataDiskVolume'))), ' -u ', parameters('solaceDockerImageUri'))]" } } } diff --git a/images/single-vmr.png b/images/single-node.png similarity index 100% rename from images/single-vmr.png rename to images/single-node.png diff --git a/loadbalancer-shared-resources.json b/loadbalancer-shared-resources.json index 0fddd83..96388e8 100644 --- a/loadbalancer-shared-resources.json +++ b/loadbalancer-shared-resources.json @@ -31,7 +31,7 @@ }, "lbPoolName": { "type": "string", - "defaultValue": "vmr-ha-group", + "defaultValue": "solace-ha-group", "metadata": { "description": "Load Balancer Backend Address Pool Name." } @@ -42,7 +42,7 @@ "frontEndIPConfigName": "LoadBalancerFrontEnd", "frontEndIPConfigID": "[concat(variables('lbID'),'/frontendIPConfigurations/',variables('frontEndIPConfigName'))]", "lbPoolID": "[concat(variables('lbID'),'/backendAddressPools/',parameters('lbPoolName'))]", - "lbProbeName": "vmr-ha-ad-health-check", + "lbProbeName": "solace-ha-ad-health-check", "lbProbeID": "[concat(variables('lbID'),'/probes/',variables('lbProbeName'))]" }, "resources": [ diff --git a/metadata.json b/metadata.json index 176e2c9..fcf0966 100644 --- a/metadata.json +++ b/metadata.json @@ -1,7 +1,7 @@ { - "itemDisplayName": "Deploy Solace Message Router(s) onto Azure Linux VM(s)", - "description": "This template allows you to deploy either a standalone Solace Message Router or a three node High Availability cluster of Solace Message Routers onto Azure Linux VM(s).", - "summary": "This template deploys either a standalone Solace Message Router or a three node High Availability cluster of Solace Message Routers onto Azure Linux VM(s).", - "githubUsername": "KenBarr", - "dateUpdated": "2018-01-31" + "itemDisplayName": "Deploy Solace PubSub+ message broker(s) onto Azure Linux VM(s)", + "description": "This template allows you to deploy either a standalone Solace PubSub+ message broker or a three node High Availability cluster of Solace PubSub+ message brokers onto Azure Linux VM(s).", + "summary": "This template deploys either a standalone Solace PubSub+ message broker or a three node High Availability cluster of Solace PubSub+ message brokers onto Azure Linux VM(s).", + "githubUsername": "SolaceDev", + "dateUpdated": "2018-05-31" } \ No newline at end of file diff --git a/scripts/deploy_vmr.sh b/scripts/deploy_solace.sh similarity index 53% rename from scripts/deploy_vmr.sh rename to scripts/deploy_solace.sh index 6c47541..375c66c 100644 --- a/scripts/deploy_vmr.sh +++ b/scripts/deploy_solace.sh @@ -1,4 +1,20 @@ #!/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. @@ -6,32 +22,31 @@ OPTIND=1 # Reset in case getopts has been used previously in the shell. current_index="" ip_prefix="" number_of_instances="" -password_file="" +solace_url="" +admin_password_file="" disk_size="" disk_volume="" -solace_url="" -DEBUG="-vvvv" is_primary="false" verbose=0 while getopts "c:i:n:p:s:v:u:" opt; do - case "$opt" in - c) current_index=$OPTARG - ;; - i) ip_prefix=$OPTARG - ;; - n) number_of_instances=$OPTARG - ;; - p) password_file=$OPTARG - ;; - s) disk_size=$OPTARG - ;; - v) disk_volume=$OPTARG - ;; - u) solace_url=$OPTARG - ;; - esac + case "$opt" in + c) current_index=$OPTARG + ;; + i) ip_prefix=$OPTARG + ;; + n) number_of_instances=$OPTARG + ;; + p) admin_password_file=$OPTARG + ;; + s) disk_size=$OPTARG + ;; + u) solace_url=$OPTARG + ;; + v) disk_volume=$OPTARG + ;; + esac done shift $((OPTIND-1)) @@ -39,124 +54,122 @@ shift $((OPTIND-1)) verbose=1 echo "`date` current_index=$current_index , ip_prefix=$ip_prefix , number_of_instances=$number_of_instances , \ - password_file=$password_file , disk_size=$disk_size , disk_volume=$disk_volume , solace_url=$solace_url , Leftovers: $@" -export password=`cat ${password_file}` + password_file=$admin_password_file , disk_size=$disk_size , disk_volume=$disk_volume , solace_url=$solace_url , Leftovers: $@" +export admin_password=`cat ${admin_password_file}` #Install the logical volume manager and jq for json parsing yum -y install lvm2 yum -y install epel-release yum -y install jq -#Load the VMR -REAL_LINK= -for filename in ./*; do - echo "File = ${filename}" - count=`grep -c "https://products.solace.com" ${filename}` - if [ "1" = ${count} ]; then - REAL_LINK=`egrep -o "https://[a-zA-Z0-9\.\/\_\?\=]*" ${filename}` - fi -done -echo "`date` INFO: check to make sure we have a complete load" -if [[ ${REAL_LINK} == "" ]]; then - # an already-existing load (plus its md5 file) hosted somewhere else (e.g. in an s3 bucket) - wget -O /tmp/solos.info -nv ${solace_url}.md5 - IFS=' ' read -ra SOLOSOTHER_INFO <<< `cat /tmp/solos.info` - MD5_SUM_OTHER=${SOLOSOTHER_INFO[0]} - SolOS_OTHER_LOAD=${SOLOSOTHER_INFO[1]} - echo "`date` INFO: Reference md5sum is: ${MD5_SUM_OTHER}" +#Load the VMR +solace_directory="/tmp" + +echo "`date` INFO: RETRIEVE SOLACE DOCKER IMAGE" +echo "#############################################################" +if [[ ${solace_url} == *"em.solace.com"* ]]; then + wget -q -O ${solace_directory}/solace-redirect ${solace_url} || echo "There has been an issue with downloading the redirect" + REAL_LINK=`egrep -o "https://[a-zA-Z0-9\.\/\_\?\=%]*" ${solace_directory}/solace-redirect` + LOAD_NAME="`echo $REAL_LINK | awk -v FS="(download/|?)" '{print $2}'`" + # a redirect link provided by solace + wget -O ${solace_directory}/solos.info -nv https://products.solace.com/download/${LOAD_NAME}_MD5 else - MD5_SUM_OTHER="" - SolOS_OTHER_LOAD="" + REAL_LINK=${solace_url} + # an already-existing load (plus its md5 file) hosted somewhere else (e.g. in an s3 bucket) + wget -O ${solace_directory}/solos.info -nv ${solace_url}.md5 fi -wget -O /tmp/solosEval.info -nv https://products.solace.com/download/VMR_DOCKER_EVAL_MD5 -IFS=' ' read -ra SOLOSEVAL_INFO <<< `cat /tmp/solosEval.info` -MD5_SUM_EVAL=${SOLOSEVAL_INFO[0]} -SolOS_EVAL_LOAD=${SOLOSEVAL_INFO[1]} -echo "`date` INFO: Reference eval md5sum is: ${MD5_SUM_EVAL}" - -wget -O /tmp/solosComm.info -nv https://products.solace.com/download/VMR_DOCKER_COMM_MD5 -IFS=' ' read -ra SOLOSCOMM_INFO <<< `cat /tmp/solosComm.info` -MD5_SUM_COMM=${SOLOSCOMM_INFO[0]} -SolOS_COMM_LOAD=${SOLOSCOMM_INFO[1]} -echo "`date` INFO: Reference comm md5sum is: ${MD5_SUM_COMM}" +IFS=' ' read -ra SOLOS_INFO <<< `cat ${solace_directory}/solos.info` +MD5_SUM=${SOLOS_INFO[0]} +SolOS_LOAD=${SOLOS_INFO[1]} +if [ -z ${MD5_SUM} ]; then + echo "`date` ERROR: Missing md5sum for the Solace load" | tee /dev/stderr + exit 1 +fi +echo "`date` INFO: Reference md5sum is: ${MD5_SUM}" -echo "`date` INFO: try 3 times to download from URL provided and validate it is Evaluation and Community edition VRM" +echo "`date` INFO: Download from URL provided and validate, trying up to 3 times" LOOP_COUNT=0 -SolOS_LOAD=solos.tar.gz -isEval=0 - while [ $LOOP_COUNT -lt 3 ]; do - if [[ ${REAL_LINK} == "" ]]; then - mv ./$(basename ${solace_url}) /tmp/${SolOS_LOAD} - else - wget -q -O /tmp/${SolOS_LOAD} -nv ${REAL_LINK} - fi - - LOCAL_OS_INFO=`md5sum /tmp/${SolOS_LOAD}` + wget -q -O ${solace_directory}/${SolOS_LOAD} ${REAL_LINK} || echo "There has been an issue with downloading the Solace load" + LOCAL_OS_INFO=`md5sum ${SolOS_LOAD}` IFS=' ' read -ra SOLOS_INFO <<< ${LOCAL_OS_INFO} LOCAL_MD5_SUM=${SOLOS_INFO[0]} - if [ ${LOCAL_MD5_SUM} == ${MD5_SUM_COMM} ]; then - echo "`date` INFO: Successfully downloaded ${SolOS_COMM_LOAD}" - break - fi - if [ ${LOCAL_MD5_SUM} == ${MD5_SUM_EVAL} ]; then - echo "`date` INFO: Successfully downloaded ${SolOS_EVAL_LOAD}" - isEval=1 - break - fi - if [ ${LOCAL_MD5_SUM} == ${MD5_SUM_OTHER} ]; then - echo "`date` INFO: Successfully downloaded ${SolOS_OTHER_LOAD}" - if [[ $(basename ${solace_url}) != *"-vmr-community"* ]]; then - isEval=1 - fi + if [ ${LOCAL_MD5_SUM} != ${MD5_SUM} ]; then + echo "`date` WARN: Possible corrupt Solace load, md5sum do not match" + else + echo "`date` INFO: Successfully downloaded ${SolOS_LOAD}" break fi - echo "`date` WARNING: CORRUPT SolOS load re-try ${LOOP_COUNT}" ((LOOP_COUNT++)) done - if [ ${LOOP_COUNT} == 3 ]; then - echo "`date` ERROR: Failed to download SolOS exiting" | tee /dev/stderr + echo "`date` ERROR: Failed to download the Solace load, exiting" | tee /dev/stderr exit 1 fi -echo "`date` INFO: Check if there is a requirement for 3 node cluster and not Evalution edition exit" -if [ ${isEval} == 0 ] && [ ${number_of_instances} == 3 ]; then - echo "`date` ERROR: Trying to build HA cluster with community edition SolOS, this is not supported" | tee /dev/stderr - exit 1 -fi - -echo "`date` INFO: Setting up SolOS Docker image" -docker load -i /tmp/${SolOS_LOAD} +echo "`date` INFO: LOAD DOCKER IMAGE INTO LOCAL STORE" +echo "##################################################################" +if [ `docker images "solace-*" -q` ] ; then docker rmi -f `docker images "solace-*" -q`; fi; +docker load -i ${solace_directory}/${SolOS_LOAD} -export VMR_VERSION=`docker images | grep solace | awk '{print $2}'` -echo "`date` INFO: VMR version: ${VMR_VERSION}" +export VMR_IMAGE=`docker images | grep solace | awk '{print $1 ":" $2}'` +echo "`date` INFO: Solace message broker image: ${VMR_IMAGE}" +# 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 6087960 ]; then - echo "`date` WARN: Not enough memory: ${MEM_SIZE} Creating 2GB Swap space" - mkdir /var/lib/solace - dd if=/dev/zero of=/var/lib/solace/swap count=2048 bs=1MiB - mkswap -f /var/lib/solace/swap - 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' +if [ ${MEM_SIZE} -lt 4000000 ]; then + # 100 if mem<4GiB + maxconnectioncount="100" + shmsize="1g" + ulimit_nofile="2448:6592" + SWAP_SIZE="1024" +elif [ ${MEM_SIZE} -lt 12000000 ]; then + # 1000 if 4GiB<=mem<12GiB + maxconnectioncount="1000" + shmsize="2g" + ulimit_nofile="2448:10192" + SWAP_SIZE="2048" +elif [ ${MEM_SIZE} -lt 29000000 ]; then + # 10000 if 12GiB<=mem<28GiB + maxconnectioncount="10000" + shmsize="2g" + ulimit_nofile="2448:42192" + SWAP_SIZE="2048" +elif [ ${MEM_SIZE} -lt 58000000 ]; then + # 100000 if 28GiB<=mem<56GiB + maxconnectioncount="100000" + shmsize="3380m" + ulimit_nofile="2448:222192" + SWAP_SIZE="2048" else - echo "`date` INFO: Memory size is ${MEM_SIZE}" + # 200000 if 56GiB<=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}" + +echo "`date` INFO: Creating Swap space" +mkdir /var/lib/solace +dd if=/dev/zero of=/var/lib/solace/swap count=${SWAP_SIZE} bs=1MiB +mkswap -f /var/lib/solace/swap +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' if [ ${number_of_instances} -gt 1 ]; then echo "`date` INFO: Configuring HA tuple" - case ${current_index} in + case ${current_index} in 0 ) redundancy_config="\ --env nodetype=message_routing \ --env routername=primary \ --env redundancy_matelink_connectvia=${ip_prefix}1 \ --env redundancy_activestandbyrole=primary \ - --env redundancy_group_passwordfilepath=$(basename ${password_file}) \ + --env redundancy_group_passwordfilepath=$(basename ${admin_password_file}) \ --env redundancy_enable=yes \ --env redundancy_group_node_primary_nodetype=message_routing \ --env redundancy_group_node_primary_connectvia=${ip_prefix}0 \ @@ -166,14 +179,14 @@ if [ ${number_of_instances} -gt 1 ]; then --env redundancy_group_node_monitor_connectvia=${ip_prefix}2 \ --env configsync_enable=yes" is_primary="true" - ;; - 1 ) + ;; + 1 ) redundancy_config="\ --env nodetype=message_routing \ --env routername=backup \ --env redundancy_matelink_connectvia=${ip_prefix}0 \ --env redundancy_activestandbyrole=backup \ - --env redundancy_group_passwordfilepath=$(basename ${password_file}) \ + --env redundancy_group_passwordfilepath=$(basename ${admin_password_file}) \ --env redundancy_enable=yes \ --env redundancy_group_node_primary_nodetype=message_routing \ --env redundancy_group_node_primary_connectvia=${ip_prefix}0 \ @@ -182,12 +195,12 @@ if [ ${number_of_instances} -gt 1 ]; then --env redundancy_group_node_monitor_nodetype=monitoring \ --env redundancy_group_node_monitor_connectvia=${ip_prefix}2 \ --env configsync_enable=yes" - ;; - 2 ) + ;; + 2 ) redundancy_config="\ --env nodetype=monitoring \ --env routername=monitor \ - --env redundancy_group_passwordfilepath=$(basename ${password_file}) \ + --env redundancy_group_passwordfilepath=$(basename ${admin_password_file}) \ --env redundancy_enable=yes \ --env redundancy_group_node_primary_nodetype=message_routing \ --env redundancy_group_node_primary_connectvia=${ip_prefix}0 \ @@ -195,7 +208,7 @@ if [ ${number_of_instances} -gt 1 ]; then --env redundancy_group_node_backup_connectvia=${ip_prefix}1 \ --env redundancy_group_node_monitor_nodetype=monitoring \ --env redundancy_group_node_monitor_connectvia=${ip_prefix}2" - ;; + ;; esac else echo "`date` INFO: Configuring singleton" @@ -233,27 +246,28 @@ else fi #Define a create script -tee /root/docker-create <<-EOF -#!/bin/bash +tee /root/docker-create <<-EOF +#!/bin/bash docker create \ --privileged=true \ --net=host \ --uts=host \ - --shm-size 2g \ + --shm-size=${shmsize} \ --ulimit core=-1 \ --ulimit memlock=-1 \ - --ulimit nofile=2448:38048 \ + --ulimit nofile=${ulimit_nofile} \ --log-driver syslog \ --log-opt syslog-format=rfc3164 \ --log-opt syslog-address=udp://127.0.0.1:25224 \ - -v $(dirname ${password_file}):/run/secrets \ + -v $(dirname ${admin_password_file}):/run/secrets \ -v jail:/usr/sw/jail \ -v var:/usr/sw/var \ -v softAdb:/usr/sw/internalSpool/softAdb \ -v adbBackup:/usr/sw/adb \ ${SPOOL_MOUNT} \ --env username_admin_globalaccesslevel=admin \ - --env username_admin_passwordfilepath=$(basename ${password_file}) \ + --env username_admin_passwordfilepath=$(basename ${admin_password_file}) \ + --env system_scaling_maxconnectioncount=${maxconnectioncount} \ --env logging_debug_output=all \ --env logging_debug_format=graylog \ --env logging_command_output=all \ @@ -265,41 +279,41 @@ docker create \ --env logging_kernel_output=all \ --env logging_kernel_format=graylog \ ${redundancy_config} \ - --name=solace solace-app:${VMR_VERSION} + --name=solace ${VMR_IMAGE} EOF #Make the file executable chmod +x /root/docker-create -echo "`date` INFO: Creating the Solace VMR container" +echo "`date` INFO: Creating the Solace container" /root/docker-create #Construct systemd for VMR tee /etc/systemd/system/solace-docker-vmr.service <<-EOF -[Unit] - Description=solace-docker-vmr - Requires=docker.service - After=docker.service -[Service] - Restart=always - ExecStart=/usr/bin/docker start -a solace - ExecStop=/usr/bin/docker stop solace -[Install] - WantedBy=default.target +[Unit] + Description=solace-docker-vmr + Requires=docker.service + After=docker.service +[Service] + Restart=always + ExecStart=/usr/bin/docker start -a solace + ExecStop=/usr/bin/docker stop solace +[Install] + WantedBy=default.target EOF -echo "`date` INFO: Start the Solace VMR container" -systemctl daemon-reload -systemctl enable solace-docker-vmr +echo "`date` INFO: Start the Solace container" +systemctl daemon-reload +systemctl enable solace-docker-vmr systemctl start solace-docker-vmr # Poll the VMR SEMP port until it is Up loop_guard=30 pause=10 count=0 -echo "`date` INFO: Wait for the VMR SEMP service to be enabled" +echo "`date` INFO: Wait for the Solace SEMP service to be enabled" while [ ${count} -lt ${loop_guard} ]; do - online_results=`./semp_query.sh -n admin -p ${password} -u http://localhost:8080/SEMP \ + online_results=`./semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ -q "" \ -v "/rpc-reply/rpc/show/service/services/service[name='SEMP']/enabled[text()]"` @@ -308,27 +322,27 @@ while [ ${count} -lt ${loop_guard} ]; do run_time=$((${count} * ${pause})) if [ "${is_vmr_up}" = "\"true\"" ]; then - echo "`date` INFO: VMR SEMP service is up, after ${run_time} seconds" - break + echo "`date` INFO: Solace message broker SEMP service is up, after ${run_time} seconds" + break fi ((count++)) - echo "`date` INFO: Waited ${run_time} seconds, VMR SEMP service not yet up" + echo "`date` INFO: Waited ${run_time} seconds, Solace message broker SEMP service not yet up" sleep ${pause} done # Remove all VMR Secrets from the host; at this point, the VMR should have come up # and it won't be needing those files anymore -rm ${password_file} +rm ${admin_password_file} # Poll the redundancy status on the Primary VMR -loop_guard=30 -pause=10 -count=0 -mate_active_check="" if [ "${is_primary}" = "true" ]; then + loop_guard=30 + pause=10 + count=0 + mate_active_check="" echo "`date` INFO: Wait for Primary to be 'Local Active' or 'Mate Active'" - while [ ${count} -lt ${loop_guard} ]; do - online_results=`./semp_query.sh -n admin -p ${password} -u http://localhost:8080/SEMP \ + while [ ${count} -lt ${loop_guard} ]; do + online_results=`./semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ -q "" \ -v "/rpc-reply/rpc/show/redundancy/virtual-routers/primary/status/activity[text()]"` @@ -355,15 +369,17 @@ if [ "${is_primary}" = "true" ]; then if [ ${count} -eq ${loop_guard} ]; then echo "`date` ERROR: Solace redundancy group never came up" | tee /dev/stderr - exit 1 + echo "`date` ERROR: giving up! Details:" + echo `curl -u admin:${admin_password} http://localhost:8080/SEMP -d ""` + exit 1 fi - loop_guard=30 + loop_guard=45 pause=10 count=0 echo "`date` INFO: Wait for Backup to be 'Active' or 'Standby'" - while [ ${count} -lt ${loop_guard} ]; do - online_results=`./semp_query.sh -n admin -p ${password} -u http://localhost:8080/SEMP \ + while [ ${count} -lt ${loop_guard} ]; do + online_results=`./semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ -q "" \ -v "/rpc-reply/rpc/show/redundancy/virtual-routers/primary/status/detail/priority-reported-by-mate/summary[text()]"` @@ -384,18 +400,25 @@ if [ "${is_primary}" = "true" ]; then ;; esac ((count++)) - echo "`date` INFO: Waited ${run_time} seconds, Redundancy not yet up" + echo "`date` INFO: Waited ${run_time} seconds, Backup not yet 'Active' or 'Standby'" sleep ${pause} done if [ ${count} -eq ${loop_guard} ]; then - echo "`date` ERROR: Solace redundancy group never came up" | tee /dev/stderr - exit 1 + echo "`date` ERROR: Backup never became 'Active' or 'Standby'" | tee /dev/stderr + echo "`date` ERROR: giving up! Details:" + echo `curl -u admin:${admin_password} http://localhost:8080/SEMP -d ""` + exit 1 fi - ./semp_query.sh -n admin -p ${password} -u http://localhost:8080/SEMP \ + ./semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ -q "" - ./semp_query.sh -n admin -p ${password} -u http://localhost:8080/SEMP \ + ./semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ -q "default" fi -echo "`date` INFO: Solace VMR bringup complete" \ No newline at end of file + +if [ ${count} -eq ${loop_guard} ]; then + echo "`date` ERROR: Solace bringup failed" | tee /dev/stderr + exit 1 +fi +echo "`date` INFO: Solace bringup complete" diff --git a/security-shared-resources.json b/security-shared-resources.json index a982cec..65f1ca1 100644 --- a/security-shared-resources.json +++ b/security-shared-resources.json @@ -4,16 +4,16 @@ "parameters": { "securityGroupName": { "type": "string", - "defaultValue": "vmr-security", + "defaultValue": "solace-security", "metadata": { - "description": "Security group defined to support VMR system level and default message vpn ports." + "description": "Security group defined to support PubSub+ message broker system level and default message vpn ports." } }, "subnetPrefix": { "type": "string", "defaultValue": "10.0.0.0/24", "metadata": { - "description": "Subnet for VMRs." + "description": "Subnet for PubSub+ message brokers." } } }, From b3ab4ead92ae89e4319cdbd5a274e2711fff299d Mon Sep 17 00:00:00 2001 From: bczoma Date: Thu, 10 May 2018 15:07:47 -0400 Subject: [PATCH 02/14] temporary update to the scriptUrl to use the test repo/branch --- azuredeploy.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azuredeploy.json b/azuredeploy.json index 1ef02bf..c0db34c 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -142,7 +142,7 @@ "OSDiskName": "osdiskfordockersimple", "dataDiskName": "datadiskfordockersimple", "nicName": "myVMNicD", - "scriptUrl": "https://raw.githubusercontent.com/SolaceDev/solace-azure-quickstart-template/Rebranding-updates/", + "scriptUrl": "https://raw.githubusercontent.com/SolaceDev/solace-azure-quickstart-template/SOL-4553/", "solaceSecurityName": "SolaceSecurity.Template", "securitySharedTemplateName": "security-shared-resources.json", "solaceLoadBalancerName": "SolaceLoadBalancer.Template", From 4b603413928fdfcd06b92556a407eac8b6a08e4b Mon Sep 17 00:00:00 2001 From: bczoma Date: Thu, 10 May 2018 15:29:28 -0400 Subject: [PATCH 03/14] Increase image load retries to 5 --- scripts/deploy_solace.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/deploy_solace.sh b/scripts/deploy_solace.sh index 375c66c..0516eb2 100644 --- a/scripts/deploy_solace.sh +++ b/scripts/deploy_solace.sh @@ -88,9 +88,9 @@ if [ -z ${MD5_SUM} ]; then fi echo "`date` INFO: Reference md5sum is: ${MD5_SUM}" -echo "`date` INFO: Download from URL provided and validate, trying up to 3 times" +echo "`date` INFO: Download from URL provided and validate, trying up to 5 times" LOOP_COUNT=0 -while [ $LOOP_COUNT -lt 3 ]; do +while [ $LOOP_COUNT -lt 5 ]; do wget -q -O ${solace_directory}/${SolOS_LOAD} ${REAL_LINK} || echo "There has been an issue with downloading the Solace load" LOCAL_OS_INFO=`md5sum ${SolOS_LOAD}` IFS=' ' read -ra SOLOS_INFO <<< ${LOCAL_OS_INFO} From e4fa6c0c01a96775c34c080c5b06f012f8ee24dc Mon Sep 17 00:00:00 2001 From: bczoma Date: Thu, 10 May 2018 19:08:39 -0400 Subject: [PATCH 04/14] Move to dynamic IPs and non static Router names --- azuredeploy.json | 35 ++++++++++++-------------- scripts/deploy_solace.sh | 54 ++++++++++++++++++++-------------------- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/azuredeploy.json b/azuredeploy.json index c0db34c..ac5c2b2 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -59,7 +59,7 @@ "dnsLabelForVmIp": { "type": "string", "metadata": { - "description": "Unique DNS Label for the Public IP used to access the Virtual Machine(s)." + "description": "Unique DNS Label for the Public IP used to access the Virtual Machine(s). Do not use '-'" } }, "centosVersion": { @@ -156,10 +156,8 @@ "publicIPAddressType": "Dynamic", "vmStorageAccountVHDsName": "vhds", "vmStorageAccountContainersName": "containers", - "vmName": "SolaceVM", "addressPrefix": "10.0.0.0/16", "subnetPrefix": "10.0.0.0/24", - "nodeAddressPrefix": "10.0.0.10", "storageAccountType": "Standard_LRS", "subnetName": "Subnet", "virtualNetworkName": "MyVNETD", @@ -177,7 +175,7 @@ "dataDisksChoices": { "0": [ { - "name": "[concat(variables('vmName'), 0, '-datadisk1')]", + "name": "[concat(parameters('dnsLabelForVmIp'), 0, '-datadisk1')]", "diskSizeGB": "[parameters('dataDiskSize')]", "lun": 0, "vhd": { @@ -189,7 +187,7 @@ ], "1": [ { - "name": "[concat(variables('vmName'), 1, '-datadisk1')]", + "name": "[concat(parameters('dnsLabelForVmIp'), 1, '-datadisk1')]", "diskSizeGB": "[parameters('dataDiskSize')]", "lun": 0, "vhd": { @@ -339,8 +337,7 @@ { "name": "ipconfig1", "properties": { - "privateIPAllocationMethod": "Static", - "privateIPAddress": "[concat(variables('nodeAddressPrefix'), copyindex())]", + "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'), copyindex()))]" }, @@ -381,7 +378,7 @@ { "apiVersion": "2015-06-15", "type": "Microsoft.Compute/virtualMachines", - "name": "[concat(variables('vmName'), copyindex())]", + "name": "[concat(parameters('dnsLabelForVmIp'), copyindex())]", "location": "[resourceGroup().location]", "copy": { "name": "virtualMachineLoop", @@ -400,7 +397,7 @@ "vmSize": "[if(equals(copyindex(), variables('monitorNodeIndex')), parameters('monitorVmSize'), parameters('messageRoutingVmSize'))]" }, "osProfile": { - "computerName": "[concat(variables('vmName'), copyindex())]", + "computerName": "[concat(parameters('dnsLabelForVmIp'), copyindex())]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPassword')]" }, @@ -412,7 +409,7 @@ "version": "latest" }, "osDisk": { - "name": "[concat(variables('vmName'), copyindex(), '-osdisk1')]", + "name": "[concat(parameters('dnsLabelForVmIp'), copyindex(), '-osdisk1')]", "vhd": { "uri": "[concat('http://',parameters('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountVHDsName'),'/',variables('OSDiskName'),copyindex(),'.vhd')]" }, @@ -433,14 +430,14 @@ { "apiVersion": "2016-03-30", "type": "Microsoft.Compute/virtualMachines/extensions", - "name": "[concat(variables('vmName'), copyindex(), '/DockerExtension')]", + "name": "[concat(parameters('dnsLabelForVmIp'), copyindex(), '/DockerExtension')]", "location": "[resourceGroup().location]", "copy": { "name": "DockerLoop", "count": "[variables('numberOfInstances')]" }, "dependsOn": [ - "[concat('Microsoft.Compute/virtualMachines/', variables('vmName'), copyindex())]" + "[concat('Microsoft.Compute/virtualMachines/', parameters('dnsLabelForVmIp'), copyindex())]" ], "properties": { "publisher": "Microsoft.Azure.Extensions", @@ -453,14 +450,14 @@ { "apiVersion": "2015-06-15", "type": "Microsoft.Compute/virtualMachines/extensions", - "name": "[concat(variables('vmName'), copyindex(), '/OmsAgentExtension')]", + "name": "[concat(parameters('dnsLabelForVmIp'), copyindex(), '/OmsAgentExtension')]", "location": "[resourceGroup().location]", "copy": { "name": "OmsAgentLoop", "count": "[variables('numberOfInstances')]" }, "dependsOn": [ - "[concat('Microsoft.Compute/virtualMachines/', variables('vmName'), copyindex(), '/extensions/DockerExtension')]", + "[concat('Microsoft.Compute/virtualMachines/', parameters('dnsLabelForVmIp'), copyindex(), '/extensions/DockerExtension')]", "[concat('Microsoft.Resources/deployments/', variables('solaceWorkspaceName'))]" ], "properties": { @@ -478,15 +475,15 @@ { "apiVersion": "2016-03-30", "type": "Microsoft.Compute/virtualMachines/extensions", - "name": "[concat(variables('vmName'), copyindex(), '/configureSolaceContainer')]", + "name": "[concat(parameters('dnsLabelForVmIp'), copyindex(), '/configureSolaceContainer')]", "location": "[resourceGroup().location]", "copy": { "name": "SolaceLoop", "count": "[variables('numberOfInstances')]" }, "dependsOn": [ - "[concat('Microsoft.Compute/virtualMachines/', variables('vmName'), copyindex(), '/extensions/DockerExtension')]" - ], + "[concat('Microsoft.Compute/virtualMachines/', parameters('dnsLabelForVmIp'), copyindex(), '/extensions/DockerExtension')]" + ], "properties": { "publisher": "Microsoft.Azure.Extensions", "type": "CustomScript", @@ -500,8 +497,8 @@ ] }, "protectedSettings": { - "commandToExecute": "[concat('mkdir -p -m 600 ', variables('adminPasswordDir'), '; echo ', parameters('adminPassword'), ' > ', variables('adminPasswordFile'), '; bash ', variables('solaceInstallScriptName'), ' -c ', copyindex(), ' -i ', variables('nodeAddressPrefix'), ' -n ', variables('numberOfInstances'), ' -p ', variables('adminPasswordFile'), ' -s ', if(equals(copyindex(), variables('monitorNodeIndex')), '0', parameters('dataDiskSize')), if(equals(copyindex(), variables('monitorNodeIndex')), '', concat(' -v ', variables('dataDiskVolume'))), ' -u ', parameters('solaceDockerImageUri'))]" - } + "commandToExecute": "[concat('mkdir -p -m 600 ', variables('adminPasswordDir'), '; echo ', parameters('adminPassword'), ' > ', variables('adminPasswordFile'), '; bash ', variables('solaceInstallScriptName'), ' -c ', copyindex(), ' -d ', parameters('dnsLabelForVmIp'), ' -n ', variables('numberOfInstances'), ' -p ', variables('adminPasswordFile'), ' -s ', if(equals(copyindex(), variables('monitorNodeIndex')), '0', parameters('dataDiskSize')), if(equals(copyindex(), variables('monitorNodeIndex')), '', concat(' -v ', variables('dataDiskVolume'))), ' -u ', parameters('solaceDockerImageUri'))]" + } } } ] diff --git a/scripts/deploy_solace.sh b/scripts/deploy_solace.sh index 0516eb2..edc9cbc 100644 --- a/scripts/deploy_solace.sh +++ b/scripts/deploy_solace.sh @@ -20,7 +20,7 @@ OPTIND=1 # Reset in case getopts has been used previously in the shell. # Initialize our own variables: current_index="" -ip_prefix="" +dns_prefix="" number_of_instances="" solace_url="" admin_password_file="" @@ -30,11 +30,11 @@ is_primary="false" verbose=0 -while getopts "c:i:n:p:s:v:u:" opt; do +while getopts "c:d:n:p:s:v:u:" opt; do case "$opt" in c) current_index=$OPTARG ;; - i) ip_prefix=$OPTARG + d) dns_prefix=$OPTARG ;; n) number_of_instances=$OPTARG ;; @@ -53,7 +53,7 @@ shift $((OPTIND-1)) [ "$1" = "--" ] && shift verbose=1 -echo "`date` current_index=$current_index , ip_prefix=$ip_prefix , number_of_instances=$number_of_instances , \ +echo "`date` current_index=$current_index , dns_prefix=$dns_prefix , number_of_instances=$number_of_instances , \ password_file=$admin_password_file , disk_size=$disk_size , disk_volume=$disk_volume , solace_url=$solace_url , Leftovers: $@" export admin_password=`cat ${admin_password_file}` @@ -166,48 +166,48 @@ if [ ${number_of_instances} -gt 1 ]; then 0 ) redundancy_config="\ --env nodetype=message_routing \ - --env routername=primary \ - --env redundancy_matelink_connectvia=${ip_prefix}1 \ + --env routername=${dns_prefix}primary \ --env redundancy_activestandbyrole=primary \ + --env redundancy_matelink_connectvia=${dns_prefix}1 \ --env redundancy_group_passwordfilepath=$(basename ${admin_password_file}) \ --env redundancy_enable=yes \ - --env redundancy_group_node_primary_nodetype=message_routing \ - --env redundancy_group_node_primary_connectvia=${ip_prefix}0 \ - --env redundancy_group_node_backup_nodetype=message_routing \ - --env redundancy_group_node_backup_connectvia=${ip_prefix}1 \ - --env redundancy_group_node_monitor_nodetype=monitoring \ - --env redundancy_group_node_monitor_connectvia=${ip_prefix}2 \ + --env redundancy_group_node_${dns_prefix}primary_nodetype=message_routing \ + --env redundancy_group_node_${dns_prefix}primary_connectvia=${dns_prefix}0 \ + --env redundancy_group_node_${dns_prefix}backup_nodetype=message_routing \ + --env redundancy_group_node_${dns_prefix}backup_connectvia=${dns_prefix}1 \ + --env redundancy_group_node_${dns_prefix}monitor_nodetype=monitoring \ + --env redundancy_group_node_${dns_prefix}monitor_connectvia=${dns_prefix}2 \ --env configsync_enable=yes" is_primary="true" ;; 1 ) redundancy_config="\ --env nodetype=message_routing \ - --env routername=backup \ - --env redundancy_matelink_connectvia=${ip_prefix}0 \ + --env routername=${dns_prefix}backup \ + --env redundancy_matelink_connectvia=${dns_prefix}0 \ --env redundancy_activestandbyrole=backup \ --env redundancy_group_passwordfilepath=$(basename ${admin_password_file}) \ --env redundancy_enable=yes \ - --env redundancy_group_node_primary_nodetype=message_routing \ - --env redundancy_group_node_primary_connectvia=${ip_prefix}0 \ - --env redundancy_group_node_backup_nodetype=message_routing \ - --env redundancy_group_node_backup_connectvia=${ip_prefix}1 \ - --env redundancy_group_node_monitor_nodetype=monitoring \ - --env redundancy_group_node_monitor_connectvia=${ip_prefix}2 \ + --env redundancy_group_node_${dns_prefix}primary_nodetype=message_routing \ + --env redundancy_group_node_${dns_prefix}primary_connectvia=${dns_prefix}0 \ + --env redundancy_group_node_${dns_prefix}backup_nodetype=message_routing \ + --env redundancy_group_node_${dns_prefix}backup_connectvia=${dns_prefix}1 \ + --env redundancy_group_node_${dns_prefix}monitor_nodetype=monitoring \ + --env redundancy_group_node_${dns_prefix}monitor_connectvia=${dns_prefix}2 \ --env configsync_enable=yes" ;; 2 ) redundancy_config="\ --env nodetype=monitoring \ - --env routername=monitor \ + --env routername=${dns_prefix}monitor \ --env redundancy_group_passwordfilepath=$(basename ${admin_password_file}) \ --env redundancy_enable=yes \ - --env redundancy_group_node_primary_nodetype=message_routing \ - --env redundancy_group_node_primary_connectvia=${ip_prefix}0 \ - --env redundancy_group_node_backup_nodetype=message_routing \ - --env redundancy_group_node_backup_connectvia=${ip_prefix}1 \ - --env redundancy_group_node_monitor_nodetype=monitoring \ - --env redundancy_group_node_monitor_connectvia=${ip_prefix}2" + --env redundancy_group_node_${dns_prefix}primary_nodetype=message_routing \ + --env redundancy_group_node_${dns_prefix}primary_connectvia=${dns_prefix}0 \ + --env redundancy_group_node_${dns_prefix}backup_nodetype=message_routing \ + --env redundancy_group_node_${dns_prefix}backup_connectvia=${dns_prefix}1 \ + --env redundancy_group_node_${dns_prefix}monitor_nodetype=monitoring \ + --env redundancy_group_node_${dns_prefix}monitor_connectvia=${dns_prefix}2" ;; esac else From 80beb0735debf697debb841f87727d591638b1d4 Mon Sep 17 00:00:00 2001 From: bczoma Date: Fri, 11 May 2018 10:37:01 -0400 Subject: [PATCH 05/14] Support optional workspace and fix dynamic syslog port --- README.md | 4 +- azuredeploy.json | 32 ++++--- .../loadbalancer-shared-resources.json | 0 .../security-shared-resources.json | 0 .../workspace-disabled-shared-resources.json | 28 ++++++ .../workspace-enabled-shared-resources.json | 0 scripts/deploy_solace.sh | 90 +++++++++++++------ 7 files changed, 110 insertions(+), 44 deletions(-) rename loadbalancer-shared-resources.json => nested/loadbalancer-shared-resources.json (100%) rename security-shared-resources.json => nested/security-shared-resources.json (100%) create mode 100644 nested/workspace-disabled-shared-resources.json rename workspace-shared-resources.json => nested/workspace-enabled-shared-resources.json (100%) diff --git a/README.md b/README.md index cbfc229..4f4e239 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,8 @@ You need to fill in the following fields: | Admin Username | Username for the virtual Machine(s). Do not use special characters. | | Admin Password | Password for the virtual Machine(s) and for the 'admin' management user. | | Security Group Name | New or existing security group, where message broker default ports will be made publicly available. | -| Workspace Name | New or existing OMS Log Analytics workspace, where logs and diagnostics are monitored. | -| Workspace Region | Select region to deploy OMS Log Analytics workspace. | +| Workspace Name | New or existing OMS Log Analytics workspace, where logs and diagnostics are monitored. Leave this field empty to not deploy an OMS Workspace. | +| Workspace Region | Select region to deploy OMS Log Analytics workspace. Not used if Workspace Name is empty. | | DNS Label for LB IP | Used for the public DNS name of the Load Balancer. | | DNS Label for VM IP | Used for the public DNS name of each Virtual Machine. | | CentOS Version | The CentOS version for deploying the Docker containers. Use CentOS 7.2, 7.3, or 7.4. | diff --git a/azuredeploy.json b/azuredeploy.json index ac5c2b2..c532314 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -29,15 +29,16 @@ }, "workspaceName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Unique OMS Workspace Name for Log Analytics." + "description": "Unique OMS Workspace Name for Log Analytics. Leave this field empty to not deploy an OMS Workspace." } }, "workspaceRegion": { "type": "string", "defaultValue": "East US", "metadata": { - "description": "OMS Workspace Region for Log Analytics." + "description": "OMS Workspace Region for Log Analytics. Not used if Workspace Name is empty." }, "allowedValues": [ "East US", @@ -142,13 +143,16 @@ "OSDiskName": "osdiskfordockersimple", "dataDiskName": "datadiskfordockersimple", "nicName": "myVMNicD", - "scriptUrl": "https://raw.githubusercontent.com/SolaceDev/solace-azure-quickstart-template/SOL-4553/", + "baseUrl": "https://raw.githubusercontent.com/SolaceDev/solace-azure-quickstart-template/Rebranding-updates/", + "nestedUrl": "[concat(variables('baseUrl'), 'nested/')]", + "scriptsUrl": "[concat(variables('baseUrl'), 'scripts/')]", "solaceSecurityName": "SolaceSecurity.Template", "securitySharedTemplateName": "security-shared-resources.json", "solaceLoadBalancerName": "SolaceLoadBalancer.Template", "loadBalancerSharedTemplateName": "loadbalancer-shared-resources.json", "solaceWorkspaceName": "SolaceWorkspace.Template", - "workspaceSharedTemplateName": "workspace-shared-resources.json", + "workspaceEnabledSharedTemplateName": "workspace-enabled-shared-resources.json", + "workspaceDisabledSharedTemplateName": "workspace-disabled-shared-resources.json", "solaceInstallScriptName": "deploy_solace.sh", "sempQueryScriptName": "semp_query.sh", "publicIPAddressName": "myPublicIPD", @@ -171,7 +175,6 @@ "lbID": "[resourceId('Microsoft.Network/loadBalancers',variables('lbName'))]", "lbPoolName": "solace-ha-group", "lbPoolID": "[concat(variables('lbID'),'/backendAddressPools/',variables('lbPoolName'))]", - "dataDiskVolume" : "/dev/sdc", "dataDisksChoices": { "0": [ { @@ -210,7 +213,7 @@ "properties": { "mode": "Incremental", "templateLink": { - "uri": "[concat(variables('scriptUrl'), variables('securitySharedTemplateName'))]", + "uri": "[concat(variables('nestedUrl'), variables('securitySharedTemplateName'))]", "contentVersion": "1.0.0.0" }, "parameters": { @@ -230,7 +233,7 @@ "properties": { "mode": "Incremental", "templateLink": { - "uri": "[concat(variables('scriptUrl'), variables('loadBalancerSharedTemplateName'))]", + "uri": "[concat(variables('nestedUrl'), variables('loadBalancerSharedTemplateName'))]", "contentVersion": "1.0.0.0" }, "parameters": { @@ -259,7 +262,7 @@ "properties": { "mode": "Incremental", "templateLink": { - "uri": "[concat(variables('scriptUrl'), variables('workspaceSharedTemplateName'))]", + "uri": "[if(empty(parameters('workspaceName')), concat(variables('nestedUrl'), variables('workspaceDisabledSharedTemplateName')), concat(variables('nestedUrl'), variables('workspaceEnabledSharedTemplateName')))]", "contentVersion": "1.0.0.0" }, "parameters": { @@ -448,6 +451,7 @@ } }, { + "condition": "[not(empty(parameters('workspaceName')))]", "apiVersion": "2015-06-15", "type": "Microsoft.Compute/virtualMachines/extensions", "name": "[concat(parameters('dnsLabelForVmIp'), copyindex(), '/OmsAgentExtension')]", @@ -482,8 +486,8 @@ "count": "[variables('numberOfInstances')]" }, "dependsOn": [ - "[concat('Microsoft.Compute/virtualMachines/', parameters('dnsLabelForVmIp'), copyindex(), '/extensions/DockerExtension')]" - ], + "[if(empty(parameters('workspaceName')), concat('Microsoft.Compute/virtualMachines/', parameters('dnsLabelForVmIp'), copyindex(), '/extensions/DockerExtension'), concat('Microsoft.Compute/virtualMachines/', parameters('dnsLabelForVmIp'), copyindex(), '/extensions/OmsAgentExtension'))]" + ], "properties": { "publisher": "Microsoft.Azure.Extensions", "type": "CustomScript", @@ -492,14 +496,14 @@ "settings": { "fileUris": [ "[parameters('solaceDockerImageUri')]", - "[concat(variables('scriptUrl'), 'scripts/', variables('solaceInstallScriptName'))]", - "[concat(variables('scriptUrl'), 'scripts/', variables('sempQueryScriptName'))]" + "[concat(variables('scriptsUrl'), variables('solaceInstallScriptName'))]", + "[concat(variables('scriptsUrl'), variables('sempQueryScriptName'))]" ] }, "protectedSettings": { - "commandToExecute": "[concat('mkdir -p -m 600 ', variables('adminPasswordDir'), '; echo ', parameters('adminPassword'), ' > ', variables('adminPasswordFile'), '; bash ', variables('solaceInstallScriptName'), ' -c ', copyindex(), ' -d ', parameters('dnsLabelForVmIp'), ' -n ', variables('numberOfInstances'), ' -p ', variables('adminPasswordFile'), ' -s ', if(equals(copyindex(), variables('monitorNodeIndex')), '0', parameters('dataDiskSize')), if(equals(copyindex(), variables('monitorNodeIndex')), '', concat(' -v ', variables('dataDiskVolume'))), ' -u ', parameters('solaceDockerImageUri'))]" + "commandToExecute": "[concat('mkdir -p -m 600 ', variables('adminPasswordDir'), '; echo ', parameters('adminPassword'), ' > ', variables('adminPasswordFile'), '; bash ', variables('solaceInstallScriptName'), ' -c ', copyindex(), ' -d ', parameters('dnsLabelForVmIp'), ' -n ', variables('numberOfInstances'), ' -p ', variables('adminPasswordFile'), ' -s ', if(equals(copyindex(), variables('monitorNodeIndex')), '0', parameters('dataDiskSize')), if(empty(parameters('workspaceName')), '', concat(' -w ', reference(variables('solaceWorkspaceName')).outputs.workspaceId.value)), ' -u ', parameters('solaceDockerImageUri'))]" } } } ] -} \ No newline at end of file +} diff --git a/loadbalancer-shared-resources.json b/nested/loadbalancer-shared-resources.json similarity index 100% rename from loadbalancer-shared-resources.json rename to nested/loadbalancer-shared-resources.json diff --git a/security-shared-resources.json b/nested/security-shared-resources.json similarity index 100% rename from security-shared-resources.json rename to nested/security-shared-resources.json diff --git a/nested/workspace-disabled-shared-resources.json b/nested/workspace-disabled-shared-resources.json new file mode 100644 index 0000000..a103d41 --- /dev/null +++ b/nested/workspace-disabled-shared-resources.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspaceName": { + "type": "string", + "defaultValue": "" + }, + "workspaceRegion": { + "type": "string", + "defaultValue": "" + } + }, + "variables": { + }, + "outputs": { + "workspaceId": { + "type": "string", + "value": "" + }, + "workspaceKey": { + "type": "string", + "value": "" + } + }, + "resources": [ + ] +} \ No newline at end of file diff --git a/workspace-shared-resources.json b/nested/workspace-enabled-shared-resources.json similarity index 100% rename from workspace-shared-resources.json rename to nested/workspace-enabled-shared-resources.json diff --git a/scripts/deploy_solace.sh b/scripts/deploy_solace.sh index edc9cbc..1aa0435 100644 --- a/scripts/deploy_solace.sh +++ b/scripts/deploy_solace.sh @@ -25,12 +25,12 @@ number_of_instances="" solace_url="" admin_password_file="" disk_size="" -disk_volume="" +workspace_id="" is_primary="false" verbose=0 -while getopts "c:d:n:p:s:v:u:" opt; do +while getopts "c:d:n:p:s:w:u:" opt; do case "$opt" in c) current_index=$OPTARG ;; @@ -44,7 +44,7 @@ while getopts "c:d:n:p:s:v:u:" opt; do ;; u) solace_url=$OPTARG ;; - v) disk_volume=$OPTARG + w) workspace_id=$OPTARG ;; esac done @@ -54,7 +54,8 @@ shift $((OPTIND-1)) verbose=1 echo "`date` current_index=$current_index , dns_prefix=$dns_prefix , number_of_instances=$number_of_instances , \ - password_file=$admin_password_file , disk_size=$disk_size , disk_volume=$disk_volume , solace_url=$solace_url , Leftovers: $@" + password_file=$admin_password_file , disk_size=$disk_size , workspace_id=$workspace_id , solace_url=$solace_url , \ + Leftovers: $@" export admin_password=`cat ${admin_password_file}` #Install the logical volume manager and jq for json parsing @@ -221,22 +222,38 @@ docker volume create --name=var docker volume create --name=softAdb docker volume create --name=adbBackup -if [ $disk_size == "0" ]; then +if [ ${disk_size} == "0" ]; then docker volume create --name=diagnostics docker volume create --name=internalSpool SPOOL_MOUNT="-v diagnostics:/var/lib/solace/diags -v internalSpool:/usr/sw/internalSpool" else - echo "`date` Create primary partition on new disk" + # Look for unpartitioned disks + disk_volume="" + DEVS=($(ls -1 /dev/sd*|egrep -v "[0-9]$")) + for DEV in "${DEVS[@]}"; do + # Check each device if there is a "1" partition. + # If not, assume it is not partitioned. + if [ ! -b ${DEV}1 ]; then + echo "`date` INFO: Disk device with no primary partition found" + disk_volume="${DEV}" + break + fi + done + if [ ${disk_volume} == "" ]; then + echo "`date` INFO: Default disk device to /dev/sdc" + disk_volume="/dev/sdc" + fi + echo "`date` INFO: Create primary partition on disk device ${disk_volume} of size ${disk_size} GiB" ( - 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 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 $workspace_id + mkfs.xfs ${workspace_id}1 -m crc=0 + UUID=`blkid -s UUID -o value ${workspace_id}1` echo "UUID=${UUID} /opt/vmr xfs defaults 0 0" >> /etc/fstab mkdir /opt/vmr mkdir /opt/vmr/diagnostics @@ -245,6 +262,34 @@ else SPOOL_MOUNT="-v /opt/vmr/diagnostics:/var/lib/solace/diags -v /opt/vmr/internalSpool:/usr/sw/internalSpool" fi +LOG_OPT="" +logging_config="" +if [[ ${workspace_id} != "" ]]; then + SYSLOG_CONF="/etc/opt/microsoft/omsagent/${workspace_id}/conf/omsagent.d/syslog.conf" + SYSLOG_PORT="" + if [ -f ${SYSLOG_CONF} ]; then + echo "`date` INFO: Configuration file for syslog found" + SYSLOG_PORT=$(sed -n 's/.*port \(.*\).*/\1/p' $SYSLOG_CONF) + fi + if [[ ${SYSLOG_PORT} == "" ]]; then + echo "`date` INFO: Default syslog port to 25224" + SYSLOG_PORT="25224" + fi + echo "`date` INFO: Configuring logging on syslog port ${SYSLOG_PORT}" + LOG_OPT="--log-driver syslog --log-opt syslog-format=rfc3164 --log-opt syslog-address=udp://127.0.0.1:$SYSLOG_PORT" + logging_config="\ + --env logging_debug_output=all \ + --env logging_debug_format=graylog \ + --env logging_command_output=all \ + --env logging_command_format=graylog \ + --env logging_system_output=all \ + --env logging_system_format=graylog \ + --env logging_event_output=all \ + --env logging_event_format=graylog \ + --env logging_kernel_output=all \ + --env logging_kernel_format=graylog" +fi + #Define a create script tee /root/docker-create <<-EOF #!/bin/bash @@ -256,9 +301,7 @@ docker create \ --ulimit core=-1 \ --ulimit memlock=-1 \ --ulimit nofile=${ulimit_nofile} \ - --log-driver syslog \ - --log-opt syslog-format=rfc3164 \ - --log-opt syslog-address=udp://127.0.0.1:25224 \ + ${LOG_OPT} \ -v $(dirname ${admin_password_file}):/run/secrets \ -v jail:/usr/sw/jail \ -v var:/usr/sw/var \ @@ -268,16 +311,7 @@ docker create \ --env username_admin_globalaccesslevel=admin \ --env username_admin_passwordfilepath=$(basename ${admin_password_file}) \ --env system_scaling_maxconnectioncount=${maxconnectioncount} \ - --env logging_debug_output=all \ - --env logging_debug_format=graylog \ - --env logging_command_output=all \ - --env logging_command_format=graylog \ - --env logging_system_output=all \ - --env logging_system_format=graylog \ - --env logging_event_output=all \ - --env logging_event_format=graylog \ - --env logging_kernel_output=all \ - --env logging_kernel_format=graylog \ + ${logging_config} \ ${redundancy_config} \ --name=solace ${VMR_IMAGE} EOF From 2867685dfb85142ecbed3f3633d4ee24aded7a1a Mon Sep 17 00:00:00 2001 From: bczoma Date: Fri, 11 May 2018 10:39:39 -0400 Subject: [PATCH 06/14] Fix temp link to test branch --- azuredeploy.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azuredeploy.json b/azuredeploy.json index c532314..9e21030 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -143,7 +143,7 @@ "OSDiskName": "osdiskfordockersimple", "dataDiskName": "datadiskfordockersimple", "nicName": "myVMNicD", - "baseUrl": "https://raw.githubusercontent.com/SolaceDev/solace-azure-quickstart-template/Rebranding-updates/", + "baseUrl": "https://raw.githubusercontent.com/SolaceDev/solace-azure-quickstart-template/SOL-4553/", "nestedUrl": "[concat(variables('baseUrl'), 'nested/')]", "scriptsUrl": "[concat(variables('baseUrl'), 'scripts/')]", "solaceSecurityName": "SolaceSecurity.Template", From b92449a2620327ffca15cad54cb55f5cd10bcc6a Mon Sep 17 00:00:00 2001 From: bczoma Date: Wed, 16 May 2018 16:01:34 -0400 Subject: [PATCH 07/14] documentation updates from review --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4f4e239..525fa16 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ You can use this quick start template with either PubSub+ `Standard` or PubSub+ | PubSub+ Standard | PubSub+ Enterprise Evaluation Edition | :---: | :---: | -| Free, up to 1k simultaneous connections,
up to 100k messages per second | 90-day trial version, unlimited | +| Free, up to 1k simultaneous connections,
up to 10k messages per second | 90-day trial version, unlimited | | | |
@@ -47,22 +47,23 @@ You need to fill in the following fields: | Field | Value | |----------------------------|--------------------------------------------------------------------------------| | **BASICS** | | +| Subscription | Provide your subscription to use. | | Resource Group | A new group, or an existing group that will be available from the pull-down menu once "Use existing" is selected. | | Location | Select region most suitable to you. | | **SETTINGS** | | -| Storage Account Name | New or existing storage account, where your VHD will be stored. | +| Storage Account Name | New or existing storage account, where your [VHD](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/about-disks-and-vhds ) will be stored. The name must be globally unique. Do not use special characters including hyphen. | | Admin Username | Username for the virtual Machine(s). Do not use special characters. | -| Admin Password | Password for the virtual Machine(s) and for the 'admin' management user. | +| Admin Password | Password for the virtual Machine(s) and for the 'admin' management user. Azure sets rules on passwords, observe the online feedback. | | Security Group Name | New or existing security group, where message broker default ports will be made publicly available. | | Workspace Name | New or existing OMS Log Analytics workspace, where logs and diagnostics are monitored. Leave this field empty to not deploy an OMS Workspace. | | Workspace Region | Select region to deploy OMS Log Analytics workspace. Not used if Workspace Name is empty. | | DNS Label for LB IP | Used for the public DNS name of the Load Balancer. | | DNS Label for VM IP | Used for the public DNS name of each Virtual Machine. | | CentOS Version | The CentOS version for deploying the Docker containers. Use CentOS 7.2, 7.3, or 7.4. | -| Message Broker VM Size | The size of the VM for the message brokers. Use Standard_D2_v2, Standard_DS2_v2, Standard_D2_v3, or Standard_D2s_v3. Note that not all regions support all these VM sizes. | +| Message Routing VM Size | The size of the VM for the message routing nodes. Use Standard_D2_v2, Standard_DS2_v2, Standard_D2_v3, or Standard_D2s_v3. Note that not all regions support all these VM sizes. | | Monitor VM Size | The size of the VM for the monitoring node. Use Standard_D2_v2, Standard_DS2_v2, Standard_D2_v3, or Standard_D2s_v3. Note that not all regions support all these VM sizes. | | Data Disk Size | The size of the data disk in GB for diagnostics and message spooling on the message brokers. Use 0, 20, 40, 80, or 160. | -| Solace PubSub+ software message broker URI | URL from the registration email. Can also use load versions hosted remotely (if so, a .md5 file needs to be created in the same remote directory). | +| Solace Docker Image URI | Solace PubSub+ software message broker URL from the registration email. Can also use load versions hosted remotely (if so, a .md5 file needs to be created in the same remote directory). | | Deployment Model | High Availability or Single Node. | After completing the template fields and accepting the legal terms, you need to purchase the deployment. The cost will only be related to the Azure instance and storage costs. @@ -132,6 +133,6 @@ For more information about writing Azure Resource Manager(ARM) templates and Azu For more information about Solace technology in general please visit these resources: -- [Solace Developer Portal](http://dev.solace.com) -- [Intro Solace technology](http://dev.solace.com/tech/) -- [Solace community on Stack Overflow](http://dev.solace.com/community/). \ No newline at end of file +- [Solace Developer Portal](http://dev.solace.com ) +- [Intro Solace technology](http://dev.solace.com/tech/ ) +- [Solace community on Stack Overflow](http://dev.solace.com/community/ ). \ No newline at end of file From 3abd4668b01b8227f986bab63bbe8786d4f97ef4 Mon Sep 17 00:00:00 2001 From: Jim Lowe Date: Tue, 22 May 2018 13:39:22 -0400 Subject: [PATCH 08/14] Updated Step 1 Updated Step 1 for copying url. --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 525fa16..84aa7a2 100644 --- a/README.md +++ b/README.md @@ -19,17 +19,14 @@ This is a two step process: ### Step 1: -Go to the Solace Developer Portal and request a Solace PubSub+ software message broker. This process will return an email with a Download link. To get going, right click "Copy Hyperlink" on the "Download the Solace PubSub+ Software Message Broker for Docker" hyperlink. This will be needed in the following section. +Go to the Solace Developer Portal and copy the download URL of the Solace PubSub+ software message broker Docker image. You can use this quick start template with either PubSub+ `Standard` or PubSub+ `Enterprise Evaluation Edition`. -| PubSub+ Standard | PubSub+ Enterprise Evaluation Edition +| PubSub+ Standard Docker Image | PubSub+ Enterprise Evaluation Edition Docker Image | :---: | :---: | -| Free, up to 1k simultaneous connections,
up to 10k messages per second | 90-day trial version, unlimited | -| | | - -
-
+| Free | 90-day trial version of PubSub+ Enterprise | +| [Copy URL of Standard Docker Image](http://dev.solace.com/downloads/) | [Copy URL of Evaluation Docker Image](http://dev.solace.com/downloads#eval) | ### Step 2: @@ -135,4 +132,4 @@ For more information about Solace technology in general please visit these resou - [Solace Developer Portal](http://dev.solace.com ) - [Intro Solace technology](http://dev.solace.com/tech/ ) -- [Solace community on Stack Overflow](http://dev.solace.com/community/ ). \ No newline at end of file +- [Solace community on Stack Overflow](http://dev.solace.com/community/ ). From cf3eb20fb94ad016a65d2cb74bb47eff4a42f41e Mon Sep 17 00:00:00 2001 From: bczoma Date: Tue, 22 May 2018 16:40:47 -0400 Subject: [PATCH 09/14] updated url download step --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 84aa7a2..38f9186 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,14 @@ This is a two step process: ### Step 1: -Go to the Solace Developer Portal and copy the download URL of the Solace PubSub+ software message broker Docker image. +Go to the Solace Developer Portal and copy the download URL of the Solace PubSub+ software message broker **Docker** image. You can use this quick start template with either PubSub+ `Standard` or PubSub+ `Enterprise Evaluation Edition`. | PubSub+ Standard Docker Image | PubSub+ Enterprise Evaluation Edition Docker Image | :---: | :---: | -| Free | 90-day trial version of PubSub+ Enterprise | -| [Copy URL of Standard Docker Image](http://dev.solace.com/downloads/) | [Copy URL of Evaluation Docker Image](http://dev.solace.com/downloads#eval) | +| Free, up to 1k simultaneous connections,
up to 10k messages per second | 90-day trial version, unlimited | +| [Get URL of Standard Docker Image](http://dev.solace.com/downloads/) | [Get URL of Evaluation Docker Image](http://dev.solace.com/downloads#eval) | ### Step 2: @@ -60,7 +60,7 @@ You need to fill in the following fields: | Message Routing VM Size | The size of the VM for the message routing nodes. Use Standard_D2_v2, Standard_DS2_v2, Standard_D2_v3, or Standard_D2s_v3. Note that not all regions support all these VM sizes. | | Monitor VM Size | The size of the VM for the monitoring node. Use Standard_D2_v2, Standard_DS2_v2, Standard_D2_v3, or Standard_D2s_v3. Note that not all regions support all these VM sizes. | | Data Disk Size | The size of the data disk in GB for diagnostics and message spooling on the message brokers. Use 0, 20, 40, 80, or 160. | -| Solace Docker Image URI | Solace PubSub+ software message broker URL from the registration email. Can also use load versions hosted remotely (if so, a .md5 file needs to be created in the same remote directory). | +| Solace Docker Image URI | Solace PubSub+ software message broker URL. Can also use load versions hosted remotely (if so, a .md5 file needs to be created in the same remote directory). | | Deployment Model | High Availability or Single Node. | After completing the template fields and accepting the legal terms, you need to purchase the deployment. The cost will only be related to the Azure instance and storage costs. From c09f242200276045742febd56f4410a025e33b43 Mon Sep 17 00:00:00 2001 From: bczoma Date: Tue, 22 May 2018 16:43:21 -0400 Subject: [PATCH 10/14] updated url download step --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38f9186..de78ef8 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Go to the Solace Developer Portal and copy the download URL of the Solace PubSub You can use this quick start template with either PubSub+ `Standard` or PubSub+ `Enterprise Evaluation Edition`. -| PubSub+ Standard Docker Image | PubSub+ Enterprise Evaluation Edition Docker Image +| PubSub+ Standard
Docker Image | PubSub+ Enterprise Evaluation Edition
Docker Image | :---: | :---: | | Free, up to 1k simultaneous connections,
up to 10k messages per second | 90-day trial version, unlimited | | [Get URL of Standard Docker Image](http://dev.solace.com/downloads/) | [Get URL of Evaluation Docker Image](http://dev.solace.com/downloads#eval) | From 6fb5c79e636976adbd21d3a0b8012f7c30085234 Mon Sep 17 00:00:00 2001 From: bczoma Date: Tue, 22 May 2018 17:05:54 -0400 Subject: [PATCH 11/14] download link related updates --- images/register.png | Bin 1766 -> 0 bytes scripts/deploy_solace.sh | 4 ++++ 2 files changed, 4 insertions(+) delete mode 100644 images/register.png diff --git a/images/register.png b/images/register.png deleted file mode 100644 index e1ccffe927687f0e4ab04cb28cf9359f70ad4cc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1766 zcma)6`8V5%9?i78wq{VLS`<@NHB>Eccw((rO)a%$stC3gj7c?wKYu>MwXf;5k!!UqV;{|KbZT&J@=k-Kj(AqFEN2}IBIFat} z0GXo#6$!zez}O;C%?7&X0Y?(hG6yKO0Z=tiGzsw6fzo#XLj-{E!s%t;#{sVzQAF$V%qkE_-Fvw6V?VGgTPqw{SF2Tt3zC%bY59E zzWh-t2NC4R4pAXp*!NyyTP4B#Z#4=8(gge==dWZ`$OvmyHO_}~z8e-zSl3vYWk+G7 zc7&NS1Q!5eq=ElMvb(XQ<13OKT7>5Qrb66=#Xh~guKyJ4A8@5h4&R?xv(}AF`8Tr2 zz&9=}WnzZuDP+!zg`{>(O{3uE)W!pM4K*U4gxUWxT!Qj#MA^S=$PqyJpTv^cn$}S? z#hxQjSf1bXO$jIczRf)EE>JidK90%CYmo-d)y9UdVT>PVt@vj>JY~9p^ zX>z|5(YDRopBjWzES9DBYx{T_3N0-uM3`XH*$^;=aic~!sFCyx<8OZ2e7~EtV~4Dz ze@wQie8si0xOEgfAN`>?yH`osc8Sp3XSYmy@y$a5Yc9De5#9%3%DOmS>;;;bm!Nmy z`3bf-b`Ui^m$P983?Zr4(O{!5bKGUegp;XW!+{NHRyNx)t05-Y=w2+#>{CV3pB zM*%hDe5&x-%~NL<5#CqZr>xnTmk1mJAs$cs15!}k;~e0oFI^xvIs5w%g1W9jEqAp% zap4NP;xvElQuf`6_g3yin$?|4WOwE}t4?9+YiduycAq?GNZnZLJlL=g%Z2s(CA}8l z&&J<5co~hq-T`_gFhLxno&JL7`XA`R+kKWgp7}I?()9Tz$8T9Kn5g93&0}1l<%c^W zZbj23gwfbK(TF62JgGo9THfrFlwxrfC4iLb!2Mk6Nq-4;wWR2Lm zaL5ZAkn;zs(RCw`0Dp4ggNvcH=bR04vWT!c#C`o9j}pQSl`^-Si! z;>seqMTJz?t|Z*#R1d2@AJgf=9DB1QP+N)*e)+kjBS(-oW-Tck6I47czG>q*V=67j zHE#~LU%&ik20x^yLB&#wP}P*rhmj^R4Qe@BA#ize%qM)ZM(-Y@o%^MLDz{f9u(3$2 zU94*bs?;FD$6Wj?(*Q|h?5F80Xv&-rsy_)G6=nY0+hl%tn{@%4q3aw{g4(h477Tm6 zEtLmp3@bMr?AxHhFT&_=h~Fhirv&k&pl>sT9WE~dXx1ZF1DwT|PUFrDFP&w5KYEmR zPwi#{rXtPfZL4h)uVpmp{PoC15?Xb-hj^#Z6U$XRURu1r>{eCIF`i)z)Mg^{SQ=|0 z`T>ULmRVfgcR^lSiLT0>eLs8}+t$?-OLth1oO7p3kl~M4n^}z&HzJ z)opVWI(%X#Ah$+5*28ytJ|ok=*Qe^>mSBlm4ZMktTQMr8C^3r|Htxi4qU5Ro;RooMOn${{Dw4}5 z)*B;ht0~>e?RAhrSzp@AB1*T^FQom}7VO3#SfSRLZVUd_LgBW>+O<<&h(?6$xW}qa zR8}d|CHC!Io{}^j`Uu4*1OuNW&Q5tur<;bS#F>Vm`SX(50Xq+NT4P!YjFeF$tzpf! zwqlB<>(X65m<8;dJGVlZEzVX6&z&;uoxY(`Uw{v9D35t|lVp`nGW9*gKb_>g+%Em| Y*BJ|$5F!5IHq)$ diff --git a/scripts/deploy_solace.sh b/scripts/deploy_solace.sh index 1aa0435..be23756 100644 --- a/scripts/deploy_solace.sh +++ b/scripts/deploy_solace.sh @@ -74,6 +74,10 @@ if [[ ${solace_url} == *"em.solace.com"* ]]; then LOAD_NAME="`echo $REAL_LINK | awk -v FS="(download/|?)" '{print $2}'`" # a redirect link provided by solace wget -O ${solace_directory}/solos.info -nv https://products.solace.com/download/${LOAD_NAME}_MD5 +elif [[ ${solace_url} == *"solace.com/download"* ]]; then + REAL_LINK=${solace_url} + # the new download url + wget -O ${solace_directory}/solos.info -nv ${solace_url}_MD5 else REAL_LINK=${solace_url} # an already-existing load (plus its md5 file) hosted somewhere else (e.g. in an s3 bucket) From d37009d41661ef3a80ae86366a1cf2af09a36411 Mon Sep 17 00:00:00 2001 From: bczoma Date: Wed, 23 May 2018 08:37:53 -0400 Subject: [PATCH 12/14] link updates --- README.md | 25 +++++++++++++++++-------- azuredeploy.json | 2 +- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index de78ef8..f0fdb52 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,23 @@ Microsoft OMS (Operations Management Suite) Agents are also installed on each me # Gaining admin access to the message broker -If you are used to working with console access to Solace PubSub+, this is available with the Azure instance. The [connect] button at the upper left of the `SolaceMessageBroker0`, `SolaceMessageBroker1`, or `SolaceMessageBroker2` resource view displays this information: +To manage the currently AD-Active message broker, you can connect to the Public IP Address associated with the Load Balancer as the 'admin' user. From the Resource Group view for your deployment on the Azure Portal, the Load Balancer is the resource named `myLB`, and its Public IP Address is the resource named `myLBPublicIPD`, which has an IP address and a DNS name that you can connect to. + +Refer to the [Management Tools section](https://docs.solace.com/Management-Tools.htm ) of the online documentation to learn more about the available tools. The WebUI is the recommended simplest way to administer the message broker for common tasks. + +### WebUI, SolAdmin and SEMP access + +Use the Load Balacer's external Public IP at port 8080 to access these services. + +### Solace CLI access + +If you are used to working with console access to Solace PubSub+, this is available with the Azure instance. + +There are two options to connect: +* Open a CLI SSH connection on port 2222 to the active node through the Load Balancer as described above; or +* Access the individual nodes: + +The [connect] button at the upper left of the `SolaceMessageBroker0`, `SolaceMessageBroker1`, or `SolaceMessageBroker2` resource view displays this information: ![alt text](images/remote_access.png "console with Solace cli") @@ -88,13 +104,6 @@ Use the specified "Admin Username" and "Admin Password" to log in. Once you have sudo docker exec -it solace /usr/sw/loads/currentload/bin/cli -A ``` -If you are unfamiliar with Solace PubSub+ message brokers, or would prefer an administration application, the SolAdmin management application is available. For more information on SolAdmin see the [SolAdmin page](http://dev.solace.com/tech/soladmin/). To get SolAdmin, visit the Solace [download page](http://dev.solace.com/downloads/) and select the OS version desired. The Management IP would be the external Public IP associated with your Azure instance and the port would be 8080 by default. - -![alt text](images/azure-soladmin.png "soladmin connection to gce") - -To manage the currently AD-Active message broker, you can open a CLI SSH connection (on port 2222) or connect SolAdmin (on port 8080) to the Public IP Address associated with the Load Balancer as the 'admin' user. From the Resource Group view for your deployment on the Azure Portal, the Load Balancer is the resource named `myLB`, and its Public IP Address is the resource named `myLBPublicIPD`, which has an IP address and a DNS name that you can connect to. - - # Testing data access to the message broker To test data traffic though the newly created message broker instance, visit the Solace developer portal and select your preferred programming language to [send and receive messages](http://dev.solace.com/get-started/send-receive-messages/). Under each language there is a Publish/Subscribe tutorial that will help you get started. diff --git a/azuredeploy.json b/azuredeploy.json index 9e21030..a178dde 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -143,7 +143,7 @@ "OSDiskName": "osdiskfordockersimple", "dataDiskName": "datadiskfordockersimple", "nicName": "myVMNicD", - "baseUrl": "https://raw.githubusercontent.com/SolaceDev/solace-azure-quickstart-template/SOL-4553/", + "baseUrl": "https://raw.githubusercontent.com/SolaceProducts/solace-azure-quickstart-template/master/", "nestedUrl": "[concat(variables('baseUrl'), 'nested/')]", "scriptsUrl": "[concat(variables('baseUrl'), 'scripts/')]", "solaceSecurityName": "SolaceSecurity.Template", From 28f9f3eb62848e1720fbd15566621c11c1060a53 Mon Sep 17 00:00:00 2001 From: bczoma Date: Wed, 23 May 2018 10:25:29 -0400 Subject: [PATCH 13/14] removal of old references --- images/ha-cluster.png | Bin 67843 -> 62275 bytes images/single-node.png | Bin 70871 -> 46564 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/images/ha-cluster.png b/images/ha-cluster.png index d8373dbf0d3b335f309dac8dbba8966914a245a1..866f0649e91f53d882d896a7173222dbdbd1b8f6 100644 GIT binary patch literal 62275 zcmdSAWmH_-wk`@ufCK_8lHe31A-H>RDI~Z<(25|1yGtcODum$f6z(LrlR$7Q+#z`3 z?)D~Rt$p@+ubtc8z5CZ~jcSdmIp-LC^wH((-{>0uhqMB?7&P? zWYWjS(+oCy&7F^qFY8iH72LAx_j^l2r1c_?pFKw+2|oD;|HbX-n~I>mhYNZJMco$% z%iJdukoZ5nlumD(TT~Ri`W-tBahxm{xH~YU%4$VW_kqlP;bRIuE-piWk`swGa#GZ_ zpf0fW{jUnE$s7Xcs|8KPm1@OLgeu_utM-gCGUGWZM((Sy#XDryQ&o0X7pGjNy&6ya z=(3fP7}U^w0d|~@urwGRsPGg$+24U)Kkds zsiiI-5@L}rre_COf8MV_m=>`vDS_tvz2Bv17Ui$vdd((dlBt2OhvzxT;$jWA<3SJF zl9D{Rbi`k{A5_tsqfXb}6LQbz7X}6fn!VyED=rR^e)RaUpnyP4O$`*KOG)XWl(qMH z6}P8a#+S$W$RUH#Y-5Q)huwQ)94YEvV=fWCkd$X_KL0>=iQ9B)av~W4*3oEU$$z2U z*?y;%@1W`cDzPb_S@n}pfM~H}YWMx5KW&7XJ}i=zqCU!DP|bC5qm|C>#YO?40ByEb z=j&M8sU0@6EebCkj}FvuVEquP9P@t;m7~ z?_YjY3N-1C6^E4!Le>&fPOr)9zZc51dhSmkyP{drg^P4bms`ngGMZD%*tobNmKEYS z{f=I>ft^r4mU|MiL9wtAY*36}x{Qrm>8n+KiYrz_ut+4IP=%?PWBIRj#cwet^uEG%=>suFakym5Ln3+LNp^LN zU3X|LFijG{a1C6{;;})#AJhubZaJ14;T-rS%j|LFUsJ6|?6&&Vct~<5``SANO1hgv z9^<#iV(B=GP@Ek;b^?zXIbk!9}6EtOBk|j9P>+86no4i!hW?o%V!2i`$2{N}R z%5X_sWLfBc6knxYT>jboa{%-!i>qc}s?;kJJU%@`h% z^Y#&nZD2OI5?AnJ>WXi6&1yh|XdfVV{OK&_@woSOC!YT;i#c5?kv4eL@!{S@D4D>| zT}bV^+f^*N?y_DZqHQF78&>~}Sva1RB;;!~Vz~KrDrG>;kQYw>G*X*2H$#F;v~)n0 zy7N<*l)lc0V_RTZyhhokes!7jbg(sncJz(BmBiqQ!#la%3lqQoOHLfBJ!ZQQ4?68E|>i5P5#+lxI4)%ily_D|= z2J5OTCKGyn{xfocaxK~X{lvZ~V?~#`b`{a99{-F=vW9Z;nc8&1KjTs2df6@Kh5wYF z3HhaqyGb=#XK8o0yx^MC&F=1>v6~qUyG*sZ^vsNV-U>wsok(BO8>hr~gre5_#lv`} zJ4)WP$2S{Uv!|6KOfyz!>*roV(nV~@Dco(A!yi{KZQ>?f)@e{%)I=DwmJ#7*)2tw+ zt*2cLCndIj&``d;v7&si-fsfkFg$;0Xw^cQqv<<96Uup*;1NfzelDR@ ztdGSGqQ7?Wt$FD5qa-VNwP=RhWza2NmRcv%O8we1vJF@zcgorHA(PVX7vCDn;p`d3 z^#NySxQ9UXD#u~tJzy@wUr-2l2JXz!5XRc5qidM}hH zS0!5RiWSruOk&<&4zw7WY>6n~S6Ieu#uIiwk8`G}Zzw2WW?*1oVzO8tDJ18$eCd7h zk|iA25Z&Y=1%|{&#fIO6J&uq>_pQDVcib3Sb_3#ABu-V58W-2xyV~P;>*vp(@$qD2 zm0U!$r!)bK>!!gIl4L@%vO%! zkRx~ZFr#+N9(?Kdl(PS3KZ^LuioR9{ZuyTaRPg@SI7RZ-)~t{>WRJ{ITU*vOmfT9z z`tU!qZ8yT!3oG~9ttzLbSDF_LJL0#D;?6T;KJ#RVrNOXw#Iy%wW>k%J=96~CBTiPOj zyBY%utOn{d1VWlT{EgVg@PCJu;O+}G^2G^0&LKP=*OIP z=D@IuUB$}_ED%he0M~c~YBb0ihU$lSXE2wRagB~|TCR2#q8hA|&Jecwz^!wg+=q~| zhy|QTsg@Bdr~s!q%7XJtkrG>{vt$2@p6rVN{|i+rY`+U!$|rxBCZXSI%yB!KHd8I$z6z@CQ0~X@sh6=bDr~=N}Jg z7u6r>l39dPvXG|R_5BGC&~&osH=~LWaiT!vHL2?wC|pA zZI5G<;*eN5cm0IyA5jmbKiCYAQwZWN3#udQr!b3ob8iS)$Mt4_UK~3I@u2*W3%)(> zz{wNcHFm~{Q-*jZ`JaP<|G(%$_{-(_ao1}o5}DrB(}R22wsqGE6&Qu}Q1qPAM{44o z!X0zyRcQC=L~`&9I*rmLf}N)Ni|ND+?`YrD_EdF*Xldj6*xf1GpJerjQ)(S5IW<^x zf~eukXNA(j_hLx7Ou7^KZ_olvG{nfnWRIeV-DzzI*bT|mzNv`T)>eU-iwjR{3$vJ~ z82w1|$Ju#`mg6Dz@xBw<;D`ZMaqJ>Qu4n(D{BhCU&xurYl%X6rq0SG~QgMYD>Z7Hv z%