public IWebApp GetOrCreateWebsite(string subscriptionId, string resourceGroupName, string appName, string regionName, string planName, bool allowAutomaticRename) { var resourceGroup = GetOrCreateResourceGroup(subscriptionId, resourceGroupName, regionName); var webApp = GetWebsite(subscriptionId, resourceGroupName, appName); if (webApp == null) { IAppServicePlan plan; if (string.IsNullOrEmpty(planName)) { planName = $"Catapult-Apps-{Guid.NewGuid()}"; _logger.LogInformation($"Creating new plan name {planName} in resource group {resourceGroupName}"); plan = ExecuteWithRetry(() => _authenticatedAzure.WithSubscription(subscriptionId).AppServices.AppServicePlans .Define(planName) .WithRegion(resourceGroup.Region) .WithExistingResourceGroup(resourceGroup) .WithFreePricingTier() .Create()); } else { plan = ExecuteWithRetry(() => _authenticatedAzure.WithSubscription(subscriptionId).AppServices.AppServicePlans.GetByResourceGroup(resourceGroupName, planName)); } if (plan != null) { webApp = CreateWebsite(subscriptionId, appName, resourceGroupName, plan, allowAutomaticRename); } else { throw new ArgumentException($"Plan {planName} is not found in resource group {resourceGroupName}"); } } return(webApp); }
public void Init(ISubscription subscription) { _azure = _authenticated .WithSubscription(subscription.SubscriptionId); }
private static async Task Run() { string subscriptionIds = ConfigurationManager.AppSettings["subscriptionIds"]; string ownerTagName = ConfigurationManager.AppSettings["ownerTagName"]; string startDate = DateTime.Now.ToUniversalTime().AddDays(-30).ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); string endDate = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); string clientId = ConfigurationManager.AppSettings["clientId"]; string clientSecret = ConfigurationManager.AppSettings["clientSecret"]; string tenantId = ConfigurationManager.AppSettings["tenantId"]; AzureCredentialsFactory factory = new AzureCredentialsFactory(); AzureCredentials azureCreds = factory.FromServicePrincipal(clientId, clientSecret, tenantId, AzureEnvironment.AzureGlobalCloud); Azure.IAuthenticated azure = Azure.Configure().Authenticate(azureCreds); string body = @" { ""type"": ""Usage"", ""timeframe"": ""Custom"", ""timePeriod"": { ""from"": """ + startDate + @""", ""to"": """ + endDate + @""", }, ""dataset"": { ""granularity"": ""Daily"", ""aggregation"": { ""totalCost"": { ""name"": ""PreTaxCost"", ""function"": ""Sum"" } }, ""grouping"": [ { ""type"": ""Dimension"", ""name"": ""ResourceGroup"" } ] } } "; string currency = String.Empty; Dictionary <string, Double> costPerUser = new Dictionary <string, Double>(); Dictionary <string, Double> costPerGroup = new Dictionary <string, Double>(); Dictionary <string, string> groupOwner = new Dictionary <string, string>(); string token = await GetOAuthTokenFromAAD(); foreach (var subscriptionId in subscriptionIds.Split(",", StringSplitOptions.RemoveEmptyEntries)) { var azureSub = azure.WithSubscription(subscriptionId); var resourceGroups = azureSub.ResourceGroups.List(); string uri = $"https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.CostManagement/query?api-version=2019-01-01"; while (!String.IsNullOrEmpty(uri)) { QueryResult result = null; int costIndex = -1; int currencyIndex = -1; int groupIndex = -1; var request = HttpWebRequest.CreateHttp(uri); request.ContentType = "application/json"; request.Method = "POST"; request.Headers.Add("Authorization", $"Bearer {token}"); try { using (StreamWriter writer = new StreamWriter(request.GetRequestStream())) { writer.Write(body); writer.Flush(); } var response = await request.GetResponseAsync(); var responseString = String.Empty; using (StreamReader reader = new StreamReader(response.GetResponseStream())) { responseString = reader.ReadToEnd(); } result = JsonConvert.DeserializeObject <QueryResult>(responseString); uri = result.properties.nextLink; costIndex = GetColumnIndex(result.properties.columns, "PreTaxCost"); currencyIndex = GetColumnIndex(result.properties.columns, "Currency"); groupIndex = GetColumnIndex(result.properties.columns, "ResourceGroup"); if (costIndex < 0) { Console.WriteLine($"Could not find cost index for subscription {subscriptionId}"); continue; } } catch (WebException wex) { string errorMessage = string.Empty; if (wex.Response != null) { using (StreamReader reader = new StreamReader(wex.Response.GetResponseStream())) { errorMessage = reader.ReadToEnd(); } } Console.WriteLine($"Error while calculating costs for subscription {subscriptionId}: {wex} ({errorMessage})"); } catch (Exception ex) { Console.WriteLine($"Error while calculating costs for subscription {subscriptionId}: {ex}"); } if (result != null) { foreach (var group in resourceGroups) { var resourceGroupOwner = OWNER_UNKNOWN; var defaultKeyValuePair = default(KeyValuePair <String, String>); var ownerTag = defaultKeyValuePair; if (group.Tags != null) { ownerTag = group.Tags.Where(tag => tag.Key.Equals(ownerTagName, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); } if (!ownerTag.Equals(defaultKeyValuePair)) { resourceGroupOwner = ownerTag.Value; } //Console.WriteLine($"Calculating costs for resource group {group.Name} in subscription {subscriptionId} which belongs to {resourceGroupOwner}"); string keyNameGroup = $"{subscriptionId}/{group.Name}"; if (!costPerUser.ContainsKey(resourceGroupOwner)) { costPerUser.Add(resourceGroupOwner, 0); } if (!costPerGroup.ContainsKey(keyNameGroup)) { costPerGroup.Add(keyNameGroup, 0); } if (!groupOwner.ContainsKey(keyNameGroup)) { groupOwner.Add(keyNameGroup, resourceGroupOwner); } var groupRows = result.properties.rows.Where(rTemp => rTemp[groupIndex].ToString().Equals(group.Name, StringComparison.InvariantCultureIgnoreCase)).ToArray(); foreach (var row in groupRows) { costPerUser[resourceGroupOwner] += (Double)row[costIndex]; costPerGroup[keyNameGroup] += (Double)row[costIndex]; var currencyOfRow = (string)row[currencyIndex]; if (String.IsNullOrEmpty(currency)) { currency = currencyOfRow; } else if (!currency.Equals(currencyOfRow)) { throw new Exception("There are different currencies"); } } } } } Console.WriteLine($"##########################################"); Console.WriteLine($"Cost between {startDate} and {endDate} per resource group for unknown owner"); Console.WriteLine($"##########################################"); var subscriptionRgUnknown = costPerGroup.Where(temp => temp.Key.Split("/")[0]. Equals(subscriptionId, StringComparison.InvariantCultureIgnoreCase)); foreach (KeyValuePair <string, double> costEntry in subscriptionRgUnknown.OrderByDescending(temp => temp.Value)) { if (groupOwner[costEntry.Key].Equals(OWNER_UNKNOWN, StringComparison.InvariantCultureIgnoreCase)) { Console.WriteLine($"{costEntry.Key}: {currency} {costEntry.Value}"); } } } Console.WriteLine($"##########################################"); Console.WriteLine($"Cost between {startDate} and {endDate} per user"); Console.WriteLine($"##########################################"); foreach (KeyValuePair <string, double> costEntry in costPerUser.OrderByDescending(temp => temp.Value)) { Console.WriteLine($"{costEntry.Key}: {currency} {costEntry.Value}"); } Console.WriteLine($"##########################################"); Console.WriteLine($"Cost between {startDate} and {endDate} per resource group"); Console.WriteLine($"##########################################"); foreach (KeyValuePair <string, double> costEntry in costPerGroup.OrderByDescending(temp => temp.Value)) { Console.WriteLine($"{costEntry.Key}: {currency} {costEntry.Value} (owner: {groupOwner[costEntry.Key]})"); } }
public static async Task Run() { string tag_owner = GetConfigItem("tag_owner"); string tag_deallocate = GetConfigItem("tag_deallocate"); int tag_deallocate_days = int.Parse(GetConfigItem("tag_deallocate_days")); string tag_deletevm = GetConfigItem("tag_deletevm"); int tag_deletevm_days = int.Parse(GetConfigItem("tag_deletevm_days")); string tag_deleterg = GetConfigItem("tag_deleterg"); int tag_deleterg_days = int.Parse(GetConfigItem("tag_deleterg_days")); string subscriptionIds = GetConfigItem("subscriptionIds"); string clientId = GetConfigItem("clientId"); string clientSecret = GetConfigItem("clientSecret"); string tenantId = GetConfigItem("tenantId"); AzureCredentialsFactory factory = new AzureCredentialsFactory(); AzureCredentials azureCreds = factory.FromServicePrincipal(clientId, clientSecret, tenantId, AzureEnvironment.AzureGlobalCloud); Azure.IAuthenticated azure = Azure.Configure().Authenticate(azureCreds); foreach (var subscriptionId in subscriptionIds.Split(",", StringSplitOptions.RemoveEmptyEntries)) { Console.WriteLine($"Looking for new resources without an owner tag in subscription {subscriptionId}"); var azureSub = azure.WithSubscription(subscriptionId); var insightsClient = new InsightsClient(azureCreds); insightsClient.SubscriptionId = subscriptionId; var resourceGroups = azureSub.ResourceGroups.List(); foreach (var group in resourceGroups) { try { var defaultKeyValuePair = default(KeyValuePair <String, String>); var ownerTag = defaultKeyValuePair; if (group.Tags != null) { ownerTag = group.Tags.Where(tag => tag.Key.Equals(tag_owner, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); } String endTime = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); String resourceId = group.Id; if (ownerTag.Equals(defaultKeyValuePair)) { //Console.WriteLine($"Resource group {group.Name} does not contain owner tag...looking in activity log"); String startTime = DateTime.Now.ToUniversalTime().AddHours(-25).ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); string newOwner = UNKNOWN_OWNER; var resourceGroupCreateLogs = await GetCreationLogs(startTime, endTime, resourceId, OPERATION_RESOURCEGROUP_WRITE, insightsClient); if (resourceGroupCreateLogs.Length == 0) { startTime = DateTime.Now.ToUniversalTime().AddDays(-90).ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); resourceGroupCreateLogs = await GetCreationLogs(startTime, endTime, resourceId, OPERATION_RESOURCEGROUP_WRITE, insightsClient); } if (resourceGroupCreateLogs.Length != 0) { newOwner = resourceGroupCreateLogs[0].Caller; } if (!UNKNOWN_OWNER.Equals(newOwner)) { await group.Update().WithTag(tag_owner, newOwner).ApplyAsync(); Console.WriteLine($"Resource group {group.Name} tagged with owner {newOwner}"); } } else if (UNKNOWN_OWNER.Equals(ownerTag.Value)) { bool needsUpdate = false; var updateGroup = group.Update(); if (group.Tags.Where(tag => tag.Key.Equals(tag_deallocate, StringComparison.InvariantCultureIgnoreCase)).Count() == 0) { needsUpdate = true; updateGroup.WithTag(tag_deallocate, DateTime.Now.ToUniversalTime().AddDays(tag_deallocate_days).ToString("yyyy-MM-ddTHH:mm:ss.fffZ")); } if (group.Tags.Where(tag => tag.Key.Equals(tag_deletevm, StringComparison.InvariantCultureIgnoreCase)).Count() == 0) { needsUpdate = true; updateGroup.WithTag(tag_deletevm, DateTime.Now.ToUniversalTime().AddDays(tag_deletevm_days).ToString("yyyy-MM-ddTHH:mm:ss.fffZ")); } if (group.Tags.Where(tag => tag.Key.Equals(tag_deleterg, StringComparison.InvariantCultureIgnoreCase)).Count() == 0) { needsUpdate = true; updateGroup.WithTag(tag_deleterg, DateTime.Now.ToUniversalTime().AddDays(tag_deleterg_days).ToString("yyyy-MM-ddTHH:mm:ss.fffZ")); } if (needsUpdate) { await updateGroup.ApplyAsync(); } } else { //Console.WriteLine($"Resource group {group.Name} is already owned by {ownerTag.Value}"); } } catch (Exception ex) { Console.WriteLine("Exception: " + ex); } } } Console.WriteLine("Done Tagging"); }