Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for filtering subscriptions #140

Merged
merged 1 commit into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Tingle.AzureCleaner.Tests/AzureCleanerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class ModifiedAzureCleaner(IMemoryCache cache, IOptions<AzureCleanerOptions> opt
public List<IReadOnlyCollection<string>> DeleteAzureResourcesAsyncCalls { get; } = [];
public List<(AzdoProjectUrl url, string? token, IReadOnlyCollection<string> possibleNames)> DeleteReviewAppsEnvironmentsAsyncCalls { get; } = [];

protected override Task DeleteAzureResourcesAsync(IReadOnlyCollection<string> possibleNames, CancellationToken cancellationToken = default)
protected override Task DeleteAzureResourcesAsync(IReadOnlyCollection<string> possibleNames, IReadOnlyCollection<string> subscriptionIdsOrNames, CancellationToken cancellationToken = default)
{
DeleteAzureResourcesAsyncCalls.Add(possibleNames);
return Task.CompletedTask;
Expand Down
2 changes: 1 addition & 1 deletion Tingle.AzureCleaner.Tests/EndpointTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class ModifiedAzureCleaner(IMemoryCache cache, IOptions<AzureCleanerOptions> opt
public List<IReadOnlyCollection<string>> DeleteAzureResourcesAsyncCalls { get; } = [];
public List<(AzdoProjectUrl url, string? token, IReadOnlyCollection<string> possibleNames)> DeleteReviewAppsEnvironmentsAsyncCalls { get; } = [];

protected override Task DeleteAzureResourcesAsync(IReadOnlyCollection<string> possibleNames, CancellationToken cancellationToken = default)
protected override Task DeleteAzureResourcesAsync(IReadOnlyCollection<string> possibleNames, IReadOnlyCollection<string> subscriptionIdsOrNames, CancellationToken cancellationToken = default)
{
DeleteAzureResourcesAsyncCalls.Add(possibleNames);
return Task.CompletedTask;
Expand Down
3 changes: 1 addition & 2 deletions Tingle.AzureCleaner/AzdoCleanupEvent.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Tingle.AzureCleaner;
using Tingle.EventBus;
using Tingle.EventBus;

namespace Tingle.AzureCleaner;

Expand Down
26 changes: 23 additions & 3 deletions Tingle.AzureCleaner/AzureCleaner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ public AzureCleaner(IMemoryCache cache, IOptions<AzureCleanerOptions> options, I
azdoProjects = this.options.AzdoProjects.Select(e => e.Split(";")).ToDictionary(s => s[0], s => s[1]);
}

public virtual async Task HandleAsync(int prId, string? remoteUrl = null, string? rawProjectUrl = null, CancellationToken cancellationToken = default)
public virtual async Task HandleAsync(int prId,
IReadOnlyCollection<string>? subscriptionIdsOrNames = null,
string? remoteUrl = null,
string? rawProjectUrl = null,
CancellationToken cancellationToken = default)
{
var possibleNames = MakePossibleNames([prId]);

Expand All @@ -60,7 +64,8 @@ public virtual async Task HandleAsync(int prId, string? remoteUrl = null, string
}
}

await DeleteAzureResourcesAsync(possibleNames, cancellationToken);
subscriptionIdsOrNames ??= options.Subscriptions;
await DeleteAzureResourcesAsync(possibleNames: possibleNames, subscriptionIdsOrNames: subscriptionIdsOrNames, cancellationToken: cancellationToken);
}

internal virtual bool TryFindAzdoProject(string? rawUrl, out AzdoProjectUrl url, [NotNullWhen(true)] out string? token)
Expand All @@ -73,7 +78,7 @@ internal virtual bool TryFindAzdoProject(string? rawUrl, out AzdoProjectUrl url,
return azdoProjects.TryGetValue(url, out token);
}

protected virtual async Task DeleteAzureResourcesAsync(IReadOnlyCollection<string> possibleNames, CancellationToken cancellationToken = default)
protected virtual async Task DeleteAzureResourcesAsync(IReadOnlyCollection<string> possibleNames, IReadOnlyCollection<string> subscriptionIdsOrNames, CancellationToken cancellationToken = default)
{
var credential = new DefaultAzureCredential();
var client = new ArmClient(credential);
Expand All @@ -82,6 +87,15 @@ protected virtual async Task DeleteAzureResourcesAsync(IReadOnlyCollection<strin
var subscriptions = client.GetSubscriptions().GetAllAsync(cancellationToken);
await foreach (var sub in subscriptions)
{
// if we have a list of subscriptions to check, skip the ones not in the list
if (subscriptionIdsOrNames.Count > 0
&& !subscriptionIdsOrNames.Contains(sub.Data.SubscriptionId, StringComparer.OrdinalIgnoreCase)
&& !subscriptionIdsOrNames.Contains(sub.Data.DisplayName, StringComparer.OrdinalIgnoreCase))
{
logger.LogDebug("Skipping subscription '{SubscriptionName} ({SubscriptionId})' ...", sub.Data.DisplayName, sub.Data.SubscriptionId);
continue;
}

logger.LogDebug("Searching in subscription '{SubscriptionName} ({SubscriptionId})' ...", sub.Data.DisplayName, sub.Data.SubscriptionId);

// resource group is deleted first to avoid repetition on dependent resources, it makes it easier
Expand Down Expand Up @@ -867,6 +881,12 @@ public class AzureCleanerOptions
{
public List<string> AzdoProjects { get; set; } = [];

/// <summary>
/// Name or ID of subscriptions allowed.
/// If none are provided, all subscriptions are checked.
/// </summary>
public List<string> Subscriptions { get; set; } = [];

public bool AzureResourceGroups { get; set; } = true;
public bool AzureKubernetes { get; set; } = true;
public bool AzureWebsites { get; set; } = true;
Expand Down
10 changes: 7 additions & 3 deletions Tingle.AzureCleaner/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@
{
var root = new RootCommand("Cleanup tool for Azure resources based on Azure DevOps PRs")
{
new Option<int>(["-p", "--pr", "--pull-request-id"], "Identifier of the pull request.") { IsRequired = true, },
new Option<int>(["-p", "--pr", "--pull-request", "--pull-request-id"], "Identifier of the pull request.") { IsRequired = true, },
new Option<string[]>(["-s", "--subscription"], "Name or ID of subscriptions allowed. If none are provided, all subscriptions are checked."),
new Option<string?>(["--remote", "--remote-url"], "Remote URL of the Azure DevOps repository."),
new Option<string?>(["--project", "--project-url"], "Project URL. Overrides the remote URL when provided."),
};
root.Handler = CommandHandler.Create(async (IHost host, int pullRequestId, string? remoteUrl, string? projectUrl) =>
root.Handler = CommandHandler.Create(async (IHost host, int pullRequestId, string[] subscription, string? remoteUrl, string? projectUrl) =>
{
var cleaner = host.Services.GetRequiredService<AzureCleaner>();
await cleaner.HandleAsync(prId: pullRequestId, remoteUrl: remoteUrl, rawProjectUrl: projectUrl);
await cleaner.HandleAsync(prId: pullRequestId,
subscriptionIdsOrNames: subscription,
remoteUrl: remoteUrl,
rawProjectUrl: projectUrl);
});

var clb = new CommandLineBuilder(root)
Expand Down
2 changes: 1 addition & 1 deletion Tingle.AzureCleaner/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"profiles": {
"Tingle.AzureCleaner": {
"commandName": "Project",
//"commandLineArgs": "Tingle.AzureCleaner --pr 12",
//"commandLineArgs": "Tingle.AzureCleaner --pr 3 --subscription DEPENDABOT",
"launchBrowser": true,
"launchUrl": "health",
"environmentVariables": {
Expand Down