Skip to content

Commit

Permalink
extension bundle probing and download
Browse files Browse the repository at this point in the history
  • Loading branch information
soninaren committed Feb 25, 2019
1 parent 04a293b commit 1318f43
Show file tree
Hide file tree
Showing 25 changed files with 1,199 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ private string GetJobBasePath()
{
basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".azurefunctions", "extensions");
}

FileUtility.EnsureDirectoryExists(basePath);
return basePath;
}

Expand Down
6 changes: 6 additions & 0 deletions src/WebJobs.Script.WebHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Linq;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Azure.WebJobs.Script.Configuration;
using Microsoft.Azure.WebJobs.Script.WebHost.Configuration;
using Microsoft.Azure.WebJobs.Script.WebHost.DependencyInjection;
using Microsoft.Azure.WebJobs.Script.WebHost.Diagnostics;
Expand Down Expand Up @@ -62,6 +63,11 @@ public static IWebHostBuilder CreateWebHostBuilder(string[] args = null)
IsLinuxContainerEnvironment = SystemEnvironment.Instance.IsLinuxContainerEnvironment(),
IsLinuxAppServiceEnvironment = SystemEnvironment.Instance.IsLinuxAppServiceEnvironment()
});

config.Add(new ExtensionBundleConfigurationSource
{
IsAppServiceEnvironment = SystemEnvironment.Instance.IsAppServiceEnvironment(),
});
})
.ConfigureLogging((context, loggingBuilder) =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
using System.Net.Http;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Hosting;
using Microsoft.Azure.WebJobs.Script.Config;
using Microsoft.Azure.WebJobs.Script.Configuration;
using Microsoft.Azure.WebJobs.Script.DependencyInjection;
using Microsoft.Azure.WebJobs.Script.ExtensionBundle;
using Microsoft.Azure.WebJobs.Script.Rpc;
using Microsoft.Azure.WebJobs.Script.WebHost.Configuration;
using Microsoft.Azure.WebJobs.Script.WebHost.ContainerManagement;
Expand Down Expand Up @@ -116,6 +120,9 @@ public static void AddWebJobsScriptHost(this IServiceCollection services, IConfi
// Configuration
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<ScriptApplicationHostOptions>, ScriptApplicationHostOptionsSetup>());
services.ConfigureOptions<LanguageWorkerOptionsSetup>();
services.ConfigureOptions<ExtensionBundleOptionsSetup>();
services.AddSingleton<IExtensionBundleManager, ExtensionBundleManager>();
services.AddSingleton<IScriptStartupTypeLocatorFactory, ScriptStartupTypeLocatorFactory>();
}

