├── .gitignore ├── CSPARMPricingCal ├── CSPARMPricingCalOps │ ├── CSPARMPricingCalculator.cs │ ├── CSPARMPricingCalculatorOps.csproj │ ├── DataModel │ │ ├── AADTokenDetails.cs │ │ ├── ARMParamValue.cs │ │ ├── ARMTemplate.cs │ │ ├── CSPARMPricingInfo.cs │ │ ├── CSPAccountCreds.cs │ │ ├── ComponentModel │ │ │ ├── PublicIPProperties.cs │ │ │ ├── StorageProperties.cs │ │ │ └── VMProperties.cs │ │ ├── Meter.cs │ │ ├── RateCard.cs │ │ ├── Resource.cs │ │ ├── ResourceComponent.cs │ │ ├── VMSKUVersion.cs │ │ ├── VMSKUVersionListItem.cs │ │ └── VMSizeList.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Util │ │ ├── AuthManager.cs │ │ ├── Constants.cs │ │ ├── Helper │ │ │ ├── ExceptionLogger.cs │ │ │ ├── Online │ │ │ │ ├── ARMAPIHelper.cs │ │ │ │ └── VMOnlineHelper.cs │ │ │ ├── PropertyHelper.cs │ │ │ ├── ResourceTypeHelper.cs │ │ │ ├── VMHelper.cs │ │ │ └── VMImageHelper.cs │ │ ├── RateCardUtil.cs │ │ ├── ResourceComponents │ │ │ ├── ComponentFetcher.cs │ │ │ ├── IComponentFetcher.cs │ │ │ ├── PublicIPComponentFetcher.cs │ │ │ └── VMComponentFetcher.cs │ │ └── ResourceRateCalc.cs │ └── packages.config ├── CSPARMPricingCalUI │ ├── App.config │ ├── CSPARMPricingCalculatorForm.Designer.cs │ ├── CSPARMPricingCalculatorForm.cs │ ├── CSPARMPricingCalculatorForm.resx │ ├── CSPARMPricingCalculatorUI.csproj │ ├── Constants.cs │ ├── Program.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ ├── Util │ │ └── FileUtil.cs │ └── packages.config ├── CSPARMPricingCalculator.sln └── TestData │ ├── azuredep.json │ └── azuredeploy.parameters.json ├── Documentation ├── app_setup.md ├── contributing.md ├── deployment.md └── images │ ├── app_setup │ ├── image1.png │ ├── image10.png │ ├── image11.jpg │ ├── image12.png │ ├── image13.png │ ├── image14.png │ ├── image15.png │ ├── image2.png │ ├── image3.png │ ├── image4.png │ ├── image5.png │ ├── image6.png │ ├── image7.png │ ├── image8.png │ └── image9.png │ └── deployment │ ├── image1.png │ ├── image10.png │ ├── image11.png │ ├── image12.png │ ├── image13.png │ ├── image14.png │ ├── image15.png │ ├── image2.png │ ├── image3.png │ ├── image4.png │ ├── image5.png │ ├── image6.png │ ├── image7.png │ ├── image8.png │ └── image9.png ├── LICENSE ├── README.md └── SECURITY.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/CSPARMPricingCalculator.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Text; 12 | using DataModel; 13 | using Util; 14 | using Util.ResourceComponents; 15 | 16 | /// 17 | /// Class that has methods to fetch Rate card and perform CSP ARM Pricing Calculation for an ARM Template 18 | /// 19 | public class CSPARMPricingCalculator 20 | { 21 | /// 22 | /// Variable to store the ARM Template object 23 | /// 24 | private ARMTemplate template; 25 | 26 | /// 27 | /// Variable to store the list of meters in the CSP Rate Card 28 | /// 29 | private List meterlist; 30 | 31 | /// 32 | /// Variable to store the currency of the Azure CSP Partner 33 | /// 34 | private string currency; 35 | 36 | /// 37 | /// Gets the resource components for the Virtual machine resource in an ARM template 38 | /// 39 | /// The object containing the ARM Template 40 | /// The object containing the values in the Parameter file 41 | /// The Azure Location 42 | /// CSP Account credentials object. A token will be generated using these credentials and used for making the online API call. 43 | /// Returns the result of the CSP ARM Pricing Calculation 44 | public CSPARMPricingInfo CalculateCSPARMPricing(ARMTemplate template, ARMParamValue paramValue, string location, CSPAccountCreds cspCreds) 45 | { 46 | CSPARMPricingInfo info = new CSPARMPricingInfo(); 47 | StringBuilder log = new StringBuilder(string.Empty); 48 | info.Log = new StringBuilder(string.Empty); 49 | this.template = template; 50 | 51 | // Fetch the list of resource components for the ARM Template 52 | List components = ComponentFetcher.GetResourceComponentsForTemplate(template, paramValue, location, cspCreds, out log); 53 | 54 | if (log != null) 55 | { 56 | // Append log of exception messages if any 57 | info.Log.Append(log.ToString()); 58 | } 59 | 60 | // Fetch the Rates for the Resource components and Calculate monthly Estimates 61 | List ratedComponents = null; 62 | if (components != null && components.Count > 0) 63 | { 64 | ratedComponents = ResourceRateCalc.CalculateResourceComponentRates(components, location, this.meterlist, out log); 65 | } 66 | 67 | if (log != null) 68 | { 69 | // Append log of exception messages if any 70 | info.Log.Append(log.ToString()); 71 | } 72 | 73 | // Set currency and object of resource component with pricing and estimation details 74 | info.Currency = this.currency; 75 | info.CSPARMPricingList = ratedComponents; 76 | 77 | return info; 78 | } 79 | 80 | /// 81 | /// Load the Azure CSP Rate Card 82 | /// 83 | /// CSP Account credentials object. A token will be generated using these credentials and used for making the online Partner Center API call. 84 | public void FetchRateCard(CSPAccountCreds cspCreds) 85 | { 86 | try 87 | { 88 | // Load CSP Azure RateCard 89 | this.meterlist = RateCardUtil.GetRateCard(cspCreds); 90 | } 91 | catch (Exception) 92 | { 93 | throw; 94 | } 95 | 96 | this.currency = cspCreds.CSPCurrency; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/CSPARMPricingCalculatorOps.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5DE96F04-76F7-4DC0-88F5-1FFFE0C75477} 8 | Library 9 | Properties 10 | CSPARMPricingCalOps 11 | CSPARMPricingCalOps 12 | v4.5.2 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | false 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.23.302261847\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll 36 | True 37 | 38 | 39 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.23.302261847\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll 40 | True 41 | 42 | 43 | ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll 44 | True 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 102 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/AADTokenDetails.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using System; 10 | using Newtonsoft.Json; 11 | 12 | /// 13 | /// Class that defines the deserialized data for the JSON of the Azure AD Token 14 | /// 15 | public class AADTokenDetails 16 | { 17 | [JsonProperty("token_type")] 18 | public string Token_type { get; set; } 19 | 20 | [JsonProperty("expires_in")] 21 | public int Expires_in { get; set; } 22 | 23 | [JsonProperty("expires_on")] 24 | public string Expires_on { get; set; } 25 | 26 | [JsonProperty("not_before")] 27 | public string Not_before { get; set; } 28 | 29 | [JsonProperty("resource")] 30 | public string Resource { get; set; } 31 | 32 | [JsonProperty("access_token")] 33 | public string Access_token { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/ARMParamValue.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using Newtonsoft.Json; 10 | using Newtonsoft.Json.Linq; 11 | 12 | /// 13 | /// Class that defines the deserialized data for the JSON of the Parameter file for an ARM Template deployment 14 | /// 15 | public class ARMParamValue 16 | { 17 | [JsonProperty("contentVersion")] 18 | public string ContentVersion { get; set; } 19 | 20 | [JsonProperty("parameters")] 21 | public JObject Parameters { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/ARMTemplate.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using System.Collections.Generic; 10 | using Newtonsoft.Json; 11 | using Newtonsoft.Json.Linq; 12 | 13 | /// 14 | /// Class that defines the deserialized data for the JSON of the ARM Template file for an ARM Template deployment 15 | /// 16 | public class ARMTemplate 17 | { 18 | [JsonProperty("contentVersion")] 19 | public string ContentVersion { get; set; } 20 | 21 | [JsonProperty("parameters")] 22 | public JObject Parameters { get; set; } 23 | 24 | [JsonProperty("variables")] 25 | public JObject Variables { get; set; } 26 | 27 | [JsonProperty("resources")] 28 | public List Resources { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/CSPARMPricingInfo.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Text; 12 | 13 | /// 14 | /// Class that defines the output of the CSP ARM Pricing Calculation. Includes the list of individual components and their associated cost estimates 15 | /// 16 | public class CSPARMPricingInfo 17 | { 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | public CSPARMPricingInfo() 22 | { 23 | this.Log = new StringBuilder(); 24 | } 25 | 26 | /// 27 | /// Gets or sets the Log with exception messages. 28 | /// 29 | public StringBuilder Log { get; set; } 30 | 31 | /// 32 | /// Gets or sets the output for the ARM Pricing Calculation in List of ResourceComponent objects. 33 | /// 34 | public List CSPARMPricingList { get; set; } 35 | 36 | /// 37 | /// Gets or sets the currency for the ARM Pricing Calculation. 38 | /// 39 | public string Currency { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/CSPAccountCreds.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using System; 10 | 11 | /// 12 | /// Class that defines the configuration values including the CSP Partner Account credentials required to make Partner Center and ARM API calls 13 | /// 14 | public class CSPAccountCreds 15 | { 16 | /// 17 | /// Gets or sets the App Id for the Native App registered on Partner Center portal. This will be used for fetching CSP Rate Card. 18 | /// 19 | public string CSPClientId { get; set; } 20 | 21 | /// 22 | /// Gets or sets the Tenant Id or Microsoft Id for the CSP Partner. 23 | /// 24 | public string CSPResellerTenantID { get; set; } 25 | 26 | /// 27 | /// Gets or sets the Region for the CSP Partner. 28 | /// 29 | public string CSPRegion { get; set; } 30 | 31 | /// 32 | /// Gets or sets the Currency for the CSP Partner. 33 | /// 34 | public string CSPCurrency { get; set; } 35 | 36 | /// 37 | /// Gets or sets App Id for the Native App registered for ARM APIs with Pre-Consent. 38 | /// 39 | public string CSPNativeAppClientId { get; set; } 40 | 41 | /// 42 | /// Gets or sets Tenant Id or Microsoft Id for a CSP Customer. 43 | /// 44 | public string CSPCustomerTenantId { get; set; } 45 | 46 | /// 47 | /// Gets or sets the Subscription Id of an Azure CSP Subscription. 48 | /// 49 | public string CSPAzureSubscriptionId { get; set; } 50 | 51 | /// 52 | /// Gets or sets the Username of an Admin Agent user of the CSP Partner Org. 53 | /// 54 | public string CSPAdminAgentUserName { get; set; } 55 | 56 | /// 57 | /// Gets or sets the Password of the Admin Agent user of the CSP Partner Org. 58 | /// 59 | public string CSPAdminAgentPassword { get; set; } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/ComponentModel/PublicIPProperties.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel.ComponentModel 8 | { 9 | using Newtonsoft.Json; 10 | 11 | /// 12 | /// Class that defines the deserialized data for the JSON in properties section for the ARM resource of "type": "Microsoft.Network/publicIPAddresses" in an ARM Template 13 | /// ARM Resource API Version: 2015-06-15 14 | /// 15 | public class PublicIPProperties 16 | { 17 | [JsonProperty("publicIPAllocationMethod")] 18 | public string PublicIPAllocationMethod { get; set; } 19 | 20 | [JsonProperty("dnsSettings")] 21 | public DNSSettings DnsSettings { get; set; } 22 | } 23 | 24 | /// 25 | /// DNSSettings class 26 | /// 27 | public class DNSSettings 28 | { 29 | [JsonProperty("domainNameLabel")] 30 | public string DomainNameLabel { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/ComponentModel/StorageProperties.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel.ComponentModel 8 | { 9 | using Newtonsoft.Json; 10 | 11 | /// 12 | /// Class that defines the deserialized data for the JSON in properties section for the ARM resource of "type": "Microsoft.Storage/storageAccounts" in an ARM Template 13 | /// ARM Resource API Version: 2015-06-15 14 | /// 15 | public class StorageProperties 16 | { 17 | [JsonProperty("accountType")] 18 | public string AccountType { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/ComponentModel/VMProperties.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel.ComponentModel 8 | { 9 | using System.Collections.Generic; 10 | using Newtonsoft.Json; 11 | 12 | /// 13 | /// Class that defines the deserialized data for the JSON in properties section for the ARM resource of "type": "Microsoft.Compute/virtualMachines" in an ARM Template 14 | /// ARM Resource API Version: 2015-06-15 15 | /// 16 | public class VMProperties 17 | { 18 | [JsonProperty("hardwareProfile")] 19 | public HardwareProfile HardwareProfile { get; set; } 20 | 21 | [JsonProperty("osProfile")] 22 | public OsProfile OsProfile { get; set; } 23 | 24 | [JsonProperty("storageProfile")] 25 | public StorageProfile StorageProfile { get; set; } 26 | 27 | [JsonProperty("networkProfile")] 28 | public NetworkProfile NetworkProfile { get; set; } 29 | 30 | [JsonProperty("diagnosticsProfile")] 31 | public DiagnosticsProfile DiagnosticsProfile { get; set; } 32 | } 33 | 34 | /// 35 | /// DataDisk class 36 | /// 37 | public class DataDisk 38 | { 39 | [JsonProperty("name")] 40 | public string Name { get; set; } 41 | 42 | [JsonProperty("diskSizeGB")] 43 | public string DiskSizeGB { get; set; } 44 | 45 | [JsonProperty("lun")] 46 | public int Lun { get; set; } 47 | 48 | [JsonProperty("vhd")] 49 | public Vhd Vhd { get; set; } 50 | 51 | [JsonProperty("createOption")] 52 | public string CreateOption { get; set; } 53 | } 54 | 55 | /// 56 | /// StorageProfile class 57 | /// 58 | public class StorageProfile 59 | { 60 | [JsonProperty("imageReference")] 61 | public ImageReference ImageReference { get; set; } 62 | 63 | [JsonProperty("osDisk")] 64 | public OsDisk OsDisk { get; set; } 65 | 66 | [JsonProperty("dataDisks")] 67 | public List DataDisks { get; set; } 68 | } 69 | 70 | /// 71 | /// NetworkInterface class 72 | /// 73 | public class NetworkInterface 74 | { 75 | [JsonProperty("id")] 76 | public string Id { get; set; } 77 | } 78 | 79 | /// 80 | /// NetworkProfile class 81 | /// 82 | public class NetworkProfile 83 | { 84 | [JsonProperty("networkInterfaces")] 85 | public List NetworkInterfaces { get; set; } 86 | } 87 | 88 | /// 89 | /// BootDiagnostics class 90 | /// 91 | public class BootDiagnostics 92 | { 93 | [JsonProperty("enabled")] 94 | public string Enabled { get; set; } 95 | 96 | [JsonProperty("storageUri")] 97 | public string StorageUri { get; set; } 98 | } 99 | 100 | /// 101 | /// DiagnosticsProfile class 102 | /// 103 | public class DiagnosticsProfile 104 | { 105 | [JsonProperty("bootDiagnostics")] 106 | public BootDiagnostics BootDiagnostics { get; set; } 107 | } 108 | 109 | /// 110 | /// HardwareProfile class 111 | /// 112 | public class HardwareProfile 113 | { 114 | [JsonProperty("vmSize")] 115 | public string VmSize { get; set; } 116 | } 117 | 118 | /// 119 | /// OsProfile class 120 | /// 121 | public class OsProfile 122 | { 123 | [JsonProperty("computerName")] 124 | public string ComputerName { get; set; } 125 | 126 | [JsonProperty("adminUsername")] 127 | public string AdminUsername { get; set; } 128 | 129 | [JsonProperty("adminPassword")] 130 | public string AdminPassword { get; set; } 131 | } 132 | 133 | /// 134 | /// ImageReference class 135 | /// 136 | public class ImageReference 137 | { 138 | [JsonProperty("publisher")] 139 | public string Publisher { get; set; } 140 | 141 | [JsonProperty("offer")] 142 | public string Offer { get; set; } 143 | 144 | [JsonProperty("sku")] 145 | public string Sku { get; set; } 146 | 147 | [JsonProperty("version")] 148 | public string Version { get; set; } 149 | } 150 | 151 | /// 152 | /// Vhd class 153 | /// 154 | public class Vhd 155 | { 156 | [JsonProperty("uri")] 157 | public string Uri { get; set; } 158 | } 159 | 160 | /// 161 | /// OsDisk class 162 | /// 163 | public class OsDisk 164 | { 165 | [JsonProperty("name")] 166 | public string Name { get; set; } 167 | 168 | [JsonProperty("osType")] 169 | public string OsType { get; set; } 170 | 171 | [JsonProperty("vhd")] 172 | public Vhd Vhd { get; set; } 173 | 174 | [JsonProperty("caching")] 175 | public string Caching { get; set; } 176 | 177 | [JsonProperty("createOption")] 178 | public string CreateOption { get; set; } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/Meter.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using System.Collections.Specialized; 10 | using Newtonsoft.Json; 11 | 12 | /// 13 | /// Class that defines the deserialized data for the JSON of the meter object of CSP Azure Rate Card 14 | /// 15 | public class Meter 16 | { 17 | [JsonProperty("id")] 18 | public string MeterId { get; set; } 19 | 20 | [JsonProperty("name")] 21 | public string MeterName { get; set; } 22 | 23 | [JsonProperty("category")] 24 | public string MeterCategory { get; set; } 25 | 26 | [JsonProperty("subcategory")] 27 | public string MeterSubCategory { get; set; } 28 | 29 | [JsonProperty("unit")] 30 | public string Unit { get; set; } 31 | 32 | [JsonProperty("region")] 33 | public string MeterRegion { get; set; } 34 | 35 | [JsonProperty("rates")] 36 | public OrderedDictionary MeterRates { get; set; } 37 | 38 | [JsonProperty("effectiveDate")] 39 | public string EffectiveDate { get; set; } 40 | 41 | [JsonProperty("includedQuantity")] 42 | public double IncludedQuantity { get; set; } 43 | } 44 | } -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/RateCard.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using System.Collections.Generic; 10 | using Newtonsoft.Json; 11 | 12 | /// 13 | /// Class that defines the deserialized data for the JSON of the response of CSP Azure Partner Center Rate Card API call 14 | /// 15 | public class RateCard 16 | { 17 | [JsonProperty("Meters")] 18 | public List Meters { get; set; } 19 | 20 | [JsonProperty("Currency")] 21 | public string Currency { get; set; } 22 | 23 | [JsonProperty("Locale")] 24 | public string Locale { get; set; } 25 | 26 | [JsonProperty("IsTaxIncluded")] 27 | public bool IsTaxIncluded { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/Resource.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using System.Collections.Generic; 10 | using Newtonsoft.Json; 11 | using Newtonsoft.Json.Linq; 12 | 13 | /// 14 | /// Class that defines the deserialized data for the JSON of an ARM resource in an ARM Template 15 | /// 16 | public class Resource 17 | { 18 | /// 19 | /// Gets or sets the type of the resource in the ARM Template. 20 | /// 21 | [JsonProperty("type")] 22 | public string Type { get; set; } 23 | 24 | /// 25 | /// Gets or sets the name of the resource in the ARM Template. 26 | /// 27 | [JsonProperty("name")] 28 | public string Name { get; set; } 29 | 30 | /// 31 | /// Gets or sets the API Version of the resource in the ARM Template. 32 | /// 33 | [JsonProperty("apiVersion")] 34 | public string ApiVersion { get; set; } 35 | 36 | /// 37 | /// Gets or sets the Location of the resource in the ARM Template. 38 | /// 39 | [JsonProperty("location")] 40 | public string Location { get; set; } 41 | 42 | /// 43 | /// Gets or sets the properties section of the resource in the ARM Template. 44 | /// 45 | [JsonProperty("properties")] 46 | public JObject Properties { get; set; } 47 | 48 | /// 49 | /// Gets or sets the depends On section of the resource in the ARM Template. 50 | /// 51 | [JsonProperty("dependsOn")] 52 | public List DependsOn { get; set; } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/ResourceComponent.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using System; 10 | 11 | /// 12 | /// Class that defines the components of resource in an ARM template and its associated cost and estimates 13 | /// 14 | public class ResourceComponent 15 | { 16 | /// 17 | /// Gets or sets the name of the resource component. 18 | /// 19 | public string ResourceName { get; set; } 20 | 21 | /// 22 | /// Gets or sets the type of the resource component. 23 | /// 24 | public string ResourceType { get; set; } 25 | 26 | /// 27 | /// Gets or sets the Azure Pricing Meter Name associated with the resource component. 28 | /// 29 | public string MeterName { get; set; } 30 | 31 | /// 32 | /// Gets or sets the Azure Pricing Meter Category associated with the resource component. 33 | /// 34 | public string MeterCategory { get; set; } 35 | 36 | /// 37 | /// Gets or sets the Azure Pricing Meter SubCategory associated with the resource component. 38 | /// 39 | public string MeterSubCategory { get; set; } 40 | 41 | /// 42 | /// Gets or sets the Quantity of the resource component. 43 | /// 44 | public double Quantity { get; set; } 45 | 46 | /// 47 | /// Gets or sets a value indicating whether the resource component is chargeable or not. 48 | /// 49 | public bool IsChargeable { get; set; } 50 | 51 | /// 52 | /// Gets or sets the Azure Rate of the resource component. 53 | /// 54 | public double Rate { get; set; } 55 | 56 | /// 57 | /// Gets or sets the estimated cost over the month for the resource component. 58 | /// 59 | public double CostPerMonth { get; set; } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/VMSKUVersion.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using System.Collections.Generic; 10 | using Newtonsoft.Json; 11 | 12 | /// 13 | /// Class that defines the deserialized data for the JSON of the ARM API call to fetch the information of a Virtual machine image 14 | /// 15 | public class VMSKUVersion 16 | { 17 | [JsonProperty("properties")] 18 | public Properties Properties { get; set; } 19 | 20 | [JsonProperty("location")] 21 | public string Location { get; set; } 22 | 23 | [JsonProperty("name")] 24 | public string Name { get; set; } 25 | 26 | [JsonProperty("id")] 27 | public string Id { get; set; } 28 | } 29 | 30 | /// 31 | /// OSDiskImage class 32 | /// 33 | public class OSDiskImage 34 | { 35 | [JsonProperty("operatingSystem")] 36 | public string OperatingSystem { get; set; } 37 | } 38 | 39 | /// 40 | /// Properties class 41 | /// 42 | public class Properties 43 | { 44 | [JsonProperty("osDiskImage")] 45 | public OSDiskImage OsDiskImage { get; set; } 46 | 47 | [JsonProperty("dataDiskImages")] 48 | public List DataDiskImages { get; set; } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/VMSKUVersionListItem.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using Newtonsoft.Json; 10 | 11 | /// 12 | /// Class that defines the deserialized data for the list item object in the JSON of the ARM API call to fetch the list of Virtual machine image versions 13 | /// 14 | public class VMSKUVersionListItem 15 | { 16 | [JsonProperty("location")] 17 | public string Location { get; set; } 18 | 19 | [JsonProperty("name")] 20 | public string Name { get; set; } 21 | 22 | [JsonProperty("id")] 23 | public string Id { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/DataModel/VMSizeList.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.DataModel 8 | { 9 | using System.Collections.Generic; 10 | using Newtonsoft.Json; 11 | 12 | /// 13 | /// Class that defines the deserialized data for the JSON of the ARM API call to fetch the list of all available virtual machine sizes 14 | /// 15 | public class VMSizeList 16 | { 17 | [JsonProperty("value")] 18 | public List Value { get; set; } 19 | } 20 | 21 | /// 22 | /// VMSizeListItem class 23 | /// 24 | public class VMSizeListItem 25 | { 26 | [JsonProperty("name")] 27 | public string Name { get; set; } 28 | 29 | [JsonProperty("numberOfCores")] 30 | public int NumberOfCores { get; set; } 31 | 32 | [JsonProperty("osDiskSizeInMB")] 33 | public int OsDiskSizeInMB { get; set; } 34 | 35 | [JsonProperty("resourceDiskSizeInMB")] 36 | public int ResourceDiskSizeInMB { get; set; } 37 | 38 | [JsonProperty("memoryInMB")] 39 | public int MemoryInMB { get; set; } 40 | 41 | [JsonProperty("maxDataDiskCount")] 42 | public int MaxDataDiskCount { get; set; } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("CSPARMPricingCalOps")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("CSPARMPricingCalOps")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5de96f04-76f7-4dc0-88f5-1fffe0c75477")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/AuthManager.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Net.Http; 12 | using System.Runtime.Caching; 13 | using DataModel; 14 | using Helper; 15 | using Newtonsoft.Json; 16 | 17 | /// 18 | /// Class that has static methods to fetch the Azure AD Token 19 | /// 20 | public class AuthManager 21 | { 22 | /// 23 | /// Gets the Azure AD Token using the App + User Authentication option 24 | /// 25 | /// The Application ID 26 | /// UserName of the User 27 | /// Password of the User 28 | /// TenantID of the Azure AD from which the token is to be fetched 29 | /// Set to true if resource for token is Partner Center API, false if resource if ARM API 30 | /// Returns the Azure AD Token in String format 31 | public static string GetAzureADTokenAppUser(string appId, string userName, string password, string tenantID, bool isResourcePCAPI) 32 | { 33 | string token = null; 34 | string cacheitemNameForToken = string.Empty; 35 | if (isResourcePCAPI) 36 | { 37 | cacheitemNameForToken = "AzureADTokenAppUserAuthPC"; 38 | } 39 | else 40 | { 41 | cacheitemNameForToken = "AzureADTokenAppUserAuthARM"; 42 | } 43 | 44 | try 45 | { 46 | ObjectCache cache = MemoryCache.Default; 47 | 48 | // Fetch from cache if available 49 | if (cache.Contains(cacheitemNameForToken)) 50 | { 51 | token = cache.Get(cacheitemNameForToken) as string; 52 | } 53 | else 54 | { 55 | using (var client = new HttpClient()) 56 | { 57 | client.DefaultRequestHeaders.Add("Accept", "application/json"); 58 | client.Timeout = new TimeSpan(0, APIResponseTimeLimitConstants.TokenFetchLimit, 0); 59 | string resourceURL; 60 | 61 | // Set the Resource URL 62 | if (isResourcePCAPI) 63 | { 64 | resourceURL = APIURLConstants.PCAPIUrl; 65 | } 66 | else 67 | { 68 | resourceURL = APIURLConstants.ARMAPIResourceURL; 69 | } 70 | 71 | var content = new FormUrlEncodedContent(new[] 72 | { 73 | new KeyValuePair("resource", resourceURL), 74 | new KeyValuePair("client_id", appId), 75 | new KeyValuePair("grant_type", "password"), 76 | new KeyValuePair("username", userName), 77 | new KeyValuePair("password", password), 78 | new KeyValuePair("scope", "openid") 79 | }); 80 | 81 | string aadTokenURL = string.Format("{0}/{1}/oauth2/token", APIURLConstants.GraphAPILoginURL, tenantID); 82 | Uri uri = new Uri(aadTokenURL); 83 | var response = client.PostAsync(uri, content).Result; 84 | if (response.IsSuccessStatusCode) 85 | { 86 | // Get the result and Add to cache 87 | string result = response.Content.ReadAsStringAsync().Result; 88 | AADTokenDetails details = JsonConvert.DeserializeObject(result); 89 | token = details.Access_token; 90 | 91 | DateTimeOffset expiryTime = DateTime.Now.AddSeconds(details.Expires_in).AddSeconds(-60); 92 | cache.Add(cacheitemNameForToken, token, expiryTime); 93 | } 94 | else 95 | { 96 | string jsonResult = response.Content.ReadAsStringAsync().Result; 97 | throw new Exception(jsonResult); 98 | } 99 | } 100 | } 101 | } 102 | catch (Exception ex) 103 | { 104 | throw new Exception(ExceptionLogger.GenerateLoggerTextForOnlineHelperCall("Azure AD Token", ex.Message)); 105 | } 106 | 107 | return token; 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/Constants.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util 8 | { 9 | using System.Collections.Generic; 10 | 11 | /// 12 | /// Class contains the constant values used in the application 13 | /// 14 | public class Constants 15 | { 16 | /// 17 | /// CSP Locale of the CSP Partner 18 | /// 19 | public const string CSPLocale = "en-US"; 20 | 21 | /// 22 | /// String to get Default value of a parameter for a property 23 | /// 24 | public const string ParamDefValueString = ".defaultValue"; 25 | 26 | /// 27 | /// String to get value of a parameter for a property 28 | /// 29 | public const string ParamValueString = ".value"; 30 | 31 | /// 32 | /// Regex to fetch variable Name from a Property 33 | /// 34 | public const string VariableNameRegexString = @"^\[variables\('(.+)'\)\]$"; 35 | 36 | /// 37 | /// Regex to fetch Parameter Name from a Property 38 | /// 39 | public const string ParamNameRegexString = @"^\[parameters\('(.+)'\)\]$"; 40 | 41 | /// 42 | /// Hours in a month, used for calculating monthly cost estimates 43 | /// 44 | public const double HoursinaMonth = 744; 45 | } 46 | 47 | /// 48 | /// Class contains the constant values for custom exception messages generated 49 | /// 50 | public class LogMessagesConstants 51 | { 52 | /// 53 | /// Exception message for Missing Field 54 | /// 55 | public const string MissingFieldMsg = "Error Occured, Field: '{0}' missing or unable to read value in Resource:'{1}'"; 56 | 57 | /// 58 | /// Exception message for Invalid value for a Field 59 | /// 60 | public const string InvalidFieldMsg = "Error Occured, Field: '{0}' invalid value:'{1}' in Resource:'{2}'"; 61 | 62 | /// 63 | /// Exception message for Unsupported resource type 64 | /// 65 | public const string ResourceNotSupportedMsg = "Error Occured, Resource:'{0}' not supported by the tool"; 66 | 67 | /// 68 | /// Exception message for no resource components returned 69 | /// 70 | public const string ResourceComponentsNoOutputMsg = "Error Occured, Unable to fetch components for Resource:'{0}'"; 71 | 72 | /// 73 | /// Exception message for Read failed for a field 74 | /// 75 | public const string PropertiesReadFailedMsg = "Error Occured, Unable to read/convert Properties section for Resource:'{0}'"; 76 | 77 | /// 78 | /// Exception message for Online API Call Failure 79 | /// 80 | public const string PropertiesOnlineCallFailedMsg = "Error Occured while fetching '{0}' Online. {1}"; 81 | 82 | /// 83 | /// Exception message for Internal Error 84 | /// 85 | public const string InternalErrorMsg = "Internal Error Occured {0}"; 86 | 87 | /// 88 | /// Exception message for Meter Rate Fetch Failure 89 | /// 90 | public const string MeterRateFetchFailedMsg = "Error Occured while fetching MeterRate as '{0}' for Resource: '{1}'"; 91 | } 92 | 93 | /// 94 | /// Class contains the constant values for URLs of the API 95 | /// 96 | public class APIURLConstants 97 | { 98 | /// 99 | /// URL to fetch the Azure AD Token 100 | /// 101 | public const string GraphAPILoginURL = "https://login.windows.net"; 102 | 103 | /// 104 | /// Resource of Graph API 105 | /// 106 | public const string GraphAPIResourceURL = "https://graph.windows.net"; 107 | 108 | /// 109 | /// Resource of ARM API 110 | /// 111 | public const string ARMAPIResourceURL = "https://management.azure.com/"; 112 | 113 | /// 114 | /// ARM API URL 115 | /// 116 | public const string ARMAPIURL = "https://management.azure.com"; 117 | 118 | /// 119 | /// Compute Version for ARM API calls 120 | /// 121 | public const string ARMComputeAPIVersion = "2016-03-30"; 122 | 123 | /// 124 | /// Partner Center API URL 125 | /// 126 | public const string PCAPIUrl = "https://api.partnercenter.microsoft.com"; 127 | 128 | /// 129 | /// ARM Compute API URL to get VM SKU Versions 130 | /// 131 | public const string VMSKUGetVersionsAPIsUrl = "{0}/subscriptions/{1}/providers/Microsoft.Compute/locations/{2}/publishers/{3}/artifacttypes/vmimage/offers/{4}/skus/{5}/versions?api-version={6}"; 132 | 133 | /// 134 | /// ARM Compute API URL to get VM SKU Version details of a specific SKU version 135 | /// 136 | public const string VMSKUGetVersionDetailsAPIsUrl = "{0}{1}?api-version={2}"; 137 | 138 | /// 139 | /// ARM Compute API URL to get VM Sizes for a given location 140 | /// 141 | public const string VMGetVMSizesAPIsUrl = "{0}/subscriptions/{1}/providers/Microsoft.Compute/locations/{2}/vmSizes?api-version={3}"; 142 | } 143 | 144 | /// 145 | /// Class contains the constant values for Response Time Out values for the API Calls 146 | /// 147 | public class APIResponseTimeLimitConstants 148 | { 149 | /// 150 | /// TimeOut Limit for Rate Card Fetch from Partner Center API in minutes 151 | /// 152 | public const int RateCardFetchLimit = 3; 153 | 154 | /// 155 | /// TimeOut Limit for for fetching Azure AD Token in minutes 156 | /// 157 | public const int TokenFetchLimit = 1; 158 | 159 | /// 160 | /// TimeOut Limit for ARM API calls in minutes 161 | /// 162 | public const int APICallDefaultLimit = 2; 163 | } 164 | 165 | /// 166 | /// Class that contains the constants for ARM Resource Types supported 167 | /// 168 | public class ARMResourceTypeConstants 169 | { 170 | /// 171 | /// Storage Account Resource Type 172 | /// 173 | public const string ARMStorageResourceType = "Microsoft.Storage/storageAccounts"; 174 | 175 | /// 176 | /// Public IP Resource Type 177 | /// 178 | public const string ARMPublicIPResourceType = "Microsoft.Network/publicIPAddresses"; 179 | 180 | /// 181 | /// Virtual Network Resource Type 182 | /// 183 | public const string ARMVirtualNetworkResourceType = "Microsoft.Network/virtualNetworks"; 184 | 185 | /// 186 | /// Network Interface Resource Type 187 | /// 188 | public const string ARMNetworkInterfaceResourceType = "Microsoft.Network/networkInterfaces"; 189 | 190 | /// 191 | /// Virtual Machine Resource Type 192 | /// 193 | public const string ARMVMResourceType = "Microsoft.Compute/virtualMachines"; 194 | 195 | /// 196 | /// Availability Sets Resource Type 197 | /// 198 | public const string ARMAvailabilitySetsResourceType = "Microsoft.Compute/availabilitySets"; 199 | 200 | /// 201 | /// Load Balancers Resource Type 202 | /// 203 | public const string ARMLoadBalancerResourceType = "Microsoft.Network/loadBalancers"; 204 | } 205 | 206 | /// 207 | /// Class that contains the location mapping between Displayed values, ARM location and Location as per Pricing specifications 208 | /// 209 | public class LocationConstants 210 | { 211 | /// 212 | /// Mapping between Display names of Azure locations and the Pricing Specs 213 | /// 214 | public static readonly Dictionary LocationAsPerPricingSpecsMap = new Dictionary 215 | { 216 | { "East Asia", "AP East" }, 217 | { "Southeast Asia", "AP Southeast" }, 218 | { "Central US", "US Central" }, 219 | { "East US", "US East" }, 220 | { "East US 2", "US East 2" }, 221 | { "West US", "US West" }, 222 | { "North Central US", "US North Central" }, 223 | { "South Central US", "US South Central" }, 224 | { "North Europe", "EU North" }, 225 | { "West Europe", "EU West" }, 226 | { "Japan West", "JA West" }, 227 | { "Japan East", "JA East" }, 228 | { "Brazil South", "BR South" }, 229 | { "Australia East", "AU East" }, 230 | { "Australia Southeast", "AU Southeast" }, 231 | { "Canada Central", "CA Central" }, 232 | { "Canada East", "CA East" }, 233 | 234 | // {"UK South", "UK South" 235 | // {"UK West", "UK West" }, 236 | { "West Central US", "US West Central" }, 237 | { "West US 2", "US West 2" } 238 | }; 239 | 240 | /// 241 | /// Mapping between Display names of Azure locations and the ARM Specs 242 | /// 243 | public static readonly Dictionary LocationAsPerARMSpecsMap = new Dictionary 244 | { 245 | { "East Asia", "eastasia" }, 246 | { "Southeast Asia", "southeastasia" }, 247 | { "Central US", "centralus" }, 248 | { "East US", "eastus" }, 249 | { "East US 2", "eastus2" }, 250 | { "West US", "westus" }, 251 | { "North Central US", "northcentralus" }, 252 | { "South Central US", "southcentralus" }, 253 | { "North Europe", "northeurope" }, 254 | { "West Europe", "westeurope" }, 255 | { "Japan West", "japanwest" }, 256 | { "Japan East", "japaneast" }, 257 | { "Brazil South", "brazilsouth" }, 258 | { "Australia East", "australiaeast" }, 259 | { "Australia Southeast", "australiasoutheast" }, 260 | { "Canada Central", "canadacentral" }, 261 | { "Canada East", "canadaeast" }, 262 | { "West Central US", "westcentralus" }, 263 | { "West US 2", "westus2" } 264 | 265 | // {"UK South", "uksouth" }, 266 | // {"UK West", "ukwest" } 267 | }; 268 | 269 | /// 270 | /// Mapping between the ARM Pricing Specs of Azure locations and the Network Zones 271 | /// 272 | public static readonly Dictionary LocationZoneMap = new Dictionary() 273 | { 274 | { "US West", "Zone 1" }, 275 | { "US West 2", "Zone 1" }, 276 | { "US West Central", "Zone 1" }, 277 | { "US East", "Zone 1" }, 278 | { "US North Central", "Zone 1" }, 279 | { "US South Central", "Zone 1" }, 280 | { "US East 2", "Zone 1" }, 281 | { "US Central", "Zone 1" }, 282 | { "EU West", "Zone 1" }, 283 | { "EU North", "Zone 1" }, 284 | { "CA East", "Zone 1" }, 285 | { "CA Central", "Zone 1" }, 286 | { "AP East", "Zone 2" }, 287 | { "AP Southeast", "Zone 2" }, 288 | { "JA East", "Zone 2" }, 289 | { "JA West", "Zone 2" }, 290 | { "AU Southeast", "Zone 2" }, 291 | { "AU East", "Zone 2" }, 292 | { "BR South", "Zone 3" } 293 | 294 | // , {"","" } 295 | // , {"","" } 296 | }; 297 | } 298 | 299 | /// 300 | /// Class contains the Virtual Machines Resource Constants including default values for usage 301 | /// 302 | public class VMResourceConstants 303 | { 304 | /// 305 | /// OS Disk Size in GB for Storage Capacity Pricing of a VM Disk 306 | /// 307 | public const double StorageOSDiskSize = 20; 308 | 309 | /// 310 | /// OS Disk Size in GB for Storage Capacity Pricing of a VM Premium Disk 311 | /// 312 | public const double StoragePremiumOSDiskSize = 128; 313 | 314 | /// 315 | /// Data Disk Size in GB for Storage Capacity Pricing of a VM 316 | /// 317 | public const double StorageDataDiskSize = 100; 318 | 319 | /// 320 | /// Table Size for Storage Capacity Pricing of a VM's Diagnostics 321 | /// 322 | public const double StorageDiagnosticsTableSize = 10; 323 | 324 | /// 325 | /// Number of Transactions (in 10000) of a OS Disk for Storage Transactions Pricing of a VM Disk 326 | /// 327 | public const double DataManagementVMStorageOSDiskTrans = 100; 328 | 329 | /// 330 | /// Number of Transactions (in 10000) of a Data Disk for Storage Transactions Pricing of a VM Disk 331 | /// 332 | public const double DataManagementVMStorageDataDiskTrans = 200; 333 | 334 | /// 335 | /// Number of Transactions (in 10000) for Storage Transactions Pricing of a VM's Diagnostics 336 | /// 337 | public const double DataManagementVMDiagnosticsStorageTrans = 20; 338 | 339 | /// 340 | /// Networking Bandwidth Usage (Out) in GB 341 | /// 342 | public const double NetworkingVMNetwork = 500; 343 | 344 | /// 345 | /// Meters Field values for Virtual Machine Compute Hours Pricing 346 | /// 347 | public const string VMMeterCategory = "Virtual Machines"; 348 | 349 | /// 350 | /// Meters Field values for Virtual Machine Compute Hours Pricing 351 | /// 352 | public const string VMMeterName = "Compute Hours"; 353 | 354 | /// 355 | /// Meters Field values for Virtual Machine Compute Hours Pricing 356 | /// 357 | public const string VMMeterSubCategoryWindowsString = "{0} VM ({1})"; 358 | 359 | /// 360 | /// Meters Field values for Virtual Machine Compute Hours Pricing 361 | /// 362 | public const string VMMeterSubCategoryLinuxString = "{0} VM"; 363 | 364 | /// 365 | /// Regex Strings for VM Size A 366 | /// 367 | public const string VMASizeRegexString = @"^(Basic|Standard)_(A.+)$"; 368 | 369 | /// 370 | /// VM Size Basic String 371 | /// 372 | public const string VMSizeBasicString = "Basic"; 373 | 374 | /// 375 | /// Regex Strings for VM Size Premium D and G 376 | /// 377 | public const string VMDGPremiumSSizeRegexString = @"^(Standard_D|Standard_G)S(.+)$"; 378 | 379 | /// 380 | /// Regex Strings for VM Size Premium F 381 | /// 382 | public const string VMFPremiumSSizeRegexString = @"^(Standard_F)(.+)S$"; 383 | } 384 | 385 | /// 386 | /// Class contains the Storage Resource Constants 387 | /// 388 | public class StorageResourceConstants 389 | { 390 | /// 391 | /// Account Type for Premium Storage 392 | /// 393 | public const string StoragePremiumAccountType = "Premium_LRS"; 394 | 395 | /// 396 | /// Account Type for Standard Storage 397 | /// 398 | public const string StorageDefaultAccountType = "Standard_LRS"; 399 | 400 | /// 401 | /// Meters Field values for Storage Pricing 402 | /// 403 | public const string StorageMeterCategory = "Storage"; 404 | 405 | /// 406 | /// Meters Field values for Storage Pricing 407 | /// 408 | public const string StorageMeterNameForVMDisk = "Standard IO - Page Blob/Disk (GB)"; 409 | 410 | /// 411 | /// Meters Field values for Storage Pricing 412 | /// 413 | public const string StorageMeterNameForTable = "Standard IO - Table (GB)"; 414 | 415 | /// 416 | /// Meters Field values for Storage Pricing 417 | /// 418 | public const string DataManagementMeterCategory = "Data Management"; 419 | 420 | /// 421 | /// Meters Field values for Storage Pricing 422 | /// 423 | public const string DataManagementMeterSubCategoryForVMDisk = ""; 424 | 425 | /// 426 | /// Meters Field values for Storage Pricing 427 | /// 428 | public const string DataManagementMeterNameForStorageTrans = "Storage Transactions (in 10,000s)"; 429 | 430 | /// 431 | /// Mapping between Storage Account Type and Meter SubCategory of Storage Pricing 432 | /// 433 | public static readonly Dictionary StorageTypeAndMeterSubCategoryMap = new Dictionary 434 | { 435 | { "Standard_LRS", "Locally Redundant" }, 436 | { "Standard_GRS", "Geo Redundant" }, 437 | { "Standard_ZRS", "Zone Redundant" }, 438 | { "Premium_LRS", "Locally Redundant" } 439 | }; 440 | 441 | /// 442 | /// Premium Storage Disk Size Options 443 | /// 444 | public static readonly double[] StoragePremiumDiskValuesArray = new double[] { 128, 512, 1024 }; 445 | 446 | /// 447 | /// Mapping of Premium Storage Disk Size Options with Pricing Meter Names 448 | /// 449 | public static readonly Dictionary StoragePremiumDiskSizeAndMeterNameMap = new Dictionary 450 | { 451 | { 128, "Premium Storage - Page Blob/P10 (Units)" }, 452 | { 512, "Premium Storage - Page Blob/P20 (Units)" }, 453 | { 1024, "Premium Storage - Page Blob/P30 (Units)" } 454 | }; 455 | } 456 | 457 | /// 458 | /// Class contains the Networking Resource Constants 459 | /// 460 | public class NetworkingResourceConstants 461 | { 462 | /// 463 | /// Meters Field values for Networking Pricing 464 | /// 465 | public const string NetworkingMeterCategory = "Networking"; 466 | 467 | /// 468 | /// Meters Field values for Networking Pricing 469 | /// 470 | public const string NetworkingMeterSubCategoryForVMNetwork = ""; 471 | 472 | /// 473 | /// Meters Field values for Networking Pricing 474 | /// 475 | public const string NetworkingMeterNameForVMNetwork = "Data Transfer Out (GB)"; 476 | } 477 | 478 | /// 479 | /// Class contains the Public IP Resource Constants 480 | /// 481 | public class PublicIPResourceConstants 482 | { 483 | /// 484 | /// Static Allocation Method String 485 | /// 486 | public const string PublicPublicIPAllocationMethodStatic = "Static"; 487 | 488 | /// 489 | /// Meters Field values for Public IP Pricing 490 | /// 491 | public const string NetworkingMeterSubCategoryForPublicIP = "Public IP Addresses"; 492 | 493 | /// 494 | /// Meters Field values for Public IP Pricing 495 | /// 496 | public const string NetworkingMeterNameForPublicIP = "IP Address Hours"; 497 | } 498 | } 499 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/Helper/ExceptionLogger.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util.Helper 8 | { 9 | using System; 10 | 11 | /// 12 | /// Class that has static methods to generate Exception Log messages 13 | /// 14 | public class ExceptionLogger 15 | { 16 | /// 17 | /// Generates the Exception message for missing values for the resources in the ARM Template 18 | /// 19 | /// Name of the field missing 20 | /// Name of the resource containing the missing field 21 | /// Returns the exception message in String format 22 | public static string GenerateLoggerTextForMissingField(string fieldName, string resourceName) 23 | { 24 | return string.Format(LogMessagesConstants.MissingFieldMsg, fieldName, resourceName); 25 | } 26 | 27 | /// 28 | /// Generates the Exception message for invalid values for the resources in the ARM Template 29 | /// 30 | /// Name of the field having invalid value 31 | /// Current invalid value of the field 32 | /// Name of the resource containing the invalid value 33 | /// Returns the exception message in String format 34 | public static string GenerateLoggerTextForInvalidField(string fieldName, string fieldValue, string resourceName) 35 | { 36 | return string.Format(LogMessagesConstants.InvalidFieldMsg, fieldName, fieldValue, resourceName); 37 | } 38 | 39 | /// 40 | /// Generates the Exception message for unsupported resource types for the resource in the ARM Template 41 | /// 42 | /// Name of the resource associated with unsupported resource type 43 | /// Returns the exception message in String format 44 | public static string GenerateLoggerTextForUnSupportedResource(string resourceName) 45 | { 46 | return string.Format(LogMessagesConstants.ResourceNotSupportedMsg, resourceName); 47 | } 48 | 49 | /// 50 | /// Generates the Exception message for no output for the resource in the ARM Template 51 | /// 52 | /// Name of the resource associated with no resource output 53 | /// Returns the exception message in String format 54 | public static string GenerateLoggerTextForNoResourceOutput(string resourceName) 55 | { 56 | return string.Format(LogMessagesConstants.ResourceComponentsNoOutputMsg, resourceName); 57 | } 58 | 59 | /// 60 | /// Generates the Exception message when fails to read properties section of the resource in the ARM Template 61 | /// 62 | /// Name of the resource for which failing to read the properties section 63 | /// Returns the exception message in String format 64 | public static string GenerateLoggerTextForFailedReadProperties(string resourceName) 65 | { 66 | return string.Format(LogMessagesConstants.PropertiesReadFailedMsg, resourceName); 67 | } 68 | 69 | /// 70 | /// Generates the Exception message for Failed Online Helper Call 71 | /// 72 | /// Name of the field being fetched Online 73 | /// Error with the fetch online 74 | /// Returns the exception message in String format 75 | public static string GenerateLoggerTextForOnlineHelperCall(string field, string exceptionMsg) 76 | { 77 | return string.Format(LogMessagesConstants.PropertiesOnlineCallFailedMsg, field, exceptionMsg); 78 | } 79 | 80 | /// 81 | /// Generates the Exception message for Internal Error in the Application 82 | /// 83 | /// Details on the internal error 84 | /// Returns the exception message in String format 85 | public static string GenerateLoggerTextForInternalError(string exceptionMsg) 86 | { 87 | return string.Format(LogMessagesConstants.InternalErrorMsg, exceptionMsg); 88 | } 89 | 90 | /// 91 | /// Generates the Exception message for Meter Rate Fetch Failure 92 | /// 93 | /// Error while fetching Meter Rate 94 | /// Name of the resource for which Meter Rate fetch failed 95 | /// Returns the exception message in String format 96 | public static string GenerateLoggerTextForMeterRateFetchFailed(string reason, string resourceName) 97 | { 98 | return string.Format(LogMessagesConstants.MeterRateFetchFailedMsg, reason, resourceName); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/Helper/Online/ARMAPIHelper.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util.Helper.Online 8 | { 9 | using System; 10 | using System.Net.Http; 11 | using Newtonsoft.Json; 12 | 13 | /// 14 | /// Helper class that has static method to assist in making ARM API calls 15 | /// 16 | public class ARMAPIHelper 17 | { 18 | /// 19 | /// Performs a "GET" ARM REST API call 20 | /// 21 | /// Azure AD Token for making the ARM API call in String format 22 | /// URL of ARM API in a String format 23 | /// Timeout in minutes that needs to be set for the client making HTTP request 24 | /// The class type to be returned from the API call. 25 | /// Deserialized Object of Type T for the JSON response obtained from the ARM API call 26 | public static T GetARMCall(string token, string url, int timeOut) 27 | { 28 | T obj = default(T); 29 | try 30 | { 31 | // Create the HTTPClient object to be used for performing the ARM API call 32 | HttpClient client = new HttpClient(); 33 | 34 | // Set the headers of the HTTP request to be sent 35 | client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); 36 | client.DefaultRequestHeaders.Add("Accept", "application/json"); 37 | client.DefaultRequestHeaders.Add("x-ms-request-id", Guid.NewGuid().ToString()); 38 | 39 | // Set the timeout of the HTTP request 40 | client.Timeout = new TimeSpan(0, timeOut, 0); 41 | 42 | // Create the URI object for the HTTP request with the specified URL String 43 | Uri uri = new Uri(url); 44 | 45 | // Make the GET ARM REST API call 46 | HttpResponseMessage response = client.GetAsync(uri).Result; 47 | 48 | // Check if HTTP response is success 49 | if (response.IsSuccessStatusCode) 50 | { 51 | string jsonResult = response.Content.ReadAsStringAsync().Result; 52 | 53 | // Deserialize and get the object 54 | obj = JsonConvert.DeserializeObject(jsonResult); 55 | } 56 | else 57 | { 58 | // Get the HTTP error message and throw an exception 59 | string jsonResult = response.Content.ReadAsStringAsync().Result; 60 | throw new Exception(string.Format("ARM API Call Response: {0}", jsonResult)); 61 | } 62 | } 63 | catch (Exception) 64 | { 65 | throw; 66 | } 67 | 68 | return obj; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/Helper/Online/VMOnlineHelper.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util.Helper.Online 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using CSPARMPricingCalOps.DataModel; 13 | 14 | /// 15 | /// Helper class that has static method to fetch Azure VM Images details and Azure VM Instance Type information 16 | /// 17 | public class VMOnlineHelper 18 | { 19 | /// 20 | /// Fetches the OS Type for the specified Publisher, Offer and SKU of the Azure VM Image 21 | /// 22 | /// CSP Account credentials object. A token will be generated using these credentials and used for making the online ARM API call 23 | /// Publisher of the Azure VM Image 24 | /// Offer of the Azure VM Image 25 | /// SKU of the Azure VM Image 26 | /// Azure Location 27 | /// Returns the Operating System type in String format 28 | public static string GetVMImageOSType(CSPAccountCreds cspCreds, string publisher, string offer, string sku, string location) 29 | { 30 | string osType = null; 31 | 32 | try 33 | { 34 | // Get AAD Token 35 | string aadToken = AuthManager.GetAzureADTokenAppUser(cspCreds.CSPNativeAppClientId, cspCreds.CSPAdminAgentUserName, cspCreds.CSPAdminAgentPassword, cspCreds.CSPCustomerTenantId, false); 36 | 37 | // Get SKUList 38 | List skuVersionList = null; 39 | skuVersionList = GetVMImageSKUS(aadToken, cspCreds.CSPAzureSubscriptionId, publisher, offer, sku, location); 40 | 41 | // Get SKUVersionDetails & OSType from it 42 | if (skuVersionList != null && skuVersionList.Count != 0) 43 | { 44 | VMSKUVersionListItem versionListItem = skuVersionList.FirstOrDefault(); 45 | if (versionListItem != null && versionListItem.Id != null) 46 | { 47 | VMSKUVersion skuVersion = GetVMImageSKUVersionDetails(aadToken, versionListItem.Id); 48 | if (skuVersion != null && skuVersion.Properties != null && skuVersion.Properties.OsDiskImage != null) 49 | { 50 | osType = skuVersion.Properties.OsDiskImage.OperatingSystem; 51 | } 52 | } 53 | } 54 | } 55 | catch (Exception) 56 | { 57 | throw; 58 | } 59 | 60 | return osType; 61 | } 62 | 63 | /// 64 | /// Get the number of cores for specified Azure VM Size 65 | /// 66 | /// CSP Account credentials object. A token will be generated using these credentials and used for making the online ARM API call 67 | /// Azure VM Size 68 | /// Azure Location 69 | /// Returns the number of cores for the specified Azure VM Size 70 | public static int GetCoresForVmSize(CSPAccountCreds cspCreds, string vmSize, string location) 71 | { 72 | int numberOfCores = -1; 73 | try 74 | { 75 | // Get AAD Token 76 | string aadToken = AuthManager.GetAzureADTokenAppUser(cspCreds.CSPNativeAppClientId, cspCreds.CSPAdminAgentUserName, cspCreds.CSPAdminAgentPassword, cspCreds.CSPCustomerTenantId, false); 77 | 78 | string url = APIURLConstants.VMGetVMSizesAPIsUrl; 79 | var path = string.Format(url, APIURLConstants.ARMAPIURL, cspCreds.CSPAzureSubscriptionId, location, APIURLConstants.ARMComputeAPIVersion); 80 | 81 | // Make the ARM API call using the Online Helper class method 82 | VMSizeList sizeList = ARMAPIHelper.GetARMCall(aadToken, path, APIResponseTimeLimitConstants.APICallDefaultLimit); 83 | 84 | VMSizeListItem listItem = sizeList.Value.FirstOrDefault(x => x.Name.Equals(vmSize, StringComparison.OrdinalIgnoreCase)); 85 | if (listItem != null) 86 | { 87 | numberOfCores = listItem.NumberOfCores; 88 | } 89 | } 90 | catch (Exception e) 91 | { 92 | throw new Exception(ExceptionLogger.GenerateLoggerTextForOnlineHelperCall("Number of Cores", e.Message)); 93 | } 94 | 95 | return numberOfCores; 96 | } 97 | 98 | /// 99 | /// Fetches the VM image SKU Version Info for the specified SKU Version of the Azure VM Image 100 | /// 101 | /// Azure AD Token to make the ARM API Call 102 | /// ID of the SKU Version 103 | /// Returns the SKU Version info of the specified Azure VM Image SKU 104 | private static VMSKUVersion GetVMImageSKUVersionDetails(string token, string skuVersionID) 105 | { 106 | VMSKUVersion skuVersion = null; 107 | try 108 | { 109 | string url = APIURLConstants.VMSKUGetVersionDetailsAPIsUrl; 110 | var path = string.Format(url, APIURLConstants.ARMAPIURL, skuVersionID, APIURLConstants.ARMComputeAPIVersion); 111 | 112 | // Make the ARM API call using the Online Helper class method 113 | skuVersion = ARMAPIHelper.GetARMCall(token, path, APIResponseTimeLimitConstants.APICallDefaultLimit); 114 | } 115 | catch (Exception e) 116 | { 117 | throw new Exception(ExceptionLogger.GenerateLoggerTextForOnlineHelperCall("VM SKU Version Details", e.Message)); 118 | } 119 | 120 | return skuVersion; 121 | } 122 | 123 | /// 124 | /// Fetches the VM image SKU List for the specified Publisher, Offer and SKU of the Azure VM Image 125 | /// 126 | /// Azure AD Token to make the ARM API Call 127 | /// CSP Azure Subscription Id 128 | /// Publisher of the Azure VM Image 129 | /// Offer of the Azure VM Image 130 | /// SKU of the Azure VM Image 131 | /// Azure Location 132 | /// Returns the list of Azure VM Image SKUs 133 | private static List GetVMImageSKUS(string token, string subscriptionId, string publisher, string offer, string sku, string location) 134 | { 135 | List skuVersionList = null; 136 | try 137 | { 138 | string url = APIURLConstants.VMSKUGetVersionsAPIsUrl; 139 | var path = string.Format(url, APIURLConstants.ARMAPIURL, subscriptionId, location, publisher, offer, sku, APIURLConstants.ARMComputeAPIVersion); 140 | 141 | // Make the ARM API call using the Online Helper class method 142 | skuVersionList = ARMAPIHelper.GetARMCall>(token, path, APIResponseTimeLimitConstants.APICallDefaultLimit); 143 | } 144 | catch (Exception e) 145 | { 146 | throw new Exception(ExceptionLogger.GenerateLoggerTextForOnlineHelperCall("VM SKU Version", e.Message)); 147 | } 148 | 149 | return skuVersionList; 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/Helper/PropertyHelper.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util.Helper 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Text.RegularExpressions; 12 | using DataModel; 13 | using Newtonsoft.Json.Linq; 14 | 15 | /// 16 | /// Helper Class that has static methods to fetch property fields from the ARM Template 17 | /// 18 | public class PropertyHelper 19 | { 20 | /// 21 | /// Fetches the Property value for the specified property from the Properties section 22 | /// 23 | /// Properties object of the resource 24 | /// Property whose value is to be fetched 25 | /// Returns the Property value in String format 26 | public static string GetPropertyValue(JObject properties, string propertyPath) 27 | { 28 | string propertyValue = null; 29 | 30 | // Check if property exists, and then, fetch the value 31 | if (IsPropertyExists(properties, propertyPath)) 32 | { 33 | propertyValue = (string)properties.SelectToken(propertyPath); 34 | } 35 | 36 | return propertyValue; 37 | } 38 | 39 | /// 40 | /// Fetches the property value from a Variable or Parameter 41 | /// 42 | /// Name of the property containing the variable or parameter 43 | /// The Variables object of the ARM template 44 | /// The Parameters object of the ARM template 45 | /// The object containing the Parameter values 46 | /// Returns the Property value in String format 47 | public static string GetValueIfVariableOrParam(string variableOrParamName, JObject variables, JObject parameters, JObject paramValue) 48 | { 49 | string propertyValue = null; 50 | if (variableOrParamName != null) 51 | { 52 | // Check if its a variable or parameter 53 | if (variableOrParamName.ToUpper().Contains("VARIABLES")) 54 | { 55 | propertyValue = GetPropertyValueFromVariables(variableOrParamName, variables); 56 | } 57 | else if (variableOrParamName.ToUpper().Contains("PARAMETERS")) 58 | { 59 | propertyValue = GetPropertyValueFromParamValue(variableOrParamName, parameters, paramValue); 60 | } 61 | else 62 | { 63 | propertyValue = variableOrParamName; 64 | } 65 | } 66 | 67 | return propertyValue; 68 | } 69 | 70 | /// 71 | /// Fetches the resource in the list of resources of the ARM Template 72 | /// 73 | /// List of the resources of the ARM Template 74 | /// The property that has the name of the resource 75 | /// Returns the resource object 76 | public static Resource SearchResourceInListByName(List resourceList, string propertyContainingName) 77 | { 78 | Resource res = null; 79 | 80 | // Check if property has parameter or variable 81 | if (propertyContainingName.ToUpper().Contains("PARAMETERS") || propertyContainingName.ToUpper().Contains("VARIABLES")) 82 | { 83 | // Remove Square Brackets from PropertyName 84 | Regex r = new Regex("^[[](.+)[]]$", RegexOptions.IgnoreCase); 85 | 86 | // Iterate thru the resource list 87 | foreach (var resource in resourceList) 88 | { 89 | Match m = r.Match(resource.Name); 90 | 91 | // Check if success and get the matching resource 92 | if (m.Success) 93 | { 94 | if ((m.Groups.Count > 1) && propertyContainingName.Contains(m.Groups[1].Value)) 95 | { 96 | res = resource; 97 | break; 98 | } 99 | } 100 | } 101 | } 102 | else 103 | { 104 | // Get the resource from the resource list 105 | res = resourceList.Find(x => propertyContainingName.Contains(x.Name)); 106 | } 107 | 108 | return res; 109 | } 110 | 111 | /// 112 | /// Check if specified property exists in the properties section of the resource of the ARM Template 113 | /// 114 | /// Properties object in the resource 115 | /// Property to be checked 116 | /// Returns a value indicating if the property exists or not 117 | public static bool IsPropertyExists(JObject properties, string propertyPath) 118 | { 119 | bool isExists = false; 120 | 121 | // Check if property exists 122 | if (properties != null && properties.SelectToken(propertyPath) != null) 123 | { 124 | isExists = true; 125 | } 126 | 127 | return isExists; 128 | } 129 | 130 | /// 131 | /// Fetches the property value from a Variable 132 | /// 133 | /// Name of the property containing the variable 134 | /// The Variables object of the ARM template 135 | /// Returns the Property value in String format 136 | private static string GetPropertyValueFromVariables(string propertyValue, JObject variables) 137 | { 138 | string variableValue = null; 139 | if (variables != null) 140 | { 141 | Regex r = new Regex(Constants.VariableNameRegexString, RegexOptions.IgnoreCase); 142 | Match m = r.Match(propertyValue); 143 | 144 | // Extract the variable name from the property and get the value of the variable 145 | if (m.Success) 146 | { 147 | if (m.Groups.Count > 1) 148 | { 149 | string variableName = m.Groups[1].Value; 150 | variableValue = GetPropertyValue(variables, variableName); 151 | } 152 | } 153 | } 154 | 155 | return variableValue; 156 | } 157 | 158 | /// 159 | /// Fetches the property value from a Parameter 160 | /// 161 | /// Name of the property containing the parameter 162 | /// The Parameter object of the ARM template 163 | /// The object containing the Parameter values 164 | /// Returns the Property value in String format 165 | private static string GetPropertyValueFromParamValue(string propertyValue, JObject parameters, JObject paramValue) 166 | { 167 | string paramValueExtract = null; 168 | if (parameters != null) 169 | { 170 | Regex r = new Regex(Constants.ParamNameRegexString, RegexOptions.IgnoreCase); 171 | Match m = r.Match(propertyValue); 172 | 173 | // Extract the parameter name from the property and get the value of the parameter 174 | if (m.Success) 175 | { 176 | if (m.Groups.Count > 1) 177 | { 178 | string paramName = m.Groups[1].Value; 179 | string paramPropertyValue = paramName + Constants.ParamValueString; 180 | string paramDefaultPropertyName = paramName + Constants.ParamDefValueString; 181 | 182 | if (paramValue != null) 183 | { 184 | paramValueExtract = GetPropertyValue(paramValue, paramPropertyValue); 185 | } 186 | 187 | if (paramValueExtract == null) 188 | { 189 | paramValueExtract = GetPropertyValue(parameters, paramDefaultPropertyName); 190 | } 191 | } 192 | } 193 | } 194 | 195 | return paramValueExtract; 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/Helper/ResourceTypeHelper.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util.Helper 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | 12 | /// 13 | /// Helper Class that has the list of supported ARM resource types 14 | /// 15 | public class ResourceTypeHelper 16 | { 17 | /// 18 | /// List of resource types supported 19 | /// 20 | public static List ResourceTypeList = new List() 21 | { 22 | new ARMResourceType() { ARMResourceTypeText = ARMResourceTypeConstants.ARMStorageResourceType, HasChargableComponents = false }, 23 | new ARMResourceType() { ARMResourceTypeText = ARMResourceTypeConstants.ARMPublicIPResourceType, HasChargableComponents = true }, 24 | new ARMResourceType() { ARMResourceTypeText = ARMResourceTypeConstants.ARMVirtualNetworkResourceType, HasChargableComponents = false }, 25 | new ARMResourceType() { ARMResourceTypeText = ARMResourceTypeConstants.ARMNetworkInterfaceResourceType, HasChargableComponents = false }, 26 | new ARMResourceType() { ARMResourceTypeText = ARMResourceTypeConstants.ARMVMResourceType, HasChargableComponents = true }, 27 | new ARMResourceType() { ARMResourceTypeText = ARMResourceTypeConstants.ARMAvailabilitySetsResourceType, HasChargableComponents = false }, 28 | new ARMResourceType() { ARMResourceTypeText = ARMResourceTypeConstants.ARMLoadBalancerResourceType, HasChargableComponents = false } 29 | 30 | // , new ARMResourceType() {ARMResourceTypeText = Constants. ,HasChargableComponents = false } 31 | }; 32 | } 33 | 34 | /// 35 | /// ARMResourceType Class 36 | /// 37 | public class ARMResourceType 38 | { 39 | /// 40 | /// Gets or sets the resource type text 41 | /// 42 | public string ARMResourceTypeText { get; set; } 43 | 44 | /// 45 | /// Gets or sets a value indicating whether the resource type has chargeable components 46 | /// 47 | public bool HasChargableComponents { get; set; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/Helper/VMHelper.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util.Helper 8 | { 9 | using System; 10 | using System.Text.RegularExpressions; 11 | 12 | /// 13 | /// Helper Class that has static methods to operate on Azure VM information 14 | /// 15 | public class VMHelper 16 | { 17 | /// 18 | /// Modifies the VM Size String as per the Azure Pricing Specs 19 | /// 20 | /// VM Size String 21 | /// Returns the modified VM Size in String format 22 | public static string ModifyVMSizeStringAsPerPricingSpecs(string vmSize) 23 | { 24 | string modifiedVMSize = vmSize; 25 | 26 | if (vmSize != null) 27 | { 28 | // Flag to set if modify is complete 29 | bool isCompletedProcessing = false; 30 | 31 | // Check if A Size and Not v2, Modify 32 | if (!isCompletedProcessing) 33 | { 34 | string modifiedSize = null; 35 | if (!vmSize.Contains("v2") && GetModifiedVMSizeForASizes(vmSize, out modifiedSize)) 36 | { 37 | isCompletedProcessing = true; 38 | modifiedVMSize = modifiedSize; 39 | } 40 | } 41 | 42 | // Check if DS series, modify string accordingly 43 | if (!isCompletedProcessing) 44 | { 45 | string modifiedSize = null; 46 | if (GetModifiedVMSizeForPremiumSSizes(vmSize, out modifiedSize, VMResourceConstants.VMDGPremiumSSizeRegexString)) 47 | { 48 | isCompletedProcessing = true; 49 | modifiedVMSize = modifiedSize; 50 | } 51 | } 52 | 53 | // Check if FS series, modify string accordingly 54 | if (!isCompletedProcessing) 55 | { 56 | string modifiedSize = null; 57 | if (GetModifiedVMSizeForPremiumSSizes(vmSize, out modifiedSize, VMResourceConstants.VMFPremiumSSizeRegexString)) 58 | { 59 | isCompletedProcessing = true; 60 | modifiedVMSize = modifiedSize; 61 | } 62 | } 63 | } 64 | 65 | return modifiedVMSize; 66 | } 67 | 68 | /// 69 | /// Modifies the VM Size String for A Sizes as per the Azure Pricing Specs 70 | /// 71 | /// VM Size String 72 | /// Out parameter with Modified Size in String format 73 | /// Returns the value indicating if a match was found and size was modified or not 74 | private static bool GetModifiedVMSizeForASizes(string vmSize, out string modifiedSize) 75 | { 76 | bool isCompletedProcessing = false; 77 | modifiedSize = null; 78 | Regex r = new Regex(VMResourceConstants.VMASizeRegexString, RegexOptions.IgnoreCase); 79 | Match m = r.Match(vmSize); 80 | 81 | // Split the String to Basic or Standard and Size 82 | if (m.Success) 83 | { 84 | isCompletedProcessing = true; 85 | if (m.Groups.Count > 2) 86 | { 87 | string basicOrStandard = m.Groups[1].Value; 88 | string size = m.Groups[2].Value; 89 | 90 | // If VM Size is Basic, Change String to Basic.Size 91 | if (string.Equals(basicOrStandard, VMResourceConstants.VMSizeBasicString, StringComparison.OrdinalIgnoreCase)) 92 | { 93 | modifiedSize = VMResourceConstants.VMSizeBasicString + "." + size; 94 | } 95 | else 96 | { 97 | modifiedSize = size; 98 | } 99 | } 100 | } 101 | 102 | return isCompletedProcessing; 103 | } 104 | 105 | /// 106 | /// Modifies the VM Size String for Premium S Sizes as per the Azure Pricing Specs 107 | /// 108 | /// VM Size String 109 | /// Out parameter with Modified Size in String format 110 | /// Regex that contains the String pattern to be matched in String format 111 | /// Returns the value indicating if a match was found and size was modified or not 112 | private static bool GetModifiedVMSizeForPremiumSSizes(string vmSize, out string modifiedSize, string premiumSRegexString) 113 | { 114 | bool isCompletedProcessing = false; 115 | modifiedSize = null; 116 | 117 | Regex r = new Regex(premiumSRegexString, RegexOptions.IgnoreCase); 118 | Match m = r.Match(vmSize); 119 | 120 | // Check if VM Size is having premium disks - DS/FS/GS, Remove S and return VM Size String 121 | if (m.Success) 122 | { 123 | isCompletedProcessing = true; 124 | if (m.Groups.Count > 2) 125 | { 126 | modifiedSize = m.Groups[1].Value + m.Groups[2].Value; 127 | } 128 | } 129 | 130 | return isCompletedProcessing; 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/RateCardUtil.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IO; 12 | using System.Net.Http; 13 | using DataModel; 14 | using Helper; 15 | using Newtonsoft.Json; 16 | 17 | /// 18 | /// Class that has static method to fetch the Azure CSP Rate Card via Partner Center API 19 | /// 20 | public class RateCardUtil 21 | { 22 | /// 23 | /// Gets the Meters for the Azure CSP Rate Card 24 | /// 25 | /// CSP Account credentials object. A token will be generated using these credentials and used for making the online Partner Center API call 26 | /// Returns the list of Azure Meters 27 | public static List GetRateCard(CSPAccountCreds cspCreds) 28 | { 29 | List meterList = null; 30 | 31 | try 32 | { 33 | if (cspCreds == null) 34 | { 35 | throw new Exception(ExceptionLogger.GenerateLoggerTextForInternalError("CSP Account Credentials is null")); 36 | } 37 | 38 | // Fetch the AzureAD Token 39 | string aadToken = AuthManager.GetAzureADTokenAppUser(cspCreds.CSPClientId, cspCreds.CSPAdminAgentUserName, cspCreds.CSPAdminAgentPassword, cspCreds.CSPResellerTenantID, true); 40 | 41 | // Create the HttpClient Object 42 | HttpClient client = new HttpClient(); 43 | 44 | // Set the request header values 45 | client.DefaultRequestHeaders.Add("Authorization", "Bearer " + aadToken); 46 | client.DefaultRequestHeaders.Add("Accept", "application/json"); 47 | client.DefaultRequestHeaders.Add("MS-CorrelationId", Guid.NewGuid().ToString()); 48 | client.DefaultRequestHeaders.Add("MS-RequestId", Guid.NewGuid().ToString()); 49 | client.DefaultRequestHeaders.Add("X-Locale", Constants.CSPLocale); 50 | client.Timeout = new TimeSpan(0, APIResponseTimeLimitConstants.RateCardFetchLimit, 0); 51 | 52 | // Set the path 53 | var path = string.Format("{0}/v1/ratecards/azure?currency={1}®ion={2}", APIURLConstants.PCAPIUrl, cspCreds.CSPCurrency, cspCreds.CSPRegion); 54 | Uri uri = new Uri(path); 55 | 56 | // Make the API Call to fetch the Rate Card 57 | HttpResponseMessage response = client.GetAsync(uri).Result; 58 | 59 | if (response.IsSuccessStatusCode) 60 | { 61 | string jsonResult = response.Content.ReadAsStringAsync().Result; 62 | RateCard card = JsonConvert.DeserializeObject(jsonResult); 63 | meterList = card.Meters; 64 | } 65 | else 66 | { 67 | string jsonResult = response.Content.ReadAsStringAsync().Result; 68 | new Exception(ExceptionLogger.GenerateLoggerTextForOnlineHelperCall("CSP Rate Card", string.Format("Error while fetching the Rate Card: {0}", jsonResult))); 69 | } 70 | } 71 | catch (Exception) 72 | { 73 | throw; 74 | } 75 | 76 | return meterList; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/ResourceComponents/ComponentFetcher.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util.ResourceComponents 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Text; 12 | using DataModel; 13 | using Helper; 14 | 15 | /// 16 | /// Class that has static methods to fetch the resource components for the resources in an ARM template 17 | /// 18 | public class ComponentFetcher 19 | { 20 | /// 21 | /// Gets the resource components for the resources in an ARM template 22 | /// 23 | /// The object containing the ARM Template 24 | /// The object containing the values in the Parameter file 25 | /// The Azure Location 26 | /// CSP Account credentials object. A token will be generated using these credentials and used for making the online ARM API call 27 | /// The object that will contain the exception messages 28 | /// Returns the list of resource components 29 | public static List GetResourceComponentsForTemplate(ARMTemplate template, ARMParamValue paramvalue, string location, CSPAccountCreds cspCreds, out StringBuilder log) 30 | { 31 | List components = new List(); 32 | log = new StringBuilder(string.Empty); 33 | string locationAsPerARMSpecs = null; 34 | 35 | try 36 | { 37 | // Fetch the location as per ARM Specs from the mapping 38 | if (!LocationConstants.LocationAsPerARMSpecsMap.TryGetValue(location, out locationAsPerARMSpecs)) 39 | { 40 | throw new Exception(ExceptionLogger.GenerateLoggerTextForInvalidField("Location", location, "ARMTemplate")); 41 | } 42 | 43 | if (template.Resources != null && template.Resources.Count > 0) 44 | { 45 | // Loop thru each resource in the ARM Template 46 | foreach (Resource res in template.Resources) 47 | { 48 | ARMResourceType resType = null; 49 | string nameOfResource = string.Empty; 50 | if (res != null && res.Name != null) 51 | { 52 | // Fetch the name of the current resource 53 | nameOfResource = PropertyHelper.GetValueIfVariableOrParam(res.Name, template.Variables, template.Parameters, paramvalue.Parameters); 54 | } 55 | 56 | // Check if resource or resource type is not null 57 | if (res != null && res.Type != null) 58 | { 59 | // Check if resource type is in supported by this application 60 | resType = ResourceTypeHelper.ResourceTypeList.Find(x => res.Type.Equals(x.ARMResourceTypeText, StringComparison.OrdinalIgnoreCase)); 61 | 62 | if (resType != null) 63 | { 64 | List currentResourceComponents = new List(); 65 | 66 | // Check if the resource type of the current resource does not have chargeable components 67 | if (!resType.HasChargableComponents) 68 | { 69 | currentResourceComponents.Add(new ResourceComponent() 70 | { 71 | ResourceType = res.Type, 72 | Quantity = 0, 73 | IsChargeable = false 74 | }); 75 | } 76 | else 77 | { 78 | IComponentFetcher resCompFetcher = null; 79 | 80 | // Create the appropriate object to fetch the components of the resource 81 | switch (resType.ARMResourceTypeText) 82 | { 83 | // Public IP Resource 84 | case ARMResourceTypeConstants.ARMPublicIPResourceType: 85 | resCompFetcher = new PublicIPComponentFetcher(); 86 | break; 87 | 88 | // Virtual Machine Resource 89 | case ARMResourceTypeConstants.ARMVMResourceType: 90 | resCompFetcher = new VMComponentFetcher(); 91 | break; 92 | 93 | default: 94 | 95 | // Has Chargable Components but not yet supported 96 | log.AppendLine(ExceptionLogger.GenerateLoggerTextForUnSupportedResource(res.Type)); 97 | break; 98 | } 99 | 100 | StringBuilder resLog = new StringBuilder(string.Empty); 101 | 102 | // Call the method to fetch the resource components 103 | List resComp = resCompFetcher.GetResourceComponents(res, template, paramvalue, locationAsPerARMSpecs, cspCreds, out resLog); 104 | if (resLog != null) 105 | { 106 | log.Append(resLog); 107 | } 108 | 109 | if (resComp != null && resComp.Count > 0) 110 | { 111 | currentResourceComponents.AddRange(resComp); 112 | } 113 | else 114 | { 115 | log.AppendLine(ExceptionLogger.GenerateLoggerTextForNoResourceOutput(nameOfResource)); 116 | } 117 | } 118 | 119 | foreach (ResourceComponent component in currentResourceComponents) 120 | { 121 | component.ResourceName = nameOfResource; 122 | } 123 | 124 | components.AddRange(currentResourceComponents); 125 | } 126 | else 127 | { 128 | log.AppendLine(ExceptionLogger.GenerateLoggerTextForUnSupportedResource(res.Type)); 129 | } 130 | } 131 | else 132 | { 133 | if (res != null) 134 | { 135 | // Type of the resourse is missing/null, generate the message 136 | log.AppendLine(ExceptionLogger.GenerateLoggerTextForMissingField("Type", nameOfResource)); 137 | } 138 | else 139 | { 140 | // Resourse is missing/null, generate the message 141 | log.AppendLine(ExceptionLogger.GenerateLoggerTextForMissingField("Resource", "ARMTemplate")); 142 | } 143 | } 144 | } 145 | } 146 | else 147 | { 148 | // Resources section in ARM template is missing/null, generate a message 149 | throw new Exception(ExceptionLogger.GenerateLoggerTextForMissingField("RESOURCES", "ARMTemplate")); 150 | } 151 | } 152 | catch (Exception ex) 153 | { 154 | // Catch any exception and log the message 155 | components = null; 156 | log.AppendLine(ex.Message); 157 | } 158 | 159 | // Return the list of components obtained for the resources in the ARM template 160 | return components; 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/ResourceComponents/IComponentFetcher.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util.ResourceComponents 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Text; 12 | using DataModel; 13 | 14 | /// 15 | /// Interface defining the method signature to fetch the components of a resource in an ARM template 16 | /// This interface is implemented by each resource type that is supported by this application and has chargeable components 17 | /// 18 | public interface IComponentFetcher 19 | { 20 | /// 21 | /// Gets the resource components for the resources in an ARM template 22 | /// 23 | /// The object containing the resource 24 | /// The object containing the ARM Template 25 | /// The object containing the values in the Parameter file 26 | /// The Azure Location 27 | /// CSP Account credentials object. A token will be generated using these credentials and used for making the online ARM API call 28 | /// The object that will contain the exception messages 29 | /// Returns the list of resource components 30 | List GetResourceComponents(Resource resource, ARMTemplate template, ARMParamValue paramValue, string location, CSPAccountCreds cspCreds, out StringBuilder log); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/ResourceComponents/PublicIPComponentFetcher.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util.ResourceComponents 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Text; 12 | using DataModel; 13 | using DataModel.ComponentModel; 14 | using Helper; 15 | 16 | /// 17 | /// Class that has method to fetch the resource components for the Public IP resource: "Microsoft.Network/publicIPAddresses" in an ARM template 18 | /// ARM Resource API Version: 2015-06-15 19 | /// 20 | public class PublicIPComponentFetcher : IComponentFetcher 21 | { 22 | /// 23 | /// Variable to store the Public IP resource from the ARM Template 24 | /// 25 | private Resource resource; 26 | 27 | /// 28 | /// Variable to store the ARM Template 29 | /// 30 | private ARMTemplate template; 31 | 32 | /// 33 | /// Variable to store the values of parameters from the Parameter file 34 | /// 35 | private ARMParamValue paramValue; 36 | 37 | /// 38 | /// Variable to store the name of the resource 39 | /// 40 | private string nameOfResource = string.Empty; 41 | 42 | /// 43 | /// Variable to store the properties of the Public IP resource from the ARM Template 44 | /// 45 | private PublicIPProperties prop; 46 | 47 | /// 48 | /// Gets the resource components for the Public IP resources in an ARM template 49 | /// 50 | /// The object containing the resource 51 | /// The object containing the ARM Template 52 | /// The object containing the values in the Parameter file 53 | /// The Azure Location 54 | /// CSP Account credentials object. This is not used in current version. 55 | /// The object that will contain the exception messages 56 | /// Returns the list of resource components 57 | public List GetResourceComponents(Resource resource, ARMTemplate template, ARMParamValue paramValue, string location, CSPAccountCreds cspCreds, out StringBuilder log) 58 | { 59 | this.resource = resource; 60 | this.template = template; 61 | this.paramValue = paramValue; 62 | List componentList = new List(); 63 | log = new StringBuilder(string.Empty); 64 | 65 | try 66 | { 67 | if (resource != null && resource.Name != null) 68 | { 69 | // Fetch the name of the resource 70 | this.nameOfResource = PropertyHelper.GetValueIfVariableOrParam(resource.Name, template.Variables, template.Parameters, paramValue.Parameters); 71 | } 72 | 73 | // Convert Resource Properties to PublicIPProperties 74 | if (resource != null && resource.Properties != null) 75 | { 76 | this.prop = resource.Properties.ToObject(); 77 | 78 | if (this.prop != null) 79 | { 80 | // Get the resource components for Public IP Resource 81 | componentList.AddRange(this.GetResourceComponentForPublicIP()); 82 | } 83 | else 84 | { 85 | throw new Exception(ExceptionLogger.GenerateLoggerTextForFailedReadProperties(this.nameOfResource)); 86 | } 87 | } 88 | else 89 | { 90 | throw new Exception(ExceptionLogger.GenerateLoggerTextForMissingField("Properties", this.nameOfResource)); 91 | } 92 | } 93 | catch (Exception ex) 94 | { 95 | componentList = null; 96 | log.AppendLine(ex.Message); 97 | } 98 | 99 | return componentList; 100 | } 101 | 102 | /// 103 | /// Gets the resource components for the Public IP resource by checking if the Public IP Allocation method is static 104 | /// 105 | /// Returns the list of resource components 106 | private List GetResourceComponentForPublicIP() 107 | { 108 | List componentList = new List(); 109 | 110 | ResourceComponent publicIPComponent = new ResourceComponent() 111 | { 112 | ResourceType = this.resource.Type, 113 | Quantity = 0, 114 | IsChargeable = false, 115 | ResourceName = this.nameOfResource 116 | }; 117 | 118 | string publicIPAllocationMethod = null; 119 | 120 | // Get the Allocation method 121 | publicIPAllocationMethod = PropertyHelper.GetValueIfVariableOrParam(this.prop.PublicIPAllocationMethod, this.template.Variables, this.template.Parameters, this.paramValue.Parameters); 122 | 123 | if (publicIPAllocationMethod != null) 124 | { 125 | // Check if Static Allocation, Add resource component with associated meter 126 | if (publicIPAllocationMethod.Equals(PublicIPResourceConstants.PublicPublicIPAllocationMethodStatic, StringComparison.OrdinalIgnoreCase)) 127 | { 128 | publicIPComponent.MeterCategory = NetworkingResourceConstants.NetworkingMeterCategory; 129 | publicIPComponent.MeterSubCategory = PublicIPResourceConstants.NetworkingMeterSubCategoryForPublicIP; 130 | publicIPComponent.MeterName = PublicIPResourceConstants.NetworkingMeterNameForPublicIP; 131 | publicIPComponent.IsChargeable = true; 132 | publicIPComponent.Quantity = Constants.HoursinaMonth; 133 | } 134 | } 135 | else 136 | { 137 | throw new Exception(ExceptionLogger.GenerateLoggerTextForMissingField("publicIPAllocationMethod", this.nameOfResource)); 138 | } 139 | 140 | componentList.Add(publicIPComponent); 141 | 142 | return componentList; 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/Util/ResourceRateCalc.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalOps.Util 8 | { 9 | using System; 10 | using System.Collections; 11 | using System.Collections.Generic; 12 | using System.Collections.Specialized; 13 | using System.Linq; 14 | using System.Text; 15 | using DataModel; 16 | using Helper; 17 | 18 | /// 19 | /// Class that has static method to fetch the Azure Meters for the Resource components and perform calculation of monthly estimates 20 | /// 21 | public class ResourceRateCalc 22 | { 23 | /// 24 | /// Variable to store the meter list for Azure CSP Rate Card 25 | /// 26 | private static List meterList; 27 | 28 | /// 29 | /// Calculates the monthly estimates for the resource components 30 | /// 31 | /// List of Resource Components 32 | /// Azure Location 33 | /// List of Meters for Azure CSP Rate Card 34 | /// The object that will contain the exception messages 35 | /// Returns the list of resource components with associated meters and monthly estimates 36 | public static List CalculateResourceComponentRates(List components, string location, List meterList, out StringBuilder log) 37 | { 38 | ResourceRateCalc.meterList = meterList; 39 | log = new StringBuilder(string.Empty); 40 | 41 | string locationAsPerPricingSpecs = null; 42 | try 43 | { 44 | // Fetch the Location as per Pricing Specs, Throw exception is cannot be mapped 45 | if (!LocationConstants.LocationAsPerPricingSpecsMap.TryGetValue(location, out locationAsPerPricingSpecs)) 46 | { 47 | throw new Exception(ExceptionLogger.GenerateLoggerTextForInternalError("Location could not be mapped as per pricing specs")); 48 | } 49 | 50 | // Loop thru the list of resource components 51 | foreach (ResourceComponent component in components) 52 | { 53 | // Check if the component is chargeable 54 | if (component.IsChargeable) 55 | { 56 | string meterRegion = locationAsPerPricingSpecs; 57 | 58 | // If Current resource component if for Networking Bandwidth, Set the region to Zone by getting value from mapping, Throw exception is not found 59 | if (NetworkingResourceConstants.NetworkingMeterNameForVMNetwork.Equals(component.MeterName, StringComparison.OrdinalIgnoreCase)) 60 | { 61 | string zone = null; 62 | if (LocationConstants.LocationZoneMap.TryGetValue(locationAsPerPricingSpecs, out zone)) 63 | { 64 | meterRegion = zone; 65 | } 66 | else 67 | { 68 | log.AppendLine(ExceptionLogger.GenerateLoggerTextForInternalError("Location could not be mapped to a networking zone as per pricing specs")); 69 | component.CostPerMonth = 0; 70 | component.Rate = 0; 71 | continue; 72 | } 73 | } 74 | 75 | double rate = 0; 76 | 77 | // Get the Rate and Monthly Cost estimates for the current resource component 78 | component.CostPerMonth = GetResourceRate(component.MeterCategory, component.MeterSubCategory, component.MeterName, meterRegion, component.Quantity, out rate, ref log, component.ResourceName); 79 | component.Rate = rate; 80 | } 81 | else 82 | { 83 | // If component is not chargeable, set to rate and monthly cost to zero 84 | component.CostPerMonth = 0; 85 | component.Rate = 0; 86 | } 87 | } 88 | } 89 | catch (Exception ex) 90 | { 91 | components = null; 92 | log.AppendLine(ex.Message); 93 | } 94 | 95 | return components; 96 | } 97 | 98 | /// 99 | /// Gets the associated Rate and calculates the monthly estimates for the specified Meter details 100 | /// 101 | /// Meter Category of the Meter 102 | /// Meter SubCategory of the Meter 103 | /// Meter Name of the Meter 104 | /// Azure Location as per Pricing Specs 105 | /// Quantity of the resource usage in a month 106 | /// Rate will be set based on the associated meter in CSP Rate Card 107 | /// The object that will contain the exception messages 108 | /// Name of the Azure resource 109 | /// Returns the Monthly Cost for the resource 110 | private static double GetResourceRate(string meterCategory, string meterSubCategory, string meterName, string region, double quantity, out double rate, ref StringBuilder log, string nameOfResource) 111 | { 112 | double totalCost = 0; 113 | rate = 0; 114 | 115 | try 116 | { 117 | // If any meter fields are missing throw an exception 118 | if (meterCategory == null) 119 | { 120 | throw new Exception(ExceptionLogger.GenerateLoggerTextForMeterRateFetchFailed("MeterCategory is null", nameOfResource)); 121 | } 122 | 123 | if (meterSubCategory == null) 124 | { 125 | throw new Exception(ExceptionLogger.GenerateLoggerTextForMeterRateFetchFailed("MeterSubCategory is null", nameOfResource)); 126 | } 127 | 128 | if (meterName == null) 129 | { 130 | throw new Exception(ExceptionLogger.GenerateLoggerTextForMeterRateFetchFailed("MeterName is null", nameOfResource)); 131 | } 132 | 133 | if (region == null) 134 | { 135 | throw new Exception(ExceptionLogger.GenerateLoggerTextForMeterRateFetchFailed("Region is null", nameOfResource)); 136 | } 137 | 138 | // Fetch the rate for the resource component by matching the meter fields provided 139 | Meter ratesForComponent = meterList.Find(x => meterCategory.Equals(x.MeterCategory, StringComparison.OrdinalIgnoreCase) 140 | && meterSubCategory.Equals(x.MeterSubCategory, StringComparison.OrdinalIgnoreCase) 141 | && meterName.Equals(x.MeterName, StringComparison.OrdinalIgnoreCase) 142 | && region.Equals(x.MeterRegion, StringComparison.OrdinalIgnoreCase)); 143 | 144 | // If the Meter is missing in CSP Rate Card, check if there is a global rate (Rate without region specified) 145 | if (ratesForComponent == null) 146 | { 147 | ratesForComponent = meterList.Find(x => meterCategory.Equals(x.MeterCategory, StringComparison.OrdinalIgnoreCase) 148 | && meterSubCategory.Equals(x.MeterSubCategory, StringComparison.OrdinalIgnoreCase) 149 | && meterName.Equals(x.MeterName, StringComparison.OrdinalIgnoreCase) 150 | && x.MeterRegion.Equals(string.Empty, StringComparison.OrdinalIgnoreCase)); 151 | } 152 | 153 | // Check if Meter found 154 | if (ratesForComponent != null) 155 | { 156 | // Fetch the Rates from the meter found 157 | OrderedDictionary meterRates = ratesForComponent.MeterRates; 158 | 159 | // If consumed quantity if less that included quantity, set rate and cost to zero 160 | if (quantity <= ratesForComponent.IncludedQuantity) 161 | { 162 | totalCost = 0; 163 | rate = 0; 164 | } 165 | else if (meterRates.Count == 1) 166 | { 167 | // If linear rating, Calculate Monthly Cost as quantity x rate 168 | rate = (double)meterRates[0]; 169 | totalCost = (quantity - ratesForComponent.IncludedQuantity) * rate; 170 | } 171 | else 172 | { 173 | // If tiered rating, calculate Monthly Cost based on tiered pricing 174 | double quantitytobeRated = quantity - ratesForComponent.IncludedQuantity; 175 | totalCost = 0; 176 | 177 | for (int i = 1; i < meterRates.Count; i++) 178 | { 179 | string currentKeyString = (string)meterRates.Cast().ElementAt(i).Key; 180 | string previousKeyString = (string)meterRates.Cast().ElementAt(i - 1).Key; 181 | double currentKey = double.Parse(currentKeyString); 182 | double previousKey = double.Parse(previousKeyString); 183 | 184 | if (quantitytobeRated <= currentKey) 185 | { 186 | totalCost = totalCost + ((quantitytobeRated - previousKey) * (double)meterRates[i - 1]); 187 | rate = (double)meterRates[i - 1]; 188 | break; 189 | } 190 | else 191 | { 192 | totalCost = totalCost + ((currentKey - previousKey) * (double)meterRates[i - 1]); 193 | if (i == meterRates.Count - 1) 194 | { 195 | totalCost = totalCost + ((quantitytobeRated - currentKey) * (double)meterRates[i]); 196 | rate = (double)meterRates[i]; 197 | } 198 | } 199 | } 200 | } 201 | } 202 | else 203 | { 204 | // Meter for specified parameters not found, Throw an exception 205 | throw new Exception(ExceptionLogger.GenerateLoggerTextForMeterRateFetchFailed(string.Format("Meter not found in Rate Card. MeterCategory:{0},MeterSubCategory:{1},MeterName:{2},Region:{3} ", meterCategory, meterSubCategory, meterName, region), nameOfResource)); 206 | } 207 | } 208 | catch (Exception ex) 209 | { 210 | totalCost = 0; 211 | log.AppendLine(ex.Message); 212 | } 213 | 214 | return totalCost; 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalOps/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/CSPARMPricingCalculatorForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | True 122 | 123 | 124 | True 125 | 126 | 127 | True 128 | 129 | 130 | True 131 | 132 | 133 | True 134 | 135 | 136 | True 137 | 138 | 139 | True 140 | 141 | 142 | 17, 3 143 | 144 | 145 | 292, 3 146 | 147 | 148 | 142, 3 149 | 150 | 151 | 25 152 | 153 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/CSPARMPricingCalculatorUI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {54562219-892A-4BC4-AB4F-E468E11D5D3C} 8 | WinExe 9 | Properties 10 | CSPARMPricingCalUI 11 | CSPARMPricingCalculator 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | CSPARMPricingCalUI.Program 37 | 38 | 39 | 40 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 41 | True 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Form 60 | 61 | 62 | CSPARMPricingCalculatorForm.cs 63 | 64 | 65 | 66 | 67 | 68 | CSPARMPricingCalculatorForm.cs 69 | Designer 70 | 71 | 72 | ResXFileCodeGenerator 73 | Resources.Designer.cs 74 | Designer 75 | 76 | 77 | True 78 | Resources.resx 79 | True 80 | 81 | 82 | 83 | SettingsSingleFileGenerator 84 | Settings.Designer.cs 85 | 86 | 87 | True 88 | Settings.settings 89 | True 90 | 91 | 92 | 93 | 94 | Designer 95 | 96 | 97 | 98 | 99 | {5de96f04-76f7-4dc0-88f5-1fffe0c75477} 100 | CSPARMPricingCalculatorOps 101 | 102 | 103 | 104 | 111 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/Constants.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalUI 8 | { 9 | /// 10 | /// Class that contains constants used in the UI project 11 | /// 12 | public static class Constants 13 | { 14 | /// 15 | /// Key String in app.config for the Partner Center Native App 16 | /// 17 | public const string ConfigSettingsFieldCSPPCNativeAppClientId = "CSP:PCNativeAppClientId"; 18 | 19 | /// 20 | /// Key String in app.config for the Tenant Id of the CSP Partner's Azure AD 21 | /// 22 | public const string ConfigSettingsFieldCSPPartnerTenantID = "CSP:PartnerTenantID"; 23 | 24 | /// 25 | /// Key String in app.config for the App Id of the Native App configured with pre-consent for ARM APIs 26 | /// 27 | public const string ConfigSettingsFieldCSPARMNativeAppClientId = "CSP:ARMNativeAppClientId"; 28 | 29 | /// 30 | /// Key String in app.config for the Tenant Id of the CSP Customer 31 | /// 32 | public const string ConfigSettingsFieldCSPCustomerTenantId = "CSP:CustomerTenantId"; 33 | 34 | /// 35 | /// Key String in app.config for the Subscription Id of the Azure CSP Subscription 36 | /// 37 | public const string ConfigSettingsFieldCSPAzureSubscriptionId = "CSP:AzureSubscriptionId"; 38 | 39 | /// 40 | /// Key String in app.config for the UserName of the Admin Agent user in CSP Partner's Azure AD 41 | /// 42 | public const string ConfigSettingsFieldCSPAdminAgentUserName = "CSP:AdminAgentUserName"; 43 | 44 | /// 45 | /// Key String in app.config for the Password of the Admin Agent user in CSP Partner's Azure AD 46 | /// 47 | public const string ConfigSettingsFieldCSPAdminAgentPassword = "CSP:AdminAgentPassword"; 48 | } 49 | 50 | /// 51 | /// Class that contains Log Message constants used in the UI project 52 | /// 53 | public static class UIMessageConstants 54 | { 55 | /// 56 | /// Message displayed before initiating the Rate Card Fetch - Line 1 57 | /// 58 | public const string RateCardFetchInitiateMsgL1 = "Fetching Ratecard for {0}...\n"; 59 | 60 | /// 61 | /// Message displayed before initiating the Rate Card Fetch - Line 2 62 | /// 63 | public const string RateCardFetchInitiateMsgL2 = "Please be patient. This may take a few minutes...\n"; 64 | 65 | /// 66 | /// Failed Rate Card Fetch Error Message 67 | /// 68 | public const string RateCardFetchFailedMsg = "Error Occured while initiating RateCard Fetch. {0}\n"; 69 | 70 | /// 71 | /// Validation Message - No ARM Template specified 72 | /// 73 | public const string NoARMTemplateProvided = "Browse an ARM Template File to proceed...\n"; 74 | 75 | /// 76 | /// Validation Message - No ARM Template specified 77 | /// 78 | public const string NoDeploymentLocationProvided = "Select a Deployment Location to proceed...\n"; 79 | 80 | /// 81 | /// CSP ARM Pricing Calculation Initiated Message 82 | /// 83 | public const string CSPARMPricingCalculationInitiateMsg = "Calculating for ARM Template: {0} and Location: {1}...\n"; 84 | 85 | /// 86 | /// CSP ARM Pricing Calculation Initiated Message 87 | /// 88 | public const string CSPARMPricingCalculationFailedMsg = "Error Occured while initiating CSP ARM Pricing Calculation. {0}\n"; 89 | 90 | /// 91 | /// CSP ARM Pricing Calculation Progress Message - After ARM Template File and Parameter file read complete 92 | /// 93 | public const string CSPARMPricingCalculationProgressFileReadCompleteMsg = "ARM Template and Param File (if provided) has been read..."; 94 | 95 | /// 96 | /// CSP ARM Pricing Calculation Progress Message - Calculation complete 97 | /// 98 | public const string CSPARMPricingCalculationProgressAllCompleteMsg = "CSP ARM Pricing Calculation Complete..."; 99 | 100 | /// 101 | /// CSP ARM Pricing Calculation Progress Message - Calculation complete 102 | /// 103 | public const string CSPARMPricingCalculationInvalidJSONMsg = "Error Occured: Invalid JSON File, Error Details:{0}"; 104 | 105 | /// 106 | /// Load Config Failed Message 107 | /// 108 | public const string LoadConfigFailedMsg = "Error Occured while fetching config values. {0}\n"; 109 | 110 | /// 111 | /// Error while browsing file path Message 112 | /// 113 | public const string BrowseFailedMsg = "Error Occured. {0}\n"; 114 | 115 | /// 116 | /// Error during background operation Message 117 | /// 118 | public const string BackgroundOperationFailedMsg = "Error Occured. {0}\n"; 119 | 120 | /// 121 | /// Error during background operation Message 122 | /// 123 | public const string BackgroundOperationCancelledMsg = "Operation Cancelled."; 124 | 125 | /// 126 | /// Rate Card Fetch Complete Message 127 | /// 128 | public const string RateCardFetchCompleteMsg = "Rate Card Fetch complete.\n"; 129 | 130 | /// 131 | /// Grid View Showing Results Message 132 | /// 133 | public const string GridShowingResultsMsg = "Displaying Estimated Cost information...\n"; 134 | 135 | /// 136 | /// Total Cost String 137 | /// 138 | public const string TotalCostStringMsg = "Estimated Cost: {0:0.00} {1} /month"; 139 | 140 | /// 141 | /// Error String in Log Messages 142 | /// 143 | public const string ErrorStringToCheck = "ERROR OCCURED"; 144 | 145 | /// 146 | /// Progress Change Message 147 | /// 148 | public const string ProgressChangeMsg = "Current Progress: {0}%, Status: {1}\n"; 149 | 150 | /// 151 | /// Error during Export Results 152 | /// 153 | public const string ExportCSVCompleteMsg = "Export Complete, File: {0}"; 154 | 155 | /// 156 | /// Error during Export Results 157 | /// 158 | public const string ExportCSVFailedMsg = "Error Occured while exporting to CSV File. {0}\n"; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace CSPARMPricingCalUI 8 | { 9 | public static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | public static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new CSPARMPricingCalculatorForm()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("CSPARMPricingCalUI")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("CSPARMPricingCalUI")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("54562219-892a-4bc4-ab4f-e468e11d5d3c")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CSPARMPricingCalUI.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CSPARMPricingCalUI.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CSPARMPricingCalUI.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/Util/FileUtil.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ----------------------------------------------------------------------- 6 | 7 | namespace CSPARMPricingCalUI.Util 8 | { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IO; 12 | using System.Text; 13 | using CSPARMPricingCalOps.DataModel; 14 | using Newtonsoft.Json; 15 | 16 | /// 17 | /// Class that has static method to do file operations including read template and parameter files and write the output to a CSV 18 | /// 19 | public class FileUtil 20 | { 21 | /// 22 | /// Read the ARM Template JSON file and convert to object 23 | /// 24 | /// Path to the file of the ARM Template 25 | /// Deserialized Object of Type ARMTemplate for the ARM Template file 26 | public static ARMTemplate GetResourceList(string armTemplateFilePath) 27 | { 28 | ARMTemplate template; 29 | try 30 | { 31 | // Read the ARM Template file and convert to the template object 32 | using (StreamReader r = new StreamReader(armTemplateFilePath)) 33 | { 34 | string json = r.ReadToEnd(); 35 | template = JsonConvert.DeserializeObject(json); 36 | } 37 | } 38 | catch (Exception) 39 | { 40 | throw; 41 | } 42 | 43 | return template; 44 | } 45 | 46 | /// 47 | /// Read the ARM Parameter JSON file and convert to object 48 | /// 49 | /// Path to the file of the ARM Parameters values 50 | /// Deserialized Object of Type ARMParamValue for the ARM Template file 51 | public static ARMParamValue GetParamValueList(string armParamFilePath) 52 | { 53 | ARMParamValue paramValue = null; 54 | 55 | // Check if filepath null, return null 56 | if (armParamFilePath == null) 57 | { 58 | return null; 59 | } 60 | 61 | try 62 | { 63 | // Read the ARM Parameter value file and convert to the parameter object 64 | using (StreamReader r = new StreamReader(armParamFilePath)) 65 | { 66 | string json = r.ReadToEnd(); 67 | paramValue = JsonConvert.DeserializeObject(json); 68 | } 69 | } 70 | catch (Exception) 71 | { 72 | throw; 73 | } 74 | 75 | return paramValue; 76 | } 77 | 78 | /// 79 | /// Writes the Result of the ARM Pricing Calculation to a file 80 | /// 81 | /// Path to the file 82 | /// Object containing the result of the ARM Pricing Calculation 83 | /// Total Cost 84 | public static void ExportCSPARMPricingToCSV(string fileName, CSPARMPricingInfo cspARMPricingInfoOutput, double totalCost) 85 | { 86 | List cspARMPricingList = cspARMPricingInfoOutput.CSPARMPricingList; 87 | StringBuilder sb = new StringBuilder(); 88 | 89 | // Add header row 90 | string line = "Resource Name,Resource Type,Meter Name,Meter Category,Meter SubCategory,Is Chargeable?,Quantity,Rate,Cost Per Month"; 91 | sb.AppendLine(line); 92 | 93 | // Add Resource Component rows with pricing 94 | for (int i = 0; i < cspARMPricingList.Count; i++) 95 | { 96 | line = string.Format("\"{0}\",{1},\"{2}\",\"{3}\",\"{4}\",{5},{6},{7},{8}", cspARMPricingList[i].ResourceName, cspARMPricingList[i].ResourceType, cspARMPricingList[i].MeterName, cspARMPricingList[i].MeterCategory, cspARMPricingList[i].MeterSubCategory, cspARMPricingList[i].IsChargeable.ToString(), cspARMPricingList[i].Quantity.ToString(), cspARMPricingList[i].Rate, cspARMPricingList[i].CostPerMonth.ToString()); 97 | sb.AppendLine(line); 98 | } 99 | 100 | // Add Total row 101 | line = string.Format("Total Cost:,,,,,,,,{0}", totalCost.ToString()); 102 | sb.AppendLine(line); 103 | 104 | try 105 | { 106 | // Write to File 107 | File.WriteAllText(fileName, sb.ToString()); 108 | } 109 | catch (Exception) 110 | { 111 | throw; 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalUI/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /CSPARMPricingCal/CSPARMPricingCalculator.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSPARMPricingCalculatorUI", "CSPARMPricingCalUI\CSPARMPricingCalculatorUI.csproj", "{54562219-892A-4BC4-AB4F-E468E11D5D3C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSPARMPricingCalculatorOps", "CSPARMPricingCalOps\CSPARMPricingCalculatorOps.csproj", "{5DE96F04-76F7-4DC0-88F5-1FFFE0C75477}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {54562219-892A-4BC4-AB4F-E468E11D5D3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {54562219-892A-4BC4-AB4F-E468E11D5D3C}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {54562219-892A-4BC4-AB4F-E468E11D5D3C}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {54562219-892A-4BC4-AB4F-E468E11D5D3C}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {5DE96F04-76F7-4DC0-88F5-1FFFE0C75477}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {5DE96F04-76F7-4DC0-88F5-1FFFE0C75477}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {5DE96F04-76F7-4DC0-88F5-1FFFE0C75477}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {5DE96F04-76F7-4DC0-88F5-1FFFE0C75477}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /CSPARMPricingCal/TestData/azuredep.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Username for the Virtual Machine." 9 | } 10 | }, 11 | "adminPassword": { 12 | "type": "securestring", 13 | "metadata": { 14 | "description": "Password for the Virtual Machine." 15 | } 16 | }, 17 | "dnsLabelPrefix": { 18 | "type": "string", 19 | "metadata": { 20 | "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." 21 | } 22 | }, 23 | "windowsOSVersion": { 24 | "type": "string", 25 | "defaultValue": "2012-R2-Datacenter", 26 | "allowedValues": [ 27 | "2008-R2-SP1", 28 | "2012-Datacenter", 29 | "2012-R2-Datacenter" 30 | ], 31 | "metadata": { 32 | "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version. Allowed values: 2008-R2-SP1, 2012-Datacenter, 2012-R2-Datacenter." 33 | } 34 | } 35 | }, 36 | "variables": { 37 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'sawinvm')]", 38 | "sizeOfDiskInGB": "100", 39 | "dataDisk1VhdName": "datadisk1", 40 | "location": "[resourceGroup().location]", 41 | "imagePublisher": "MicrosoftWindowsServer", 42 | "imageOffer": "WindowsServer", 43 | "OSDiskName": "osdiskforwindowssimple", 44 | "nicName": "myVMNic", 45 | "addressPrefix": "10.0.0.0/16", 46 | "subnetName": "Subnet", 47 | "subnetPrefix": "10.0.0.0/24", 48 | "storageAccountType": "Standard_LRS", 49 | "publicIPAddressName": "myPublicIP", 50 | "publicIPAddressType": "Dynamic", 51 | "vmStorageAccountContainerName": "vhds", 52 | "vmName": "MyWindowsVM", 53 | "vmSize": "Standard_D1_v2", 54 | "virtualNetworkName": "MyVNET", 55 | "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]", 56 | "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", 57 | "apiVersion": "2015-06-15" 58 | }, 59 | "resources": [ 60 | { 61 | "type": "Microsoft.Storage/storageAccounts", 62 | "name": "[variables('storageAccountName')]", 63 | "apiVersion": "[variables('apiVersion')]", 64 | "location": "[variables('location')]", 65 | "properties": { 66 | "accountType": "[variables('storageAccountType')]" 67 | } 68 | }, 69 | { 70 | "apiVersion": "[variables('apiVersion')]", 71 | "type": "Microsoft.Network/publicIPAddresses", 72 | "name": "[variables('publicIPAddressName')]", 73 | "location": "[variables('location')]", 74 | "properties": { 75 | "publicIPAllocationMethod": "[variables('publicIPAddressType')]", 76 | "dnsSettings": { 77 | "domainNameLabel": "[parameters('dnsLabelPrefix')]" 78 | } 79 | } 80 | }, 81 | { 82 | "apiVersion": "[variables('apiVersion')]", 83 | "type": "Microsoft.Network/virtualNetworks", 84 | "name": "[variables('virtualNetworkName')]", 85 | "location": "[variables('location')]", 86 | "properties": { 87 | "addressSpace": { 88 | "addressPrefixes": [ 89 | "[variables('addressPrefix')]" 90 | ] 91 | }, 92 | "subnets": [ 93 | { 94 | "name": "[variables('subnetName')]", 95 | "properties": { 96 | "addressPrefix": "[variables('subnetPrefix')]" 97 | } 98 | } 99 | ] 100 | } 101 | }, 102 | { 103 | "apiVersion": "[variables('apiVersion')]", 104 | "type": "Microsoft.Network/networkInterfaces", 105 | "name": "[variables('nicName')]", 106 | "location": "[variables('location')]", 107 | "dependsOn": [ 108 | "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", 109 | "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" 110 | ], 111 | "properties": { 112 | "ipConfigurations": [ 113 | { 114 | "name": "ipconfig1", 115 | "properties": { 116 | "privateIPAllocationMethod": "Dynamic", 117 | "publicIPAddress": { 118 | "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" 119 | }, 120 | "subnet": { 121 | "id": "[variables('subnetRef')]" 122 | } 123 | } 124 | } 125 | ] 126 | } 127 | }, 128 | { 129 | "apiVersion": "[variables('apiVersion')]", 130 | "type": "Microsoft.Compute/virtualMachines", 131 | "name": "[variables('vmName')]", 132 | "location": "[variables('location')]", 133 | "dependsOn": [ 134 | "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", 135 | "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" 136 | ], 137 | "properties": { 138 | "hardwareProfile": { 139 | "vmSize": "[variables('vmSize')]" 140 | }, 141 | "osProfile": { 142 | "computerName": "[variables('vmName')]", 143 | "adminUsername": "[parameters('adminUsername')]", 144 | "adminPassword": "[parameters('adminPassword')]" 145 | }, 146 | "storageProfile": { 147 | "imageReference": { 148 | "publisher": "[variables('imagePublisher')]", 149 | "offer": "[variables('imageOffer')]", 150 | "sku": "[parameters('windowsOSVersion')]", 151 | "version": "latest" 152 | }, 153 | "osDisk": { 154 | "name": "osdisk", 155 | "vhd": { 156 | "uri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/',variables('OSDiskName'),'.vhd')]" 157 | }, 158 | "caching": "ReadWrite", 159 | "createOption": "FromImage" 160 | }, 161 | "dataDisks": [ 162 | { 163 | "name": "datadisk1", 164 | "diskSizeGB": "[variables('sizeOfDiskInGB')]", 165 | "lun": 0, 166 | "vhd": { 167 | "uri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/',variables('dataDisk1VhdName'),'.vhd')]" 168 | }, 169 | "createOption": "Empty" 170 | } 171 | ] 172 | }, 173 | "networkProfile": { 174 | "networkInterfaces": [ 175 | { 176 | "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]" 177 | } 178 | ] 179 | }, 180 | "diagnosticsProfile": { 181 | "bootDiagnostics": { 182 | "enabled": "true", 183 | "storageUri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net')]" 184 | } 185 | } 186 | } 187 | } 188 | ] 189 | } 190 | 191 | -------------------------------------------------------------------------------- /CSPARMPricingCal/TestData/azuredeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "value": "user54996" 7 | }, 8 | "adminPassword": { 9 | "value": "zyZW&kU4=?8g" 10 | }, 11 | "dnsLabelPrefix": { 12 | "value": "webservervm54996" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Documentation/app_setup.md: -------------------------------------------------------------------------------- 1 | #App Setup Steps 2 | 3 | 4 | ##1. Introduction 5 | This document explains the steps involved in setting up of an Azure AD Application by a CSP Partner for accessing the ARM APIs to integrate with Azure CSP subscriptions of CSP customers. 6 | An Azure AD Application authentication can be App only or App + User. This document shows the App + User based authentication option. 7 | 8 | ##2. Prerequisites 9 | 10 | * The CSP Partner has already created the Customer and one or more Azure subscriptions for the customer. 11 | * This steps in this document requires a user in CSP Partner’s directory who has access to create application in the partner’s directory. Also, a user who is an Admin Agent is also required. 12 | * A computer with Azure Active Directory PowerShell v2 module installed. 13 | 14 | ##3. Add an Azure AD Native Application 15 | 1. Navigate to the [Azure Management Portal](https://manage.windowsazure.com). Login with user having permissions to create an Azure AD Application. 16 | 17 | 2. Click on ACTIVE DIRECTORY from the menu. Click on the directory from the displayed list. 18 | ![ad_portal](/Documentation/images/app_setup/image1.png) 19 | 20 | 3. Click on APPLICATIONS. Click on ADD icon to create an Azure AD application. 21 | ![apps](/Documentation/images/app_setup/image2.png) 22 | 23 | 4. Click on the link: Add an application my organization is developing. 24 | ![whatToDo](/Documentation/images/app_setup/image3.png) 25 | 26 | 5. Provide a name for the application. Select the NATIVE CLIENT APPLICATION option 27 | ![aboutApp](/Documentation/images/app_setup/image4.png) 28 | 29 | 6. Provide a name for the application. Select the NATIVE CLIENT APPLICATION option 30 | ![appInfo](/Documentation/images/app_setup/image5.png) 31 | 32 | 7. Click on CONFIGURE option 33 | ![configure](/Documentation/images/app_setup/image6.png) 34 | 35 | 8. Scroll down to the section: permissions to other applications. Click on Add application button. 36 | ![permissions](/Documentation/images/app_setup/image7.png) 37 | 38 | 9. Add the Windows Azure Service Management API app. 39 | ![permissions_select](/Documentation/images/app_setup/image8.png) 40 | 41 | 10. Expand the dropdown for the Windows Azure Service Management API application. Tick the “Access Azure Service Management …” option. Click on SAVE icon to save the changes to the application configuration. 42 | ![permissions_select_others](/Documentation/images/app_setup/image9.png) 43 | 44 | 11. Copy the Client ID for the application. This is the App Id of the Azure AD Application which can be used to fetch the Azure AD Token and used to perform the ARM API operations after the completing the remaining steps in this document. 45 | ![configure](/Documentation/images/app_setup/image10.png) 46 | 47 | ##4. Configure Pre-consent for the application 48 | 1. On a computer having Azure Active Directory PowerShell v2 module installed, Open a new PowerShell session. 49 | 50 | 2. Type the following cmdlet to initiate login 51 | ```powershell 52 | Connect-AzureAD 53 | ``` 54 | ![connect-ad](/Documentation/images/app_setup/image11.jpg) 55 | 56 | 3. Login with the user credentials having permissions to obtain information of the created application and also having permissions to add members to Admin Agent groups. 57 | ![connect-ad](/Documentation/images/app_setup/image12.png) 58 | 59 | 4. Type the following cmdlet to view the list of Azure AD groups in the directory 60 | ```powershell 61 | Get-AzureADGroup 62 | ``` 63 | ![connect-adgroup](/Documentation/images/app_setup/image13.png) 64 | *Copy the ObjectId for the AdminAgents group. This will be used in the subsequent steps.* 65 | 66 | 5. Type the following cmdlet to view the ServicePrincipal for the application created earlier. 67 | ```powershell 68 | Get-AzureADServicePrincipal -SearchString "Name of the Azure AD Application here" 69 | ``` 70 | ![connect-adprincipal](/Documentation/images/app_setup/image14.png) 71 | 72 | *Copy the ObjectId for the Serviceprincipal. This will be used in the subsequent step.* 73 | 74 | 6. Run the following cmdlet to configure the pre-consent. 75 | ```powershell 76 | Add-AzureADGroupMember -ObjectId "ObjectId of the AdminAgents Group here" -RefObjectId "ObjectId of the ServicePrincipal" 77 | ``` 78 | 79 | ![connect-adGroupMember](/Documentation/images/app_setup/image15.png) 80 | 81 | ##5. Conclusion 82 | The application created using the previous steps has been configured for pre-consent and can be used for accessing ARM APIs of the CSP Azure subscriptions of the CSP Partner. 83 | 84 | -------------------------------------------------------------------------------- /Documentation/contributing.md: -------------------------------------------------------------------------------- 1 | ##Contributing 2 | 3 | We are thrilled that you'd like to contribute to this project. You help is essential for keep it great. 4 | 5 | This project adheres to the 6 | [Microsoft Open Source Code of Conduct] (https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ] (https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com] (mailto:opencode@microsoft.com) with any additional questions or comments. 7 | By participating, you are expected to uphold this code. -------------------------------------------------------------------------------- /Documentation/deployment.md: -------------------------------------------------------------------------------- 1 | #Deployment Steps 2 | 3 | 1. Install Visual Studio 2015 4 | 5 | 2. Open the CSPARMPricingCalculator.sln file from the code folder 6 | 7 | 3. From the Solution Explorer pane, double click on "App.config" file in the CSPARMPricingCalculatorUI project in the solution. 8 | ![vs](/Documentation/images/deployment/image1.png) 9 | 10 | 4. Observe the appSettings section. The "value" field for the appSettings needs to be provided and will be configured as per the subsequent steps mentioned below. 11 | ![vs](/Documentation/images/deployment/image2.png) 12 | 13 | 5. Login to Partner Center portal 14 | 15 | 6. On the dashboard, select "Account Settings" -> Click on "App Management" 16 | 17 | 7. Under "Native App" section, check if App already created. If not click on "Add new native app" 18 | ![vs](/Documentation/images/deployment/image3.png) 19 | 20 | 8. Copy the values from the "Native App" section on the portal and paste in the appSettings "value" field as per below mapping: 21 | * "App ID" -> "CSP:PCNativeAppClientId" * 22 | * "Account ID" -> "CSP:PartnerTenantID" * 23 | ![vs](/Documentation/images/deployment/image4.png) 24 | ![vs](/Documentation/images/deployment/image5.png) 25 | 26 | 9. Create a Native App in Azure AD for ARM API access with pre-consent setup. To do so follow the step by step guide provided [here](https://github.com/Microsoft/CSPARMPricingCalculator/blob/master/Documentation/app_setup.md) 27 | 28 | 10. Copy the value for the "Client Id" of the Azure AD Application created in previous step and paste in the appSettings "value" field for "CSP:ARMNativeAppClientId" in the app.config file. 29 | ![vs](/Documentation/images/deployment/image6.png) 30 | 31 | 11. Switch back to the Partner Center Portal window. On dashboard, Click on "View Customers" to view the list of customers. 32 | ![vs](/Documentation/images/deployment/image7.png) 33 | 34 | 12. Click on the dropdown arrow adjacent to any customer who has Azure subscription provisioned. 35 | ![vs](/Documentation/images/deployment/image8.png) 36 | 37 | 13. Copy the value for "Microsoft ID" field and paste in the appSettings "value" field for "CSP:CustomerTenantId" in the app.config file. 38 | ![vs](/Documentation/images/deployment/image9.png) 39 | 40 | 14. Click on "View subscriptions" to view the list of subscriptions provisioned for the customer. Click on the dropdown arrow adjacent to any active Azure subscription for the customer. 41 | ![vs](/Documentation/images/deployment/image10.png) 42 | 43 | 15. Copy the value for the "Subscription ID" field and paste in the appSettings "value" field for "CSP: AzureSubscriptionId" in the app.config file. 44 | ![vs](/Documentation/images/deployment/image11.png) 45 | 46 | 16. On the Partner Center dashboard, Click on "Add new user" under the "User Accounts" section. 47 | ![vs](/Documentation/images/deployment/image12.png) 48 | 49 | 17. Provide a name and email for the new user. Click on "Admin Agent" radio button to provide the user Admin Agent role. 50 | ![vs](/Documentation/images/deployment/image13.png) 51 | 52 | 18. Click on "Add" button to create the user. Note the username and temporary password of the new user created. 53 | 54 | 19. Start an "InPrivate browsing" window in Internet Explorer/Edge or "Incognito" window in Chrome. Navigate to https://partnercenter.microsoft.com and login with the user created earlier. Follow the password change page and change the password. 55 | 56 | 20. In the app.config file, provide the value for the username in the appSettings "values" field for "CSP:AdminAgentUserName". 57 | 58 | 21. Provide the value for password of the user created in the previous steps in the appSettings "values" field for "CSP:AdminAgentPassword". Save the changes to the file. 59 | ![vs](/Documentation/images/deployment/image14.png) 60 | 61 | 22. Please remember to remove the Password value after running the sample code, as it is NOT safe to leave password in the config file in unencrypted format. 62 | 63 | 23. Click on Build -> Build Solution. 64 | ![vs](/Documentation/images/deployment/image15.png) 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Documentation/images/app_setup/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image1.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image10.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image11.jpg -------------------------------------------------------------------------------- /Documentation/images/app_setup/image12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image12.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image13.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image14.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image15.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image2.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image3.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image4.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image5.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image6.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image7.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image8.png -------------------------------------------------------------------------------- /Documentation/images/app_setup/image9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/app_setup/image9.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image1.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image10.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image11.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image12.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image13.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image14.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image15.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image2.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image3.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image4.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image5.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image6.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image7.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image8.png -------------------------------------------------------------------------------- /Documentation/images/deployment/image9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CSPARMPricingCalculator/d93d49060debd68773edd95d24a675b014090933/Documentation/images/deployment/image9.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSP – ARM Pricing Calculator 2 | ## Introduction 3 | 4 | The tool can be used to estimate the cost of hosting a solution in an Azure CSP subscription. It takes the ARM Template as an input and gives the estimated costs as an output. It has been built as a sample and currently estimates Virtual machine and its components including Compute hours, Storage, Network, Public IP and Software costs. 5 | 6 | The tool does the following: 7 | 8 | * Fetch the Rate card for Azure CSP 9 | * Read the resources defined in the template 10 | * Map the resources to the appropriate meters and provide cost estimates 11 | * The estimates can then be exported into a csv file. 12 | 13 | The idea is to help CSP partners who are performing integration by providing the tool and source code to assist them to incorporate this feature at their end. 14 | 15 | ## Prerequisites 16 | 17 | The following are the prerequisites for using the CSP ARM Pricing Calculator: 18 | 19 | * The CSP Partner has already created the Customer and one or more Azure subscriptions for the customer. 20 | * A computer with Visual Studio 2015 installed. 21 | * An account that has Admin Agent privileges in the CSP account. 22 | * An account that has Global Admin privileges will be needed during setup and configure of the Azure AD Application 23 | 24 | ## Deployment 25 | Please refer to the [deployment](https://github.com/Microsoft/CSPARMPricingCalculator/blob/master/Documentation/deployment.md) guide 26 | 27 | ## Limitations 28 | It has been built as a sample and currently supports Virtual machine and its components including compute hours, storage, network, public ip and software costs. The source code is provided to enable the CSP Partners to understand the steps and logic involved and may choose to build their own. 29 | It does not support advanced scenarios of ARM templates like nested templates, copy index, etc. 30 | It shows the estimates based on CSP Partner Pricing and does not include pricing of hosting any 3rd party services or margins of the CSP Partner/reseller. 31 | The tool and source code is provided as a sample and no support is provided. 32 | 33 | ## Contributions 34 | 35 | Please refer to [contributing.md](Documentation/contributing.md) 36 | 37 | 38 | ## License 39 | 40 | This project has adopted the [Microsoft Open Source Code of Conduct] (https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ] (https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com] (mailto:opencode@microsoft.com) with any additional questions or comments. 41 | 42 | The MIT License (MIT) 43 | 44 | Copyright (c) 2016 Microsoft 45 | 46 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 47 | 48 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 49 | 50 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 51 | 52 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------