├── .gitignore ├── README.md ├── azure-powershell-windows ├── EventStoreScriptExtensionProvisionFile.ps1 ├── ProvisionEventStore.ps1 └── README.md ├── azure-resource-manager ├── EventStoreCluster.sln ├── EventStoreCluster │ ├── CreateStripedDataDisk.ps1 │ ├── Deployment.targets │ ├── EventStoreCluster.deployproj │ ├── Scripts │ │ └── Deploy-AzureResourceGroup.ps1 │ ├── Templates │ │ ├── azuredeploy.json │ │ ├── azuredeploy.param.dev.json │ │ ├── cluster-nodes-0disk-resources.json │ │ ├── cluster-nodes-16disk-resources.json │ │ ├── cluster-nodes-2disk-resources.json │ │ ├── cluster-nodes-4disk-resources.json │ │ ├── cluster-nodes-8disk-resources.json │ │ ├── create-data-disks.ps1 │ │ ├── data-nodes-0disk-resources.json │ │ ├── empty-resources.json │ │ ├── eventstore-ubuntu-sources.txt │ │ ├── eventstore-windows-sources.csv │ │ ├── install-eventstore.ps1 │ │ ├── install-nginx.ps1 │ │ ├── jumpbox-resources.json │ │ ├── master.ps1 │ │ ├── shared-resources.json │ │ └── tmpl │ │ │ └── data-nodes.yml │ └── Tools │ │ ├── AzCopy.exe │ │ ├── Microsoft.Data.Edm.dll │ │ ├── Microsoft.Data.OData.dll │ │ ├── Microsoft.Data.Services.Client.dll │ │ ├── Microsoft.WindowsAzure.Storage.DataMovement.dll │ │ └── Microsoft.WindowsAzure.Storage.dll └── README.md └── vagrant-eventstore-cluster ├── .gitignore ├── Berksfile ├── LICENSE ├── README.md └── Vagrantfile /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | 154 | # Windows Azure Build Output 155 | csx/ 156 | *.build.csdef 157 | 158 | # Windows Azure Emulator 159 | efc/ 160 | rfc/ 161 | 162 | # Windows Store app package directory 163 | AppPackages/ 164 | 165 | # Visual Studio cache files 166 | # files ending in .cache can be ignored 167 | *.[Cc]ache 168 | # but keep track of directories ending in .cache 169 | !*.[Cc]ache/ 170 | 171 | # Others 172 | ClientBin/ 173 | [Ss]tyle[Cc]op.* 174 | ~$* 175 | *~ 176 | *.dbmdl 177 | *.dbproj.schemaview 178 | *.pfx 179 | *.publishsettings 180 | node_modules/ 181 | orleans.codegen.cs 182 | 183 | # RIA/Silverlight projects 184 | Generated_Code/ 185 | 186 | # Backup & report files from converting an old project file 187 | # to a newer Visual Studio version. Backup files are not needed, 188 | # because we have git ;-) 189 | _UpgradeReport_Files/ 190 | Backup*/ 191 | UpgradeLog*.XML 192 | UpgradeLog*.htm 193 | 194 | # SQL Server files 195 | *.mdf 196 | *.ldf 197 | 198 | # Business Intelligence projects 199 | *.rdl.data 200 | *.bim.layout 201 | *.bim_*.settings 202 | 203 | # Microsoft Fakes 204 | FakesAssemblies/ 205 | 206 | # GhostDoc plugin setting file 207 | *.GhostDoc.xml 208 | 209 | # Node.js Tools for Visual Studio 210 | .ntvs_analysis.dat 211 | 212 | # Visual Studio 6 build log 213 | *.plg 214 | 215 | # Visual Studio 6 workspace options file 216 | *.opt 217 | 218 | # Visual Studio LightSwitch build output 219 | **/*.HTMLClient/GeneratedArtifacts 220 | **/*.DesktopClient/GeneratedArtifacts 221 | **/*.DesktopClient/ModelManifest.xml 222 | **/*.Server/GeneratedArtifacts 223 | **/*.Server/ModelManifest.xml 224 | _Pvt_Extensions 225 | 226 | # Paket dependency manager 227 | .paket/paket.exe 228 | 229 | # FAKE - F# Make 230 | .fake/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EventStore DevOps 2 | 3 | This project is used to setup an [Event Store](https://geteventstore.com/) cluster on Azure. The preferred method is to use the azure resource manager approach. 4 | 5 | * **azure-resource-manager** - Use Azure Resource Manager to create a cluster 6 | * **vagrant-eventstore-cluster** - *not actively maintained* create a local Event Store cluster in vagrant and virtual box. Cloned from [seif/vagrant-eventstore-cluster](https://github.com/seif/vagrant-eventstore-cluster) and now references my fork of [eventstore-cookbook](https://github.com/pbolduc/eventstore-cookbook) 7 | * **azure-powershell-Windows** - *depreicated* create an arbitrary sized Event Store cluster on Windows hosts on Windows Azure -------------------------------------------------------------------------------- /azure-powershell-windows/EventStoreScriptExtensionProvisionFile.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [Int] 3 | $clusterSize, 4 | [string] 5 | $VMName, 6 | [Int] 7 | $nodeNumber, 8 | [Int] 9 | $IntIp, 10 | [Int] 11 | $ExtIp, 12 | [Int] 13 | $IntTcpPort = 1112, 14 | [Int] 15 | $IntHttpPort = 2112, 16 | [Int] 17 | $ExtTcpPort = 1113, 18 | [Int] 19 | $ExtHttpPort = 2113 20 | ) 21 | 22 | 23 | function Extract-ZipFile($file, $destination) 24 | { 25 | if (![System.IO.Directory]::Exists($destination)) { 26 | [System.IO.Directory]::CreateDirectory($destination) 27 | } 28 | $shell = new-object -com shell.application 29 | $zip = $shell.NameSpace($file) 30 | 31 | foreach($item in $zip.items()) { 32 | $shell.Namespace($destination).copyhere($item) 33 | } 34 | } 35 | 36 | function Install-Chocolatey($InstallToPath) { 37 | $env:ChocolateyInstall = $InstallToPath 38 | iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) 39 | } 40 | 41 | function Download-EventStore($DownloadUrl, $SaveToPath) { 42 | $client = new-object System.Net.WebClient 43 | $client.DownloadFile($DownloadUrl, $SaveToPath) 44 | } 45 | 46 | function Format-DataDisks() { 47 | $Interleave = 65536 # is this the best value for EventStore? 48 | $uninitializedDisks = Get-PhysicalDisk -CanPool $true 49 | 50 | $poolDisks = $uninitializedDisks 51 | $numberOfDisksPerPool = $poolDisks.Length 52 | 53 | $poolName = "Data Storage Pool" 54 | $newPool = New-StoragePool -FriendlyName $poolName -StorageSubSystemFriendlyName "Storage Spaces*" -PhysicalDisks $poolDisks 55 | 56 | $virtualDiskJob = New-VirtualDisk -StoragePoolFriendlyName $poolName -FriendlyName $poolName -ResiliencySettingName Simple -ProvisioningType Fixed -Interleave $Interleave ` 57 | -NumberOfDataCopies 1 -NumberOfColumns $numberOfDisksPerPool -UseMaximumSize -AsJob 58 | 59 | Receive-Job -Job $virtualDiskJobs -Wait 60 | Wait-Job -Job $virtualDiskJobs 61 | Remove-Job -Job $virtualDiskJobs 62 | 63 | # Initialize and format the virtual disks on the pools 64 | $formatted = Get-VirtualDisk | Initialize-Disk -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -FileSystem NTFS -Confirm:$false 65 | 66 | # Create the data directory 67 | $formatted | ForEach-Object { 68 | # Get current drive letter. 69 | $downloadDriveLetter = $_.DriveLetter 70 | 71 | # Create the data directory 72 | $dataDirectory = "$($downloadDriveLetter):\Data" 73 | 74 | New-Item $dataDirectory -Type directory -Force | Out-Null 75 | } 76 | 77 | # Dive time to the storage service to pick up the changes 78 | Start-Sleep -Seconds 60 79 | } 80 | 81 | function New-EventStoreConfigFile() { 82 | 83 | $seeds = @() 84 | for ($n = 1; $n -le $clusterSize; $n++) { 85 | $nodeName = $VMName + "-" + $n 86 | if ($nodeName -ne $env:COMPUTERNAME) { 87 | do { 88 | # the other nodes may not be running yet, wait for them to return an ip address 89 | $ip = (Resolve-DnsName $nodeName -Type A -ErrorAction SilentlyContinue).IPAddress 90 | } while ($ip -eq $null) 91 | 92 | # 93 | $seeds += "'" + $ip + ":" + $IntHttpPort + "'" 94 | } 95 | } 96 | 97 | $gossipSeed = $seeds -join ',' 98 | 99 | # this is a bit of a hack that depends on the BGInfo plugin. Is there a better way to determine this? 100 | #$publicIp = PS C:\Users\eventstore> (Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Azure\BGInfo").PublicIp 101 | 102 | $configFile = "C:\EventStore\EventStore-Config.yaml" 103 | $ipAddress = (Resolve-DnsName $env:COMPUTERNAME -Type A).IPAddress 104 | 105 | $IntIp = $ipAddress 106 | $ExtIp = $ipAddress 107 | 108 | "# EventStore configuration file. Created at: $(Get-Date -Format 'u')" | Out-File -FilePath $configFile 109 | "Db: F:\Data\eventstore" | Out-File -FilePath $configFile -Append 110 | "Log: D:\Logs\eventstore" | Out-File -FilePath $configFile -Append 111 | "IntIp: $IntIp" | Out-File -FilePath $configFile -Append 112 | "ExtIp: $ExtIp" | Out-File -FilePath $configFile -Append 113 | "IntTcpPort: $IntTcpPort" | Out-File -FilePath $configFile -Append 114 | "IntHttpPort: $IntHttpPort" | Out-File -FilePath $configFile -Append 115 | "ExtTcpPort: $ExtTcpPort" | Out-File -FilePath $configFile -Append 116 | "ExtHttpPort: $ExtHttpPort" | Out-File -FilePath $configFile -Append 117 | "DiscoverViaDns: false" | Out-File -FilePath $configFile -Append 118 | "GossipSeed: [$gossipSeed]" | Out-File -FilePath $configFile -Append 119 | "ClusterSize: $clusterSize" | Out-File -FilePath $configFile -Append 120 | } 121 | 122 | # 123 | # Azure VM's have Temporary Storage on D:\ - Store only log data / temp files there 124 | # 125 | 126 | Format-DataDisks 127 | 128 | Install-Chocolatey -InstallToPath "C:\Chocolatey" 129 | Download-EventStore -DownloadUrl "http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.0.2.zip" -SaveToPath "D:\EventStore-OSS-Win-v3.0.2.zip" 130 | Extract-ZipFile -file "D:\EventStore-OSS-Win-v3.0.2.zip" -destination "C:\EventStore\v3.0.2\" 131 | 132 | New-EventStoreConfigFile 133 | 134 | choco install nssm --version 2.24.0 135 | #choco install logstash 136 | #choco install timberwinr 137 | 138 | # 139 | # 140 | # 141 | $ipAddress = (Resolve-DnsName $env:COMPUTERNAME -Type A).IPAddress 142 | 143 | #Database Node Internal HTTP Interface (open source and commercial) 144 | netsh http add urlacl url=http://${ipAddress}:${IntHttpPort}/ user="NT AUTHORITY\LOCAL SERVICE" 145 | 146 | # Database Node External HTTP Interface (open source and commercial) 147 | netsh http add urlacl url=http://${ipAddress}:${ExtHttpPort}/ user="NT AUTHORITY\LOCAL SERVICE" 148 | 149 | # Manager Node Internal HTTP Interface (commercial only) 150 | #netsh http add urlacl url=http://$ipAddress:30777/ user="NT AUTHORITY\LOCAL SERVICE" 151 | 152 | # Manager Node External HTTP Interface (commercial only) 153 | #netsh http add urlacl url=http://$ipAddress:30778/ user="NT AUTHORITY\LOCAL SERVICE" 154 | 155 | # Added all the ports, but think I only require the 2112,2113 ports 156 | New-NetFirewallRule -Name Allow_EventStore_Int_In -DisplayName "Allow inbound Internal Event Store traffic" -Protocol TCP -Direction Inbound -Action Allow -LocalPort ${IntTcpPort},${IntHttpPort} 157 | New-NetFirewallRule -Name Allow_EventStore_Ext_In -DisplayName "Allow inbound External Event Store traffic" -Protocol TCP -Direction Inbound -Action Allow -LocalPort ${ExtTcpPort},${ExtHttpPort} 158 | 159 | C:\Chocolatey\lib\NSSM.2.24.0\Tools\nssm-2.24\win64\nssm.exe install EventStore C:\EventStore\v3.0.2\EventStore.ClusterNode.exe --config C:\EventStore\EventStore-Config.yaml 160 | C:\Chocolatey\lib\NSSM.2.24.0\Tools\nssm-2.24\win64\nssm.exe set EventStore Description "The EventStore service." 161 | 162 | 163 | #net start EventStore -------------------------------------------------------------------------------- /azure-powershell-windows/ProvisionEventStore.ps1: -------------------------------------------------------------------------------- 1 | # ProvisionEventStore.ps1 2 | 3 | <# 4 | .SYNOPSIS 5 | .DESCRIPTION 6 | .EXAMPLE 7 | #> 8 | 9 | # http://azure.microsoft.com/en-us/documentation/articles/install-configure-powershell/ 10 | # Add-AzureAccount 11 | 12 | param 13 | ( 14 | [Int]$ClusterSize, 15 | [Int]$DataDiskSize = 0, 16 | [String]$Location, 17 | [String]$InstanceSize, 18 | [String]$username, 19 | [String]$password, 20 | [String]$ServiceName, 21 | [String]$VMName, 22 | [String]$ImageName, 23 | [String]$AffinityGroup, 24 | [String]$TargetStorageAccountName, 25 | [Int]$MaxDisksPerStorageAccount = 40, 26 | [Int]$MaxDataDisksPerVirtualMachine = 0, 27 | [String]$AvailabilitySetName, 28 | [String]$VNetName, 29 | [String]$VNetSubnetName, 30 | [String]$CustomScriptExtensionStorageAccountName, 31 | [String]$CustomScriptExtensionStorageAccountKey, 32 | [String]$CustomScriptExtensionContainerName, 33 | [String]$CustomScriptExtensionProvisionFile 34 | ) 35 | 36 | function Get-RandomStorageAccountName { 37 | param ( 38 | [Parameter(Mandatory = $true)] 39 | [String] 40 | $prefix, 41 | [ValidateRange(3,24)] 42 | [Int] 43 | $maxLength = 24 44 | ) 45 | 46 | $name = $prefix.ToLower() 47 | while ($name.Length -lt 24) { 48 | $name = $name + [char](Get-Random -Minimum 97 -Maximum 122) 49 | } 50 | return $name 51 | } 52 | 53 | function Ensure-AzureAffinityGroup { 54 | param 55 | ( 56 | [Parameter(Mandatory = $true)] 57 | [String] 58 | $name, 59 | [Parameter(Mandatory = $true)] 60 | [string]$location 61 | ) 62 | 63 | $affinityGroup = Get-AzureAffinityGroup -Name $name -ErrorAction SilentlyContinue 64 | if ($affinityGroup -eq $null) { 65 | New-AzureAffinityGroup -Location $location -Name $name | Out-Null 66 | } elseif ($affinityGroup.Location -ne $location) { 67 | $actualLocation = $affinityGroup.Location 68 | Write-Error "Affinity Group '$name' exists, but is not in location '$location'. It is in location '$actualLocation'." 69 | } 70 | } 71 | 72 | function Ensure-StorageAccount() { 73 | if ((Get-AzureStorageAccount -StorageAccountName $TargetStorageAccountName -ErrorAction SilentlyContinue) -eq $null) { 74 | 75 | $storageAccountName = Get-RandomStorageAccountName($TargetStorageAccountName) 76 | New-AzureStorageAccount -AffinityGroup $AffinityGroup -StorageAccountName $storageAccountName -Type Standard_LRS | Out-Null 77 | 78 | # Wait for the storage account to be available so we can use it 79 | Write-Verbose "$(Get-Date -Format 'T') Waiting for storage account $storageAccountName to be available..." 80 | while ((Get-AzureStorageAccount -StorageAccountName $storageAccountName).StatusOfPrimary -ne "Available") { 81 | Start-Sleep -Seconds 1 82 | } 83 | return $storageAccountName 84 | } else { 85 | return $TargetStorageAccountName 86 | } 87 | } 88 | 89 | function Create-EventStoreNodes { 90 | param ( 91 | [Parameter(Mandatory = $true)] 92 | [String] 93 | $StorageAccountName 94 | ) 95 | <# Subscription Limits - http://azure.microsoft.com/en-us/documentation/articles/azure-subscription-service-limits/ 96 | 97 | Default Max limit 98 | Cores 20 10,000 99 | Storage accounts per subscription - 100 100 100 | 101 | Max 8 KB IOPS per persistent disk (Basic Tier) 300 102 | Max 8 KB IOPS per persistent disk (Standard Tier) 500 103 | Total Request Rate (assuming 1KB object size) per storage account 20,000 104 | Target Throughput for Single Blob Up to 60 MB per second, or up to 500 requests per second 105 | #> 106 | 107 | # create the cloud service first so that it will be ready when the VM are created below 108 | New-AzureService -ServiceName $ServiceName -AffinityGroup $AffinityGroup | Out-Null 109 | 110 | $vms = @() 111 | 112 | $numberOfDataDisks = (Get-AzureRoleSize -InstanceSize $InstanceSize).MaxDataDiskCount 113 | 114 | # if we are limiting the total data disks 115 | if ($MaxDataDisksPerVirtualMachine -ge 1) { 116 | $numberOfDataDisks = [System.Math]::Min($numberOfDataDisks,$MaxDataDisksPerVirtualMachine) 117 | } 118 | 119 | $totalDiskCount = $ClusterSize * ($numberOfDataDisks+1) # OS Disk + N data disks $MaxDiskPerStorageAccount 120 | 121 | if ($totalDiskCount -ge 40) { 122 | Write-Warning "You may have too many disks per storage account. Your performance may degrade. See http://blogs.msdn.com/b/mast/archive/2014/10/14/configuring-azure-virtual-machines-for-optimal-storage-performance.aspx" 123 | } 124 | 125 | for ($node=1;$node -le $ClusterSize;$node++) { 126 | $name = $VMName + "-" + $node 127 | 128 | $vm = New-AzureVMConfig -ImageName $ImageName -InstanceSize $InstanceSize -Name $name -AvailabilitySetName $AvailabilitySetName 129 | $vm = $vm | Set-AzureSubnet -SubnetNames $VNetSubnetName 130 | 131 | $isWindows = $true 132 | if ($isWindows) { 133 | $vm = $vm | Add-AzureProvisioningConfig -AdminUsername $username -Password $password -Windows 134 | } else { 135 | $vm = $vm | Add-AzureProvisioningConfig -LinuxUser $username -Password $password -Linux 136 | } 137 | 138 | if ($true) { 139 | $StandardTcpPort = 1113 140 | $StandardHttpPort = 2113 141 | 142 | $ExtTcpPort = $StandardTcpPort + ($node - 1) * 100 143 | $ExtHttpPort = $StandardHttpPort + ($node - 1) * 100 144 | 145 | # http://michaelwasham.com/windows-azure-powershell-reference-guide/configuring-disks-endpoints-vms-powershell/ 146 | $vm = $vm | Add-AzureEndpoint -Name 'EventStoreTcp' -LocalPort $ExtTcpPort -PublicPort $ExtTcpPort -Protocol Tcp 147 | $vm = $vm | Add-AzureEndpoint -Name 'EventStoreHttp' -LocalPort $ExtHttpPort -PublicPort $ExtHttpPort -Protocol Tcp 148 | } 149 | 150 | $vm = $vm | Set-AzureVMCustomScriptExtension ` 151 | -StorageAccountName $CustomScriptExtensionStorageAccountName ` 152 | -StorageAccountKey $CustomScriptExtensionStorageAccountKey ` 153 | -ContainerName $CustomScriptExtensionContainerName ` 154 | -FileName $CustomScriptExtensionProvisionFile ` 155 | -Run $CustomScriptExtensionProvisionFile ` 156 | -Argument "-clusterSize $ClusterSize -VMName $VMName -nodeNumber $node -ExtTcpPort $ExtTcpPort -ExtHttpPort $ExtHttpPort" 157 | 158 | # Attach the maximum data disks allowed for the virtual machine size 159 | if ($DataDiskSize -gt 0) { 160 | 161 | $minSizeInGB = 4 # min size for each disk to be stripped: All disks must be at least 4 GB. 162 | $sizeInGB = [int][System.Math]::Max([System.Math]::Ceiling($DataDiskSize / $numberOfDataDisks), $minSizeInGB) 163 | 164 | for ($index = 0; $index -lt $numberOfDataDisks; $index++) { 165 | $label = "Data disk " + $index 166 | # The maximum number of data disks that may simultaneously use read caching is 4. 167 | $vm = $vm | Add-AzureDataDisk -CreateNew -DiskSizeInGB $sizeInGB -DiskLabel $label -LUN $index -HostCaching None 168 | } 169 | } 170 | 171 | $vms += $vm 172 | } 173 | 174 | # create all of the VMs 175 | New-AzureVM -ServiceName $ServiceName -VNetName $VNetName -VMs $vms | Out-Null 176 | } 177 | 178 | Write-Verbose "$(Get-Date -Format 'T') Ensuring Affinity Group '$AffinityGroup' exists and is in '$Location' location." 179 | Ensure-AzureAffinityGroup $AffinityGroup $Location 180 | $storageAccountName = Ensure-StorageAccount 181 | 182 | $SubscriptionName = (Get-AzureSubscription).SubscriptionName 183 | Set-AzureSubscription -SubscriptionName $SubscriptionName -CurrentStorageAccount $storageAccountName 184 | 185 | Write-Verbose "$(Get-Date -Format 'T') Creating Virtual Machines" 186 | Create-EventStoreNodes -StorageAccountName $storageAccountName -------------------------------------------------------------------------------- /azure-powershell-windows/README.md: -------------------------------------------------------------------------------- 1 | I thought I would share the work I have done to automatically setup Event Store running on Azure VMs. Right now, it only targets Windows hosts, but should be easily extended for Linux. To extend for Linux, you would need to create a shell script to replace the PowerShell provisioning script shown in step #4. I have observed it takes about 20 minutes until all the VMs are running with Event Store. 2 | 3 | https://gist.github.com/pbolduc/f8ba49358a97e1e95332 4 | 5 | Files: 6 | 7 | * ProvisionEventStore.ps1 - creates Affinity Group, Storage Account, VMs and data disks for VMs 8 | * EventStoreScriptExtensionProvisionFile.ps1 - Run automatically on the VM to install and configure Event Store to run as a service using NSSM 9 | 10 | Features: 11 | 12 | * Creates any number of VMs for your cluster. No validation to ensure the number is odd. See -ClusterSize 13 | * Creates a stripped data disk using as many data disks the VM will support based on the instance size. The user specifies total target disk size in GB 14 | * Creates all VMs inside the same cloud service. VMs in the same cloud service can resolve the VM names to internal IP addresses 15 | * Uses a virtual network so nodes can user internal addresses for communication 16 | * Sets up all resources in one affinity group to ensure VMs and storage are close to each other in the data center 17 | * Creates a random storage account name to avoid conflicts (uses the user supplied prefix) 18 | 19 | on each VM created: 20 | 21 | * Formats all the data disks into a single striped volume 22 | * Installs Chocolatey 23 | * Installs NSSM using Chocolatey 24 | * Downloads Event Store 3.0.1 from http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.0.1.zip 25 | * Determines the IP addresses of the other nodes and configures the gossip seeds in the configuration file 26 | * Adds a service called 'EventStore' that will start automatically 27 | * Logs are written to D:\Logs\eventstore\ 28 | * Data is stored to F:\Data\eventstore\ 29 | * Adds firewall rules to allow Event Store traffic 30 | * Adds netsh urlacls for Event Store 31 | 32 | How to use: 33 | 34 | 1. Manually create a virtual network so that your Event Store nodes can talk to each other on private IP addresses 35 | 2. Manually create a named subnet in your virtual network 36 | 3. Manually create a storage account and container to host the the custom script extension 37 | 4. Upload file EventStoreScriptExtensionProvisionFile.ps1 (found in the gist) to your custom script extension container 38 | 5. Install the Azure PowerShell Cmdlets and ensure they are working with your subscription (see: How to install and configure Azure PowerShell) 39 | 6. Login to your Azure account using Add-AzureAccount and/or 40 | 7. Run ProvisionEventStore.ps1 with your desired parameters 41 | 42 | Example Execution: 43 | 44 | ``` 45 | # Run Add-AzureAccount to get a authorization token 46 | 47 | $VerbosePreference = 'Continue' 48 | 49 | Write-Verbose "$(Get-Date -Format 'T') Starting Provision Environment" 50 | 51 | . "$PSScriptRoot\ProvisionEventStore.ps1" ` 52 | -ClusterSize 3 ` 53 | -DataDiskSize 160 ` 54 | -Location "West US" ` 55 | -InstanceSize "Medium" ` 56 | -username "admin-username" ` 57 | -password "admin-password" ` 58 | -ServiceName "cloud-service-name" ` 59 | -VMName "vm-name-prefix" ` 60 | -ImageName "a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-201502.01-en.us-127GB.vhd" ` 61 | -AffinityGroup "affinity-group-name" ` 62 | -TargetStorageAccountName "target-storage-account" ` 63 | -AvailabilitySetName "availability-set-name" ` 64 | -VNetName "virtual-network-name" ` 65 | -VNetSubnetName "subnet-name" ` 66 | -CustomScriptExtensionStorageAccountName "storage-account-name" ` 67 | -CustomScriptExtensionStorageAccountKey 'storage-account-key' ` 68 | -CustomScriptExtensionContainerName 'storage-account-container-name' ` 69 | -CustomScriptExtensionProvisionFile 'EventStoreScriptExtensionProvisionFile.ps1' 70 | 71 | Write-Verbose "$(Get-Date -Format 'T') Provision Complete" 72 | ``` 73 | 74 | Example output: 75 | ``` 76 | VERBOSE: 1:54:35 PM Starting Provision Environment 77 | VERBOSE: 1:54:35 PM Ensuring Affinity Group 'EventStore' exists and is in 'West US' location. 78 | VERBOSE: 1:54:35 PM - Begin Operation: Get-AzureAffinityGroup 79 | VERBOSE: 1:54:36 PM - Completed Operation: Get-AzureAffinityGroup 80 | VERBOSE: 1:54:36 PM - Begin Operation: Get-AzureStorageAccount 81 | VERBOSE: 1:54:37 PM - Completed Operation: Get-AzureStorageAccount 82 | WARNING: GeoReplicationEnabled property will be deprecated in a future release of Azure PowerShell. The value will be merged into the AccountType property. 83 | VERBOSE: 1:54:37 PM - Begin Operation: New-AzureStorageAccount 84 | VERBOSE: 1:55:09 PM - Completed Operation: New-AzureStorageAccount 85 | VERBOSE: 1:55:09 PM Waiting for storage account eventstoreaeugnjsexgyefy to be available... 86 | VERBOSE: 1:55:09 PM - Begin Operation: Get-AzureStorageAccount 87 | VERBOSE: 1:55:10 PM - Completed Operation: Get-AzureStorageAccount 88 | WARNING: GeoReplicationEnabled property will be deprecated in a future release of Azure PowerShell. The value will be merged into the AccountType property. 89 | VERBOSE: 1:55:12 PM Creating Virtual Machines 90 | VERBOSE: 1:55:12 PM - Begin Operation: New-AzureService 91 | VERBOSE: 1:55:14 PM - Completed Operation: New-AzureService 92 | VERBOSE: 1:55:14 PM - Begin Operation: Get-AzureRoleSize 93 | VERBOSE: 1:55:14 PM - Completed Operation: Get-AzureRoleSize 94 | VERBOSE: 1:55:28 PM - Begin Operation: New-AzureVM - Create Deployment with VM ES-demo-1 95 | VERBOSE: 1:56:40 PM - Completed Operation: New-AzureVM - Create Deployment with VM ES-demo-1 96 | VERBOSE: 1:56:40 PM - Begin Operation: New-AzureVM - Create VM ES-demo-2 97 | VERBOSE: 1:57:47 PM - Completed Operation: New-AzureVM - Create VM ES-demo-2 98 | VERBOSE: 1:57:47 PM - Begin Operation: New-AzureVM - Create VM ES-demo-3 99 | VERBOSE: 1:58:53 PM - Completed Operation: New-AzureVM - Create VM ES-demo-3 100 | VERBOSE: 1:58:53 PM Provision Complete 101 | ``` -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "EventStoreCluster", "EventStoreCluster\EventStoreCluster.deployproj", "{637B288B-477E-48A9-B609-F894EA0F566B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {637B288B-477E-48A9-B609-F894EA0F566B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {637B288B-477E-48A9-B609-F894EA0F566B}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {637B288B-477E-48A9-B609-F894EA0F566B}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {637B288B-477E-48A9-B609-F894EA0F566B}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/CreateStripedDataDisk.ps1: -------------------------------------------------------------------------------- 1 | Write-Verbose 'Creating Storage Pool' 2 | 3 | $storagePoolFriendlyName = 'LUN-0' 4 | $virtualDiskFriendlyName = 'Datastore01' 5 | $physicalDisks = Get-PhysicalDisk -CanPool $true 6 | $numberOfColumns = $physicalDisks.Length 7 | 8 | New-StoragePool -FriendlyName $storagePoolFriendlyName ` 9 | -StorageSubSystemUniqueId (Get-StorageSubSystem -FriendlyName '*Space*').uniqueID ` 10 | -PhysicalDisks $physicalDisks 11 | 12 | Write-Verbose 'Creating Virtual Disk' 13 | 14 | New-VirtualDisk -FriendlyName $virtualDiskFriendlyName ` 15 | -StoragePoolFriendlyName $storagePoolFriendlyName ` 16 | -UseMaximumSize ` 17 | -NumberOfColumns $NumberOfColumns ` 18 | -Interleave 65536 ` 19 | -ProvisioningType Fixed ` 20 | -ResiliencySettingName Simple 21 | 22 | Start-Sleep -Seconds 20 23 | 24 | Write-Verbose 'Initializing Disk' 25 | 26 | Initialize-Disk -VirtualDisk (Get-VirtualDisk -FriendlyName $virtualDiskFriendlyName) 27 | 28 | Start-Sleep -Seconds 20 29 | 30 | $diskNumber = ((Get-VirtualDisk -FriendlyName $virtualDiskFriendlyName | Get-Disk).Number) 31 | 32 | Write-Verbose 'Creating Partition' 33 | 34 | New-Partition -DiskNumber $diskNumber ` 35 | -UseMaximumSize ` 36 | -AssignDriveLetter ` 37 | -DriveLetter F 38 | 39 | Start-Sleep -Seconds 20 40 | 41 | Write-Verbose 'Formatting Volume and Assigning Drive Letter' 42 | 43 | Format-Volume -DriveLetter F ` 44 | -FileSystem NTFS ` 45 | -NewFileSystemLabel 'Data' ` 46 | -Confirm:$false ` 47 | -Force 48 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Deployment.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | bin\$(Configuration)\ 7 | false 8 | true 9 | false 10 | None 11 | obj\ 12 | $(BaseIntermediateOutputPath)\ 13 | $(BaseIntermediateOutputPath)$(Configuration)\ 14 | $(IntermediateOutputPath)ProjectReferences 15 | $(ProjectReferencesOutputPath)\ 16 | true 17 | 18 | 19 | 20 | false 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Always 33 | 34 | 35 | Never 36 | 37 | 38 | false 39 | Build 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | _GetDeploymentProjectContent; 48 | _CalculateContentOutputRelativePaths; 49 | _GetReferencedProjectsOutput; 50 | _CalculateArtifactStagingDirectory; 51 | _CopyOutputToArtifactStagingDirectory; 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | Configuration=$(Configuration);Platform=$(Platform) 69 | 70 | 71 | 75 | 76 | 77 | 78 | $([System.IO.Path]::GetFileNameWithoutExtension('%(ProjectReference.Identity)')) 79 | 80 | 81 | 82 | 83 | 84 | 85 | $(OutDir) 86 | $(OutputPath) 87 | $(ArtifactStagingDirectory)\ 88 | $(ArtifactStagingDirectory)staging\ 89 | $(Build_StagingDirectory) 90 | 91 | 92 | 93 | 94 | 96 | 97 | <_OriginalIdentity>%(DeploymentProjectContentOutput.Identity) 98 | <_RelativePath>$(_OriginalIdentity.Replace('$(MSBuildProjectDirectory)', '')) 99 | 100 | 101 | 102 | 103 | $(_RelativePath) 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | PrepareForRun 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/EventStoreCluster.deployproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | Release 10 | AnyCPU 11 | 12 | 13 | 14 | 637b288b-477e-48a9-b609-f894ea0f566b 15 | 16 | 17 | Deployment 18 | 1.0 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | False 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | False 57 | 58 | 59 | False 60 | 61 | 62 | False 63 | 64 | 65 | False 66 | 67 | 68 | False 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Scripts/Deploy-AzureResourceGroup.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 2 | 3 | Param( 4 | [string] [Parameter(Mandatory=$true)] $ResourceGroupLocation, 5 | [string] $ResourceGroupName = 'EventStoreCluster', 6 | [switch] $UploadArtifacts, 7 | [string] $StorageAccountName, 8 | [string] $StorageAccountResourceGroupName, 9 | [string] $StorageContainerName = $ResourceGroupName.ToLowerInvariant() + '-stageartifacts', 10 | [string] $TemplateFile = '..\Templates\azuredeploy.json', 11 | [string] $TemplateParametersFile = '..\Templates\azuredeploy.param.dev.json', 12 | [string] $ArtifactStagingDirectory = '..\bin\Debug\staging', 13 | [string] $AzCopyPath = '..\Tools\AzCopy.exe', 14 | [string] $DSCSourceFolder = '..\DSC' 15 | ) 16 | 17 | if (Get-Module -ListAvailable | Where-Object { $_.Name -eq 'AzureResourceManager' -and $_.Version -ge '1.5.1' }) { 18 | Throw "The version of the Azure PowerShell cmdlets installed on this machine are not compatible with this script. For help updating this script visit: http://go.microsoft.com/fwlink/?LinkID=623011" 19 | } 20 | 21 | Import-Module Azure -ErrorAction SilentlyContinue 22 | 23 | try { 24 | [Microsoft.Azure.Common.Authentication.AzureSession]::ClientFactory.AddUserAgent("VSAzureTools-$UI$($host.name)".replace(" ","_"), "2.7.1") 25 | } catch { } 26 | 27 | Set-StrictMode -Version 3 28 | 29 | $OptionalParameters = New-Object -TypeName Hashtable 30 | $TemplateFile = [System.IO.Path]::Combine($PSScriptRoot, $TemplateFile) 31 | $TemplateParametersFile = [System.IO.Path]::Combine($PSScriptRoot, $TemplateParametersFile) 32 | 33 | if ($UploadArtifacts) 34 | { 35 | # Convert relative paths to absolute paths if needed 36 | $AzCopyPath = [System.IO.Path]::Combine($PSScriptRoot, $AzCopyPath) 37 | $ArtifactStagingDirectory = [System.IO.Path]::Combine($PSScriptRoot, $ArtifactStagingDirectory) 38 | $DSCSourceFolder = [System.IO.Path]::Combine($PSScriptRoot, $DSCSourceFolder) 39 | 40 | Set-Variable ArtifactsLocationName '_artifactsLocation' -Option ReadOnly 41 | Set-Variable ArtifactsLocationSasTokenName '_artifactsLocationSasToken' -Option ReadOnly 42 | 43 | $OptionalParameters.Add($ArtifactsLocationName, $null) 44 | $OptionalParameters.Add($ArtifactsLocationSasTokenName, $null) 45 | 46 | # Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present 47 | $JsonContent = Get-Content $TemplateParametersFile -Raw | ConvertFrom-Json 48 | $JsonParameters = $JsonContent | Get-Member -Type NoteProperty | Where-Object {$_.Name -eq "parameters"} 49 | 50 | if ($JsonParameters -eq $null) { 51 | $JsonParameters = $JsonContent 52 | } 53 | else { 54 | $JsonParameters = $JsonContent.parameters 55 | } 56 | 57 | $JsonParameters | Get-Member -Type NoteProperty | ForEach-Object { 58 | $ParameterValue = $JsonParameters | Select-Object -ExpandProperty $_.Name 59 | 60 | if ($_.Name -eq $ArtifactsLocationName -or $_.Name -eq $ArtifactsLocationSasTokenName) { 61 | $OptionalParameters[$_.Name] = $ParameterValue.value 62 | } 63 | } 64 | 65 | if ($StorageAccountResourceGroupName) { 66 | # Switch-AzureMode AzureResourceManager 67 | $StorageAccountKey = (Get-AzureStorageAccountKey -ResourceGroupName $StorageAccountResourceGroupName -Name $StorageAccountName).Key1 68 | } 69 | else { 70 | # Switch-AzureMode AzureServiceManagement 71 | $StorageAccountKey = (Get-AzureStorageKey -StorageAccountName $StorageAccountName).Primary 72 | } 73 | 74 | $StorageAccountContext = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey 75 | 76 | # Create DSC configuration archive 77 | if (Test-Path $DSCSourceFolder) { 78 | Add-Type -Assembly System.IO.Compression.FileSystem 79 | $ArchiveFile = Join-Path $ArtifactStagingDirectory "dsc.zip" 80 | Remove-Item -Path $ArchiveFile -ErrorAction SilentlyContinue 81 | [System.IO.Compression.ZipFile]::CreateFromDirectory($DSCSourceFolder, $ArchiveFile) 82 | } 83 | 84 | # Generate the value for artifacts location if it is not provided in the parameter file 85 | $ArtifactsLocation = $OptionalParameters[$ArtifactsLocationName] 86 | if ($ArtifactsLocation -eq $null) { 87 | $ArtifactsLocation = $StorageAccountContext.BlobEndPoint + $StorageContainerName 88 | $OptionalParameters[$ArtifactsLocationName] = $ArtifactsLocation 89 | } 90 | 91 | # Use AzCopy to copy files from the local storage drop path to the storage account container 92 | & $AzCopyPath """$ArtifactStagingDirectory""", $ArtifactsLocation, "/DestKey:$StorageAccountKey", "/S", "/Y", "/Z:$env:LocalAppData\Microsoft\Azure\AzCopy\$ResourceGroupName" 93 | 94 | # Generate the value for artifacts location SAS token if it is not provided in the parameter file 95 | $ArtifactsLocationSasToken = $OptionalParameters[$ArtifactsLocationSasTokenName] 96 | if ($ArtifactsLocationSasToken -eq $null) { 97 | # Create a SAS token for the storage container - this gives temporary read-only access to the container (defaults to 1 hour). 98 | $ArtifactsLocationSasToken = New-AzureStorageContainerSASToken -Container $StorageContainerName -Context $StorageAccountContext -Permission r 99 | $ArtifactsLocationSasToken = ConvertTo-SecureString $ArtifactsLocationSasToken -AsPlainText -Force 100 | $OptionalParameters[$ArtifactsLocationSasTokenName] = $ArtifactsLocationSasToken 101 | } 102 | } 103 | 104 | # Create or update the resource group using the specified template file and template parameters file 105 | # Switch-AzureMode AzureResourceManager 106 | Login-AzureRmAccount 107 | New-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation 108 | New-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName ` 109 | -TemplateFile $TemplateFile ` 110 | -TemplateParameterFile $TemplateParametersFile ` 111 | @OptionalParameters ` 112 | -Force -Verbose 113 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Admin username used when provisioning virtual machines" 9 | } 10 | }, 11 | "adminPassword": { 12 | "type": "securestring", 13 | "metadata": { 14 | "description": "Admin password used when provisioning virtual machines" 15 | } 16 | }, 17 | "location": { 18 | "type": "string", 19 | "allowedValues": [ 20 | "ResourceGroup", 21 | "Brazil South", 22 | "Canada Central", 23 | "Canada East", 24 | "Central US", 25 | "East Asia", 26 | "East US", 27 | "East US 2", 28 | "Japan East", 29 | "Japan West", 30 | "North Central US", 31 | "North Europe", 32 | "South Central US", 33 | "Southeast Asia", 34 | "West Central US", 35 | "West Europe", 36 | "West US", 37 | "West US 2" 38 | ], 39 | "defaultValue": "ResourceGroup", 40 | "metadata": { 41 | "description": "Location where resources will be provisioned. A value of 'ResourceGroup' will deploy the resource to the same location of the resource group the resources are provisioned into" 42 | } 43 | }, 44 | "virtualNetworkName": { 45 | "type": "string", 46 | "defaultValue": "es-vnet", 47 | "metadata": { 48 | "description": "Virtual Network" 49 | } 50 | }, 51 | "OS": { 52 | "type": "string", 53 | "defaultValue": "windows", 54 | "allowedValues": [ 55 | "ubuntu", 56 | "windows" 57 | ], 58 | "metadata": { 59 | "description": "The operating system to deploy Event Store cluster on" 60 | } 61 | }, 62 | "jumpbox": { 63 | "type": "string", 64 | "defaultValue": "No", 65 | "allowedValues": [ 66 | "Yes", 67 | "No" 68 | ], 69 | "metadata": { 70 | "description": "Optionally add a virtual machine to the deployment which you can use to connect and manage virtual machines on the internal network" 71 | } 72 | }, 73 | "vmEventStoreNodeCount": { 74 | "type": "int", 75 | "defaultValue": 1, 76 | "allowedValues": [ 77 | 1, 78 | 3, 79 | 5, 80 | 7, 81 | 9 82 | ], 83 | "metadata": { 84 | "description": "Number of Event Store client nodes to provision" 85 | } 86 | }, 87 | "vmSizeEventStoreNode": { 88 | "type": "string", 89 | "defaultValue": "Standard_D2", 90 | "allowedValues": [ 91 | "Standard_D1", 92 | "Standard_D2", 93 | "Standard_D3", 94 | "Standard_D4", 95 | "Standard_A2", 96 | "Standard_A3", 97 | "Standard_A4", 98 | "Standard_A7", 99 | "Standard_DS1", 100 | "Standard_DS2", 101 | "Standard_DS3", 102 | "Standard_DS4", 103 | "Standard_DS13" 104 | ], 105 | "metadata": { 106 | "description": "Size of the Event Store data nodes" 107 | } 108 | }, 109 | "vmEventStoreDataDiskSize": { 110 | "type": "int", 111 | "defaultValue": 4, 112 | "metadata": { 113 | "description": "Size of each data disk attached to data nodes in (Gb). You can only pool disks that have 4GB of contiguous unallocated space." 114 | } 115 | }, 116 | "esVersion": { 117 | "type": "string", 118 | "defaultValue": "3.8.1", 119 | "allowedValues": [ 120 | "3.8.1", 121 | "3.8.0", 122 | "3.7.0", 123 | "3.6.3", 124 | "3.6.2", 125 | "3.6.1", 126 | "3.6.0", 127 | "3.5.0", 128 | "3.4.0", 129 | "3.3.1", 130 | "3.3.0", 131 | "3.2.2", 132 | "3.2.1", 133 | "3.2.0", 134 | "3.1.0", 135 | "3.0.5", 136 | "3.0.3", 137 | "3.0.2", 138 | "3.0.1", 139 | "3.0.0" 140 | ], 141 | "metadata": { 142 | "description": "Event Store version to install" 143 | } 144 | }, 145 | "githubAccount": { 146 | "type": "string", 147 | "defaultValue": "pbolduc", 148 | "metadata": { 149 | "description": "The GitHub account to use down load the resource manager template assets (ie scripts to download, install and configure the VMs). You will only need to change this if you have your own copy or working of a separate branch." 150 | } 151 | }, 152 | "githubProject": { 153 | "type": "string", 154 | "defaultValue": "EventStore-DevOps", 155 | "metadata": { 156 | "description": "The GitHub project to down load the resource manager templates assets (ie scripts to download, install and configure the VMs). You will only need to change this if you have your own copy or working of a separate branch." 157 | } 158 | }, 159 | "githubBranch": { 160 | "type": "string", 161 | "defaultValue": "master", 162 | "metadata": { 163 | "description": "The GitHub branch to use down load the resource manager templates assets (ie scripts to download, install and configure the VMs). You will only need to change this if you have your own copy or working of a separate branch." 164 | } 165 | } 166 | }, 167 | "variables": { 168 | "templateBaseUrl": "[concat('https://raw.githubusercontent.com/',parameters('githubAccount'),'/',parameters('githubProject'),'/',parameters('githubBranch'),'/azure-resource-manager/EventStoreCluster/Templates/')]", 169 | "locationMap": { 170 | "ResourceGroup": "[resourceGroup().location]", 171 | "Brazil South": "[parameters('location')]", 172 | "Canada Central": "[parameters('location')]", 173 | "Canada East": "[parameters('location')]", 174 | "Central US": "[parameters('location')]", 175 | "East Asia": "[parameters('location')]", 176 | "East US": "[parameters('location')]", 177 | "East US 2": "[parameters('location')]", 178 | "Japan East": "[parameters('location')]", 179 | "Japan West": "[parameters('location')]", 180 | "North Central US": "[parameters('location')]", 181 | "North Europe": "[parameters('location')]", 182 | "South Central US": "[parameters('location')]", 183 | "Southeast Asia": "[parameters('location')]", 184 | "West Central US": "[parameters('location')]", 185 | "West Europe": "[parameters('location')]", 186 | "West US": "[parameters('location')]", 187 | "West US 2": "[parameters('location')]" 188 | }, 189 | "location": "[variables('locationMap')[parameters('location')]]", 190 | "storageAccountPrefix": "esdata", 191 | "storageAccountNameShared": "[concat(variables('storageAccountPrefix'), 's', uniqueString(resourceGroup().id, deployment().name))]", 192 | "networkSettings": { 193 | "virtualNetworkName": "[parameters('virtualNetworkName')]", 194 | "networkSecurityGroupName": "[concat(parameters('virtualNetworkName'), '-nsg')]", 195 | "addressPrefix": "10.0.0.0/16", 196 | "subnet": { 197 | "eventstore": { 198 | "name": "eventstore", 199 | "prefix": "10.0.1.0/28", 200 | "networkPrefix": "10.0.1", 201 | "vnet": "[parameters('virtualNetworkName')]" 202 | } 203 | } 204 | }, 205 | "sharedTemplateUrl": "[concat(variables('templateBaseUrl'), 'shared-resources.json')]", 206 | "jumpboxTemplateYes": "jumpbox-resources.json", 207 | "jumpboxTemplateNo": "empty-resources.json", 208 | "jumpboxTemplateUrl": "[concat(variables('templateBaseUrl'), variables(concat('jumpboxTemplate',parameters('jumpbox'))))]", 209 | "windowsScripts": [ 210 | "[concat(variables('templateBaseUrl'), 'master.ps1')]", 211 | "[concat(variables('templateBaseUrl'), 'create-data-disks.ps1')]", 212 | "[concat(variables('templateBaseUrl'), 'install-eventstore.ps1')]", 213 | "[concat(variables('templateBaseUrl'), 'eventstore-windows-sources.csv')]", 214 | "[concat(variables('templateBaseUrl'), 'install-nginx.ps1')]" 215 | ], 216 | "windowsSettings": { 217 | "imageReference": { 218 | "publisher": "MicrosoftWindowsServer", 219 | "offer": "WindowsServer", 220 | "sku": "2012-R2-Datacenter", 221 | "version": "latest" 222 | }, 223 | "managementPort": "3389", 224 | "extentionSettings": { 225 | "eventstore": { 226 | "publisher": "Microsoft.Compute", 227 | "type": "CustomScriptExtension", 228 | "typeHandlerVersion": "1.8", 229 | "autoUpgradeMinorVersion": true, 230 | "settings": { 231 | "fileUris": "[variables('windowsScripts')]", 232 | "commandToExecute": "[concat('powershell.exe -File master.ps1 -ClusterSize ',parameters('vmEventStoreNodeCount'),' -esVer ',parameters('esVersion'))]" 233 | } 234 | } 235 | } 236 | }, 237 | "osSettings": "[variables(concat(parameters('OS'), 'Settings'))]", 238 | "virtualMachineSkuSettings": { 239 | "Standard_D1": { 240 | "dataDisks": 2, 241 | "nodesPerStorageAccount": 6, 242 | "storageAccountType": "Standard_LRS" 243 | }, 244 | "Standard_D2": { 245 | "dataDisks": 4, 246 | "nodesPerStorageAccount": 4, 247 | "storageAccountType": "Standard_LRS" 248 | }, 249 | "Standard_D3": { 250 | "dataDisks": 8, 251 | "nodesPerStorageAccount": 3, 252 | "storageAccountType": "Standard_LRS" 253 | }, 254 | "Standard_D4": { 255 | "dataDisks": 16, 256 | "nodesPerStorageAccount": 2, 257 | "storageAccountType": "Standard_LRS" 258 | }, 259 | "Standard_DS1": { 260 | "dataDisks": 2, 261 | "nodesPerStorageAccount": 6, 262 | "storageAccountType": "Premium_LRS" 263 | }, 264 | "Standard_DS2": { 265 | "dataDisks": 4, 266 | "nodesPerStorageAccount": 4, 267 | "storageAccountType": "Premium_LRS" 268 | }, 269 | "Standard_DS3": { 270 | "dataDisks": 8, 271 | "nodesPerStorageAccount": 4, 272 | "storageAccountType": "Premium_LRS" 273 | }, 274 | "Standard_DS4": { 275 | "dataDisks": 16, 276 | "nodesPerStorageAccount": 2, 277 | "storageAccountType": "Premium_LRS" 278 | }, 279 | "Standard_DS13": { 280 | "dataDisks": 16, 281 | "nodesPerStorageAccount": 2, 282 | "storageAccountType": "Premium_LRS" 283 | }, 284 | "Standard_A2": { 285 | "dataDisks": 4, 286 | "nodesPerStorageAccount": 6, 287 | "storageAccountType": "Standard_LRS" 288 | }, 289 | "Standard_A3": { 290 | "dataDisks": 8, 291 | "nodesPerStorageAccount": 4, 292 | "storageAccountType": "Standard_LRS" 293 | }, 294 | "Standard_A4": { 295 | "dataDisks": 16, 296 | "nodesPerStorageAccount": 2, 297 | "storageAccountType": "Standard_LRS" 298 | }, 299 | "Standard_A7": { 300 | "dataDisks": 16, 301 | "nodesPerStorageAccount": 2, 302 | "storageAccountType": "Standard_LRS" 303 | } 304 | }, 305 | "eventStoreClusterNodesPerStorageAccount": "[variables('virtualMachineSkuSettings')[parameters('vmSizeEventStoreNode')].nodesPerStorageAccount]", 306 | "storageBinPackMap": [ 307 | "[div(sub(add(1, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 308 | "[div(sub(add(2, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 309 | "[div(sub(add(3, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 310 | "[div(sub(add(4, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 311 | "[div(sub(add(5, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 312 | "[div(sub(add(6, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 313 | "[div(sub(add(7, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 314 | "[div(sub(add(8, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 315 | "[div(sub(add(9, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 316 | "[div(sub(add(10, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 317 | "[div(sub(add(11, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 318 | "[div(sub(add(12, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 319 | "[div(sub(add(13, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 320 | "[div(sub(add(14, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 321 | "[div(sub(add(15, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 322 | "[div(sub(add(16, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 323 | "[div(sub(add(17, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 324 | "[div(sub(add(18, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 325 | "[div(sub(add(19, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 326 | "[div(sub(add(20, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 327 | "[div(sub(add(21, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 328 | "[div(sub(add(22, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 329 | "[div(sub(add(23, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 330 | "[div(sub(add(24, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 331 | "[div(sub(add(25, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 332 | "[div(sub(add(26, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 333 | "[div(sub(add(27, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 334 | "[div(sub(add(28, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 335 | "[div(sub(add(29, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 336 | "[div(sub(add(30, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 337 | "[div(sub(add(31, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 338 | "[div(sub(add(32, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 339 | "[div(sub(add(33, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 340 | "[div(sub(add(34, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 341 | "[div(sub(add(35, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 342 | "[div(sub(add(36, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 343 | "[div(sub(add(37, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 344 | "[div(sub(add(38, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 345 | "[div(sub(add(39, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 346 | "[div(sub(add(40, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 347 | "[div(sub(add(51, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 348 | "[div(sub(add(52, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 349 | "[div(sub(add(53, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 350 | "[div(sub(add(54, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 351 | "[div(sub(add(55, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 352 | "[div(sub(add(56, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 353 | "[div(sub(add(57, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 354 | "[div(sub(add(58, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 355 | "[div(sub(add(59, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 356 | "[div(sub(add(60, variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]" 357 | ], 358 | "clusterNodeStorageSettings": { 359 | "count": "[div(sub(add(parameters('vmEventStoreNodeCount'), variables('eventStoreClusterNodesPerStorageAccount')), 1), variables('eventStoreClusterNodesPerStorageAccount'))]", 360 | "mapping": "[variables('storageBinPackMap')]", 361 | "accountType": "[variables('virtualMachineSkuSettings')[parameters('vmSizeEventStoreNode')].storageAccountType]", 362 | "prefix": "[concat(variables('storageAccountPrefix'), 'd', uniqueString(resourceGroup().id, deployment().name))]" 363 | }, 364 | "clusterNodeTemplateUrl": "[concat(variables('templateBaseUrl'), 'cluster-nodes-', string(variables('virtualMachineSkuSettings')[parameters('vmSizeEventStoreNode')].dataDisks), 'disk-resources.json')]", 365 | }, 366 | "resources": [ 367 | { 368 | "name": "shared", 369 | "type": "Microsoft.Resources/deployments", 370 | "apiVersion": "2015-01-01", 371 | "properties": { 372 | "mode": "Incremental", 373 | "templateLink": { 374 | "uri": "[variables('sharedTemplateUrl')]", 375 | "contentVersion": "1.0.0.0" 376 | }, 377 | "parameters": { 378 | "location": { 379 | "value": "[variables('location')]" 380 | }, 381 | "networkSettings": { 382 | "value": "[variables('networkSettings')]" 383 | }, 384 | "storageAccountName": { 385 | "value": "[variables('storageAccountNameShared')]" 386 | }, 387 | "subnet": { "value": "eventstore" } 388 | } 389 | } 390 | }, 391 | { 392 | "name": "cluster-nodes", 393 | "type": "Microsoft.Resources/deployments", 394 | "apiVersion": "2015-01-01", 395 | "dependsOn": [ 396 | "[concat('Microsoft.Resources/deployments/', 'shared')]" 397 | ], 398 | "properties": { 399 | "mode": "Incremental", 400 | "templateLink": { 401 | "uri": "[variables('clusterNodeTemplateUrl')]", 402 | "contentVersion": "1.0.0.0" 403 | }, 404 | "parameters": { 405 | "adminUsername": { 406 | "value": "[parameters('adminUsername')]" 407 | }, 408 | "adminPassword": { 409 | "value": "[parameters('adminPassword')]" 410 | }, 411 | "location": { 412 | "value": "[variables('location')]" 413 | }, 414 | "storageSettings": { 415 | "value": "[variables('clusterNodeStorageSettings')]" 416 | }, 417 | "subnet": { 418 | "value": "[variables('networkSettings').subnet.eventstore]" 419 | }, 420 | "vmSize": { 421 | "value": "[parameters('vmSizeEventStoreNode')]" 422 | }, 423 | "vmCount": { 424 | "value": "[parameters('vmEventStoreNodeCount')]" 425 | }, 426 | "dataDiskSize": { 427 | "value": "[parameters('vmEventStoreDataDiskSize')]" 428 | }, 429 | "namespace": { 430 | "value": "es" 431 | }, 432 | "osSettings": { 433 | "value": "[variables('osSettings')]" 434 | } 435 | } 436 | } 437 | } 438 | ], 439 | "outputs": { 440 | } 441 | } 442 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/azuredeploy.param.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "value": "EventStoreAdmin" 7 | }, 8 | "adminPassword": { 9 | "value": "YourEventStoreVMPassword" 10 | }, 11 | "jumpbox": { 12 | "value": "No" 13 | }, 14 | "vmEventStoreNodeCount": { 15 | "value": 3 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/cluster-nodes-0disk-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Admin username used when provisioning virtual machines" 9 | } 10 | }, 11 | "adminPassword": { 12 | "type": "securestring", 13 | "metadata": { 14 | "description": "Admin password used when provisioning virtual machines" 15 | } 16 | }, 17 | "storageSettings": { 18 | "type": "object", 19 | "metadata": { 20 | "description": "Storage Account Settings" 21 | } 22 | }, 23 | "location": { 24 | "type": "string", 25 | "metadata": { 26 | "description": "Location where resources will be provisioned" 27 | } 28 | }, 29 | "subnet": { 30 | "type": "object", 31 | "metadata": { 32 | "description": "The name of the subnet to deploy resources into" 33 | } 34 | }, 35 | "vmSize": { 36 | "type": "string", 37 | "defaultValue": "Standard_A1", 38 | "metadata": { 39 | "description": "Size of the Elasticsearch data nodes" 40 | } 41 | }, 42 | "vmCount": { 43 | "type": "int", 44 | "defaultValue": 2, 45 | "metadata": { 46 | "description": "Number of Elasticsearch data nodes" 47 | } 48 | }, 49 | "osSettings": { 50 | "type": "object", 51 | "metadata": { 52 | "description": "OS settings to deploy on" 53 | } 54 | }, 55 | "dataDiskSize": { 56 | "type": "int", 57 | "defaultValue": 1023, 58 | "metadata": { 59 | "description": "Size of each data disk attached to data nodes in (Gb)" 60 | } 61 | }, 62 | "namespace": { 63 | "type": "string", 64 | "metadata": { 65 | "description": "The namespace for resources created by this template" 66 | } 67 | } 68 | }, 69 | "variables": { 70 | "vmStorageAccountContainerName": "vhd", 71 | "subnetRef": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('subnet').vnet), '/subnets/', parameters('subnet').name)]", 72 | "storageAccountName": "[concat(parameters('storageSettings').prefix)]", 73 | "vmName": "[concat(parameters('namespace'), 'vm')]" 74 | }, 75 | "resources": [ 76 | { 77 | "type": "Microsoft.Storage/storageAccounts", 78 | "name": "[concat(variables('storageAccountName'), copyIndex(1))]", 79 | "apiVersion": "2015-05-01-preview", 80 | "location": "[parameters('location')]", 81 | "copy": { 82 | "name": "[concat(parameters('namespace'),'storageLoop')]", 83 | "count": "[parameters('storageSettings').count]" 84 | }, 85 | "properties": { 86 | "accountType": "[parameters('storageSettings').accountType]" 87 | } 88 | }, 89 | { 90 | "apiVersion": "2015-06-15", 91 | "type": "Microsoft.Compute/availabilitySets", 92 | "name": "[concat(parameters('namespace'), '-set')]", 93 | "location": "[parameters('location')]", 94 | "properties": { 95 | "platformUpdateDomainCount": 20, 96 | "platformFaultDomainCount": 3 97 | } 98 | }, 99 | { 100 | "apiVersion": "2015-06-15", 101 | "type": "Microsoft.Network/networkInterfaces", 102 | "name": "[concat(parameters('namespace'), 'nic', copyIndex())]", 103 | "location": "[parameters('location')]", 104 | "copy": { 105 | "name": "[concat(parameters('namespace'),'nicLoop')]", 106 | "count": "[parameters('vmCount')]" 107 | }, 108 | "properties": { 109 | "ipConfigurations": [ 110 | { 111 | "name": "ipconfig1", 112 | "properties": { 113 | "privateIPAllocationMethod": "Dynamic", 114 | "subnet": { 115 | "id": "[variables('subnetRef')]" 116 | } 117 | } 118 | } 119 | ] 120 | } 121 | }, 122 | { 123 | "apiVersion": "2015-06-15", 124 | "type": "Microsoft.Compute/virtualMachines", 125 | "name": "[concat(parameters('namespace'), 'vm', copyIndex())]", 126 | "location": "[parameters('location')]", 127 | "copy": { 128 | "name": "[concat(parameters('namespace'), 'virtualMachineLoop')]", 129 | "count": "[parameters('vmCount')]" 130 | }, 131 | "dependsOn": [ 132 | "[concat('Microsoft.Network/networkInterfaces/', parameters('namespace'), 'nic', copyIndex())]", 133 | "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()])]" 134 | ], 135 | "properties": { 136 | "availabilitySet": { 137 | "id": "[resourceId('Microsoft.Compute/availabilitySets', concat(parameters('namespace'), '-set'))]" 138 | }, 139 | "hardwareProfile": { 140 | "vmSize": "[parameters('vmSize')]" 141 | }, 142 | "osProfile": { 143 | "computerName": "[concat(parameters('namespace'), 'vm', copyIndex())]", 144 | "adminUsername": "[parameters('adminUsername')]", 145 | "adminPassword": "[parameters('adminPassword')]" 146 | }, 147 | "storageProfile": { 148 | "imageReference": "[parameters('osSettings').imageReference]", 149 | "osDisk": { 150 | "name": "osdisk", 151 | "vhd": { 152 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()], '.blob.core.windows.net/vhd/', variables('vmName'), copyIndex(), '-osdisk.vhd')]" 153 | }, 154 | "caching": "ReadWrite", 155 | "createOption": "FromImage" 156 | } 157 | }, 158 | "networkProfile": { 159 | "networkInterfaces": [ 160 | { 161 | "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(parameters('namespace'),'nic', copyIndex()))]" 162 | } 163 | ] 164 | } 165 | }, 166 | "resources": [ 167 | { 168 | "type": "Microsoft.Compute/virtualMachines/extensions", 169 | "name": "[concat(parameters('namespace'),'-vm-', copyIndex(), '/installapplications')]", 170 | "location": "[parameters('location')]", 171 | "apiVersion": "2015-06-15", 172 | "dependsOn": [ 173 | "[concat('Microsoft.Compute/virtualMachines/', parameters('namespace'), '-vm-', copyIndex())]" 174 | ], 175 | "properties": "[parameters('osSettings').extentionSettings.eventstore]" 176 | } 177 | ] 178 | } 179 | ] 180 | } -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/cluster-nodes-16disk-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Admin username used when provisioning virtual machines" 9 | } 10 | }, 11 | "adminPassword": { 12 | "type": "securestring", 13 | "metadata": { 14 | "description": "Admin password used when provisioning virtual machines" 15 | } 16 | }, 17 | "storageSettings": { 18 | "type": "object", 19 | "metadata": { 20 | "description": "Storage Account Settings" 21 | } 22 | }, 23 | "location": { 24 | "type": "string", 25 | "metadata": { 26 | "description": "Location where resources will be provisioned" 27 | } 28 | }, 29 | "subnet": { 30 | "type": "object", 31 | "metadata": { 32 | "description": "The name of the subnet to deploy resources into" 33 | } 34 | }, 35 | "vmSize": { 36 | "type": "string", 37 | "defaultValue": "Standard_A1", 38 | "metadata": { 39 | "description": "Size of the Elasticsearch data nodes" 40 | } 41 | }, 42 | "vmCount": { 43 | "type": "int", 44 | "defaultValue": 2, 45 | "metadata": { 46 | "description": "Number of Elasticsearch data nodes" 47 | } 48 | }, 49 | "osSettings": { 50 | "type": "object", 51 | "metadata": { 52 | "description": "OS settings to deploy on" 53 | } 54 | }, 55 | "dataDiskSize": { 56 | "type": "int", 57 | "defaultValue": 1023, 58 | "metadata": { 59 | "description": "Size of each data disk attached to data nodes in (Gb)" 60 | } 61 | }, 62 | "namespace": { 63 | "type": "string", 64 | "metadata": { 65 | "description": "The namespace for resources created by this template" 66 | } 67 | } 68 | }, 69 | "variables": { 70 | "vmStorageAccountContainerName": "vhd", 71 | "subnetRef": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('subnet').vnet), '/subnets/', parameters('subnet').name)]", 72 | "storageAccountName": "[concat(parameters('storageSettings').prefix)]", 73 | "vmName": "[parameters('namespace')]" 74 | }, 75 | "resources": [ 76 | { 77 | "type": "Microsoft.Storage/storageAccounts", 78 | "name": "[concat(variables('storageAccountName'), copyIndex(1))]", 79 | "apiVersion": "2015-05-01-preview", 80 | "location": "[parameters('location')]", 81 | "copy": { 82 | "name": "[concat(parameters('namespace'),'storageLoop')]", 83 | "count": "[parameters('storageSettings').count]" 84 | }, 85 | "properties": { 86 | "accountType": "[parameters('storageSettings').accountType]" 87 | } 88 | }, 89 | { 90 | "apiVersion": "2015-06-15", 91 | "type": "Microsoft.Compute/availabilitySets", 92 | "name": "[concat(parameters('namespace'), '-set')]", 93 | "location": "[parameters('location')]", 94 | "properties": { 95 | "platformUpdateDomainCount": 20, 96 | "platformFaultDomainCount": 3 97 | } 98 | }, 99 | { 100 | "apiVersion": "2015-06-15", 101 | "type": "Microsoft.Network/publicIPAddresses", 102 | "name": "[concat(parameters('namespace'), '-pip-', copyIndex())]", 103 | "location": "[parameters('location')]", 104 | "copy": { 105 | "name": "[concat(parameters('namespace'),'pipLoop')]", 106 | "count": "[parameters('vmCount')]" 107 | }, 108 | "properties": { 109 | "publicIPAllocationMethod": "Dynamic" 110 | } 111 | }, 112 | { 113 | "apiVersion": "2015-06-15", 114 | "type": "Microsoft.Network/networkInterfaces", 115 | "name": "[concat(parameters('namespace'), '-nic-', copyIndex())]", 116 | "location": "[parameters('location')]", 117 | "copy": { 118 | "name": "[concat(parameters('namespace'),'nicLoop')]", 119 | "count": "[parameters('vmCount')]" 120 | }, 121 | "dependsOn": [ 122 | "[concat('Microsoft.Network/publicIPAddresses/', parameters('namespace'), '-pip-', copyIndex())]" 123 | ], 124 | "properties": { 125 | "ipConfigurations": [ 126 | { 127 | "name": "ipconfig1", 128 | "properties": { 129 | "privateIPAddress": "[concat(parameters('subnet').networkPrefix, '.', string(add(4,copyIndex())))]", 130 | "privateIPAllocationMethod": "Static", 131 | "subnet": { 132 | "id": "[variables('subnetRef')]" 133 | } 134 | } 135 | } 136 | ] 137 | } 138 | }, 139 | { 140 | "apiVersion": "2015-06-15", 141 | "type": "Microsoft.Compute/virtualMachines", 142 | "name": "[concat(parameters('namespace'), '-vm-', copyIndex())]", 143 | "location": "[parameters('location')]", 144 | "copy": { 145 | "name": "[concat(parameters('namespace'), 'virtualMachineLoop')]", 146 | "count": "[parameters('vmCount')]" 147 | }, 148 | "dependsOn": [ 149 | "[concat('Microsoft.Network/networkInterfaces/', parameters('namespace'), '-nic-', copyIndex())]", 150 | "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()])]" 151 | ], 152 | "properties": { 153 | "availabilitySet": { 154 | "id": "[resourceId('Microsoft.Compute/availabilitySets', concat(parameters('namespace'), '-set'))]" 155 | }, 156 | "hardwareProfile": { 157 | "vmSize": "[parameters('vmSize')]" 158 | }, 159 | "osProfile": { 160 | "computerName": "[concat(parameters('namespace'), '-vm-', copyIndex())]", 161 | "adminUsername": "[parameters('adminUsername')]", 162 | "adminPassword": "[parameters('adminPassword')]" 163 | }, 164 | "storageProfile": { 165 | "imageReference": "[parameters('osSettings').imageReference]", 166 | "osDisk": { 167 | "name": "osdisk", 168 | "vhd": { 169 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()], '.blob.core.windows.net/vhds/', variables('vmName'), '-vm-', copyIndex(), '-osdisk.vhd')]" 170 | }, 171 | "caching": "ReadWrite", 172 | "createOption": "FromImage" 173 | }, 174 | "dataDisks": [ 175 | { 176 | "name": "datadisk1", 177 | "diskSizeGB": "[parameters('dataDiskSize')]", 178 | "lun": 0, 179 | "vhd": { 180 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk1' ,'.vhd')]" 181 | }, 182 | "caching": "None", 183 | "createOption": "Empty" 184 | }, 185 | { 186 | "name": "datadisk2", 187 | "diskSizeGB": "[parameters('dataDiskSize')]", 188 | "lun": 1, 189 | "vhd": { 190 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk2' ,'.vhd')]" 191 | }, 192 | "caching": "None", 193 | "createOption": "Empty" 194 | }, 195 | { 196 | "name": "datadisk3", 197 | "diskSizeGB": "[parameters('dataDiskSize')]", 198 | "lun": 2, 199 | "vhd": { 200 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk3' ,'.vhd')]" 201 | }, 202 | "caching": "None", 203 | "createOption": "Empty" 204 | }, 205 | { 206 | "name": "datadisk4", 207 | "diskSizeGB": "[parameters('dataDiskSize')]", 208 | "lun": 3, 209 | "vhd": { 210 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk4' ,'.vhd')]" 211 | }, 212 | "caching": "None", 213 | "createOption": "Empty" 214 | }, 215 | { 216 | "name": "datadisk5", 217 | "diskSizeGB": "[parameters('dataDiskSize')]", 218 | "lun": 4, 219 | "vhd": { 220 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk5' ,'.vhd')]" 221 | }, 222 | "caching": "None", 223 | "createOption": "Empty" 224 | }, 225 | { 226 | "name": "datadisk6", 227 | "diskSizeGB": "[parameters('dataDiskSize')]", 228 | "lun": 5, 229 | "vhd": { 230 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk6' ,'.vhd')]" 231 | }, 232 | "caching": "None", 233 | "createOption": "Empty" 234 | }, 235 | { 236 | "name": "datadisk7", 237 | "diskSizeGB": "[parameters('dataDiskSize')]", 238 | "lun": 6, 239 | "vhd": { 240 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk7' ,'.vhd')]" 241 | }, 242 | "caching": "None", 243 | "createOption": "Empty" 244 | }, 245 | { 246 | "name": "datadisk8", 247 | "diskSizeGB": "[parameters('dataDiskSize')]", 248 | "lun": 7, 249 | "vhd": { 250 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk8' ,'.vhd')]" 251 | }, 252 | "caching": "None", 253 | "createOption": "Empty" 254 | }, 255 | { 256 | "name": "datadisk9", 257 | "diskSizeGB": "[parameters('dataDiskSize')]", 258 | "lun": 8, 259 | "vhd": { 260 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk9' ,'.vhd')]" 261 | }, 262 | "caching": "None", 263 | "createOption": "Empty" 264 | }, 265 | { 266 | "name": "datadisk10", 267 | "diskSizeGB": "[parameters('dataDiskSize')]", 268 | "lun": 9, 269 | "vhd": { 270 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk10' ,'.vhd')]" 271 | }, 272 | "caching": "None", 273 | "createOption": "Empty" 274 | }, 275 | { 276 | "name": "datadisk11", 277 | "diskSizeGB": "[parameters('dataDiskSize')]", 278 | "lun": 10, 279 | "vhd": { 280 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk11' ,'.vhd')]" 281 | }, 282 | "caching": "None", 283 | "createOption": "Empty" 284 | }, 285 | { 286 | "name": "datadisk12", 287 | "diskSizeGB": "[parameters('dataDiskSize')]", 288 | "lun": 11, 289 | "vhd": { 290 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk12' ,'.vhd')]" 291 | }, 292 | "caching": "None", 293 | "createOption": "Empty" 294 | }, 295 | { 296 | "name": "datadisk13", 297 | "diskSizeGB": "[parameters('dataDiskSize')]", 298 | "lun": 12, 299 | "vhd": { 300 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk13' ,'.vhd')]" 301 | }, 302 | "caching": "None", 303 | "createOption": "Empty" 304 | }, 305 | { 306 | "name": "datadisk14", 307 | "diskSizeGB": "[parameters('dataDiskSize')]", 308 | "lun": 13, 309 | "vhd": { 310 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk14' ,'.vhd')]" 311 | }, 312 | "caching": "None", 313 | "createOption": "Empty" 314 | }, 315 | { 316 | "name": "datadisk15", 317 | "diskSizeGB": "[parameters('dataDiskSize')]", 318 | "lun": 14, 319 | "vhd": { 320 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk15' ,'.vhd')]" 321 | }, 322 | "caching": "None", 323 | "createOption": "Empty" 324 | }, 325 | { 326 | "name": "datadisk16", 327 | "diskSizeGB": "[parameters('dataDiskSize')]", 328 | "lun": 15, 329 | "vhd": { 330 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk16' ,'.vhd')]" 331 | }, 332 | "caching": "None", 333 | "createOption": "Empty" 334 | } 335 | ] 336 | }, 337 | "networkProfile": { 338 | "networkInterfaces": [ 339 | { 340 | "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(parameters('namespace'),'-nic-', copyIndex()))]" 341 | } 342 | ] 343 | } 344 | }, 345 | "resources": [ 346 | { 347 | "type": "Microsoft.Compute/virtualMachines/extensions", 348 | "name": "[concat(parameters('namespace'),'-vm-', copyIndex(), '/installapplications')]", 349 | "location": "[parameters('location')]", 350 | "apiVersion": "2015-06-15", 351 | "dependsOn": [ 352 | "[concat('Microsoft.Compute/virtualMachines/', parameters('namespace'), '-vm-', copyIndex())]" 353 | ], 354 | "properties": "[parameters('osSettings').extentionSettings.eventstore]" 355 | } 356 | ] 357 | } 358 | ] 359 | } -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/cluster-nodes-2disk-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Admin username used when provisioning virtual machines" 9 | } 10 | }, 11 | "adminPassword": { 12 | "type": "securestring", 13 | "metadata": { 14 | "description": "Admin password used when provisioning virtual machines" 15 | } 16 | }, 17 | "storageSettings": { 18 | "type": "object", 19 | "metadata": { 20 | "description": "Storage Account Settings" 21 | } 22 | }, 23 | "location": { 24 | "type": "string", 25 | "metadata": { 26 | "description": "Location where resources will be provisioned" 27 | } 28 | }, 29 | "subnet": { 30 | "type": "object", 31 | "metadata": { 32 | "description": "The name of the subnet to deploy resources into" 33 | } 34 | }, 35 | "vmSize": { 36 | "type": "string", 37 | "defaultValue": "Standard_A1", 38 | "metadata": { 39 | "description": "Size of the Elasticsearch data nodes" 40 | } 41 | }, 42 | "vmCount": { 43 | "type": "int", 44 | "defaultValue": 2, 45 | "metadata": { 46 | "description": "Number of Elasticsearch data nodes" 47 | } 48 | }, 49 | "osSettings": { 50 | "type": "object", 51 | "metadata": { 52 | "description": "OS settings to deploy on" 53 | } 54 | }, 55 | "dataDiskSize": { 56 | "type": "int", 57 | "defaultValue": 1023, 58 | "metadata": { 59 | "description": "Size of each data disk attached to data nodes in (Gb)" 60 | } 61 | }, 62 | "namespace": { 63 | "type": "string", 64 | "metadata": { 65 | "description": "The namespace for resources created by this template" 66 | } 67 | } 68 | }, 69 | "variables": { 70 | "vmStorageAccountContainerName": "vhd", 71 | "subnetRef": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('subnet').vnet), '/subnets/', parameters('subnet').name)]", 72 | "storageAccountName": "[concat(parameters('storageSettings').prefix)]", 73 | "vmName": "[parameters('namespace')]" 74 | }, 75 | "resources": [ 76 | { 77 | "type": "Microsoft.Storage/storageAccounts", 78 | "name": "[concat(variables('storageAccountName'), copyIndex(1))]", 79 | "apiVersion": "2015-05-01-preview", 80 | "location": "[parameters('location')]", 81 | "copy": { 82 | "name": "[concat(parameters('namespace'),'storageLoop')]", 83 | "count": "[parameters('storageSettings').count]" 84 | }, 85 | "properties": { 86 | "accountType": "[parameters('storageSettings').accountType]" 87 | } 88 | }, 89 | { 90 | "apiVersion": "2015-06-15", 91 | "type": "Microsoft.Compute/availabilitySets", 92 | "name": "[concat(parameters('namespace'), '-set')]", 93 | "location": "[parameters('location')]", 94 | "properties": { 95 | "platformUpdateDomainCount": 20, 96 | "platformFaultDomainCount": 3 97 | } 98 | }, 99 | { 100 | "apiVersion": "2015-06-15", 101 | "type": "Microsoft.Network/publicIPAddresses", 102 | "name": "[concat(parameters('namespace'), '-pip-', copyIndex())]", 103 | "location": "[parameters('location')]", 104 | "copy": { 105 | "name": "[concat(parameters('namespace'),'pipLoop')]", 106 | "count": "[parameters('vmCount')]" 107 | }, 108 | "properties": { 109 | "publicIPAllocationMethod": "Dynamic" 110 | } 111 | }, 112 | { 113 | "apiVersion": "2015-06-15", 114 | "type": "Microsoft.Network/networkInterfaces", 115 | "name": "[concat(parameters('namespace'), '-nic-', copyIndex())]", 116 | "location": "[parameters('location')]", 117 | "copy": { 118 | "name": "[concat(parameters('namespace'),'nicLoop')]", 119 | "count": "[parameters('vmCount')]" 120 | }, 121 | "dependsOn": [ 122 | "[concat('Microsoft.Network/publicIPAddresses/', parameters('namespace'), '-pip-', copyIndex())]" 123 | ], 124 | "properties": { 125 | "ipConfigurations": [ 126 | { 127 | "name": "ipconfig1", 128 | "properties": { 129 | "privateIPAddress": "[concat(parameters('subnet').networkPrefix, '.', string(add(4,copyIndex())))]", 130 | "privateIPAllocationMethod": "Static", 131 | "subnet": { 132 | "id": "[variables('subnetRef')]" 133 | } 134 | } 135 | } 136 | ] 137 | } 138 | }, 139 | { 140 | "apiVersion": "2015-06-15", 141 | "type": "Microsoft.Compute/virtualMachines", 142 | "name": "[concat(parameters('namespace'), '-vm-', copyIndex())]", 143 | "location": "[parameters('location')]", 144 | "copy": { 145 | "name": "[concat(parameters('namespace'), 'virtualMachineLoop')]", 146 | "count": "[parameters('vmCount')]" 147 | }, 148 | "dependsOn": [ 149 | "[concat('Microsoft.Network/networkInterfaces/', parameters('namespace'), '-nic-', copyIndex())]", 150 | "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()])]" 151 | ], 152 | "properties": { 153 | "availabilitySet": { 154 | "id": "[resourceId('Microsoft.Compute/availabilitySets', concat(parameters('namespace'), '-set'))]" 155 | }, 156 | "hardwareProfile": { 157 | "vmSize": "[parameters('vmSize')]" 158 | }, 159 | "osProfile": { 160 | "computerName": "[concat(parameters('namespace'), '-vm-', copyIndex())]", 161 | "adminUsername": "[parameters('adminUsername')]", 162 | "adminPassword": "[parameters('adminPassword')]" 163 | }, 164 | "storageProfile": { 165 | "imageReference": "[parameters('osSettings').imageReference]", 166 | "osDisk": { 167 | "name": "osdisk", 168 | "vhd": { 169 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()], '.blob.core.windows.net/vhds/', variables('vmName'), '-vm-', copyIndex(), '-osdisk.vhd')]" 170 | }, 171 | "caching": "ReadWrite", 172 | "createOption": "FromImage" 173 | }, 174 | "dataDisks": [ 175 | { 176 | "name": "datadisk1", 177 | "diskSizeGB": "[parameters('dataDiskSize')]", 178 | "lun": 0, 179 | "vhd": { 180 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk1' ,'.vhd')]" 181 | }, 182 | "caching": "None", 183 | "createOption": "Empty" 184 | }, 185 | { 186 | "name": "datadisk2", 187 | "diskSizeGB": "[parameters('dataDiskSize')]", 188 | "lun": 1, 189 | "vhd": { 190 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk2' ,'.vhd')]" 191 | }, 192 | "caching": "None", 193 | "createOption": "Empty" 194 | } 195 | ] 196 | }, 197 | "networkProfile": { 198 | "networkInterfaces": [ 199 | { 200 | "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(parameters('namespace'),'-nic-', copyIndex()))]" 201 | } 202 | ] 203 | } 204 | }, 205 | "resources": [ 206 | { 207 | "type": "Microsoft.Compute/virtualMachines/extensions", 208 | "name": "[concat(parameters('namespace'),'-vm-', copyIndex(), '/installapplications')]", 209 | "location": "[parameters('location')]", 210 | "apiVersion": "2015-06-15", 211 | "dependsOn": [ 212 | "[concat('Microsoft.Compute/virtualMachines/', parameters('namespace'), '-vm-', copyIndex())]" 213 | ], 214 | "properties": "[parameters('osSettings').extentionSettings.eventstore]" 215 | } 216 | ] 217 | } 218 | ] 219 | } -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/cluster-nodes-4disk-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Admin username used when provisioning virtual machines" 9 | } 10 | }, 11 | "adminPassword": { 12 | "type": "securestring", 13 | "metadata": { 14 | "description": "Admin password used when provisioning virtual machines" 15 | } 16 | }, 17 | "storageSettings": { 18 | "type": "object", 19 | "metadata": { 20 | "description": "Storage Account Settings" 21 | } 22 | }, 23 | "location": { 24 | "type": "string", 25 | "metadata": { 26 | "description": "Location where resources will be provisioned" 27 | } 28 | }, 29 | "subnet": { 30 | "type": "object", 31 | "metadata": { 32 | "description": "The name of the subnet to deploy resources into" 33 | } 34 | }, 35 | "vmSize": { 36 | "type": "string", 37 | "defaultValue": "Standard_A1", 38 | "metadata": { 39 | "description": "Size of the Elasticsearch data nodes" 40 | } 41 | }, 42 | "vmCount": { 43 | "type": "int", 44 | "defaultValue": 2, 45 | "metadata": { 46 | "description": "Number of Elasticsearch data nodes" 47 | } 48 | }, 49 | "osSettings": { 50 | "type": "object", 51 | "metadata": { 52 | "description": "OS settings to deploy on" 53 | } 54 | }, 55 | "dataDiskSize": { 56 | "type": "int", 57 | "defaultValue": 1023, 58 | "metadata": { 59 | "description": "Size of each data disk attached to data nodes in (Gb)" 60 | } 61 | }, 62 | "namespace": { 63 | "type": "string", 64 | "metadata": { 65 | "description": "The namespace for resources created by this template" 66 | } 67 | } 68 | }, 69 | "variables": { 70 | "vmStorageAccountContainerName": "vhd", 71 | "subnetRef": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('subnet').vnet), '/subnets/', parameters('subnet').name)]", 72 | "storageAccountName": "[concat(parameters('storageSettings').prefix)]", 73 | "vmName": "[parameters('namespace')]" 74 | }, 75 | "resources": [ 76 | { 77 | "type": "Microsoft.Storage/storageAccounts", 78 | "name": "[concat(variables('storageAccountName'), copyIndex(1))]", 79 | "apiVersion": "2015-05-01-preview", 80 | "location": "[parameters('location')]", 81 | "copy": { 82 | "name": "[concat(parameters('namespace'),'storageLoop')]", 83 | "count": "[parameters('storageSettings').count]" 84 | }, 85 | "properties": { 86 | "accountType": "[parameters('storageSettings').accountType]" 87 | } 88 | }, 89 | { 90 | "apiVersion": "2015-06-15", 91 | "type": "Microsoft.Compute/availabilitySets", 92 | "name": "[concat(parameters('namespace'), '-set')]", 93 | "location": "[parameters('location')]", 94 | "properties": { 95 | "platformUpdateDomainCount": 20, 96 | "platformFaultDomainCount": 3 97 | } 98 | }, 99 | { 100 | "apiVersion": "2015-06-15", 101 | "type": "Microsoft.Network/publicIPAddresses", 102 | "name": "[concat(parameters('namespace'), '-pip-', copyIndex())]", 103 | "location": "[parameters('location')]", 104 | "copy": { 105 | "name": "[concat(parameters('namespace'),'pipLoop')]", 106 | "count": "[parameters('vmCount')]" 107 | }, 108 | "properties": { 109 | "publicIPAllocationMethod": "Dynamic" 110 | } 111 | }, 112 | { 113 | "apiVersion": "2015-06-15", 114 | "type": "Microsoft.Network/networkInterfaces", 115 | "name": "[concat(parameters('namespace'), '-nic-', copyIndex())]", 116 | "location": "[parameters('location')]", 117 | "copy": { 118 | "name": "[concat(parameters('namespace'),'nicLoop')]", 119 | "count": "[parameters('vmCount')]" 120 | }, 121 | "dependsOn": [ 122 | "[concat('Microsoft.Network/publicIPAddresses/', parameters('namespace'), '-pip-', copyIndex())]" 123 | ], 124 | "properties": { 125 | "ipConfigurations": [ 126 | { 127 | "name": "ipconfig1", 128 | "properties": { 129 | "privateIPAddress": "[concat(parameters('subnet').networkPrefix, '.', string(add(4,copyIndex())))]", 130 | "privateIPAllocationMethod": "Static", 131 | "subnet": { 132 | "id": "[variables('subnetRef')]" 133 | }, 134 | "publicIPAddress": { 135 | "id": "[resourceId('Microsoft.Network/publicIPAddresses', concat(parameters('namespace'), '-pip-', copyIndex()))]" 136 | } 137 | } 138 | } 139 | ] 140 | } 141 | }, 142 | { 143 | "apiVersion": "2015-06-15", 144 | "type": "Microsoft.Compute/virtualMachines", 145 | "name": "[concat(parameters('namespace'), '-vm-', copyIndex())]", 146 | "location": "[parameters('location')]", 147 | "copy": { 148 | "name": "[concat(parameters('namespace'), 'virtualMachineLoop')]", 149 | "count": "[parameters('vmCount')]" 150 | }, 151 | "dependsOn": [ 152 | "[concat('Microsoft.Network/networkInterfaces/', parameters('namespace'), '-nic-', copyIndex())]", 153 | "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()])]" 154 | ], 155 | "properties": { 156 | "availabilitySet": { 157 | "id": "[resourceId('Microsoft.Compute/availabilitySets', concat(parameters('namespace'), '-set'))]" 158 | }, 159 | "hardwareProfile": { 160 | "vmSize": "[parameters('vmSize')]" 161 | }, 162 | "osProfile": { 163 | "computerName": "[concat(parameters('namespace'), '-vm-', copyIndex())]", 164 | "adminUsername": "[parameters('adminUsername')]", 165 | "adminPassword": "[parameters('adminPassword')]" 166 | }, 167 | "storageProfile": { 168 | "imageReference": "[parameters('osSettings').imageReference]", 169 | "osDisk": { 170 | "name": "osdisk", 171 | "vhd": { 172 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()], '.blob.core.windows.net/vhds/', variables('vmName'), '-vm-', copyIndex(), '-osdisk.vhd')]" 173 | }, 174 | "caching": "ReadWrite", 175 | "createOption": "FromImage" 176 | }, 177 | "dataDisks": [ 178 | { 179 | "name": "datadisk1", 180 | "diskSizeGB": "[parameters('dataDiskSize')]", 181 | "lun": 0, 182 | "vhd": { 183 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk1' ,'.vhd')]" 184 | }, 185 | "caching": "None", 186 | "createOption": "Empty" 187 | }, 188 | { 189 | "name": "datadisk2", 190 | "diskSizeGB": "[parameters('dataDiskSize')]", 191 | "lun": 1, 192 | "vhd": { 193 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk2' ,'.vhd')]" 194 | }, 195 | "caching": "None", 196 | "createOption": "Empty" 197 | }, 198 | { 199 | "name": "datadisk3", 200 | "diskSizeGB": "[parameters('dataDiskSize')]", 201 | "lun": 2, 202 | "vhd": { 203 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk3' ,'.vhd')]" 204 | }, 205 | "caching": "None", 206 | "createOption": "Empty" 207 | }, 208 | { 209 | "name": "datadisk4", 210 | "diskSizeGB": "[parameters('dataDiskSize')]", 211 | "lun": 3, 212 | "vhd": { 213 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk4' ,'.vhd')]" 214 | }, 215 | "caching": "None", 216 | "createOption": "Empty" 217 | } 218 | ] 219 | }, 220 | "networkProfile": { 221 | "networkInterfaces": [ 222 | { 223 | "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(parameters('namespace'),'-nic-', copyIndex()))]" 224 | } 225 | ] 226 | } 227 | }, 228 | "resources": [ 229 | { 230 | "type": "Microsoft.Compute/virtualMachines/extensions", 231 | "name": "[concat(parameters('namespace'),'-vm-', copyIndex(), '/installapplications')]", 232 | "location": "[parameters('location')]", 233 | "apiVersion": "2015-06-15", 234 | "dependsOn": [ 235 | "[concat('Microsoft.Compute/virtualMachines/', parameters('namespace'), '-vm-', copyIndex())]" 236 | ], 237 | "properties": "[parameters('osSettings').extentionSettings.eventstore]" 238 | } 239 | ] 240 | } 241 | ] 242 | } -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/cluster-nodes-8disk-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Admin username used when provisioning virtual machines" 9 | } 10 | }, 11 | "adminPassword": { 12 | "type": "securestring", 13 | "metadata": { 14 | "description": "Admin password used when provisioning virtual machines" 15 | } 16 | }, 17 | "storageSettings": { 18 | "type": "object", 19 | "metadata": { 20 | "description": "Storage Account Settings" 21 | } 22 | }, 23 | "location": { 24 | "type": "string", 25 | "metadata": { 26 | "description": "Location where resources will be provisioned" 27 | } 28 | }, 29 | "subnet": { 30 | "type": "object", 31 | "metadata": { 32 | "description": "The name of the subnet to deploy resources into" 33 | } 34 | }, 35 | "vmSize": { 36 | "type": "string", 37 | "defaultValue": "Standard_A1", 38 | "metadata": { 39 | "description": "Size of the Elasticsearch data nodes" 40 | } 41 | }, 42 | "vmCount": { 43 | "type": "int", 44 | "defaultValue": 2, 45 | "metadata": { 46 | "description": "Number of Elasticsearch data nodes" 47 | } 48 | }, 49 | "osSettings": { 50 | "type": "object", 51 | "metadata": { 52 | "description": "OS settings to deploy on" 53 | } 54 | }, 55 | "dataDiskSize": { 56 | "type": "int", 57 | "defaultValue": 1023, 58 | "metadata": { 59 | "description": "Size of each data disk attached to data nodes in (Gb)" 60 | } 61 | }, 62 | "namespace": { 63 | "type": "string", 64 | "metadata": { 65 | "description": "The namespace for resources created by this template" 66 | } 67 | } 68 | }, 69 | "variables": { 70 | "vmStorageAccountContainerName": "vhd", 71 | "subnetRef": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('subnet').vnet), '/subnets/', parameters('subnet').name)]", 72 | "storageAccountName": "[concat(parameters('storageSettings').prefix)]", 73 | "vmName": "[parameters('namespace')]" 74 | }, 75 | "resources": [ 76 | { 77 | "type": "Microsoft.Storage/storageAccounts", 78 | "name": "[concat(variables('storageAccountName'), copyIndex(1))]", 79 | "apiVersion": "2015-05-01-preview", 80 | "location": "[parameters('location')]", 81 | "copy": { 82 | "name": "[concat(parameters('namespace'),'storageLoop')]", 83 | "count": "[parameters('storageSettings').count]" 84 | }, 85 | "properties": { 86 | "accountType": "[parameters('storageSettings').accountType]" 87 | } 88 | }, 89 | { 90 | "apiVersion": "2015-06-15", 91 | "type": "Microsoft.Compute/availabilitySets", 92 | "name": "[concat(parameters('namespace'), '-set')]", 93 | "location": "[parameters('location')]", 94 | "properties": { 95 | "platformUpdateDomainCount": 20, 96 | "platformFaultDomainCount": 3 97 | } 98 | }, 99 | { 100 | "apiVersion": "2015-06-15", 101 | "type": "Microsoft.Network/publicIPAddresses", 102 | "name": "[concat(parameters('namespace'), '-pip-', copyIndex())]", 103 | "location": "[parameters('location')]", 104 | "copy": { 105 | "name": "[concat(parameters('namespace'),'pipLoop')]", 106 | "count": "[parameters('vmCount')]" 107 | }, 108 | "properties": { 109 | "publicIPAllocationMethod": "Dynamic" 110 | } 111 | }, 112 | { 113 | "apiVersion": "2015-06-15", 114 | "type": "Microsoft.Network/networkInterfaces", 115 | "name": "[concat(parameters('namespace'), '-nic-', copyIndex())]", 116 | "location": "[parameters('location')]", 117 | "copy": { 118 | "name": "[concat(parameters('namespace'),'nicLoop')]", 119 | "count": "[parameters('vmCount')]" 120 | }, 121 | "dependsOn": [ 122 | "[concat('Microsoft.Network/publicIPAddresses/', parameters('namespace'), '-pip-', copyIndex())]" 123 | ], 124 | "properties": { 125 | "ipConfigurations": [ 126 | { 127 | "name": "ipconfig1", 128 | "properties": { 129 | "privateIPAddress": "[concat(parameters('subnet').networkPrefix, '.', string(add(4,copyIndex())))]", 130 | "privateIPAllocationMethod": "Static", 131 | "subnet": { 132 | "id": "[variables('subnetRef')]" 133 | } 134 | } 135 | } 136 | ] 137 | } 138 | }, 139 | { 140 | "apiVersion": "2015-06-15", 141 | "type": "Microsoft.Compute/virtualMachines", 142 | "name": "[concat(parameters('namespace'), '-vm-', copyIndex())]", 143 | "location": "[parameters('location')]", 144 | "copy": { 145 | "name": "[concat(parameters('namespace'), 'virtualMachineLoop')]", 146 | "count": "[parameters('vmCount')]" 147 | }, 148 | "dependsOn": [ 149 | "[concat('Microsoft.Network/networkInterfaces/', parameters('namespace'), '-nic-', copyIndex())]", 150 | "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()])]" 151 | ], 152 | "properties": { 153 | "availabilitySet": { 154 | "id": "[resourceId('Microsoft.Compute/availabilitySets', concat(parameters('namespace'), '-set'))]" 155 | }, 156 | "hardwareProfile": { 157 | "vmSize": "[parameters('vmSize')]" 158 | }, 159 | "osProfile": { 160 | "computerName": "[concat(parameters('namespace'), '-vm-', copyIndex())]", 161 | "adminUsername": "[parameters('adminUsername')]", 162 | "adminPassword": "[parameters('adminPassword')]" 163 | }, 164 | "storageProfile": { 165 | "imageReference": "[parameters('osSettings').imageReference]", 166 | "osDisk": { 167 | "name": "osdisk", 168 | "vhd": { 169 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()], '.blob.core.windows.net/vhds/', variables('vmName'), '-vm-', copyIndex(), '-osdisk.vhd')]" 170 | }, 171 | "caching": "ReadWrite", 172 | "createOption": "FromImage" 173 | }, 174 | "dataDisks": [ 175 | { 176 | "name": "datadisk1", 177 | "diskSizeGB": "[parameters('dataDiskSize')]", 178 | "lun": 0, 179 | "vhd": { 180 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk1' ,'.vhd')]" 181 | }, 182 | "caching": "None", 183 | "createOption": "Empty" 184 | }, 185 | { 186 | "name": "datadisk2", 187 | "diskSizeGB": "[parameters('dataDiskSize')]", 188 | "lun": 1, 189 | "vhd": { 190 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk2' ,'.vhd')]" 191 | }, 192 | "caching": "None", 193 | "createOption": "Empty" 194 | }, 195 | { 196 | "name": "datadisk3", 197 | "diskSizeGB": "[parameters('dataDiskSize')]", 198 | "lun": 2, 199 | "vhd": { 200 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk3' ,'.vhd')]" 201 | }, 202 | "caching": "None", 203 | "createOption": "Empty" 204 | }, 205 | { 206 | "name": "datadisk4", 207 | "diskSizeGB": "[parameters('dataDiskSize')]", 208 | "lun": 3, 209 | "vhd": { 210 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk4' ,'.vhd')]" 211 | }, 212 | "caching": "None", 213 | "createOption": "Empty" 214 | }, 215 | { 216 | "name": "datadisk5", 217 | "diskSizeGB": "[parameters('dataDiskSize')]", 218 | "lun": 4, 219 | "vhd": { 220 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk5' ,'.vhd')]" 221 | }, 222 | "caching": "None", 223 | "createOption": "Empty" 224 | }, 225 | { 226 | "name": "datadisk6", 227 | "diskSizeGB": "[parameters('dataDiskSize')]", 228 | "lun": 5, 229 | "vhd": { 230 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk6' ,'.vhd')]" 231 | }, 232 | "caching": "None", 233 | "createOption": "Empty" 234 | }, 235 | { 236 | "name": "datadisk7", 237 | "diskSizeGB": "[parameters('dataDiskSize')]", 238 | "lun": 6, 239 | "vhd": { 240 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk7' ,'.vhd')]" 241 | }, 242 | "caching": "None", 243 | "createOption": "Empty" 244 | }, 245 | { 246 | "name": "datadisk8", 247 | "diskSizeGB": "[parameters('dataDiskSize')]", 248 | "lun": 7, 249 | "vhd": { 250 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyIndex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyIndex(),'dataDisk8' ,'.vhd')]" 251 | }, 252 | "caching": "None", 253 | "createOption": "Empty" 254 | } 255 | ] 256 | }, 257 | "networkProfile": { 258 | "networkInterfaces": [ 259 | { 260 | "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(parameters('namespace'),'-nic-', copyIndex()))]" 261 | } 262 | ] 263 | } 264 | }, 265 | "resources": [ 266 | { 267 | "type": "Microsoft.Compute/virtualMachines/extensions", 268 | "name": "[concat(parameters('namespace'),'-vm-', copyIndex(), '/installapplications')]", 269 | "location": "[parameters('location')]", 270 | "apiVersion": "2015-06-15", 271 | "dependsOn": [ 272 | "[concat('Microsoft.Compute/virtualMachines/', parameters('namespace'), '-vm-', copyIndex())]" 273 | ], 274 | "properties": "[parameters('osSettings').extentionSettings.eventstore]" 275 | } 276 | ] 277 | } 278 | ] 279 | } -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/create-data-disks.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # This script will create a stripped data disk with all available disks. 3 | # Note: For disks to be added to a pool, they must be at least 4GB in size. 4 | # 5 | $ErrorActionPreference="SilentlyContinue" 6 | Stop-Transcript | out-null 7 | $ErrorActionPreference = "Continue" 8 | Start-Transcript -path C:\ps-output-createdisks.txt -append -noClobber 9 | 10 | Write-Verbose 'Creating Storage Pool' 11 | 12 | $storagePoolFriendlyName = 'LUN-0' 13 | $virtualDiskFriendlyName = 'Datastore01' 14 | $physicalDisks = Get-PhysicalDisk -CanPool $true 15 | $numberOfColumns = $physicalDisks.Length 16 | 17 | New-StoragePool -FriendlyName $storagePoolFriendlyName ` 18 | -StorageSubSystemUniqueId (Get-StorageSubSystem -FriendlyName '*Space*').uniqueID ` 19 | -PhysicalDisks $physicalDisks 20 | 21 | Write-Verbose 'Creating Virtual Disk' 22 | 23 | New-VirtualDisk -FriendlyName $virtualDiskFriendlyName ` 24 | -StoragePoolFriendlyName $storagePoolFriendlyName ` 25 | -UseMaximumSize ` 26 | -NumberOfColumns $NumberOfColumns ` 27 | -Interleave 65536 ` 28 | -ProvisioningType Fixed ` 29 | -ResiliencySettingName Simple 30 | 31 | Start-Sleep -Seconds 20 32 | 33 | Write-Verbose 'Initializing Disk' 34 | 35 | Initialize-Disk -VirtualDisk (Get-VirtualDisk -FriendlyName $virtualDiskFriendlyName) 36 | 37 | Start-Sleep -Seconds 20 38 | 39 | $diskNumber = ((Get-VirtualDisk -FriendlyName $virtualDiskFriendlyName | Get-Disk).Number) 40 | 41 | Write-Verbose 'Creating Partition' 42 | 43 | New-Partition -DiskNumber $diskNumber ` 44 | -UseMaximumSize ` 45 | -DriveLetter F 46 | 47 | Start-Sleep -Seconds 20 48 | 49 | Write-Verbose 'Formatting Volume and Assigning Drive Letter' 50 | 51 | Format-Volume -DriveLetter F ` 52 | -FileSystem NTFS ` 53 | -NewFileSystemLabel 'Data' ` 54 | -Confirm:$false ` 55 | -Force 56 | 57 | Stop-Transcript -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/data-nodes-0disk-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Admin username used when provisioning virtual machines" 9 | } 10 | }, 11 | "adminPassword": { 12 | "type": "securestring", 13 | "metadata": { 14 | "description": "Admin password used when provisioning virtual machines" 15 | } 16 | }, 17 | "storageSettings": { 18 | "type": "object", 19 | "metadata": { 20 | "description": "Storage Account Settings" 21 | } 22 | }, 23 | "location": { 24 | "type": "string", 25 | "metadata": { 26 | "description": "Location where resources will be provisioned" 27 | } 28 | }, 29 | "subnet": { 30 | "type": "object", 31 | "metadata": { 32 | "description": "The name of the subnet to deploy resources into" 33 | } 34 | }, 35 | "vmSize": { 36 | "type": "string", 37 | "defaultValue": "Standard_A1", 38 | "metadata": { 39 | "description": "Size of the Elasticsearch data nodes" 40 | } 41 | }, 42 | "vmCount": { 43 | "type": "int", 44 | "defaultValue": 2, 45 | "metadata": { 46 | "description": "Number of Elasticsearch data nodes" 47 | } 48 | }, 49 | "osSettings": { 50 | "type": "object", 51 | "metadata": { 52 | "description": "OS settings to deploy on" 53 | } 54 | }, 55 | "dataDiskSize": { 56 | "type": "int", 57 | "defaultValue": 1023, 58 | "metadata": { 59 | "description": "Size of each data disk attached to data nodes in (Gb)" 60 | } 61 | }, 62 | "namespace": { 63 | "type": "string", 64 | "metadata": { 65 | "description": "The namespace for resources created by this template" 66 | } 67 | } 68 | }, 69 | "variables": { 70 | "vmStorageAccountContainerName": "vhd", 71 | "subnetRef": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('subnet').vnet), '/subnets/', parameters('subnet').name)]", 72 | "storageAccountName": "[concat(parameters('storageSettings').prefix)]", 73 | "vmName": "[parameters('namespace')]" 74 | }, 75 | "resources": [ 76 | { 77 | "type": "Microsoft.Storage/storageAccounts", 78 | "name": "[concat(variables('storageAccountName'), copyindex(1))]", 79 | "apiVersion": "2015-05-01-preview", 80 | "location": "[parameters('location')]", 81 | "copy": { 82 | "name": "[concat(parameters('namespace'),'storageLoop')]", 83 | "count": "[parameters('storageSettings').count]" 84 | }, 85 | "properties": { 86 | "accountType": "[parameters('storageSettings').accountType]" 87 | } 88 | }, 89 | { 90 | "apiVersion": "2015-06-15", 91 | "type": "Microsoft.Compute/availabilitySets", 92 | "name": "[concat(parameters('namespace'), '-set')]", 93 | "location": "[parameters('location')]", 94 | "properties": { 95 | "platformUpdateDomainCount": 20, 96 | "platformFaultDomainCount": 3 97 | } 98 | }, 99 | { 100 | "apiVersion": "2015-06-15", 101 | "type": "Microsoft.Network/publicIPAddresses", 102 | "name": "[concat(parameters('namespace'), '-pip-', copyindex())]", 103 | "location": "[parameters('location')]", 104 | "properties": { 105 | "publicIPAllocationMethod": "Dynamic" 106 | } 107 | }, 108 | { 109 | "apiVersion": "2015-06-15", 110 | "type": "Microsoft.Network/networkInterfaces", 111 | "name": "[concat(parameters('namespace'), '-nic-', copyindex())]", 112 | "location": "[parameters('location')]", 113 | "copy": { 114 | "name": "[concat(parameters('namespace'),'nicLoop')]", 115 | "count": "[parameters('vmCount')]" 116 | }, 117 | "dependsOn": [ 118 | "[concat('Microsoft.Network/publicIPAddresses/', parameters('namespace'), '-pip-', copyindex())]" 119 | ], 120 | "properties": { 121 | "ipConfigurations": [ 122 | { 123 | "name": "ipconfig1", 124 | "properties": { 125 | "privateIPAddress": "[concat(parameters('subnet').networkPrefix, '.', string(add(4,copyindex())))]", 126 | "privateIPAllocationMethod": "Static", 127 | "subnet": { 128 | "id": "[variables('subnetRef')]" 129 | } 130 | } 131 | } 132 | ] 133 | } 134 | }, 135 | { 136 | "apiVersion": "2015-06-15", 137 | "type": "Microsoft.Compute/virtualMachines", 138 | "name": "[concat(parameters('namespace'), '-vm-', copyindex())]", 139 | "location": "[parameters('location')]", 140 | "copy": { 141 | "name": "[concat(parameters('namespace'), 'virtualMachineLoop')]", 142 | "count": "[parameters('vmCount')]" 143 | }, 144 | "dependsOn": [ 145 | "[concat('Microsoft.Network/networkInterfaces/', parameters('namespace'), '-nic-', copyindex())]", 146 | "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), parameters('storageSettings').mapping[copyindex()])]" 147 | ], 148 | "properties": { 149 | "availabilitySet": { 150 | "id": "[resourceId('Microsoft.Compute/availabilitySets', concat(parameters('namespace'), '-set'))]" 151 | }, 152 | "hardwareProfile": { 153 | "vmSize": "[parameters('vmSize')]" 154 | }, 155 | "osProfile": { 156 | "computername": "[concat(parameters('namespace'), '-vm-', copyIndex())]", 157 | "adminUsername": "[parameters('adminUsername')]", 158 | "adminPassword": "[parameters('adminPassword')]" 159 | }, 160 | "storageProfile": { 161 | "imageReference": "[parameters('osSettings').imageReference]", 162 | "osDisk": { 163 | "name": "osdisk", 164 | "vhd": { 165 | "uri": "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyindex()], '.blob.core.windows.net/vhds/', variables('vmName'), '-vm-', copyindex(), '-osdisk.vhd')]" 166 | }, 167 | "caching": "ReadWrite", 168 | "createOption": "FromImage" 169 | } 170 | }, 171 | "networkProfile": { 172 | "networkInterfaces": [ 173 | { 174 | "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(parameters('namespace'),'-nic-', copyindex()))]" 175 | } 176 | ] 177 | } 178 | }, 179 | "resources": [ 180 | { 181 | "type": "Microsoft.Compute/virtualMachines/extensions", 182 | "name": "[concat(parameters('namespace'),'-vm-', copyindex(), '/createdatadisk')]", 183 | "location": "[parameters('location')]", 184 | "apiVersion": "2015-06-15", 185 | "dependsOn": [ 186 | "[concat('Microsoft.Compute/virtualMachines/', parameters('namespace'), '-vm-', copyindex())]" 187 | ], 188 | "properties": "[parameters('osSettings').extentionSettings.eventstore]" 189 | } 190 | ] 191 | } 192 | ] 193 | } -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/empty-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "type": "string", 7 | "defaultValue": "" 8 | }, 9 | "subnet": { 10 | "type": "object", 11 | "defaultValue": {} 12 | }, 13 | "storageAccountName": { 14 | "type": "string", 15 | "defaultValue": "" 16 | }, 17 | "adminUsername": { 18 | "type": "string", 19 | "defaultValue": "" 20 | }, 21 | "adminPassword": { 22 | "type": "securestring", 23 | "defaultValue": "" 24 | }, 25 | "osSettings": { 26 | "type": "object", 27 | "defaultValue": {} 28 | }, 29 | "vmSize": { 30 | "type": "string", 31 | "defaultValue": "" 32 | }, 33 | "vmCount": { 34 | "type": "int", 35 | "defaultValue": 0 36 | }, 37 | "lbBackendPools": { 38 | "type": "object", 39 | "defaultValue": {} 40 | } 41 | }, 42 | "variables": {}, 43 | "resources": [], 44 | "outputs": {} 45 | } 46 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/eventstore-ubuntu-sources.txt: -------------------------------------------------------------------------------- 1 | # 2 | # to do: make this file contents something unbuntu shell script can process natively 3 | # 4 | 5 | "3.8.1": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-14.04-v3.8.1.tar.gz", 6 | "3.8.0": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-14.04-v3.8.0.tar.gz", 7 | "3.7.0": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-14.04-v3.7.0.tar.gz", 8 | "3.6.3": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-14.04-v3.6.3.tar.gz", 9 | "3.6.2": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-14.04-v3.6.2.tar.gz", 10 | "3.6.1": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-14.04-v3.6.1.tar.gz", 11 | "3.6.0": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-14.04-v3.6.0.tar.gz", 12 | "3.5.0": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-14.04-v3.5.0.tar.gz", 13 | "3.4.0": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-14.04-v3.4.0.tar.gz", 14 | "3.3.1": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-v3.3.1.tar.gz", 15 | "3.3.0": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-v3.3.0.tar.gz", 16 | "3.2.2": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-v3.2.2.tar.gz", 17 | "3.2.1": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-v3.2.1.tar.gz", 18 | "3.2.0": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-v3.2.0.tar.gz", 19 | "3.1.0": "http://download.geteventstore.com/binaries/EventStore-OSS-Ubuntu-v3.1.0.tar.gz", 20 | "3.0.5": "http://download.geteventstore.com/binaries/EventStore-OSS-Linux-v3.0.5.tar.gz", 21 | "3.0.3": "http://download.geteventstore.com/binaries/EventStore-OSS-Linux-v3.0.3.tar.gz", 22 | "3.0.2": "http://download.geteventstore.com/binaries/EventStore-OSS-Linux-v3.0.2.tar.gz", 23 | "3.0.1": "http://download.geteventstore.com/binaries/EventStore-OSS-Linux-v3.0.1.tar.gz", 24 | "3.0.0": "http://download.geteventstore.com/binaries/EventStore-OSS-Linux-v3.0.0.tar.gz" 25 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/eventstore-windows-sources.csv: -------------------------------------------------------------------------------- 1 | "3.8.1",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.8.1.zip 2 | "3.8.0",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.8.0.zip 3 | "3.7.0",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.7.0.zip 4 | "3.6.3",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.6.3.zip 5 | "3.6.2",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.6.2.zip 6 | "3.6.1",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.6.1.zip 7 | "3.6.0",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.6.0.zip 8 | "3.5.0",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.5.0.zip 9 | "3.4.0",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.4.0.zip 10 | "3.3.1",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.3.1.zip 11 | "3.3.0",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.3.0.zip 12 | "3.2.2",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.2.2.zip 13 | "3.2.1",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.2.1.zip 14 | "3.2.0",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.2.0.zip 15 | "3.1.0",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.1.0.zip 16 | "3.0.5",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.0.5.zip 17 | "3.0.3",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.0.3.zip 18 | "3.0.2",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.0.2.zip 19 | "3.0.1",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.0.1.zip 20 | "3.0.0",http://download.geteventstore.com/binaries/EventStore-OSS-Win-v3.0.0.zip 21 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/install-eventstore.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # install_eventstore.ps1 3 | # 4 | param ( 5 | [string] 6 | $EventStoreVersion, 7 | [string] 8 | $nssmDownloadUrl, 9 | [string] 10 | $IntIp, 11 | [string] 12 | $ExtIp, 13 | [string] 14 | $ExtIpAdvertiseAs, 15 | [Int] 16 | $ClusterSize = 1, 17 | [Int] 18 | $IntTcpPort = 1112, 19 | [Int] 20 | $ExtTcpPort = 1113, 21 | [Int] 22 | $IntHttpPort = 2112, 23 | [Int] 24 | $ExtHttpPort = 2113, 25 | [string] 26 | $downloadDirectory 27 | ) 28 | 29 | function Extract-ZipFile($file, $destination) { 30 | if (![System.IO.Directory]::Exists($destination)) { 31 | [System.IO.Directory]::CreateDirectory($destination) 32 | } 33 | 34 | $shell = new-object -com shell.application 35 | $zip = $shell.NameSpace($file) 36 | 37 | foreach($item in $zip.items()) { 38 | $shell.Namespace($destination).copyhere($item) 39 | } 40 | } 41 | 42 | function Download-FileTo($DownloadUrl, $path) { 43 | $uri = [System.Uri]$DownloadUrl 44 | $filename = $uri.Segments[$uri.Segments.Length-1] 45 | $outFile = Join-Path $path -ChildPath $filename 46 | 47 | Invoke-WebRequest $DownloadUrl -OutFile $outFile | Out-Null 48 | return $outFile 49 | } 50 | 51 | $ErrorActionPreference="SilentlyContinue" 52 | Stop-Transcript | out-null 53 | $ErrorActionPreference = "Continue" 54 | Start-Transcript -path C:\ps-output-es.txt -append -noClobber 55 | 56 | $nssmZip = Download-FileTo -DownloadUrl $nssmDownloadUrl -Path $downloadDirectory 57 | # NSSM is packed with in a folder already 58 | Extract-ZipFile -File $nssmZip -Destination F:\ 59 | 60 | $url = (Import-Csv -Header Version,Url -Path eventstore-windows-sources.csv | Where-Object { $_.Version -eq $esVer }).Url 61 | $eventStoreZip = Download-FileTo -DownloadUrl $url -Path $downloadDirectory 62 | Extract-ZipFile -File $eventStoreZip -Destination F:\eventstore\bin\ 63 | 64 | # 65 | # 66 | # 67 | $ipAddress = (Resolve-DnsName $env:COMPUTERNAME -Type A).IPAddress 68 | 69 | #Database Node Internal HTTP Interface (open source and commercial) 70 | #netsh http add urlacl url=http://${ipAddress}:${IntHttpPort}/ user="NT AUTHORITY\LOCAL SERVICE" 71 | 72 | # Database Node External HTTP Interface (open source and commercial) 73 | #netsh http add urlacl url=http://${ipAddress}:${ExtHttpPort}/ user="NT AUTHORITY\LOCAL SERVICE" 74 | 75 | # Manager Node Internal HTTP Interface (commercial only) 76 | #netsh http add urlacl url=http://$ipAddress:30777/ user="NT AUTHORITY\LOCAL SERVICE" 77 | 78 | # Manager Node External HTTP Interface (commercial only) 79 | #netsh http add urlacl url=http://$ipAddress:30778/ user="NT AUTHORITY\LOCAL SERVICE" 80 | 81 | New-NetFirewallRule -Name Allow_EventStore_Int_In ` 82 | -DisplayName "Allow inbound Internal Event Store traffic" ` 83 | -Protocol TCP ` 84 | -Direction Inbound ` 85 | -Action Allow ` 86 | -LocalPort $IntTcpPort,$ExtTcpPort 87 | 88 | New-NetFirewallRule -Name Allow_EventStore_Ext_In ` 89 | -DisplayName "Allow inbound External Event Store traffic" ` 90 | -Protocol TCP ` 91 | -Direction Inbound ` 92 | -Action Allow ` 93 | -LocalPort $IntHttpPort,$ExtHttpPort 94 | 95 | # SET COMMON_OPTS=-MemDb -Log D:\eventstore\logs -ClusterSize 3 -DiscoverViaDns false -GossipSeed %IP0%:2112,%IP1%:2112,%IP2%:2112 96 | # 97 | # EventStore.ClusterNode.exe %COMMON_OPTS% -IntIp %IP0% -ExtIp %IP0% -ExtIpAdvertiseAs %PIP0% 98 | # EventStore.ClusterNode.exe %COMMON_OPTS% -IntIp %IP1% -ExtIp %IP1% -ExtIpAdvertiseAs %PIP1% 99 | # EventStore.ClusterNode.exe %COMMON_OPTS% -IntIp %IP2% -ExtIp %IP2% -ExtIpAdvertiseAs %PIP2% 100 | 101 | Add-Content F:\eventstore\config.yaml "# default Event Store configuration file`n" 102 | Add-Content F:\eventstore\config.yaml "Db: F:\eventstore\data`n" 103 | Add-Content F:\eventstore\config.yaml "Log: D:\eventstore\logs`n" 104 | Add-Content F:\eventstore\config.yaml "IntIp: $ipAddress`n" 105 | # Don't need these, locking down the ES behind NGinx 106 | # Add-Content F:\eventstore\config.yaml "ExtIp: $ipAddress`n" 107 | # Add-Content F:\eventstore\config.yaml "ExtIpAdvertiseAs: $ExtIpAdvertiseAs`n" 108 | Add-Content F:\eventstore\config.yaml "ClusterSize: $ClusterSize`n" 109 | Add-Content F:\eventstore\config.yaml "DiscoverViaDns: false`n" 110 | Add-Content F:\eventstore\config.yaml "GossipSeed: 10.0.1.4:$IntHttpPort,10.0.1.5:$IntHttpPort,10.0.1.6:$IntHttpPort`n" 111 | 112 | Add-Content F:\eventstore\install-service.cmd "F:\nssm-2.24\win64\nssm.exe install EventStore F:\eventstore\bin\EventStore.ClusterNode.exe --config F:\eventstore\config.yaml" 113 | Add-Content F:\eventstore\install-service.cmd "F:\nssm-2.24\win64\nssm.exe set EventStore Description ""The EventStore service""" 114 | 115 | Add-Content F:\eventstore\start-service.cmd "net start EventStore" 116 | Add-Content F:\eventstore\stop-service.cmd "net stop EventStore" 117 | 118 | . F:\eventstore\install-service.cmd 119 | . F:\eventstore\start-service.cmd 120 | 121 | Stop-Transcript -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/install-nginx.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # install_nginx.ps1 3 | # 4 | param ( 5 | [string] 6 | $NGinxVersion, 7 | [string] 8 | $NGinxDownloadUrl, 9 | [string] 10 | $downloadDirectory 11 | ) 12 | 13 | function Extract-ZipFile($file, $destination) { 14 | if (![System.IO.Directory]::Exists($destination)) { 15 | [System.IO.Directory]::CreateDirectory($destination) 16 | } 17 | 18 | $shell = new-object -com shell.application 19 | $zip = $shell.NameSpace($file) 20 | 21 | foreach($item in $zip.items()) { 22 | $shell.Namespace($destination).copyhere($item) 23 | } 24 | } 25 | 26 | function Download-FileTo($DownloadUrl, $path) { 27 | $uri = [System.Uri]$DownloadUrl 28 | $filename = $uri.Segments[$uri.Segments.Length-1] 29 | $outFile = Join-Path $path -ChildPath $filename 30 | 31 | Invoke-WebRequest $DownloadUrl -OutFile $outFile | Out-Null 32 | return $outFile 33 | } 34 | 35 | $ErrorActionPreference="SilentlyContinue" 36 | Stop-Transcript | out-null 37 | $ErrorActionPreference = "Continue" 38 | Start-Transcript -path C:\ps-output-nginx.txt -append -noClobber 39 | 40 | $nginxZip = Download-FileTo -DownloadUrl $NGinxDownloadUrl -Path $downloadDirectory 41 | Extract-ZipFile -File $nginxZip -Destination F:\nginx\bin\ 42 | 43 | New-NetFirewallRule -Name Allow_80_In ` 44 | -DisplayName "Allow inbound port 80 traffic" ` 45 | -Protocol TCP ` 46 | -Direction Inbound ` 47 | -Action Allow ` 48 | -LocalPort 80 49 | 50 | Add-Content F:\nginx\install-service.cmd "F:\nssm-2.24\win64\nssm.exe install Nginx F:\nginx\bin\nginx-1.10.1\nginx.exe" 51 | Add-Content F:\nginx\install-service.cmd "F:\nssm-2.24\win64\nssm.exe set Nginx Description ""The Nginx service""" 52 | 53 | Add-Content F:\nginx\start-service.cmd "net start Nginx" 54 | Add-Content F:\nginx\stop-service.cmd "net stop Nginx" 55 | 56 | . F:\nginx\install-service.cmd 57 | . F:\nginx\start-service.cmd 58 | 59 | Stop-Transcript -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/jumpbox-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "namespace": { 6 | "type": "string", 7 | "defaultValue": "jumpbox", 8 | "metadata": { 9 | "description": "The namespace prefix for resources created by this template" 10 | } 11 | }, 12 | "location": { 13 | "type": "string", 14 | "metadata": { 15 | "description": "Location where resources will be provisioned" 16 | } 17 | }, 18 | "subnet": { 19 | "type": "object", 20 | "metadata": { 21 | "description": "Subnet object for provisioning resources in (expects properties name as the subnet name, and vnet as the virtual network name on the object)" 22 | } 23 | }, 24 | "storageAccountName": { 25 | "type": "string", 26 | "metadata": { 27 | "description": "Existing Storage Account where the Virtual Machine's disks will be placed" 28 | } 29 | }, 30 | "adminUsername": { 31 | "type": "string", 32 | "metadata": { 33 | "description": "Administrator user name used when provisioning virtual machines" 34 | } 35 | }, 36 | "adminPassword": { 37 | "type": "securestring", 38 | "metadata": { 39 | "description": "Administrator password used when provisioning virtual machines" 40 | } 41 | }, 42 | "osSettings": { 43 | "type": "object", 44 | "metadata": { 45 | "description": "Elasticsearch deployment platform settings" 46 | } 47 | } 48 | }, 49 | "variables": { 50 | "vmStorageAccountContainerName": "vhd", 51 | "vmSize": "Standard_A0", 52 | "subnetRef": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('subnet').vnet), '/subnets/', parameters('subnet').name)]", 53 | "vmName": "[concat(parameters('namespace'), '-vm')]", 54 | "publicIpName": "[concat(parameters('namespace'), '-pip')]", 55 | "securityGroupName": "[concat(parameters('namespace'), '-nsg')]", 56 | "nicName": "[concat(parameters('namespace'), '-nic')]" 57 | }, 58 | "resources": [ 59 | { 60 | "apiVersion": "2015-06-15", 61 | "type": "Microsoft.Network/networkSecurityGroups", 62 | "name": "[variables('securityGroupName')]", 63 | "location": "[parameters('location')]", 64 | "properties": { 65 | "securityRules": [ 66 | { 67 | "name": "SSH", 68 | "properties": { 69 | "description": "Allows SSH traffic", 70 | "protocol": "Tcp", 71 | "sourcePortRange": "[parameters('osSettings').managementPort]", 72 | "destinationPortRange": "[parameters('osSettings').managementPort]", 73 | "sourceAddressPrefix": "*", 74 | "destinationAddressPrefix": "*", 75 | "access": "Allow", 76 | "priority": 100, 77 | "direction": "Inbound" 78 | } 79 | } 80 | ] 81 | } 82 | }, 83 | { 84 | "apiVersion": "2015-06-15", 85 | "type": "Microsoft.Network/publicIPAddresses", 86 | "name": "[variables('publicIpName')]", 87 | "location": "[parameters('location')]", 88 | "properties": { 89 | "publicIPAllocationMethod": "Dynamic" 90 | } 91 | }, 92 | { 93 | "apiVersion": "2015-06-15", 94 | "type": "Microsoft.Network/networkInterfaces", 95 | "name": "[variables('nicName')]", 96 | "location": "[parameters('location')]", 97 | "dependsOn": [ 98 | "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIpName'))]", 99 | "[concat('Microsoft.Network/networkSecurityGroups/', variables('securityGroupName'))]" 100 | ], 101 | "properties": { 102 | "ipConfigurations": [ 103 | { 104 | "name": "ipconfig1", 105 | "properties": { 106 | "privateIPAllocationMethod": "Dynamic", 107 | "publicIPAddress": { 108 | "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIpName'))]" 109 | }, 110 | "subnet": { 111 | "id": "[variables('subnetRef')]" 112 | }, 113 | "networkSecurityGroup": { 114 | "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('securityGroupName'))]" 115 | } 116 | } 117 | } 118 | ] 119 | } 120 | }, 121 | { 122 | "apiVersion": "2015-06-15", 123 | "type": "Microsoft.Compute/virtualMachines", 124 | "name": "[variables('vmName')]", 125 | "location": "[parameters('location')]", 126 | "dependsOn": [ 127 | "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" 128 | ], 129 | "properties": { 130 | "hardwareProfile": { 131 | "vmSize": "[variables('vmSize')]" 132 | }, 133 | "osProfile": { 134 | "computerName": "[variables('vmName')]", 135 | "adminUsername": "[parameters('adminUsername')]", 136 | "adminPassword": "[parameters('adminPassword')]" 137 | }, 138 | "storageProfile": { 139 | "imageReference": "[parameters('osSettings').imageReference]", 140 | "osDisk": { 141 | "name": "osdisk", 142 | "vhd": { 143 | "uri": "[concat('http://', parameters('storageAccountName'),'.blob.core.windows.net/vhd/', variables('vmName'), '-osdisk.vhd')]" 144 | }, 145 | "caching": "ReadWrite", 146 | "createOption": "FromImage" 147 | } 148 | }, 149 | "networkProfile": { 150 | "networkInterfaces": [ 151 | { 152 | "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" 153 | } 154 | ] 155 | } 156 | } 157 | } 158 | ], 159 | "outputs": {} 160 | } 161 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/master.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # master.ps1 3 | # 4 | param( 5 | [Int32]$ClusterSize, 6 | [string]$esVer, 7 | [string]$nginxVer="1.10.1", 8 | [string]$nginxUrl="https://landdb.blob.core.windows.net/eventstore-cluster-resources/nginx-1.10.1.zip" 9 | ) 10 | 11 | $ErrorActionPreference="SilentlyContinue" 12 | Stop-Transcript | out-null 13 | $ErrorActionPreference = "Continue" 14 | Start-Transcript -path C:\ps-output-master.txt -append -noClobber 15 | 16 | $downloadDirectory = 'D:\download' 17 | New-Item $downloadDirectory -ItemType Directory | Out-Null 18 | 19 | . .\create-data-disks.ps1 20 | 21 | # TODO: These parameters should come from the template! 22 | . .\install-eventstore.ps1 -EventStoreVersion $esVer ` 23 | -nssmDownloadUrl "https://nssm.cc/release/nssm-2.24.zip" ` 24 | -ClusterSize $ClusterSize ` 25 | -downloadDirectory $downloadDirectory 26 | 27 | . .\install-nginx.ps1 -NGinxVersion $nginxVer ` 28 | -NGinxDownloadUrl $nginxUrl ` 29 | -downloadDirectory $downloadDirectory 30 | 31 | Stop-Transcript 32 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/shared-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Location where resources will be provisioned" 9 | } 10 | }, 11 | "networkSettings": { 12 | "type": "object", 13 | "metadata": { 14 | "description": "Network settings object" 15 | } 16 | }, 17 | "storageAccountName": { 18 | "type": "string", 19 | "metadata": { 20 | "description": "Storage account used for share virtual machine images" 21 | } 22 | }, 23 | "subnet": { 24 | "type": "string", 25 | "metadata": { 26 | "description": "The name of the subnet to use from the network settings." 27 | } 28 | } 29 | }, 30 | "variables": { 31 | }, 32 | "resources": [ 33 | { 34 | "apiVersion": "2015-06-15", 35 | "type": "Microsoft.Network/networkSecurityGroups", 36 | "name": "[parameters('networkSettings').networkSecurityGroupName]", 37 | "location": "[parameters('location')]", 38 | "properties": { 39 | "securityRules": [ 40 | { 41 | "name": "Allow-EventStore-Web-HTTP", 42 | "properties": { 43 | "description": "Allows inbound web traffic from anyone", 44 | "protocol": "Tcp", 45 | "sourcePortRange": "*", 46 | "destinationPortRange": "80", 47 | "sourceAddressPrefix": "Internet", 48 | "destinationAddressPrefix": "VirtualNetwork", 49 | "access": "Allow", 50 | "priority": 100, 51 | "direction": "Inbound" 52 | } 53 | }, 54 | { 55 | "name": "Allow-EventStore-TCP", 56 | "properties": { 57 | "description": "Allows inbound EventStore TCP traffic from anyone", 58 | "protocol": "Tcp", 59 | "sourcePortRange": "*", 60 | "destinationPortRange": "1113", 61 | "sourceAddressPrefix": "Internet", 62 | "destinationAddressPrefix": "VirtualNetwork", 63 | "access": "Allow", 64 | "priority": 110, 65 | "direction": "Inbound" 66 | } 67 | }, 68 | { 69 | "name": "Allow-EventStore-HTTP", 70 | "properties": { 71 | "description": "Allows inbound EventStore HTTP traffic from anyone", 72 | "protocol": "Tcp", 73 | "sourcePortRange": "*", 74 | "destinationPortRange": "2113", 75 | "sourceAddressPrefix": "Internet", 76 | "destinationAddressPrefix": "VirtualNetwork", 77 | "access": "Allow", 78 | "priority": 120, 79 | "direction": "Inbound" 80 | } 81 | } 82 | ] 83 | } 84 | }, 85 | { 86 | "type": "Microsoft.Storage/storageAccounts", 87 | "name": "[parameters('storageAccountName')]", 88 | "apiVersion": "2015-05-01-preview", 89 | "location": "[parameters('location')]", 90 | "properties": { 91 | "accountType": "Standard_LRS" 92 | } 93 | }, 94 | { 95 | "apiVersion": "2015-06-15", 96 | "dependsOn": [ 97 | "[concat('Microsoft.Network/networkSecurityGroups/', parameters('networkSettings').networkSecurityGroupName)]" 98 | ], 99 | "type": "Microsoft.Network/virtualNetworks", 100 | "name": "[parameters('networkSettings').virtualNetworkName]", 101 | "location": "[parameters('location')]", 102 | "properties": { 103 | "addressSpace": { 104 | "addressPrefixes": [ 105 | "[parameters('networkSettings').addressPrefix]" 106 | ] 107 | }, 108 | "subnets": [ 109 | { 110 | "name": "[parameters('networkSettings').subnet[parameters('subnet')].name]", 111 | "properties": { 112 | "addressPrefix": "[parameters('networkSettings').subnet[parameters('subnet')].prefix]", 113 | "networkSecurityGroup": { 114 | "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSettings').networkSecurityGroupName)]" 115 | } 116 | } 117 | } 118 | ] 119 | } 120 | } 121 | ] 122 | } 123 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Templates/tmpl/data-nodes.yml: -------------------------------------------------------------------------------- 1 | "$schema": https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json# 2 | contentVersion: 1.0.0.0 3 | parameters: 4 | adminUsername: 5 | type: string 6 | metadata: 7 | description: Admin username used when provisioning virtual machines 8 | adminPassword: 9 | type: securestring 10 | metadata: 11 | description: Admin password used when provisioning virtual machines 12 | storageSettings: 13 | type: object 14 | metadata: 15 | description: Storage Account Settings 16 | location: 17 | type: string 18 | metadata: 19 | description: Location where resources will be provisioned 20 | subnet: 21 | type: object 22 | metadata: 23 | description: The name of the subnet to deploy resources into 24 | vmSize: 25 | type: string 26 | defaultValue: Standard_A1 27 | metadata: 28 | description: Size of the Elasticsearch data nodes 29 | vmCount: 30 | type: int 31 | defaultValue: 2 32 | metadata: 33 | description: Number of Elasticsearch data nodes 34 | osSettings: 35 | type: object 36 | metadata: 37 | description: OS settings to deploy on 38 | dataDiskSize: 39 | type: int 40 | defaultValue: 1023 41 | metadata: 42 | description: Size of each data disk attached to data nodes in (Gb) 43 | namespace: 44 | type: string 45 | metadata: 46 | description: The namespace for resources created by this template 47 | variables: 48 | vmStorageAccountContainerName: vhd 49 | subnetRef: "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('subnet').vnet), '/subnets/', parameters('subnet').name)]" 50 | storageAccountName: "[concat(parameters('storageSettings').prefix)]" 51 | vmName: "[parameters('namespace')]" 52 | resources: 53 | - type: Microsoft.Storage/storageAccounts 54 | name: "[concat(variables('storageAccountName'), copyindex(1))]" 55 | apiVersion: 2015-05-01-preview 56 | location: "[parameters('location')]" 57 | copy: 58 | name: "[concat(parameters('namespace'),'storageLoop')]" 59 | count: "[parameters('storageSettings').count]" 60 | properties: 61 | accountType: "[parameters('storageSettings').accountType]" 62 | - apiVersion: '2015-06-15' 63 | type: Microsoft.Compute/availabilitySets 64 | name: "[concat(parameters('namespace'), '-set')]" 65 | location: "[parameters('location')]" 66 | properties: 67 | platformUpdateDomainCount: 20 68 | platformFaultDomainCount: 3 69 | - apiVersion: '2015-06-15' 70 | type: Microsoft.Network/publicIPAddresses 71 | name: "[concat(parameters('namespace'), '-pip-', copyindex())]" 72 | location: "[parameters('location')]" 73 | properties: 74 | publicIPAllocationMethod: Dynamic 75 | - apiVersion: '2015-06-15' 76 | type: Microsoft.Network/networkInterfaces 77 | name: "[concat(parameters('namespace'), '-nic-', copyindex())]" 78 | location: "[parameters('location')]" 79 | copy: 80 | name: "[concat(parameters('namespace'),'nicLoop')]" 81 | count: "[parameters('vmCount')]" 82 | dependsOn: 83 | - "[concat('Microsoft.Network/publicIPAddresses/', parameters('namespace'), '-pip-', copyindex())]" 84 | properties: 85 | ipConfigurations: 86 | - name: ipconfig1 87 | properties: 88 | privateIPAddress: "[concat(parameters('subnet').networkPrefix, '.', string(add(4,copyindex())))]" 89 | privateIPAllocationMethod: Static 90 | subnet: 91 | id: "[variables('subnetRef')]" 92 | - apiVersion: '2015-06-15' 93 | type: Microsoft.Compute/virtualMachines 94 | name: "[concat(parameters('namespace'), '-vm-', copyindex())]" 95 | location: "[parameters('location')]" 96 | copy: 97 | name: "[concat(parameters('namespace'), 'virtualMachineLoop')]" 98 | count: "[parameters('vmCount')]" 99 | dependsOn: 100 | - "[concat('Microsoft.Network/networkInterfaces/', parameters('namespace'), '-nic-', copyindex())]" 101 | - "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), parameters('storageSettings').mapping[copyindex()])]" 102 | properties: 103 | availabilitySet: 104 | id: "[resourceId('Microsoft.Compute/availabilitySets', concat(parameters('namespace'), '-set'))]" 105 | hardwareProfile: 106 | vmSize: "[parameters('vmSize')]" 107 | osProfile: 108 | computername: "[concat(parameters('namespace'), '-vm-', copyIndex())]" 109 | adminUsername: "[parameters('adminUsername')]" 110 | adminPassword: "[parameters('adminPassword')]" 111 | storageProfile: 112 | imageReference: "[parameters('osSettings').imageReference]" 113 | osDisk: 114 | name: osdisk 115 | vhd: 116 | uri: "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyindex()], '.blob.core.windows.net/vhds/', variables('vmName'), '-vm-', copyindex(), '-osdisk.vhd')]" 117 | caching: ReadWrite 118 | createOption: FromImage 119 | dataDisks: 120 | - name: datadisk::index 121 | diskSizeGB: "[parameters('dataDiskSize')]" 122 | lun: 0 123 | vhd: 124 | uri: "[concat('http://', variables('storageAccountName'), parameters('storageSettings').mapping[copyindex()],'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', parameters('namespace'),'-vm-', copyindex(),'dataDisk::index' ,'.vhd')]" 125 | caching: None 126 | createOption: Empty 127 | networkProfile: 128 | networkInterfaces: 129 | - id: "[resourceId('Microsoft.Network/networkInterfaces',concat(parameters('namespace'),'-nic-', copyindex()))]" 130 | resources: 131 | - type: Microsoft.Compute/virtualMachines/extensions 132 | name: "[concat(parameters('namespace'),'-vm-', copyindex(), '/createdatadisk')]" 133 | location: "[parameters('location')]" 134 | apiVersion: '2015-06-15' 135 | dependsOn: 136 | - "[concat('Microsoft.Compute/virtualMachines/', parameters('namespace'), '-vm-', copyindex())]" 137 | properties: "[parameters('osSettings').extentionSettings.eventstore]" 138 | -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Tools/AzCopy.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbolduc/EventStore-DevOps/5ee8b2c6fcfcef55900cf54b5990af6184794b4c/azure-resource-manager/EventStoreCluster/Tools/AzCopy.exe -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Tools/Microsoft.Data.Edm.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbolduc/EventStore-DevOps/5ee8b2c6fcfcef55900cf54b5990af6184794b4c/azure-resource-manager/EventStoreCluster/Tools/Microsoft.Data.Edm.dll -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Tools/Microsoft.Data.OData.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbolduc/EventStore-DevOps/5ee8b2c6fcfcef55900cf54b5990af6184794b4c/azure-resource-manager/EventStoreCluster/Tools/Microsoft.Data.OData.dll -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Tools/Microsoft.Data.Services.Client.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbolduc/EventStore-DevOps/5ee8b2c6fcfcef55900cf54b5990af6184794b4c/azure-resource-manager/EventStoreCluster/Tools/Microsoft.Data.Services.Client.dll -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Tools/Microsoft.WindowsAzure.Storage.DataMovement.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbolduc/EventStore-DevOps/5ee8b2c6fcfcef55900cf54b5990af6184794b4c/azure-resource-manager/EventStoreCluster/Tools/Microsoft.WindowsAzure.Storage.DataMovement.dll -------------------------------------------------------------------------------- /azure-resource-manager/EventStoreCluster/Tools/Microsoft.WindowsAzure.Storage.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbolduc/EventStore-DevOps/5ee8b2c6fcfcef55900cf54b5990af6184794b4c/azure-resource-manager/EventStoreCluster/Tools/Microsoft.WindowsAzure.Storage.dll -------------------------------------------------------------------------------- /azure-resource-manager/README.md: -------------------------------------------------------------------------------- 1 | # Install Event Store cluster on Virtual Machines 2 | 3 | 4 | 5 | 6 | 7 | Create a multi-machine Event Store cluster on Windows (Ubuntu is not complete). This template is heavily influenced by the [Elasticsearch cluster on Virtual Machines](https://github.com/Azure/azure-quickstart-templates/tree/master/elasticsearch) template sample on GitHub. 8 | 9 | Parameters | Default | Description 10 | ------------- | ------------- | ------------- 11 | adminUsername | | The operating system admin username used when provisioning virtual machines 12 | adminPassword | | The operating system admin password used when provisioning virtual machines 13 | location | ResourceGroup | Location where resources will be provisioned. A value of 'ResourceGroup' will deploy the resource to the same location of the resource group the resources are provisioned into 14 | virtualNetworkName | es-vnet | Virtual Network name 15 | OS | windows | The operating system to install on the VM. Allowed values are: windows or ubuntu. (*ubuntu is not complete*) 16 | jumpbox | No | Optionally add a virtual machine to the deployment which you can use to connect and manage virtual machines on the internal network 17 | vmEventStoreNodeCount | 1 | Number of Event Store nodes to provision. The number must be odd. The template limits this to 9. 18 | vmSizeEventStoreNode | Standard_D2 | The VM size to deploy 19 | vmEventStoreDataDiskSize | 4 | Size of each data disk attached to data nodes in (Gb). Each VM size will be provisioned with the maximum number of data disks to maximize the IOPS. In Windows, you can only pool disks that have at least 4GB of contiguous unallocated space. Setting this less than 4 will prevent striping of data disks and the installation will fail. 20 | esVersion | 3.8.1 | The Event Store version to install 21 | githubAccount | pbolduc | The github parameters allow changing the template root URL. This allows customization of the source location install scripts that are uploaded to azure for provisioning. 22 | githubProject | EventStore-DevOps | 23 | githubBranch | master | 24 | 25 | 26 | * a Storage Account for OS Disks 27 | * one or more storage accounts for data disks 28 | * each VM will have multiple data disks striped together for higher IOPS (based on the maximum number of data disks allowed for VM size) 29 | * an Availability Set 30 | * a Virtual Network with a single subnet with 16 available addresses 31 | * a Network Security Group 32 | * a Public IP address for each node 33 | * a NIC for each node 34 | * a VM for each node 35 | 36 | ## Network Security Group configuration 37 | 38 | The network security is setup in [shared-resources.json](EventStoreCluster/Templates/shared-resources.json) 39 | 40 | * Allow Inbound TCP on port 80 41 | * Allow Inbound TCP on port 1113 42 | * Allow Inbound TCP on port 2113 43 | -------------------------------------------------------------------------------- /vagrant-eventstore-cluster/.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | Berksfile.lock 3 | -------------------------------------------------------------------------------- /vagrant-eventstore-cluster/Berksfile: -------------------------------------------------------------------------------- 1 | source "https://supermarket.chef.io" 2 | 3 | cookbook 'eventstore', github: 'pbolduc/eventstore-cookbook' 4 | -------------------------------------------------------------------------------- /vagrant-eventstore-cluster/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /vagrant-eventstore-cluster/README.md: -------------------------------------------------------------------------------- 1 | # vagrant-eventstore-cluster 2 | 3 | 4 | **Note**: cloned from [seif/vagrant-eventstore-cluster](https://github.com/seif/vagrant-eventstore-cluster) 5 | 6 | 7 | Vagrant files to setup a local EventStore cluster using OpsCode Chef Cookbook 8 | 9 | > This is a work in progress. 10 | > Cluster and gossip seem to be setup correctly now, but having issues with Projections. 11 | 12 | ## Usage 13 | 14 | ### Install Vagrant 15 | 16 | Download and install [Vagrant](http://downloads.vagrantup.com/). 17 | 18 | ### Install Vagrant plugins 19 | 20 | ``` bash 21 | vagrant plugin install vagrant-berkshelf 22 | vagrant plugin install vagrant-omnibus 23 | vagrant plugin install vagrant-cachier 24 | ``` 25 | 26 | ### Clone this repository 27 | 28 | ``` bash 29 | git clone https://github.com/seif/vagrant-eventstore-cluster.git 30 | cd vagrant-eventstore-cluster 31 | ``` 32 | 33 | ### Start the cluster 34 | 35 | ``` bash 36 | vagrant up 37 | ``` 38 | 39 | Wait for all operations to complete, the cluster nodes should now be available at the address 33.33.33.10, 33.33.33.20 and 33.33.33.30 40 | 41 | ## Customising 42 | 43 | ### Vagrant configuration 44 | 45 | There are some variables at the top of the file which you can use to customise the cluster: 46 | 47 | * **NODE_COUNT:** The number of nodes in the cluster. 48 | * **IP_INCREMENT:** How much to increment the ip of each node by. 49 | * **BASE_IP:** The first 3 octects that will make up the ip, the last octet is made up of the IP_INCREMENT * node index. 50 | 51 | ### EventStore configuration 52 | 53 | The [Event Store cookbook](http://community.opscode.com/cookbooks/eventstore) is used to provision the machines. 54 | 55 | EventStore configuration parameters can be passed in by modifying the Vagrantfile and adding some keys/values to the eventstore/config hash. Any added keys will be put into the /etc/eventstore/config.json file. 56 | 57 | 58 | -------------------------------------------------------------------------------- /vagrant-eventstore-cluster/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | NODE_COUNT = 3 5 | BASE_IP = "33.33.33" 6 | IP_INCREMENT = 10 7 | 8 | seeds = [] 9 | 10 | (1..NODE_COUNT).each do |index| 11 | last_octet = index * IP_INCREMENT 12 | node_ip = "#{BASE_IP}.#{last_octet}" 13 | seeds << {'index' => index, 14 | 'name' => "node#{index}", 15 | 'ip' => node_ip} 16 | end 17 | 18 | Vagrant.configure("2") do |cluster| 19 | # Install latest chef on the client node, requires vagrant-omnibus plugin 20 | cluster.omnibus.chef_version = :latest 21 | 22 | # Configure caching, so that cache can be shared among nodes, minimising downloads. Requires vagrant-cachier plugin 23 | # Uncomment next line to enable cachier, seems to cause problems on windows 24 | cluster.cache.auto_detect = true 25 | 26 | # Enable berkshelf because it makes manages cookbooks much simpler. Required vagrant-berkshelf plugin 27 | cluster.berkshelf.enabled = true 28 | 29 | 30 | seeds.each do |seed| 31 | cluster.vm.define seed['name'] do |config| 32 | config.vm.box = "ubuntu/trusty64" 33 | config.vm.provider(:virtualbox) { |v| v.customize ["modifyvm", :id, "--memory", 1024] } 34 | 35 | config.vm.hostname = seed['name'] 36 | config.vm.network :private_network, ip: seed['ip'] 37 | 38 | # Provision using Chef. 39 | config.vm.provision :chef_solo do |chef| 40 | chef.json = { 41 | :eventstore => { 42 | :config => { 43 | :IntIp => seed['ip'], 44 | :ExtIp => seed['ip'], 45 | :IntHttpPort => 2112, 46 | :ExtHttpPort => 2113, 47 | :IntTcpPort => 1112, 48 | :ExtTcpPort => 1113, 49 | :ClusterSize => NODE_COUNT, 50 | :DiscoverViaDns => false, 51 | :GossipSeed => seeds.reject{|s| s['index'] == seed['index']}.map{|i| "#{i['ip']}:2112"} 52 | } 53 | } 54 | } 55 | chef.add_recipe "eventstore" 56 | end 57 | end 58 | end 59 | end 60 | --------------------------------------------------------------------------------