├── scripts ├── placeholder.txt ├── SetupServiceFabric │ ├── README.md │ └── SetupServiceFabric.sh ├── CodePackageToDockerPackage │ ├── README.md │ └── CreateDockerPackage.ps1 └── BackupRetentionScript │ ├── modules │ ├── README.md │ ├── RetentionScript.psm1 │ ├── RetentionScriptAzureBlobStore.psm1 │ ├── RetentionScriptFileShare.psm1 │ └── UtilScript.psm1 │ ├── README.md │ ├── RetentionScript.ps1 │ ├── RetentionScriptAzureBlobStore.ps1 │ ├── RetentionScriptFileShare.ps1 │ └── UtilScript.ps1 ├── templates ├── placeholder.txt ├── service-integration │ ├── network-apim.parameters.json │ ├── apim.parameters.json │ ├── network-apim.json │ └── apim.json ├── nodetype-upgrade │ ├── parameters.json │ └── README.md ├── nodetype-upgrade-nonprimary │ ├── parameters.json │ └── README.md ├── cluster-tutorial │ ├── vnet-cluster.parameters.json │ └── vnet-linuxcluster.parameters.json └── networking │ ├── template_original.json │ └── template_existingvnet.json ├── docker └── service-fabric-reliableservices-windowsservercore │ ├── Dockerfile │ ├── README.md │ └── InstallPreReq.ps1 ├── code └── SFBinaryLoaderForContainers │ ├── README.md │ └── SFBinaryLoader.cs ├── README.md ├── LICENSE ├── SECURITY.md └── .gitignore /scripts/placeholder.txt: -------------------------------------------------------------------------------- 1 | Create a new directory for each script here. -------------------------------------------------------------------------------- /templates/placeholder.txt: -------------------------------------------------------------------------------- 1 | Create a new directory for each Resource Manager template here. -------------------------------------------------------------------------------- /docker/service-fabric-reliableservices-windowsservercore/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/windows/servercore:ltsc2016 2 | ADD InstallPreReq.ps1 / 3 | RUN powershell -File C:\InstallPreReq.ps1 4 | RUN setx PATH "%PATH%;C:\sffabricbin;C:\sffabricruntimeload" /M -------------------------------------------------------------------------------- /docker/service-fabric-reliableservices-windowsservercore/README.md: -------------------------------------------------------------------------------- 1 | # About 2 | This folder has Dockerfile to create a Windows Server Core image with prerequisites and environment variables setup to run Service Fabric services inside containers. 3 | 4 | ## More details 5 | For more information, see the [How to containerize your Service Fabric Services](https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-services-inside-containers) 6 | -------------------------------------------------------------------------------- /code/SFBinaryLoaderForContainers/README.md: -------------------------------------------------------------------------------- 1 | 2 | # About SFBinaryLoader.cs Script 3 | This class is sample code on how to load the Service Fabric binaries when hosting service fabric services from within containers. This code should be included in your project and referenced from program main. 4 | 5 | ## More details 6 | For more details, see the [How to containerize your Service Fabric Services](https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-services-inside-containers). 7 | -------------------------------------------------------------------------------- /templates/service-integration/network-apim.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "apimNetworkSecurityGroupName": { 6 | "value": "apim-vnet-security" 7 | }, 8 | "vnetAddressSpace": { 9 | "value": "172.16.0.0/20" 10 | }, 11 | "apimSubnetSpace": { 12 | "value": "172.16.0.0/27" 13 | }, 14 | "apimSubnetName": { 15 | "value": "apim-subnet" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /scripts/SetupServiceFabric/README.md: -------------------------------------------------------------------------------- 1 | 2 | # About SetupServiceFabric.sh Script 3 | This script is used for automated installation of Service Fabric Runtime and Common SDK on Linux. 4 | It also sets up the Service Fabric CLI 'sfctl'. 5 | 6 | ## Usage 7 | Use following command for automated installation of Service Fabric Runtime and Common SDK. 8 | 9 | ```bash 10 | git clone https://github.com/Azure/service-fabric-scripts-and-templates.git 11 | cd scripts/SetupServiceFabric 12 | sudo ./SetupServiceFabric.sh 13 | ``` 14 | 15 | ## More details 16 | For more details, see the [Service Fabric get started on Linux](https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-get-started-linux). 17 | -------------------------------------------------------------------------------- /scripts/CodePackageToDockerPackage/README.md: -------------------------------------------------------------------------------- 1 | 2 | # About CreateDockerPackage.ps1 Script 3 | This script is a utility used to help convert your service fabric code package to a container package. 4 | 5 | ## Usage 6 | 7 | ```powershell 8 | $codePackagePath = 'Path to the code package to containerize.' 9 | $dockerPackageOutputDirectoryPath = 'Output path for the generated docker folder.' 10 | $applicationExeName = 'Name of the ode package executable.' 11 | CreateDockerPackage.ps1 -CodePackageDirectoryPath $codePackagePath -DockerPackageOutputDirectoryPath $dockerPackageOutputDirectoryPath -ApplicationExeName $applicationExeName 12 | ``` 13 | 14 | ## More details 15 | For more information, see the [How to containerize your Service Fabric Services](https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-services-inside-containers) 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributing 3 | 4 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 5 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 6 | the rights to use your contribution. For details, visit https://cla.microsoft.com. 7 | 8 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide 9 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions 10 | provided by the bot. You will only need to do this once across all repos using our CLA. 11 | 12 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 13 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 14 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 15 | -------------------------------------------------------------------------------- /scripts/BackupRetentionScript/modules/README.md: -------------------------------------------------------------------------------- 1 | 2 | # About the scripts: 3 | Service Fabric Backup Restore Service (https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-backuprestoreservice-quickstart-azurecluster), 4 | currently in preview, allows you to take periodic backups of your Reliable stateful service and Reliable Actors. Depending on the frequency of your backup interval, backups can really grow fast. 5 | While we work on providing retention support integrated with the service, this script would help you manage your storage till that time. It allows you to delete backups older than a specified time. 6 | 7 | ## Usage 8 | Import all the modules, and the use of these modules is same as of RetentionScript.ps1. 9 | Example: 10 | ```powershell 11 | Start-RetentionScript -DateTimeBefore "2018-06-18 23.44.03Z" -ConnectionString "your-connection-string" -ClusterEndPoint "clustername.centralus.cloupapp.azure.com:19080" -SSLCertificateThumbPrint "Client#Certificate#Thumbpring" -ServiceId "WebReferenceApplication~RestockRequestManager" 12 | ``` 13 | These modules come in handy while scheduling the script from azure time trigger. 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /templates/nodetype-upgrade/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "clusterLocation": { 6 | "value": "southcentralus" 7 | }, 8 | "clusterName": { 9 | "value": "sftestupgrade" 10 | }, 11 | "adminUserName": { 12 | "value": "testadmin" 13 | }, 14 | "adminPassword": { 15 | "value": "Password#1234" 16 | }, 17 | "loadBalancedAppPort1": { 18 | "value": 80 19 | }, 20 | "loadBalancedAppPort2": { 21 | "value": 443 22 | }, 23 | "clusterProtectionLevel": { 24 | "value": "EncryptAndSign" 25 | }, 26 | "certificateStoreValue": { 27 | "value": "My" 28 | }, 29 | "certificateThumbprint": { 30 | "value": "" 31 | }, 32 | "sourceVaultValue": { 33 | "value": "" 34 | }, 35 | "certificateUrlValue": { 36 | "value": "" 37 | }, 38 | "storageAccountType": { 39 | "value": "Standard_LRS" 40 | }, 41 | "supportLogStorageAccountType": { 42 | "value": "Standard_LRS" 43 | }, 44 | "applicationDiagnosticsStorageAccountType": { 45 | "value": "Standard_LRS" 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /templates/nodetype-upgrade-nonprimary/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "clusterLocation": { 6 | "value": "southcentralus" 7 | }, 8 | "clusterName": { 9 | "value": "sftestupgrade" 10 | }, 11 | "adminUserName": { 12 | "value": "testadmin" 13 | }, 14 | "adminPassword": { 15 | "value": "Password#1234" 16 | }, 17 | "loadBalancedAppPort1": { 18 | "value": 80 19 | }, 20 | "loadBalancedAppPort2": { 21 | "value": 443 22 | }, 23 | "clusterProtectionLevel": { 24 | "value": "EncryptAndSign" 25 | }, 26 | "certificateStoreValue": { 27 | "value": "My" 28 | }, 29 | "certificateThumbprint": { 30 | "value": "" 31 | }, 32 | "sourceVaultValue": { 33 | "value": "" 34 | }, 35 | "certificateUrlValue": { 36 | "value": "" 37 | }, 38 | "storageAccountType": { 39 | "value": "Standard_LRS" 40 | }, 41 | "supportLogStorageAccountType": { 42 | "value": "Standard_LRS" 43 | }, 44 | "applicationDiagnosticsStorageAccountType": { 45 | "value": "Standard_LRS" 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /code/SFBinaryLoaderForContainers/SFBinaryLoader.cs: -------------------------------------------------------------------------------- 1 | namespace StatelessContainer 2 | { 3 | using System; 4 | using System.IO; 5 | using System.Reflection; 6 | 7 | public static class SFBinaryLoader 8 | { 9 | private const string FabricCodePathEnvironmentVariableName = "FabricCodePath"; 10 | private static string SFCodePath; 11 | 12 | static SFBinaryLoader() 13 | { 14 | AppDomain.CurrentDomain.AssemblyResolve += LoadFromFabricCodePath; 15 | } 16 | 17 | public static void Initialize() 18 | { 19 | SFCodePath = Environment.GetEnvironmentVariable(FabricCodePathEnvironmentVariableName, EnvironmentVariableTarget.Process); 20 | } 21 | 22 | private static Assembly LoadFromFabricCodePath(object sender, ResolveEventArgs args) 23 | { 24 | string assemblyName = new AssemblyName(args.Name).Name; 25 | 26 | if (string.IsNullOrEmpty(SFCodePath)) 27 | { 28 | throw new InvalidOperationException("The path from where to resolve the Service Fabric binaries has not been set; please try calling SFBinaryLoader.Initialize()."); 29 | } 30 | 31 | try 32 | { 33 | string assemblyPath = Path.Combine(SFCodePath, assemblyName + ".dll"); 34 | if (File.Exists(assemblyPath)) 35 | { 36 | return Assembly.LoadFrom(assemblyPath); 37 | } 38 | } 39 | catch (Exception e) 40 | { 41 | // Supress any Exception so that we can continue to 42 | // load the assembly through other means 43 | Console.WriteLine("Exception in LoadFromFabricCodePath={0}", e.ToString()); 44 | } 45 | 46 | return null; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /templates/cluster-tutorial/vnet-cluster.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vnetName": { 6 | "value": "sf-vnet" 7 | }, 8 | "vnetAddressSpace": { 9 | "value": "172.16.0.0/20" 10 | }, 11 | "sfSubnetSpace": { 12 | "value": "172.16.2.0/23" 13 | }, 14 | "sfSubnetName": { 15 | "value": "sf-subnet" 16 | }, 17 | "location":{ 18 | "value": "southcentralus" 19 | }, 20 | "clusterName": { 21 | "value": "mysfcluster123" 22 | }, 23 | "adminUserName": { 24 | "value": "adminuser" 25 | }, 26 | "adminPassword": { 27 | "value": "Pa$sw00rd!123" 28 | }, 29 | "certificateThumbprint": { 30 | "value": "" 31 | }, 32 | "sourceVaultValue": { 33 | "value": "" 34 | }, 35 | "certificateUrlValue": { 36 | "value": "" 37 | }, 38 | "subnetName": { 39 | "value": "sf-subnet" 40 | }, 41 | "networkSecurityGroupName": { 42 | "value": "sf-vnet-security" 43 | }, 44 | "vmImagePublisher": { 45 | "value": "MicrosoftWindowsServer" 46 | }, 47 | "vmImageOffer": { 48 | "value": "WindowsServer" 49 | }, 50 | "vmImageSku": { 51 | "value": "2016-Datacenter-with-Containers" 52 | }, 53 | "vmImageVersion": { 54 | "value": "latest" 55 | }, 56 | "loadBalancedAppPort1": { 57 | "value": 80 58 | }, 59 | "loadBalancedAppPort2": { 60 | "value": 443 61 | }, 62 | "certificateStoreValue": { 63 | "value": "My" 64 | }, 65 | "clusterProtectionLevel": { 66 | "value": "EncryptAndSign" 67 | }, 68 | "storageAccountType": { 69 | "value": "Standard_LRS" 70 | }, 71 | "supportLogStorageAccountType": { 72 | "value": "Standard_LRS" 73 | }, 74 | "applicationDiagnosticsStorageAccountType": { 75 | "value": "Standard_LRS" 76 | }, 77 | "nt0InstanceCount": { 78 | "value": 5 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /templates/cluster-tutorial/vnet-linuxcluster.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vnetName": { 6 | "value": "sf-vnet" 7 | }, 8 | "vnetAddressSpace": { 9 | "value": "10.0.0.0/16" 10 | }, 11 | "sfSubnetSpace": { 12 | "value": "10.0.2.0/24" 13 | }, 14 | "sfSubnetName": { 15 | "value": "sf-subnet" 16 | }, 17 | "location":{ 18 | "value": "southcentralus" 19 | }, 20 | "clusterName": { 21 | "value": "mysfcluster" 22 | }, 23 | "adminUserName": { 24 | "value": "adminuser" 25 | }, 26 | "adminPassword": { 27 | "value": "Pa$sw00rd!123" 28 | }, 29 | "certificateThumbprint": { 30 | "value": "" 31 | }, 32 | "sourceVaultValue": { 33 | "value": "" 34 | }, 35 | "certificateUrlValue": { 36 | "value": "" 37 | }, 38 | "subnetName": { 39 | "value": "sf-subnet" 40 | }, 41 | "networkSecurityGroupName": { 42 | "value": "sf-vnet-security" 43 | }, 44 | "vmImagePublisher": { 45 | "value": "Canonical" 46 | }, 47 | "vmImageOffer": { 48 | "value": "UbuntuServer" 49 | }, 50 | "vmImageSku": { 51 | "value": "16.04-LTS" 52 | }, 53 | "vmImageVersion": { 54 | "value": "latest" 55 | }, 56 | "loadBalancedAppPort1": { 57 | "value": 80 58 | }, 59 | "loadBalancedAppPort2": { 60 | "value": 443 61 | }, 62 | "certificateStorevalue": { 63 | "value": "My" 64 | }, 65 | "clusterProtectionLevel": { 66 | "value": "EncryptAndSign" 67 | }, 68 | "storageAccountType": { 69 | "value": "Standard_LRS" 70 | }, 71 | "supportLogStorageAccountType": { 72 | "value": "Standard_LRS" 73 | }, 74 | "applicationDiagnosticsStorageAccountType": { 75 | "value": "Standard_LRS" 76 | }, 77 | "nt0InstanceCount": { 78 | "value": 5 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /templates/service-integration/apim.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "apimInstanceName": { 6 | "value": "sfapim" 7 | }, 8 | "apimPublisherEmail": { 9 | "value": "user@contoso.com" 10 | }, 11 | "apimSku": { 12 | "value": "Developer" 13 | }, 14 | "serviceFabricCertificateName": { 15 | "value": "sfclustertutorialgroup320171031144217" 16 | }, 17 | "serviceFabricCertificate": { 18 | "value": "" 19 | }, 20 | "certificatePassword": { 21 | "value": "q6D7nN%6ck@6" 22 | }, 23 | "serviceFabricCertificateThumbprint": { 24 | "value": "" 25 | }, 26 | "url_path": { 27 | "value": "/api/values" 28 | }, 29 | "clusterHttpManagementEndpoint": { 30 | "value": "https://mysfcluster123.southcentralus.cloudapp.azure.com:19080" 31 | }, 32 | "inbound_policy":{ 33 | "value": "\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n" 34 | }, 35 | "policies_policy_name": { 36 | "value": "policy" 37 | }, 38 | "apis_service_fabric_app_name": { 39 | "value": "service-fabric-app" 40 | }, 41 | "apim_service_fabric_product_name": { 42 | "value": "service-fabric-api-product" 43 | }, 44 | "service_fabric_backend_name": { 45 | "value": "servicefabric" 46 | }, 47 | "apis_service_fabric_app_name_operation": { 48 | "value": "service-fabric-app-operation" 49 | }, 50 | "vnetName": { 51 | "value": "sf-vnet" 52 | }, 53 | "subnetName": { 54 | "value": "apim-subnet" 55 | }, 56 | "vnetVersion": { 57 | "value": "2017-03-01" 58 | }, 59 | "networkSecurityGroupName": { 60 | "value": "apim-vnet-security" 61 | }, 62 | "networkSecurityGroupVersion": { 63 | "value": "2017-03-01" 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /docker/service-fabric-reliableservices-windowsservercore/InstallPreReq.ps1: -------------------------------------------------------------------------------- 1 | $scriptDirectory = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition 2 | $containerSetupLogDirectory = Join-Path $scriptDirectory "ContainerSetupLogs" 3 | 4 | $dotnetUrl = "https://download.visualstudio.microsoft.com/download/pr/518aafee-1285-4153-a30a-e4eefd538c90/6437d77a67b9c6b8cf0b7b3323004229/dotnet-runtime-3.1.6-win-x64.exe" 5 | $vcpp11redistUrl = "https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x64.exe" 6 | $vcpp14redistUrl = "https://download.visualstudio.microsoft.com/download/pr/11687625/2cd2dba5748dc95950a5c42c2d2d78e4/VC_redist.x64.exe" 7 | 8 | $TempDir = $env:TEMP 9 | $dotnetPath = Join-Path $TempDir "dotnet-runtime-3.1.6-win-x64.exe" 10 | $vcpp11redistPath = Join-Path $TempDir "vcredist_x64.exe" 11 | $vcpp14redistPath = Join-Path $TempDir "vc14_redist.x64.exe" 12 | 13 | $DownloadStartTime = [DateTime]::UtcNow 14 | 15 | $webClient = New-Object System.Net.WebClient 16 | $webClient.DownloadFile($vcpp11redistUrl, $vcpp11redistPath) 17 | 18 | $DownloadEndTime = [DateTime]::UtcNow 19 | 20 | if(Test-Path($vcpp11redistPath)) 21 | { 22 | Write-Output "$($vcpp11redistPath) file download Time: $(($DownloadEndTime).Subtract($DownloadStartTime).TotalSeconds) secs" 23 | 24 | Write-Output "Installing vc++ 11 Redistributable..." 25 | 26 | Start-Process "$vcpp11redistPath" -ArgumentList "/install /quiet /norestart /log $(Join-Path $containerSetupLogDirectory vcpp11redistlog.txt)" -Wait 27 | 28 | Write-Output "Done." 29 | } 30 | else 31 | { 32 | Write-Error "Download failed" 33 | } 34 | 35 | $DownloadStartTime = [DateTime]::UtcNow 36 | 37 | $webClient.DownloadFile($vcpp14redistUrl, $vcpp14redistPath) 38 | 39 | $DownloadEndTime = [DateTime]::UtcNow 40 | 41 | if(Test-Path($vcpp14redistPath)) 42 | { 43 | Write-Output "$($vcpp14redistPath) file download Time: $(($DownloadEndTime).Subtract($DownloadStartTime).TotalSeconds) secs" 44 | 45 | Write-Output "Installing vc++ 14 Redistributable..." 46 | 47 | Start-Process "$vcpp14redistPath" -ArgumentList "/install /quiet /norestart /log $(Join-Path $containerSetupLogDirectory vcpp14redistlog.txt)" -Wait 48 | 49 | Write-Output "Done." 50 | } 51 | else 52 | { 53 | Write-Error "Download failed" 54 | } 55 | 56 | $DownloadStartTime = [DateTime]::UtcNow 57 | 58 | $webClient.DownloadFile($dotnetUrl, $dotnetPath) 59 | 60 | $DownloadEndTime = [DateTime]::UtcNow 61 | 62 | if(Test-Path($dotnetPath)) 63 | { 64 | Write-Output "$($dotnetPath) file download Time: $(($DownloadEndTime).Subtract($DownloadStartTime).TotalSeconds) secs" 65 | 66 | Write-Output "Installing dotnet 3.1.6..." 67 | 68 | Start-Process "$dotnetPath" -ArgumentList "/install /quiet /norestart /log $(Join-Path $containerSetupLogDirectory log.txt)" -Wait 69 | 70 | Write-Output "Done." 71 | } 72 | else 73 | { 74 | Write-Error "Download failed" 75 | } 76 | -------------------------------------------------------------------------------- /templates/service-integration/network-apim.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vnetName": { 6 | "defaultValue": "sf-vnet", 7 | "type": "string" 8 | }, 9 | "vnetAddressSpace": { 10 | "defaultValue": "172.16.0.0/20", 11 | "type": "string" 12 | }, 13 | "apimSubnetName": { 14 | "defaultValue": "apim-subnet", 15 | "type": "string" 16 | }, 17 | "apimSubnetSpace": { 18 | "defaultValue": "172.16.0.0/27", 19 | "type": "string" 20 | }, 21 | "apimNetworkSecurityGroupName": { 22 | "defaultValue": "apim-vnet-security", 23 | "type": "string" 24 | } 25 | }, 26 | "variables": { 27 | "location": "[string(resourceGroup().location)]", 28 | "vnetApiVersion": "2017-03-01", 29 | "sgApiVersion": "2017-03-01" 30 | }, 31 | "outputs": { 32 | "vnet": { 33 | "type": "object", 34 | "value": "[reference(parameters('vnetName'))]" 35 | }, 36 | "vnetVersion": { 37 | "type": "string", 38 | "value": "[variables('vnetApiVersion')]" 39 | }, 40 | "vnetName": { 41 | "type": "string", 42 | "value": "[parameters('vnetName')]" 43 | }, 44 | "sgVersion": { 45 | "type": "string", 46 | "value": "[variables('sgApiVersion')]" 47 | }, 48 | "apimSubnetName": { 49 | "type": "string", 50 | "value": "[parameters('apimSubnetName')]" 51 | }, 52 | "apimSgName": { 53 | "type": "string", 54 | "value": "[parameters('apimNetworkSecurityGroupName')]" 55 | } 56 | }, 57 | "resources": [ 58 | { 59 | 60 | "apiVersion": "[variables('sgApiversion')]", 61 | 62 | "type": "Microsoft.Network/virtualNetworks/subnets", 63 | 64 | "name": "[concat(parameters('vnetName'), '/', parameters('apimSubnetName'))]", 65 | 66 | "location": "[variables('location')]", 67 | 68 | "properties": { 69 | "addressPrefix": "[parameters('apimSubnetSpace')]", 70 | "networkSecurityGroup": { 71 | "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('apimNetworkSecurityGroupName'))]" 72 | } 73 | }, 74 | "dependsOn": [ 75 | "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('apimNetworkSecurityGroupName'))]" 76 | ] 77 | 78 | }, 79 | { 80 | "type": "Microsoft.Network/networkSecurityGroups", 81 | "name": "[parameters('apimNetworkSecurityGroupName')]", 82 | "apiVersion": "[variables('sgApiversion')]", 83 | "location": "[variables('location')]", 84 | "tags": { 85 | "resourceType": "API Management" 86 | } 87 | } 88 | ], 89 | "outputs": {} 90 | } -------------------------------------------------------------------------------- /scripts/CodePackageToDockerPackage/CreateDockerPackage.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [Parameter(Mandatory=$true, ParameterSetName = "Exe")] 3 | [Parameter(Mandatory=$true, ParameterSetName = "Dll")] 4 | [string] $CodePackageDirectoryPath, 5 | 6 | [Parameter(Mandatory=$true, ParameterSetName = "Exe")] 7 | [Parameter(Mandatory=$true, ParameterSetName = "Dll")] 8 | [string] $DockerPackageOutputDirectoryPath, 9 | 10 | [Parameter(Mandatory=$false, ParameterSetName = "Exe")] 11 | [string] $ApplicationExeName, 12 | 13 | [Parameter(Mandatory=$false, ParameterSetName = "Dll")] 14 | [string] $DotnetCoreDllName 15 | ) 16 | 17 | if(!(Test-Path -Path $CodePackageDirectoryPath)) 18 | { 19 | Write-Error "CodePackageDirectoryPath does not exist." 20 | exit 1 21 | } 22 | 23 | if(!(Test-Path -Path $DockerPackageOutputDirectoryPath)) 24 | { 25 | Write-Host $DockerPackageOutputDirectoryPath "does not exist. Creating directory.." 26 | New-Item -ItemType directory $DockerPackageOutputDirectoryPath | Out-Null 27 | Write-Host "Created " $DockerPackageOutputDirectoryPath 28 | } 29 | 30 | # Remove publish folder if it exists, and remove the dockerfile 31 | $DockerPublishPath = Join-Path $DockerPackageOutputDirectoryPath -ChildPath "publish" 32 | if(Test-Path -Path $DockerPublishPath) 33 | { 34 | Remove-Item -Path $DockerPublishPath -Recurse -Force 35 | Write-Host "Removed existing publish directory." 36 | } 37 | 38 | $dockerfilePath = Join-Path $DockerPackageOutputDirectoryPath -ChildPath "Dockerfile" 39 | if(Test-Path -Path $dockerfilePath) 40 | { 41 | Remove-Item -Path $dockerfilePath -Force 42 | Write-Host "Removed existing Dockerfile." 43 | } 44 | 45 | $DockerPublishPath = Join-Path $DockerPackageOutputDirectoryPath -ChildPath "publish" 46 | if(!(Test-Path -Path $DockerPublishPath)) 47 | { 48 | New-Item -ItemType directory $DockerPublishPath | Out-Null 49 | Write-Host "Created " $DockerPublishPath 50 | } 51 | 52 | 53 | Write-Host "Copying all files from " $CodePackageDirectoryPath " to " $DockerPublishPath 54 | $SourceCopyPath = Join-Path $CodePackageDirectoryPath -ChildPath "*" 55 | Copy-Item -Path $SourceCopyPath -Destination $DockerPublishPath -Recurse -Force 56 | Write-Host "Files successfully copied." 57 | 58 | Remove-Item $CodePackageDirectoryPath -Recurse -Force 59 | Write-Host "Removed " $CodePackageDirectoryPath 60 | 61 | $initScriptPath = Join-Path $DockerPublishPath -ChildPath "init.bat" 62 | 63 | if ($ApplicationExeName) 64 | { 65 | $initScriptContents = [System.IO.Path]::GetFileNameWithoutExtension($ApplicationExeName) + ".exe" 66 | } 67 | elseif ($DotnetCoreDllName) 68 | { 69 | $initScriptContents = "dotnet " + [System.IO.Path]::GetFileNameWithoutExtension($DotnetCoreDllName) + ".dll" 70 | } 71 | else 72 | { 73 | $warning = "Modify init.bat inside " + $DockerPublishPath + " to include the name of your startup executable." 74 | Write-Warning $warning 75 | } 76 | 77 | Write-Host "Creating init.bat for docker package" 78 | New-Item -ItemType file $initScriptPath -Value $initScriptContents -Force | Out-Null 79 | 80 | $dockerfilePath = Join-Path $DockerPackageOutputDirectoryPath -ChildPath "Dockerfile" 81 | $dockerfileContents = 'FROM mcr.microsoft.com/windows/servercore:ltsc2019 82 | ADD https://raw.githubusercontent.com/microsoft/service-fabric-scripts-and-templates/master/docker/service-fabric-reliableservices-windowsservercore/InstallPreReq.ps1 / 83 | RUN powershell -File C:\InstallPreReq.ps1 84 | RUN setx PATH "%PATH%;C:\sffabricbin;C:\sffabricruntimeload" /M 85 | ADD publish/ / 86 | CMD C:\init.bat' 87 | 88 | Write-Host "Creating Dockerfile" 89 | New-Item -ItemType file $dockerfilePath -Value $dockerfileContents -Force | Out-Null 90 | 91 | Write-Host "Docker package successfully created at " $DockerPackageOutputDirectoryPath 92 | -------------------------------------------------------------------------------- /templates/nodetype-upgrade-nonprimary/README.md: -------------------------------------------------------------------------------- 1 | # Scale up a Service Fabric cluster non-primary node type 2 | 3 | These before/after templates represent the steps of upgrading the primary node type VM size and operating system of an example cluster. 4 | 5 | The initial state of the example test cluster consists of two node types of Silver durability, backed by a single scale set with five nodes. The upgraded state of the cluster adds an additional, upgraded scale set (with VM size from Standard_D2_V2 to Standard D4_V2, and OS from Windows Server 2019 to 2022 Datacenter). Follow these commands to walkthrough the complete upgrade scenario. For a more detailed discussion of the procedure, see [Scale up a Service Fabric cluster primary node type](https://docs.microsoft.com/azure/service-fabric/service-fabric-scale-up-primary-node-type). 6 | 7 | ```powershell 8 | # Sign in to your Azure account 9 | Login-AzAccount -SubscriptionId "" 10 | 11 | # Assign deployment variables 12 | $resourceGroupName = "sftestupgradegroup" 13 | $certOutputFolder = "c:\certificates" 14 | $certPassword = "Password!1" | ConvertTo-SecureString -AsPlainText -Force 15 | $certSubjectName = "sftestupgrade.southcentralus.cloudapp.azure.com" 16 | $templateFilePath = "C:\Initial-TestClusterSetup.json" 17 | $parameterFilePath = "C:\parameters.json" 18 | 19 | # Deploy the initial test cluster 20 | New-AzServiceFabricCluster ` 21 | -ResourceGroupName $resourceGroupName ` 22 | -CertificateOutputFolder $certOutputFolder ` 23 | -CertificatePassword $certPassword ` 24 | -CertificateSubjectName $certSubjectName ` 25 | -TemplateFile $templateFilePath ` 26 | -ParameterFile $parameterFilePath 27 | 28 | # Import the local .pfx file to your certificate store 29 | cd c:\certificates 30 | $certPfx = ".\sftestupgradegroup20200312121003.pfx" 31 | 32 | Import-PfxCertificate ` 33 | -FilePath $certPfx ` 34 | -CertStoreLocation Cert:\CurrentUser\My ` 35 | -Password (ConvertTo-SecureString Password!1 -AsPlainText -Force) 36 | 37 | # Connect to the cluster and check health 38 | $clusterName = "sftestupgrade.southcentralus.cloudapp.azure.com:19000" 39 | $thumb = "BB796AA33BD9767E7DA27FE5182CF8FDEE714A70" 40 | 41 | Connect-ServiceFabricCluster ` 42 | -ConnectionEndpoint $clusterName ` 43 | -KeepAliveIntervalInSec 10 ` 44 | -X509Credential ` 45 | -ServerCertThumbprint $thumb ` 46 | -FindType FindByThumbprint ` 47 | -FindValue $thumb ` 48 | -StoreLocation CurrentUser ` 49 | -StoreName My 50 | 51 | Get-ServiceFabricClusterHealth 52 | 53 | # Find your certificate Key Vault references (in Azure portal) 54 | $certUrlValue = "https://sftestupgradegroup.vault.azure.net/secrets/sftestupgradegroup20200309235308/dac0e7b7f9d4414984ccaa72bfb2ea39" 55 | $thumb = "BB796AA33BD9767E7DA27FE5182CF8FDEE714A70" 56 | $sourceVaultValue = "/subscriptions/########-####-####-####-############/resourceGroups/sftestupgradegroup/providers/Microsoft.KeyVault/vaults/sftestupgradegroup" 57 | 58 | # Deploy the updated template with new scale set (upgraded to use managed disks) 59 | $templateFilePath = "C:\Step1-AddNonPrimaryNodeType.json" 60 | 61 | New-AzResourceGroupDeployment ` 62 | -ResourceGroupName $resourceGroupName ` 63 | -TemplateFile $templateFilePath ` 64 | -TemplateParameterFile $parameterFilePath ` 65 | -CertificateThumbprint $thumb ` 66 | -CertificateUrlValue $certUrlValue ` 67 | -SourceVaultValue $sourceVaultValue ` 68 | -Verbose 69 | 70 | # Ensure cluster is healthy, then disable nodes in the original scale set 71 | Get-ServiceFabricClusterHealth 72 | 73 | # Disable the nodes in the original scale set. 74 | $nodeType = "nt1vm" 75 | $nodes = Get-ServiceFabricNode 76 | 77 | Write-Host "Disabling nodes..." 78 | foreach($node in $nodes) 79 | { 80 | if ($node.NodeType -eq $nodeType) 81 | { 82 | $node.NodeName 83 | 84 | Disable-ServiceFabricNode -Intent RemoveNode -NodeName $node.NodeName -Force 85 | } 86 | } 87 | 88 | # Stop data on the disabled nodes. 89 | foreach($node in $nodes) 90 | { 91 | if ($node.NodeType -eq $nodeType) 92 | { 93 | $node.NodeName 94 | 95 | Start-ServiceFabricNodeTransition -Stop -OperationId (New-Guid) -NodeInstanceId $node.NodeInstanceId -NodeName $node.NodeName -StopDurationInSeconds 10000 96 | } 97 | } 98 | 99 | # Remove the original scale set 100 | $scaleSetName = "nt1vm" 101 | $scaleSetResourceType = "Microsoft.Compute/virtualMachineScaleSets" 102 | 103 | Remove-AzResource -ResourceName $scaleSetName -ResourceType $scaleSetResourceType -ResourceGroupName $resourceGroupName -Force 104 | 105 | # Delete the original IP and load balancer resources 106 | $lbName = "LB-sftestupgrade-nt1vm" 107 | $lbResourceType = "Microsoft.Network/loadBalancers" 108 | $ipResourceType = "Microsoft.Network/publicIPAddresses" 109 | $oldPublicIpName = "PublicIP-LB-FE-nt0vm" 110 | 111 | Remove-AzResource -ResourceName $lbName -ResourceType $lbResourceType -ResourceGroupName $resourceGroupName -Force 112 | Remove-AzResource -ResourceName $oldPublicIpName -ResourceType $ipResourceType -ResourceGroupName $resourceGroupName -Force 113 | 114 | # Remove node states for the deleted scale set 115 | $nodeType = "nt1vm" 116 | $nodes = Get-ServiceFabricNode 117 | 118 | Write-Host "Removing node state..." 119 | foreach($node in $nodes) 120 | { 121 | if ($node.NodeType -eq $nodeType) 122 | { 123 | $node.NodeName 124 | 125 | Remove-ServiceFabricNodeState -NodeName $node.NodeName -Force 126 | } 127 | } 128 | 129 | # Update the template to reflect your changes and redeploy 130 | $templateFilePath = "C:\Step2-CleanupOriginalNonPrimaryNodeType" 131 | 132 | New-AzResourceGroupDeployment ` 133 | -ResourceGroupName $resourceGroupName ` 134 | -TemplateFile $templateFilePath ` 135 | -TemplateParameterFile $parameterFilePath ` 136 | -CertificateThumbprint $thumb ` 137 | -CertificateUrlValue $certUrlValue ` 138 | -SourceVaultValue $sourceVaultValue ` 139 | -Verbose 140 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | -------------------------------------------------------------------------------- /scripts/BackupRetentionScript/README.md: -------------------------------------------------------------------------------- 1 | 2 | # About the scripts: 3 | Service Fabric Backup Restore Service (https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-backuprestoreservice-quickstart-azurecluster), 4 | currently in preview, allows you to take periodic backups of your Reliable stateful service and Reliable Actors. Depending on the frequency of your backup interval, backups can really grow fast. 5 | While we work on providing retention support integrated with the service, this script would help you manage your storage till that time. It allows you to delete backups older than a specified time. 6 | 7 | ## Usage 8 | This script support both the storage types supported by Backup Restore service: 9 | 1) Azure blob store 10 | 2) File Share 11 | 12 | ## How to use with Azure Storage: 13 | 14 | You can run the script by providing single azure storage connection string as parameter or you can also provide azure account name and key separately. 15 | Examples: 16 | 1) The below example will delete all the backups in the storage(specifed with connection string) of the service with serviceid *WebReferenceApplication~RestockRequestManager*. 17 | ```powershell 18 | .\RetentionScript.ps1 -DateTimeBefore "2018-06-18 23.44.03Z" -ConnectionString "your-connection-string" -ClusterEndPoint "clustername.centralus.cloupapp.azure.com:19080" -ClientCertificateThumbprint "Client#Certificate#Thumbpring" -ServiceId "WebReferenceApplication~RestockRequestManager" 19 | ``` 20 | 2) In this example, passing storage account name and key separately. 21 | ```powershell 22 | .\RetentionScript.ps1 -DateTimeBefore "2018-06-18 23.44.03Z" -StorageAccountName "storageaccountname" -StorageAccountName "storgeAccountName" -ClusterEndPoint "clustername.centralus.cloupapp.azure.com:19080" -ClientCertificateThumbprint "Client#Certificate#Thumbpring" -ServiceId "WebReferenceApplication~RestockRequestManager" 23 | ``` 24 | 3) You can also filter the container for cleanup. This example will delete backup data for all the partitions available on the container named brstorage: 25 | ```powershell 26 | .\RetentionScript.ps1 -ContainerName "brstorage"-DateTimeBefore "2018-06-18 23.44.03Z" -StorageAccountName "storageaccountname" -StorageAccountName "storgeAccountName" -ClusterEndPoint "clustername.centralus.cloupapp.azure.com:19080" -ClientCertificateThumbprint "Client#Certificate#Thumbpring" 27 | ``` 28 | 3) Similarly you can also filter the application by providing the ApplicationId. If Application name is *fabric:/WebReferenceApplication* then, 29 | application id is *WebReferenceApplication*: 30 | ```powershell 31 | .\RetentionScript.ps1 -ContainerName "brstorage"-DateTimeBefore "2018-06-18 23.44.03Z" -StorageAccountName "storageaccountname" -StorageAccountName "storgeAccountName" -ClusterEndPoint "clustername.centralus.cloupapp.azure.com:19080" -ClientCertificateThumbprint "Client#Certificate#Thumbpring" -ApplicationId "WebReferenceApplication" 32 | ``` 33 | 4) Filtering for parition with partitionId *18cf9495-7233-42a0-929d-5ca9c110b861* 34 | ```powershell 35 | .\RetentionScript.ps1 -ContainerName "brstorage"-DateTimeBefore "2018-06-18 23.44.03Z" -StorageAccountName "storageaccountname" -StorageAccountName "storgeAccountName" -ClusterEndPoint "clustername.centralus.cloupapp.azure.com:19080" -ClientCertificateThumbprint "Client#Certificate#Thumbpring" -PartitionId "18cf9495-7233-42a0-929d-5ca9c110b861" 36 | ``` 37 | 38 | ## How to use with File Storage: 39 | 40 | If the storage is protected with userName(in the format Domain\user) and password, then, you need to provide password as securestring to the input variable *Password* 41 | Examples: 42 | The below example will delete backups of the paritition with partition id "18cf9495-7233-42a0-929d-5ca9c110b861" before "2018-06-18 23.44.03Z". 43 | ```powershell 44 | $pass = "Passoword" | ConvertTo-SecureString -AsPlainText -Force 45 | .\RetentionScript.ps1 -DateTimeBefore "2018-06-18 23.44.03Z" -FileShareUserName "Domain\brsuser" -ClusterEndPoint "clustername.centralus.cloupapp.azure.com:19080" -ClientCertificateThumbprint "Client#Certificate#Thumbpring" -Password $pass -FileSharePath "\\fileshare\sharedfolder" -PartitionId "18cf9495-7233-42a0-929d-5ca9c110b861" 46 | ``` 47 | 48 | The below example will delete backups of the application with application id *WebReferenceApplication* before "2018-06-18 23.44.03Z". 49 | ```powershell 50 | .\RetentionScript.ps1 -DateTimeBefore "2018-06-18 23.44.03Z" -FileShareUserName "Domain\brsuser" -ClusterEndPoint "clustername.centralus.cloupapp.azure.com:19080" -ClientCertificateThumbprint "Client#Certificate#Thumbpring" -Password $pass -FileSharePath "\\fileshare\sharedfolder" -ApplicationId "WebReferenceApplication" 51 | ``` 52 | 53 | The below example will delete backups of the service with service id *WebReferenceApplication~RestockRequestManager* before "2018-06-18 23.44.03Z". 54 | ```powershell 55 | .\RetentionScript.ps1 -DateTimeBefore "2018-06-18 23.44.03Z" -FileShareUserName "Domain\brsuser" -ClusterEndPoint "clustername.centralus.cloupapp.azure.com:19080" -ClientCertificateThumbprint "Client#Certificate#Thumbpring" -Password $pass -FileSharePath "\\fileshare\sharedfolder" -ServiceId "WebReferenceApplication~RestockRequestManager" 56 | ``` 57 | 58 | ## Notes: 59 | 60 | 1) DateTimeBefore should be provided in the format(*yyyy-MM-dd HH.mm.ssZ*) 61 | 2) ClientCertificateThumbprint is required if you are cleaning up storage of a secured cluster. 62 | 3) If the management end point of the cluster is this *https://cluster.centralus.cloudapp.azure.com:19080/*, then, the clusterendpoint will be *cluster.centralus.cloudapp.azure.com:19080* 63 | 4) The above script will delete the data for only those partitions on the storage which are found active on the cluster end point provided. 64 | If you need to delete data for the partitions which are not active on the cluster, then add -DeleteNotFoundPartitions flag while running the retention script. 65 | 66 | ## How to schedule the script? 67 | 68 | For azure storage, it is recommended to use azure function time trigger to schedule the script. For more information, please visit https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer 69 | For file share, you can use windows task scheduler. 70 | 71 | ## More details 72 | For more information about the parameters , please read description of RetentionScript.ps1 file by opening it in any text editor. 73 | -------------------------------------------------------------------------------- /templates/nodetype-upgrade/README.md: -------------------------------------------------------------------------------- 1 | # Scale up a Service Fabric cluster primary node type 2 | 3 | These before/after templates represent the steps of upgrading the primary node type VM size and operating system of an example cluster. 4 | 5 | The initial state of the example test cluster consists of one node type of Silver durability, backed by a single scale set with five nodes. The upgraded state of the cluster adds an additional, upgraded scale set (with VM size from Standard_D2_V2 to Standard D4_V2, and OS from Windows Server 2019 to 2022 Datacenter). Follow these commands to walkthrough the complete upgrade scenario. For a more detailed discussion of the procedure, see [Scale up a Service Fabric cluster primary node type](https://docs.microsoft.com/azure/service-fabric/service-fabric-scale-up-primary-node-type). 6 | 7 | ```powershell 8 | # Sign in to your Azure account 9 | Login-AzAccount -SubscriptionId "" 10 | 11 | # Assign deployment variables 12 | $resourceGroupName = "sftestupgradegroup" 13 | $certOutputFolder = "c:\certificates" 14 | $certPassword = "Password!1" | ConvertTo-SecureString -AsPlainText -Force 15 | $certSubjectName = "sftestupgrade.southcentralus.cloudapp.azure.com" 16 | $templateFilePath = "C:\Initial-TestClusterSetup.json" 17 | $parameterFilePath = "C:\parameters.json" 18 | 19 | # Deploy the initial test cluster 20 | New-AzServiceFabricCluster ` 21 | -ResourceGroupName $resourceGroupName ` 22 | -CertificateOutputFolder $certOutputFolder ` 23 | -CertificatePassword $certPassword ` 24 | -CertificateSubjectName $certSubjectName ` 25 | -TemplateFile $templateFilePath ` 26 | -ParameterFile $parameterFilePath 27 | 28 | # Import the local .pfx file to your certificate store 29 | cd c:\certificates 30 | $certPfx = ".\sftestupgradegroup20200312121003.pfx" 31 | 32 | Import-PfxCertificate ` 33 | -FilePath $certPfx ` 34 | -CertStoreLocation Cert:\CurrentUser\My ` 35 | -Password (ConvertTo-SecureString Password!1 -AsPlainText -Force) 36 | 37 | # Connect to the cluster and check health 38 | $clusterName = "sftestupgrade.southcentralus.cloudapp.azure.com:19000" 39 | $thumb = "BB796AA33BD9767E7DA27FE5182CF8FDEE714A70" 40 | 41 | Connect-ServiceFabricCluster ` 42 | -ConnectionEndpoint $clusterName ` 43 | -KeepAliveIntervalInSec 10 ` 44 | -X509Credential ` 45 | -ServerCertThumbprint $thumb ` 46 | -FindType FindByThumbprint ` 47 | -FindValue $thumb ` 48 | -StoreLocation CurrentUser ` 49 | -StoreName My 50 | 51 | Get-ServiceFabricClusterHealth 52 | 53 | # Find your certificate Key Vault references (in Azure portal) 54 | $certUrlValue = "https://sftestupgradegroup.vault.azure.net/secrets/sftestupgradegroup20200309235308/dac0e7b7f9d4414984ccaa72bfb2ea39" 55 | $thumb = "BB796AA33BD9767E7DA27FE5182CF8FDEE714A70" 56 | $sourceVaultValue = "/subscriptions/########-####-####-####-############/resourceGroups/sftestupgradegroup/providers/Microsoft.KeyVault/vaults/sftestupgradegroup" 57 | 58 | # Deploy the updated template with new scale set (upgraded to use managed disks) 59 | $templateFilePath = "C:\Step1-AddPrimaryNodeType.json" 60 | 61 | New-AzResourceGroupDeployment ` 62 | -ResourceGroupName $resourceGroupName ` 63 | -TemplateFile $templateFilePath ` 64 | -TemplateParameterFile $parameterFilePath ` 65 | -CertificateThumbprint $thumb ` 66 | -CertificateUrlValue $certUrlValue ` 67 | -SourceVaultValue $sourceVaultValue ` 68 | -Verbose 69 | 70 | # Ensure cluster is healthy, then disable nodes in the original scale set 71 | Get-ServiceFabricClusterHealth 72 | 73 | # Disable the nodes in the original scale set. 74 | $nodeType = "nt0vm" 75 | $nodes = Get-ServiceFabricNode 76 | 77 | Write-Host "Disabling nodes..." 78 | foreach($node in $nodes) 79 | { 80 | if ($node.NodeType -eq $nodeType) 81 | { 82 | $node.NodeName 83 | 84 | Disable-ServiceFabricNode -Intent RemoveNode -NodeName $node.NodeName -Force 85 | } 86 | } 87 | 88 | # Stop data on the disabled nodes. 89 | foreach($node in $nodes) 90 | { 91 | if ($node.NodeType -eq $nodeType) 92 | { 93 | $node.NodeName 94 | 95 | Start-ServiceFabricNodeTransition -Stop -OperationId (New-Guid) -NodeInstanceId $node.NodeInstanceId -NodeName $node.NodeName -StopDurationInSeconds 10000 96 | } 97 | } 98 | 99 | # Remove the original scale set 100 | $scaleSetName = "nt0vm" 101 | $scaleSetResourceType = "Microsoft.Compute/virtualMachineScaleSets" 102 | 103 | Remove-AzResource -ResourceName $scaleSetName -ResourceType $scaleSetResourceType -ResourceGroupName $resourceGroupName -Force 104 | 105 | # Delete the original IP and load balancer resources 106 | $lbName = "LB-sftestupgrade-nt0vm" 107 | $lbResourceType = "Microsoft.Network/loadBalancers" 108 | $ipResourceType = "Microsoft.Network/publicIPAddresses" 109 | $oldPublicIpName = "PublicIP-LB-FE-nt0vm" 110 | $newPublicIpName = "PublicIP-LB-FE-nt1vm" 111 | 112 | $oldPrimaryPublicIP = Get-AzPublicIpAddress -Name $oldPublicIpName -ResourceGroupName $resourceGroupName 113 | $primaryDNSName = $oldPrimaryPublicIP.DnsSettings.DomainNameLabel 114 | $primaryDNSFqdn = $oldPrimaryPublicIP.DnsSettings.Fqdn 115 | 116 | Remove-AzResource -ResourceName $lbName -ResourceType $lbResourceType -ResourceGroupName $resourceGroupName -Force 117 | Remove-AzResource -ResourceName $oldPublicIpName -ResourceType $ipResourceType -ResourceGroupName $resourceGroupName -Force 118 | 119 | $PublicIP = Get-AzPublicIpAddress -Name $newPublicIpName -ResourceGroupName $resourceGroupName 120 | $PublicIP.DnsSettings.DomainNameLabel = $primaryDNSName 121 | $PublicIP.DnsSettings.Fqdn = $primaryDNSFqdn 122 | Set-AzPublicIpAddress -PublicIpAddress $PublicIP 123 | 124 | # Remove node states for the deleted scale set 125 | $nodeType = "nt0vm" 126 | $nodes = Get-ServiceFabricNode 127 | 128 | Write-Host "Removing node state..." 129 | foreach($node in $nodes) 130 | { 131 | if ($node.NodeType -eq $nodeType) 132 | { 133 | $node.NodeName 134 | 135 | Remove-ServiceFabricNodeState -NodeName $node.NodeName -Force 136 | } 137 | } 138 | 139 | # Update the template to reflect your changes and redeploy 140 | $templateFilePath = "C:\Step3-CleanupOriginalPrimaryNodeType" 141 | 142 | New-AzResourceGroupDeployment ` 143 | -ResourceGroupName $resourceGroupName ` 144 | -TemplateFile $templateFilePath ` 145 | -TemplateParameterFile $parameterFilePath ` 146 | -CertificateThumbprint $thumb ` 147 | -CertificateUrlValue $certUrlValue ` 148 | -SourceVaultValue $sourceVaultValue ` 149 | -Verbose 150 | 151 | -------------------------------------------------------------------------------- /scripts/BackupRetentionScript/RetentionScript.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This powersehll script helps delete older backups from Azure storage or file share which were taken using the Service Fabric Backup Restore service. 4 | 5 | .PARAMETER FileShareUserName 6 | FileShareUserName associated with file share. 7 | 8 | .PARAMETER FileSharePath 9 | The file share path of the storage configured for backup. 10 | 11 | .PARAMETER StorageType 12 | It could be one of the two storages supported: 13 | 1. AzureBlob 14 | 2. FileShare 15 | 16 | .PARAMETER DateTimeBefore(Required) 17 | It is the date time value for deleting the backups before that time. It should be provided in the format(yyyy-MM-dd HH.mm.ssZ) 18 | Example: 19 | $DateTimeBefore = [DateTime]::Now.ToString("yyyy-MM-dd HH.mm.ssZ") 20 | 21 | .PARAMETER ConnectionString 22 | Connection string to the azure storage configured for backup. 23 | 24 | .PARAMETER Password 25 | File share password for the user name $FileShareUserName.It must be specified in Secure String 26 | Example: 27 | $Password ="Password" | ConvertTo-SecureString -AsPlainText -Force 28 | 29 | .PARAMETER ContainerName(Optional) 30 | Container name of storage in which backups are stored. 31 | 32 | .PARAMETER StorageAccountName 33 | Azure storage account name 34 | 35 | .PARAMETER StorageAccountKey 36 | Azure storage account key 37 | 38 | .PARAMETER ClusterEndPoint(Required) 39 | It is the management end point of the cluster. 40 | example: 41 | ManagementEndpoint : https://clustername.centralus.cloudapp.azure.com:19080 42 | $ClusterEndPoint : clustername.centralus.cloudapp.azure.com:19080 43 | 44 | .PARAMETER DeleteNotFoundPartitions(Optional) 45 | If there are partitions on the storage which are not found on the cluster, and you want to delete complete data in the partition 46 | then, enable the flag and run the script. 47 | 48 | .PARAMETER PartitionId(Optional) 49 | Filter to delete data for a particular partition on the cluster 50 | 51 | .PARAMETER ApplicationId 52 | Filter to delete data for a particular Application on the cluster 53 | Example: 54 | if ApplicationName(without fabric:) is "application/Name" then, 55 | $ApplicationId = "application~Name"(Replace "/" with "~") 56 | 57 | .PARAMETER ServiceId 58 | Filter to delete data for a particular service on the cluster 59 | Example: 60 | if ServiceName(without fabric:) is "Service/Name" then, 61 | $ServiceId = "Service~Name"(Replace "/" with "~") 62 | 63 | .PARAMETER ClientCertificateThumbprint(Required in case of secured cluster) 64 | Thumbprint of the client certificate 65 | #> 66 | 67 | [CmdletBinding(PositionalBinding = $false)] 68 | param ( 69 | [Parameter(Mandatory=$false)] 70 | [String] $FileShareUserName, 71 | 72 | [Parameter(Mandatory=$false)] 73 | [String] $FileSharePath, 74 | 75 | [Parameter(Mandatory=$true)] 76 | [String] $StorageType, 77 | 78 | [Parameter(Mandatory=$true)] 79 | [String] $DateTimeBefore, 80 | 81 | [Parameter(Mandatory=$false)] 82 | [String] $ConnectionString, 83 | 84 | [Parameter(Mandatory=$false)] 85 | [SecureString] $Password, 86 | 87 | [Parameter(Mandatory=$false)] 88 | [String] $ContainerName, 89 | 90 | [Parameter(Mandatory=$false)] 91 | [string] $StorageAccountName, 92 | 93 | [Parameter(Mandatory=$false)] 94 | [String] $StorageAccountKey, 95 | 96 | [Parameter(Mandatory=$true)] 97 | [String] $ClusterEndPoint, 98 | 99 | [Parameter(Mandatory=$false)] 100 | [Switch] $DeleteNotFoundPartitions, 101 | 102 | [Parameter(Mandatory=$false)] 103 | [String] $PartitionId, 104 | 105 | [Parameter(Mandatory=$false)] 106 | [String] $ServiceId, 107 | 108 | [Parameter(Mandatory=$false)] 109 | [String] $ApplicationId, 110 | 111 | [Parameter(Mandatory=$false)] 112 | [String] $ClientCertificateThumbprint 113 | ) 114 | 115 | $command = "" 116 | if($StorageType -eq "FileShare") 117 | { 118 | if(!$FileSharePath) 119 | { 120 | $FileSharePath = Read-Host -Prompt "Please enter the FileShare path" 121 | } 122 | 123 | if($FileShareUserName) 124 | { 125 | $command = $command + ".\RetentionScriptFileShare.ps1 -UserName `"$FileShareUserName`" -FileSharePath `"$FileSharePath`" -DateTimeBefore `"$DateTimeBefore`" -ClusterEndPoint `"$ClusterEndPoint`"" 126 | if(!$Password) 127 | { 128 | $Password = Read-Host -Prompt "Please enter password for the userName: $FileShareUserName" -AsSecureString 129 | } 130 | $Global:Pass = $Password 131 | } 132 | else { 133 | $command = $command + ".\RetentionScriptFileShare.ps1 -FileSharePath `"$FileSharePath`" -DateTimeBefore `"$DateTimeBefore`" -ClusterEndPoint `"$ClusterEndPoint`"" 134 | } 135 | } 136 | elseif($StorageType -eq "AzureBlob") 137 | { 138 | if($ConnectionString) 139 | { 140 | if($ContainerName) 141 | { 142 | $command = $command + ".\RetentionScriptAzureBlobStore.ps1 -ConnectionString `"$ConnectionString`" -DateTimeBefore `"$DateTimeBefore`" -ClusterEndPoint `"$ClusterEndPoint`"" 143 | } 144 | else { 145 | $command = $command + ".\RetentionScriptAzureBlobStore.ps1 -ConnectionString `"$ConnectionString`" -DateTimeBefore `"$DateTimeBefore`" -ClusterEndPoint `"$ClusterEndPoint`"" 146 | } 147 | } 148 | else { 149 | if(!$StorageAccountName) 150 | { 151 | $StorageAccountName = Read-Host -Prompt "Please enter the Storage account name" 152 | } 153 | if(!$StorageAccountKey) 154 | { 155 | $StorageAccountKey = Read-Host -Prompt "Please enter the Storage account key" 156 | } 157 | $command = $command + ".\RetentionScriptAzureBlobStore.ps1 -StorageAccountName `"$StorageAccountName`" -StorageAccountKey `"$StorageAccountKey`" -DateTimeBefore `"$DateTimeBefore`" -ContainerName `"$ContainerName`" -ClusterEndPoint `"$ClusterEndPoint`"" 158 | } 159 | 160 | if($ContainerName) 161 | { 162 | $command = $command + " -ContainerName `"$ContainerName`"" 163 | } 164 | } 165 | else { 166 | throw "The storage of type $StorageType not supported" 167 | } 168 | 169 | if($ApplicationId) 170 | { 171 | $command = $command + " -ApplicationId `"$ApplicationId`"" 172 | } 173 | if($ServiceId) 174 | { 175 | $command = $command + " -ServiceId `"$ServiceId`"" 176 | } 177 | 178 | if($ClientCertificateThumbprint) 179 | { 180 | $command = $command + " -ClientCertificateThumbprint `"$ClientCertificateThumbprint`"" 181 | } 182 | 183 | if($PartitionId) 184 | { 185 | $command = $command + " -PartitionId `"$PartitionId`"" 186 | } 187 | 188 | if($DeleteNotFoundPartitions) 189 | { 190 | $command = $command + " -DeleteNotFoundPartitions" 191 | } 192 | 193 | $scriptBlock = [ScriptBlock]::Create($command) 194 | Invoke-Command $scriptBlock -------------------------------------------------------------------------------- /scripts/BackupRetentionScript/modules/RetentionScript.psm1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This powersehll module helps delete older backups from Azure storage or file share which were taken using the Service Fabric Backup Restore service. 4 | 5 | .PARAMETER FileShareUserName 6 | FileShareUserName associated with file share. 7 | 8 | .PARAMETER FileSharePath 9 | The file share path of the storage configured for backup. 10 | 11 | .PARAMETER StorageType 12 | It could be one of the two storages supported: 13 | 1. AzureBlob 14 | 2. FileShare 15 | 16 | .PARAMETER DateTimeBefore(Required) 17 | It is the date time value for deleting the backups before that time. It should be provided in the format(yyyy-MM-dd HH.mm.ssZ) 18 | Example: 19 | $DateTimeBefore = [DateTime]::Now.ToString("yyyy-MM-dd HH.mm.ssZ") 20 | 21 | .PARAMETER ConnectionString 22 | Connection string to the azure storage configured for backup. 23 | 24 | .PARAMETER Password 25 | File share password for the user name $FileShareUserName.It must be specified in Secured String 26 | Example: 27 | $pass ="Password" | ConvertTo-SecureString -AsPlainText -Force 28 | 29 | .PARAMETER ContainerName(Optional) 30 | Container name of storage in which backups are stored. 31 | 32 | .PARAMETER StorageAccountName 33 | Azure storage account name 34 | 35 | .PARAMETER StorageAccountKey 36 | Azure storage account key 37 | 38 | .PARAMETER ClusterEndPoint(Required) 39 | It is the management end point of the cluster. 40 | example: 41 | ManagementEndpoint : https://clustername.centralus.cloudapp.azure.com:19080 42 | $ClusterEndPoint : clustername.centralus.cloudapp.azure.com:19080 43 | 44 | .PARAMETER DeleteNotFoundPartitions(Optional) 45 | If there are partitions on the storage which are not found on the cluster, and you want to delete complete data in the partition 46 | then, enable the flag and run the script. 47 | 48 | .PARAMETER PartitionId(Optional) 49 | Filter to delete data for a particular partition on the cluster 50 | 51 | .PARAMETER ApplicationId 52 | Filter to delete data for a particular Application on the cluster 53 | Example: 54 | if ApplicationName(without fabric:) is "application/Name" then, 55 | $ApplicationId = "application~Name"(Replace "/" with "~") 56 | 57 | .PARAMETER ServiceId 58 | Filter to delete data for a particular service on the cluster 59 | Example: 60 | if ServiceName(without fabric:) is "Service/Name" then, 61 | $ServiceId = "Service~Name"(Replace "/" with "~") 62 | 63 | .PARAMETER ClientCertificateThumbprint(Required in case of secured cluster) 64 | Thumbprint of the client certificate 65 | #> 66 | 67 | Function Start-RetentionScript 68 | { 69 | [CmdletBinding(PositionalBinding = $false)] 70 | param ( 71 | [Parameter(Mandatory=$false)] 72 | [String] $FileShareUserName, 73 | 74 | [Parameter(Mandatory=$false)] 75 | [String] $FileSharePath, 76 | 77 | [Parameter(Mandatory=$true)] 78 | [String] $StorageType, 79 | 80 | [Parameter(Mandatory=$true)] 81 | [String] $DateTimeBefore, 82 | 83 | [Parameter(Mandatory=$false)] 84 | [String] $ConnectionString, 85 | 86 | [Parameter(Mandatory=$false)] 87 | [SecureString] $Password, 88 | 89 | [Parameter(Mandatory=$false)] 90 | [String] $ContainerName, 91 | 92 | [Parameter(Mandatory=$false)] 93 | [string] $StorageAccountName, 94 | 95 | [Parameter(Mandatory=$false)] 96 | [String] $StorageAccountKey, 97 | 98 | [Parameter(Mandatory=$true)] 99 | [String] $ClusterEndPoint, 100 | 101 | [Parameter(Mandatory=$false)] 102 | [Switch] $DeleteNotFoundPartitions, 103 | 104 | [Parameter(Mandatory=$false)] 105 | [String] $PartitionId, 106 | 107 | [Parameter(Mandatory=$false)] 108 | [String] $ServiceId, 109 | 110 | [Parameter(Mandatory=$false)] 111 | [String] $ApplicationId, 112 | 113 | [Parameter(Mandatory=$false)] 114 | [String] $ClientCertificateThumbprint 115 | ) 116 | 117 | $command = "" 118 | if($StorageType -eq "FileShare") 119 | { 120 | if(!$FileSharePath) 121 | { 122 | $FileSharePath = Read-Host -Prompt "Please enter the FileSharePath" 123 | } 124 | 125 | if($FileShareUserName) 126 | { 127 | $command = $command + "Start-RetentionScriptFileShare -UserName `"$FileShareUserName`" -FileSharePath `"$FileSharePath`" -DateTimeBefore `"$DateTimeBefore`" -ClusterEndPoint `"$ClusterEndPoint`"" 128 | if(!$Password) 129 | { 130 | $Password = Read-Host -Prompt "Please enter password for the userName: $FileShareUserName" -AsSecureString 131 | } 132 | $Global:Pass = $Password 133 | 134 | } 135 | else { 136 | $command = $command + "Start-RetentionScriptFileShare -FileSharePath `"$FileSharePath`" -DateTimeBefore `"$DateTimeBefore`" -ClusterEndPoint `"$ClusterEndPoint`"" 137 | } 138 | } 139 | elseif($StorageType -eq "AzureBlob") 140 | { 141 | if($ConnectionString) 142 | { 143 | if($ContainerName) 144 | { 145 | $command = $command + "Start-RetentionScriptAzureShare -ConnectionString `"$ConnectionString`" -DateTimeBefore `"$DateTimeBefore`" -ClusterEndPoint `"$ClusterEndPoint`"" 146 | } 147 | else { 148 | $command = $command + "Start-RetentionScriptAzureShare -ConnectionString `"$ConnectionString`" -DateTimeBefore `"$DateTimeBefore`" -ClusterEndPoint `"$ClusterEndPoint`"" 149 | } 150 | } 151 | else { 152 | if(!$StorageAccountName) 153 | { 154 | $StorageAccountName = Read-Host -Prompt "Please enter the Storage account name" 155 | } 156 | if(!$StorageAccountKey) 157 | { 158 | $StorageAccountKey = Read-Host -Prompt "Please enter the Storage account key" 159 | } 160 | $command = $command + "Start-RetentionScriptAzureShare -StorageAccountName `"$StorageAccountName`" -StorageAccountKey `"$StorageAccountKey`" -DateTimeBefore `"$DateTimeBefore`" -ContainerName `"$ContainerName`" -ClusterEndPoint `"$ClusterEndPoint`"" 161 | } 162 | 163 | if($ContainerName) 164 | { 165 | $command = $command + " -ContainerName `"$ContainerName`"" 166 | } 167 | } 168 | else { 169 | throw "The storage of type $StorageType not supported" 170 | } 171 | 172 | if($ApplicationId) 173 | { 174 | $command = $command + " -ApplicationId `"$ApplicationId`"" 175 | } 176 | if($ServiceId) 177 | { 178 | $command = $command + " -ServiceId `"$ServiceId`"" 179 | } 180 | 181 | if($ClientCertificateThumbprint) 182 | { 183 | $command = $command + " -ClientCertificateThumbprint `"$ClientCertificateThumbprint`"" 184 | } 185 | 186 | if($PartitionId) 187 | { 188 | $command = $command + " -PartitionId `"$PartitionId`"" 189 | } 190 | 191 | if($DeleteNotFoundPartitions) 192 | { 193 | $command = $command + " -DeleteNotFoundPartitions" 194 | } 195 | 196 | $scriptBlock = [ScriptBlock]::Create($command) 197 | Invoke-Command $scriptBlock 198 | } -------------------------------------------------------------------------------- /scripts/BackupRetentionScript/RetentionScriptAzureBlobStore.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(PositionalBinding = $false)] 2 | param ( 3 | [Parameter(Mandatory=$false)] 4 | [String] $ConnectionString, 5 | 6 | [Parameter(Mandatory=$false)] 7 | [String] $ContainerName, 8 | 9 | [Parameter(Mandatory=$false)] 10 | [string] $StorageAccountName, 11 | 12 | [Parameter(Mandatory=$false)] 13 | [String] $StorageAccountKey, 14 | 15 | [Parameter(Mandatory=$true)] 16 | [String] $DateTimeBefore, 17 | 18 | [Parameter(Mandatory=$true)] 19 | [String] $ClusterEndpoint, 20 | 21 | [Parameter(Mandatory=$false)] 22 | [switch] $DeleteNotFoundPartitions, 23 | 24 | [Parameter(Mandatory=$false)] 25 | [String] $PartitionId, 26 | 27 | [Parameter(Mandatory=$false)] 28 | [String] $ServiceId, 29 | 30 | [Parameter(Mandatory=$false)] 31 | [String] $ApplicationId, 32 | 33 | [Parameter(Mandatory=$false)] 34 | [String] $ClientCertificateThumbprint 35 | ) 36 | . .\UtilScript.ps1 37 | 38 | $partitionIdListToWatch = New-Object System.Collections.ArrayList 39 | 40 | if($ApplicationId) 41 | { 42 | if($ClientCertificateThumbprint) 43 | { 44 | $partitionIdListToWatch = Get-PartitionIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 45 | } 46 | else { 47 | $partitionIdListToWatch = Get-PartitionIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint 48 | } 49 | } 50 | elseif($ServiceId) 51 | { 52 | if($ClientCertificateThumbprint) 53 | { 54 | $partitionIdListToWatch = Get-PartitionIdList -ServiceId $ServiceId -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 55 | } 56 | else { 57 | $partitionIdListToWatch = Get-PartitionIdList -ServiceId $ServiceId -ClusterEndpoint $ClusterEndpoint 58 | } 59 | } 60 | elseif($PartitionId) 61 | { 62 | $partitionIdListToWatch.Add($PartitionId) 63 | } 64 | 65 | $contextForStorageAccount = $null 66 | 67 | if($ConnectionString) 68 | { 69 | $contextForStorageAccount = New-AzureStorageContext -ConnectionString $ConnectionString 70 | } 71 | else 72 | { 73 | $contextForStorageAccount = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey 74 | } 75 | 76 | $containerNameList = New-Object System.Collections.ArrayList 77 | 78 | if(!$ContainerName) 79 | { 80 | $containers = Get-AzureStorageContainer -Context $contextForStorageAccount 81 | foreach($container in $containers) 82 | { 83 | $containerNameList.Add($container.Name) | Out-Null 84 | } 85 | } 86 | Else { 87 | $containerNameList.Add($ContainerName) | Out-Null 88 | } 89 | 90 | foreach($containerName in $containerNameList) 91 | { 92 | $token = $null 93 | $pathsList = New-Object System.Collections.ArrayList 94 | do 95 | { 96 | $blobs = Get-AzureStorageBlob -Container $ContainerName -ContinuationToken $token -Context $contextForStorageAccount 97 | 98 | foreach($blob in $blobs) 99 | { 100 | $pathsList.Add($blob.Name) | Out-Null 101 | } 102 | if($blobs.Count -le 0) { Break;} 103 | $token = $blobs[$blobs.Count -1].ContinuationToken; 104 | } 105 | While ($token -ne $Null) 106 | $partitionDict = New-Object 'system.collections.generic.dictionary[[string],[system.collections.generic.list[string]]]' 107 | $finalDateTimeObject = $dateTimeBeforeObject 108 | $partitionDict = Get-PartitionDict -pathsList $pathsList 109 | $partitionCountDict = New-Object 'system.collections.generic.dictionary[[String],[Int32]]' 110 | 111 | foreach($partitionid in $partitionDict.Keys) 112 | { 113 | $partitionCountDict[$partitionid] = $partitionDict[$partitionid].Count 114 | if($partitionIdListToWatch.Count -ne 0 -and !$partitionIdListToWatch.Contains($partitionid)) 115 | { 116 | continue 117 | } 118 | if($ClientCertificateThumbprint) 119 | { 120 | $finalDateTimeObject = Get-FinalDateTimeBefore -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -DeleteNotFoundPartitions $DeleteNotFoundPartitions -ClientCertificateThumbprint $ClientCertificateThumbprint 121 | } 122 | else { 123 | $finalDateTimeObject = Get-FinalDateTimeBefore -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -DeleteNotFoundPartitions $DeleteNotFoundPartitions 124 | } 125 | if($finalDateTimeObject -eq [DateTime]::MinValue) 126 | { 127 | continue 128 | } 129 | $deleteCount = 0 130 | foreach($blobPath in $partitionDict[$partitionid]) 131 | { 132 | $fileNameWithExtension = Split-Path $blobPath -Leaf 133 | $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($fileNameWithExtension) 134 | $extension = [IO.Path]::GetExtension($fileNameWithExtension) 135 | if($extension -eq ".zip" -or $extension -eq ".bkmetadata" ) 136 | { 137 | $dateTimeObject = [DateTime]::ParseExact($fileNameWithoutExtension + "Z","yyyy-MM-dd HH.mm.ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None) 138 | if($dateTimeObject.ToUniversalTime() -lt $finalDateTimeObject.ToUniversalTime()) 139 | { 140 | Write-Host "Deleting the file: $blobPath" 141 | Remove-AzureStorageBlob -Blob $blobPath -Container $containerName -Context $contextForStorageAccount 142 | $partitionCountDict[$partitionid] = $partitionCountDict[$partitionid] -1 143 | $deleteCount = $deleteCount + 1 144 | if($partitionCountDict[$partitionid] -eq 0) 145 | { 146 | Write-Warning -Message "The backup count in this $partitionid is zero. It could happen if the partition is not found on the $ClusterEndpoint" 147 | } 148 | } 149 | } 150 | } 151 | $numberOfBackupsLeft = $partitionCountDict[$partitionid] 152 | Write-Host "Cleanup for the partitionID: $partitionid is complete " 153 | Write-Host "The number of backup left in the partition after cleanup: $numberOfBackupsLeft" 154 | Write-Host "The number of backup files deleted : $deleteCount (.bkmetadata + .zip files)" 155 | } 156 | } 157 | 158 | 159 | $newPathsList = New-Object System.Collections.ArrayList 160 | $newToken = $null 161 | do 162 | { 163 | $blobs = Get-AzureStorageBlob -Container $ContainerName -ContinuationToken $newToken -Context $contextForStorageAccount 164 | 165 | foreach($blob in $blobs) 166 | { 167 | $newPathsList.Add($blob.Name) | Out-Null 168 | } 169 | if($blobs.Count -le 0) { Break;} 170 | $newToken = $blobs[$blobs.Count -1].ContinuationToken; 171 | } 172 | While ($newToken -ne $Null) 173 | 174 | $newPartitionDict = Get-PartitionDict -pathsList $newPathsList 175 | 176 | foreach($partitionid in $newPartitionDict.Keys) 177 | { 178 | if($partitionCountDict.ContainsKey) 179 | { 180 | if($partitionCountDict[$partitionid] -gt $newPartitionDict[$partitionid].Count) 181 | { 182 | throw "The partition with partitionId : $partitionid has less number of backups than expected." 183 | } 184 | } 185 | Start-BackupDataCorruptionTest -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 186 | } 187 | 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /scripts/BackupRetentionScript/modules/RetentionScriptAzureBlobStore.psm1: -------------------------------------------------------------------------------- 1 | Function Start-RetentionScriptAzureShare 2 | { 3 | [CmdletBinding(PositionalBinding = $false)] 4 | param ( 5 | [Parameter(Mandatory=$false)] 6 | [String] $ConnectionString, 7 | 8 | [Parameter(Mandatory=$false)] 9 | [String] $ContainerName, 10 | 11 | [Parameter(Mandatory=$false)] 12 | [string] $StorageAccountName, 13 | 14 | [Parameter(Mandatory=$false)] 15 | [String] $StorageAccountKey, 16 | 17 | [Parameter(Mandatory=$true)] 18 | [String] $DateTimeBefore, 19 | 20 | [Parameter(Mandatory=$true)] 21 | [String] $ClusterEndpoint, 22 | 23 | [Parameter(Mandatory=$false)] 24 | [switch] $DeleteNotFoundPartitions, 25 | 26 | [Parameter(Mandatory=$false)] 27 | [String] $PartitionId, 28 | 29 | [Parameter(Mandatory=$false)] 30 | [String] $ServiceId, 31 | 32 | [Parameter(Mandatory=$false)] 33 | [String] $ApplicationId, 34 | 35 | [Parameter(Mandatory=$false)] 36 | [String] $ClientCertificateThumbprint 37 | ) 38 | 39 | $partitionIdListToWatch = New-Object System.Collections.ArrayList 40 | 41 | if($ApplicationId) 42 | { 43 | if($ClientCertificateThumbprint) 44 | { 45 | $partitionIdListToWatch = Get-PartitionIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 46 | } 47 | else { 48 | $partitionIdListToWatch = Get-PartitionIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint 49 | } 50 | } 51 | elseif($ServiceId) 52 | { 53 | if($ClientCertificateThumbprint) 54 | { 55 | $partitionIdListToWatch = Get-PartitionIdList -ServiceId $ServiceId -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 56 | } 57 | else { 58 | $partitionIdListToWatch = Get-PartitionIdList -ServiceId $ServiceId -ClusterEndpoint $ClusterEndpoint 59 | } 60 | } 61 | elseif($PartitionId) 62 | { 63 | $partitionIdListToWatch.Add($PartitionId) 64 | } 65 | 66 | $contextForStorageAccount = $null 67 | 68 | if($ConnectionString) 69 | { 70 | $contextForStorageAccount = New-AzureStorageContext -ConnectionString $ConnectionString 71 | } 72 | else 73 | { 74 | $contextForStorageAccount = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey 75 | } 76 | 77 | $containerNameList = New-Object System.Collections.ArrayList 78 | 79 | if(!$ContainerName) 80 | { 81 | $containers = Get-AzureStorageContainer -Context $contextForStorageAccount 82 | foreach($container in $containers) 83 | { 84 | $containerNameList.Add($container.Name) | Out-Null 85 | } 86 | } 87 | Else { 88 | $containerNameList.Add($ContainerName) | Out-Null 89 | } 90 | 91 | foreach($containerName in $containerNameList) 92 | { 93 | $token = $null 94 | $pathsList = New-Object System.Collections.ArrayList 95 | do 96 | { 97 | $blobs = Get-AzureStorageBlob -Container $ContainerName -ContinuationToken $token -Context $contextForStorageAccount 98 | 99 | foreach($blob in $blobs) 100 | { 101 | $pathsList.Add($blob.Name) | Out-Null 102 | } 103 | if($blobs.Count -le 0) { Break;} 104 | $token = $blobs[$blobs.Count -1].ContinuationToken; 105 | } 106 | While ($token -ne $Null) 107 | $partitionDict = New-Object 'system.collections.generic.dictionary[[string],[system.collections.generic.list[string]]]' 108 | $finalDateTimeObject = $dateTimeBeforeObject 109 | $partitionDict = Get-PartitionDict -pathsList $pathsList 110 | $partitionCountDict = New-Object 'system.collections.generic.dictionary[[String],[Int32]]' 111 | 112 | foreach($partitionid in $partitionDict.Keys) 113 | { 114 | $partitionCountDict[$partitionid] = $partitionDict[$partitionid].Count 115 | if($partitionIdListToWatch.Count -ne 0 -and !$partitionIdListToWatch.Contains($partitionid)) 116 | { 117 | continue 118 | } 119 | if($ClientCertificateThumbprint) 120 | { 121 | $finalDateTimeObject = Get-FinalDateTimeBefore -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -DeleteNotFoundPartitions $DeleteNotFoundPartitions -ClientCertificateThumbprint $ClientCertificateThumbprint 122 | } 123 | else { 124 | $finalDateTimeObject = Get-FinalDateTimeBefore -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -DeleteNotFoundPartitions $DeleteNotFoundPartitions 125 | } 126 | if($finalDateTimeObject -eq [DateTime]::MinValue) 127 | { 128 | continue 129 | } 130 | $deleteCount = 0 131 | foreach($blobPath in $partitionDict[$partitionid]) 132 | { 133 | $fileNameWithExtension = Split-Path $blobPath -Leaf 134 | $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($fileNameWithExtension) 135 | $extension = [IO.Path]::GetExtension($fileNameWithExtension) 136 | if($extension -eq ".zip" -or $extension -eq ".bkmetadata" ) 137 | { 138 | $dateTimeObject = [DateTime]::ParseExact($fileNameWithoutExtension + "Z","yyyy-MM-dd HH.mm.ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None) 139 | if($dateTimeObject.ToUniversalTime() -lt $finalDateTimeObject.ToUniversalTime()) 140 | { 141 | Write-Host "Deleting the file: $blobPath" 142 | Remove-AzureStorageBlob -Blob $blobPath -Container $containerName -Context $contextForStorageAccount 143 | $partitionCountDict[$partitionid] = $partitionCountDict[$partitionid] -1 144 | $deleteCount = $deleteCount + 1 145 | if($partitionCountDict[$partitionid] -eq 0) 146 | { 147 | Write-Warning -Message "The backup count in this $partitionid is zero. It could happen if the partition is not found on the $ClusterEndpoint" 148 | } 149 | } 150 | } 151 | } 152 | $numberOfBackupsLeft = $partitionCountDict[$partitionid] 153 | Write-Host "Cleanup for the partitionID: $partitionid is complete " 154 | Write-Host "The number of backup left in the partition after cleanup: $numberOfBackupsLeft" 155 | Write-Host "The number of backup files deleted : $deleteCount (.bkmetadata + .zip files)" 156 | } 157 | } 158 | 159 | 160 | $newPathsList = New-Object System.Collections.ArrayList 161 | $newToken = $null 162 | do 163 | { 164 | $blobs = Get-AzureStorageBlob -Container $ContainerName -ContinuationToken $newToken -Context $contextForStorageAccount 165 | 166 | foreach($blob in $blobs) 167 | { 168 | $newPathsList.Add($blob.Name) | Out-Null 169 | } 170 | if($blobs.Count -le 0) { Break;} 171 | $newToken = $blobs[$blobs.Count -1].ContinuationToken; 172 | } 173 | While ($newToken -ne $Null) 174 | 175 | $newPartitionDict = Get-PartitionDict -pathsList $newPathsList 176 | 177 | foreach($partitionid in $newPartitionDict.Keys) 178 | { 179 | if($partitionCountDict.ContainsKey) 180 | { 181 | if($partitionCountDict[$partitionid] -gt $newPartitionDict[$partitionid].Count) 182 | { 183 | throw "The partition with partitionId : $partitionid has less number of backups than expected." 184 | } 185 | } 186 | Start-BackupDataCorruptionTest -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 187 | } 188 | 189 | 190 | 191 | 192 | } -------------------------------------------------------------------------------- /scripts/SetupServiceFabric/SetupServiceFabric.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # This script installs and sets up the Service Fabric Runtime and Common SDK. 5 | # It also sets up Azure Service Fabric CLI 6 | 7 | # Usage: sudo ./SetupServiceFabric.sh 8 | # Above fetches Service Fabric Runtime and SDK along with required packages/dependencies from repositories and does the setup. 9 | # This script also supports installation of SDK from local .deb packages of Servie Fabric runtime and sdk. Both packages will be needed for installation and paths should be provided as parameter, make sure files are present at given paths. 10 | # Below is the sample: 11 | # sudo ./SetupServiceFabric.sh --servicefabricruntime=/mnt/c/Users/sindoria/Downloads/servicefabric_8.2.142.2.deb --servicefabricsdk=/mnt/c/Users/sindoria/Downloads/servicefabric_sdkcommon_1.4.2.deb 12 | # 13 | 14 | if [ "$EUID" -ne 0 ]; then 15 | echo Please run this script as root or using sudo 16 | exit 17 | fi 18 | 19 | ExitIfError() 20 | { 21 | if [ $1 != 0 ]; then 22 | echo "$2" 1>&2 23 | exit -1 24 | fi 25 | } 26 | 27 | Distribution=`lsb_release -cs` 28 | if [[ "xenial" != "$Distribution" && "bionic" != "$Distribution" ]]; then 29 | echo "Service Fabric is not supported on $Distribution" 30 | exit -1 31 | fi 32 | 33 | # Check ServiceFabricRuntimePath and ServiceFabricSdkPath have been provided. If yes, extract that 34 | ServiceFabricRuntimePath="" 35 | ServiceFabricSdkPath="" 36 | for i in "$@" 37 | do 38 | case $i in 39 | -sfrt=*|--servicefabricruntime=*) 40 | ServiceFabricRuntimePath="${i#*=}" 41 | ;; 42 | -sfs=*|--servicefabricsdk=*) 43 | ServiceFabricSdkPath="${i#*=}" 44 | ;; 45 | *) 46 | echo Error: Unknown option passed in: $i 47 | exit 1 48 | ;; 49 | esac 50 | done 51 | 52 | # Check if systemd is running as PID1, if not it should be enabled via systemd-genie 53 | pidone=$(ps --no-headers -o comm 1) 54 | if [[ "systemd" != "$pidone" ]]; then 55 | # Set systemd-genie to run systemd as PID 1 56 | echo "Setting up systemd-genie to run systemd as PID 1" 57 | echo "Installing .NET SDK and runtime 5.0" 58 | wget https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb 59 | dpkg -i packages-microsoft-prod.deb 60 | rm packages-microsoft-prod.deb 61 | 62 | echo "Installing the .NET SDK" 63 | apt-get update; \ 64 | apt-get install -y apt-transport-https && \ 65 | apt-get update && \ 66 | apt-get install -y dotnet-sdk-5.0 67 | 68 | echo "Installing the .NET runtime " 69 | apt-get update; \ 70 | apt-get install -y apt-transport-https && \ 71 | apt-get update && \ 72 | apt-get install -y aspnetcore-runtime-5.0 73 | 74 | echo "Adding the wsl-translinux repository" 75 | apt install apt-transport-https 76 | 77 | wget -O /etc/apt/trusted.gpg.d/wsl-transdebian.gpg https://arkane-systems.github.io/wsl-transdebian/apt/wsl-transdebian.gpg 78 | chmod a+r /etc/apt/trusted.gpg.d/wsl-transdebian.gpg 79 | 80 | file="/etc/apt/sources.list.d/wsl-transdebian.list" 81 | echo "deb https://arkane-systems.github.io/wsl-transdebian/apt/ $(lsb_release -cs) main" >> $file 82 | echo "deb-src https://arkane-systems.github.io/wsl-transdebian/apt/ $(lsb_release -cs) main" >> $file 83 | cat $file 84 | 85 | apt update 86 | echo "Installing systemd-genie" 87 | apt install -y systemd-genie 88 | 89 | # Start genie 90 | echo "Starting genie" 91 | genie -i 92 | echo "Genie has been started" 93 | fi 94 | 95 | # 96 | # If setup is being done inside WLS2 Distribution, then below helps in doing installation inside genie namespace if needed 97 | # 98 | genieCommand='' 99 | isGenieInstalled=$(apt list --installed | grep systemd-genie) 100 | 101 | if [[ ! -z "$isGenieInstalled" ]]; then 102 | isGenieRunning=$(genie -r) 103 | isOutsideGenie=$(genie -b) 104 | 105 | if [[ "$isGenieRunning"=="runnning" ]]; then 106 | # If outside genie then genie prefix command should be used. 107 | if [[ "$isOutsideGenie"=="outside" ]]; then 108 | genieCommand="genie -c" 109 | fi 110 | # if genie is used for cluster management, current user should get permission to control service without sudo password. 111 | # This enables cluster management from windows host via Powershell or LocalClusterManager. 112 | # find user running the script 113 | usr=$SUDO_USER 114 | # if this script is being run by root dont do anything 115 | if [ -z "$usr" ] || [ "root" = "$usr" ]; then 116 | echo "This script should be run by default user with sudo, otherwise add in /etc/sudoers manually. This enables linux cluster management from windwos host via powershell or LocalClusterManager." 117 | else 118 | # Copy /etc/sudoers to /tmp/sudoers.new 119 | cp /etc/sudoers /tmp/sudoers.new 120 | # Remove entery if exists and then make an entry for current user 121 | userentry="$usr ALL = (ALL) NOPASSWD:ALL" 122 | sed -i "/${userentry}/d" /tmp/sudoers.new 123 | sed -i "$ a ${userentry}" /tmp/sudoers.new 124 | # check validity of entry using visudo, if validation is successful, replace /etc/sudoers 125 | visudo -c -f /tmp/sudoers.new 126 | if [ "$?" -eq "0" ]; then 127 | cp /tmp/sudoers.new /etc/sudoers 128 | fi 129 | rm /tmp/sudoers.new 130 | fi 131 | fi 132 | fi 133 | 134 | # 135 | # Install all packages 136 | # 137 | MSPackage="https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" 138 | wget -q $MSPackage 139 | dpkg -i packages-microsoft-prod.deb 140 | ExitIfError $? "Error@$LINENO: Failed to add package $MSPackage" 141 | 142 | curl -fsSL https://packages.microsoft.com/keys/msopentech.asc | apt-key add - 143 | ExitIfError $? "Error@$LINENO: Failed to add MS GPG key" 144 | 145 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - 146 | ExitIfError $? "Error@$LINENO: Failed to add Docker GPG key" 147 | 148 | add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" 149 | ExitIfError $? "Error@$LINENO: Failed to setup docker repository" 150 | 151 | apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0xB1998361219BD9C9 152 | apt-add-repository "deb http://repos.azul.com/azure-only/zulu/apt stable main" 153 | ExitIfError $? "Error@$LINENO: Failed to add key for zulu repo" 154 | 155 | apt-get update 156 | 157 | # 158 | # Install Service Fabric SDK. 159 | # 160 | echo "servicefabric servicefabric/accepted-eula-ga select true" | debconf-set-selections 161 | echo "servicefabricsdkcommon servicefabricsdkcommon/accepted-eula-ga select true" | debconf-set-selections 162 | 163 | # 164 | # If local debian packages for ServiceFabricRunTime and ServiceFabricSDK are provided, install SF SDK from these packages 165 | # 166 | if [[ ! -z $ServiceFabricRuntimePath ]] && [[ ! -z $ServiceFabricSdkPath ]]; then 167 | echo "Copying $ServiceFabricRuntimePath to /var/cache/apt/archives/servicefabric.deb" 168 | cp $ServiceFabricRuntimePath /var/cache/apt/archives/servicefabric.deb 169 | echo "Copying $ServiceFabricSdkPath to /var/cache/apt/archives/servicefabricsdkcommon.deb" 170 | cp $ServiceFabricSdkPath /var/cache/apt/archives/servicefabricsdkcommon.deb 171 | 172 | echo "Installing servicefabric and servicefabricsdkcommon from local .deb packages" 173 | $genieCommand dpkg -i /var/cache/apt/archives/servicefabric.deb 174 | # Fix broken dependencies for servicefabric if any. 175 | $genieCommand apt-get install -f -y 176 | $genieCommand dpkg -i /var/cache/apt/archives/servicefabricsdkcommon.deb 177 | # Fix broken dependencies for servicefabricsdkcommon if any. 178 | $genieCommand apt-get install -f -y 179 | 180 | echo "Removing /var/cache/apt/archives/servicefabric.deb and /var/cache/apt/archives/servicefabricsdkcommon.deb" 181 | rm /var/cache/apt/archives/servicefabric.deb 182 | rm /var/cache/apt/archives/servicefabricsdkcommon.deb 183 | else 184 | $genieCommand apt-get install servicefabricsdkcommon -f -y 185 | ExitIfError $? "Error@$LINENO: Failed to install Service Fabric SDK" 186 | fi 187 | 188 | # 189 | # Setup Azure Service Fabric CLI 190 | # 191 | 192 | $genieCommand apt-get install python3 -f -y 193 | ExitIfError $? "Error@$LINENO: Failed to install python3 for sfctl setup." 194 | 195 | $genieCommand apt-get install python3-pip -f -y 196 | ExitIfError $? "Error@$LINENO: Failed to install pip for sfctl setup." 197 | 198 | $genieCommand pip3 install sfctl 199 | ExitIfError $? "Error@$LINENO: sfctl installation failed." 200 | 201 | export PATH=$PATH:$HOME/.local/bin/ 202 | 203 | echo "Successfully completed Service Fabric SDK installation and setup." -------------------------------------------------------------------------------- /scripts/BackupRetentionScript/RetentionScriptFileShare.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(PositionalBinding = $false)] 2 | param ( 3 | [Parameter(Mandatory=$false)] 4 | [String] $UserName, 5 | 6 | [Parameter(Mandatory=$true)] 7 | [String] $FileSharePath, 8 | 9 | [Parameter(Mandatory=$true)] 10 | [String] $DateTimeBefore, 11 | 12 | [Parameter(Mandatory=$true)] 13 | [String] $ClusterEndpoint, 14 | 15 | [Parameter(Mandatory=$false)] 16 | [switch] $DeleteNotFoundPartitions, 17 | 18 | [Parameter(Mandatory=$false)] 19 | [String] $PartitionId, 20 | 21 | [Parameter(Mandatory=$false)] 22 | [String] $ServiceId, 23 | 24 | [Parameter(Mandatory=$false)] 25 | [String] $ApplicationId, 26 | 27 | [Parameter(Mandatory=$false)] 28 | [String] $ClientCertificateThumbprint 29 | ) 30 | 31 | 32 | Add-Type -Namespace Import -Name Win32 -MemberDefinition @' 33 | [DllImport("advapi32.dll", SetLastError = true)] 34 | public static extern bool LogonUser(string user, string domain, string password, int logonType, int logonProvider, out IntPtr token); 35 | 36 | [DllImport("kernel32.dll", SetLastError = true)] 37 | public static extern bool CloseHandle(IntPtr handle); 38 | '@ 39 | . .\UtilScript.ps1 40 | 41 | Function Get-LogonUserToken 42 | { 43 | param([Parameter(Mandatory=$true)][string]$UsernameToLogon, 44 | [Parameter(Mandatory=$true)][string]$Domain, 45 | [Parameter(Mandatory=$true)][SecureString]$PassToUse, 46 | [Parameter(Mandatory=$false)][string]$LogonType = 'NEW_CREDENTIALS', 47 | [Parameter(Mandatory=$false)][string]$LogonProvider = 'WINNT50' 48 | ) 49 | 50 | $tokenHandle = [IntPtr]::Zero 51 | 52 | 53 | $LogonTypeID = Switch ($LogonType) { 54 | 'BATCH' { 4 } 55 | 'INTERACTIVE' { 2 } 56 | 'NETWORK' { 3 } 57 | 'NETWORK_CLEARTEXT' { 8 } 58 | 'NEW_CREDENTIALS' { 9 } 59 | 'SERVICE' { 5 } 60 | } 61 | 62 | $LogonProviderID = Switch ($LogonProvider) { 63 | 'DEFAULT' { 0 } 64 | 'WINNT40' { 2 } 65 | 'WINNT50' { 3 } 66 | } 67 | $unmanagedString = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PassToUse) 68 | $passunenc = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($unmanagedString) 69 | $returnValue = [Import.Win32]::LogonUser($UsernameToLogon, $Domain, $passunenc, $LogonTypeID, $LogonProviderID, [ref]$tokenHandle) 70 | 71 | #If it fails, throw the verbose with the error code 72 | if (!$returnValue) { 73 | $errCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error(); 74 | Write-Host "Impersonate-User failed a call to LogonUser with error code: $errCode" 75 | throw [System.ComponentModel.Win32Exception]$errCode 76 | 77 | } 78 | 79 | return $tokenHandle 80 | } 81 | 82 | $filePathList = New-Object System.Collections.ArrayList 83 | $Global:ImpersonatedUser = @{} 84 | 85 | $partitionIdListToWatch = New-Object System.Collections.ArrayList 86 | 87 | if($ApplicationId) 88 | { 89 | if($ClientCertificateThumbprint) 90 | { 91 | $partitionIdListToWatch = Get-PartitionIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 92 | } 93 | else { 94 | $partitionIdListToWatch = Get-PartitionIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint 95 | } 96 | } 97 | elseif($ServiceId) 98 | { 99 | if($ClientCertificateThumbprint) 100 | { 101 | $partitionIdListToWatch = Get-PartitionIdList -ServiceId $ServiceId -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 102 | } 103 | else { 104 | $partitionIdListToWatch = Get-PartitionIdList -ServiceId $ServiceId -ClusterEndpoint $ClusterEndpoint 105 | } 106 | } 107 | elseif($PartitionId) 108 | { 109 | $partitionIdListToWatch.Add($PartitionId) 110 | } 111 | 112 | 113 | if($UserName) 114 | { 115 | $userNameDomainList = $username.Split("\",[StringSplitOptions]'RemoveEmptyEntries') 116 | 117 | if($userNameDomainList.Count -eq 2) 118 | { 119 | $userNameToTry = $userNameDomainList[1] 120 | $domain = $userNameDomainList[0] 121 | } 122 | else { 123 | $userNameToTry = $UserName 124 | $domain = "." 125 | } 126 | 127 | $userToken = Get-LogonUserToken -Username $userNameToTry -Domain $domain -PassToUse $Global:Pass 128 | $Global:ImpersonatedUser.ImpersonationContext = [System.Security.Principal.WindowsIdentity]::Impersonate($userToken) 129 | 130 | # Close the handle to the token. Voided to mask the Boolean return value. 131 | [void][Import.Win32]::CloseHandle($userToken) 132 | 133 | } 134 | 135 | 136 | Get-ChildItem -Path $FileSharePath -Include *.bkmetadata -Recurse | ForEach-Object {$filePathList.Add($_.FullName) | Out-Null} 137 | Get-ChildItem -Path $FileSharePath -Include *.zip -Recurse | ForEach-Object {$filePathList.Add($_.FullName) | Out-Null} 138 | 139 | $partitionDict = Get-PartitionDict -pathsList $filePathList 140 | $partitionCountDict = New-Object 'system.collections.generic.dictionary[[String],[Int32]]' 141 | 142 | foreach($partitionid in $partitionDict.Keys) 143 | { 144 | $partitionCountDict[$partitionid] = $partitionDict[$partitionid].Count 145 | if($partitionIdListToWatch.Count -ne 0 -and !$partitionIdListToWatch.Contains($partitionid) ) 146 | { 147 | continue 148 | } 149 | if($ClientCertificateThumbprint) 150 | { 151 | $finalDateTimeObject = Get-FinalDateTimeBefore -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -DeleteNotFoundPartitions $DeleteNotFoundPartitions -ClientCertificateThumbprint $ClientCertificateThumbprint 152 | } 153 | else { 154 | $finalDateTimeObject = Get-FinalDateTimeBefore -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -DeleteNotFoundPartitions $DeleteNotFoundPartitions 155 | } 156 | if($finalDateTimeObject -eq [DateTime]::MinValue) 157 | { 158 | continue 159 | } 160 | $deleteCount = 0 161 | foreach($filePath in $partitionDict[$partitionid]) 162 | { 163 | $fileNameWithExtension = Split-Path $filePath -Leaf 164 | $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($fileNameWithExtension) 165 | $extension = [IO.Path]::GetExtension($fileNameWithExtension) 166 | if($extension -eq ".zip" -or $extension -eq ".bkmetadata" ) 167 | { 168 | $dateTimeObject = [DateTime]::ParseExact($fileNameWithoutExtension + "Z","yyyy-MM-dd HH.mm.ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None) 169 | if($dateTimeObject.ToUniversalTime() -lt $finalDateTimeObject.ToUniversalTime()) 170 | { 171 | Remove-Item -Path $filePath 172 | $deleteCount = $deleteCount + 1 173 | $partitionCountDict[$partitionid] = $partitionCountDict[$partitionid] -1 174 | if($partitionCountDict[$partitionid] -lt 0) 175 | { 176 | Write-Warning -Message "The backup count in this $partitionid is zero. It could happen if the partition is not found on the $ClusterEndpoint" 177 | } 178 | } 179 | } 180 | } 181 | $numberOfBackupsLeft = $partitionCountDict[$partitionid] 182 | Write-Host "Cleanup for the partitionID: $partitionid is complete " 183 | Write-Host "The number of backup left in the partition after cleanup: $numberOfBackupsLeft" 184 | Write-Host "The number of backup files deleted : $deleteCount (.bkmetadata + .zip files)" 185 | } 186 | 187 | 188 | $testFilePathList = New-Object System.Collections.ArrayList 189 | 190 | Get-ChildItem -Path $FileSharePath -Include *.bkmetadata -Recurse | ForEach-Object {$testFilePathList.Add($_.FullName) | Out-Null} 191 | Get-ChildItem -Path $FileSharePath -Include *.zip -Recurse | ForEach-Object {$testFilePathList.Add($_.FullName) | Out-Null} 192 | $newPartitionDict = Get-PartitionDict -pathsList $filePathList 193 | 194 | foreach($partitionid in $newPartitionDict.Keys) 195 | { 196 | if($partitionCountDict.ContainsKey) 197 | { 198 | if($partitionCountDict[$partitionid] -gt $newPartitionDict[$partitionid].Count) 199 | { 200 | throw "The partition with partitionId : $partitionid has less number of backups than expected." 201 | } 202 | } 203 | Start-BackupDataCorruptionTest -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 204 | } 205 | 206 | 207 | 208 | if($UserName) 209 | { 210 | $ImpersonatedUser.ImpersonationContext.Undo() 211 | Remove-Variable ImpersonatedUser -Scope Global 212 | } 213 | -------------------------------------------------------------------------------- /scripts/BackupRetentionScript/modules/RetentionScriptFileShare.psm1: -------------------------------------------------------------------------------- 1 | Function Start-RetentionScriptFileShare 2 | { 3 | [CmdletBinding(PositionalBinding = $false)] 4 | param ( 5 | [Parameter(Mandatory=$false)] 6 | [String] $UserName, 7 | 8 | [Parameter(Mandatory=$true)] 9 | [String] $FileSharePath, 10 | 11 | [Parameter(Mandatory=$true)] 12 | [String] $DateTimeBefore, 13 | 14 | [Parameter(Mandatory=$true)] 15 | [String] $ClusterEndpoint, 16 | 17 | [Parameter(Mandatory=$false)] 18 | [switch] $DeleteNotFoundPartitions, 19 | 20 | [Parameter(Mandatory=$false)] 21 | [String] $PartitionId, 22 | 23 | [Parameter(Mandatory=$false)] 24 | [String] $ServiceId, 25 | 26 | [Parameter(Mandatory=$false)] 27 | [String] $ApplicationId, 28 | 29 | [Parameter(Mandatory=$false)] 30 | [String] $ClientCertificateThumbprint 31 | ) 32 | 33 | 34 | Add-Type -Namespace Import -Name Win32 -MemberDefinition @' 35 | [DllImport("advapi32.dll", SetLastError = true)] 36 | public static extern bool LogonUser(string user, string domain, string password, int logonType, int logonProvider, out IntPtr token); 37 | 38 | [DllImport("kernel32.dll", SetLastError = true)] 39 | public static extern bool CloseHandle(IntPtr handle); 40 | '@ 41 | 42 | Function Get-LogonUserToken 43 | { 44 | param([Parameter(Mandatory=$true)][string]$UsernameToLogon, 45 | [Parameter(Mandatory=$true)][string]$Domain, 46 | [Parameter(Mandatory=$true)][SecureString]$PassToUse, 47 | [Parameter(Mandatory=$false)][string]$LogonType = 'NEW_CREDENTIALS', 48 | [Parameter(Mandatory=$false)][string]$LogonProvider = 'WINNT50' 49 | ) 50 | 51 | $tokenHandle = [IntPtr]::Zero 52 | 53 | 54 | $LogonTypeID = Switch ($LogonType) { 55 | 'BATCH' { 4 } 56 | 'INTERACTIVE' { 2 } 57 | 'NETWORK' { 3 } 58 | 'NETWORK_CLEARTEXT' { 8 } 59 | 'NEW_CREDENTIALS' { 9 } 60 | 'SERVICE' { 5 } 61 | } 62 | 63 | $LogonProviderID = Switch ($LogonProvider) { 64 | 'DEFAULT' { 0 } 65 | 'WINNT40' { 2 } 66 | 'WINNT50' { 3 } 67 | } 68 | $unmanagedString = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PassToUse) 69 | $passunenc = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($unmanagedString) 70 | $returnValue = [Import.Win32]::LogonUser($UsernameToLogon, $Domain, $passunenc, $LogonTypeID, $LogonProviderID, [ref]$tokenHandle) 71 | 72 | #If it fails, throw the verbose with the error code 73 | if (!$returnValue) { 74 | $errCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error(); 75 | Write-Host "Impersonate-User failed a call to LogonUser with error code: $errCode" 76 | throw [System.ComponentModel.Win32Exception]$errCode 77 | 78 | } 79 | 80 | return $tokenHandle 81 | } 82 | 83 | $filePathList = New-Object System.Collections.ArrayList 84 | $Global:ImpersonatedUser = @{} 85 | 86 | $partitionIdListToWatch = New-Object System.Collections.ArrayList 87 | 88 | if($ApplicationId) 89 | { 90 | if($ClientCertificateThumbprint) 91 | { 92 | $partitionIdListToWatch = Get-PartitionIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 93 | } 94 | else { 95 | $partitionIdListToWatch = Get-PartitionIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint 96 | } 97 | } 98 | elseif($ServiceId) 99 | { 100 | if($ClientCertificateThumbprint) 101 | { 102 | $partitionIdListToWatch = Get-PartitionIdList -ServiceId $ServiceId -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 103 | } 104 | else { 105 | $partitionIdListToWatch = Get-PartitionIdList -ServiceId $ServiceId -ClusterEndpoint $ClusterEndpoint 106 | } 107 | } 108 | elseif($PartitionId) 109 | { 110 | $partitionIdListToWatch.Add($PartitionId) 111 | } 112 | 113 | 114 | if($UserName) 115 | { 116 | $userNameDomainList = $username.Split("\",[StringSplitOptions]'RemoveEmptyEntries') 117 | 118 | if($userNameDomainList.Count -eq 2) 119 | { 120 | $userNameToTry = $userNameDomainList[1] 121 | $domain = $userNameDomainList[0] 122 | } 123 | else { 124 | $userNameToTry = $UserName 125 | $domain = "." 126 | } 127 | 128 | $userToken = Get-LogonUserToken -Username $userNameToTry -Domain $domain -PassToUse $Global:Pass 129 | $Global:ImpersonatedUser.ImpersonationContext = [System.Security.Principal.WindowsIdentity]::Impersonate($userToken) 130 | 131 | # Close the handle to the token. Voided to mask the Boolean return value. 132 | [void][Import.Win32]::CloseHandle($userToken) 133 | 134 | } 135 | 136 | 137 | Get-ChildItem -Path $FileSharePath -Include *.bkmetadata -Recurse | ForEach-Object {$filePathList.Add($_.FullName) | Out-Null} 138 | Get-ChildItem -Path $FileSharePath -Include *.zip -Recurse | ForEach-Object {$filePathList.Add($_.FullName) | Out-Null} 139 | 140 | $partitionDict = Get-PartitionDict -pathsList $filePathList 141 | $partitionCountDict = New-Object 'system.collections.generic.dictionary[[String],[Int32]]' 142 | 143 | foreach($partitionid in $partitionDict.Keys) 144 | { 145 | $partitionCountDict[$partitionid] = $partitionDict[$partitionid].Count 146 | if($partitionIdListToWatch.Count -ne 0 -and !$partitionIdListToWatch.Contains($partitionid) ) 147 | { 148 | continue 149 | } 150 | if($ClientCertificateThumbprint) 151 | { 152 | $finalDateTimeObject = Get-FinalDateTimeBefore -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -DeleteNotFoundPartitions $DeleteNotFoundPartitions -ClientCertificateThumbprint $ClientCertificateThumbprint 153 | } 154 | else { 155 | $finalDateTimeObject = Get-FinalDateTimeBefore -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -DeleteNotFoundPartitions $DeleteNotFoundPartitions 156 | } 157 | if($finalDateTimeObject -eq [DateTime]::MinValue) 158 | { 159 | continue 160 | } 161 | $deleteCount = 0 162 | foreach($filePath in $partitionDict[$partitionid]) 163 | { 164 | $fileNameWithExtension = Split-Path $filePath -Leaf 165 | $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($fileNameWithExtension) 166 | $extension = [IO.Path]::GetExtension($fileNameWithExtension) 167 | if($extension -eq ".zip" -or $extension -eq ".bkmetadata" ) 168 | { 169 | $dateTimeObject = [DateTime]::ParseExact($fileNameWithoutExtension + "Z","yyyy-MM-dd HH.mm.ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None) 170 | if($dateTimeObject.ToUniversalTime() -lt $finalDateTimeObject.ToUniversalTime()) 171 | { 172 | Remove-Item -Path $filePath 173 | $deleteCount = $deleteCount + 1 174 | $partitionCountDict[$partitionid] = $partitionCountDict[$partitionid] -1 175 | if($partitionCountDict[$partitionid] -lt 0) 176 | { 177 | Write-Warning -Message "The backup count in this $partitionid is zero. It could happen if the partition is not found on the $ClusterEndpoint" 178 | } 179 | } 180 | } 181 | } 182 | $numberOfBackupsLeft = $partitionCountDict[$partitionid] 183 | Write-Host "Cleanup for the partitionID: $partitionid is complete " 184 | Write-Host "The number of backup left in the partition after cleanup: $numberOfBackupsLeft" 185 | Write-Host "The number of backup files deleted : $deleteCount (.bkmetadata + .zip files)" 186 | } 187 | 188 | 189 | $testFilePathList = New-Object System.Collections.ArrayList 190 | 191 | Get-ChildItem -Path $FileSharePath -Include *.bkmetadata -Recurse | ForEach-Object {$testFilePathList.Add($_.FullName) | Out-Null} 192 | Get-ChildItem -Path $FileSharePath -Include *.zip -Recurse | ForEach-Object {$testFilePathList.Add($_.FullName) | Out-Null} 193 | $newPartitionDict = Get-PartitionDict -pathsList $filePathList 194 | 195 | foreach($partitionid in $newPartitionDict.Keys) 196 | { 197 | if($partitionCountDict.ContainsKey) 198 | { 199 | if($partitionCountDict[$partitionid] -gt $newPartitionDict[$partitionid].Count) 200 | { 201 | throw "The partition with partitionId : $partitionid has less number of backups than expected." 202 | } 203 | } 204 | Start-BackupDataCorruptionTest -DateTimeBefore $DateTimeBefore -Partitionid $partitionid -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 205 | } 206 | 207 | 208 | 209 | if($UserName) 210 | { 211 | $ImpersonatedUser.ImpersonationContext.Undo() 212 | Remove-Variable ImpersonatedUser -Scope Global 213 | } 214 | 215 | } -------------------------------------------------------------------------------- /scripts/BackupRetentionScript/modules/UtilScript.psm1: -------------------------------------------------------------------------------- 1 | Function Get-PartitionDict 2 | { 3 | [CmdletBinding(PositionalBinding = $false)] 4 | param([Parameter(Mandatory=$true)][System.Collections.ArrayList]$pathsList 5 | ) 6 | 7 | $partitionDict = New-Object 'system.collections.generic.dictionary[[string],[system.collections.generic.list[string]]]' 8 | foreach($path in $pathsList) 9 | { 10 | $pathList = $path.Split("\",[StringSplitOptions]'RemoveEmptyEntries') 11 | $length = $pathList.Count 12 | $partitionID = $null 13 | if($length -le 1) 14 | { 15 | $pathList = $path.Split("/",[StringSplitOptions]'RemoveEmptyEntries') 16 | $length = $pathList.Count 17 | if($length -le 1) 18 | { 19 | throw "$path is not in correct format." 20 | } 21 | Else 22 | { 23 | $partitionID = $pathList[$length - 2] 24 | } 25 | } 26 | Else { 27 | $partitionID = $pathList[$length - 2] 28 | } 29 | 30 | 31 | if($partitionID -eq $null) 32 | { 33 | throw "Not able to extract partitionID" 34 | } 35 | 36 | if(!$partitionDict.ContainsKey($partitionID)) 37 | { 38 | $partitionDict.Add($partitionID, $path) 39 | } 40 | else { 41 | $partitionDict[$partitionID].add($path) 42 | } 43 | } 44 | 45 | return $partitionDict 46 | } 47 | 48 | Function Get-FinalDateTimeBefore 49 | { 50 | [CmdletBinding(PositionalBinding = $false)] 51 | param([Parameter(Mandatory=$true)][string]$DateTimeBefore, 52 | [Parameter(Mandatory=$true)][string]$Partitionid, 53 | [Parameter(Mandatory=$true)][string]$ClusterEndpoint, 54 | [Parameter(Mandatory=$false)][bool]$DeleteNotFoundPartitions, 55 | [Parameter(Mandatory=$false)][string]$ClientCertificateThumbprint 56 | ) 57 | 58 | $dateTimeBeforeObject = [DateTime]::ParseExact($DateTimeBefore,"yyyy-MM-dd HH.mm.ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None) 59 | $finalDateTimeObject = $dateTimeBeforeObject 60 | $dateTimeBeforeString = $dateTimeBeforeObject.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") 61 | $url = "http://$ClusterEndpoint/Partitions/$Partitionid/$/GetBackups?api-version=6.4&EndDateTimeFilter=$dateTimeBeforeString" 62 | $backupEnumerations = $null 63 | try { 64 | if($ClientCertificateThumbprint) 65 | { 66 | $url = "https://$ClusterEndpoint/Partitions/$Partitionid/$/GetBackups?api-version=6.4&EndDateTimeFilter=$dateTimeBeforeString" 67 | $pagedBackupEnumeration = Invoke-RestMethod -Uri $url -CertificateThumbprint $ClientCertificateThumbprint 68 | } 69 | else { 70 | $pagedBackupEnumeration = Invoke-RestMethod -Uri $url 71 | } 72 | $backupEnumerations = $pagedBackupEnumeration.Items | Sort-Object -Property @{Expression = {[DateTime]::ParseExact($_.CreationTimeUtc,"yyyy-MM-ddTHH:mm:ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None)}; Ascending = $false} 73 | } 74 | catch { 75 | $err = $_.ToString() | ConvertFrom-Json 76 | if($err.Error.Code -eq "FABRIC_E_PARTITION_NOT_FOUND") 77 | { 78 | Write-Warning "$Partitionid is not found on the cluster : $ClusterEndpoint" 79 | if($DeleteNotFoundPartitions -eq $true) 80 | { 81 | Write-Warning "DeleteNotFoundPartitions flag is enabled so, deleting data all in this partition" 82 | return [DateTime]::MaxValue 83 | } 84 | else { 85 | Write-Warning "If you want to remove data on this partition as well, please run the script by enabling DeleteNotFoundPartitions flag." 86 | return [DateTime]::MinValue 87 | } 88 | } 89 | else { 90 | throw $_.Exception.Message 91 | } 92 | } 93 | 94 | $fullBackupFound = $false 95 | foreach($backupEnumeration in $backupEnumerations) 96 | { 97 | if($backupEnumeration.BackupType -eq "Full") 98 | { 99 | $finalDateTimeObject = [DateTime]::Parse($backupEnumeration.CreationTimeUtc) 100 | $fullBackupFound = $true 101 | break 102 | } 103 | } 104 | if($backupEnumerations.Count -eq 0) 105 | { 106 | Write-Host "There are no backups available in the partition: $Partitionid before the specified date." 107 | return [DateTime]::MinValue 108 | } 109 | 110 | if(!$fullBackupFound) 111 | { 112 | Write-Host "The Backups Before this $dateTimeBeforeString date are corrupt as no full backup is found, So, deleting them." 113 | } 114 | return $finalDateTimeObject 115 | } 116 | 117 | 118 | Function Get-PartitionIdList 119 | { 120 | [CmdletBinding(PositionalBinding = $false)] 121 | param([Parameter(Mandatory=$false)][string]$ApplicationId, 122 | [Parameter(Mandatory=$false)][string]$ServiceId, 123 | [Parameter(Mandatory=$true)][string]$ClusterEndpoint, 124 | [Parameter(Mandatory=$false)][string]$ClientCertificateThumbprint 125 | ) 126 | # need to add continuationToken Logic here. 127 | $serviceIdList = New-Object System.Collections.ArrayList 128 | if($ApplicationId) 129 | { 130 | if($ClientCertificateThumbprint) 131 | { 132 | $serviceIdList = Get-ServiceIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 133 | } 134 | else { 135 | $serviceIdList = Get-ServiceIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint 136 | } 137 | } 138 | else { 139 | $serviceIdList.Add($ServiceId) | Out-Null 140 | } 141 | 142 | $partitionIdList = New-Object System.Collections.ArrayList 143 | 144 | foreach($serviceId in $serviceIdList) 145 | { 146 | $continuationToken = $null 147 | do 148 | { 149 | if($ClientCertificateThumbprint) 150 | { 151 | $partitionInfoList = Invoke-RestMethod -Uri "https://$ClusterEndpoint/Services/$serviceId/$/GetPartitions?api-version=6.4&ContinuationToken=$continuationToken" -CertificateThumbprint $ClientCertificateThumbprint 152 | } 153 | else { 154 | $partitionInfoList = Invoke-RestMethod -Uri "http://$ClusterEndpoint/Services/$serviceId/$/GetPartitions?api-version=6.4&ContinuationToken=$continuationToken" 155 | } 156 | foreach($partitionInfo in $partitionInfoList.Items) 157 | { 158 | $partitionIdList.Add($partitionInfo.PartitionInformation.Id) 159 | } 160 | $continuationToken = $partitionInfoList.ContinuationToken 161 | }while($continuationToken -ne "") 162 | } 163 | $length = $partitionIdList.Count 164 | Write-Host "The total number of partitions found on the cluster $ClusterEndpoint are $length" 165 | return $partitionIdList 166 | } 167 | 168 | 169 | Function Get-ServiceIdList 170 | { 171 | [CmdletBinding(PositionalBinding = $false)] 172 | param([Parameter(Mandatory=$true)][string]$ApplicationId, 173 | [Parameter(Mandatory=$true)][string]$ClusterEndpoint, 174 | [Parameter(Mandatory=$false)][string]$ClientCertificateThumbprint 175 | ) 176 | 177 | $continuationToken = $null 178 | $serviceIdList = New-Object System.Collections.ArrayList 179 | do 180 | { 181 | if($ClientCertificateThumbprint) 182 | { 183 | $serviceInfoList = Invoke-RestMethod -Uri "https://$ClusterEndpoint/Applications/$ApplicationId/$/GetServices?api-version=6.4&ContinuationToken=$continuationToken" -CertificateThumbprint $ClientCertificateThumbprint 184 | } 185 | else { 186 | $serviceInfoList = Invoke-RestMethod -Uri "http://$ClusterEndpoint/Applications/$ApplicationId/$/GetServices?api-version=6.4&ContinuationToken=$continuationToken" 187 | } 188 | foreach($serviceInfo in $serviceInfoList.Items) 189 | { 190 | $serviceIdList.Add($serviceInfo.Id) | Out-Null 191 | } 192 | $continuationToken = $serviceInfoList.ContinuationToken 193 | }while($continuationToken -ne "") 194 | 195 | $length = $serviceIdList.Count 196 | Write-Host "$ApplicationId has $length number of services" 197 | return $serviceIdList 198 | } 199 | 200 | 201 | Function Start-BackupDataCorruptionTest 202 | { 203 | [CmdletBinding(PositionalBinding = $false)] 204 | param([Parameter(Mandatory=$true)][string]$DateTimeBefore, 205 | [Parameter(Mandatory=$true)][string]$Partitionid, 206 | [Parameter(Mandatory=$true)][string]$ClusterEndpoint, 207 | [Parameter(Mandatory=$false)][string]$ClientCertificateThumbprint 208 | ) 209 | $dateTimeBeforeObject = [DateTime]::ParseExact($DateTimeBefore,"yyyy-MM-dd HH.mm.ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None) 210 | $dateTimeBeforeString = $dateTimeBeforeObject.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") 211 | $url = "http://$ClusterEndpoint/Partitions/$Partitionid/$/GetBackups?api-version=6.4&EndDateTimeFilter=$dateTimeBeforeString" 212 | 213 | $backupEnumerations = $null 214 | try { 215 | if($ClientCertificateThumbprint) 216 | { 217 | $url = "https://$ClusterEndpoint/Partitions/$Partitionid/$/GetBackups?api-version=6.4&EndDateTimeFilter=$dateTimeBeforeString" 218 | $pagedBackupEnumeration = Invoke-RestMethod -Uri $url -CertificateThumbprint $ClientCertificateThumbprint 219 | } 220 | else { 221 | $pagedBackupEnumeration = Invoke-RestMethod -Uri $url 222 | } 223 | $backupEnumerations = $pagedBackupEnumeration.Items | Sort-Object -Property @{Expression = {[DateTime]::ParseExact($_.CreationTimeUtc,"yyyy-MM-ddTHH:mm:ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None)}; Ascending = $true} 224 | 225 | if($backupEnumerations -ne $null -and $backupEnumerations[0].BackupType -ne "Full") 226 | { 227 | throw "Data is corrupted for this partition : $Partitionid" 228 | } 229 | } 230 | catch { 231 | $err = $_.ToString() | ConvertFrom-Json 232 | if($err.Error.Code -eq "FABRIC_E_PARTITION_NOT_FOUND") 233 | { 234 | Write-Host "Partition: $Partitionid not found, so, could not go through with testing the integrity of data of this partition." 235 | } 236 | else { 237 | throw $_.Exception.Message 238 | } 239 | } 240 | } -------------------------------------------------------------------------------- /scripts/BackupRetentionScript/UtilScript.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Utility functions for retention script. 4 | #> 5 | 6 | Function Get-PartitionDict 7 | { 8 | [CmdletBinding(PositionalBinding = $false)] 9 | param([Parameter(Mandatory=$true)][System.Collections.ArrayList]$pathsList 10 | ) 11 | 12 | $partitionDict = New-Object 'system.collections.generic.dictionary[[string],[system.collections.generic.list[string]]]' 13 | foreach($path in $pathsList) 14 | { 15 | $pathList = $path.Split("\",[StringSplitOptions]'RemoveEmptyEntries') 16 | $length = $pathList.Count 17 | $partitionID = $null 18 | if($length -le 1) 19 | { 20 | $pathList = $path.Split("/",[StringSplitOptions]'RemoveEmptyEntries') 21 | $length = $pathList.Count 22 | if($length -le 1) 23 | { 24 | throw "$path is not in correct format." 25 | } 26 | Else 27 | { 28 | $partitionID = $pathList[$length - 2] 29 | } 30 | } 31 | Else { 32 | $partitionID = $pathList[$length - 2] 33 | } 34 | 35 | 36 | if($partitionID -eq $null) 37 | { 38 | throw "Not able to extract partitionID" 39 | } 40 | 41 | if(!$partitionDict.ContainsKey($partitionID)) 42 | { 43 | $partitionDict.Add($partitionID, $path) 44 | } 45 | else { 46 | $partitionDict[$partitionID].add($path) 47 | } 48 | } 49 | 50 | return $partitionDict 51 | } 52 | 53 | Function Get-FinalDateTimeBefore 54 | { 55 | [CmdletBinding(PositionalBinding = $false)] 56 | param([Parameter(Mandatory=$true)][string]$DateTimeBefore, 57 | [Parameter(Mandatory=$true)][string]$Partitionid, 58 | [Parameter(Mandatory=$true)][string]$ClusterEndpoint, 59 | [Parameter(Mandatory=$false)][bool]$DeleteNotFoundPartitions, 60 | [Parameter(Mandatory=$false)][string]$ClientCertificateThumbprint 61 | ) 62 | 63 | # DateTime Improvement to be done here. 64 | $dateTimeBeforeObject = [DateTime]::ParseExact($DateTimeBefore,"yyyy-MM-dd HH.mm.ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None) 65 | $finalDateTimeObject = $dateTimeBeforeObject 66 | $dateTimeBeforeString = $dateTimeBeforeObject.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") 67 | $url = "http://$ClusterEndpoint/Partitions/$Partitionid/$/GetBackups?api-version=6.4&EndDateTimeFilter=$dateTimeBeforeString" 68 | $backupEnumerations = $null 69 | try { 70 | if($ClientCertificateThumbprint) 71 | { 72 | $url = "https://$ClusterEndpoint/Partitions/$Partitionid/$/GetBackups?api-version=6.4&EndDateTimeFilter=$dateTimeBeforeString" 73 | $pagedBackupEnumeration = Invoke-RestMethod -Uri $url -CertificateThumbprint $ClientCertificateThumbprint 74 | } 75 | else { 76 | $pagedBackupEnumeration = Invoke-RestMethod -Uri $url 77 | } 78 | $backupEnumerations = $pagedBackupEnumeration.Items | Sort-Object -Property @{Expression = {[DateTime]::ParseExact($_.CreationTimeUtc,"yyyy-MM-ddTHH:mm:ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None)}; Ascending = $false} 79 | } 80 | catch { 81 | $err = $_.ToString() | ConvertFrom-Json 82 | if($err.Error.Code -eq "FABRIC_E_PARTITION_NOT_FOUND") 83 | { 84 | Write-Warning "$Partitionid is not found on the cluster : $ClusterEndpoint" 85 | if($DeleteNotFoundPartitions -eq $true) 86 | { 87 | Write-Warning "DeleteNotFoundPartitions flag is enabled so, deleting data all in this partition" 88 | return [DateTime]::MaxValue 89 | } 90 | else { 91 | Write-Warning "If you want to remove data in this partition as well, please run the script by enabling DeleteNotFoundPartitions flag." 92 | return [DateTime]::MinValue 93 | } 94 | } 95 | else { 96 | throw $_.Exception.Message 97 | } 98 | } 99 | 100 | $fullBackupFound = $false 101 | foreach($backupEnumeration in $backupEnumerations) 102 | { 103 | if($backupEnumeration.BackupType -eq "Full") 104 | { 105 | $finalDateTimeObject = [DateTime]::Parse($backupEnumeration.CreationTimeUtc) 106 | $fullBackupFound = $true 107 | break 108 | } 109 | } 110 | if($backupEnumerations.Count -eq 0) 111 | { 112 | Write-Host "There are no backups available in the partition: $Partitionid before the specified date." 113 | return [DateTime]::MinValue 114 | } 115 | 116 | if(!$fullBackupFound) 117 | { 118 | Write-Host "The Backups Before this $dateTimeBeforeString date are corrupt as no full backup is found, So, deleting them." 119 | } 120 | return $finalDateTimeObject 121 | } 122 | 123 | 124 | Function Get-PartitionIdList 125 | { 126 | [CmdletBinding(PositionalBinding = $false)] 127 | param([Parameter(Mandatory=$false)][string]$ApplicationId, 128 | [Parameter(Mandatory=$false)][string]$ServiceId, 129 | [Parameter(Mandatory=$true)][string]$ClusterEndpoint, 130 | [Parameter(Mandatory=$false)][string]$ClientCertificateThumbprint 131 | ) 132 | 133 | $serviceIdList = New-Object System.Collections.ArrayList 134 | if($ApplicationId) 135 | { 136 | if($ClientCertificateThumbprint) 137 | { 138 | $serviceIdList = Get-ServiceIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint -ClientCertificateThumbprint $ClientCertificateThumbprint 139 | } 140 | else { 141 | $serviceIdList = Get-ServiceIdList -ApplicationId $ApplicationId -ClusterEndpoint $ClusterEndpoint 142 | } 143 | } 144 | else { 145 | $serviceIdList.Add($ServiceId) | Out-Null 146 | } 147 | 148 | $partitionIdList = New-Object System.Collections.ArrayList 149 | 150 | foreach($serviceId in $serviceIdList) 151 | { 152 | $continuationToken = $null 153 | do 154 | { 155 | if($ClientCertificateThumbprint) 156 | { 157 | $partitionInfoList = Invoke-RestMethod -Uri "https://$ClusterEndpoint/Services/$serviceId/$/GetPartitions?api-version=6.4&ContinuationToken=$continuationToken" -CertificateThumbprint $ClientCertificateThumbprint 158 | } 159 | else { 160 | $partitionInfoList = Invoke-RestMethod -Uri "http://$ClusterEndpoint/Services/$serviceId/$/GetPartitions?api-version=6.4&ContinuationToken=$continuationToken" 161 | } 162 | foreach($partitionInfo in $partitionInfoList.Items) 163 | { 164 | $partitionIdList.Add($partitionInfo.PartitionInformation.Id) 165 | } 166 | $continuationToken = $partitionInfoList.ContinuationToken 167 | }while($continuationToken -ne "") 168 | } 169 | $length = $partitionIdList.Count 170 | Write-Host "The total number of partitions found on the cluster are $length" 171 | return $partitionIdList 172 | } 173 | 174 | 175 | Function Get-ServiceIdList 176 | { 177 | [CmdletBinding(PositionalBinding = $false)] 178 | param([Parameter(Mandatory=$true)][string]$ApplicationId, 179 | [Parameter(Mandatory=$true)][string]$ClusterEndpoint, 180 | [Parameter(Mandatory=$false)][string]$ClientCertificateThumbprint 181 | ) 182 | 183 | $continuationToken = $null 184 | $serviceIdList = New-Object System.Collections.ArrayList 185 | do 186 | { 187 | if($ClientCertificateThumbprint) 188 | { 189 | $serviceInfoList = Invoke-RestMethod -Uri "https://$ClusterEndpoint/Applications/$ApplicationId/$/GetServices?api-version=6.4&ContinuationToken=$continuationToken" -CertificateThumbprint $ClientCertificateThumbprint 190 | } 191 | else { 192 | $serviceInfoList = Invoke-RestMethod -Uri "http://$ClusterEndpoint/Applications/$ApplicationId/$/GetServices?api-version=6.4&ContinuationToken=$continuationToken" 193 | } 194 | foreach($serviceInfo in $serviceInfoList.Items) 195 | { 196 | $serviceIdList.Add($serviceInfo.Id) | Out-Null 197 | } 198 | $continuationToken = $serviceInfoList.ContinuationToken 199 | }while($continuationToken -ne "") 200 | 201 | $length = $serviceIdList.Count 202 | Write-Host "$ApplicationId has $length number of services" 203 | return $serviceIdList 204 | } 205 | 206 | 207 | Function Start-BackupDataCorruptionTest 208 | { 209 | [CmdletBinding(PositionalBinding = $false)] 210 | param([Parameter(Mandatory=$true)][string]$DateTimeBefore, 211 | [Parameter(Mandatory=$true)][string]$Partitionid, 212 | [Parameter(Mandatory=$true)][string]$ClusterEndpoint, 213 | [Parameter(Mandatory=$false)][string]$ClientCertificateThumbprint 214 | ) 215 | $dateTimeBeforeObject = [DateTime]::ParseExact($DateTimeBefore,"yyyy-MM-dd HH.mm.ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None) 216 | $dateTimeBeforeString = $dateTimeBeforeObject.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") 217 | # DateTime Improvement to be done here. 218 | $url = "http://$ClusterEndpoint/Partitions/$Partitionid/$/GetBackups?api-version=6.4&EndDateTimeFilter=$dateTimeBeforeString" 219 | 220 | $backupEnumerations = $null 221 | try { 222 | if($ClientCertificateThumbprint) 223 | { 224 | $url = "https://$ClusterEndpoint/Partitions/$Partitionid/$/GetBackups?api-version=6.4&EndDateTimeFilter=$dateTimeBeforeString" 225 | $pagedBackupEnumeration = Invoke-RestMethod -Uri $url -CertificateThumbprint $ClientCertificateThumbprint 226 | } 227 | else { 228 | $pagedBackupEnumeration = Invoke-RestMethod -Uri $url 229 | } 230 | $backupEnumerations = $pagedBackupEnumeration.Items | Sort-Object -Property @{Expression = {[DateTime]::ParseExact($_.CreationTimeUtc,"yyyy-MM-ddTHH:mm:ssZ",[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None)}; Ascending = $true} 231 | 232 | if($backupEnumerations -ne $null -and $backupEnumerations[0].BackupType -ne "Full") 233 | { 234 | throw "Data is corrupted for this partition : $Partitionid" 235 | } 236 | } 237 | catch { 238 | $err = $_.ToString() | ConvertFrom-Json 239 | if($err.Error.Code -eq "FABRIC_E_PARTITION_NOT_FOUND") 240 | { 241 | Write-Host "Partition: $Partitionid not found, so, could not go through with testing the integrity of data of this partition." 242 | } 243 | else { 244 | throw $_.Exception.Message 245 | } 246 | } 247 | } -------------------------------------------------------------------------------- /templates/service-integration/apim.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "apimInstanceName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "The name of your API Management service." 9 | } 10 | }, 11 | "apimPublisherEmail": { 12 | "type": "string", 13 | "minLength": 1, 14 | "metadata": { 15 | "description": "The email address of the owner of the service" 16 | } 17 | }, 18 | "apimSku": { 19 | "type": "string", 20 | "allowedValues": [ 21 | "Developer", 22 | "Premium" 23 | ], 24 | "defaultValue": "Developer", 25 | "metadata": { 26 | "description": "The pricing tier of this API Management service. Only Developer and Premium are supported when deploying into a shared VNET." 27 | } 28 | }, 29 | "serviceFabricCertificateName": { 30 | "defaultValue": "service-fabric-certificate-name", 31 | "type": "string" 32 | }, 33 | "serviceFabricCertificate": { 34 | "type": "securestring", 35 | "metadata": { 36 | "description": "Base-64 encoded PFX certificate to talk to Service Fabric Backend ." 37 | } 38 | }, 39 | "certificatePassword": { 40 | "type": "securestring", 41 | "metadata": { 42 | "description": "Certificate password to use to talk to Service Fabric Backend." 43 | } 44 | }, 45 | "serviceFabricCertificateThumbprint": { 46 | "type": "string", 47 | "metadata": { 48 | "description": "Certificate Thumbprint to use to talk to Service Fabric Backend." 49 | } 50 | }, 51 | "clusterHttpManagementEndpoint": { 52 | "type": "string", 53 | "metadata": { 54 | "description": "cluster HTTP management endpoint." 55 | } 56 | }, 57 | "policies_policy_name": { 58 | "defaultValue": "policy", 59 | "type": "string" 60 | }, 61 | "inbound_policy":{ 62 | "defaultValue": "\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n", 63 | "type": "string" 64 | }, 65 | "apis_service_fabric_app_name": { 66 | "defaultValue": "service-fabric-app", 67 | "type": "string" 68 | }, 69 | "apim_service_fabric_product_name": { 70 | "defaultValue": "service-fabric-api-product", 71 | "type": "String" 72 | }, 73 | "service_fabric_backend_name": { 74 | "defaultValue": "servicefabric", 75 | "type": "string" 76 | }, 77 | "apis_service_fabric_app_name_operation": { 78 | "defaultValue": "service-fabric-app-operation", 79 | "type": "string" 80 | }, 81 | "url_path": { 82 | "defaultValue": "/api/values", 83 | "type": "string" 84 | }, 85 | "vnetName": { 86 | "defaultValue": "sf-apim-vnet", 87 | "type": "string", 88 | "metadata": { 89 | "description": "The name of the VNET that contains the Service Fabric cluster and API Management service deployment." 90 | } 91 | }, 92 | "subnetName": { 93 | "defaultValue": "apim-subnet", 94 | "type": "string", 95 | "metadata": { 96 | "description": "The name subnet to deploy the API Management service to. This subnet cannot have any other resources in it and must be in the same VNET that contains the Service Fabric cluster back-end." 97 | } 98 | }, 99 | "vnetVersion": { 100 | "defaultValue": "2017-03-01", 101 | "type": "string", 102 | "metadata": { 103 | "description": "The version of the VNET resource to which the subnet belongs as defined by the subnetName parameter." 104 | } 105 | }, 106 | "networkSecurityGroupName": { 107 | "defaultValue": "apim-vnet-security", 108 | "type": "string", 109 | "metadata": { 110 | "description": "The name Network Security Group to deploy the API Management service to. This NSG must be applied to the subnet in the 'subnetName' parameter." 111 | } 112 | }, 113 | "networkSecurityGroupVersion": { 114 | "defaultValue": "2017-03-01", 115 | "type": "string", 116 | "metadata": { 117 | "description": "The version of the Network Security Group resource." 118 | } 119 | } 120 | }, 121 | "variables": { 122 | "location": "[string(resourceGroup().location)]", 123 | "apimSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), parameters('subnetName'))]" 124 | }, 125 | "resources": [ 126 | { 127 | "type": "Microsoft.ApiManagement/service", 128 | "sku": { 129 | "name": "[parameters('apimSku')]", 130 | "capacity": 1 131 | }, 132 | "name": "[parameters('apimInstanceName')]", 133 | "apiVersion": "2017-03-01", 134 | "location": "[variables('location')]", 135 | "tags": {}, 136 | "properties": { 137 | "publisherEmail": "[parameters('apimPublisherEmail')]", 138 | "publisherName": "Microsoft", 139 | "virtualNetworkConfiguration": { 140 | "subnetResourceId": "[variables('apimSubnetId')]", 141 | "location": "[variables('location')]" 142 | }, 143 | "customProperties": { 144 | "subnetAddress": "[reference(variables('apimSubnetId'), parameters('vnetVersion')).addressPrefix]" 145 | }, 146 | "virtualNetworkType": "External" 147 | } 148 | }, 149 | { 150 | "apiVersion": "2017-03-01", 151 | "type": "Microsoft.ApiManagement/service/certificates", 152 | "name": "[concat(parameters('apimInstanceName'), '/', parameters('serviceFabricCertificateName'))]", 153 | "dependsOn": [ 154 | "[resourceId('Microsoft.ApiManagement/service', parameters('apimInstanceName'))]" 155 | ], 156 | "properties": { 157 | "data": "[parameters('serviceFabricCertificate')]", 158 | "password": "[parameters('certificatePassword')]" 159 | } 160 | }, 161 | { 162 | "apiVersion": "2017-03-01", 163 | "type": "Microsoft.ApiManagement/service/backends", 164 | "name": "[concat(parameters('apimInstanceName'), '/', parameters('service_fabric_backend_name'))]", 165 | "dependsOn": [ 166 | "[resourceId('Microsoft.ApiManagement/service', parameters('apimInstanceName'))]", 167 | "[resourceId('Microsoft.ApiManagement/service/certificates', parameters('apimInstanceName'), parameters('serviceFabricCertificateName'))]" 168 | ], 169 | "properties": { 170 | "description": "My Service Fabric backend", 171 | "url": "fabric:/fake/service", 172 | "protocol": "http", 173 | "resourceId": "[parameters('clusterHttpManagementEndpoint')]", 174 | "properties": { 175 | "serviceFabricCluster": { 176 | "managementEndpoints": [ 177 | "[parameters('clusterHttpManagementEndpoint')]" 178 | ], 179 | "clientCertificateThumbprint": "[parameters('serviceFabricCertificateThumbprint')]", 180 | "serverCertificateThumbprints": [ 181 | "[parameters('serviceFabricCertificateThumbprint')]" 182 | ], 183 | "maxPartitionResolutionRetries": 5 184 | } 185 | } 186 | } 187 | }, 188 | { 189 | "type": "Microsoft.ApiManagement/service/products", 190 | "name": "[concat(parameters('apimInstanceName'), '/', parameters('apim_service_fabric_product_name'))]", 191 | "apiVersion": "2017-03-01", 192 | "scale": null, 193 | "properties": { 194 | "displayName": "Service Fabric Apis", 195 | "description": "Subscribers have access to Service Fabric Apis.", 196 | "terms": null, 197 | "subscriptionRequired": true, 198 | "approvalRequired": false, 199 | "subscriptionsLimit": 1, 200 | "state": "published" 201 | }, 202 | "dependsOn": [ 203 | "[resourceId('Microsoft.ApiManagement/service', parameters('apimInstanceName'))]" 204 | ] 205 | }, 206 | { 207 | "type": "Microsoft.ApiManagement/service/apis", 208 | "name": "[concat(parameters('apimInstanceName'), '/', parameters('apis_service_fabric_app_name'))]", 209 | "apiVersion": "2017-03-01", 210 | "scale": null, 211 | "properties": { 212 | "displayName": "Service Fabric App", 213 | "apiRevision": "1", 214 | "description": "", 215 | "serviceUrl": "http://servicefabric", 216 | "path": "myapp", 217 | "protocols": [ 218 | "http", 219 | "https" 220 | ], 221 | "authenticationSettings": null, 222 | "subscriptionKeyParameterNames": null, 223 | "isCurrent": true 224 | }, 225 | "dependsOn": [ 226 | "[resourceId('Microsoft.ApiManagement/service', parameters('apimInstanceName'))]" 227 | ] 228 | }, 229 | { 230 | "type": "Microsoft.ApiManagement/service/apis/operations", 231 | "name": "[concat(parameters('apimInstanceName'), '/', parameters('apis_service_fabric_app_name'), '/', parameters('apis_service_fabric_app_name_operation'))]", 232 | "apiVersion": "2017-03-01", 233 | "scale": null, 234 | "properties": { 235 | "displayName": "Values", 236 | "method": "GET", 237 | "urlTemplate": "[parameters('url_path')]", 238 | "description": "", 239 | "policies": null 240 | }, 241 | "dependsOn": [ 242 | "[resourceId('Microsoft.ApiManagement/service', parameters('apimInstanceName'))]", 243 | "[resourceId('Microsoft.ApiManagement/service/apis', parameters('apimInstanceName'), parameters('apis_service_fabric_app_name'))]" 244 | ] 245 | }, 246 | { 247 | "type": "Microsoft.ApiManagement/service/apis/policies", 248 | "name": "[concat(parameters('apimInstanceName'), '/', parameters('apis_service_fabric_app_name'), '/', parameters('policies_policy_name'))]", 249 | "apiVersion": "2017-03-01", 250 | "properties": { 251 | "policyContent": "[parameters('inbound_policy')]" 252 | }, 253 | "dependsOn": [ 254 | "[resourceId('Microsoft.ApiManagement/service', parameters('apimInstanceName'))]", 255 | "[resourceId('Microsoft.ApiManagement/service/apis', parameters('apimInstanceName'), parameters('apis_service_fabric_app_name'))]", 256 | "[resourceId('Microsoft.ApiManagement/service/backends', parameters('apimInstanceName'), parameters('service_fabric_backend_name'))]" 257 | ] 258 | }, 259 | { 260 | "type": "Microsoft.ApiManagement/service/products/apis", 261 | "name": "[concat(parameters('apimInstanceName'), '/', parameters('apim_service_fabric_product_name'), '/', parameters('apis_service_fabric_app_name'))]", 262 | "apiVersion": "2017-03-01", 263 | "scale": null, 264 | "properties": {}, 265 | "dependsOn": [ 266 | "[resourceId('Microsoft.ApiManagement/service', parameters('apimInstanceName'))]", 267 | "[resourceId('Microsoft.ApiManagement/service/apis', parameters('apimInstanceName'), parameters('apis_service_fabric_app_name'))]", 268 | "[resourceId('Microsoft.ApiManagement/service/products', parameters('apimInstanceName'), parameters('apim_service_fabric_product_name'))]" 269 | ] 270 | }, 271 | { 272 | "type": "Microsoft.Network/networkSecurityGroups", 273 | "name": "[parameters('networkSecurityGroupName')]", 274 | "apiVersion": "[parameters('networkSecurityGroupVersion')]", 275 | "location": "[variables('location')]", 276 | "properties": { 277 | "securityRules": [ 278 | { 279 | "name": "Client_communication_to_API_Management", 280 | "properties": { 281 | "protocol": "TCP", 282 | "sourcePortRange": "*", 283 | "destinationPortRange": "80", 284 | "sourceAddressPrefix": "Internet", 285 | "destinationAddressPrefix": "[reference(variables('apimSubnetId'), parameters('vnetVersion')).addressPrefix]", 286 | "access": "Allow", 287 | "priority": 100, 288 | "direction": "Inbound" 289 | } 290 | }, 291 | { 292 | "name": "Secure_Client_communication_to_API_Management", 293 | "properties": { 294 | "protocol": "TCP", 295 | "sourcePortRange": "*", 296 | "destinationPortRange": "443", 297 | "sourceAddressPrefix": "Internet", 298 | "destinationAddressPrefix": "[reference(variables('apimSubnetId'), parameters('vnetVersion')).addressPrefix]", 299 | "access": "Allow", 300 | "priority": 110, 301 | "direction": "Inbound" 302 | } 303 | }, 304 | { 305 | "name": "Management_endpoint_for_Azure_portal_and_Powershell", 306 | "properties": { 307 | "protocol": "TCP", 308 | "sourcePortRange": "*", 309 | "destinationPortRange": "3443", 310 | "sourceAddressPrefix": "Internet", 311 | "destinationAddressPrefix": "VirtualNetwork", 312 | "access": "Allow", 313 | "priority": 120, 314 | "direction": "Inbound" 315 | } 316 | }, 317 | { 318 | "name": "Dependency_on_Redis_Cache", 319 | "properties": { 320 | "protocol": "TCP", 321 | "sourcePortRange": "*", 322 | "destinationPortRange": "6381-6383", 323 | "sourceAddressPrefix": "VirtualNetwork", 324 | "destinationAddressPrefix": "VirtualNetwork", 325 | "access": "Allow", 326 | "priority": 130, 327 | "direction": "Inbound" 328 | } 329 | }, 330 | { 331 | "name": "Dependency_on_Azure_Storage_and_Azure_Service_Bus", 332 | "properties": { 333 | "protocol": "TCP", 334 | "sourcePortRange": "*", 335 | "destinationPortRange": "80", 336 | "sourceAddressPrefix": "VirtualNetwork", 337 | "destinationAddressPrefix": "Internet", 338 | "access": "Allow", 339 | "priority": 100, 340 | "direction": "Outbound" 341 | } 342 | }, 343 | { 344 | "name": "Dependency_on_Azure_SQL", 345 | "properties": { 346 | "protocol": "TCP", 347 | "sourcePortRange": "*", 348 | "destinationPortRange": "1433", 349 | "sourceAddressPrefix": "VirtualNetwork", 350 | "destinationAddressPrefix": "Internet", 351 | "access": "Allow", 352 | "priority": 110, 353 | "direction": "Outbound" 354 | } 355 | }, 356 | { 357 | "name": "Dependency_on_Azure_SQL_V12", 358 | "properties": { 359 | "protocol": "TCP", 360 | "sourcePortRange": "*", 361 | "destinationPortRange": "11000-11999", 362 | "sourceAddressPrefix": "VirtualNetwork", 363 | "destinationAddressPrefix": "Internet", 364 | "access": "Allow", 365 | "priority": 120, 366 | "direction": "Outbound" 367 | } 368 | }, 369 | { 370 | "name": "Dependency_on_Azure_SQL_V12_2", 371 | "properties": { 372 | "protocol": "TCP", 373 | "sourcePortRange": "*", 374 | "destinationPortRange": "14000-14999", 375 | "sourceAddressPrefix": "VirtualNetwork", 376 | "destinationAddressPrefix": "Internet", 377 | "access": "Allow", 378 | "priority": 130, 379 | "direction": "Outbound" 380 | } 381 | }, 382 | { 383 | "name": "Dependency_on_Service_Bus", 384 | "properties": { 385 | "protocol": "TCP", 386 | "sourcePortRange": "*", 387 | "destinationPortRange": "9350-9354", 388 | "sourceAddressPrefix": "VirtualNetwork", 389 | "destinationAddressPrefix": "Internet", 390 | "access": "Allow", 391 | "priority": 140, 392 | "direction": "Outbound" 393 | } 394 | }, 395 | { 396 | "name": "Dependency_for_Log_to_event_Hub_policy", 397 | "properties": { 398 | "protocol": "*", 399 | "sourcePortRange": "*", 400 | "destinationPortRange": "5671", 401 | "sourceAddressPrefix": "VirtualNetwork", 402 | "destinationAddressPrefix": "Internet", 403 | "access": "Allow", 404 | "priority": 150, 405 | "direction": "Outbound" 406 | } 407 | }, 408 | { 409 | "name": "Dependency_on_Redis_Cache_outbound", 410 | "properties": { 411 | "protocol": "TCP", 412 | "sourcePortRange": "*", 413 | "destinationPortRange": "6381-6383", 414 | "sourceAddressPrefix": "VirtualNetwork", 415 | "destinationAddressPrefix": "VirtualNetwork", 416 | "access": "Allow", 417 | "priority": 160, 418 | "direction": "Outbound" 419 | } 420 | }, 421 | { 422 | "name": "Dependency_on_Azure_File_Share_for_GIT", 423 | "properties": { 424 | "protocol": "TCP", 425 | "sourcePortRange": "*", 426 | "destinationPortRange": "445", 427 | "sourceAddressPrefix": "VirtualNetwork", 428 | "destinationAddressPrefix": "Internet", 429 | "access": "Allow", 430 | "priority": 170, 431 | "direction": "Outbound" 432 | } 433 | }, 434 | { 435 | "name": "Azure_Infrastructure_Load_Balancer", 436 | "properties": { 437 | "protocol": "TCP", 438 | "sourcePortRange": "*", 439 | "destinationPortRange": "*", 440 | "sourceAddressPrefix": "AzureLoadBalancer", 441 | "destinationAddressPrefix": "VirtualNetwork", 442 | "access": "Allow", 443 | "priority": 140, 444 | "direction": "Inbound" 445 | } 446 | } 447 | ] 448 | } 449 | } 450 | ] 451 | } 452 | -------------------------------------------------------------------------------- /templates/networking/template_original.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "clusterLocation": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Location of the Cluster" 9 | } 10 | }, 11 | "clusterName": { 12 | "type": "string", 13 | "defaultValue": "Cluster", 14 | "metadata": { 15 | "description": "Name of your cluster - Between 3 and 23 characters. Letters and numbers only" 16 | } 17 | }, 18 | "nt0applicationStartPort": { 19 | "type": "int", 20 | "defaultValue": 20000 21 | }, 22 | "nt0applicationEndPort": { 23 | "type": "int", 24 | "defaultValue": 30000 25 | }, 26 | "nt0ephemeralStartPort": { 27 | "type": "int", 28 | "defaultValue": 49152 29 | }, 30 | "nt0ephemeralEndPort": { 31 | "type": "int", 32 | "defaultValue": 65534 33 | }, 34 | "nt0fabricTcpGatewayPort": { 35 | "type": "int", 36 | "defaultValue": 19000 37 | }, 38 | "nt0fabricHttpGatewayPort": { 39 | "type": "int", 40 | "defaultValue": 19080 41 | }, 42 | "subnet0Name": { 43 | "type": "string", 44 | "defaultValue": "Subnet-0" 45 | }, 46 | "subnet0Prefix": { 47 | "type": "string", 48 | "defaultValue": "10.0.0.0/24" 49 | }, 50 | "computeLocation": { 51 | "type": "string" 52 | }, 53 | "vmStorageAccountName": { 54 | "type": "string" 55 | }, 56 | "publicIPAddressName": { 57 | "type": "string", 58 | "defaultValue": "PublicIP-VM" 59 | }, 60 | "publicIPAddressType": { 61 | "type": "string", 62 | "allowedValues": [ 63 | "Dynamic" 64 | ], 65 | "defaultValue": "Dynamic" 66 | }, 67 | "vmStorageAccountContainerName": { 68 | "type": "string", 69 | "defaultValue": "vhds" 70 | }, 71 | "adminUserName": { 72 | "type": "string", 73 | "defaultValue": "testadm", 74 | "metadata": { 75 | "description": "Remote desktop user Id" 76 | } 77 | }, 78 | "adminPassword": { 79 | "type": "securestring", 80 | "metadata": { 81 | "description": "Remote desktop user password. Must be a strong password" 82 | } 83 | }, 84 | "virtualNetworkName": { 85 | "type": "string", 86 | "defaultValue": "VNet" 87 | }, 88 | "addressPrefix": { 89 | "type": "string", 90 | "defaultValue": "10.0.0.0/16" 91 | }, 92 | "dnsName": { 93 | "type": "string" 94 | }, 95 | "nicName": { 96 | "type": "string", 97 | "defaultValue": "NIC" 98 | }, 99 | "lbName": { 100 | "type": "string", 101 | "defaultValue": "LoadBalancer" 102 | }, 103 | "lbIPName": { 104 | "type": "string", 105 | "defaultValue": "PublicIP-LB-FE" 106 | }, 107 | "overProvision": { 108 | "type": "string", 109 | "defaultValue": "false" 110 | }, 111 | "vmImagePublisher": { 112 | "type": "string", 113 | "defaultValue": "MicrosoftWindowsServer" 114 | }, 115 | "vmImageOffer": { 116 | "type": "string", 117 | "defaultValue": "WindowsServer" 118 | }, 119 | "vmImageSku": { 120 | "type": "string", 121 | "defaultValue": "2012-R2-Datacenter" 122 | }, 123 | "vmImageVersion": { 124 | "type": "string", 125 | "defaultValue": "latest" 126 | }, 127 | "loadBalancedAppPort1": { 128 | "type": "int", 129 | "defaultValue": 80, 130 | "metadata": { 131 | "description": "Input endpoint1 for the application to use. Replace it with what your application uses" 132 | } 133 | }, 134 | "storageAccountType": { 135 | "type": "string", 136 | "allowedValues": [ 137 | "Standard_LRS", 138 | "Standard_GRS" 139 | ], 140 | "defaultValue": "Standard_LRS", 141 | "metadata": { 142 | "description": "Replication option for the VM image storage account" 143 | } 144 | }, 145 | "supportLogStorageAccountType": { 146 | "type": "string", 147 | "allowedValues": [ 148 | "Standard_LRS", 149 | "Standard_GRS" 150 | ], 151 | "defaultValue": "Standard_LRS", 152 | "metadata": { 153 | "description": "Replication option for the support log storage account" 154 | } 155 | }, 156 | "supportLogStorageAccountName": { 157 | "type": "string", 158 | "defaultValue": "[toLower( concat('sflogs', uniqueString(resourceGroup().id),'2'))]", 159 | "metadata": { 160 | "description": "Name for the storage account that contains support logs from the cluster" 161 | } 162 | }, 163 | "applicationDiagnosticsStorageAccountType": { 164 | "type": "string", 165 | "allowedValues": [ 166 | "Standard_LRS", 167 | "Standard_GRS" 168 | ], 169 | "defaultValue": "Standard_LRS", 170 | "metadata": { 171 | "description": "Replication option for the application diagnostics storage account" 172 | } 173 | }, 174 | "applicationDiagnosticsStorageAccountName": { 175 | "type": "string", 176 | "defaultValue": "[toLower(concat(uniqueString(resourceGroup().id), '3' ))]", 177 | "metadata": { 178 | "description": "Name for the storage account that contains application diagnostics data from the cluster" 179 | } 180 | }, 181 | "nt0InstanceCount": { 182 | "type": "int", 183 | "defaultValue": 5, 184 | "metadata": { 185 | "description": "Instance count for node type" 186 | } 187 | }, 188 | "vmNodeType0Name": { 189 | "type": "string", 190 | "defaultValue": "Node1", 191 | "maxLength": 9 192 | }, 193 | "vmNodeType0Size": { 194 | "type": "string", 195 | "defaultValue": "Standard_D1_v2" 196 | } 197 | }, 198 | "variables": { 199 | "vmssApiVersion": "2016-03-30", 200 | "lbApiVersion": "2015-06-15", 201 | "vNetApiVersion": "2015-06-15", 202 | "storageApiVersion": "2016-01-01", 203 | "publicIPApiVersion": "2015-06-15", 204 | "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]", 205 | "subnet0Ref": "[concat(variables('vnetID'),'/subnets/',parameters('subnet0Name'))]", 206 | "lbID0": "[resourceId('Microsoft.Network/loadBalancers', concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name')))]", 207 | "lbIPConfig0": "[concat(variables('lbID0'),'/frontendIPConfigurations/LoadBalancerIPConfig')]", 208 | "lbPoolID0": "[concat(variables('lbID0'),'/backendAddressPools/LoadBalancerBEAddressPool')]", 209 | "lbProbeID0": "[concat(variables('lbID0'),'/probes/FabricGatewayProbe')]", 210 | "lbHttpProbeID0": "[concat(variables('lbID0'),'/probes/FabricHttpGatewayProbe')]", 211 | "lbNatPoolID0": "[concat(variables('lbID0'),'/inboundNatPools/LoadBalancerBEAddressNatPool')]", 212 | "vmStorageAccountName0": "[toLower(concat(uniqueString(resourceGroup().id), '1', '0' ))]", 213 | "uniqueStringArray0": [ 214 | "[concat(variables('vmStorageAccountName0'), '0')]", 215 | "[concat(variables('vmStorageAccountName0'), '1')]", 216 | "[concat(variables('vmStorageAccountName0'), '2')]", 217 | "[concat(variables('vmStorageAccountName0'), '3')]", 218 | "[concat(variables('vmStorageAccountName0'), '4')]" 219 | ] 220 | }, 221 | "resources": [ 222 | { 223 | "apiVersion": "[variables('storageApiVersion')]", 224 | "type": "Microsoft.Storage/storageAccounts", 225 | "name": "[parameters('supportLogStorageAccountName')]", 226 | "location": "[parameters('computeLocation')]", 227 | "dependsOn": [], 228 | "properties": {}, 229 | "kind": "Storage", 230 | "sku": { 231 | "name": "[parameters('supportLogStorageAccountType')]" 232 | }, 233 | "tags": { 234 | "resourceType": "Service Fabric", 235 | "clusterName": "[parameters('clusterName')]" 236 | } 237 | }, 238 | { 239 | "apiVersion": "[variables('storageApiVersion')]", 240 | "type": "Microsoft.Storage/storageAccounts", 241 | "name": "[parameters('applicationDiagnosticsStorageAccountName')]", 242 | "location": "[parameters('computeLocation')]", 243 | "dependsOn": [], 244 | "properties": {}, 245 | "kind": "Storage", 246 | "sku": { 247 | "name": "[parameters('applicationDiagnosticsStorageAccountType')]" 248 | }, 249 | "tags": { 250 | "resourceType": "Service Fabric", 251 | "clusterName": "[parameters('clusterName')]" 252 | } 253 | }, 254 | { 255 | "apiVersion": "[variables('vNetApiVersion')]", 256 | "type": "Microsoft.Network/virtualNetworks", 257 | "name": "[parameters('virtualNetworkName')]", 258 | "location": "[parameters('computeLocation')]", 259 | "properties": { 260 | "addressSpace": { 261 | "addressPrefixes": [ 262 | "[parameters('addressPrefix')]" 263 | ] 264 | }, 265 | "subnets": [ 266 | { 267 | "name": "[parameters('subnet0Name')]", 268 | "properties": { 269 | "addressPrefix": "[parameters('subnet0Prefix')]" 270 | } 271 | } 272 | ] 273 | }, 274 | "tags": { 275 | "resourceType": "Service Fabric", 276 | "clusterName": "[parameters('clusterName')]" 277 | } 278 | }, 279 | { 280 | "apiVersion": "[variables('publicIPApiVersion')]", 281 | "type": "Microsoft.Network/publicIPAddresses", 282 | "name": "[concat(parameters('lbIPName'),'-','0')]", 283 | "location": "[parameters('computeLocation')]", 284 | "properties": { 285 | "dnsSettings": { 286 | "domainNameLabel": "[parameters('dnsName')]" 287 | }, 288 | "publicIPAllocationMethod": "Dynamic" 289 | }, 290 | "tags": { 291 | "resourceType": "Service Fabric", 292 | "clusterName": "[parameters('clusterName')]" 293 | } 294 | }, 295 | { 296 | "apiVersion": "[variables('lbApiVersion')]", 297 | "type": "Microsoft.Network/loadBalancers", 298 | "name": "[concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name'))]", 299 | "location": "[parameters('computeLocation')]", 300 | "dependsOn": [ 301 | "[concat('Microsoft.Network/publicIPAddresses/',concat(parameters('lbIPName'),'-','0'))]" 302 | ], 303 | "properties": { 304 | "frontendIPConfigurations": [ 305 | { 306 | "name": "LoadBalancerIPConfig", 307 | "properties": { 308 | "publicIPAddress": { 309 | "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('lbIPName'),'-','0'))]" 310 | } 311 | } 312 | } 313 | ], 314 | "backendAddressPools": [ 315 | { 316 | "name": "LoadBalancerBEAddressPool", 317 | "properties": {} 318 | } 319 | ], 320 | "loadBalancingRules": [ 321 | { 322 | "name": "LBRule", 323 | "properties": { 324 | "backendAddressPool": { 325 | "id": "[variables('lbPoolID0')]" 326 | }, 327 | "backendPort": "[parameters('nt0fabricTcpGatewayPort')]", 328 | "enableFloatingIP": "false", 329 | "frontendIPConfiguration": { 330 | "id": "[variables('lbIPConfig0')]" 331 | }, 332 | "frontendPort": "[parameters('nt0fabricTcpGatewayPort')]", 333 | "idleTimeoutInMinutes": "5", 334 | "probe": { 335 | "id": "[variables('lbProbeID0')]" 336 | }, 337 | "protocol": "tcp" 338 | } 339 | }, 340 | { 341 | "name": "LBHttpRule", 342 | "properties": { 343 | "backendAddressPool": { 344 | "id": "[variables('lbPoolID0')]" 345 | }, 346 | "backendPort": "[parameters('nt0fabricHttpGatewayPort')]", 347 | "enableFloatingIP": "false", 348 | "frontendIPConfiguration": { 349 | "id": "[variables('lbIPConfig0')]" 350 | }, 351 | "frontendPort": "[parameters('nt0fabricHttpGatewayPort')]", 352 | "idleTimeoutInMinutes": "5", 353 | "probe": { 354 | "id": "[variables('lbHttpProbeID0')]" 355 | }, 356 | "protocol": "tcp" 357 | } 358 | }, 359 | { 360 | "name": "AppPortLBRule1", 361 | "properties": { 362 | "backendAddressPool": { 363 | "id": "[variables('lbPoolID0')]" 364 | }, 365 | "backendPort": "[parameters('loadBalancedAppPort1')]", 366 | "enableFloatingIP": "false", 367 | "frontendIPConfiguration": { 368 | "id": "[variables('lbIPConfig0')]" 369 | }, 370 | "frontendPort": "[parameters('loadBalancedAppPort1')]", 371 | "idleTimeoutInMinutes": "5", 372 | "probe": { 373 | "id": "[concat(variables('lbID0'),'/probes/AppPortProbe1')]" 374 | }, 375 | "protocol": "tcp" 376 | } 377 | } 378 | ], 379 | "probes": [ 380 | { 381 | "name": "FabricGatewayProbe", 382 | "properties": { 383 | "intervalInSeconds": 5, 384 | "numberOfProbes": 2, 385 | "port": "[parameters('nt0fabricTcpGatewayPort')]", 386 | "protocol": "tcp" 387 | } 388 | }, 389 | { 390 | "name": "FabricHttpGatewayProbe", 391 | "properties": { 392 | "intervalInSeconds": 5, 393 | "numberOfProbes": 2, 394 | "port": "[parameters('nt0fabricHttpGatewayPort')]", 395 | "protocol": "tcp" 396 | } 397 | }, 398 | { 399 | "name": "AppPortProbe1", 400 | "properties": { 401 | "intervalInSeconds": 5, 402 | "numberOfProbes": 2, 403 | "port": "[parameters('loadBalancedAppPort1')]", 404 | "protocol": "tcp" 405 | } 406 | } 407 | ], 408 | "inboundNatPools": [ 409 | { 410 | "name": "LoadBalancerBEAddressNatPool", 411 | "properties": { 412 | "backendPort": "3389", 413 | "frontendIPConfiguration": { 414 | "id": "[variables('lbIPConfig0')]" 415 | }, 416 | "frontendPortRangeEnd": "4500", 417 | "frontendPortRangeStart": "3389", 418 | "protocol": "tcp" 419 | } 420 | } 421 | ] 422 | }, 423 | "tags": { 424 | "resourceType": "Service Fabric", 425 | "clusterName": "[parameters('clusterName')]" 426 | } 427 | }, 428 | { 429 | "apiVersion": "[variables('storageApiVersion')]", 430 | "type": "Microsoft.Storage/storageAccounts", 431 | "name": "[variables('uniqueStringArray0')[copyIndex()]]", 432 | "location": "[parameters('computeLocation')]", 433 | "dependsOn": [], 434 | "properties": {}, 435 | "copy": { 436 | "name": "storageLoop", 437 | "count": 5 438 | }, 439 | "kind": "Storage", 440 | "sku": { 441 | "name": "[parameters('storageAccountType')]" 442 | }, 443 | "tags": { 444 | "resourceType": "Service Fabric", 445 | "clusterName": "[parameters('clusterName')]" 446 | } 447 | }, 448 | { 449 | "apiVersion": "[variables('vmssApiVersion')]", 450 | "type": "Microsoft.Compute/virtualMachineScaleSets", 451 | "name": "[parameters('vmNodeType0Name')]", 452 | "location": "[parameters('computeLocation')]", 453 | "dependsOn": [ 454 | "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]", 455 | "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[0])]", 456 | "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[1])]", 457 | "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[2])]", 458 | "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[3])]", 459 | "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[4])]", 460 | "[concat('Microsoft.Network/loadBalancers/', concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name')))]", 461 | "[concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName'))]", 462 | "[concat('Microsoft.Storage/storageAccounts/', parameters('applicationDiagnosticsStorageAccountName'))]" 463 | ], 464 | "properties": { 465 | "overprovision": "[parameters('overProvision')]", 466 | "upgradePolicy": { 467 | "mode": "Automatic" 468 | }, 469 | "virtualMachineProfile": { 470 | "extensionProfile": { 471 | "extensions": [ 472 | { 473 | "name": "[concat(parameters('vmNodeType0Name'),'_ServiceFabricNode')]", 474 | "properties": { 475 | "type": "ServiceFabricNode", 476 | "autoUpgradeMinorVersion": false, 477 | "protectedSettings": { 478 | "StorageAccountKey1": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('supportLogStorageAccountName')),'2015-05-01-preview').key1]", 479 | "StorageAccountKey2": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('supportLogStorageAccountName')),'2015-05-01-preview').key2]" 480 | }, 481 | "publisher": "Microsoft.Azure.ServiceFabric", 482 | "settings": { 483 | "clusterEndpoint": "[reference(parameters('clusterName')).clusterEndpoint]", 484 | "nodeTypeRef": "[parameters('vmNodeType0Name')]", 485 | "dataPath": "D:\\\\SvcFab", 486 | "durabilityLevel": "Bronze" 487 | }, 488 | "typeHandlerVersion": "1.0" 489 | } 490 | }, 491 | { 492 | "name": "[concat('VMDiagnosticsVmExt','_vmNodeType0Name')]", 493 | "properties": { 494 | "type": "IaaSDiagnostics", 495 | "autoUpgradeMinorVersion": true, 496 | "protectedSettings": { 497 | "storageAccountName": "[parameters('applicationDiagnosticsStorageAccountName')]", 498 | "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('applicationDiagnosticsStorageAccountName')),'2015-05-01-preview').key1]", 499 | "storageAccountEndPoint": "https://core.windows.net/" 500 | }, 501 | "publisher": "Microsoft.Azure.Diagnostics", 502 | "settings": { 503 | "WadCfg": { 504 | "DiagnosticMonitorConfiguration": { 505 | "overallQuotaInMB": "50000", 506 | "EtwProviders": { 507 | "EtwEventSourceProviderConfiguration": [ 508 | { 509 | "provider": "Microsoft-ServiceFabric-Actors", 510 | "scheduledTransferKeywordFilter": "1", 511 | "scheduledTransferPeriod": "PT5M", 512 | "DefaultEvents": { 513 | "eventDestination": "ServiceFabricReliableActorEventTable" 514 | } 515 | }, 516 | { 517 | "provider": "Microsoft-ServiceFabric-Services", 518 | "scheduledTransferPeriod": "PT5M", 519 | "DefaultEvents": { 520 | "eventDestination": "ServiceFabricReliableServiceEventTable" 521 | } 522 | } 523 | ], 524 | "EtwManifestProviderConfiguration": [ 525 | { 526 | "provider": "cbd93bc2-71e5-4566-b3a7-595d8eeca6e8", 527 | "scheduledTransferLogLevelFilter": "Information", 528 | "scheduledTransferKeywordFilter": "4611686018427387904", 529 | "scheduledTransferPeriod": "PT5M", 530 | "DefaultEvents": { 531 | "eventDestination": "ServiceFabricSystemEventTable" 532 | } 533 | } 534 | ] 535 | } 536 | } 537 | }, 538 | "StorageAccount": "[parameters('applicationDiagnosticsStorageAccountName')]" 539 | }, 540 | "typeHandlerVersion": "1.5" 541 | } 542 | } 543 | ] 544 | }, 545 | "networkProfile": { 546 | "networkInterfaceConfigurations": [ 547 | { 548 | "name": "[concat(parameters('nicName'), '-0')]", 549 | "properties": { 550 | "ipConfigurations": [ 551 | { 552 | "name": "[concat(parameters('nicName'),'-',0)]", 553 | "properties": { 554 | "loadBalancerBackendAddressPools": [ 555 | { 556 | "id": "[variables('lbPoolID0')]" 557 | } 558 | ], 559 | "loadBalancerInboundNatPools": [ 560 | { 561 | "id": "[variables('lbNatPoolID0')]" 562 | } 563 | ], 564 | "subnet": { 565 | "id": "[variables('subnet0Ref')]" 566 | } 567 | } 568 | } 569 | ], 570 | "primary": true 571 | } 572 | } 573 | ] 574 | }, 575 | "osProfile": { 576 | "adminPassword": "[parameters('adminPassword')]", 577 | "adminUsername": "[parameters('adminUsername')]", 578 | "computernamePrefix": "[parameters('vmNodeType0Name')]" 579 | }, 580 | "storageProfile": { 581 | "imageReference": { 582 | "publisher": "[parameters('vmImagePublisher')]", 583 | "offer": "[parameters('vmImageOffer')]", 584 | "sku": "[parameters('vmImageSku')]", 585 | "version": "[parameters('vmImageVersion')]" 586 | }, 587 | "osDisk": { 588 | "vhdContainers": [ 589 | "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[0]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", 590 | "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[1]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", 591 | "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[2]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", 592 | "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[3]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", 593 | "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[4]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]" 594 | ], 595 | "name": "vmssosdisk", 596 | "caching": "ReadOnly", 597 | "createOption": "FromImage" 598 | } 599 | } 600 | } 601 | }, 602 | "sku": { 603 | "name": "[parameters('vmNodeType0Size')]", 604 | "capacity": "[parameters('nt0InstanceCount')]", 605 | "tier": "Standard" 606 | }, 607 | "tags": { 608 | "resourceType": "Service Fabric", 609 | "clusterName": "[parameters('clusterName')]" 610 | } 611 | }, 612 | { 613 | "apiVersion": "2016-09-01", 614 | "type": "Microsoft.ServiceFabric/clusters", 615 | "name": "[parameters('clusterName')]", 616 | "location": "[parameters('clusterLocation')]", 617 | "dependsOn": [ 618 | "[concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName'))]" 619 | ], 620 | "properties": { 621 | "clientCertificateCommonNames": [], 622 | "clientCertificateThumbprints": [], 623 | "clusterState": "Default", 624 | "diagnosticsStorageAccountConfig": { 625 | "blobEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.blob]", 626 | "protectedAccountKeyName": "StorageAccountKey1", 627 | "queueEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.queue]", 628 | "storageAccountName": "[parameters('supportLogStorageAccountName')]", 629 | "tableEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.table]" 630 | }, 631 | "fabricSettings": [], 632 | "managementEndpoint": "[concat('http://',reference(concat(parameters('lbIPName'),'-','0')).dnsSettings.fqdn,':',parameters('nt0fabricHttpGatewayPort'))]", 633 | "nodeTypes": [ 634 | { 635 | "name": "[parameters('vmNodeType0Name')]", 636 | "applicationPorts": { 637 | "endPort": "[parameters('nt0applicationEndPort')]", 638 | "startPort": "[parameters('nt0applicationStartPort')]" 639 | }, 640 | "clientConnectionEndpointPort": "[parameters('nt0fabricTcpGatewayPort')]", 641 | "durabilityLevel": "Bronze", 642 | "ephemeralPorts": { 643 | "endPort": "[parameters('nt0ephemeralEndPort')]", 644 | "startPort": "[parameters('nt0ephemeralStartPort')]" 645 | }, 646 | "httpGatewayEndpointPort": "[parameters('nt0fabricHttpGatewayPort')]", 647 | "isPrimary": true, 648 | "vmInstanceCount": "[parameters('nt0InstanceCount')]" 649 | } 650 | ], 651 | "provisioningState": "Default", 652 | "reliabilityLevel": "Silver", 653 | "upgradeMode": "Automatic", 654 | "vmImage": "Windows" 655 | }, 656 | "tags": { 657 | "resourceType": "Service Fabric", 658 | "clusterName": "[parameters('clusterName')]" 659 | } 660 | } 661 | ], 662 | "outputs": { 663 | "clusterProperties": { 664 | "value": "[reference(parameters('clusterName'))]", 665 | "type": "object" 666 | } 667 | } 668 | } -------------------------------------------------------------------------------- /templates/networking/template_existingvnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "clusterLocation": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Location of the Cluster" 9 | } 10 | }, 11 | "clusterName": { 12 | "type": "string", 13 | "defaultValue": "Cluster", 14 | "metadata": { 15 | "description": "Name of your cluster - Between 3 and 23 characters. Letters and numbers only" 16 | } 17 | }, 18 | "nt0applicationStartPort": { 19 | "type": "int", 20 | "defaultValue": 20000 21 | }, 22 | "nt0applicationEndPort": { 23 | "type": "int", 24 | "defaultValue": 30000 25 | }, 26 | "nt0ephemeralStartPort": { 27 | "type": "int", 28 | "defaultValue": 49152 29 | }, 30 | "nt0ephemeralEndPort": { 31 | "type": "int", 32 | "defaultValue": 65534 33 | }, 34 | "nt0fabricTcpGatewayPort": { 35 | "type": "int", 36 | "defaultValue": 19000 37 | }, 38 | "nt0fabricHttpGatewayPort": { 39 | "type": "int", 40 | "defaultValue": 19080 41 | }, 42 | "subnet0Name": { 43 | "type": "string", 44 | "defaultValue": "default" 45 | }, 46 | "existingVNetRGName": { 47 | "type": "string", 48 | "defaultValue": "ExistingRG" 49 | }, 50 | "existingVNetName": { 51 | "type": "string", 52 | "defaultValue": "ExistingRG-vnet" 53 | }, 54 | /* 55 | "subnet0Name": { 56 | "type": "string", 57 | "defaultValue": "Subnet-0" 58 | }, 59 | "subnet0Prefix": { 60 | "type": "string", 61 | "defaultValue": "10.0.0.0/24" 62 | },*/ 63 | "computeLocation": { 64 | "type": "string" 65 | }, 66 | "vmStorageAccountName": { 67 | "type": "string" 68 | }, 69 | "publicIPAddressName": { 70 | "type": "string", 71 | "defaultValue": "PublicIP-VM" 72 | }, 73 | "publicIPAddressType": { 74 | "type": "string", 75 | "allowedValues": [ 76 | "Dynamic" 77 | ], 78 | "defaultValue": "Dynamic" 79 | }, 80 | "vmStorageAccountContainerName": { 81 | "type": "string", 82 | "defaultValue": "vhds" 83 | }, 84 | "adminUserName": { 85 | "type": "string", 86 | "defaultValue": "testadm", 87 | "metadata": { 88 | "description": "Remote desktop user Id" 89 | } 90 | }, 91 | "adminPassword": { 92 | "type": "securestring", 93 | "metadata": { 94 | "description": "Remote desktop user password. Must be a strong password" 95 | } 96 | }, 97 | "virtualNetworkName": { 98 | "type": "string", 99 | "defaultValue": "VNet" 100 | }, 101 | "addressPrefix": { 102 | "type": "string", 103 | "defaultValue": "10.0.0.0/16" 104 | }, 105 | "dnsName": { 106 | "type": "string" 107 | }, 108 | "nicName": { 109 | "type": "string", 110 | "defaultValue": "NIC" 111 | }, 112 | "lbName": { 113 | "type": "string", 114 | "defaultValue": "LoadBalancer" 115 | }, 116 | "lbIPName": { 117 | "type": "string", 118 | "defaultValue": "PublicIP-LB-FE" 119 | }, 120 | "overProvision": { 121 | "type": "string", 122 | "defaultValue": "false" 123 | }, 124 | "vmImagePublisher": { 125 | "type": "string", 126 | "defaultValue": "MicrosoftWindowsServer" 127 | }, 128 | "vmImageOffer": { 129 | "type": "string", 130 | "defaultValue": "WindowsServer" 131 | }, 132 | "vmImageSku": { 133 | "type": "string", 134 | "defaultValue": "2012-R2-Datacenter" 135 | }, 136 | "vmImageVersion": { 137 | "type": "string", 138 | "defaultValue": "latest" 139 | }, 140 | "loadBalancedAppPort1": { 141 | "type": "int", 142 | "defaultValue": 80, 143 | "metadata": { 144 | "description": "Input endpoint1 for the application to use. Replace it with what your application uses" 145 | } 146 | }, 147 | "storageAccountType": { 148 | "type": "string", 149 | "allowedValues": [ 150 | "Standard_LRS", 151 | "Standard_GRS" 152 | ], 153 | "defaultValue": "Standard_LRS", 154 | "metadata": { 155 | "description": "Replication option for the VM image storage account" 156 | } 157 | }, 158 | "supportLogStorageAccountType": { 159 | "type": "string", 160 | "allowedValues": [ 161 | "Standard_LRS", 162 | "Standard_GRS" 163 | ], 164 | "defaultValue": "Standard_LRS", 165 | "metadata": { 166 | "description": "Replication option for the support log storage account" 167 | } 168 | }, 169 | "supportLogStorageAccountName": { 170 | "type": "string", 171 | "defaultValue": "[toLower( concat('sflogs', uniqueString(resourceGroup().id),'2'))]", 172 | "metadata": { 173 | "description": "Name for the storage account that contains support logs from the cluster" 174 | } 175 | }, 176 | "applicationDiagnosticsStorageAccountType": { 177 | "type": "string", 178 | "allowedValues": [ 179 | "Standard_LRS", 180 | "Standard_GRS" 181 | ], 182 | "defaultValue": "Standard_LRS", 183 | "metadata": { 184 | "description": "Replication option for the application diagnostics storage account" 185 | } 186 | }, 187 | "applicationDiagnosticsStorageAccountName": { 188 | "type": "string", 189 | "defaultValue": "[toLower(concat(uniqueString(resourceGroup().id), '3' ))]", 190 | "metadata": { 191 | "description": "Name for the storage account that contains application diagnostics data from the cluster" 192 | } 193 | }, 194 | "nt0InstanceCount": { 195 | "type": "int", 196 | "defaultValue": 5, 197 | "metadata": { 198 | "description": "Instance count for node type" 199 | } 200 | }, 201 | "vmNodeType0Name": { 202 | "type": "string", 203 | "defaultValue": "Node1", 204 | "maxLength": 9 205 | }, 206 | "vmNodeType0Size": { 207 | "type": "string", 208 | "defaultValue": "Standard_D1_v2" 209 | } 210 | }, 211 | "variables": { 212 | "vmssApiVersion": "2016-03-30", 213 | "lbApiVersion": "2015-06-15", 214 | "vNetApiVersion": "2015-06-15", 215 | "storageApiVersion": "2016-01-01", 216 | "publicIPApiVersion": "2015-06-15", 217 | /*"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]",*/ 218 | "vnetID": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('existingVNetRGName'), '/providers/Microsoft.Network/virtualNetworks/', parameters('existingVNetName'))]", 219 | "subnet0Ref": "[concat(variables('vnetID'),'/subnets/',parameters('subnet0Name'))]", 220 | "lbID0": "[resourceId('Microsoft.Network/loadBalancers', concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name')))]", 221 | "lbIPConfig0": "[concat(variables('lbID0'),'/frontendIPConfigurations/LoadBalancerIPConfig')]", 222 | "lbPoolID0": "[concat(variables('lbID0'),'/backendAddressPools/LoadBalancerBEAddressPool')]", 223 | "lbProbeID0": "[concat(variables('lbID0'),'/probes/FabricGatewayProbe')]", 224 | "lbHttpProbeID0": "[concat(variables('lbID0'),'/probes/FabricHttpGatewayProbe')]", 225 | "lbNatPoolID0": "[concat(variables('lbID0'),'/inboundNatPools/LoadBalancerBEAddressNatPool')]", 226 | "vmStorageAccountName0": "[toLower(concat(uniqueString(resourceGroup().id), '1', '0' ))]", 227 | "uniqueStringArray0": [ 228 | "[concat(variables('vmStorageAccountName0'), '0')]", 229 | "[concat(variables('vmStorageAccountName0'), '1')]", 230 | "[concat(variables('vmStorageAccountName0'), '2')]", 231 | "[concat(variables('vmStorageAccountName0'), '3')]", 232 | "[concat(variables('vmStorageAccountName0'), '4')]" 233 | ] 234 | }, 235 | "resources": [ 236 | { 237 | "apiVersion": "[variables('storageApiVersion')]", 238 | "type": "Microsoft.Storage/storageAccounts", 239 | "name": "[parameters('supportLogStorageAccountName')]", 240 | "location": "[parameters('computeLocation')]", 241 | "dependsOn": [], 242 | "properties": {}, 243 | "kind": "Storage", 244 | "sku": { 245 | "name": "[parameters('supportLogStorageAccountType')]" 246 | }, 247 | "tags": { 248 | "resourceType": "Service Fabric", 249 | "clusterName": "[parameters('clusterName')]" 250 | } 251 | }, 252 | { 253 | "apiVersion": "[variables('storageApiVersion')]", 254 | "type": "Microsoft.Storage/storageAccounts", 255 | "name": "[parameters('applicationDiagnosticsStorageAccountName')]", 256 | "location": "[parameters('computeLocation')]", 257 | "dependsOn": [], 258 | "properties": {}, 259 | "kind": "Storage", 260 | "sku": { 261 | "name": "[parameters('applicationDiagnosticsStorageAccountType')]" 262 | }, 263 | "tags": { 264 | "resourceType": "Service Fabric", 265 | "clusterName": "[parameters('clusterName')]" 266 | } 267 | }, 268 | /* 269 | { 270 | "apiVersion": "[variables('vNetApiVersion')]", 271 | "type": "Microsoft.Network/virtualNetworks", 272 | "name": "[parameters('virtualNetworkName')]", 273 | "location": "[parameters('computeLocation')]", 274 | "properties": { 275 | "addressSpace": { 276 | "addressPrefixes": [ 277 | "[parameters('addressPrefix')]" 278 | ] 279 | }, 280 | "subnets": [ 281 | { 282 | "name": "[parameters('subnet0Name')]", 283 | "properties": { 284 | "addressPrefix": "[parameters('subnet0Prefix')]" 285 | } 286 | } 287 | ] 288 | }, 289 | "tags": { 290 | "resourceType": "Service Fabric", 291 | "clusterName": "[parameters('clusterName')]" 292 | } 293 | }, 294 | */ 295 | { 296 | "apiVersion": "[variables('publicIPApiVersion')]", 297 | "type": "Microsoft.Network/publicIPAddresses", 298 | "name": "[concat(parameters('lbIPName'),'-','0')]", 299 | "location": "[parameters('computeLocation')]", 300 | "properties": { 301 | "dnsSettings": { 302 | "domainNameLabel": "[parameters('dnsName')]" 303 | }, 304 | "publicIPAllocationMethod": "Dynamic" 305 | }, 306 | "tags": { 307 | "resourceType": "Service Fabric", 308 | "clusterName": "[parameters('clusterName')]" 309 | } 310 | }, 311 | { 312 | "apiVersion": "[variables('lbApiVersion')]", 313 | "type": "Microsoft.Network/loadBalancers", 314 | "name": "[concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name'))]", 315 | "location": "[parameters('computeLocation')]", 316 | "dependsOn": [ 317 | "[concat('Microsoft.Network/publicIPAddresses/',concat(parameters('lbIPName'),'-','0'))]" 318 | ], 319 | "properties": { 320 | "frontendIPConfigurations": [ 321 | { 322 | "name": "LoadBalancerIPConfig", 323 | "properties": { 324 | "publicIPAddress": { 325 | "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('lbIPName'),'-','0'))]" 326 | } 327 | } 328 | } 329 | ], 330 | "backendAddressPools": [ 331 | { 332 | "name": "LoadBalancerBEAddressPool", 333 | "properties": {} 334 | } 335 | ], 336 | "loadBalancingRules": [ 337 | { 338 | "name": "LBRule", 339 | "properties": { 340 | "backendAddressPool": { 341 | "id": "[variables('lbPoolID0')]" 342 | }, 343 | "backendPort": "[parameters('nt0fabricTcpGatewayPort')]", 344 | "enableFloatingIP": "false", 345 | "frontendIPConfiguration": { 346 | "id": "[variables('lbIPConfig0')]" 347 | }, 348 | "frontendPort": "[parameters('nt0fabricTcpGatewayPort')]", 349 | "idleTimeoutInMinutes": "5", 350 | "probe": { 351 | "id": "[variables('lbProbeID0')]" 352 | }, 353 | "protocol": "tcp" 354 | } 355 | }, 356 | { 357 | "name": "LBHttpRule", 358 | "properties": { 359 | "backendAddressPool": { 360 | "id": "[variables('lbPoolID0')]" 361 | }, 362 | "backendPort": "[parameters('nt0fabricHttpGatewayPort')]", 363 | "enableFloatingIP": "false", 364 | "frontendIPConfiguration": { 365 | "id": "[variables('lbIPConfig0')]" 366 | }, 367 | "frontendPort": "[parameters('nt0fabricHttpGatewayPort')]", 368 | "idleTimeoutInMinutes": "5", 369 | "probe": { 370 | "id": "[variables('lbHttpProbeID0')]" 371 | }, 372 | "protocol": "tcp" 373 | } 374 | }, 375 | { 376 | "name": "AppPortLBRule1", 377 | "properties": { 378 | "backendAddressPool": { 379 | "id": "[variables('lbPoolID0')]" 380 | }, 381 | "backendPort": "[parameters('loadBalancedAppPort1')]", 382 | "enableFloatingIP": "false", 383 | "frontendIPConfiguration": { 384 | "id": "[variables('lbIPConfig0')]" 385 | }, 386 | "frontendPort": "[parameters('loadBalancedAppPort1')]", 387 | "idleTimeoutInMinutes": "5", 388 | "probe": { 389 | "id": "[concat(variables('lbID0'),'/probes/AppPortProbe1')]" 390 | }, 391 | "protocol": "tcp" 392 | } 393 | } 394 | ], 395 | "probes": [ 396 | { 397 | "name": "FabricGatewayProbe", 398 | "properties": { 399 | "intervalInSeconds": 5, 400 | "numberOfProbes": 2, 401 | "port": "[parameters('nt0fabricTcpGatewayPort')]", 402 | "protocol": "tcp" 403 | } 404 | }, 405 | { 406 | "name": "FabricHttpGatewayProbe", 407 | "properties": { 408 | "intervalInSeconds": 5, 409 | "numberOfProbes": 2, 410 | "port": "[parameters('nt0fabricHttpGatewayPort')]", 411 | "protocol": "tcp" 412 | } 413 | }, 414 | { 415 | "name": "AppPortProbe1", 416 | "properties": { 417 | "intervalInSeconds": 5, 418 | "numberOfProbes": 2, 419 | "port": "[parameters('loadBalancedAppPort1')]", 420 | "protocol": "tcp" 421 | } 422 | } 423 | ], 424 | "inboundNatPools": [ 425 | { 426 | "name": "LoadBalancerBEAddressNatPool", 427 | "properties": { 428 | "backendPort": "3389", 429 | "frontendIPConfiguration": { 430 | "id": "[variables('lbIPConfig0')]" 431 | }, 432 | "frontendPortRangeEnd": "4500", 433 | "frontendPortRangeStart": "3389", 434 | "protocol": "tcp" 435 | } 436 | } 437 | ] 438 | }, 439 | "tags": { 440 | "resourceType": "Service Fabric", 441 | "clusterName": "[parameters('clusterName')]" 442 | } 443 | }, 444 | { 445 | "apiVersion": "[variables('storageApiVersion')]", 446 | "type": "Microsoft.Storage/storageAccounts", 447 | "name": "[variables('uniqueStringArray0')[copyIndex()]]", 448 | "location": "[parameters('computeLocation')]", 449 | "dependsOn": [], 450 | "properties": {}, 451 | "copy": { 452 | "name": "storageLoop", 453 | "count": 5 454 | }, 455 | "kind": "Storage", 456 | "sku": { 457 | "name": "[parameters('storageAccountType')]" 458 | }, 459 | "tags": { 460 | "resourceType": "Service Fabric", 461 | "clusterName": "[parameters('clusterName')]" 462 | } 463 | }, 464 | { 465 | "apiVersion": "[variables('vmssApiVersion')]", 466 | "type": "Microsoft.Compute/virtualMachineScaleSets", 467 | "name": "[parameters('vmNodeType0Name')]", 468 | "location": "[parameters('computeLocation')]", 469 | "dependsOn": [ 470 | /* "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]", */ 471 | "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[0])]", 472 | "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[1])]", 473 | "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[2])]", 474 | "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[3])]", 475 | "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[4])]", 476 | "[concat('Microsoft.Network/loadBalancers/', concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name')))]", 477 | "[concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName'))]", 478 | "[concat('Microsoft.Storage/storageAccounts/', parameters('applicationDiagnosticsStorageAccountName'))]" 479 | ], 480 | "properties": { 481 | "overprovision": "[parameters('overProvision')]", 482 | "upgradePolicy": { 483 | "mode": "Automatic" 484 | }, 485 | "virtualMachineProfile": { 486 | "extensionProfile": { 487 | "extensions": [ 488 | { 489 | "name": "[concat(parameters('vmNodeType0Name'),'_ServiceFabricNode')]", 490 | "properties": { 491 | "type": "ServiceFabricNode", 492 | "autoUpgradeMinorVersion": false, 493 | "protectedSettings": { 494 | "StorageAccountKey1": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('supportLogStorageAccountName')),'2015-05-01-preview').key1]", 495 | "StorageAccountKey2": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('supportLogStorageAccountName')),'2015-05-01-preview').key2]" 496 | }, 497 | "publisher": "Microsoft.Azure.ServiceFabric", 498 | "settings": { 499 | "clusterEndpoint": "[reference(parameters('clusterName')).clusterEndpoint]", 500 | "nodeTypeRef": "[parameters('vmNodeType0Name')]", 501 | "dataPath": "D:\\\\SvcFab", 502 | "durabilityLevel": "Bronze" 503 | }, 504 | "typeHandlerVersion": "1.0" 505 | } 506 | }, 507 | { 508 | "name": "[concat('VMDiagnosticsVmExt','_vmNodeType0Name')]", 509 | "properties": { 510 | "type": "IaaSDiagnostics", 511 | "autoUpgradeMinorVersion": true, 512 | "protectedSettings": { 513 | "storageAccountName": "[parameters('applicationDiagnosticsStorageAccountName')]", 514 | "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('applicationDiagnosticsStorageAccountName')),'2015-05-01-preview').key1]", 515 | "storageAccountEndPoint": "https://core.windows.net/" 516 | }, 517 | "publisher": "Microsoft.Azure.Diagnostics", 518 | "settings": { 519 | "WadCfg": { 520 | "DiagnosticMonitorConfiguration": { 521 | "overallQuotaInMB": "50000", 522 | "EtwProviders": { 523 | "EtwEventSourceProviderConfiguration": [ 524 | { 525 | "provider": "Microsoft-ServiceFabric-Actors", 526 | "scheduledTransferKeywordFilter": "1", 527 | "scheduledTransferPeriod": "PT5M", 528 | "DefaultEvents": { 529 | "eventDestination": "ServiceFabricReliableActorEventTable" 530 | } 531 | }, 532 | { 533 | "provider": "Microsoft-ServiceFabric-Services", 534 | "scheduledTransferPeriod": "PT5M", 535 | "DefaultEvents": { 536 | "eventDestination": "ServiceFabricReliableServiceEventTable" 537 | } 538 | } 539 | ], 540 | "EtwManifestProviderConfiguration": [ 541 | { 542 | "provider": "cbd93bc2-71e5-4566-b3a7-595d8eeca6e8", 543 | "scheduledTransferLogLevelFilter": "Information", 544 | "scheduledTransferKeywordFilter": "4611686018427387904", 545 | "scheduledTransferPeriod": "PT5M", 546 | "DefaultEvents": { 547 | "eventDestination": "ServiceFabricSystemEventTable" 548 | } 549 | } 550 | ] 551 | } 552 | } 553 | }, 554 | "StorageAccount": "[parameters('applicationDiagnosticsStorageAccountName')]" 555 | }, 556 | "typeHandlerVersion": "1.5" 557 | } 558 | } 559 | ] 560 | }, 561 | "networkProfile": { 562 | "networkInterfaceConfigurations": [ 563 | { 564 | "name": "[concat(parameters('nicName'), '-0')]", 565 | "properties": { 566 | "ipConfigurations": [ 567 | { 568 | "name": "[concat(parameters('nicName'),'-',0)]", 569 | "properties": { 570 | "loadBalancerBackendAddressPools": [ 571 | { 572 | "id": "[variables('lbPoolID0')]" 573 | } 574 | ], 575 | "loadBalancerInboundNatPools": [ 576 | { 577 | "id": "[variables('lbNatPoolID0')]" 578 | } 579 | ], 580 | "subnet": { 581 | "id": "[variables('subnet0Ref')]" 582 | } 583 | } 584 | } 585 | ], 586 | "primary": true 587 | } 588 | } 589 | ] 590 | }, 591 | "osProfile": { 592 | "adminPassword": "[parameters('adminPassword')]", 593 | "adminUsername": "[parameters('adminUsername')]", 594 | "computernamePrefix": "[parameters('vmNodeType0Name')]" 595 | }, 596 | "storageProfile": { 597 | "imageReference": { 598 | "publisher": "[parameters('vmImagePublisher')]", 599 | "offer": "[parameters('vmImageOffer')]", 600 | "sku": "[parameters('vmImageSku')]", 601 | "version": "[parameters('vmImageVersion')]" 602 | }, 603 | "osDisk": { 604 | "vhdContainers": [ 605 | "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[0]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", 606 | "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[1]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", 607 | "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[2]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", 608 | "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[3]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", 609 | "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[4]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]" 610 | ], 611 | "name": "vmssosdisk", 612 | "caching": "ReadOnly", 613 | "createOption": "FromImage" 614 | } 615 | } 616 | } 617 | }, 618 | "sku": { 619 | "name": "[parameters('vmNodeType0Size')]", 620 | "capacity": "[parameters('nt0InstanceCount')]", 621 | "tier": "Standard" 622 | }, 623 | "tags": { 624 | "resourceType": "Service Fabric", 625 | "clusterName": "[parameters('clusterName')]" 626 | } 627 | }, 628 | { 629 | "apiVersion": "2016-09-01", 630 | "type": "Microsoft.ServiceFabric/clusters", 631 | "name": "[parameters('clusterName')]", 632 | "location": "[parameters('clusterLocation')]", 633 | "dependsOn": [ 634 | "[concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName'))]" 635 | ], 636 | "properties": { 637 | "clientCertificateCommonNames": [], 638 | "clientCertificateThumbprints": [], 639 | "clusterState": "Default", 640 | "diagnosticsStorageAccountConfig": { 641 | "blobEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.blob]", 642 | "protectedAccountKeyName": "StorageAccountKey1", 643 | "queueEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.queue]", 644 | "storageAccountName": "[parameters('supportLogStorageAccountName')]", 645 | "tableEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.table]" 646 | }, 647 | "fabricSettings": [], 648 | "managementEndpoint": "[concat('http://',reference(concat(parameters('lbIPName'),'-','0')).dnsSettings.fqdn,':',parameters('nt0fabricHttpGatewayPort'))]", 649 | "nodeTypes": [ 650 | { 651 | "name": "[parameters('vmNodeType0Name')]", 652 | "applicationPorts": { 653 | "endPort": "[parameters('nt0applicationEndPort')]", 654 | "startPort": "[parameters('nt0applicationStartPort')]" 655 | }, 656 | "clientConnectionEndpointPort": "[parameters('nt0fabricTcpGatewayPort')]", 657 | "durabilityLevel": "Bronze", 658 | "ephemeralPorts": { 659 | "endPort": "[parameters('nt0ephemeralEndPort')]", 660 | "startPort": "[parameters('nt0ephemeralStartPort')]" 661 | }, 662 | "httpGatewayEndpointPort": "[parameters('nt0fabricHttpGatewayPort')]", 663 | "isPrimary": true, 664 | "vmInstanceCount": "[parameters('nt0InstanceCount')]" 665 | } 666 | ], 667 | "provisioningState": "Default", 668 | "reliabilityLevel": "Silver", 669 | "upgradeMode": "Automatic", 670 | "vmImage": "Windows" 671 | }, 672 | "tags": { 673 | "resourceType": "Service Fabric", 674 | "clusterName": "[parameters('clusterName')]" 675 | } 676 | } 677 | ], 678 | "outputs": { 679 | "clusterProperties": { 680 | "value": "[reference(parameters('clusterName'))]", 681 | "type": "object" 682 | } 683 | } 684 | } --------------------------------------------------------------------------------