public void InvokeBasicFunctionWithTriggerMetadataAndTraceContextWorks() { string path = Path.Join(s_funcDirectory, "testBasicFunctionWithTriggerMetadata.ps1"); var(functionInfo, testManager) = PrepareFunction(path, string.Empty); Hashtable triggerMetadata = new Hashtable(StringComparer.OrdinalIgnoreCase) { { TestInputBindingName, TestStringData } }; try { FunctionMetadata.RegisterFunctionMetadata(testManager.InstanceId, functionInfo); Hashtable result = InvokeFunction(testManager, functionInfo, triggerMetadata); // The outputBinding hashtable for the runspace should be cleared after 'InvokeFunction' Hashtable outputBindings = FunctionMetadata.GetOutputBindingHashtable(testManager.InstanceId); Assert.Empty(outputBindings); // A PowerShell function should be created fro the Az function. string expectedResult = $"{TestStringData},{functionInfo.DeployedPSFuncName}"; Assert.Equal(expectedResult, result[TestOutputBindingName]); } finally { FunctionMetadata.UnregisterFunctionMetadata(testManager.InstanceId); } }
public void InvokeBasicFunctionWithRequiresWorks() { string path = Path.Join(s_funcDirectory, "testBasicFunctionWithRequires.ps1"); var(functionInfo, testManager) = PrepareFunction(path, string.Empty); try { FunctionMetadata.RegisterFunctionMetadata(testManager.InstanceId, functionInfo); Hashtable result = InvokeFunction(testManager, functionInfo); // The outputBinding hashtable for the runspace should be cleared after 'InvokeFunction' Hashtable outputBindings = FunctionMetadata.GetOutputBindingHashtable(testManager.InstanceId); Assert.Empty(outputBindings); // When function script has #requires, not PowerShell function will be created for the Az function, // and the invocation uses the file path directly. string expectedResult = $"{TestStringData},ThreadJob,testBasicFunctionWithRequires.ps1"; Assert.Equal(expectedResult, result[TestOutputBindingName]); } finally { FunctionMetadata.UnregisterFunctionMetadata(testManager.InstanceId); } }
public Hashtable InvokeFunction( AzFunctionInfo functionInfo, Hashtable triggerMetadata, TraceContext traceContext, RetryContext retryContext, IList <ParameterBinding> inputData, FunctionInvocationPerformanceStopwatch stopwatch) { var outputBindings = FunctionMetadata.GetOutputBindingHashtable(_pwsh.Runspace.InstanceId); var durableController = new DurableController(functionInfo.DurableFunctionInfo, _pwsh); try { durableController.BeforeFunctionInvocation(inputData); AddEntryPointInvocationCommand(functionInfo); stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.FunctionCodeReady); SetInputBindingParameterValues(functionInfo, inputData, durableController, triggerMetadata, traceContext, retryContext); stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.InputBindingValuesReady); if (!durableController.ShouldSuppressPipelineTraces()) { _pwsh.AddCommand("Microsoft.Azure.Functions.PowerShellWorker\\Trace-PipelineObject"); } stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.InvokingFunctionCode); Logger.Log(isUserOnlyLog: false, LogLevel.Trace, CreateInvocationPerformanceReportMessage(functionInfo.FuncName, stopwatch)); try { return(durableController.TryInvokeOrchestrationFunction(out var result) ? result : InvokeNonOrchestrationFunction(durableController, outputBindings)); } catch (RuntimeException e) { ErrorAnalysisLogger.Log(Logger, e.ErrorRecord, isException: true); Logger.Log(isUserOnlyLog: true, LogLevel.Error, GetFunctionExceptionMessage(e)); throw; } catch (OrchestrationFailureException e) { if (e.InnerException is IContainsErrorRecord inner) { Logger.Log(isUserOnlyLog: true, LogLevel.Error, GetFunctionExceptionMessage(inner)); } throw; } } finally { durableController.AfterFunctionInvocation(); outputBindings.Clear(); ResetRunspace(); } }
public void InvokeFunctionWithEntryPointWorks() { string path = Path.Join(s_funcDirectory, "testFunctionWithEntryPoint.psm1"); var(functionInfo, testManager) = PrepareFunction(path, "Run"); try { FunctionMetadata.RegisterFunctionMetadata(testManager.InstanceId, functionInfo); Hashtable result = InvokeFunction(testManager, functionInfo); // The outputBinding hashtable for the runspace should be cleared after 'InvokeFunction' Hashtable outputBindings = FunctionMetadata.GetOutputBindingHashtable(testManager.InstanceId); Assert.Empty(outputBindings); string expectedResult = $"{TestStringData},Run"; Assert.Equal(expectedResult, result[TestOutputBindingName]); } finally { FunctionMetadata.UnregisterFunctionMetadata(testManager.InstanceId); } }
public void InvokeFunctionWithSpecialVariableWorks() { string path = Path.Join(s_funcDirectory, "testBasicFunctionSpecialVariables.ps1"); var(functionInfo, testManager) = PrepareFunction(path, string.Empty); try { FunctionMetadata.RegisterFunctionMetadata(testManager.InstanceId, functionInfo); Hashtable result = InvokeFunction(testManager, functionInfo); // The outputBinding hashtable for the runspace should be cleared after 'InvokeFunction' Hashtable outputBindings = FunctionMetadata.GetOutputBindingHashtable(testManager.InstanceId); Assert.Empty(outputBindings); // A PowerShell function should be created fro the Az function. string expectedResult = $"{s_funcDirectory},{path},{functionInfo.DeployedPSFuncName}"; Assert.Equal(expectedResult, result[TestOutputBindingName]); } finally { FunctionMetadata.UnregisterFunctionMetadata(testManager.InstanceId); } }
/// <summary> /// Execution a function fired by a trigger or an activity function scheduled by an orchestration. /// </summary> internal Hashtable InvokeFunction( AzFunctionInfo functionInfo, Hashtable triggerMetadata, TraceContext traceContext, IList <ParameterBinding> inputData, FunctionInvocationPerformanceStopwatch stopwatch) { string scriptPath = functionInfo.ScriptPath; string entryPoint = functionInfo.EntryPoint; var hasSetInvocationContext = false; Hashtable outputBindings = FunctionMetadata.GetOutputBindingHashtable(_pwsh.Runspace.InstanceId); try { if (Utils.AreDurableFunctionsEnabled()) { // If the function has a output binding of the 'orchestrationClient' type, then we set the binding name // in the module context for the 'Start-NewOrchestration' function to use. if (!string.IsNullOrEmpty(functionInfo.OrchestrationClientBindingName)) { _pwsh.AddCommand("Microsoft.Azure.Functions.PowerShellWorker\\Set-FunctionInvocationContext") .AddParameter("OrchestrationStarter", functionInfo.OrchestrationClientBindingName) .InvokeAndClearCommands(); hasSetInvocationContext = true; } } if (string.IsNullOrEmpty(entryPoint)) { _pwsh.AddCommand(functionInfo.DeployedPSFuncName ?? scriptPath); } else { // If an entry point is defined, we import the script module. _pwsh.AddCommand(Utils.ImportModuleCmdletInfo) .AddParameter("Name", scriptPath) .InvokeAndClearCommands(); _pwsh.AddCommand(entryPoint); } stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.FunctionCodeReady); // Set arguments for each input binding parameter foreach (ParameterBinding binding in inputData) { string bindingName = binding.Name; if (functionInfo.FuncParameters.TryGetValue(bindingName, out PSScriptParamInfo paramInfo)) { var bindingInfo = functionInfo.InputBindings[bindingName]; var valueToUse = Utils.TransformInBindingValueAsNeeded(paramInfo, bindingInfo, binding.Data.ToObject()); _pwsh.AddParameter(bindingName, valueToUse); } } stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.InputBindingValuesReady); // Gives access to additional Trigger Metadata if the user specifies TriggerMetadata if (functionInfo.HasTriggerMetadataParam) { _pwsh.AddParameter(AzFunctionInfo.TriggerMetadata, triggerMetadata); } if (functionInfo.HasTraceContextParam) { _pwsh.AddParameter(AzFunctionInfo.TraceContext, traceContext); } _pwsh.AddCommand("Microsoft.Azure.Functions.PowerShellWorker\\Trace-PipelineObject"); stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.InvokingFunctionCode); Logger.Log(isUserOnlyLog: false, LogLevel.Trace, CreateInvocationPerformanceReportMessage(functionInfo.FuncName, stopwatch)); Collection <object> pipelineItems = null; try { pipelineItems = _pwsh.InvokeAndClearCommands <object>(); } catch (RuntimeException e) { if (e.ErrorRecord.FullyQualifiedErrorId == "CommandNotFoundException") { Logger.Log(isUserOnlyLog: false, LogLevel.Warning, PowerShellWorkerStrings.CommandNotFoundException_Exception); } Logger.Log(isUserOnlyLog: true, LogLevel.Error, GetFunctionExceptionMessage(e)); throw; } Hashtable result = new Hashtable(outputBindings, StringComparer.OrdinalIgnoreCase); if (Utils.AreDurableFunctionsEnabled() && functionInfo.Type == AzFunctionType.ActivityFunction) { var returnValue = CreateReturnValueFromFunctionOutput(pipelineItems); result.Add(AzFunctionInfo.DollarReturn, returnValue); } return(result); } finally { if (hasSetInvocationContext) { ClearInvocationContext(); } outputBindings.Clear(); ResetRunspace(); } }
/// <summary> /// BeginProcessing override. /// </summary> protected override void BeginProcessing() { _retHashtable = new Hashtable(StringComparer.OrdinalIgnoreCase); _outputBindings = FunctionMetadata.GetOutputBindingHashtable(Runspace.DefaultRunspace.InstanceId); }
/// <summary> /// Execution a function fired by a trigger or an activity function scheduled by an orchestration. /// </summary> internal Hashtable InvokeFunction( AzFunctionInfo functionInfo, Hashtable triggerMetadata, IList <ParameterBinding> inputData) { string scriptPath = functionInfo.ScriptPath; string entryPoint = functionInfo.EntryPoint; Hashtable outputBindings = FunctionMetadata.GetOutputBindingHashtable(_pwsh.Runspace.InstanceId); try { if (string.IsNullOrEmpty(entryPoint)) { _pwsh.AddCommand(functionInfo.DeployedPSFuncName ?? scriptPath); } else { // If an entry point is defined, we import the script module. _pwsh.AddCommand(Utils.ImportModuleCmdletInfo) .AddParameter("Name", scriptPath) .InvokeAndClearCommands(); _pwsh.AddCommand(entryPoint); } // Set arguments for each input binding parameter foreach (ParameterBinding binding in inputData) { string bindingName = binding.Name; if (functionInfo.FuncParameters.TryGetValue(bindingName, out PSScriptParamInfo paramInfo)) { var bindingInfo = functionInfo.InputBindings[bindingName]; var valueToUse = Utils.TransformInBindingValueAsNeeded(paramInfo, bindingInfo, binding.Data.ToObject()); _pwsh.AddParameter(bindingName, valueToUse); } } // Gives access to additional Trigger Metadata if the user specifies TriggerMetadata if (functionInfo.HasTriggerMetadataParam) { _pwsh.AddParameter(AzFunctionInfo.TriggerMetadata, triggerMetadata); } Collection <object> pipelineItems = _pwsh.AddCommand("Microsoft.Azure.Functions.PowerShellWorker\\Trace-PipelineObject") .InvokeAndClearCommands <object>(); Hashtable result = new Hashtable(outputBindings, StringComparer.OrdinalIgnoreCase); /* * TODO: See GitHub issue #82. We are not settled on how to handle the Azure Functions concept of the $returns Output Binding * if (pipelineItems != null && pipelineItems.Count > 0) * { * // If we would like to support Option 1 from #82, use the following 3 lines of code: * object[] items = new object[pipelineItems.Count]; * pipelineItems.CopyTo(items, 0); * result.Add(AzFunctionInfo.DollarReturn, items); * * // If we would like to support Option 2 from #82, use this line: * result.Add(AzFunctionInfo.DollarReturn, pipelineItems[pipelineItems.Count - 1]); * } */ return(result); } finally { outputBindings.Clear(); ResetRunspace(); } }
/// <summary> /// BeginProcessing override. /// </summary> protected override void BeginProcessing() { _bindingInfo = GetBindingInfo(Name); _behavior = GetDataCollectingBehavior(_bindingInfo); _outputBindings = FunctionMetadata.GetOutputBindingHashtable(Runspace.DefaultRunspace.InstanceId); }