Skip to content

Commit

Permalink
[K8SE] Add BetaMetadata options for 'feature/k8se' (#136)
Browse files Browse the repository at this point in the history
* Modified buildversion to have build metadata json

* Minor fix to json patch

* Override scheme to https if running in K8SE Environment

* Implement API App Update for DevOps Deployment Scenario

* Added build headers for k8se

* Fix in site builder for repo path for zip deploy
  • Loading branch information
sanchitmehta authored Sep 30, 2020
1 parent 6d9a031 commit 1d20b32
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 26 deletions.
19 changes: 19 additions & 0 deletions Kudu.Contracts/Deployment/BuildMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;

namespace Kudu.Contracts.Deployment
{
public class BuildMetadata
{
[JsonProperty(PropertyName = "appName")]
public string AppName;

[JsonProperty(PropertyName = "buildVersion")]
public string BuildVersion;

[JsonProperty(PropertyName = "appSubPath")]
public string AppSubPath;
}
}
3 changes: 3 additions & 0 deletions Kudu.Contracts/Deployment/DeploymentInfoBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,8 @@ public bool IsValid()
// won't update until after a process restart. Therefore, we copy the needed
// files into a separate folders and run sync triggers from there.
public string SyncFunctionsTriggersPath { get; set; } = null;

// Used to set Publish Endpoint context
public bool ShouldBuildArtifact { get; set; }
}
}
5 changes: 2 additions & 3 deletions Kudu.Core/Deployment/DeploymentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using Kudu.Contracts.Infrastructure;
using Kudu.Contracts.Settings;
using Kudu.Contracts.Tracing;
using Kudu.Core.Functions;
using Kudu.Core.Helpers;
using Kudu.Core.Hooks;
using Kudu.Core.Infrastructure;
Expand Down Expand Up @@ -286,7 +285,7 @@ public async Task DeployAsync(
}

string appName = _environment.SiteRootPath.Replace("/home/apps/", "").Split("/")[0];
DockerContainerRestartTrigger.RequestContainerRestart(_environment, RestartTriggerReason, deploymentInfo.RepositoryUrl);
DockerContainerRestartTrigger.RequestContainerRestart(_environment, RestartTriggerReason, deploymentInfo.RepositoryUrl, deploymentInfo.TargetPath);
logger.Log($"Deployment Pod Rollout Started! Use kubectl watch deplotment {appName} to monitor the rollout status");
}
}
Expand Down Expand Up @@ -645,7 +644,7 @@ private async Task Build(
{
using (tracer.Step("Determining deployment builder"))
{
builder = _builderFactory.CreateBuilder(tracer, innerLogger, perDeploymentSettings, repository);
builder = _builderFactory.CreateBuilder(tracer, innerLogger, perDeploymentSettings, repository, deploymentInfo);
deploymentAnalytics.ProjectType = builder.ProjectType;
tracer.Trace("Builder is {0}", builder.GetType().Name);
}
Expand Down
8 changes: 8 additions & 0 deletions Kudu.Core/Deployment/Generator/OryxBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,15 @@ public override Task Build(DeploymentContext context)
{
PreOryxBuild(context);

args.Flags = BuildOptimizationsFlags.UseExpressBuild;

string buildCommand = args.GenerateOryxBuildCommand(context, environment);
RunCommand(context, buildCommand, false, "Running oryx build...");

//
// Run express build setups if needed
//

if (args.Flags == BuildOptimizationsFlags.UseExpressBuild)
{
if (FunctionAppHelper.LooksLikeFunctionApp())
Expand All @@ -73,6 +77,10 @@ public override Task Build(DeploymentContext context)
appServiceExpressBuilder.SetupExpressBuilderArtifacts(context.OutputPath, context, args);
}
}
else
{
Console.WriteLine("No Express :(");
}
}
return Task.CompletedTask;
}
Expand Down
11 changes: 8 additions & 3 deletions Kudu.Core/Deployment/Generator/SiteBuilderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,14 @@ private IEnvironment GetEnvironment(IHttpContextAccessor accessor, IEnvironment
return _environment;
}

