public async Task CompilerError_IsRetried_UpToLimit() { // Create the invoker dependencies and setup the appropriate method to throw the exception RunDependencies dependencies = CreateDependencies(); // Set the host to primary dependencies.Host.SetupGet(h => h.IsPrimary).Returns(true); var metadata = new FunctionMetadata { ScriptFile = "run.csx", FunctionDirectory = "c:\\somedir", Name = Guid.NewGuid().ToString(), ScriptType = ScriptType.CSharp }; metadata.Bindings.Add(new BindingMetadata() { Name = "myQueueItem", Type = "ManualTrigger" }); var testBinding = new Mock <FunctionBinding>(null, new BindingMetadata() { Name = "TestBinding", Type = "blob" }, FileAccess.Write); var dotNetCompilation = new Mock <IDotNetCompilation>(); var dotnetCompilationService = new Mock <ICompilationService <IDotNetCompilation> >(); dotnetCompilationService.SetupSequence(s => s.GetFunctionCompilationAsync(It.IsAny <FunctionMetadata>())) .ThrowsAsync(new CompilationServiceException("1")) .ThrowsAsync(new CompilationServiceException("2")) .ThrowsAsync(new CompilationServiceException("3")) .ThrowsAsync(new CompilationServiceException("4")); // This should not be reached var compilationFactory = new Mock <ICompilationServiceFactory <ICompilationService <IDotNetCompilation>, IFunctionMetadataResolver> >(); compilationFactory.Setup(f => f.CreateService(ScriptType.CSharp, It.IsAny <IFunctionMetadataResolver>())).Returns(dotnetCompilationService.Object); var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <FunctionBinding>(), new Collection <FunctionBinding> { testBinding.Object }, new FunctionEntryPointResolver(), new FunctionAssemblyLoader(string.Empty), compilationFactory.Object, new Mock <IFunctionMetadataResolver>().Object); var arguments = new object[] { new ExecutionContext() { FunctionDirectory = "c:\\test", FunctionName = "test", InvocationId = Guid.NewGuid() } }; for (int i = 1; i <= 10; i++) { var expectedAttempt = Math.Min(i, 3); CompilationServiceException exception = await Assert.ThrowsAsync <CompilationServiceException>(() => invoker.Invoke(arguments)); Assert.Equal(expectedAttempt.ToString(), exception.Message); } var compilerErrorTraces = dependencies.LoggerProvider.GetAllLogMessages() .Where(t => string.Equals(t.FormattedMessage, "Function loader reset. Failed compilation result will not be cached.")); // 3 attempts total, make sure we've logged the 2 retries. Assert.Equal(2, compilerErrorTraces.Count()); }
public async Task Compilation_WithMissingBindingArguments_LogsAF004Warning(IDictionary <string, string> environment) { using (var testEnvironment = new TestScopedEnvironmentVariable(environment)) { // Create the compilation exception we expect to throw during the reload string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(rootFunctionsFolder); // Create the invoker dependencies and setup the appropriate method to throw the exception RunDependencies dependencies = CreateDependencies(); // Create a dummy file to represent our function string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx"); File.WriteAllText(filePath, Resources.TestFunctionWithMissingBindingArgumentsCode); var metadata = new FunctionMetadata { ScriptFile = filePath, FunctionDirectory = Path.GetDirectoryName(filePath), Name = Guid.NewGuid().ToString(), ScriptType = ScriptType.CSharp }; metadata.Bindings.Add(new BindingMetadata() { Name = "myQueueItem", Type = "ManualTrigger" }); var testBinding = new Mock <FunctionBinding>(null, new BindingMetadata() { Name = "TestBinding", Type = "blob" }, FileAccess.Write); var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <FunctionBinding>(), new Collection <FunctionBinding> { testBinding.Object }, new FunctionEntryPointResolver(), new FunctionAssemblyLoader(string.Empty), new DotNetCompilationServiceFactory(null)); try { await invoker.GetFunctionTargetAsync(); } catch (CompilationErrorException exc) { var builder = new StringBuilder(); builder.AppendLine(Resources.TestFunctionWithMissingBindingArgumentsCode); builder.AppendLine(); string compilationDetails = exc.Diagnostics.Aggregate( builder, (a, d) => a.AppendLine(d.ToString()), a => a.ToString()); throw new Exception(compilationDetails, exc); } Assert.Contains(dependencies.LoggerProvider.GetAllLogMessages(), t => t.FormattedMessage.Contains($"warning {DotNetConstants.MissingBindingArgumentCompilationCode}") && t.FormattedMessage.Contains("'TestBinding'")); } }
public async Task Compilation_OnSecondaryHost_SuppressesLogs(IDictionary <string, string> environment) { using (new TestScopedEnvironmentVariable(environment)) { // Create the compilation exception we expect to throw during the reload string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(rootFunctionsFolder); // Create the invoker dependencies and setup the appropriate method to throw the exception RunDependencies dependencies = CreateDependencies(); // Set the host to secondary dependencies.Host.SetupGet(h => h.IsPrimary).Returns(false); // Create a dummy file to represent our function string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx"); File.WriteAllText(filePath, Resources.TestFunctionWithMissingBindingArgumentsCode); var metadata = new FunctionMetadata { ScriptFile = filePath, FunctionDirectory = Path.GetDirectoryName(filePath), Name = Guid.NewGuid().ToString(), ScriptType = ScriptType.CSharp }; metadata.Bindings.Add(new BindingMetadata() { Name = "myQueueItem", Type = "ManualTrigger" }); var testBinding = new Mock <FunctionBinding>(null, new BindingMetadata() { Name = "TestBinding", Type = "blob" }, FileAccess.Write); var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <FunctionBinding>(), new Collection <FunctionBinding> { testBinding.Object }, new FunctionEntryPointResolver(), new FunctionAssemblyLoader(string.Empty), new DotNetCompilationServiceFactory(null)); try { await invoker.GetFunctionTargetAsync(); } catch (CompilationErrorException exc) { var builder = new StringBuilder(); builder.AppendLine(Resources.TestFunctionWithMissingBindingArgumentsCode); builder.AppendLine(); string compilationDetails = exc.Diagnostics.Aggregate( builder, (a, d) => a.AppendLine(d.ToString()), a => a.ToString()); throw new Exception(compilationDetails, exc); } // Verify that we send the log, but that it has MS_PrimaryHost set so the logger can filter appropriately. var logMessage = dependencies.LoggerProvider.GetAllLogMessages().Single(); Assert.True((bool)logMessage.State.Single(k => k.Key == ScriptConstants.LogPropertyPrimaryHostKey).Value); } }
private FuncPtg(int funcIndex, FunctionMetadata fm) : base(funcIndex, fm.ReturnClassCode, fm.ParameterClassCodes, fm.MinParams) // minParams same as max since these are not var-arg funcs { { }
public MockInvoker(ScriptHost host, IMetricsLogger metrics, FunctionMetadata metadata) : base(host, metadata) { _fastLogger = new FunctionInstanceLogger( (name) => this.Host.GetFunctionOrNull(name), metrics); }
/// <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; 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 outputBindings = FunctionMetadata.GetOutputBindingHashtable(_pwsh.Runspace.InstanceId); Hashtable result = new Hashtable(outputBindings, StringComparer.OrdinalIgnoreCase); outputBindings.Clear(); /* * 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 { ResetRunspace(); } }
public bool TryGetFunctionMetadata(string functionName, out FunctionMetadata functionMetadata, bool forceRefresh) { functionMetadata = _functions.FirstOrDefault(p => Utility.FunctionNamesMatch(p.Name, functionName)); return(functionMetadata != null); }
public async Task Generate_EndToEnd() { // construct our TimerTrigger attribute ([TimerTrigger("00:00:02", RunOnStartup = true)]) Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>(); ParameterDescriptor parameter = new ParameterDescriptor("timerInfo", typeof(TimerInfo)); ConstructorInfo ctorInfo = typeof(TimerTriggerAttribute).GetConstructor(new Type[] { typeof(string) }); PropertyInfo runOnStartupProperty = typeof(TimerTriggerAttribute).GetProperty("RunOnStartup"); CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder( ctorInfo, new object[] { "00:00:02" }, new PropertyInfo[] { runOnStartupProperty }, new object[] { true }); parameter.CustomAttributes.Add(attributeBuilder); parameters.Add(parameter); // create the FunctionDefinition FunctionMetadata metadata = new FunctionMetadata(); TestInvoker invoker = new TestInvoker(); FunctionDescriptor function = new FunctionDescriptor("TimerFunction", invoker, metadata, parameters, null, null, null); Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>(); functions.Add(function); // Get the Type Attributes (in this case, a TimeoutAttribute) ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration(); scriptConfig.FunctionTimeout = TimeSpan.FromMinutes(5); Collection <CustomAttributeBuilder> typeAttributes = ScriptHost.CreateTypeAttributes(scriptConfig); // generate the Type Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", typeAttributes, functions); // verify the generated function MethodInfo method = functionType.GetMethod("TimerFunction"); TimeoutAttribute timeoutAttribute = (TimeoutAttribute)functionType.GetCustomAttributes().Single(); Assert.Equal(TimeSpan.FromMinutes(5), timeoutAttribute.Timeout); Assert.True(timeoutAttribute.ThrowOnTimeout); Assert.True(timeoutAttribute.TimeoutWhileDebugging); ParameterInfo triggerParameter = method.GetParameters()[0]; TimerTriggerAttribute triggerAttribute = triggerParameter.GetCustomAttribute <TimerTriggerAttribute>(); Assert.NotNull(triggerAttribute); // start the JobHost which will start running the timer function JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new TypeLocator(functionType) }; config.UseTimers(); JobHost host = new JobHost(config); await host.StartAsync(); await Task.Delay(3000); await host.StopAsync(); // verify our custom invoker was called Assert.True(invoker.InvokeCount >= 2); }
/// <summary> /// Maps FunctionMetadata to FunctionMetadataResponse. /// </summary> /// <param name="functionMetadata">FunctionMetadata to be mapped.</param> /// <param name="request">Current HttpRequest</param> /// <param name="config">ScriptHostConfig</param> /// <returns>Promise of a FunctionMetadataResponse</returns> public static async Task <FunctionMetadataResponse> ToFunctionMetadataResponse(this FunctionMetadata functionMetadata, HttpRequest request, ScriptHostConfiguration config, IWebJobsRouter router = null) { var functionPath = Path.Combine(config.RootScriptPath, functionMetadata.Name); var functionMetadataFilePath = Path.Combine(functionPath, ScriptConstants.FunctionMetadataFileName); var baseUrl = request != null ? $"{request.Scheme}://{request.Host}" : "https://localhost/"; var response = new FunctionMetadataResponse { Name = functionMetadata.Name, // Q: can functionMetadata.ScriptFile be null or empty? ScriptHref = VirtualFileSystem.FilePathToVfsUri(Path.Combine(config.RootScriptPath, functionMetadata.ScriptFile), baseUrl, config), ConfigHref = VirtualFileSystem.FilePathToVfsUri(functionMetadataFilePath, baseUrl, config), ScriptRootPathHref = VirtualFileSystem.FilePathToVfsUri(functionPath, baseUrl, config, isDirectory: true), TestDataHref = VirtualFileSystem.FilePathToVfsUri(functionMetadata.GetTestDataFilePath(config), baseUrl, config), Href = GetFunctionHref(functionMetadata.Name, baseUrl), TestData = await GetTestData(functionMetadata.GetTestDataFilePath(config), config), Config = await GetFunctionConfig(functionMetadataFilePath), // Properties below this comment are not present in the kudu version. IsDirect = functionMetadata.IsDirect, IsDisabled = functionMetadata.IsDisabled, IsProxy = functionMetadata.IsProxy, InvokeUrlTemplate = GetFunctionInvokeUrlTemplate(baseUrl, functionMetadata.Name, router) }; return(response); }
public static ScriptInvocationContext GetScriptInvocationContext(string functionName, Guid invocationId, ILogger testLogger, DataType dataType = DataType.String) { ScriptInvocationContext scriptInvocationContext = new ScriptInvocationContext() { ExecutionContext = new ExecutionContext() { InvocationId = invocationId, FunctionName = functionName, }, BindingData = GetScriptInvocationBindingData(), Inputs = GetScriptInvocationInputs(), ResultSource = new TaskCompletionSource <ScriptInvocationResult>(), Logger = testLogger, AsyncExecutionContext = System.Threading.ExecutionContext.Capture() }; var functionMetadata = new FunctionMetadata { Name = functionName }; var httpTriggerBinding = new BindingMetadata { Name = "req", Type = "httpTrigger", Direction = BindingDirection.In, Raw = new JObject() }; var queueInputBinding = new BindingMetadata { Name = "queueInput", Type = "queue", Direction = BindingDirection.In, DataType = dataType }; var httpOutputBinding = new BindingMetadata { Name = "res", Type = "http", Direction = BindingDirection.Out, Raw = new JObject(), DataType = dataType }; var queueOutputBinding1 = new BindingMetadata { Name = "output1", Type = "queue", Direction = BindingDirection.Out, DataType = dataType }; var queueOutputBinding2 = new BindingMetadata { Name = "output2", Type = "queue", Direction = BindingDirection.Out, DataType = dataType }; var queueOutputRetrun = new BindingMetadata { Name = "$return", Type = "queue", Direction = BindingDirection.Out, DataType = dataType }; functionMetadata.Bindings.Add(httpTriggerBinding); functionMetadata.Bindings.Add(queueOutputBinding1); functionMetadata.Bindings.Add(queueOutputBinding2); functionMetadata.Bindings.Add(queueOutputRetrun); scriptInvocationContext.FunctionMetadata = functionMetadata; return(scriptInvocationContext); }
protected override IFunctionInvoker CreateFunctionInvoker(string scriptFilePath, BindingMetadata triggerMetadata, FunctionMetadata functionMetadata, Collection <FunctionBinding> inputBindings, Collection <FunctionBinding> outputBindings) { throw new NotImplementedException(); }
public MockInvoker(ScriptHost host, FunctionMetadata metadata) : base(host, metadata) { }
public async Task ToRpcInvocationRequest_Http_OmitsDuplicateBodyOfBindingData() { var logger = new TestLogger("test"); var httpContext = new DefaultHttpContext(); httpContext.Request.Host = new HostString("local"); httpContext.Request.Path = "/test"; httpContext.Request.Method = "Post"; var inputs = new List <(string name, DataType type, object val)> { ("req", DataType.String, httpContext.Request) }; var bindingData = new Dictionary <string, object> { { "req", httpContext.Request }, { "$request", httpContext.Request }, { "headers", httpContext.Request.Headers.ToDictionary(p => p.Key, p => p.Value) }, { "query", httpContext.Request.QueryString.ToString() }, { "sys", new SystemBindingData() } }; var invocationContext = new ScriptInvocationContext() { ExecutionContext = new ExecutionContext() { InvocationId = Guid.NewGuid(), FunctionName = "Test", }, BindingData = bindingData, Inputs = inputs, ResultSource = new TaskCompletionSource <ScriptInvocationResult>(), Logger = logger, AsyncExecutionContext = System.Threading.ExecutionContext.Capture() }; var functionMetadata = new FunctionMetadata { Name = "Test" }; var httpTriggerBinding = new BindingMetadata { Name = "req", Type = "httpTrigger", Direction = BindingDirection.In, Raw = new JObject() }; var httpOutputBinding = new BindingMetadata { Name = "res", Type = "http", Direction = BindingDirection.Out, Raw = new JObject(), DataType = DataType.String }; functionMetadata.Bindings.Add(httpTriggerBinding); functionMetadata.Bindings.Add(httpOutputBinding); invocationContext.FunctionMetadata = functionMetadata; Capabilities capabilities = new Capabilities(logger); MapField <string, string> addedCapabilities = new MapField <string, string> { { RpcWorkerConstants.RpcHttpTriggerMetadataRemoved, "1" }, { RpcWorkerConstants.RpcHttpBodyOnly, "1" } }; capabilities.UpdateCapabilities(addedCapabilities); var result = await invocationContext.ToRpcInvocationRequest(logger, capabilities); Assert.Equal(1, result.InputData.Count); Assert.Equal(3, result.TriggerMetadata.Count); Assert.True(result.TriggerMetadata.ContainsKey("headers")); Assert.True(result.TriggerMetadata.ContainsKey("query")); Assert.True(result.TriggerMetadata.ContainsKey("sys")); }
public MockInvoker(ScriptHost host, FunctionMetadata metadata, ITraceWriterFactory traceWriterFactory = null) : base(host, metadata, traceWriterFactory) { }
public async Task ReloadScript_WithInvalidCompilationAndMissingMethod_ReportsResults() { // Create the compilation exception we expect to throw during the reload var descriptor = new DiagnosticDescriptor(DotNetConstants.MissingFunctionEntryPointCompilationCode, "Test compilation exception", "Test compilation error", "AzureFunctions", DiagnosticSeverity.Error, true); var exception = new CompilationErrorException("Test compilation exception", ImmutableArray.Create(Diagnostic.Create(descriptor, Location.None))); // Create the invoker dependencies and setup the appropriate method to throw the exception RunDependencies dependencies = CreateDependencies(); dependencies.Compilation.Setup(c => c.GetEntryPointSignature(It.IsAny <IFunctionEntryPointResolver>())) .Throws(exception); dependencies.Compilation.Setup(c => c.EmitAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(typeof(object).Assembly); string functionName = Guid.NewGuid().ToString(); string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), functionName); Directory.CreateDirectory(rootFunctionsFolder); // Create a dummy file to represent our function string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx"); File.WriteAllText(filePath, string.Empty); var metadata = new FunctionMetadata { ScriptFile = filePath, FunctionDirectory = Path.GetDirectoryName(filePath), Name = functionName, ScriptType = ScriptType.CSharp }; metadata.Bindings.Add(new BindingMetadata() { Name = "Test", Type = "ManualTrigger" }); var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <Script.Binding.FunctionBinding>(), new Collection <FunctionBinding>(), dependencies.EntrypointResolver.Object, new FunctionAssemblyLoader(string.Empty), dependencies.CompilationServiceFactory.Object); // Send file change notification to trigger a reload var fileEventArgs = new FileSystemEventArgs(WatcherChangeTypes.Changed, Path.GetTempPath(), Path.Combine(Path.GetFileName(rootFunctionsFolder), Path.GetFileName(filePath))); dependencies.Host.Object.EventManager.Publish(new FileEvent(EventSources.ScriptFiles, fileEventArgs)); await TestHelpers.Await(() => { IEnumerable <LogMessage> logMessages = dependencies.LoggerProvider.GetAllLogMessages(); return(logMessages.Any(t => t.FormattedMessage.Contains("Compilation failed.")) && logMessages.Any(t => t.FormattedMessage.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); dependencies.LoggerProvider.ClearAllLogMessages(); CompilationErrorException resultException = await Assert.ThrowsAsync <CompilationErrorException>(() => invoker.GetFunctionTargetAsync()); await TestHelpers.Await(() => { IEnumerable <LogMessage> logMessages = dependencies.LoggerProvider.GetAllLogMessages(); return(logMessages.Any(t => t.FormattedMessage.Contains("Function compilation error")) && logMessages.Any(t => t.FormattedMessage.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); }
public static string GetTestDataFilePath(this FunctionMetadata functionMetadata, ScriptHostConfiguration config) => GetTestDataFilePath(functionMetadata.Name, config);
internal static bool TryParseFunctionMetadata(string functionName, JObject functionConfig, Dictionary <string, HttpTriggerBindingMetadata> mappedHttpFunctions, TraceWriter traceWriter, Lazy <string[]> functionFilesProvider, out FunctionMetadata functionMetadata, out string error) { error = null; functionMetadata = ParseFunctionMetadata(functionName, functionConfig); if (functionMetadata.IsExcluded) { traceWriter.Info(string.Format("Function '{0}' is marked as excluded", functionName)); functionMetadata = null; return(true); } if (functionMetadata.IsDisabled) { traceWriter.Info(string.Format("Function '{0}' is disabled", functionName)); } // determine the primary script string[] functionFiles = functionFilesProvider.Value; if (functionFiles.Length == 0) { error = "No function script files present."; return(false); } string scriptFile = DeterminePrimaryScriptFile(functionConfig, functionFiles); if (string.IsNullOrEmpty(scriptFile)) { error = "Unable to determine the primary function script. Try renaming your entry point script to 'run' (or 'index' in the case of Node), " + "or alternatively you can specify the name of the entry point script explicitly by adding a 'scriptFile' property to your function metadata."; return(false); } functionMetadata.ScriptFile = scriptFile; // determine the script type based on the primary script file extension functionMetadata.ScriptType = ParseScriptType(functionMetadata.ScriptFile); functionMetadata.EntryPoint = (string)functionConfig["entryPoint"]; var httpTriggerBindingMetadata = functionMetadata.InputBindings.OfType <HttpTriggerBindingMetadata>().SingleOrDefault(); if (httpTriggerBindingMetadata != null) { if (string.IsNullOrWhiteSpace(httpTriggerBindingMetadata.Route)) { // if no explicit route is provided, default to the function name httpTriggerBindingMetadata.Route = functionName; } // disallow custom routes in our own reserved route space string httpRoute = httpTriggerBindingMetadata.Route.Trim('/').ToLowerInvariant(); if (httpRoute.StartsWith("admin")) { error = "The specified route conflicts with one or more built in routes."; return(false); } // prevent duplicate/conflicting routes foreach (var pair in mappedHttpFunctions) { if (HttpRoutesConflict(httpTriggerBindingMetadata, pair.Value)) { error = $"The route specified conflicts with the route defined by function '{pair.Key}'."; return(false); } } mappedHttpFunctions.Add(functionName, httpTriggerBindingMetadata); } return(true); }
private Collection <FunctionDescriptor> ReadFunctions(ScriptHostConfiguration config, IEnumerable <FunctionDescriptorProvider> descriptorProviders) { string scriptRootPath = config.RootScriptPath; List <FunctionMetadata> metadatas = new List <FunctionMetadata>(); foreach (var scriptDir in Directory.EnumerateDirectories(scriptRootPath)) { string functionName = null; try { // read the function config string functionConfigPath = Path.Combine(scriptDir, ScriptConstants.FunctionMetadataFileName); if (!File.Exists(functionConfigPath)) { // not a function directory continue; } functionName = Path.GetFileNameWithoutExtension(scriptDir); if (ScriptConfig.Functions != null && !ScriptConfig.Functions.Contains(functionName, StringComparer.OrdinalIgnoreCase)) { // a functions filter has been specified and the current function is // not in the filter list continue; } ValidateFunctionName(functionName); // TODO: we need to define a json schema document and do // schema validation and give more informative responses string json = File.ReadAllText(functionConfigPath); JObject functionConfig = JObject.Parse(json); FunctionMetadata metadata = ParseFunctionMetadata(functionName, functionConfig); if (metadata.IsExcluded) { TraceWriter.Info(string.Format("Function '{0}' is marked as excluded", functionName)); continue; } if (metadata.IsDisabled) { TraceWriter.Info(string.Format("Function '{0}' is disabled", functionName)); } // determine the primary script string[] functionFiles = Directory.EnumerateFiles(scriptDir).Where(p => Path.GetFileName(p).ToLowerInvariant() != ScriptConstants.FunctionMetadataFileName).ToArray(); if (functionFiles.Length == 0) { AddFunctionError(functionName, "No function script files present."); continue; } string scriptFile = DeterminePrimaryScriptFile(functionConfig, functionFiles); if (string.IsNullOrEmpty(scriptFile)) { AddFunctionError(functionName, "Unable to determine the primary function script. Try renaming your entry point script to 'run' (or 'index' in the case of Node), " + "or alternatively you can specify the name of the entry point script explicitly by adding a 'scriptFile' property to your function metadata."); continue; } metadata.ScriptFile = scriptFile; // determine the script type based on the primary script file extension metadata.ScriptType = ParseScriptType(metadata.ScriptFile); metadata.EntryPoint = (string)functionConfig["entryPoint"]; metadatas.Add(metadata); } catch (Exception ex) { // log any unhandled exceptions and continue AddFunctionError(functionName, ex.Message); } } return(ReadFunctions(metadatas, descriptorProviders)); }
public override RfcPreparedFunction PrepareFunction(string functionName) { FunctionMetadata metadata = this.metadataCache.GetFunctionMetadata(functionName); return(new SoapRfcPreparedFunction(metadata, this.structureMapper, this._webClient)); }
public MockInvoker(ScriptHost host, IMetricsLogger metrics, IFunctionMetadataManager functionMetadataManager, FunctionMetadata metadata, ILoggerFactory loggerFactory) : base(host, metadata, loggerFactory) { _instanceLogger = new FunctionInstanceLogger(functionMetadataManager, metrics); }