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

Fuction App Flex Consumption publish support #2688

Closed
Closed
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
DeploymentPassword="$(Password)"
SiteName="$(DeployIisAppPath)"
PublishUrl="$(PublishUrl)"
UserAgentVersion="$(ZipDeployUserAgent)"/>
UserAgentVersion="$(ZipDeployUserAgent)"
UseBlobContainerDeploy="$(UseBlobContainerDeploy)"/>
</Target>

</Project>
1 change: 1 addition & 0 deletions sdk/Sdk/Tasks/ZipDeploy/StringMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
public static class StringMessages
{
public const string DeploymentStatus = "Deployment status is {0}.";
public const string DeploymentStatusWithText = "Deployment status is {0}: {1}";
public const string DeploymentStatusPolling = "Polling for deployment status...";
public const string NeitherSiteNameNorPublishUrlGivenError = "Neither SiteName nor PublishUrl was given a value.";
public const string PublishingZipViaZipDeploy = "Publishing {0} to {1}...";
Expand Down
20 changes: 16 additions & 4 deletions sdk/Sdk/Tasks/ZipDeploy/ZipDeployTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class ZipDeployTask : Task

public string? PublishUrl { get; set; }

public bool UseBlobContainerDeploy { get; set; }

/// <summary>
/// Our fallback if PublishUrl is not given, which is the case for ZIP Deploy profiles created prior to 15.8 Preview 4.
Expand All @@ -52,13 +53,18 @@ public override bool Execute()
{
using (DefaultHttpClient client = new DefaultHttpClient())
{
System.Threading.Tasks.Task<bool> t = ZipDeployAsync(ZipToPublishPath!, DeploymentUsername!, DeploymentPassword!, PublishUrl, SiteName!, UserAgentVersion!, client, true);
System.Threading.Tasks.Task<bool> t = ZipDeployAsync(ZipToPublishPath!, DeploymentUsername!, DeploymentPassword!, PublishUrl, SiteName!, UserAgentVersion!, UseBlobContainerDeploy, client, true);
t.Wait();
return t.Result;
}
}

internal async System.Threading.Tasks.Task<bool> ZipDeployAsync(string zipToPublishPath, string userName, string password, string? publishUrl, string siteName, string userAgentVersion, IHttpClient client, bool logMessages)
internal System.Threading.Tasks.Task<bool> ZipDeployAsync(string zipToPublishPath, string userName, string password, string publishUrl, string siteName, string userAgentVersion, IHttpClient client, bool logMessages)
{
return ZipDeployAsync(zipToPublishPath, userName, password, publishUrl, siteName, userAgentVersion, useBlobContainerDeploy: false, client, logMessages);
}

internal async System.Threading.Tasks.Task<bool> ZipDeployAsync(string zipToPublishPath, string userName, string password, string? publishUrl, string siteName, string userAgentVersion, bool useBlobContainerDeploy, IHttpClient client, bool logMessages)
{
if (!File.Exists(zipToPublishPath) || client == null)
{
Expand All @@ -73,11 +79,11 @@ internal async System.Threading.Tasks.Task<bool> ZipDeployAsync(string zipToPubl
publishUrl += "/";
}

zipDeployPublishUrl = publishUrl + "api/zipdeploy";
zipDeployPublishUrl = publishUrl + "api";
}
else if (!string.IsNullOrEmpty(siteName))
{
zipDeployPublishUrl = $"https://{siteName}.scm.azurewebsites.net/api/zipdeploy";
zipDeployPublishUrl = $"https://{siteName}.scm.azurewebsites.net/api";
}
else
{
Expand All @@ -89,6 +95,12 @@ internal async System.Threading.Tasks.Task<bool> ZipDeployAsync(string zipToPubl
return false;
}

// publish endpoint differs when using a blob storage container
var publishUriPath = useBlobContainerDeploy ? "publish" : "zipdeploy";
anvillan marked this conversation as resolved.
Show resolved Hide resolved

// "<publishUrl>/api/zipdeploy" or "<publishUrl>/api/publish"
zipDeployPublishUrl = $"{zipDeployPublishUrl}/{publishUriPath}";

if (logMessages)
{
Log.LogMessage(MessageImportance.High, String.Format(StringMessages.PublishingZipViaZipDeploy, zipToPublishPath, zipDeployPublishUrl));
Expand Down
50 changes: 41 additions & 9 deletions sdk/Sdk/Tasks/ZipDeploy/ZipDeploymentStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -43,7 +41,8 @@ public ZipDeploymentStatus(IHttpClient client, string userAgent, TaskLoggingHelp

public async Task<DeployStatus> PollDeploymentStatusAsync(string deploymentUrl, string userName, string password)
{
DeployStatus deployStatus = DeployStatus.Pending;
var deployStatus = DeployStatus.Pending;
var deployStatusText = string.Empty;
var tokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(MaxMinutesToWait));

if (_logMessages)
Expand All @@ -54,10 +53,16 @@ public async Task<DeployStatus> PollDeploymentStatusAsync(string deploymentUrl,
{
anvillan marked this conversation as resolved.
Show resolved Hide resolved
try
{
deployStatus = await GetDeploymentStatusAsync(deploymentUrl, userName, password, RetryCount, TimeSpan.FromSeconds(RetryDelaySeconds), tokenSource);
(deployStatus, deployStatusText) = await GetDeploymentStatusAsync(deploymentUrl, userName, password, RetryCount, TimeSpan.FromSeconds(RetryDelaySeconds), tokenSource);
if (_logMessages)
{
_log.LogMessage(String.Format(StringMessages.DeploymentStatus, Enum.GetName(typeof(DeployStatus), deployStatus)));
var deployStatusName = Enum.GetName(typeof(DeployStatus), deployStatus);

var message = string.IsNullOrEmpty(deployStatusText)
? string.Format(StringMessages.DeploymentStatus, deployStatusName)
: string.Format(StringMessages.DeploymentStatusWithText, deployStatusName, deployStatusText);

_log.LogMessage(message);
}
}
catch (HttpRequestException)
Expand All @@ -71,16 +76,29 @@ public async Task<DeployStatus> PollDeploymentStatusAsync(string deploymentUrl,
return deployStatus;
}

private async Task<DeployStatus> GetDeploymentStatusAsync(string deploymentUrl, string userName, string password, int retryCount, TimeSpan retryDelay, CancellationTokenSource cts)
private async Task<(DeployStatus, string)> GetDeploymentStatusAsync(string deploymentUrl, string userName, string password, int retryCount, TimeSpan retryDelay, CancellationTokenSource cts)
{
var status = DeployStatus.Unknown;
var statusText = string.Empty;

IDictionary<string, object>? json = await InvokeGetRequestWithRetryAsync<Dictionary<string, object>>(deploymentUrl, userName, password, retryCount, retryDelay, cts);

if (json != null && TryParseDeploymentStatus(json, out DeployStatus result))
if (json is not null)
{
return result;
// status
if (TryParseDeploymentStatus(json, out DeployStatus result))
{
status = result;
}

// status text message
if (TryParseDeploymentStatusText(json, out string text))
{
statusText = text;
}
}

return DeployStatus.Unknown;
return (status, statusText);
}

private static bool TryParseDeploymentStatus(IDictionary<string, object> json, out DeployStatus status)
Expand All @@ -97,6 +115,20 @@ private static bool TryParseDeploymentStatus(IDictionary<string, object> json, o
return false;
}

private static bool TryParseDeploymentStatusText(IDictionary<string, object> json, out string statusText)
{
statusText = string.Empty;

if (json.TryGetValue("status_text", out var textObj)
&& textObj is not null)
{
statusText = textObj.ToString();
return true;
}

return false;
}

private async Task<T?> InvokeGetRequestWithRetryAsync<T>(string url, string userName, string password, int retryCount, TimeSpan retryDelay, CancellationTokenSource cts)
{
IHttpResponse? response = null;
Expand Down
4 changes: 4 additions & 0 deletions sdk/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

- Fix incorrect function version in build message (#2606)

- Add support to publish a Function App (Flex Consumption) with `ZipDeploy` (#2688)
- Add `'UseBlobContainerDeploy'` property to identify when to use `OneDeploy` publish API endpoint (`"<publish_url>/api/publish"`)
- Enhance `ZipDeploy` deployment status logging by appending the `'status_message'` (when defined) to the output messages

- <entry>

### Microsoft.Azure.Functions.Worker.Sdk.Generators <version>
Expand Down