public ISiteBuilder CreateBuilder(ITracer tracer, ILogger logger, IDeploymentSettingsManager settings, IRepository repository)
public ISiteBuilder CreateBuilder(ITracer tracer, ILogger logger, IDeploymentSettingsManager settings, IRepository repository, DeploymentInfoBase deploymentInfo)
{

string repositoryRoot = _environment.RepositoryPath;
if (!string.IsNullOrEmpty(repository.RepositoryPath))
{
repositoryRoot = repository.RepositoryPath;
}

// Use the cached vs projects file finder for: a. better performance, b. ignoring solutions/projects under node_modules
var fileFinder = new CachedVsProjectsFileFinder(repository);
Expand Down Expand Up @@ -75,14 +80,14 @@ public ISiteBuilder CreateBuilder(ITracer tracer, ILogger logger, IDeploymentSet
return new RunFromZipSiteBuilder();
}

if (!settings.DoBuildDuringDeployment() && repository.RepositoryType != RepositoryType.Git)
if (!deploymentInfo.ShouldBuildArtifact && !settings.DoBuildDuringDeployment() && repository.RepositoryType != RepositoryType.Git)
{
var projectPath = !String.IsNullOrEmpty(targetProjectPath) ? targetProjectPath : repositoryRoot;
return new BasicBuilder(_environment, settings, _propertyProvider, repositoryRoot, projectPath);
}

string enableOryxBuild = System.Environment.GetEnvironmentVariable("ENABLE_ORYX_BUILD");
if (!string.IsNullOrEmpty(enableOryxBuild))
if (!string.IsNullOrEmpty(enableOryxBuild) && (deploymentInfo.ShouldBuildArtifact || settings.DoBuildDuringDeployment()))
{
if (StringUtils.IsTrueLike(enableOryxBuild))
{
Expand Down
2 changes: 1 addition & 1 deletion Kudu.Core/Deployment/ISiteBuilderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ namespace Kudu.Core.Deployment
{
public interface ISiteBuilderFactory
{
ISiteBuilder CreateBuilder(ITracer tracer, ILogger logger, IDeploymentSettingsManager settings, IRepository fileFinder);
ISiteBuilder CreateBuilder(ITracer tracer, ILogger logger, IDeploymentSettingsManager settings, IRepository fileFinder, DeploymentInfoBase deploymentInfo);
}
}
4 changes: 2 additions & 2 deletions Kudu.Core/Deployment/Oryx/AppServiceOryxArguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ public AppServiceOryxArguments(IEnvironment environment)

if (K8SEDeploymentHelper.IsK8SEEnvironment())
{
Console.WriteLine("Oryx App Name : " + environment.K8SEAppName);
this.AppName = environment.K8SEAppName;

// K8SE TODO: Inject Environment
Expand Down Expand Up @@ -184,12 +183,13 @@ public string GenerateOryxBuildCommand(DeploymentContext context, IEnvironment e
{
// 10-LTS, 12-LTS should use versions 10, 12 etc
// Oryx Builder uses lts for major versions
Version = Version.Replace("LTS", "").Replace("-", "");
Version = Version.Replace("LTS", "").Replace("lts", "").Replace("-", "");
if (string.IsNullOrEmpty(Version))
{
// Current LTS
Version = "10";
}
OryxArgumentsHelper.AddLanguageVersion(args, Version);
}
break;
case Framework.Python:
Expand Down
14 changes: 11 additions & 3 deletions Kudu.Core/Infrastructure/DockerContainerRestartTrigger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
using System.Globalization;
using System.IO;
using System.Linq;
using Kudu.Contracts.Deployment;
using Kudu.Core.Functions;
using Kudu.Core.Helpers;
using Kudu.Core.K8SE;
using Newtonsoft.Json;

namespace Kudu.Core.Infrastructure
{
Expand All @@ -25,22 +27,28 @@ public static class DockerContainerRestartTrigger
"The last modification Kudu made to this file was at {0}, for the following reason: {1}.",
System.Environment.NewLine);

public static void RequestContainerRestart(IEnvironment environment, string reason, string repositoryUrl = null)
public static void RequestContainerRestart(IEnvironment environment, string reason, string repositoryUrl = null, string appSubPath = "")
{
if (K8SEDeploymentHelper.IsK8SEEnvironment())
{
string appName = environment.SiteRootPath.Replace("/home/apps/", "").Split("/")[0];
string buildNumber = environment.CurrId;
var functionTriggers = FunctionTriggerProvider.GetFunctionTriggers<IEnumerable<ScaleTrigger>>("keda", repositoryUrl);
var buildMetadata = new BuildMetadata()
{
AppName = appName,
BuildVersion = buildNumber,
AppSubPath = appSubPath
};

//Only for function apps functionTriggers will be non-null/non-empty
if (functionTriggers?.Any() == true)
{
K8SEDeploymentHelper.UpdateFunctionAppTriggers(appName, functionTriggers, $"{buildNumber}|{appName}");
K8SEDeploymentHelper.UpdateFunctionAppTriggers(appName, functionTriggers, buildMetadata);
}
else
{
K8SEDeploymentHelper.UpdateBuildNumber(appName, buildNumber);
K8SEDeploymentHelper.UpdateBuildNumber(appName, buildMetadata);
}

return;
Expand Down
47 changes: 36 additions & 11 deletions Kudu.Core/K8SE/K8SEDeploymentHelper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Kudu.Contracts.Tracing;
using Kudu.Contracts.Deployment;
using Kudu.Contracts.Tracing;
using Kudu.Core.Deployment;
using Kudu.Core.Functions;
using Microsoft.AspNetCore.Http;
Expand All @@ -8,6 +9,7 @@
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Web;

namespace Kudu.Core.K8SE
{
Expand Down Expand Up @@ -44,25 +46,43 @@ public static string GetLinuxFxVersion(string appName)
/// </summary>
/// <param name="appName"></param>
/// <returns></returns>
public static void UpdateBuildNumber(string appName, string buildNumber)
public static void UpdateBuildNumber(string appName, BuildMetadata buildMetadata)
{
var buildPatchJson = $"\"{HttpUtility.JavaScriptStringEncode(JsonConvert.SerializeObject(buildMetadata)).Replace("\\","\\\\")}\"";

var cmd = new StringBuilder();
BuildCtlArgumentsHelper.AddBuildCtlCommand(cmd, "update");
BuildCtlArgumentsHelper.AddAppNameArgument(cmd, appName);
BuildCtlArgumentsHelper.AddAppPropertyArgument(cmd, "buildVersion");
BuildCtlArgumentsHelper.AddAppPropertyValueArgument(cmd, buildNumber);
BuildCtlArgumentsHelper.AddAppPropertyArgument(cmd, "buildMetadata");
BuildCtlArgumentsHelper.AddAppPropertyValueArgument(cmd, buildPatchJson);
RunBuildCtlCommand(cmd.ToString(), "Updating build version...");
}

/// <summary>
/// Updates the Image Tag of the K8SE custom container app
/// </summary>
/// <param name="appName"></param>
/// <param name="imageTag">container image tag of the format registry/<image>:<tag></param>
/// <returns></returns>
public static void UpdateImageTag(string appName, string imageTag)
{
var cmd = new StringBuilder();
BuildCtlArgumentsHelper.AddBuildCtlCommand(cmd, "update");
BuildCtlArgumentsHelper.AddAppNameArgument(cmd, appName);
BuildCtlArgumentsHelper.AddAppPropertyArgument(cmd, "appImage");
BuildCtlArgumentsHelper.AddAppPropertyValueArgument(cmd, imageTag);
RunBuildCtlCommand(cmd.ToString(), "Updating image tag...");
}

/// <summary>
/// Updates the triggers for the function apps
/// </summary>
/// <param name="appName">The app name to update</param>
/// <param name="functionTriggers">The IEnumerable<ScaleTrigger></param>
/// <param name="buildNumber">Build number to update</param>
public static void UpdateFunctionAppTriggers(string appName, IEnumerable<ScaleTrigger> functionTriggers, string buildNumber)
public static void UpdateFunctionAppTriggers(string appName, IEnumerable<ScaleTrigger> functionTriggers, BuildMetadata buildMetadata)
{
var functionAppPatchJson = GetFunctionAppPatchJson(functionTriggers, buildNumber);
var functionAppPatchJson = GetFunctionAppPatchJson(functionTriggers, buildMetadata);
if (string.IsNullOrEmpty(functionAppPatchJson))
{
return;
Expand Down Expand Up @@ -118,19 +138,24 @@ public static string GetAppName(HttpContext context)
// K8SE TODO: move this to resource map
throw new InvalidOperationException("Couldn't recognize AppName");
}

Console.WriteLine("AppName :::::::: " + appName);

return appName;
}

private static string GetFunctionAppPatchJson(IEnumerable<ScaleTrigger> functionTriggers, string buildNumber)
private static string GetFunctionAppPatchJson(IEnumerable<ScaleTrigger> functionTriggers, BuildMetadata buildMetadata)
{
if (functionTriggers == null || !functionTriggers.Any())
{
return null;
}

if (buildMetadata == null )
{
return null;
}

var buildPatchJson = JsonConvert.SerializeObject(buildMetadata);
var buildmetaJsonString = JsonConvert.ToString(buildPatchJson);

var patchAppJson = new PatchAppJson
{
PatchSpec = new PatchSpec
Expand All @@ -143,7 +168,7 @@ private static string GetFunctionAppPatchJson(IEnumerable<ScaleTrigger> function
{
PackageRef = new PackageReference
{
BuildVersion = buildNumber
BuildVersion = buildmetaJsonString
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions Kudu.Services.Web/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ public void ConfigureServices(IServiceCollection services)
services.Configure<FormOptions>(options =>
{
options.MultipartBodyLengthLimit = 52428800;
options.ValueCountLimit = 500000;
options.KeyLengthLimit = 500000;
options.ValueCountLimit = 1000000;
options.KeyLengthLimit = 1000000;
});

services.AddRouteAnalyzer();
Expand Down Expand Up @@ -518,6 +518,8 @@ public void Configure(IApplicationBuilder app,
new {controller = "Deployment", action = "GetLogEntry"});
routes.MapHttpRouteDual("one-deployment-log-details", "deployments/{id}/log/{logId}",
new {controller = "Deployment", action = "GetLogEntryDetails"});
routes.MapHttpRouteDual("update-container-tag", "app/update",
new { controller = "Deployment", action = "UpdateContainerTag" });

// Deployment script
routes.MapRoute("get-deployment-script", "api/deploymentscript",
Expand Down
Loading

0 comments on commit 1d20b32

Please sign in to comment.