private static void AddStandbyServices(this IServiceCollection services)
Expand Down
6 changes: 6 additions & 0 deletions src/WebJobs.Script.WebHost/WebScriptHostBuilderExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.Azure.WebJobs.Host.Executors;
using Microsoft.Azure.WebJobs.Host.Loggers;
using Microsoft.Azure.WebJobs.Host.Timers;
using Microsoft.Azure.WebJobs.Script.DependencyInjection;
using Microsoft.Azure.WebJobs.Script.Diagnostics;
using Microsoft.Azure.WebJobs.Script.WebHost.Configuration;
using Microsoft.Azure.WebJobs.Script.WebHost.DependencyInjection;
Expand All @@ -25,6 +26,11 @@ public static IHostBuilder AddWebScriptHost(this IHostBuilder builder, IServiceP
IServiceScopeFactory rootScopeFactory, ScriptApplicationHostOptions webHostOptions, Action<IWebJobsBuilder> configureWebJobs = null)
{
ILoggerFactory configLoggerFactory = rootServiceProvider.GetService<ILoggerFactory>();
var startupTypeLocatorFactory = rootServiceProvider.GetService<IScriptStartupTypeLocatorFactory>();
if (startupTypeLocatorFactory != null)
{
builder.Properties.Add(nameof(IScriptStartupTypeLocatorFactory), startupTypeLocatorFactory);
}

builder.UseServiceProviderFactory(new JobHostScopedServiceProviderFactory(rootServiceProvider, rootScopeFactory))
.ConfigureServices(services =>
Expand Down

This file was deleted.

1 change: 1 addition & 0 deletions src/WebJobs.Script/BindingExtensions/ExtensionsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Xml;
using Microsoft.Azure.WebJobs.Script.Config;
using Microsoft.Azure.WebJobs.Script.Description.DotNet;
using Microsoft.Azure.WebJobs.Script.ExtensionBundle;
using Microsoft.Azure.WebJobs.Script.Models;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
Expand Down
73 changes: 73 additions & 0 deletions src/WebJobs.Script/Config/ExtensionBundleConfigurationSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using static System.Environment;

namespace Microsoft.Azure.WebJobs.Script.Configuration
{
public class ExtensionBundleConfigurationSource : FileConfigurationSource
{
private const string IdProperty = "id";
private const string VersionProperty = "version";

public bool IsAppServiceEnvironment { get; set; }

public override IConfigurationProvider Build(IConfigurationBuilder builder)
{
if (IsAppServiceEnvironment)
{
string home = GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteHomePath);
Path = System.IO.Path.Combine(home, "site", "wwwroot", ScriptConstants.HostMetadataFileName);
}
else
{
string root = GetEnvironmentVariable(EnvironmentSettingNames.AzureWebJobsScriptRoot);
Path = System.IO.Path.Combine(root, ScriptConstants.HostMetadataFileName);
}

ReloadOnChange = true;
ResolveFileProvider();
return new ExtensionBundleConfigurationProvider(this);
}

public class ExtensionBundleConfigurationProvider : FileConfigurationProvider
{
public ExtensionBundleConfigurationProvider(ExtensionBundleConfigurationSource configurationSource) : base(configurationSource) { }

public override void Load(Stream stream)
{
using (var reader = new StreamReader(stream))
{
string json = reader.ReadToEnd();
JObject configObject = JObject.Parse(json);

var bundleConfig = configObject?[ConfigurationSectionNames.ExtensionBundle];
if (bundleConfig == null)
{
return;
}

var bundleSection = ConfigurationPath.Combine(ConfigurationSectionNames.JobHost, ConfigurationSectionNames.ExtensionBundle);
var idProperty = ConfigurationPath.Combine(bundleSection, IdProperty);
var versionProperty = ConfigurationPath.Combine(bundleSection, VersionProperty);

if (bundleConfig.Type != JTokenType.Object)
{
Data[bundleSection] = string.Empty;
}
else
{
Data[idProperty] = bundleConfig?[IdProperty]?.Value<string>();
Data[versionProperty] = bundleConfig?[VersionProperty]?.Value<string>();
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using NuGet.Versioning;

namespace Microsoft.Azure.WebJobs.Script.BindingExtensionBundle
namespace Microsoft.Azure.WebJobs.Script.Configuration
{
public class ExtensionBundleOptions
{
public string Id { get; set; }

public VersionRange Version { get; set; }

public ICollection<string> ProbingPaths { get; private set; } = new Collection<string>();

public string DownloadPath { get; set; }

public bool EnsureLatest { get; set; }
}
}
93 changes: 93 additions & 0 deletions src/WebJobs.Script/Config/ExtensionBundleOptionsSetup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Azure.WebJobs.Script.Properties;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using NuGet.Packaging;
using NuGet.Versioning;

namespace Microsoft.Azure.WebJobs.Script.Configuration
{
public class ExtensionBundleOptionsSetup : IConfigureOptions<ExtensionBundleOptions>
{
private readonly IConfiguration _configuration;
private readonly IEnvironment _environment;
private readonly IHostingEnvironment _hostingEnvironment;

public ExtensionBundleOptionsSetup(IConfiguration configuration, IEnvironment environment, IHostingEnvironment hostingEnvironment)
{
_configuration = configuration;
_environment = environment;
_hostingEnvironment = hostingEnvironment;
}

public void Configure(ExtensionBundleOptions options)
{
IConfigurationSection jobHostSection = _configuration.GetSection(ConfigurationSectionNames.JobHost);
var extensionBundleSection = jobHostSection.GetSection(ConfigurationSectionNames.ExtensionBundle);
extensionBundleSection.Bind(options);

if (extensionBundleSection.Exists())
{
ValidateBundleId(options.Id);
ConfigureBundleVersion(extensionBundleSection, options);

if (_environment.IsAppServiceEnvironment() || _hostingEnvironment.IsDevelopment())
{
options.DownloadPath = Path.Combine(_environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteHomePath),
"data", "Functions", ScriptConstants.ExtensionBundleDirectory, options.Id);
ConfigureProbingPaths(options);
}
}
}

private void ConfigureBundleVersion(IConfigurationSection configurationSection, ExtensionBundleOptions options)
{
string bundleVersion = configurationSection.GetValue<string>("version");
if (string.IsNullOrWhiteSpace(bundleVersion) || !VersionRange.TryParse(bundleVersion.ToString(), allowFloating: true, out VersionRange version))
{
string message = string.Format(Resources.ExtensionBundleConfigMissingVersion, ScriptConstants.HostMetadataFileName);
throw new ArgumentException(message);
}
options.Version = version;
}

private void ValidateBundleId(string id)
{
if (string.IsNullOrWhiteSpace(id) || !PackageIdValidator.IsValidPackageId(id))
{
string message = string.Format(Resources.ExtensionBundleConfigMissingId, ScriptConstants.HostMetadataFileName);
throw new ArgumentException(message);
}
}

private void ConfigureProbingPaths(ExtensionBundleOptions options)
{
if (_environment.IsAppServiceWindowsEnvironment() || _hostingEnvironment.IsDevelopment())
{
string windowsDefaultPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
ScriptConstants.DefaultExtensionBundleDirectory,
options.Id);

options.ProbingPaths.Add(windowsDefaultPath);
}

if (_environment.IsLinuxAppServiceEnvironment())
{
string linuxDefaultPath = Path.Combine(Path.PathSeparator.ToString(), ScriptConstants.DefaultExtensionBundleDirectory, options.Id);

string deploymentPackageBundlePath = Path.Combine(
_environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteHomePath),
"site", "wwwroot", ".azureFunctions", ScriptConstants.ExtensionBundleDirectory, options.Id);

options.ProbingPaths.Add(linuxDefaultPath);
options.ProbingPaths.Add(deploymentPackageBundlePath);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using Microsoft.Azure.WebJobs.Hosting;

namespace Microsoft.Azure.WebJobs.Script.DependencyInjection
{
public interface IScriptStartupTypeLocatorFactory
{
IWebJobsStartupTypeLocator Create();
}
}
Loading

0 comments on commit 1318f43

Please sign in to comment.