Skip to content

Commit 6e095d2

Browse files
SatishRanjanbrettsam
authored andcommitted
Files for PowerShell function apps created through azure portal (#4211)
* File augmentation for powershell function apps * - Changing name to FileProvisioningService - Register FucnAppFileProvisioningService only when the language runtime is PowerShell - if host.json doesn't exist then only add managedDependencyEnabl flag in host. json * Fixing "requirements.psd1" and "profile.ps1" resource assembly name
1 parent d6e7a27 commit 6e095d2

13 files changed

+356
-3
lines changed

src/WebJobs.Script/Config/HostJsonFileConfigurationSource.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.IO;
88
using System.Linq;
99
using Microsoft.Azure.WebJobs.Logging;
10+
using Microsoft.Azure.WebJobs.Script.Rpc;
1011
using Microsoft.Extensions.Configuration;
1112
using Microsoft.Extensions.Logging;
1213
using Newtonsoft.Json;
@@ -189,9 +190,15 @@ internal JObject LoadHostConfig(string configFilePath)
189190
return hostConfigObject;
190191
}
191192

192-
private static JObject GetDefaultHostConfigObject()
193+
private JObject GetDefaultHostConfigObject()
193194
{
194-
return new JObject { { "version", "2.0" } };
195+
var hostJsonJObj = JObject.Parse("{'version': '2.0'}");
196+
if (string.Equals(_configurationSource.Environment.GetEnvironmentVariable(LanguageWorkerConstants.FunctionWorkerRuntimeSettingName), "powershell", StringComparison.InvariantCultureIgnoreCase))
197+
{
198+
hostJsonJObj.Add("managedDependency", JToken.Parse("{'Enabled': true}"));
199+
}
200+
201+
return hostJsonJObj;
195202
}
196203

