Skip to content

Update Calamari.AzureWebApp to support .NET 6.0 (#1355) #1446

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
366 changes: 196 additions & 170 deletions build/Build.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Calamari.AzureAppService.Json
namespace Calamari.Azure.AppServices
{
public class AppSetting
{
Expand All @@ -14,7 +9,7 @@ public class AppSetting

public bool SlotSetting { get; set; }

internal void Deconstruct(out string name, out string value, out bool isSlotSetting)
public void Deconstruct(out string name, out string value, out bool isSlotSetting)
{
name = Name;
value = Value;
Expand Down Expand Up @@ -50,4 +45,4 @@ public override string ToString()
return $"\nName: {Name}\nValue: {Value}\nIsSlotSetting: {SlotSetting}\n";
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
using System;
#nullable enable
using System;
using Azure.Core;
using Azure.ResourceManager.AppService;
using Calamari.CloudAccounts;
using Calamari.Common.Plumbing.Logging;
using Calamari.Common.Plumbing.Variables;
using Microsoft.Azure.Management.Fluent;

#nullable enable
namespace Calamari.AzureAppService.Azure
namespace Calamari.Azure.AppServices
{
public class AzureTargetSite
{
Expand Down Expand Up @@ -64,12 +68,33 @@ public ResourceIdentifier CreateResourceIdentifier()
? WebSiteSlotResource.CreateResourceIdentifier(SubscriptionId, ResourceGroupName, Site, Slot)
: CreateWebSiteResourceIdentifier();
}

/// <summary>
/// Creates a new <see cref="ResourceIdentifier"/> for the root <see cref="WebSiteSlotResource"/>, even if this is targeting a slot.
/// </summary>
/// <returns></returns>
public ResourceIdentifier CreateWebSiteResourceIdentifier()
=> WebSiteResource.CreateResourceIdentifier(SubscriptionId, ResourceGroupName, Site);

public static AzureTargetSite Create(IAzureAccount account, IVariables variables, ILog? log = null, bool allowEmptyResourceGroupName = false)
{
var resourceGroupName = variables.Get(AzureVariables.Action.Azure.ResourceGroupName);
if (!allowEmptyResourceGroupName && string.IsNullOrEmpty(resourceGroupName))
throw new Exception("resource group name must be specified");
log?.Verbose($"Using Azure Resource Group '{resourceGroupName}'.");

var webAppName = variables.Get(AzureVariables.Action.Azure.WebAppName);
if (string.IsNullOrEmpty(webAppName))
throw new Exception("Web App Name must be specified");
log?.Verbose($"Using App Service Name '{webAppName}'.");

var slotName = variables.Get(AzureVariables.Action.Azure.WebAppSlot);
log?.Verbose(string.IsNullOrEmpty(slotName)
? "No Deployment Slot specified"
: $"Using Deployment Slot '{slotName}'");

return new AzureTargetSite(account.SubscriptionNumber, resourceGroupName, webAppName, slotName);
}
}
}
#nullable restore
#nullable restore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using Azure.ResourceManager.AppService.Models;

namespace Calamari.AzureAppService.Json
namespace Calamari.Azure.AppServices
{
public class ConnectionStringSetting
{
Expand Down Expand Up @@ -49,4 +49,4 @@ public override string ToString()
return $"\nName: {Name}\nValue: {Value}\nType: {Type}\nIsSlotSetting: {SlotSetting}\n";
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
using Calamari.Common.Plumbing.Logging;
using Polly;
using Polly.Retry;
using Polly.Timeout;

namespace Calamari.AzureAppService
namespace Calamari.Azure.AppServices
{
public static class RetryPolicies
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Azure;
using Azure.ResourceManager;
using Azure.ResourceManager.AppService;
using Azure.ResourceManager.AppService.Models;
using Calamari.AzureAppService.Azure;
using Calamari.AzureAppService.Json;
using Calamari.Azure.AppServices;
using Octopus.CoreUtilities.Extensions;

namespace Calamari.AzureAppService
namespace Calamari.Azure
{
///<summary>
/// Provides a set of static methods for interacting with an <see cref="ArmClient"/> using an <see cref="AzureTargetSite"/>.
Expand All @@ -21,6 +21,17 @@ namespace Calamari.AzureAppService
/// </remarks>
public static class ArmClientExtensions
{
public static async Task<WebSiteData> GetWebSiteDataAsync(this ArmClient armClient, AzureTargetSite targetSite)
{
return targetSite.HasSlot switch
{
true => (await armClient.GetWebSiteSlotResource( targetSite.CreateResourceIdentifier())
.GetAsync()).Value.Data,
false => (await armClient.GetWebSiteResource(targetSite.CreateResourceIdentifier())
.GetAsync()).Value.Data
};
}

public static async Task<SiteConfigData> GetSiteConfigDataAsync(this ArmClient armClient, AzureTargetSite targetSite)
{
return targetSite.HasSlot switch
Expand Down Expand Up @@ -213,4 +224,4 @@ await armClient.GetWebSiteResource(targetSite.CreateResourceIdentifier())
}
}
}
}
}
13 changes: 13 additions & 0 deletions source/Calamari.Azure/AzureAccountExtensionMethods.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Calamari.CloudAccounts;
using Calamari.Common.Plumbing.Variables;

namespace Calamari.Azure
{
public static class AzureAccountExtensionMethods
{
public static bool HasAzureAccountJwt(this IVariables variables)
{
return !string.IsNullOrEmpty(variables.Get(AzureAccountVariables.OpenIDJwt));
}
}
}
5 changes: 2 additions & 3 deletions source/Calamari.Azure/AzureClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ public static ArmClient CreateArmClient(this IAzureAccount azureAccount, Action<
return new ArmClient(clientAssertionCreds, defaultSubscriptionId: azureAccount.SubscriptionNumber, clientOptions);
}

string clientSecret;
clientSecret = azureAccount.GetCredentials;
var clientSecret = azureAccount.GetCredentials;

var (armClientOptions, tokenCredentialOptions) = GetArmClientOptions(azureAccount, retryOptionsSetter);
var credential = new ClientSecretCredential(azureAccount.TenantId, azureAccount.ClientId, clientSecret, tokenCredentialOptions);
Expand All @@ -41,7 +40,7 @@ public static (ArmClientOptions, TokenCredentialOptions) GetArmClientOptions(thi
{
var azureKnownEnvironment = new AzureKnownEnvironment(azureAccount.AzureEnvironment);

// Configure a specific transport that will pick up the proxy settings set by Calamari
// Configure the specific transport that will pick up the proxy settings set by Calamari
#pragma warning disable DE0003
var httpClientTransport = new HttpClientTransport(new HttpClientHandler { Proxy = WebRequest.DefaultWebProxy });
#pragma warning restore DE0003
Expand Down
25 changes: 25 additions & 0 deletions source/Calamari.Azure/AzureVariables.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Calamari.Azure
{
public static class AzureVariables
{
public static class Action
{
public static class Azure
{
/// <summary>
/// Expected Values:
/// Package,
/// Container,
/// </summary>
public static readonly string DeploymentType = "Octopus.Action.Azure.DeploymentType";

public static readonly string ResourceGroupName = "Octopus.Action.Azure.ResourceGroupName";
public static readonly string WebAppName = "Octopus.Action.Azure.WebAppName";
public static readonly string WebAppSlot = "Octopus.Action.Azure.DeploymentSlot";
public static readonly string AppSettings = "Octopus.Action.Azure.AppSettings";
public static readonly string ConnectionStrings = "Octopus.Action.Azure.ConnectionStrings";
public static readonly string AsyncZipDeploymentTimeout = "Octopus.Action.Azure.AsyncZipDeploymentTimeout";
}
}
}
}
5 changes: 4 additions & 1 deletion source/Calamari.Azure/Calamari.Azure.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.13.1" />
<PackageReference Include="Azure.ResourceManager" Version="1.11.0" />
<PackageReference Include="Azure.ResourceManager" Version="1.12.0" />
<PackageReference Include="Azure.Identity" Version="1.12.0" />
<PackageReference Include="Azure.ResourceManager" Version="1.12.0" />
<PackageReference Include="Azure.ResourceManager.AppService" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Calamari.CloudAccounts\Calamari.CloudAccounts.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Azure.ResourceManager.AppService.Models;
using Azure.ResourceManager.Resources;
using Calamari.Azure;
using Calamari.Azure.AppServices;
using Calamari.AzureAppService.Azure;
using Calamari.AzureAppService.Json;
using Calamari.CloudAccounts;
Expand Down Expand Up @@ -97,7 +98,8 @@ public async Task Setup()
// We keep them for 14 days just in case we need to do debugging/investigation
["LifetimeInDays"] = "14"
}
});
},
cancellationToken);

ResourceGroupResource = response.Value;

Expand All @@ -110,7 +112,7 @@ public async Task Setup()
public virtual async Task Cleanup()
{
await ArmClient.GetResourceGroupResource(ResourceGroupResource.CreateResourceIdentifier(SubscriptionId, ResourceGroupName))
.DeleteAsync(WaitUntil.Started);
.DeleteAsync(WaitUntil.Started, cancellationToken: cancellationToken);
}

protected async Task AssertContent(string hostName, string actualText, string rootPath = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using Azure;
using Azure.ResourceManager.AppService.Models;
using Azure.ResourceManager.Resources;
using Calamari.Azure;
using Calamari.Azure.AppServices;
using Calamari.AzureAppService.Azure;
using Calamari.AzureAppService.Behaviors;
using Calamari.AzureAppService.Json;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
using Azure.ResourceManager.AppService;
using Azure.ResourceManager.AppService.Models;
using Azure.ResourceManager.Resources;
using Calamari.Azure;
using Calamari.Azure.AppServices;
using Calamari.AzureAppService.Azure;
using Calamari.AzureAppService.Behaviors;
using Calamari.Common.Commands;
using Calamari.Common.Plumbing.Variables;
using Calamari.Testing;
using Calamari.Testing.Helpers;
using FluentAssertions;
using NUnit.Framework;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Azure.ResourceManager;
using Azure.ResourceManager.AppService.Models;
using Calamari.Azure;
using Calamari.Azure.AppServices;
using Calamari.AzureAppService.Azure;
using Calamari.AzureAppService.Json;
using Calamari.CloudAccounts;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Azure.ResourceManager;
using Azure.ResourceManager.AppService;
using Calamari.Azure;
using Calamari.Azure.AppServices;
using Calamari.AzureAppService.Azure;
using Calamari.CloudAccounts;
using Calamari.Common.Commands;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Azure.ResourceManager.AppService;
using Azure.ResourceManager.Resources;
using Calamari.Azure;
using Calamari.Azure.AppServices;
using Calamari.AzureAppService.Azure;
using Calamari.CloudAccounts;
using Calamari.Common.Commands;
Expand Down Expand Up @@ -49,8 +50,7 @@ public async Task Execute(RunningDeployment context)
Log.Verbose("Starting Azure App Service deployment.");

var variables = context.Variables;
var hasJwt = !variables.Get(AccountVariables.Jwt).IsNullOrEmpty();
var account = hasJwt ? (IAzureAccount)new AzureOidcAccount(variables) : new AzureServicePrincipalAccount(variables);
var account = AzureAccountFactory.Create(variables);
Log.Verbose($"Using Azure Tenant '{account.TenantId}'");
Log.Verbose($"Using Azure Subscription '{account.SubscriptionNumber}'");
Log.Verbose($"Using Azure ServicePrincipal AppId/ClientId '{account.ClientId}'");
Expand All @@ -61,23 +61,10 @@ public async Task Execute(RunningDeployment context)
var pollingTimeout = TimeSpan.FromMinutes(pollingTimeoutValue);
var asyncZipDeployTimeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(pollingTimeout, TimeoutStrategy.Optimistic);

string? resourceGroupName = variables.Get(SpecialVariables.Action.Azure.ResourceGroupName);
if (resourceGroupName == null)
throw new Exception("resource group name must be specified");
Log.Verbose($"Using Azure Resource Group '{resourceGroupName}'.");

string? webAppName = variables.Get(SpecialVariables.Action.Azure.WebAppName);
if (webAppName == null)
throw new Exception("Web App Name must be specified");
Log.Verbose($"Using App Service Name '{webAppName}'.");

string? slotName = variables.Get(SpecialVariables.Action.Azure.WebAppSlot);
Log.Verbose(slotName == null
? "No Deployment Slot specified"
: $"Using Deployment Slot '{slotName}'");

var armClient = account.CreateArmClient();
var targetSite = new AzureTargetSite(account.SubscriptionNumber, resourceGroupName, webAppName, slotName);
var targetSite = AzureTargetSite.Create(account, variables, Log);

var resourceGroupName = targetSite.ResourceGroupName;

var resourceGroups = armClient
.GetSubscriptionResource(SubscriptionResource.CreateResourceIdentifier(targetSite.SubscriptionId))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Calamari.Azure;
using Calamari.Azure.AppServices;
using Calamari.AzureAppService.Azure;
using Calamari.CloudAccounts;
using Calamari.Common.Commands;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<TargetFrameworks>net462;net6.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.ResourceManager.AppService" Version="1.0.2" />
<PackageReference Include="Azure.ResourceManager.AppService" Version="1.2.0" />
<PackageReference Include="Azure.ResourceManager.ResourceGraph" Version="1.0.1" />
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
<PackageReference Include="Microsoft.DotNet.Analyzers.Compatibility" Version="0.2.12-alpha">
Expand Down
4 changes: 0 additions & 4 deletions source/Calamari.AzureAppService/Json/SlotSettingsNames.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

/*
* JSON format
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
<PackageReference Include="Microsoft.Identity.Client" Version="4.66.2"/>
<PackageReference Include="Microsoft.Azure.Management.ResourceManager" Version="3.9.0-preview"/>
<PackageReference Include="Azure.Identity" Version="1.13.1" />
<PackageReference Include="Microsoft.Rest.ClientRuntime" Version="2.3.23"/>
<PackageReference Include="Microsoft.Identity.Client" Version="4.65.0" />
<PackageReference Include="Microsoft.Azure.Management.ResourceManager" Version="3.9.0-preview"/>
<PackageReference Include="Azure.Identity" Version="1.12.0" />
<PackageReference Include="Azure.ResourceManager.Resources" Version="1.7.0" />
<PackageReference Include="Microsoft.DotNet.Analyzers.Compatibility" Version="0.2.12-alpha">
<PrivateAssets>all</PrivateAssets>
Expand Down
Loading