Skip to content

Refactor and clean up based on the dependency management changes #194

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

Merged
merged 3 commits into from
Apr 27, 2019
Merged
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
24 changes: 10 additions & 14 deletions src/DependencyManagement/DependencyManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.PowerShellWorker.PowerShell;
using Microsoft.Azure.Functions.PowerShellWorker.Utility;
using LogLevel = Microsoft.Azure.WebJobs.Script.Grpc.Messages.RpcLog.Types.Level;
using Microsoft.Azure.Functions.PowerShellWorker.Messaging;
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
using LogLevel = Microsoft.Azure.WebJobs.Script.Grpc.Messages.RpcLog.Types.Level;

namespace Microsoft.Azure.Functions.PowerShellWorker.DependencyManagement
{
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Management.Automation.Runspaces;
using System.Threading.Tasks;

internal class DependencyManager
{
Expand Down Expand Up @@ -122,18 +122,9 @@ private void ProcessDependencies(RpcLogger rpcLogger)
try
{
_dependencyError = null;
var initialSessionState = InitialSessionState.CreateDefault();
initialSessionState.ThreadOptions = PSThreadOptions.UseCurrentThread;
initialSessionState.EnvironmentVariables.Add(new SessionStateVariableEntry("PSModulePath", FunctionLoader.FunctionModulePath, null));
// Setting the execution policy on macOS and Linux throws an exception so only update it on Windows
if (Platform.IsWindows)
using (PowerShell pwsh = PowerShell.Create(Utils.SingletonISS.Value))
{
initialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;
}

using (PowerShell powerShellInstance = PowerShell.Create(initialSessionState))
{
InstallFunctionAppDependencies(powerShellInstance, rpcLogger);
InstallFunctionAppDependencies(pwsh, rpcLogger);
}
}
catch (Exception e)
Expand All @@ -152,6 +143,11 @@ private void ProcessDependencies(RpcLogger rpcLogger)
/// </summary>
internal void Initialize(FunctionLoadRequest request)
{
if (!request.ManagedDependencyEnabled)
{
return;
}

try
{
// Resolve the FunctionApp root path.
Expand Down
15 changes: 1 addition & 14 deletions src/PowerShell/PowerShellManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,8 @@ internal PowerShellManager(ILogger logger)
throw new InvalidOperationException(PowerShellWorkerStrings.FunctionAppRootNotResolved);
}

var initialSessionState = InitialSessionState.CreateDefault();
initialSessionState.ThreadOptions = PSThreadOptions.UseCurrentThread;
initialSessionState.EnvironmentVariables.Add(
new SessionStateVariableEntry("PSModulePath", FunctionLoader.FunctionModulePath, null));

// Setting the execution policy on macOS and Linux throws an exception so only update it on Windows
if(Platform.IsWindows)
{
// This sets the execution policy on Windows to Unrestricted which is required to run the user's function scripts on
// Windows client versions. This is needed if a user is testing their function locally with the func CLI
initialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;
}

_logger = logger;
_pwsh = PowerShell.Create(initialSessionState);
_pwsh = PowerShell.Create(Utils.SingletonISS.Value);

// Setup Stream event listeners
var streamHandler = new StreamHandler(logger);
Expand Down
57 changes: 20 additions & 37 deletions src/RequestProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ internal class RequestProcessor
private readonly PowerShellManagerPool _powershellPool;
private readonly DependencyManager _dependencyManager;

// Holds the exception if an issue is encountered while installing the function app dependencies
// or while initializing PowerShell.
// Holds the exception if an issue is encountered while processing the function app dependencies.
private Exception _initTerminatingError;

// Indicate whether the FunctionApp has been initialized.
Expand Down Expand Up @@ -167,7 +166,11 @@ internal StreamingMessage ProcessFunctionLoadRequest(StreamingMessage request)
try
{
_isFunctionAppInitialized = true;
InitializeForFunctionApp(request);
_dependencyManager.Initialize(functionLoadRequest);

// Setup the FunctionApp root path and module path.
FunctionLoader.SetupWellKnownPaths(functionLoadRequest);
_dependencyManager.ProcessDependencyDownload(_msgStream, request);
}
catch (Exception e)
{
Expand Down Expand Up @@ -200,15 +203,12 @@ internal StreamingMessage ProcessFunctionLoadRequest(StreamingMessage request)
/// </summary>
internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
{
AzFunctionInfo functionInfo = null;
PowerShellManager psManager = null;
Exception error = null;

try
{
if (_dependencyManager.DependencyDownloadTask != null
&& (_dependencyManager.DependencyDownloadTask.Status != TaskStatus.Canceled
|| _dependencyManager.DependencyDownloadTask.Status != TaskStatus.Faulted
|| _dependencyManager.DependencyDownloadTask.Status != TaskStatus.RanToCompletion))
if (_dependencyManager.DependencyDownloadTask != null &&
!_dependencyManager.DependencyDownloadTask.IsCompleted)
{
var rpcLogger = new RpcLogger(_msgStream);
rpcLogger.SetContext(request.RequestId, request.InvocationRequest?.InvocationId);
Expand All @@ -218,17 +218,12 @@ internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)

if (_dependencyManager.DependencyError != null)
{
StreamingMessage response = NewStreamingMessageTemplate(request.RequestId,
StreamingMessage.ContentOneofCase.InvocationResponse,
out StatusResult status);
status.Status = StatusResult.Types.Status.Failure;
status.Exception = _dependencyManager.DependencyError.ToRpcException();
response.InvocationResponse.InvocationId = request.InvocationRequest.InvocationId;
return response;
error = _dependencyManager.DependencyError;
}

functionInfo = _functionLoader.GetFunctionInfo(request.InvocationRequest.FunctionId);
psManager = _powershellPool.CheckoutIdleWorker(request, functionInfo);
else
{
AzFunctionInfo functionInfo = _functionLoader.GetFunctionInfo(request.InvocationRequest.FunctionId);
PowerShellManager psManager = _powershellPool.CheckoutIdleWorker(request, functionInfo);

if (_powershellPool.UpperBound == 1)
{
Expand All @@ -243,18 +238,22 @@ internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
Task.Run(() => ProcessInvocationRequestImpl(request, functionInfo, psManager));
}
}
}
catch (Exception e)
{
_powershellPool.ReclaimUsedWorker(psManager);
error = e;
}

if (error != null)
{
StreamingMessage response = NewStreamingMessageTemplate(
request.RequestId,
StreamingMessage.ContentOneofCase.InvocationResponse,
out StatusResult status);

response.InvocationResponse.InvocationId = request.InvocationRequest.InvocationId;
status.Status = StatusResult.Types.Status.Failure;
status.Exception = e.ToRpcException();
status.Exception = error.ToRpcException();

return response;
}
Expand Down Expand Up @@ -314,22 +313,6 @@ internal StreamingMessage ProcessFunctionEnvironmentReloadRequest(StreamingMessa

#region Helper_Methods

/// <summary>
/// Initialize the worker based on the FunctionApp that the worker will deal with.
/// </summary>
private void InitializeForFunctionApp(StreamingMessage request)
{
var functionLoadRequest = request.FunctionLoadRequest;
if (functionLoadRequest.ManagedDependencyEnabled)
{
_dependencyManager.Initialize(functionLoadRequest);
}

// Setup the FunctionApp root path and module path.
FunctionLoader.SetupWellKnownPaths(functionLoadRequest);
_dependencyManager.ProcessDependencyDownload(_msgStream, request);
}

/// <summary>
/// Create an object of 'StreamingMessage' as a template, for further update.
/// </summary>
Expand Down
34 changes: 30 additions & 4 deletions src/Utility/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,43 @@
using System;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
using System.Threading;
using Microsoft.PowerShell.Commands;

namespace Microsoft.Azure.Functions.PowerShellWorker.Utility
{
internal class Utils
{
internal static CmdletInfo ImportModuleCmdletInfo = new CmdletInfo("Import-Module", typeof(ImportModuleCommand));
internal static CmdletInfo RemoveModuleCmdletInfo = new CmdletInfo("Remove-Module", typeof(RemoveModuleCommand));
internal static CmdletInfo GetJobCmdletInfo = new CmdletInfo("Get-Job", typeof(GetJobCommand));
internal static CmdletInfo RemoveJobCmdletInfo = new CmdletInfo("Remove-Job", typeof(RemoveJobCommand));
internal readonly static CmdletInfo ImportModuleCmdletInfo = new CmdletInfo("Import-Module", typeof(ImportModuleCommand));
internal readonly static CmdletInfo RemoveModuleCmdletInfo = new CmdletInfo("Remove-Module", typeof(RemoveModuleCommand));
internal readonly static CmdletInfo GetJobCmdletInfo = new CmdletInfo("Get-Job", typeof(GetJobCommand));
internal readonly static CmdletInfo RemoveJobCmdletInfo = new CmdletInfo("Remove-Job", typeof(RemoveJobCommand));

internal readonly static Lazy<InitialSessionState> SingletonISS
= new Lazy<InitialSessionState>(NewInitialSessionState, LazyThreadSafetyMode.PublicationOnly);

private static InitialSessionState NewInitialSessionState()
{
var iss = InitialSessionState.CreateDefault();
iss.ThreadOptions = PSThreadOptions.UseCurrentThread;
iss.EnvironmentVariables.Add(
new SessionStateVariableEntry(
"PSModulePath",
FunctionLoader.FunctionModulePath,
description: null));

// Setting the execution policy on macOS and Linux throws an exception so only update it on Windows
if(Platform.IsWindows)
{
// This sets the execution policy on Windows to Unrestricted which is required to run the user's function scripts on
// Windows client versions. This is needed if a user is testing their function locally with the func CLI.
iss.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;
}

return iss;
}

/// <summary>
/// Helper method to do additional transformation on the input value based on the type constraints specified in the script.
Expand Down