197204
private void TryWriteHostJson(string filePath, JObject content)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using Microsoft.Azure.WebJobs.Script.FileProvisioning.PowerShell;
6+
7+
namespace Microsoft.Azure.WebJobs.Script.FileProvisioning
8+
{
9+
internal class FuncAppFileProvisionerFactory : IFuncAppFileProvisionerFactory
10+
{
11+
public IFuncAppFileProvisioner CreatFileProvisioner(string runtime)
12+
{
13+
if (string.IsNullOrWhiteSpace(runtime))
14+
{
15+
return null;
16+
}
17+
18+
switch (runtime.ToLowerInvariant())
19+
{
20+
case "powershell":
21+
return new PowerShellFileProvisioner();
22+
default:
23+
return null;
24+
}
25+
}
26+
}
27+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using Microsoft.Azure.WebJobs.Script.Rpc;
7+
using Microsoft.Extensions.Hosting;
8+
using Microsoft.Extensions.Options;
9+
10+
namespace Microsoft.Azure.WebJobs.Script.FileProvisioning
11+
{
12+
internal class FuncAppFileProvisioningService : IHostedService
13+
{
14+
private readonly IOptionsMonitor<ScriptApplicationHostOptions> _options;
15+
private readonly IEnvironment _environment;
16+
private readonly IFuncAppFileProvisionerFactory _funcAppFileProvisionerFactory;
17+
18+
public FuncAppFileProvisioningService(
19+
IEnvironment environment,
20+
IOptionsMonitor<ScriptApplicationHostOptions> options,
21+
IFuncAppFileProvisionerFactory funcAppFileProvisionerFactory)
22+
{
23+
_environment = environment;
24+
_options = options;
25+
_funcAppFileProvisionerFactory = funcAppFileProvisionerFactory;
26+
}
27+
28+
public async Task StartAsync(CancellationToken cancellationToken)
29+
{
30+
if (!_environment.FileSystemIsReadOnly())
31+
{
32+
var funcAppFileProvisioner = _funcAppFileProvisionerFactory.CreatFileProvisioner(_environment.GetEnvironmentVariable(LanguageWorkerConstants.FunctionWorkerRuntimeSettingName));
33+
if (funcAppFileProvisioner != null)
34+
{
35+
await funcAppFileProvisioner.ProvisionFiles(_options.CurrentValue.ScriptPath);
36+
}
37+
}
38+
}
39+
40+
public Task StopAsync(CancellationToken cancellationToken)
41+
{
42+
return Task.CompletedTask;
43+
}
44+
}
45+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System.Threading.Tasks;
5+
6+
namespace Microsoft.Azure.WebJobs.Script.FileProvisioning
7+
{
8+
public interface IFuncAppFileProvisioner
9+
{
10+
/// <summary>
11+
/// Adds the required files to the function app
12+
/// </summary>
13+
/// <param name="scriptRootPath">The root path of the function app</param>
14+
/// <returns>An empty completed task <see cref="Task"/></returns>
15+
Task ProvisionFiles(string scriptRootPath);
16+
}
17+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.Azure.WebJobs.Script.FileProvisioning
5+
{
6+
internal interface IFuncAppFileProvisionerFactory
7+
{
8+
/// <summary>
9+
/// Creates the file augmentor for the given runtime
10+
/// </summary>
11+
/// <param name="runtime">The name of the runtime</param>
12+
/// <returns>Fun app file augmentor <see cref="IFuncAppFileProvisioner"/></returns>
13+
IFuncAppFileProvisioner CreatFileProvisioner(string runtime);
14+
}
15+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.IO;
6+
using System.Threading.Tasks;
7+
using Newtonsoft.Json;
8+
using Newtonsoft.Json.Linq;
9+
10+
namespace Microsoft.Azure.WebJobs.Script.FileProvisioning.PowerShell
11+
{
12+
internal class PowerShellFileProvisioner : IFuncAppFileProvisioner
13+
{
14+
/// <summary>
15+
/// Adds the required files to the function app
16+
/// </summary>
17+
/// <param name="scriptRootPath">The root path of the function app</param>
18+
/// <returns>An empty completed task <see cref="Task"/></returns>
19+
public Task ProvisionFiles(string scriptRootPath)
20+
{
21+
if (string.IsNullOrWhiteSpace(scriptRootPath))
22+
{
23+
throw new ArgumentException("The parameter {0} cannot be null or empty", nameof(scriptRootPath));
24+
}
25+
26+
AddRequirementsFile(scriptRootPath);
27+
AddProfileFile(scriptRootPath);
28+
return Task.CompletedTask;
29+
}
30+
31+
private void AddRequirementsFile(string scriptRootPath)
32+
{
33+
string requirementsFilePath = Path.Combine(scriptRootPath, "requirements.psd1");
34+
if (!File.Exists(requirementsFilePath))
35+
{
36+
string content = FileUtility.ReadResourceString($"Microsoft.Azure.WebJobs.Script.FileProvisioning.PowerShell.requirements.psd1");
37+
File.WriteAllText(requirementsFilePath, content);
38+
}
39+
}
40+
41+
private void AddProfileFile(string scriptRootPath)
42+
{
43+
string profileFilePath = Path.Combine(scriptRootPath, "profile.ps1");
44+
if (!File.Exists(profileFilePath))
45+
{
46+
string content = FileUtility.ReadResourceString($"Microsoft.Azure.WebJobs.Script.FileProvisioning.PowerShell.profile.ps1");
47+
File.WriteAllText(profileFilePath, content);
48+
}
49+
}
50+
}
51+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Azure Functions profile.ps1
2+
#
3+
# This profile.ps1 will get executed every "cold start" of your Function App.
4+
# "cold start" occurs when:
5+
#
6+
# * A Function App starts up for the very first time
7+
# * A Function App starts up after being de-allocated due to inactivity
8+
#
9+
# You can define helper functions, run commands, or specify environment variables
10+
# NOTE: any variables defined that are not environment variables will get reset after the first execution
11+
# Authenticate with Azure PowerShell using MSI.
12+
# Remove this if you are not planning on using MSI or Azure PowerShell.
13+
14+
if ($env:MSI_SECRET -and (Get-Module -ListAvailable Az.Accounts)) {
15+
    Connect-AzAccount -Identity
16+
}
17+
18+
# Uncomment the next line to enable legacy AzureRm alias in Azure PowerShell.
19+
# Enable-AzureRmAlias
20+
# You can also define functions or aliases that can be referenced in any of your PowerShell functions.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@{
2+
Az = '1.*'
3+
}

src/WebJobs.Script/ScriptHostBuilderExtensions.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using Microsoft.Azure.WebJobs.Script.Eventing;
2020
using Microsoft.Azure.WebJobs.Script.Extensibility;
2121
using Microsoft.Azure.WebJobs.Script.ExtensionBundle;
22+
using Microsoft.Azure.WebJobs.Script.FileProvisioning;
2223
using Microsoft.Azure.WebJobs.Script.Grpc;
2324
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
2425
using Microsoft.Azure.WebJobs.Script.ManagedDependencies;
@@ -163,11 +164,11 @@ public static IHostBuilder AddScriptHostCore(this IHostBuilder builder, ScriptAp
163164
AddCommonServices(services);
164165
}
165166

166-
// Hosted services
167167
services.AddSingleton<IHostedService, LanguageWorkerConsoleLogService>();
168168
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, PrimaryHostCoordinator>());
169169
});
170170

171+
RegisterFileProvisioningService(builder);
171172
return builder;
172173
}
173174

@@ -262,5 +263,17 @@ internal static ExtensionBundleOptions GetExtensionBundleOptions(HostBuilderCont
262263
optionsSetup.Configure(options);
263264
return options;
264265
}
266+
267+
private static void RegisterFileProvisioningService(IHostBuilder builder)
268+
{
269+
if (string.Equals(Environment.GetEnvironmentVariable(LanguageWorkerConstants.FunctionWorkerRuntimeSettingName), "powershell"))
270+
{
271+
builder.ConfigureServices(services =>
272+
{
273+
services.AddSingleton<IFuncAppFileProvisionerFactory, FuncAppFileProvisionerFactory>();
274+
services.AddSingleton<IHostedService, FuncAppFileProvisioningService>();
275+
});
276+
}
277+
}
265278
}
266279
}

src/WebJobs.Script/WebJobs.Script.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@
1717
<WarningsAsErrors />
1818
</PropertyGroup>
1919
<ItemGroup>
20+
<None Remove="FileProvisioning\PowerShell\profile.ps1" />
21+
<None Remove="FileProvisioning\PowerShell\requirements.psd1" />
2022
<None Remove="runtimeassemblies.json" />
2123
<None Remove="runtimes.json" />
2224
</ItemGroup>
2325
<ItemGroup>
26+
<EmbeddedResource Include="FileProvisioning\PowerShell\profile.ps1" />
27+
<EmbeddedResource Include="FileProvisioning\PowerShell\requirements.psd1" />
2428
<EmbeddedResource Include="runtimeassemblies.json">
2529
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
2630
</EmbeddedResource>

0 commit comments

Comments
 (0)