diff --git a/README.md b/README.md index 7ad1de9..f0fdb52 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,36 @@ -# 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 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, 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: -* 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,74 +39,84 @@ 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 | |----------------------------|--------------------------------------------------------------------------------| | **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' SolOS CLI user. | -| Security Group Name | New or existing security group, where VMR 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. | +| 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(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 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. 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: +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. -![alt text](images/remote_access.png "console with SolOS cli") +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. -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: +### WebUI, SolAdmin and SEMP access -``` -sudo docker exec -it solace /usr/sw/loads/currentload/bin/cli -A -``` +Use the Load Balacer's external Public IP at port 8080 to access these services. + +### Solace CLI access -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 used to working with console access to Solace PubSub+, this is available with the Azure instance. -![alt text](images/azure-soladmin.png "soladmin connection to gce") +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: -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. +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") + +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 +``` -# 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,13 +132,13 @@ 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/) 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/). +- [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/ ). diff --git a/azuredeploy.json b/azuredeploy.json index 0321702..a178dde 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -22,22 +22,23 @@ }, "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": { "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", @@ -59,7 +60,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": { @@ -89,11 +90,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 +117,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,24 +143,25 @@ "OSDiskName": "osdiskfordockersimple", "dataDiskName": "datadiskfordockersimple", "nicName": "myVMNicD", - "scriptUrl": "https://raw.githubusercontent.com/SolaceProducts/solace-azure-quickstart-template/master/", + "baseUrl": "https://raw.githubusercontent.com/SolaceProducts/solace-azure-quickstart-template/master/", + "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", - "solaceInstallScriptName": "deploy_vmr.sh", + "workspaceEnabledSharedTemplateName": "workspace-enabled-shared-resources.json", + "workspaceDisabledSharedTemplateName": "workspace-disabled-shared-resources.json", + "solaceInstallScriptName": "deploy_solace.sh", "sempQueryScriptName": "semp_query.sh", "publicIPAddressName": "myPublicIPD", "publicIPAddressNameLB": "myLBPublicIPD", "publicIPAddressType": "Dynamic", "vmStorageAccountVHDsName": "vhds", "vmStorageAccountContainersName": "containers", - "vmName": "SolaceVMR", "addressPrefix": "10.0.0.0/16", "subnetPrefix": "10.0.0.0/24", - "nodeAddressPrefix": "10.0.0.10", "storageAccountType": "Standard_LRS", "subnetName": "Subnet", "virtualNetworkName": "MyVNETD", @@ -169,13 +173,12 @@ "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": { "0": [ { - "name": "[concat(variables('vmName'), 0, '-datadisk1')]", + "name": "[concat(parameters('dnsLabelForVmIp'), 0, '-datadisk1')]", "diskSizeGB": "[parameters('dataDiskSize')]", "lun": 0, "vhd": { @@ -187,7 +190,7 @@ ], "1": [ { - "name": "[concat(variables('vmName'), 1, '-datadisk1')]", + "name": "[concat(parameters('dnsLabelForVmIp'), 1, '-datadisk1')]", "diskSizeGB": "[parameters('dataDiskSize')]", "lun": 0, "vhd": { @@ -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": { @@ -337,8 +340,7 @@ { "name": "ipconfig1", "properties": { - "privateIPAllocationMethod": "Static", - "privateIPAddress": "[concat(variables('nodeAddressPrefix'), copyindex())]", + "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'), copyindex()))]" }, @@ -379,7 +381,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", @@ -398,7 +400,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')]" }, @@ -410,7 +412,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')]" }, @@ -431,14 +433,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", @@ -449,16 +451,17 @@ } }, { + "condition": "[not(empty(parameters('workspaceName')))]", "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": { @@ -476,14 +479,14 @@ { "apiVersion": "2016-03-30", "type": "Microsoft.Compute/virtualMachines/extensions", - "name": "[concat(variables('vmName'), copyindex(), '/configureVMRContainer')]", + "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')]" + "[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", @@ -492,15 +495,15 @@ "autoUpgradeMinorVersion": true, "settings": { "fileUris": [ - "[parameters('solaceVmrUri')]", - "[concat(variables('scriptUrl'), 'scripts/', variables('solaceInstallScriptName'))]", - "[concat(variables('scriptUrl'), 'scripts/', variables('sempQueryScriptName'))]" + "[parameters('solaceDockerImageUri')]", + "[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(), ' -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(), ' -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/images/ha-cluster.png b/images/ha-cluster.png index d8373db..1ec294b 100644 Binary files a/images/ha-cluster.png and b/images/ha-cluster.png differ diff --git a/images/register.png b/images/register.png deleted file mode 100644 index e1ccffe..0000000 Binary files a/images/register.png and /dev/null differ diff --git a/images/single-node.png b/images/single-node.png new file mode 100644 index 0000000..289d4ea Binary files /dev/null and b/images/single-node.png differ diff --git a/images/single-vmr.png b/images/single-vmr.png deleted file mode 100644 index baa0385..0000000 Binary files a/images/single-vmr.png and /dev/null differ 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/loadbalancer-shared-resources.json b/nested/loadbalancer-shared-resources.json similarity index 98% rename from loadbalancer-shared-resources.json rename to nested/loadbalancer-shared-resources.json index 0fddd83..96388e8 100644 --- a/loadbalancer-shared-resources.json +++ b/nested/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/security-shared-resources.json b/nested/security-shared-resources.json similarity index 97% rename from security-shared-resources.json rename to nested/security-shared-resources.json index a982cec..65f1ca1 100644 --- a/security-shared-resources.json +++ b/nested/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." } } }, 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 new file mode 100644 index 0000000..be23756 --- /dev/null +++ b/scripts/deploy_solace.sh @@ -0,0 +1,462 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +OPTIND=1 # Reset in case getopts has been used previously in the shell. + +# Initialize our own variables: +current_index="" +dns_prefix="" +number_of_instances="" +solace_url="" +admin_password_file="" +disk_size="" +workspace_id="" +is_primary="false" + +verbose=0 + +while getopts "c:d:n:p:s:w:u:" opt; do + case "$opt" in + c) current_index=$OPTARG + ;; + d) dns_prefix=$OPTARG + ;; + n) number_of_instances=$OPTARG + ;; + p) admin_password_file=$OPTARG + ;; + s) disk_size=$OPTARG + ;; + u) solace_url=$OPTARG + ;; + w) workspace_id=$OPTARG + ;; + esac +done + +shift $((OPTIND-1)) +[ "$1" = "--" ] && shift + +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 , 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 +yum -y install lvm2 +yum -y install epel-release +yum -y install jq + +#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 +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) + wget -O ${solace_directory}/solos.info -nv ${solace_url}.md5 +fi + +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: Download from URL provided and validate, trying up to 5 times" +LOOP_COUNT=0 +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} + LOCAL_MD5_SUM=${SOLOS_INFO[0]} + 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 + ((LOOP_COUNT++)) +done +if [ ${LOOP_COUNT} == 3 ]; then + echo "`date` ERROR: Failed to download the Solace load, exiting" | tee /dev/stderr + exit 1 +fi + +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_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 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 + # 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 + 0 ) + redundancy_config="\ + --env nodetype=message_routing \ + --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_${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=${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_${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=${dns_prefix}monitor \ + --env redundancy_group_passwordfilepath=$(basename ${admin_password_file}) \ + --env redundancy_enable=yes \ + --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 + echo "`date` INFO: Configuring singleton" + redundancy_config="" +fi + +#Create new volumes that the VMR container can use to consume and store data. +docker volume create --name=jail +docker volume create --name=var +docker volume create --name=softAdb +docker volume create --name=adbBackup + +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 + # 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 $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 + mkdir /opt/vmr/internalSpool + mount -a + 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 +docker create \ + --privileged=true \ + --net=host \ + --uts=host \ + --shm-size=${shmsize} \ + --ulimit core=-1 \ + --ulimit memlock=-1 \ + --ulimit nofile=${ulimit_nofile} \ + ${LOG_OPT} \ + -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 ${admin_password_file}) \ + --env system_scaling_maxconnectioncount=${maxconnectioncount} \ + ${logging_config} \ + ${redundancy_config} \ + --name=solace ${VMR_IMAGE} +EOF + +#Make the file executable +chmod +x /root/docker-create + +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 +EOF + +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 Solace SEMP service to be enabled" +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/service/services/service[name='SEMP']/enabled[text()]"` + + is_vmr_up=`echo ${online_results} | jq '.valueSearchResult' -` + echo "`date` INFO: SEMP service 'enabled' status is: ${is_vmr_up}" + + run_time=$((${count} * ${pause})) + if [ "${is_vmr_up}" = "\"true\"" ]; then + echo "`date` INFO: Solace message broker SEMP service is up, after ${run_time} seconds" + break + fi + ((count++)) + 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 ${admin_password_file} + +# Poll the redundancy status on the Primary VMR +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 ${admin_password} -u http://localhost:8080/SEMP \ + -q "" \ + -v "/rpc-reply/rpc/show/redundancy/virtual-routers/primary/status/activity[text()]"` + + local_activity=`echo ${online_results} | jq '.valueSearchResult' -` + echo "`date` INFO: Local activity state is: ${local_activity}" + + run_time=$((${count} * ${pause})) + case "${local_activity}" in + "\"Local Active\"") + echo "`date` INFO: Redundancy is up locally, Primary Active, after ${run_time} seconds" + mate_active_check="Standby" + break + ;; + "\"Mate Active\"") + echo "`date` INFO: Redundancy is up locally, Backup Active, after ${run_time} seconds" + mate_active_check="Active" + break + ;; + esac + ((count++)) + echo "`date` INFO: Waited ${run_time} seconds, Redundancy not yet up" + sleep ${pause} + done + + if [ ${count} -eq ${loop_guard} ]; then + echo "`date` ERROR: Solace redundancy group never came up" | tee /dev/stderr + echo "`date` ERROR: giving up! Details:" + echo `curl -u admin:${admin_password} http://localhost:8080/SEMP -d ""` + exit 1 + fi + + 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 ${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()]"` + + mate_activity=`echo ${online_results} | jq '.valueSearchResult' -` + echo "`date` INFO: Mate activity state is: ${mate_activity}" + + run_time=$((${count} * ${pause})) + case "${mate_activity}" in + "\"Active\"") + echo "`date` INFO: Redundancy is up end-to-end, Backup Active, after ${run_time} seconds" + mate_active_check="Standby" + break + ;; + "\"Standby\"") + echo "`date` INFO: Redundancy is up end-to-end, Primary Active, after ${run_time} seconds" + mate_active_check="Active" + break + ;; + esac + ((count++)) + 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: 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 ${admin_password} -u http://localhost:8080/SEMP \ + -q "" + ./semp_query.sh -n admin -p ${admin_password} -u http://localhost:8080/SEMP \ + -q "default" +fi + +if [ ${count} -eq ${loop_guard} ]; then + echo "`date` ERROR: Solace bringup failed" | tee /dev/stderr + exit 1 +fi +echo "`date` INFO: Solace bringup complete" diff --git a/scripts/deploy_vmr.sh b/scripts/deploy_vmr.sh deleted file mode 100644 index 6c47541..0000000 --- a/scripts/deploy_vmr.sh +++ /dev/null @@ -1,401 +0,0 @@ -#!/bin/bash - -OPTIND=1 # Reset in case getopts has been used previously in the shell. - -# Initialize our own variables: -current_index="" -ip_prefix="" -number_of_instances="" -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 -done - -shift $((OPTIND-1)) -[ "$1" = "--" ] && shift - -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}` - -#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}" -else - MD5_SUM_OTHER="" - SolOS_OTHER_LOAD="" -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}" - -echo "`date` INFO: try 3 times to download from URL provided and validate it is Evaluation and Community edition VRM" -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}` - 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 - 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 - 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} - -export VMR_VERSION=`docker images | grep solace | awk '{print $2}'` -echo "`date` INFO: VMR version: ${VMR_VERSION}" - -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' -else - echo "`date` INFO: Memory size is ${MEM_SIZE}" -fi - -if [ ${number_of_instances} -gt 1 ]; then - echo "`date` INFO: Configuring HA tuple" - 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_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 configsync_enable=yes" - is_primary="true" - ;; - 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_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 configsync_enable=yes" - ;; - 2 ) - redundancy_config="\ - --env nodetype=monitoring \ - --env routername=monitor \ - --env redundancy_group_passwordfilepath=$(basename ${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" - ;; - esac -else - echo "`date` INFO: Configuring singleton" - redundancy_config="" -fi - -#Create new volumes that the VMR container can use to consume and store data. -docker volume create --name=jail -docker volume create --name=var -docker volume create --name=softAdb -docker volume create --name=adbBackup - -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" - ( - echo n # Add a new partition - echo p # Primary partition - echo 1 # Partition number - echo # First sector (Accept default: 1) - echo # Last sector (Accept default: varies) - echo w # Write changes - ) | sudo fdisk $disk_volume - mkfs.xfs ${disk_volume}1 -m crc=0 - UUID=`blkid -s UUID -o value ${disk_volume}1` - echo "UUID=${UUID} /opt/vmr xfs defaults 0 0" >> /etc/fstab - mkdir /opt/vmr - mkdir /opt/vmr/diagnostics - mkdir /opt/vmr/internalSpool - mount -a - SPOOL_MOUNT="-v /opt/vmr/diagnostics:/var/lib/solace/diags -v /opt/vmr/internalSpool:/usr/sw/internalSpool" -fi - -#Define a create script -tee /root/docker-create <<-EOF -#!/bin/bash -docker create \ - --privileged=true \ - --net=host \ - --uts=host \ - --shm-size 2g \ - --ulimit core=-1 \ - --ulimit memlock=-1 \ - --ulimit nofile=2448:38048 \ - --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 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 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 \ - ${redundancy_config} \ - --name=solace solace-app:${VMR_VERSION} -EOF - -#Make the file executable -chmod +x /root/docker-create - -echo "`date` INFO: Creating the Solace VMR 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 -EOF - -echo "`date` INFO: Start the Solace VMR 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" -while [ ${count} -lt ${loop_guard} ]; do - online_results=`./semp_query.sh -n admin -p ${password} -u http://localhost:8080/SEMP \ - -q "" \ - -v "/rpc-reply/rpc/show/service/services/service[name='SEMP']/enabled[text()]"` - - is_vmr_up=`echo ${online_results} | jq '.valueSearchResult' -` - echo "`date` INFO: SEMP service 'enabled' status is: ${is_vmr_up}" - - run_time=$((${count} * ${pause})) - if [ "${is_vmr_up}" = "\"true\"" ]; then - echo "`date` INFO: VMR SEMP service is up, after ${run_time} seconds" - break - fi - ((count++)) - echo "`date` INFO: Waited ${run_time} seconds, VMR 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} - -# Poll the redundancy status on the Primary VMR -loop_guard=30 -pause=10 -count=0 -mate_active_check="" -if [ "${is_primary}" = "true" ]; then - echo "`date` INFO: Wait for Primary to be 'Local Active' or 'Mate Active'" - while [ ${count} -lt ${loop_guard} ]; do - online_results=`./semp_query.sh -n admin -p ${password} -u http://localhost:8080/SEMP \ - -q "" \ - -v "/rpc-reply/rpc/show/redundancy/virtual-routers/primary/status/activity[text()]"` - - local_activity=`echo ${online_results} | jq '.valueSearchResult' -` - echo "`date` INFO: Local activity state is: ${local_activity}" - - run_time=$((${count} * ${pause})) - case "${local_activity}" in - "\"Local Active\"") - echo "`date` INFO: Redundancy is up locally, Primary Active, after ${run_time} seconds" - mate_active_check="Standby" - break - ;; - "\"Mate Active\"") - echo "`date` INFO: Redundancy is up locally, Backup Active, after ${run_time} seconds" - mate_active_check="Active" - break - ;; - esac - ((count++)) - echo "`date` INFO: Waited ${run_time} seconds, Redundancy not yet up" - sleep ${pause} - done - - if [ ${count} -eq ${loop_guard} ]; then - echo "`date` ERROR: Solace redundancy group never came up" | tee /dev/stderr - exit 1 - fi - - loop_guard=30 - 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 \ - -q "" \ - -v "/rpc-reply/rpc/show/redundancy/virtual-routers/primary/status/detail/priority-reported-by-mate/summary[text()]"` - - mate_activity=`echo ${online_results} | jq '.valueSearchResult' -` - echo "`date` INFO: Mate activity state is: ${mate_activity}" - - run_time=$((${count} * ${pause})) - case "${mate_activity}" in - "\"Active\"") - echo "`date` INFO: Redundancy is up end-to-end, Backup Active, after ${run_time} seconds" - mate_active_check="Standby" - break - ;; - "\"Standby\"") - echo "`date` INFO: Redundancy is up end-to-end, Primary Active, after ${run_time} seconds" - mate_active_check="Active" - break - ;; - esac - ((count++)) - echo "`date` INFO: Waited ${run_time} seconds, Redundancy not yet up" - sleep ${pause} - done - - if [ ${count} -eq ${loop_guard} ]; then - echo "`date` ERROR: Solace redundancy group never came up" | tee /dev/stderr - exit 1 - fi - - ./semp_query.sh -n admin -p ${password} -u http://localhost:8080/SEMP \ - -q "" - ./semp_query.sh -n admin -p ${password} -u http://localhost:8080/SEMP \ - -q "default" -fi -echo "`date` INFO: Solace VMR bringup complete" \ No newline at end of file