├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── advanced-monitoring ├── .gitignore ├── Deployment │ ├── createUiDefinition.json │ └── template.json ├── README.md ├── Worker │ ├── Dockerfile │ ├── crontab │ ├── get_cloud_info.py │ ├── get_info.sh │ ├── install.sh │ ├── install_rhel.sh │ ├── loop.sh │ ├── main.py │ ├── nsx-stat.service │ ├── requirements.txt │ ├── start.sh │ └── telegraf.conf └── media │ ├── assign_identity.png │ ├── assign_identity_private_cloud.png │ ├── assign_userdata.png │ ├── evm_pervm_cpu_usage.png │ ├── extended_metrics.PNG │ ├── nsx_base_metrics.PNG │ ├── nsx_t0_priv01_bytes.PNG │ ├── overview.PNG │ ├── pervm_cpu_usage.png │ ├── template_1.png │ ├── template_2.png │ ├── template_3.png │ ├── template_4.png │ └── template_5.png ├── avs-autoscale ├── README.md ├── code │ ├── autoscale-in-runbook.ps1 │ └── autoscale-out-runbook.ps1 └── media │ ├── image1.png │ ├── image10.png │ ├── image11.png │ ├── image12.png │ ├── image13.png │ ├── image14.png │ ├── image15.png │ ├── image16.png │ ├── image17.png │ ├── image18.png │ ├── image19.png │ ├── image2.png │ ├── image20.png │ ├── image21.png │ ├── image22.png │ ├── image23.png │ ├── image24.png │ ├── image25.png │ ├── image26.png │ ├── image27.png │ ├── image28.png │ ├── image29.png │ ├── image3.png │ ├── image30.png │ ├── image31.png │ ├── image32.png │ ├── image33.png │ ├── image34.png │ ├── image35.png │ ├── image36.png │ ├── image37.png │ ├── image38.png │ ├── image39.png │ ├── image4.png │ ├── image40.png │ ├── image41.png │ ├── image42.png │ ├── image5.png │ ├── image6.png │ ├── image7.png │ ├── image8.png │ └── image9.png ├── azure-vmware-master-diagrams ├── Azure-VMware-Solution-Availability-Design-Template.pptx ├── Azure-VMware-Solution-Performance-Design-Template.pptx ├── Azure-VMware-Solution-Recoverability-Design-Template.pptx ├── Azure-VMware-Solution-Security-Design-Template.pptx └── azure-vmware-master-diagrams.pptx └── syslog-forwarder ├── README.md ├── code └── index.js └── media ├── image1.png ├── image10.png ├── image11.png ├── image12.png ├── image13.png ├── image14.png ├── image15.png ├── image16.png ├── image17.png ├── image18.png ├── image19.png ├── image2.png ├── image20.png ├── image21.png ├── image22.png ├── image23.png ├── image24.png ├── image25.png ├── image26.png ├── image27.png ├── image28.png ├── image29.png ├── image3.png ├── image30.png ├── image31.png ├── image32.png ├── image33.png ├── image34.png ├── image35.png ├── image36.png ├── image37.png ├── image38.png ├── image39.png ├── image4.png ├── image40.png ├── image41.png ├── image42.png ├── image43.png ├── image44.png ├── image45.png ├── image46.png ├── image47.png ├── image48.png ├── image49.png ├── image5.png ├── image50.png ├── image51.png ├── image52.png ├── image53.png ├── image54.png ├── image55.png ├── image56.png ├── image6.png ├── image7.png ├── image8.png └── image9.png /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure VMware Solution Repository 2 | 3 | The Azure VMware Solution product group has created this GitHub repository to share prescriptive architectural approaches and tools for customers and partners using the Azure VMware Solution service. This is intended to enhance the value of the Azure VMware Solution service to our customers and partners. 4 | 5 | Use the [Table of Contents](#table-of-contents) section below to jump to the README.md file of the solution you are interested in. These solutions have been peer reviewed but are best-effort and should be assessed and tested by the customer before using in an Azure VMware Solution production environment. 6 | 7 | ## Table of Contents 8 | 9 | * [Azure VMware Solution Auto-Scale](https://github.com/Azure/azure-vmware-solution/blob/main/avs-autoscale/) 10 | * [Azure VMware Solution Advanced Monitoring](https://github.com/Azure/azure-vmware-solution/blob/main/advanced-monitoring/) 11 | * [Azure VMware Solution Syslog Forwarder](https://github.com/Azure/azure-vmware-solution/tree/main/syslog-forwarder) 12 | * [Azure VMware Solution Master Diagrams](https://github.com/Azure/azure-vmware-solution/tree/main/azure-vmware-master-diagrams) 13 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## How to file issues and get help 4 | 5 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 6 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 7 | feature request as a new Issue. 8 | 9 | ## Microsoft Support Policy 10 | 11 | Support for this Azure VMware Solution GitHub Repo is limited to the resources listed above. 12 | -------------------------------------------------------------------------------- /advanced-monitoring/.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | .vscode 3 | .env -------------------------------------------------------------------------------- /advanced-monitoring/Deployment/createUiDefinition.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "", 3 | "view": { 4 | "kind": "Form", 5 | "properties": { 6 | "title": "AVS Advanced Monitoring", 7 | "isWizard": true, 8 | "steps": [ 9 | { 10 | "name": "basics", 11 | "label": "Basics", 12 | "elements": [ 13 | { 14 | "name": "resourceScope", 15 | "type": "Microsoft.Common.ResourceScope", 16 | "location": { 17 | "resourceTypes": [ 18 | "microsoft.resources/resourcegroups" 19 | ] 20 | } 21 | } 22 | ] 23 | }, 24 | { 25 | "name" : "privateCloud", 26 | "label": "Private Cloud Selection", 27 | "elements": [ 28 | { 29 | "name": "privateCloudSelector", 30 | "type": "Microsoft.Solutions.ResourceSelector", 31 | "label": "Select AVS Private Cloud", 32 | "resourceType": "Microsoft.AVS/privateClouds", 33 | "options": { 34 | "filter": { 35 | "subscription": "onBasics" 36 | } 37 | } 38 | } 39 | ] 40 | }, 41 | { 42 | "name" : "virtualNetwork", 43 | "label": "Virtual Network Selection", 44 | "elements": [ 45 | { 46 | "name": "virtualNetwork", 47 | "type": "Microsoft.Network.VirtualNetworkCombo", 48 | "label": { 49 | "virtualNetwork": "Select existing virtual network with access to the Private Cloud", 50 | "subnets": "Select an existing subnet" 51 | }, 52 | "scope": { 53 | "subscriptionId": "[steps('basics').resourceScope.subscription.subscriptionId]", 54 | "location": "[steps('basics').resourceScope.location.name]" 55 | }, 56 | "toolTip": { 57 | "virtualNetwork": "Creating a new VNet is not allowed, attempts to do so will fail", 58 | "subnets": "Must select an existing subnet" 59 | }, 60 | "options": { 61 | "hideExisting": false 62 | }, 63 | "constraints": { 64 | "minAddressPrefixSize": "/30" 65 | }, 66 | "subnets": { 67 | "subnet1": { 68 | "label": "Subnet", 69 | "defaultValue": { 70 | "name": "Default" 71 | }, 72 | "constraints": { 73 | "minAddressPrefixSize": "/30", 74 | "minAddressCount": 1, 75 | "requireContiguousAddresses": true 76 | } 77 | } 78 | } 79 | } 80 | ] 81 | }, 82 | { 83 | "name" : "virtualMachineName", 84 | "label": "Virtual Machine", 85 | "elements": [ 86 | { 87 | "name": "virtualMachineName", 88 | "type": "Microsoft.Common.TextBox", 89 | "label": "Enter a name for the Virtual Machine" 90 | }, 91 | { 92 | "name" :"virtualMachineUserName", 93 | "type": "Microsoft.Common.TextBox", 94 | "label": "Enter a username for the VM" 95 | }, 96 | { 97 | "name" :"virtualMachinePassword", 98 | "type": "Microsoft.Common.PasswordBox", 99 | "label": { 100 | "password": "Password", 101 | "confirmPassword": "Confirm password" 102 | }, 103 | "toolTip": "", 104 | "constraints": { 105 | "required": true, 106 | "regex": "^(?=.*[A-Z])(?=.*[.!@#$%^&*()-_=+])(?=.*[0-9])(?=.*[a-z]).{8,40}$", 107 | "validationMessage": "Password must be at least 8 characters long, and contain upper case, lower case, number and symbol" 108 | }, 109 | "options": { 110 | "hideConfirmation": false 111 | }, 112 | "visible": true 113 | } 114 | ] 115 | } 116 | ] 117 | }, 118 | "outputs": { 119 | "parameters": { 120 | "location": "[steps('basics').resourceScope.location.name]", 121 | "networkInterfaceName" : "[guid()]", 122 | "subnetName": "[steps('virtualNetwork').virtualNetwork.subnets.subnet1.name]", 123 | "virtualNetworkId" : "[concat(steps('basics').resourceScope.subscription.id , '/resourceGroups/', steps('virtualNetwork').virtualNetwork.resourceGroup, '/providers/Microsoft.Network/virtualNetworks/', steps('virtualNetwork').virtualNetwork.name)]", 124 | "virtualMachineName" : "[steps('virtualMachineName').virtualMachineName]", 125 | "virtualMachineComputerName" : "[steps('virtualMachineName').virtualMachineName]", 126 | "virtualMachineRG": "[steps('basics').resourceScope.resourceGroup.name]", 127 | "osDiskType" : "Premium_LRS", 128 | "osDiskDeleteOption" : "Delete", 129 | "virtualMachineSize" :"Standard_DS1_v2", 130 | "nicDeleteOption": "Delete", 131 | "adminUsername" : "[steps('virtualMachineName').virtualMachineUserName]", 132 | "adminPassword" : "[steps('virtualMachineName').virtualMachinePassword]", 133 | "userData" : "[encodeBase64(concat('AVS_CLOUD_ID=',steps('privateCloud').privateCloudSelector.id))]", 134 | "privateCloudId" : "[steps('privateCloud').privateCloudSelector.id]" 135 | }, 136 | "kind": "ResourceGroup", 137 | "location": "[steps('basics').resourceScope.location.name]", 138 | "resourceGroupId": "[steps('basics').resourceScope.resourceGroup.id]" 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /advanced-monitoring/Deployment/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "type": "string" 7 | }, 8 | "networkInterfaceName": { 9 | "type": "string" 10 | }, 11 | "subnetName": { 12 | "type": "string" 13 | }, 14 | "virtualNetworkId": { 15 | "type": "string" 16 | }, 17 | "virtualMachineName": { 18 | "type": "string" 19 | }, 20 | "virtualMachineComputerName": { 21 | "type": "string" 22 | }, 23 | "virtualMachineRG": { 24 | "type": "string" 25 | }, 26 | "osDiskType": { 27 | "type": "string" 28 | }, 29 | "osDiskDeleteOption": { 30 | "type": "string" 31 | }, 32 | "virtualMachineSize": { 33 | "type": "string" 34 | }, 35 | "nicDeleteOption": { 36 | "type": "string" 37 | }, 38 | "adminUsername": { 39 | "type": "string" 40 | }, 41 | "adminPassword": { 42 | "type": "secureString" 43 | }, 44 | "userData": { 45 | "type": "string" 46 | }, 47 | "privateCloudId": { 48 | "type" : "string" 49 | } 50 | }, 51 | "variables": { 52 | "vnetId": "[parameters('virtualNetworkId')]", 53 | "vnetName": "[last(split(variables('vnetId'), '/'))]", 54 | "subnetRef": "[concat(variables('vnetId'), '/subnets/', parameters('subnetName'))]" 55 | }, 56 | "resources": [ 57 | { 58 | "name": "[parameters('networkInterfaceName')]", 59 | "type": "Microsoft.Network/networkInterfaces", 60 | "apiVersion": "2021-03-01", 61 | "location": "[parameters('location')]", 62 | "dependsOn": [], 63 | "properties": { 64 | "ipConfigurations": [ 65 | { 66 | "name": "ipconfig1", 67 | "properties": { 68 | "subnet": { 69 | "id": "[variables('subnetRef')]" 70 | }, 71 | "privateIPAllocationMethod": "Dynamic" 72 | } 73 | } 74 | ] 75 | } 76 | }, 77 | { 78 | "name": "[parameters('virtualMachineName')]", 79 | "type": "Microsoft.Compute/virtualMachines", 80 | "apiVersion": "2022-03-01", 81 | "location": "[parameters('location')]", 82 | "identity": { 83 | "type" :"SystemAssigned" 84 | }, 85 | "dependsOn": [ 86 | "[concat('Microsoft.Network/networkInterfaces/', parameters('networkInterfaceName'))]" 87 | ], 88 | "properties": { 89 | "hardwareProfile": { 90 | "vmSize": "[parameters('virtualMachineSize')]" 91 | }, 92 | "storageProfile": { 93 | "osDisk": { 94 | "createOption": "fromImage", 95 | "managedDisk": { 96 | "storageAccountType": "[parameters('osDiskType')]" 97 | }, 98 | "deleteOption": "[parameters('osDiskDeleteOption')]" 99 | }, 100 | "imageReference": { 101 | "publisher": "canonical", 102 | "offer": "0001-com-ubuntu-server-jammy", 103 | "sku": "22_04-lts-gen2", 104 | "version": "latest" 105 | } 106 | }, 107 | "networkProfile": { 108 | "networkInterfaces": [ 109 | { 110 | "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaceName'))]", 111 | "properties": { 112 | "deleteOption": "[parameters('nicDeleteOption')]" 113 | } 114 | } 115 | ] 116 | }, 117 | "osProfile": { 118 | "computerName": "[parameters('virtualMachineComputerName')]", 119 | "adminUsername": "[parameters('adminUsername')]", 120 | "adminPassword": "[parameters('adminPassword')]", 121 | "linuxConfiguration": { 122 | "patchSettings": { 123 | "patchMode": "ImageDefault" 124 | } 125 | } 126 | }, 127 | "userData": "[parameters('userData')]", 128 | "diagnosticsProfile": { 129 | "bootDiagnostics": { 130 | "enabled": true 131 | } 132 | } 133 | }, 134 | "resources": [ 135 | { 136 | "type": "Extensions", 137 | "apiVersion": "2019-03-01", 138 | "name": "config-app", 139 | "location": "[parameters('location')]", 140 | "dependsOn": [ 141 | "[parameters('virtualMachineName')]" 142 | ], 143 | "properties": { 144 | "publisher": "Microsoft.Azure.Extensions", 145 | "type": "CustomScript", 146 | "typeHandlerVersion": "2.1", 147 | "autoUpgradeMinorVersion": true, 148 | "protectedSettings": { 149 | "commandToExecute": "git clone https://github.com/Azure/azure-vmware-solution /root/azure-vmware-solution && sudo /root/azure-vmware-solution/advanced-monitoring/Worker/install.sh" 150 | } 151 | } 152 | } 153 | ] 154 | }, 155 | { 156 | "type": "Microsoft.Resources/deployments", 157 | "apiVersion": "2019-09-01", 158 | "name": "assignRolesToPrivateCloud", 159 | "dependsOn": [ 160 | "[parameters('virtualMachineName')]" 161 | ], 162 | "resourceGroup" : "[split(parameters('privateCloudId'), '/')[4]]", 163 | "properties": { 164 | "mode": "Incremental", 165 | "template": { 166 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 167 | "contentVersion": "1.0.0.0", 168 | "resources": [ 169 | { 170 | "type": "Microsoft.Authorization/roleAssignments", 171 | "apiVersion": "2020-04-01-preview", 172 | "name": "[guid(parameters('privateCloudId'),'b24988ac-6180-42a0-ab88-20f7382dd24c')]", 173 | "properties": { 174 | //contributor 175 | "roleDefinitionId": "[concat(parameters('privateCloudId'), '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c')]", 176 | "principalId": "[reference(parameters('virtualMachineName'), '2022-03-01', 'Full').identity.principalId]", 177 | "principalType": "ServicePrincipal" 178 | }, 179 | "scope": "[parameters('privateCloudId')]" 180 | }, 181 | { 182 | "type": "Microsoft.Authorization/roleAssignments", 183 | "apiVersion": "2020-04-01-preview", 184 | "name": "[guid(parameters('privateCloudId'),'3913510d-42f4-4e42-8a64-420c390055eb')]", 185 | "properties": { 186 | //metrics publisher 187 | "roleDefinitionId": "[concat(parameters('privateCloudId'), '/providers/Microsoft.Authorization/roleDefinitions/3913510d-42f4-4e42-8a64-420c390055eb')]", 188 | "principalId": "[reference(parameters('virtualMachineName'), '2022-03-01', 'Full').identity.principalId]", 189 | "principalType": "ServicePrincipal" 190 | }, 191 | "scope": "[parameters('privateCloudId')]" 192 | } 193 | ] 194 | } 195 | } 196 | } 197 | ], 198 | "outputs": { 199 | "adminUsername": { 200 | "type": "string", 201 | "value": "[parameters('adminUsername')]" 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /advanced-monitoring/README.md: -------------------------------------------------------------------------------- 1 | # Azure VMware Solution Advanced Monitoring 2 | 3 | ## Overview 4 | 5 | The Azure VMware Solution metrics available in the Azure portal contains standard metrics. By using the solution provided in this repository customers can extend the metrics collected to include more advanced vSphere metrics as well as NSX-T Data Center Edge and Tier-0 Gateway metrics. This solution deploys a virtual machine in Azure with a managed identity that has contributor and metrics publisher access to the private cloud object. 6 | 7 | ![](./media/overview.PNG) 8 | 9 | This solution has been peer reviewed but is best-effort and should be assessed and tested by the customer before using in an Azure VMware Solution production environment. 10 | 11 | ## Considerations 12 | 13 | ### Deployment 14 | 15 | The solution deployment requires that you select an existing vNet with network access to the vCenter Server and NSX-T Manager of an existing Azure VMware Solution Private Cloud. A new vNet cannot be created during the deployment of this solution because the new vNet would not have a connection to the private cloud. The default virtual machine sized deployed is Standard_DS1_v2, this virtual machine can be scaled if additional resources are required due to increased monitoring load. There is a 1:1 relationship between monitoring virtual machines and a private cloud. The virtual machine will need access to the internet to install the required Ubuntu packages, GitHub to download additional packages, and the Azure monitoring public endpoints. 16 | 17 | ### Cost 18 | 19 | The solution will deploy an Ubunutu 22.04 virtual machine of size Standard_DS1_v2. This is an additional cost that the customer subscription will be billed for. This virtual machine will also consume network traffic for both collection metrics as well as publishing metrics. The amount of traffic will vary based on the size of the private cloud as well as number of objects deployed in the private cloud. Custom metrics also incur a cost. The costs associated with Azure Monitor are available here [Azure Monitor](https://azure.microsoft.com/en-us/pricing/details/monitor/). 20 | 21 | ## Deployment 22 | 23 | ### Option 1 - ARM Template with UI 24 | 25 | The deployment of the solution can be done automatically via a custom template gui by following this link: 26 | 27 | [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-vmware-solution%2Fmain%2Fadvanced-monitoring%2FDeployment%2Ftemplate.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-vmware-solution%2Fmain%2Fadvanced-monitoring%2FDeployment%2FcreateUiDefinition.json) 28 | 29 | Follow the deployment wizard 30 | - Enter the deployment basic info 31 | 32 | ![](./media/template_1.png) 33 | 34 | - Select the private cloud 35 | 36 | ![](./media/template_2.png) 37 | 38 | - Select an existing vnet that has connectivity to the private cloud 39 | 40 | ![](./media/template_3.png) 41 | 42 | - Enter the virtual machine details 43 | 44 | ![](./media/template_4.png) 45 | 46 | - Complete the deployment 47 | 48 | ![](./media/template_5.png) 49 | 50 | The ARM template for deployment is located here: [template.json](./Deployment/template.json) 51 | 52 | ### Option 2 - Manual 53 | 54 | The solution can be deployed manually as well: 55 | 56 | There are two installation scripts for Ubuntu and RHEL-based distributionns. 57 | 58 | - For Ubuntu create an Ubuntu 22.04 virtual machine connected to a vNet that has access to the private cloud. 59 | - For RHEL-based distributions create a Red Hat Enterprise Linux 9 or a Rocky Linux 9 vritual machine, conencted to a vNet with access to the private cloud. 60 | - Configure an identity on the virtual machine either System or User managed 61 | ![](./media/assign_identity.png) 62 | 63 | - Grant the identity the Contributor and Metrics Publisher roles on the private cloud 64 | ![](./media//assign_identity_private_cloud.png) 65 | 66 | - Configure the User Data on the virtual machine as AVS_CLOUD_ID=\ 67 | The format of the resource ID is `/subscriptions//resourceGroups//providers/Microsoft.AVS/privateClouds/` 68 | ![](./media/assign_userdata.png) 69 | 70 | - Install the software on the virtual machine. The installation scripts must be executed as `root` user or with `sudo`. 71 | - Ubuntu: 72 | - `git clone https://github.com/Azure/azure-vmware-solution` 73 | - `cd azure-vmware-solution/advanced-monitoring/Worker/` 74 | - `./install.sh` 75 | - RHEL: 76 | - `git clone https://github.com/Azure/azure-vmware-solution` 77 | - `cd azure-vmware-solution/advanced-monitoring/Worker/` 78 | - `./install_rhel.sh` 79 | - Check status 80 | - `systemctl status nsx-stat` 81 | - `systemctl status telegraf` 82 | 83 | The services should be running 84 | 85 | ## Viewing Metrics 86 | 87 | The metrics will appear on the private cloud object under the metrics tab under the telegraf namespace. The vSphere metrics will be listed as vsphere_* and the NSX-T Data Center metrics will appear under tnt##: 88 | - vSphere Metrics 89 | 90 | ![](./media/extended_metrics.png) 91 | 92 | These metrics are listed at [README.md](https://github.com/influxdata/telegraf/blob/master/plugins/inputs/vsphere/METRICS.md) 93 | 94 | - NSX-T Data Center Metrics 95 | 96 | ![](./media/nsx_base_metrics.PNG) 97 | 98 | Splitting may be applied to some metrics to gain more detailed insight: 99 | - Per VM CPU usage 100 | 101 | ![](./media/pervm_cpu_usage.png) 102 | 103 | NSX-T Data Center Edge VM metrics are under the EVM## metric. 104 | - Edge VM per core CPU usage 105 | 106 | ![](./media/evm_pervm_cpu_usage.png) 107 | 108 | - Edge Tier-0 Interfaces are tied to specific edge VMs. The interfaces are listed in metrics under T0-Priv0#. Each edge VM has two interfaces Priv01 and Priv03 are attached to EVM01. Interface Priv02 and Priv04 are attached to EVM02. 109 | 110 | ![](./media/nsx_t0_priv01_bytes.PNG) 111 | -------------------------------------------------------------------------------- /advanced-monitoring/Worker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | ADD * /root/ 3 | RUN /root/install.sh -p /opt/nsx-stat 4 | CMD ["/root/loop.sh"] -------------------------------------------------------------------------------- /advanced-monitoring/Worker/crontab: -------------------------------------------------------------------------------- 1 | 59 23 * * * rm -f /##WORKINGDIR##/*.csv 2 | -------------------------------------------------------------------------------- /advanced-monitoring/Worker/get_cloud_info.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | from azure.mgmt.avs import AVSClient 4 | from azure.identity import DefaultAzureCredential 5 | from azure.identity import ChainedTokenCredential,ManagedIdentityCredential 6 | 7 | try: 8 | MSI_credential = ManagedIdentityCredential(client_id=os.environ['client_id']) 9 | except: 10 | MSI_credential = DefaultAzureCredential() 11 | credential = ChainedTokenCredential(MSI_credential) 12 | resource_id = os.environ['AVS_CLOUD_ID'] 13 | subscription_id = resource_id[15:resource_id[15:].find("/")+15] 14 | avs_client = AVSClient(credential, subscription_id) 15 | resource_group_name = resource_id[resource_id.find("resourceGroups/")+15:resource_id.find("/",resource_id.find("resourceGroups/")+15)] 16 | private_cloud_name = resource_id[resource_id.find("privateClouds/")+14:] 17 | #get cloud object 18 | cloud = avs_client.private_clouds.get(resource_group_name=resource_group_name,private_cloud_name=private_cloud_name) 19 | #colllect more info 20 | region_id = cloud.location 21 | cloud_credentials = avs_client.private_clouds.list_admin_credentials(resource_group_name, cloud.name) 22 | if (sys.argv[1] == "user"): 23 | print(cloud_credentials.vcenter_username) 24 | if (sys.argv[1] == "pass"): 25 | print(cloud_credentials.vcenter_password) 26 | if (sys.argv[1] == "ip"): 27 | print(cloud.endpoints.vcsa) 28 | if (sys.argv[1] == "region"): 29 | print(region_id) 30 | -------------------------------------------------------------------------------- /advanced-monitoring/Worker/get_info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ##WORKINGDIR##/venv/bin/activate 3 | python3 ##WORKINGDIR##/get_cloud_info.py $1 4 | #env $(cat .env | xargs) python3 main.py -------------------------------------------------------------------------------- /advanced-monitoring/Worker/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export `curl -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/compute/userData?api-version=2021-01-01&format=text" | base64 --decode` 3 | if [[ -z ${AVS_CLOUD_ID+x} ]]; then 4 | while getopts ":p:c:" opt; do 5 | case $opt in 6 | p) install_path="$OPTARG" 7 | ;; 8 | c) cloud_id="$OPTARG" 9 | ;; 10 | \?) echo "Invalid option -$OPTARG" >&2 11 | exit 1 12 | ;; 13 | esac 14 | 15 | case $OPTARG in 16 | -*) echo "Option $opt needs a valid argument" 17 | exit 1 18 | ;; 19 | esac 20 | done 21 | else 22 | export install_path=/opt/nsx-stat 23 | export cloud_id=$AVS_CLOUD_ID 24 | fi 25 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 26 | echo Installing to $install_path 27 | echo Cloud $cloud_id 28 | export DEBIAN_FRONTEND=noninteractive 29 | apt-get update 30 | apt install wget 31 | wget -qO- https://repos.influxdata.com/influxdb.key | tee /etc/apt/trusted.gpg.d/influxdb.asc >/dev/null 32 | source /etc/os-release && echo "deb https://repos.influxdata.com/${ID} ${VERSION_CODENAME} stable" | tee /etc/apt/sources.list.d/influxdb.list 33 | apt-get update 34 | apt-get install python3-pip python3-venv telegraf -y 35 | #install 1.25 via dpkg because 1.21 has a bug that causes the telegraf service to fail 36 | wget https://dl.influxdata.com/telegraf/releases/telegraf_1.25.0-1_amd64.deb 37 | dpkg -i telegraf_1.25.0-1_amd64.deb 38 | service telegraf stop 39 | systemctl disable telegraf.service 40 | mkdir $install_path 41 | cd $SCRIPT_DIR 42 | cp main.py $install_path 43 | cp requirements.txt $install_path 44 | cp telegraf.conf $install_path 45 | cp nsx-stat.service $install_path 46 | cp start.sh $install_path 47 | cp get_cloud_info.py $install_path 48 | cp get_info.sh $install_path 49 | cp crontab $install_path 50 | chmod +x $install_path/start.sh 51 | cd $install_path 52 | sed -i "s~##WORKINGDIR##~$install_path~" $install_path/get_info.sh 53 | chmod +x $install_path/get_info.sh 54 | python3 -m venv venv 55 | source ./venv/bin/activate 56 | python3 -m pip install -r requirements.txt 57 | sed -i "s~##WORKINGDIR##~$install_path~" nsx-stat.service 58 | sed -i "s~##CLOUDID##~$cloud_id~" nsx-stat.service 59 | cp nsx-stat.service /etc/systemd/system/ 60 | systemctl daemon-reload 61 | sed -i "s~/##WORKINGDIR##~$install_path~" $install_path/telegraf.conf 62 | sed -i "s~/##WORKINGDIR##~$install_path~" $install_path/crontab 63 | crontab crontab 64 | cp $install_path/telegraf.conf /etc/telegraf/ 65 | systemctl enable nsx-stat.service 66 | systemctl start nsx-stat 67 | -------------------------------------------------------------------------------- /advanced-monitoring/Worker/install_rhel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Installation script gor RHEL-based systems 4 | # 5 | export `curl -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/compute/userData?api-version=2021-01-01&format=text" | base64 --decode` 6 | if [[ -z ${AVS_CLOUD_ID+x} ]]; then 7 | while getopts ":p:c:" opt; do 8 | case $opt in 9 | p) install_path="$OPTARG" 10 | ;; 11 | c) cloud_id="$OPTARG" 12 | ;; 13 | \?) echo "Invalid option -$OPTARG" >&2 14 | exit 1 15 | ;; 16 | esac 17 | 18 | case $OPTARG in 19 | -*) echo "Option $opt needs a valid argument" 20 | exit 1 21 | ;; 22 | esac 23 | done 24 | else 25 | export install_path=/opt/nsx-stat 26 | export cloud_id=$AVS_CLOUD_ID 27 | fi 28 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 29 | echo Installing to $install_path 30 | echo Cloud $cloud_id 31 | dnf install -y wget 32 | # Install Telegraf and InfluxDB 33 | cat <". 51 | # namespace_prefix = "Telegraf/" 52 | 53 | ## Azure Monitor doesn't have a string value type, so convert string 54 | ## fields to dimensions (a.k.a. tags) if enabled. Azure Monitor allows 55 | ## a maximum of 10 dimensions so Telegraf will only send the first 10 56 | ## alphanumeric dimensions. 57 | # strings_as_dimensions = false 58 | 59 | ## Both region and resource_id must be set or be available via the 60 | ## Instance Metadata service on Azure Virtual Machines. 61 | # 62 | ## Azure Region to publish metrics against. 63 | ## ex: region = "southcentralus" 64 | region = "${REGION}" 65 | # 66 | ## The Azure Resource ID against which metric will be logged, e.g. 67 | ## ex: resource_id = "/subscriptions//resourceGroups//providers/Microsoft.Compute/virtualMachines/" 68 | resource_id = "${AVS_CLOUD_ID}" 69 | 70 | ## Optionally, if in Azure US Government, China, or other sovereign 71 | ## cloud environment, set the appropriate REST endpoint for receiving 72 | ## metrics. (Note: region may be unused in this context) 73 | # endpoint_url = "https://monitoring.core.usgovcloudapi.net" 74 | -------------------------------------------------------------------------------- /advanced-monitoring/media/assign_identity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/assign_identity.png -------------------------------------------------------------------------------- /advanced-monitoring/media/assign_identity_private_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/assign_identity_private_cloud.png -------------------------------------------------------------------------------- /advanced-monitoring/media/assign_userdata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/assign_userdata.png -------------------------------------------------------------------------------- /advanced-monitoring/media/evm_pervm_cpu_usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/evm_pervm_cpu_usage.png -------------------------------------------------------------------------------- /advanced-monitoring/media/extended_metrics.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/extended_metrics.PNG -------------------------------------------------------------------------------- /advanced-monitoring/media/nsx_base_metrics.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/nsx_base_metrics.PNG -------------------------------------------------------------------------------- /advanced-monitoring/media/nsx_t0_priv01_bytes.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/nsx_t0_priv01_bytes.PNG -------------------------------------------------------------------------------- /advanced-monitoring/media/overview.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/overview.PNG -------------------------------------------------------------------------------- /advanced-monitoring/media/pervm_cpu_usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/pervm_cpu_usage.png -------------------------------------------------------------------------------- /advanced-monitoring/media/template_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/template_1.png -------------------------------------------------------------------------------- /advanced-monitoring/media/template_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/template_2.png -------------------------------------------------------------------------------- /advanced-monitoring/media/template_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/template_3.png -------------------------------------------------------------------------------- /advanced-monitoring/media/template_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/template_4.png -------------------------------------------------------------------------------- /advanced-monitoring/media/template_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/advanced-monitoring/media/template_5.png -------------------------------------------------------------------------------- /avs-autoscale/README.md: -------------------------------------------------------------------------------- 1 | # Azure VMware Solution Auto-Scale 2 | 3 | ## Overview 4 | 5 | This Auto-Scale function allows a customer to scale their Azure VMware Solution automatically to cost effectively meet their performance goals. 6 | 7 | The Azure VMware Solution has Azure Metrics for the percentage usage of cluster CPU, memory, and storage resources. These metrics are incorporated into Azure Alerts with thresholds for high-water mark and low-water mark values to trigger a call to an Azure Automation PowerShell Runbook via a Webhook which triggers the auto-scale event within the Azure VMware Solution private cloud. 8 | 9 | ![](./media/image1.png) 10 | 11 | This solution has been peer reviewed but is best-effort and should be assessed and tested by the customer before using in an Azure VMware Solution production environment. 12 | 13 | ## Operational Considerations 14 | 15 | When Alert Rules are defined within the Azure VMware Solution, they are fired when the defined threshold is met, and the auto-scale PowerShell Runbook is executed. Once the auto-scale event has completed, the Alert condition will resolve once the Alert threshold is no longer breached and the Alert Rule will be ready to be fired again. 16 | 17 | In addition, the cloud operations team can track the Alert lifecycle by setting the User response of Acknowledged or Closed. An automated email can also be sent to the cloud operations team each time an Alert is triggered for additional tracking. 18 | 19 | The scale-out node add time is approximately 30min and scale-in node remove time is approximately 45min. The Azure VMware Solution private clouds and Azure Automation Accounts need to be configured within the same subscription. This mechanism supports standard and stretched clusters and supports the maximum number of clusters of Azure VMware Solution (12). 20 | 21 | ![](./media/image2.png) 22 | 23 | ![](./media/image3.png) 24 | 25 | As cluster resources change, IT operations need to manually update the auto-scale alert rule percentages as per the tables below to match the node count for used CPU, memory and storage. These percentages also reflect the resource thresholds enforced by VMware vSphere HA Admission Control for cluster CPU and Memory resources. 26 | 27 | Azure VMware Solution Standard Cluster high-water and low-water marks for auto-scale alerts. 28 | 29 | ![](./media/image4.png) 30 | 31 | Azure VMware Solution Stretched Cluster high-water and low-water marks for auto-scale alerts. 32 | 33 | ![](./media/image5.png) 34 | 35 | Note: the percentages change as the number of nodes change. 36 | 37 | There should be a minimum one or two node (standard/stretched cluster respectively) steady-state percentage gap between the scale out alert high-water mark and the scale in alert low water mark values to avoid auto-scale flapping. 38 | 39 | ![](./media/image6.png) 40 | 41 | For each cluster, the CPU, memory, and storage alert monitors should be stacked within the same alert rule. Multiple clusters should not be aggregated into the same alert rule, because the alert threshold for a second cluster will not be detected when the alert is fired for the initial cluster, it would have to wait until the alert was cleared before being fired again for the second cluster. There would also be an imbalance of alert threshold percentages when the aggregate clusters have different node counts. 42 | 43 | ![](./media/image7.png) 44 | 45 | The alert timelines should use larger values (Aggregation Period 6, 12 or 24 hours, Frequency of Evaluation every 30 minutes or every hour) to provide the most consistent experience and avoid reacting to short term trends. During periods of planned migrations and major resource changes, alerts should be disabled to avoid auto-scale flapping. 46 | 47 | To reduce unnecessary alerts, the scale-in alert should be disabled when the node count is 3 or 6 (cluster minimum limit standard/stretched cluster respectively) and the scale-out alert should be disabled when the node count is 16 (cluster maximum limit). When an auto-scale event is executed that violates the Azure VMware Solution limits, the PowerShell Runbook will report a Failed state. 48 | 49 | Depending upon the customer perceived severity of an auto-scale event, the scale-in and scale-out alert severity should be selected from the Verbose, Informational, Warning, Error or Critical classifications. 50 | 51 | ## How-to Guide 52 | 53 | ### Step 1: Create an Azure Automation Account within the same Azure Subscription as the Azure VMware Solution private cloud. 54 | 55 | 1. In the Basics tab, select the Azure Subscription, Azure Resource Group, Azure Region and enter the Automation account name. 56 | 57 | ![](./media/image8.png) 58 | 59 | 2. In the Advanced tab, select the System Assigned Managed Identities checkbox. 60 | 61 | ![](./media/image9.png) 62 | 63 | 3. In the Networking tab, select the Public access Connectivity configuration if your corporate security policies allow it. Otherwise select Private access (Private endpoint needed). 64 | 65 | ![](./media/image10.png) 66 | 67 | 4. In the Tags tab, configure any needed tags. 68 | 69 | ![](./media/image11.png) 70 | 71 | 5. In the Review & Create tab, validate the configuration and create the Azure Automation Account. 72 | 73 | ![](./media/image12.png) 74 | 75 | ### Step 2: Create the Scale-Out and Scale-In PowerShell Runbooks within the Azure Automation Account. 76 | 77 | 1. Delete the sample Azure Automation Runbooks, they are not needed for this procedure. 78 | 79 | ![](./media/image13.png) 80 | 81 | 2. Select the Create Runbook icon. 82 | 83 | ![](./media/image13.png) 84 | 85 | 3. In the Create Runbook window, give the Runbook a meaningful name. e.g. "Avs-Scale-Out-PS-Runbook". Select the PowerShell Runbook type, the 5.1 Runtime version and provide a meaningful description. 86 | 87 | ![](./media/image14.png) 88 | 89 | 4. In the Edit PowerShell Runbook window, copy the [Scale-Out PowerShell Runbook code from the code repository](https://github.com/Azure/azure-vmware-solution/blob/main/avs-autoscale/code/autoscale-out-runbook.ps1) into the main code screen without modification. Then select Save and Publish. 90 | 91 | ![](./media/image15.png) 92 | 93 | 5. In the Scale-Out Runbook screen, select the Webhooks object and then select Add Webhook. 94 | 95 | ![](./media/image16.png) 96 | 97 | 6. In the Add Webhook window, select the Create new webhook object. 98 | 99 | ![](./media/image17.png) 100 | 101 | 7. In the Create a new webhook screen, give the Webhook a meaningful name, set Enabled to Yes, set an Expiry date that complies with your corporate security policy and copy the URL to a secure document (this will be needed when configuring the Azure VMware Solution Scale-Out Alert). Select the OK button. 102 | 103 | ![](./media/image18.png) 104 | 105 | 8. In the Add Webhook window, select Configure parameters and run settings object. 106 | 107 | ![](./media/image17.png) 108 | 109 | 9. In the Parameters screen, make no changes and select the OK button. 110 | 111 | ![](./media/image19.png) 112 | 113 | 10. In the Add Webhook window, select the Create button. 114 | 115 | ![](./media/image20.png) 116 | 117 | 11. Repeat tasks 1 to 10 for the [Scale-In PowerShell Runbook](https://github.com/Azure/azure-vmware-solution/blob/main/avs-autoscale/code/autoscale-in-runbook.ps1). 118 | 119 | ### Step 3: Add Azure VMware Solution (Az.VMware) PowerShell Module to the Azure Automation Account. 120 | 121 | 1. In the Automation Account window, select the Modules object and then select the Add a module button. 122 | 123 | ![](./media/image21.png) 124 | 125 | 2. In the Add a Module screen, Browse from the Gallery for the Az.VMware PowerShell Module and select the 5.1 Runtime version. Select the Import button. 126 | 127 | Note: The Az.VMware module has a dependency on Az.Accounts. If Az.Accounts has not previously been added to an Azure Automation Account in your subscription, you will need to add that module first and allow a few minutes for the import to complete before adding the Az.VMware module. 128 | 129 | ![](./media/image22.png) 130 | 131 | ### Step 4: Add Runas Service Account to the Azure Automation Account. 132 | 133 | 1. In the Automation Account window, select the Run as accounts object and then select the Create Azure Run as Account button. Then select the Create button. 134 | 135 | ![](./media/image23.png) 136 | 137 | ![](./media/image24.png) 138 | 139 | ### Step 5: Add Scale-Out and Scale-In Alert Action Groups to Azure VMware Solution. 140 | 141 | 1. In the Azure VMware Solution Alerts window, select the Alerts object and then select the Action Group button. 142 | 143 | ![](./media/image25.png) 144 | 145 | 2. In the Action Groups window, select the Create button. 146 | 147 | ![](./media/image26.png) 148 | 149 | 3. In the Basics tab, select the Azure Subscription, Azure Resource Group, Azure Region and enter the Action group name and Display name. e.g. avs-autoscale-out-ag and AvsScaleOut. 150 | 151 | ![](./media/image27.png) 152 | 153 | 4. In the Notifications tab, select the Email/SMS message/Push/Voice Notification type and enter a Name e.g. emailtoITOperations. 154 | 155 | ![](./media/image28.png) 156 | 157 | 5. Then click the Selected edit button and tick the Email box in the Email/SMS message/Push/Voice edit screen. Then enter the appropriate IT Operations email address for alert notifications to be sent to. Then select Yes for the Enable common alert schema. Then select OK. 158 | 159 | ![](./media/image28.png) 160 | 161 | 6. In the Actions tab, select the Webhook Action type and enter a Name e.g. avs-scale-out-webhook. 162 | 163 | ![](./media/image29.png) 164 | 165 | 7. Then click the Selected edit button and paste the Scale-Out webhook URI saved earlier. Then select Yes for the Enable common alert schema. Then select OK. 166 | 167 | ![](./media/image30.png) 168 | 169 | 8. In the Tags tab, configure any needed tags. 170 | 171 | ![](./media/image31.png) 172 | 173 | 9. In the Review & Create tab, validate the configuration and create the Azure VMware Solution Alert Action Group. 174 | 175 | ![](./media/image32.png) 176 | 177 | 10. Repeat tasks 1 to 9 for the Scale-In Azure VMware Solution Alert Action Group. 178 | 179 | ### Step 6: Add Scale-Out and Scale-In Alert Rules to Azure VMware Solution for each cluster. 180 | 181 | 1. In the Azure VMware Solution Alerts window, select the Create alert rule button. 182 | 183 | ![](./media/image33.png) 184 | 185 | 2. In the Condition tab, select Percentage Datastore Disk Used, Percentage CPU or Average Memory Usage Signal from the Signal name list. These three are the only signal metrics that support percentage used values. 186 | 187 | ![](./media/image34.png) 188 | 189 | 3. Select the Datastore or Cluster name from the Dimension name. Leave the Operator as = and then select the vsanDatastore# or Cluster-# from the Dimension values list. Only select a single cluster for each signal. 190 | 191 | 4. In the Alert logic section, select the Static Threshold, Average Aggregation type, Greater than Operator and a Threshold value that matches the cluster type and node count for the Scale-Out high-water mark. 192 | 193 | 5. In the Evaluation frequency section, select Check every 30 minutes or 1 hour and Look at data from the last 6 hours, 12 hours or 24 hours. 194 | 195 | 6. If you want to trigger on multiple signals (CPU, memory and storage), then select the Add condition button and repeat tasks 2 to 5 until the desired signals are configured. 196 | 197 | ![](./media/image35.png) 198 | 199 | 7. In the Actions tab, press the Select action groups button. 200 | 201 | 8. From the Select action groups screen, select the Subscription and then tick the Scale-Out Action Group name box. Press the Select button. 202 | 203 | ![](./media/image36.png) 204 | 205 | 9. In the Details tab, select the Azure Subscription, Azure Resource Group, Alert Rule Severity and enter the Alert rule name and description. e.g. avs-autoscale-out-cluster-1-alert-rule. 206 | 207 | ![](./media/image37.png) 208 | 209 | 10. In the Tags tab, configure any needed tags. 210 | 211 | ![](./media/image38.png) 212 | 213 | 11. In the Review & Create tab, validate the configuration and create the Azure VMware Solution Alert Rule. 214 | 215 | ![](./media/image39.png) 216 | 217 | 12. Repeat tasks 1 to 11 for the Scale-In Azure VMware Solution Alert. 218 | 219 | 13. Repeat tasks 1 to 12 for each cluster. 220 | 221 | ## Troubleshooting 222 | 223 | Step 7: Troubleshooting Azure Automation PowerShell Runbook Jobs. 224 | 225 | 1. In the Runbook window, select the Logging and tracking object and turn Log verbose records and Log progress records to On. 226 | 227 | ![](./media/image40.png) 228 | 229 | 2. In the Runbook window, select the Jobs object and select specific Job to investigate. Then select the All Logs tab and scroll through the complete log. 230 | 231 | ![](./media/image41.png) 232 | 233 | ![](./media/image42.png) 234 | 235 | ## Testing 236 | 237 | During testing, there may not be time to wait for the Alert to resolve and be ready to fire again. If this occurs, delete the fired alert rule and recreate. 238 | -------------------------------------------------------------------------------- /avs-autoscale/code/autoscale-in-runbook.ps1: -------------------------------------------------------------------------------- 1 | # Title: Azure VMware Solution Private Cloud Cluster Auto-scale Scale-In PowerShell Runbook 2 | 3 | # Purpose: Azure Automation PowerShell Runbook for the scale-in of an Azure VMware Solution management or resource cluster. 4 | 5 | [OutputType("PSAzureOperationResponse")] 6 | param ( 7 | [Parameter (Mandatory=$false)] 8 | [object] $WebhookData 9 | ) 10 | $ErrorActionPreference = "stop" 11 | 12 | # Minimum number of nodes in allowed to scale up to in the cluster 13 | # This is set to 5 for the purpose of this example. The minimum number of nodes in a cluster is 3. 14 | $minnodes = 5 15 | 16 | # Array of datastore names in storage alert used to map to clustername 17 | $vsandatastorename = 'vsanDatastore (1)','vsanDatastore (2)','vsanDatastore (3)','vsanDatastore (4)','vsanDatastore (5)','vsanDatastore (6)','vsanDatastore (7)','vsanDatastore (8)','vsanDatastore (9)','vsanDatastore (10)','vsanDatastore (11)' 18 | 19 | if ($WebhookData) { 20 | # Get the data object from WebhookData 21 | $WebhookBody = (ConvertFrom-Json -InputObject $WebhookData.RequestBody) 22 | 23 | # Get the info needed to identify the AVS Private Cloud (AVS alerts use "azureMonitorCommonAlertSchema") 24 | $schemaId = $WebhookBody.schemaId 25 | Write-Verbose "schemaId: $schemaId" -Verbose 26 | if ($schemaId -eq "azureMonitorCommonAlertSchema") { 27 | # This is the common Metric Alert schema (released March 2019) 28 | $Essentials = [object] ($WebhookBody.data).essentials 29 | # Get the first target only as this script doesn't handle multiple 30 | 31 | $alertTargetIdArray = (($Essentials.alertTargetIds)[0]).Split("/") 32 | $SubId = ($alertTargetIdArray)[2] 33 | $ResourceGroupName = ($alertTargetIdArray)[4] 34 | $ResourceType = ($alertTargetIdArray)[6] + "/" + ($alertTargetIdArray)[7] 35 | $ResourceName = ($alertTargetIdArray)[-1] 36 | $status = $Essentials.monitorCondition 37 | $alertContext = [object] ($WebhookBody.data).alertContext 38 | $alertContextdimensionsName = $alertContext.condition.allOf[0].dimensions[0].name 39 | $alertContextdimensionsValue = $alertContext.condition.allOf[0].dimensions[0].value 40 | Write-Verbose "*** alertContextdimensionsName: $alertContextdimensionsName" -Verbose 41 | Write-Verbose "*** alertContextdimensionsValue: $alertContextdimensionsValue" -Verbose 42 | } 43 | else { 44 | # Schema not supported 45 | Write-Error "The alert data schema - $schemaId - is not supported." 46 | } 47 | Write-Verbose "*** status: $status" -Verbose 48 | if (($status -eq "Activated") -or ($status -eq "Fired")) { 49 | Write-Verbose "*** resourceType: $ResourceType" -Verbose 50 | Write-Verbose "*** resourceName: $ResourceName" -Verbose 51 | Write-Verbose "*** resourceGroupName: $ResourceGroupName" -Verbose 52 | Write-Verbose "*** subscriptionId: $SubId" -Verbose 53 | 54 | # Determine code path depending on the resourceType 55 | if ($ResourceType -eq "Microsoft.AVS/privateClouds") 56 | { 57 | # This is an AVS Private Cloud 58 | Write-Verbose "*** This is an AVS Private Cloud." -Verbose 59 | 60 | # Authenticate to Azure with service principal and certificate and set subscription 61 | Write-Verbose "*** Authenticating to Azure" -Verbose 62 | Connect-AzAccount -Identity -ErrorAction Stop 63 | Write-Verbose "Authentication successful." 64 | Write-Verbose "Setting subscription context to $SubId" 65 | Set-AzContext -SubscriptionId $SubId -ErrorAction Stop | Write-Verbose 66 | 67 | # Part 1 - Detect if Cluster Type is the Management Cluster (Cluster-1) or a Resource cluster (Cluster-2 -> Cluster-12) 68 | # Part 2 - Detect if the alert type is storage, cpu or ram and map to correct cluster name 69 | # This is necessary because the AVS management and resource clusters use different PowerShell commands (Get-AzVMwarePrivateCloud, Update-AzVMwarePrivateCloud, Get-AzVMwareCluster, Update-AzVMwareCluster) 70 | if (($alertContextdimensionsValue -eq "Cluster-1") -or ($alertContextdimensionsValue -eq "vsanDatastore")) { 71 | # Management Cluster (Cluster-1) detected 72 | $ClusterTypeManagement = $true 73 | $ClusterName = "Cluster-1" 74 | Write-Verbose "*** Management ($ClusterName) detected" -Verbose 75 | } 76 | else { 77 | # Resource Cluster (Cluster-2 -> Cluster-12) detected 78 | $ClusterTypeManagement = $false 79 | Write-Verbose "*** Resource Cluster (Cluster-2 -> Cluster-12) detected" -Verbose 80 | if ($alertContextdimensionsName -eq "clustername") { 81 | # CPU or RAM alert detected, use existing $alertContextdimensionsValue, which has the correct clustername (Cluster-2 -> Cluster-12) 82 | $ClusterName = $alertContextdimensionsValue 83 | Write-Verbose "*** CPU or RAM Alert detected" -Verbose 84 | } 85 | else { 86 | # Storage alert detected, search through array for datastore name (vsanDatastore (1) -> vsanDatastore (11)) and map to clustername (Cluster-2 -> Cluster-12) 87 | for ($arrayindex = 0; $arrayindex -lt $vsandatastorename.count; $arrayindex++) { 88 | if ($alertContextdimensionsValue -eq $vsandatastorename[$arrayindex]) { 89 | $ClusterName = "Cluster-$($arrayindex+2)" 90 | Write-Verbose "*** Storage Alert detected" -Verbose 91 | Write-Verbose "*** alertContextdimensionsValue: $alertContextdimensionsValue" -Verbose 92 | } 93 | } 94 | } 95 | } 96 | Write-Verbose "*** ClusterTypeManagement: $ClusterTypeManagement" -Verbose 97 | Write-Verbose "*** ClusterName: $ClusterName" -Verbose 98 | 99 | # Get Private Cloud (includes Management Cluster: Cluster-1) Object 100 | $MgmtCluster = Get-AzVMwarePrivateCloud -SubscriptionId $SubId -ResourceGroupName $ResourceGroupName -Name $ResourceName 101 | 102 | # Get Private Cloud Provisioning State 103 | $PrivateCloudProvisioningState = $MgmtCluster.ProvisioningState 104 | 105 | # Check Private Cloud Provisioning State 106 | if ($PrivateCloudProvisioningState -eq "Succeeded") { 107 | 108 | # Cluster Size calculation for Standard or Stretched Cluster 109 | # We deliberately rely upon the Azure VMware Solution management & control plane to enforce the cluster size minimum (standard 3 nodes, stretched 6 nodes) and the cluster size maximum (16 nodes). This provides operational simplicity in maintaining this PS Runbook. 110 | 111 | # Get Availability Strategy (SingleZone or DualZone) 112 | $MgmtClusterAvailabilityType = $MgmtCluster.AvailabilityStrategy 113 | Write-Verbose "*** MgmtClusterAvailabilityType: $MgmtClusterAvailabilityType" -Verbose 114 | 115 | # Cluster Type Check, Cluster Size Calculation and Cluster Autoscale Execution 116 | if ($ClusterTypeManagement -eq $true) { 117 | # Management Cluster Size Calculation & Execution 118 | $MgmtClusterCurrentSize = $MgmtCluster.ManagementClusterSize 119 | 120 | # Check if the current size is less than or equal to the minimum nodes allowed 121 | # If so, exit the script and do not attempt to scale in the cluster 122 | if ($MgmtClusterCurrentSize -le $minnodes) { 123 | Write-Verbose "*** Management Cluster already at or below min size $minnodes. No action taken." -Verbose 124 | return 125 | } 126 | 127 | if ($MgmtClusterAvailabilityType -eq "DualZone") { 128 | # DualZone requires 1 node per Availability Zone = 2 129 | $MgmtClusterNewSize = $MgmtClusterCurrentSize - 2 130 | } 131 | elseif ($MgmtClusterAvailabilityType -eq "SingleZone") { 132 | # SingleZone requires 1 node per Availability Zone = 1 133 | $MgmtClusterNewSize = $MgmtClusterCurrentSize - 1 134 | } 135 | else { 136 | # Unknown Availability Strategy Type 137 | Write-Error "The Azure VMware Solution Availability Strategy - $MgmtClusterAvailabilityType - is not supported." 138 | } 139 | Write-Verbose "*** MgmtClusterNewSize: $MgmtClusterNewSize" -Verbose 140 | # Execute Management Cluster Autoscale Command 141 | Write-Verbose "*** Scaling PrivateCloudName: $ResourceName Management Cluster (Cluster-1) from $MgmtClusterCurrentSize nodes to $MgmtClusterNewSize nodes" -Verbose 142 | Write-Verbose "*** PrivateCloudName: $ResourceName resides in resourceGroupName: $ResourceGroupName & subscriptionId: $SubId" -Verbose 143 | Update-AzVMwarePrivateCloud -SubscriptionId $SubId -ResourceGroupName $ResourceGroupName -Name $ResourceName -ManagementClusterSize $MgmtClusterNewSize 144 | } 145 | else { 146 | # Resource Cluster Size Calculation & Execution 147 | $ResourceCluster = Get-AzVMwareCluster -SubscriptionId $SubId -ResourceGroupName $ResourceGroupName -PrivateCloudName $ResourceName -Name $ClusterName 148 | $ResourceClusterCurrentSize = $ResourceCluster.Size 149 | 150 | # Check if the current size is less than or equal to the minimum nodes allowed 151 | # If so, exit the script and do not attempt to scale in the cluster 152 | if ($ResourceClusterCurrentSize -le $minnodes) { 153 | Write-Verbose "*** Resource Cluster already at or below min size $minnodes. No action taken." -Verbose 154 | return 155 | } 156 | 157 | if ($MgmtClusterAvailabilityType -eq "DualZone") { 158 | # DualZone requires 1 node per Availability Zone = 2 159 | $ResourceClusterNewSize = $ResourceClusterCurrentSize - 2 160 | } 161 | elseif ($MgmtClusterAvailabilityType -eq "SingleZone") { 162 | # SingleZone requires 1 node per Availability Zone = 1 163 | $ResourceClusterNewSize = $ResourceClusterCurrentSize - 1 164 | } 165 | else { 166 | # Unknown Availability Strategy Type 167 | Write-Error "The Azure VMware Solution Availability Strategy - $MgmtClusterAvailabilityType - is not supported." 168 | } 169 | Write-Verbose "*** ResourceClusterNewSize: $ResourceClusterNewSize" -Verbose 170 | # Execute Resource Cluster Autoscale Command 171 | Write-Verbose "*** Scaling PrivateCloudName: $ResourceName Resource Cluster $ClusterName from $ResourceClusterCurrentSize nodes to $ResourceClusterNewSize nodes" -Verbose 172 | Write-Verbose "*** PrivateCloudName: $ResourceName resides in resourceGroupName: $ResourceGroupName & subscriptionId: $SubId" -Verbose 173 | Update-AzVMwareCluster -SubscriptionId $SubId -ResourceGroupName $ResourceGroupName -PrivateCloudName $ResourceName -Name $ClusterName -ClusterSize $ResourceClusterNewSize 174 | } 175 | } 176 | else { 177 | # SDDC Provisioning State is not Succeeded 178 | Write-Error "The Azure VMware Solution Private Cloud: $ResourceName provisioning state: $PrivateCloudProvisioningState is not in Succeeded state." 179 | } 180 | # [OutputType(PSAzureOperationResponse")] 181 | } 182 | else { 183 | # ResourceType not supported 184 | Write-Error "$ResourceType is not a supported resource type for this runbook." 185 | } 186 | } 187 | else { 188 | # The alert status was not 'Activated' or 'Fired' so no action taken 189 | Write-Verbose ("*** No action taken. Alert status: " + $status) -Verbose 190 | } 191 | } 192 | else { 193 | # Error 194 | Write-Error "This runbook is meant to be started from an Azure alert webhook only." 195 | } 196 | -------------------------------------------------------------------------------- /avs-autoscale/code/autoscale-out-runbook.ps1: -------------------------------------------------------------------------------- 1 | # Title: Azure VMware Solution Private Cloud Cluster Auto-scale Scale-Out PowerShell Runbook 2 | 3 | # Purpose: Azure Automation PowerShell Runbook for the scale-out of an Azure VMware Solution management or resource cluster. 4 | 5 | [OutputType("PSAzureOperationResponse")] 6 | param ( 7 | [Parameter (Mandatory=$false)] 8 | [object] $WebhookData 9 | ) 10 | $ErrorActionPreference = "stop" 11 | 12 | # Maximum number of nodes in allowed to scale up to in the cluster 13 | # This is set to 5 for the purpose of this example. The maximum number of nodes in a cluster is 16. 14 | $maxnodes = 5 15 | 16 | # Array of datastore names in storage alert used to map to clustername 17 | $vsandatastorename = 'vsanDatastore (1)','vsanDatastore (2)','vsanDatastore (3)','vsanDatastore (4)','vsanDatastore (5)','vsanDatastore (6)','vsanDatastore (7)','vsanDatastore (8)','vsanDatastore (9)','vsanDatastore (10)','vsanDatastore (11)' 18 | 19 | if ($WebhookData) { 20 | # Get the data object from WebhookData 21 | $WebhookBody = (ConvertFrom-Json -InputObject $WebhookData.RequestBody) 22 | 23 | # Get the info needed to identify the AVS Private Cloud (AVS alerts use "azureMonitorCommonAlertSchema") 24 | $schemaId = $WebhookBody.schemaId 25 | Write-Verbose "schemaId: $schemaId" -Verbose 26 | if ($schemaId -eq "azureMonitorCommonAlertSchema") { 27 | # This is the common Metric Alert schema (released March 2019) 28 | $Essentials = [object] ($WebhookBody.data).essentials 29 | # Get the first target only as this script doesn't handle multiple 30 | 31 | $alertTargetIdArray = (($Essentials.alertTargetIds)[0]).Split("/") 32 | $SubId = ($alertTargetIdArray)[2] 33 | $ResourceGroupName = ($alertTargetIdArray)[4] 34 | $ResourceType = ($alertTargetIdArray)[6] + "/" + ($alertTargetIdArray)[7] 35 | $ResourceName = ($alertTargetIdArray)[-1] 36 | $status = $Essentials.monitorCondition 37 | $alertContext = [object] ($WebhookBody.data).alertContext 38 | $alertContextdimensionsName = $alertContext.condition.allOf[0].dimensions[0].name 39 | $alertContextdimensionsValue = $alertContext.condition.allOf[0].dimensions[0].value 40 | Write-Verbose "*** alertContext: $alertContext" -Verbose 41 | Write-Verbose "*** alertContextdimensionsName: $alertContextdimensionsName" -Verbose 42 | Write-Verbose "*** alertContextdimensionsValue: $alertContextdimensionsValue" -Verbose 43 | } 44 | else { 45 | # Schema not supported 46 | Write-Error "The alert data schema - $schemaId - is not supported." 47 | } 48 | Write-Verbose "*** status: $status" -Verbose 49 | if (($status -eq "Activated") -or ($status -eq "Fired")) { 50 | Write-Verbose "*** resourceType: $ResourceType" -Verbose 51 | Write-Verbose "*** resourceName: $ResourceName" -Verbose 52 | Write-Verbose "*** resourceGroupName: $ResourceGroupName" -Verbose 53 | Write-Verbose "*** subscriptionId: $SubId" -Verbose 54 | 55 | # Determine code path depending on the resourceType 56 | if ($ResourceType -eq "Microsoft.AVS/privateClouds") 57 | { 58 | # This is an AVS Private Cloud 59 | Write-Verbose "*** This is an AVS Private Cloud." -Verbose 60 | 61 | # Authenticate to Azure with Manged identity 62 | Write-Verbose "*** Authenticating to Azure" -Verbose 63 | Connect-AzAccount -Identity -ErrorAction Stop 64 | Write-Verbose "Authentication successful." 65 | Write-Verbose "Setting subscription context to $SubId" 66 | Set-AzContext -SubscriptionId $SubId -ErrorAction Stop | Write-Verbose 67 | 68 | 69 | # Part 1 - Detect if Cluster Type is the Management Cluster (Cluster-1) or a Resource cluster (Cluster-2 -> Cluster-12) 70 | # Part 2 - Detect if the alert type is storage, cpu or ram and map to correct cluster name 71 | # This is necessary because the AVS management and resource clusters use different PowerShell commands (Get-AzVMwarePrivateCloud, Update-AzVMwarePrivateCloud, Get-AzVMwareCluster, Update-AzVMwareCluster) 72 | if (($alertContextdimensionsValue -eq "Cluster-1") -or ($alertContextdimensionsValue -eq "vsanDatastore")) { 73 | # Management Cluster (Cluster-1) detected 74 | $ClusterTypeManagement = $true 75 | $ClusterName = "Cluster-1" 76 | Write-Verbose "*** Management ($ClusterName) detected" -Verbose 77 | } 78 | else { 79 | # Resource Cluster (Cluster-2 -> Cluster-12) detected 80 | $ClusterTypeManagement = $false 81 | Write-Verbose "*** Resource Cluster (Cluster-2 -> Cluster-12) detected" -Verbose 82 | if ($alertContextdimensionsName -eq "clustername") { 83 | # CPU or RAM alert detected, use existing $alertContextdimensionsValue, which has the correct clustername (Cluster-2 -> Cluster-12) 84 | $ClusterName = $alertContextdimensionsValue 85 | Write-Verbose "*** CPU or RAM Alert detected" -Verbose 86 | } 87 | else { 88 | # Storage alert detected, search through array for datastore name (vsanDatastore (1) -> vsanDatastore (11)) and map to clustername (Cluster-2 -> Cluster-12) 89 | for ($arrayindex = 0; $arrayindex -lt $vsandatastorename.count; $arrayindex++) { 90 | if ($alertContextdimensionsValue -eq $vsandatastorename[$arrayindex]) { 91 | $ClusterName = "Cluster-$($arrayindex+2)" 92 | Write-Verbose "*** Storage Alert detected" -Verbose 93 | Write-Verbose "*** alertContextdimensionsValue: $alertContextdimensionsValue" -Verbose 94 | } 95 | } 96 | } 97 | } 98 | Write-Verbose "*** ClusterTypeManagement: $ClusterTypeManagement" -Verbose 99 | Write-Verbose "*** ClusterName: $ClusterName" -Verbose 100 | 101 | # Get Private Cloud (includes Management Cluster: Cluster-1) Object 102 | $MgmtCluster = Get-AzVMwarePrivateCloud -SubscriptionId $SubId -ResourceGroupName $ResourceGroupName -Name $ResourceName 103 | 104 | # Get Private Cloud Provisioning State 105 | $PrivateCloudProvisioningState = $MgmtCluster.ProvisioningState 106 | 107 | # Check Private Cloud Provisioning State 108 | if ($PrivateCloudProvisioningState -eq "Succeeded") { 109 | 110 | # Cluster Size calculation for Standard or Stretched Cluster 111 | # We deliberately rely upon the Azure VMware Solution management & control plane to enforce the cluster size minimum (standard 3 nodes, stretched 6 nodes) and the cluster size maximum (16 nodes). This provides operational simplicity in maintaining this PS Runbook. 112 | 113 | # Get Availability Strategy (SingleZone or DualZone) 114 | $MgmtClusterAvailabilityType = $MgmtCluster.AvailabilityStrategy 115 | Write-Verbose "*** MgmtClusterAvailabilityType: $MgmtClusterAvailabilityType" -Verbose 116 | 117 | # Cluster Type Check, Cluster Size Calculation and Cluster Autoscale Execution 118 | if ($ClusterTypeManagement -eq $true) { 119 | # Management Cluster Size Calculation & Execution 120 | $MgmtClusterCurrentSize = $MgmtCluster.ManagementClusterSize 121 | 122 | if ($MgmtClusterCurrentSize -ge $maxnodes) { 123 | # Management Cluster is already at maximum size, exit 124 | Write-Verbose "*** Management Cluster is already at maximum size of $maxnodes nodes. No action taken." -Verbose 125 | return 126 | } 127 | 128 | if ($MgmtClusterAvailabilityType -eq "DualZone") { 129 | # DualZone requires 1 node per Availability Zone = 2 130 | $MgmtClusterNewSize = $MgmtClusterCurrentSize + 2 131 | } 132 | elseif ($MgmtClusterAvailabilityType -eq "SingleZone") { 133 | # SingleZone requires 1 node per Availability Zone = 1 134 | $MgmtClusterNewSize = $MgmtClusterCurrentSize + 1 135 | } 136 | else { 137 | # Unknown Availability Strategy Type 138 | Write-Error "The Azure VMware Solution Availability Strategy - $MgmtClusterAvailabilityType - is not supported." 139 | } 140 | Write-Verbose "*** MgmtClusterNewSize: $MgmtClusterNewSize" -Verbose 141 | # Execute Management Cluster Autoscale Command 142 | Write-Verbose "*** Scaling PrivateCloudName: $ResourceName Management Cluster (Cluster-1) from $MgmtClusterCurrentSize nodes to $MgmtClusterNewSize nodes" -Verbose 143 | Write-Verbose "*** PrivateCloudName: $ResourceName resides in resourceGroupName: $ResourceGroupName & subscriptionId: $SubId" -Verbose 144 | Update-AzVMwarePrivateCloud -SubscriptionId $SubId -ResourceGroupName $ResourceGroupName -Name $ResourceName -ManagementClusterSize $MgmtClusterNewSize 145 | } 146 | else { 147 | # Resource Cluster Size Calculation & Execution 148 | $ResourceCluster = Get-AzVMwareCluster -SubscriptionId $SubId -ResourceGroupName $ResourceGroupName -PrivateCloudName $ResourceName -Name $ClusterName 149 | $ResourceClusterCurrentSize = $ResourceCluster.Size 150 | 151 | if ($ResourceClusterCurrentSize -ge $maxnodes) { 152 | # Resource Cluster is already at maximum size, exit 153 | Write-Verbose "*** Resource Cluster is already at maximum size of $maxnodes nodes. No action taken." -Verbose 154 | return 155 | } 156 | 157 | if ($MgmtClusterAvailabilityType -eq "DualZone") { 158 | # DualZone requires 1 node per Availability Zone = 2 159 | $ResourceClusterNewSize = $ResourceClusterCurrentSize + 2 160 | } 161 | elseif ($MgmtClusterAvailabilityType -eq "SingleZone") { 162 | # SingleZone requires 1 node per Availability Zone = 1 163 | $ResourceClusterNewSize = $ResourceClusterCurrentSize + 1 164 | } 165 | else { 166 | # Unknown Availability Strategy Type 167 | Write-Error "The Azure VMware Solution Availability Strategy - $MgmtClusterAvailabilityType - is not supported." 168 | } 169 | Write-Verbose "*** ResourceClusterNewSize: $ResourceClusterNewSize" -Verbose 170 | # Execute Resource Cluster Autoscale Command 171 | Write-Verbose "*** Scaling PrivateCloudName: $ResourceName Resource Cluster $ClusterName from $ResourceClusterCurrentSize nodes to $ResourceClusterNewSize nodes" -Verbose 172 | Write-Verbose "*** PrivateCloudName: $ResourceName resides in resourceGroupName: $ResourceGroupName & subscriptionId: $SubId" -Verbose 173 | Update-AzVMwareCluster -SubscriptionId $SubId -ResourceGroupName $ResourceGroupName -PrivateCloudName $ResourceName -Name $ClusterName -ClusterSize $ResourceClusterNewSize 174 | } 175 | } 176 | else { 177 | # SDDC Provisioning State is not Succeeded 178 | Write-Error "The Azure VMware Solution Private Cloud: $ResourceName provisioning state: $PrivateCloudProvisioningState is not in Succeeded state." 179 | } 180 | # [OutputType(PSAzureOperationResponse")] 181 | } 182 | else { 183 | # ResourceType not supported 184 | Write-Error "$ResourceType is not a supported resource type for this runbook." 185 | } 186 | } 187 | else { 188 | # The alert status was not 'Activated' or 'Fired' so no action taken 189 | Write-Verbose ("*** No action taken. Alert status: " + $status) -Verbose 190 | } 191 | } 192 | else { 193 | # Error 194 | Write-Error "This runbook is meant to be started from an Azure alert webhook only." 195 | } -------------------------------------------------------------------------------- /avs-autoscale/media/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image1.png -------------------------------------------------------------------------------- /avs-autoscale/media/image10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image10.png -------------------------------------------------------------------------------- /avs-autoscale/media/image11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image11.png -------------------------------------------------------------------------------- /avs-autoscale/media/image12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image12.png -------------------------------------------------------------------------------- /avs-autoscale/media/image13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image13.png -------------------------------------------------------------------------------- /avs-autoscale/media/image14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image14.png -------------------------------------------------------------------------------- /avs-autoscale/media/image15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image15.png -------------------------------------------------------------------------------- /avs-autoscale/media/image16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image16.png -------------------------------------------------------------------------------- /avs-autoscale/media/image17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image17.png -------------------------------------------------------------------------------- /avs-autoscale/media/image18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image18.png -------------------------------------------------------------------------------- /avs-autoscale/media/image19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image19.png -------------------------------------------------------------------------------- /avs-autoscale/media/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image2.png -------------------------------------------------------------------------------- /avs-autoscale/media/image20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image20.png -------------------------------------------------------------------------------- /avs-autoscale/media/image21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image21.png -------------------------------------------------------------------------------- /avs-autoscale/media/image22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image22.png -------------------------------------------------------------------------------- /avs-autoscale/media/image23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image23.png -------------------------------------------------------------------------------- /avs-autoscale/media/image24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image24.png -------------------------------------------------------------------------------- /avs-autoscale/media/image25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image25.png -------------------------------------------------------------------------------- /avs-autoscale/media/image26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image26.png -------------------------------------------------------------------------------- /avs-autoscale/media/image27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image27.png -------------------------------------------------------------------------------- /avs-autoscale/media/image28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image28.png -------------------------------------------------------------------------------- /avs-autoscale/media/image29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image29.png -------------------------------------------------------------------------------- /avs-autoscale/media/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image3.png -------------------------------------------------------------------------------- /avs-autoscale/media/image30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image30.png -------------------------------------------------------------------------------- /avs-autoscale/media/image31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image31.png -------------------------------------------------------------------------------- /avs-autoscale/media/image32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image32.png -------------------------------------------------------------------------------- /avs-autoscale/media/image33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image33.png -------------------------------------------------------------------------------- /avs-autoscale/media/image34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image34.png -------------------------------------------------------------------------------- /avs-autoscale/media/image35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image35.png -------------------------------------------------------------------------------- /avs-autoscale/media/image36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image36.png -------------------------------------------------------------------------------- /avs-autoscale/media/image37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image37.png -------------------------------------------------------------------------------- /avs-autoscale/media/image38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image38.png -------------------------------------------------------------------------------- /avs-autoscale/media/image39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image39.png -------------------------------------------------------------------------------- /avs-autoscale/media/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image4.png -------------------------------------------------------------------------------- /avs-autoscale/media/image40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image40.png -------------------------------------------------------------------------------- /avs-autoscale/media/image41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image41.png -------------------------------------------------------------------------------- /avs-autoscale/media/image42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image42.png -------------------------------------------------------------------------------- /avs-autoscale/media/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image5.png -------------------------------------------------------------------------------- /avs-autoscale/media/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image6.png -------------------------------------------------------------------------------- /avs-autoscale/media/image7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image7.png -------------------------------------------------------------------------------- /avs-autoscale/media/image8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image8.png -------------------------------------------------------------------------------- /avs-autoscale/media/image9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/avs-autoscale/media/image9.png -------------------------------------------------------------------------------- /azure-vmware-master-diagrams/Azure-VMware-Solution-Availability-Design-Template.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/azure-vmware-master-diagrams/Azure-VMware-Solution-Availability-Design-Template.pptx -------------------------------------------------------------------------------- /azure-vmware-master-diagrams/Azure-VMware-Solution-Performance-Design-Template.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/azure-vmware-master-diagrams/Azure-VMware-Solution-Performance-Design-Template.pptx -------------------------------------------------------------------------------- /azure-vmware-master-diagrams/Azure-VMware-Solution-Recoverability-Design-Template.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/azure-vmware-master-diagrams/Azure-VMware-Solution-Recoverability-Design-Template.pptx -------------------------------------------------------------------------------- /azure-vmware-master-diagrams/Azure-VMware-Solution-Security-Design-Template.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/azure-vmware-master-diagrams/Azure-VMware-Solution-Security-Design-Template.pptx -------------------------------------------------------------------------------- /azure-vmware-master-diagrams/azure-vmware-master-diagrams.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/azure-vmware-master-diagrams/azure-vmware-master-diagrams.pptx -------------------------------------------------------------------------------- /syslog-forwarder/README.md: -------------------------------------------------------------------------------- 1 | # Azure VMware Solution Syslog Forwarder 2 | 3 | **This solution has been replaced by [Send VMware syslogs to log management server using Azure Logic Apps](https://learn.microsoft.com/en-us/azure/azure-vmware/logs-via-logic-app).** 4 | 5 | **Sourced from this GitHub repository and modified to work with Azure VMware 6 | Solution:** [miguelangelopereira/azuremonitor2syslog: Forward Azure 7 | monitor logs to syslog (via Event Hub) 8 | (github.com)](https://github.com/miguelangelopereira/azuremonitor2syslog) 9 | which relies upon this [Syslog-Client](https://travis-ci.org/github/paulgrove/node-syslog-client) 10 | 11 | ## Overview 12 | 13 | Large enterprise and strategic customers have existing and established 14 | monitoring solutions that are a constraint for adopting new solutions 15 | such as the Azure VMware Solution. Customers do not want to adopt a new 16 | real-time monitoring framework for the Azure VMware Solution. This 17 | Syslog Forwarder function allows a customer to achieve operational 18 | excellence with the Azure VMware Solution and meet their operational 19 | management goals. 20 | 21 | The Azure VMware Solution does not currently support Syslog Forwarding 22 | to a customer Syslog server. This Syslog Forwarder function provides 23 | this capability by streaming Azure VMware Solution Diagnostic logs as a 24 | JSON.string to Azure Event Hub which is then in turn processed by an 25 | Azure Function App to convert the JSON.string into Syslog format and 26 | send to an external Syslog server. 27 | 28 | ![](./media/image1.png) 29 | 30 | This solution has been peer reviewed but is best-effort and should be assessed and tested by the customer before using in an Azure VMware Solution production environment. 31 | 32 | ## Operational Considerations 33 | 34 | This Azure service configuration (Event Hub & Azure Function App) costs 35 | approximately US\$3/day for a single Azure VMware Solution private 36 | cloud. 37 | 38 | The Azure Function App is deployed with Visual Studio Code. GitHub is 39 | possible as well but is not covered here. 40 | 41 | ## How-to Guide 42 | 43 | Prerequisites: Connect Syslog Server (Azure VM or on-premises) to Azure 44 | vNET and ExpressRoute Gateway, if needed. 45 | 46 | ### Step 1: Create an Azure Event Hub Namespace within the same Azure 47 | Subscription and Azure Region as the Azure VMware Solution private 48 | cloud. 49 | 50 | 1. In the Basics tab, select the Azure Subscription, Azure Resource 51 | Group, Azure Region, Pricing Tier (Standard), Throughput Units (1), 52 | Auto-Inflate (Enabled), Auto-Inflate Maximum Throughput Units (3) 53 | and enter the Event Hub Namespace name. 54 | 55 | ![](./media/image2.png) 56 | 57 | 2. In the Advanced tab, select the Minimum TLS version 1.2 and enable 58 | Local Authentication. 59 | 60 | ![](./media/image3.png) 61 | 62 | 3. In the Networking tab, select the Public access Connectivity 63 | configuration if your corporate security policies allow it. 64 | Otherwise select Private access (Private endpoint needed). 65 | 66 | ![](./media/image4.png) 67 | 68 | 4. In the Tags tab, configure any needed tags. 69 | 70 | ![](./media/image5.png) 71 | 72 | 5. In the Review & Create tab, validate the configuration and create 73 | the Azure Event Hubs Namespace. 74 | 75 | ![](./media/image6.png) 76 | 77 | ### Step 2: Create an Azure Event Hub within the Azure Event Hub Namespace 78 | from Step 1. 79 | 80 | 1. Select the Add Event Hub icon. 81 | 82 | ![](./media/image7.png) 83 | 84 | 2. In the Basics tab, enter the Event Hub name and set the Partition 85 | Count (1) and Message Retention (1). 86 | 87 | ![](./media/image8.png) 88 | 89 | 3. In the Capture tab, set Capture to Off. 90 | 91 | ![](./media/image9.png) 92 | 93 | 4. In the Review & Create tab, validate the configuration and create 94 | the Azure Event Hub. 95 | 96 | ![](./media/image10.png) 97 | 98 | 5. From the Event Hub Namespace Shared access policies, record the 99 | "RootManagedSharedAccessKey" "Connection string-primary key" which 100 | will be used in Step 4 to allow the Azure Function to access the 101 | Event Hub. 102 | 103 | ![](./media/image11.png) 104 | 105 | ### Step 3: Create an Azure Function App within the same Azure Subscription 106 | and Azure Region as the Azure VMware Solution private cloud. 107 | 108 | 1. In the Basics tab, select the Azure Subscription, Azure Resource 109 | Group, Azure Region, Publish (Code), Runtime Stack (Node.js), 110 | Version (16 LTS), Operating System (Windows), Plan Type (App service 111 | plan), Pricing Plan (Basic B1) and enter the Function App name. 112 | 113 | ![](./media/image12.png) 114 | 115 | 2. In the Hosting tab, select Storage Account. 116 | 117 | ![](./media/image13.png) 118 | 119 | 3. In the Networking tab, network injection is disabled with the Basic 120 | B1 pricing plan. 121 | 122 | ![](./media/image14.png) 123 | 124 | 4. In the Monitoring tab, set Enable Application Insights (Yes). 125 | 126 | ![](./media/image15.png) 127 | 128 | 5. In the Deployment tab, set Continuous Deployment (Disable). 129 | 130 | ![](./media/image16.png) 131 | 132 | 6. In the Tags tab, configure any needed tags. 133 | 134 | ![](./media/image17.png) 135 | 136 | 7. In the Review & Create tab, validate the configuration and create 137 | the Azure Function App. 138 | 139 | ![](./media/image18.png) 140 | 141 | 8. Use the Azure CLI command "az functionapp update --plan \ 142 | -n "\" --resource-group "\" to 143 | change the Plan Type after the Azure Function App has been built. 144 | This is necessary if a higher performance tier (e.g. Premium) is 145 | necessary. 146 | 147 | ![](./media/image19.png) 148 | 149 | ### Step 4: Connect the Azure Function App to the Azure Virtual Network that 150 | has network connectivity to the Syslog server. 151 | 152 | 1. Select the VNet integration link from the Networking tab of the 153 | Function App screen. 154 | 155 | ![](./media/image20.png) 156 | 157 | 2. In the VNet Integration window, select the Add VNet icon. 158 | 159 | ![](./media/image21.png) 160 | 161 | 3. In the Add VNet Integration window, select the Azure Subscription, 162 | Virtual Network and Subnet the Syslog server is connected to and 163 | select the OK button. 164 | 165 | ![](./media/image22.png) 166 | 167 | ### Step 5: Configure Microsoft Visual Studio Code with the necessary 168 | extensions to deploy code to the Azure Function App. 169 | 170 | 1. Open Visual Studio Code, select the Extensions object and make sure 171 | the following extensions are installed: 172 | 173 | a. Azure Account: search for this term in the Market place search 174 | and press the Install button. 175 | 176 | b. Azure Resources: search for this term in the Market place search 177 | and press the Install button. 178 | 179 | c. Azure Functions: search for this term in the Market place search 180 | and press the Install button. 181 | 182 | d. NVM for Windows: [coreybutler/nvm-windows: A node.js version 183 | management utility for Windows. Ironically written in Go. 184 | (github.com)](https://github.com/coreybutler/nvm-windows#installation--upgrades) 185 | 186 | e. After NVM for Windows is installed, open a new Terminal Window from Visual Studio Code 187 | and run the following commands in sequence: "nvm on", "nvm install latest" & "nvm use 19.2.0". 188 | 189 | ![](./media/image23.png) 190 | 191 | ![](./media/image54.png) 192 | 193 | ![](./media/image55.png) 194 | 195 | ![](./media/image56.png) 196 | 197 | ### Step 6: Configure Azure Function App with syslog-forwarding code using 198 | Microsoft Visual Studio Code. 199 | 200 | 1. Copy the GitHub repository file ([index.js](https://github.com/Azure/azure-vmware-solution/blob/main/syslog-forwarder/code/index.js)) to a folder on your Windows 201 | desktop. The create project build will create the function.json file with 202 | the Azure Event Hub connector variables. 203 | 204 | ![](./media/image53.png) 205 | 206 | 2. Open Visual Studio Code and select the Create Function icon from the 207 | Workspace section and then select the folder the GitHub repository 208 | files were copied to. 209 | 210 | ![](./media/image24.png) 211 | 212 | 3. In the Create new project field, select the JavaScript language. 213 | 214 | ![](./media/image25.png) 215 | 216 | 4. In the Create new project field, select the Azure Event Hub trigger 217 | as the function. 218 | 219 | ![](./media/image26.png) 220 | 221 | 5. In the Create new Azure Event Hub trigger field, give the function a 222 | name. e.g. EventHubTrigger1. 223 | 224 | ![](./media/image27.png) 225 | 226 | 6. In the Create new Azure Event Hub trigger field, select the Create 227 | new local app setting. 228 | 229 | ![](./media/image28.png) 230 | 231 | 7. In the Create new Azure Event Hub trigger field, select the Azure 232 | Function App configured in Step 3. 233 | 234 | ![](./media/image29.png) 235 | 236 | 8. In the Create new Azure Event Hub trigger field, select the Azure 237 | Event Hub Namespace configured in Step 1. 238 | 239 | ![](./media/image30.png) 240 | 241 | 9. In the Create new Azure Event Hub trigger field, select the Azure 242 | Event Hub configured in Step 2. 243 | 244 | ![](./media/image31.png) 245 | 246 | 10. In the Create new Azure Event Hub trigger field, select the Azure 247 | Event Hub policy configured in Step 1. E.g. 248 | RootManagedSharedAccessKey. 249 | 250 | ![](./media/image32.png) 251 | 252 | 11. In the Create new Azure Event Hub trigger field, select the Azure 253 | Event Hub consumer group configured in Step 1. E.g. \$Default. 254 | 255 | ![](./media/image33.png) 256 | 257 | 12. In the Create new project field, select the Open in current window 258 | option. 259 | 260 | ![](./media/image34.png) 261 | 262 | 13. In the Visual Studio Code popup window, select the Deploy button. 263 | 264 | ![](./media/image35.png) 265 | 266 | 14. Track the deployment status in the Terminal window and by the deploy 267 | status in the bottom right corner of Visual Studio Code. 268 | 269 | ![](./media/image36.png) 270 | 271 | 15. When deployment is complete, the deploy status in the bottom right 272 | corner of Visual Studio Code will be marked as completed. 273 | 274 | ![](./media/image37.png) 275 | 276 | 16. If the deployment fails, make sure the syslog-client is installed, 277 | by typing "npm install syslog-client" in the Terminal window and 278 | then execute the deploy Azure Function App again by right mouse 279 | click over the Azure Function App (not the Workspace) and select the 280 | local folder that contains the GitHub code. 281 | 282 | ![](./media/image38.png) 283 | 284 | ![](./media/image39.png) 285 | 286 | 17. From Visual Studio Code, expand the Azure Function App created in 287 | Step 3, right click the Application Settings folder and select Add 288 | New Setting. Add the following six settings by repeating this step: 289 | 290 | a. Name: SYSLOG_FACILITY, Value: \ 292 | 293 | b. Name: SYSLOG_HOSTNAME, Value: \ 295 | 296 | c. Name: SYSLOG_PORT, Value: 514 297 | 298 | d. Name: SYSLOG_PROTOCOL, Value: TCP 299 | 300 | e. Name: SYSLOG_SERVER, Value: \ 301 | 302 | f. Name: \-RootManageSharedAccessKey_EVENTHUB (this 303 | needs to match the connection name in the function.json file in 304 | the Azure Function App EventHubTrigger folder), Value: \ 306 | 307 | ![](./media/image40.png) 308 | 309 | ![](./media/image41.png) 310 | 311 | ![](./media/image42.png) 312 | 313 | ![](./media/image43.png) 314 | 315 | 18. Right click over the Azure Function App and select Restart. 316 | 317 | ### Step 7: Configure Azure VMware Solution private cloud to forward syslog 318 | messages to Azure Event Hub. 319 | 320 | 1. In the Azure VMware Solution Diagnostic settings window, select the 321 | Add diagnostic setting icon. 322 | 323 | ![](./media/image44.png) 324 | 325 | 2. In the Add Diagnostic setting window, select the audit and allLogs 326 | Category groups, select the VMware Syslog Category, select the 327 | Stream to event hub option and select the Subscription, Event Hub 328 | Namespace, Event Hub name and Event Hub policy name. Then press the 329 | Save button. 330 | 331 | ![](./media/image45.png) 332 | 333 | 3. The Azure VMware Solution syslogs will now start streaming to the 334 | Syslog server via the Event Hub and Azure Function App. 335 | 336 | ![](./media/image46.png) 337 | 338 | ## Troubleshooting 339 | 340 | ### Step 8: Troubleshooting Azure Function syslog message processing. 341 | 342 | 1. From Visual Studio Code, select the Azure Function App built in Step 343 | 3 and make sure the following items exist: 344 | 345 | a. Functions folder has an EventHubTrigger object. 346 | 347 | b. Application settings have the six entries for SYSLOG and Event 348 | Hub shared access key. 349 | 350 | c. Files folder has EventHubTrigger function.json, index.js files 351 | and node_modules has syslog-client folder. Verify that the index.js 352 | file has the syslog function code. If it does not, update the index.js 353 | file and deploy the Azure Function App again. 354 | 355 | ![](./media/image47.png) 356 | 357 | 2. From the Azure portal, select the Azure Event Hub Namespace 358 | configured in Step 1 and from the Overview page, verify that the 359 | Messages graph has Incoming and Outgoing Message traffic. 360 | 361 | ![](./media/image48.png) 362 | 363 | 3. Then select the Azure Function App configured in Step 3 and from the 364 | Overview page, verify that the Function Execution Count is non-zero. 365 | 366 | ![](./media/image49.png) 367 | 368 | 4. Then select the Function page of the Azure Function App and select 369 | the Event Hub Trigger Name. 370 | 371 | ![](./media/image50.png) 372 | 373 | 5. Then select the Function page of the Azure Function App and select 374 | the Event Hub Trigger Name. Verify that Invocation Traces exist and 375 | click on the timestamped trace to view the details. 376 | 377 | ![](./media/image51.png) 378 | 379 | 6. From the Azure portal, in the Azure Function window, select the 380 | Console object from the Development Tools section and run the 381 | "tcpping \:\" command. 382 | If there is a tcpping response, this means the Azure Function has 383 | network connectivity to the Syslog server. 384 | 385 | ![](./media/image52.png) 386 | 387 | ## Testing 388 | 389 | From a CentOS Linux machine connected to the Azure Virtual Network, 390 | logger can be used to send a test message to the Syslog server: logger 391 | -n \ -t myapp -p user.notice \"TESTING" 392 | -------------------------------------------------------------------------------- /syslog-forwarder/code/index.js: -------------------------------------------------------------------------------- 1 | // Title: Azure VMware Solution Private Cloud Syslog Forwarding Node.js function for Azure Function App 2 | 3 | // Purpose: Azure Function App pulls messages from the Azure Event Hub and forwards them to a Syslog server with the Syslog protocol. 4 | 5 | module.exports = function (context, myEventHubMessage) { 6 | context.log(`JavaScript eventhub trigger function called for message JSON string ${myEventHubMessage}`); 7 | // Initializing syslog-client, which is installed using the "npm install syslog-client" command. 8 | try{ 9 | var syslog = require("syslog-client"); 10 | } catch (e) { 11 | throw e; 12 | } 13 | 14 | // Get environment variables which are defined in the Azure Function App Application Settings. 15 | var SYSLOG_SERVER = GetEnvironmentVariable("SYSLOG_SERVER"); 16 | 17 | var SYSLOG_PORT = GetEnvironmentVariable("SYSLOG_PORT"); 18 | 19 | // If key environment variables are not configured, throw an error. Remaining environment variables are assigned a default value if null. 20 | if ((SYSLOG_SERVER == null) || (SYSLOG_PORT == null)) { 21 | throw "Please setup SYSLOG_SERVER and/or SYSLOG_PORT environment variables. " 22 | } 23 | 24 | var SYSLOG_PROTOCOL; 25 | if (GetEnvironmentVariable("SYSLOG_PROTOCOL")=="TCP") { 26 | SYSLOG_PROTOCOL = syslog.Transport.Tcp; 27 | context.log('*** Syslog TCP'); 28 | } else { 29 | SYSLOG_PROTOCOL = syslog.Transport.Udp; 30 | context.log('*** Syslog UDP'); 31 | } 32 | 33 | var SYSLOG_HOSTNAME; 34 | if (GetEnvironmentVariable("SYSLOG_HOSTNAME")==null) { 35 | SYSLOG_HOSTNAME = "azurefunction" 36 | } else { 37 | SYSLOG_HOSTNAME = GetEnvironmentVariable("SYSLOG_HOSTNAME"); 38 | context.log('*** Syslog hostname', SYSLOG_HOSTNAME); 39 | } 40 | 41 | var SYSLOG_FACILITY; 42 | if (GetEnvironmentVariable("SYSLOG_FACILITY")==null) { 43 | SYSLOG_FACILITY = syslog.Facility.Local0; 44 | } else { 45 | SYSLOG_FACILITY = GetEnvironmentVariable("SYSLOG_FACILITY"); 46 | } 47 | 48 | // Options for syslog connection which are defined in the Azure Function App Application Settings. 49 | var options = { 50 | syslogHostname: SYSLOG_HOSTNAME, 51 | transport: SYSLOG_PROTOCOL, 52 | port: SYSLOG_PORT, 53 | facility: SYSLOG_FACILITY 54 | }; 55 | 56 | // Log connection variables which are defined in the Azure Function App Application Settings. 57 | context.log('SYSLOG Server: ', SYSLOG_SERVER); 58 | context.log('SYSLOG Port: ', SYSLOG_PORT); 59 | context.log('SYSLOG Protocol: ', SYSLOG_PROTOCOL); 60 | context.log('SYSLOG Hostname: ', SYSLOG_HOSTNAME); 61 | context.log('SYSLOG Facility: ', SYSLOG_FACILITY); 62 | 63 | // Log received message from Azure Event Hub. Azure Event Hub is the configured Azure VMware Solution Diagnostic log target. 64 | context.log(`Event Hubs trigger function processed message: ${myEventHubMessage}`); 65 | context.log('EnqueuedTimeUtc =', context.bindingData.enqueuedTimeUtc); 66 | context.log('SequenceNumber =', context.bindingData.sequenceNumber); 67 | context.log('Offset =', context.bindingData.offset); 68 | 69 | // Create syslog client, which is installed using the "npm install syslog-client" command. 70 | var client = syslog.createClient(SYSLOG_SERVER, options); 71 | 72 | // Cycle through Azure Event Hub messages and send messages with Syslog protocol to configured Syslog server. 73 | // Azure Event Hub sends the messages in JSON.string format. 74 | myEventHubMessage.forEach((message, index)=>{ 75 | if(typeof message === 'string'){ 76 | var msg = JSON.parse(message); 77 | msg.records.forEach((m1, i) => { 78 | client.log(JSON.stringify(m1), options, function(error) { 79 | if (error) { 80 | context.log("error sending message"); 81 | context.log(error); 82 | } else { 83 | context.log("sent message successfully"); 84 | } 85 | }); 86 | }); 87 | } 88 | }); 89 | 90 | context.log("completed sending all messages"); 91 | context.done(); 92 | }; 93 | 94 | // Get environment variables defined in the Azure Function App Application Settings. 95 | function GetEnvironmentVariable(name) 96 | { 97 | return process.env[name]; 98 | } 99 | -------------------------------------------------------------------------------- /syslog-forwarder/media/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image1.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image10.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image11.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image12.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image13.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image14.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image15.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image16.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image17.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image18.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image19.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image2.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image20.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image21.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image22.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image23.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image24.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image25.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image26.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image27.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image28.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image29.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image3.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image30.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image31.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image32.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image33.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image34.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image35.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image36.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image37.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image38.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image39.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image4.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image40.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image41.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image42.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image43.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image44.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image45.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image46.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image47.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image48.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image49.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image5.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image50.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image51.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image52.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image53.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image54.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image55.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image56.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image6.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image7.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image8.png -------------------------------------------------------------------------------- /syslog-forwarder/media/image9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-vmware-solution/3d5c9a80b7973f4b4ea0d65e5184c473b5706875/syslog-forwarder/media/image9.png --------------------------------------------------------------------------------