private static bool TryParseFunctionBinding(ScriptHostConfiguration config, Newtonsoft.Json.Linq.JObject metadata, out FunctionBinding functionBinding)
        {
            functionBinding = null;

            ScriptBindingContext bindingContext = new ScriptBindingContext(metadata);
            ScriptBinding        scriptBinding  = null;

            foreach (var provider in config.BindingProviders)
            {
                if (provider.TryCreate(bindingContext, out scriptBinding))
                {
                    break;
                }
            }

            if (scriptBinding == null)
            {
                return(false);
            }

            BindingMetadata bindingMetadata = BindingMetadata.Create(metadata);

            functionBinding = new ExtensionBinding(config, scriptBinding, bindingMetadata);

            return(true);
        }
        public static FunctionMetadata GetSampleMetadata(string functionName)
        {
            Func <HttpRequest, ILogger, Task <IActionResult> > invokeFunction = MyFunction;
            string endToendAssemblySuffix = "WebHostEndToEnd";

            var functionMetadata = new FunctionMetadata
            {
                Name = functionName,
                FunctionDirectory = null,
                ScriptFile        = $"assembly:{Assembly.GetExecutingAssembly().FullName}",
                EntryPoint        = $"{Assembly.GetExecutingAssembly().GetName().Name}.{endToendAssemblySuffix}.{typeof(CodelessEndToEndTests_Data).Name}.{invokeFunction.Method.Name}",
                Language          = "DotNetAssembly"
            };

            JObject functionConfig = JObject.Parse(_sampleBindingsJson);
            JArray  bindingArray   = (JArray)functionConfig["bindings"];

            foreach (JObject binding in bindingArray)
            {
                BindingMetadata bindingMetadata = BindingMetadata.Create(binding);
                functionMetadata.Bindings.Add(bindingMetadata);
            }

            return(functionMetadata);
        }
        public void GenerateServiceBusTriggerFunction()
        {
            BindingMetadata trigger = BindingMetadata.Create(new JObject
            {
                { "type", "ServiceBusTrigger" },
                { "name", "input" },
                { "direction", "in" },
                { "topicName", "testTopic" },
                { "subscriptionName", "testSubscription" },
                { "accessRights", "Listen" }
            });
            MethodInfo method = GenerateMethod(trigger);

            VerifyCommonProperties(method);

            // verify trigger parameter
            ParameterInfo parameter = method.GetParameters()[0];

            Assert.Equal("input", parameter.Name);
            Assert.Equal(typeof(string), parameter.ParameterType);
            ServiceBusTriggerAttribute attribute = parameter.GetCustomAttribute <ServiceBusTriggerAttribute>();

            Assert.Equal(null, attribute.QueueName);
            Assert.Equal("testTopic", attribute.TopicName);
            Assert.Equal("testSubscription", attribute.SubscriptionName);
            Assert.Equal(AccessRights.Listen, attribute.Access);
        }
        private static bool TryParseFunctionBinding(ScriptJobHostOptions config, IEnumerable <IScriptBindingProvider> bindingProviders, JObject metadata, out FunctionBinding functionBinding)
        {
            functionBinding = null;

            ScriptBindingContext bindingContext = new ScriptBindingContext(metadata);
            ScriptBinding        scriptBinding  = null;

            foreach (var provider in bindingProviders)
            {
                if (provider.TryCreate(bindingContext, out scriptBinding))
                {
                    break;
                }
            }

            if (scriptBinding == null)
            {
                return(false);
            }

            BindingMetadata bindingMetadata = BindingMetadata.Create(metadata);

            functionBinding = new ExtensionBinding(config, scriptBinding, bindingMetadata);

            return(true);
        }
        public async Task ToFunctionTrigger_Codeless_ReturnsExpected()
        {
            var functionMetadata = new FunctionMetadata
            {
                Name = "TestFunction1"
            };
            var options = new ScriptJobHostOptions
            {
                RootScriptPath = _testRootScriptPath
            };

            functionMetadata.SetIsCodeless(true);

            JObject functionConfig = JObject.Parse(_sampleBindingsJson);
            JArray  bindingArray   = (JArray)functionConfig["bindings"];

            foreach (JObject binding in bindingArray)
            {
                BindingMetadata bindingMetadata = BindingMetadata.Create(binding);
                functionMetadata.Bindings.Add(bindingMetadata);
            }

            var result = await functionMetadata.ToFunctionTrigger(options);

            Assert.Equal("TestFunction1", result["functionName"].Value <string>());
            Assert.Equal("httpTrigger", result["type"].Value <string>());

            // make sure original binding did not change
            Assert.Null(functionMetadata.Bindings[0].Raw["functionName"]?.Value <string>());
            Assert.Equal("httpTrigger", functionMetadata.Bindings[0].Raw["type"].Value <string>());
        }
Example #6
0
        private static (Collection <FunctionMetadata>, ProxyClientExecutor) LoadProxyMetadata(string proxiesJson, Dictionary <string, ICollection <string> > functionErrors, ILogger logger)
        {
            var proxies = new Collection <FunctionMetadata>();
            ProxyClientExecutor client = null;

            var rawProxyClient = ProxyClientFactory.Create(proxiesJson, logger);

            if (rawProxyClient != null)
            {
                client = new ProxyClientExecutor(rawProxyClient);
            }

            if (client == null)
            {
                return(proxies, null);
            }

            var routes = client.GetProxyData();

            foreach (var route in routes.Routes)
            {
                try
                {
                    // Proxy names should follow the same naming restrictions as in function names. If not, invalid characters will be removed.
                    var proxyName = NormalizeProxyName(route.Name);

                    var proxyMetadata = new FunctionMetadata();

                    var json = new JObject
                    {
                        { "authLevel", "anonymous" },
                        { "name", "req" },
                        { "type", "httptrigger" },
                        { "direction", "in" },
                        { "Route", route.UrlTemplate.TrimStart('/') },
                        { "Methods", new JArray(route.Methods.Select(m => m.Method.ToString()).ToArray()) }
                    };

                    BindingMetadata bindingMetadata = BindingMetadata.Create(json);

                    proxyMetadata.Bindings.Add(bindingMetadata);

                    proxyMetadata.Name    = proxyName;
                    proxyMetadata.IsProxy = true;

                    proxies.Add(proxyMetadata);
                }
                catch (Exception ex)
                {
                    // log any unhandled exceptions and continue
                    Utility.AddFunctionError(functionErrors, route.Name, Utility.FlattenException(ex, includeSource: false), isFunctionShortName: true);
                }
            }

            return(proxies, client);
        }
Example #7
0
        private void AddSampleBindings(FunctionMetadata functionMetadata)
        {
            JObject functionConfig = JObject.Parse(_sampleBindingsJson);
            JArray  bindingArray   = (JArray)functionConfig["bindings"];

            foreach (JObject binding in bindingArray)
            {
                BindingMetadata bindingMetadata = BindingMetadata.Create(binding);
                functionMetadata.Bindings.Add(bindingMetadata);
            }
        }
        public static FunctionBinding CreateTestBinding(JObject json)
        {
            ScriptBindingContext             context  = new ScriptBindingContext(json);
            WebJobsCoreScriptBindingProvider provider = new WebJobsCoreScriptBindingProvider(new JobHostConfiguration(), new JObject(), null);
            ScriptBinding scriptBinding = null;

            provider.TryCreate(context, out scriptBinding);
            BindingMetadata         bindingMetadata = BindingMetadata.Create(json);
            ScriptHostConfiguration config          = new ScriptHostConfiguration();

            return(new ExtensionBinding(config, scriptBinding, bindingMetadata));
        }
Example #9
0
        public static FunctionBinding CreateTestBinding(JObject json)
        {
            ScriptBindingContext             context  = new ScriptBindingContext(json);
            WebJobsCoreScriptBindingProvider provider = new WebJobsCoreScriptBindingProvider(NullLogger <WebJobsCoreScriptBindingProvider> .Instance);
            ScriptBinding scriptBinding = null;

            provider.TryCreate(context, out scriptBinding);
            BindingMetadata bindingMetadata = BindingMetadata.Create(json);
            var             config          = new ScriptJobHostOptions();

            return(new ExtensionBinding(config, scriptBinding, bindingMetadata));
        }
        private FunctionMetadata ParseFunctionMetadata(string functionName, JObject configMetadata, string scriptDirectory, IFileSystem fileSystem, IEnumerable <RpcWorkerConfig> workerConfigs)
        {
            var functionMetadata = new FunctionMetadata
            {
                Name = functionName,
                FunctionDirectory = scriptDirectory
            };

            JArray bindingArray = (JArray)configMetadata["bindings"];

            if (bindingArray == null || bindingArray.Count == 0)
            {
                throw new FormatException("At least one binding must be declared.");
            }

            if (bindingArray != null)
            {
                foreach (JObject binding in bindingArray)
                {
                    BindingMetadata bindingMetadata = BindingMetadata.Create(binding);
                    functionMetadata.Bindings.Add(bindingMetadata);
                }
            }

            JToken isDirect;

            if (configMetadata.TryGetValue("configurationSource", StringComparison.OrdinalIgnoreCase, out isDirect))
            {
                var isDirectValue = isDirect.ToString();
                if (string.Equals(isDirectValue, "attributes", StringComparison.OrdinalIgnoreCase))
                {
                    functionMetadata.SetIsDirect(true);
                }
                else if (!string.Equals(isDirectValue, "config", StringComparison.OrdinalIgnoreCase))
                {
                    throw new FormatException($"Illegal value '{isDirectValue}' for 'configurationSource' property in {functionMetadata.Name}'.");
                }
            }
            functionMetadata.ScriptFile = DeterminePrimaryScriptFile((string)configMetadata["scriptFile"], scriptDirectory, fileSystem);
            if (!string.IsNullOrWhiteSpace(functionMetadata.ScriptFile))
            {
                functionMetadata.Language = ParseLanguage(functionMetadata.ScriptFile, workerConfigs);
            }
            functionMetadata.EntryPoint = (string)configMetadata["entryPoint"];

            //Retry
            functionMetadata.Retry = configMetadata.Property(ConfigurationSectionNames.Retry)?.Value?.ToObject <RetryOptions>();
            Utility.ValidateRetryOptions(functionMetadata.Retry);

            return(functionMetadata);
        }
Example #11
0
        public void CreateTriggerParameter_WithNoBindingMatch_ThrowsExpectedException()
        {
            FunctionMetadata functionMetadata = new FunctionMetadata();
            BindingMetadata  metadata         = BindingMetadata.Create(JObject.Parse("{\"type\": \"someInvalidTrigger\",\"name\": \"req\",\"direction\": \"in\"}"));

            functionMetadata.Bindings.Add(metadata);

            var ex = Assert.Throws <FunctionConfigurationException>(() =>
            {
                _provider.TryCreate(functionMetadata, out FunctionDescriptor descriptor);
            });

            Assert.Contains("someInvalidTrigger", ex.Message);
        }
        public async Task VerifyResolvedBindings_WithNoBindingMatch_ThrowsExpectedException()
        {
            FunctionMetadata functionMetadata = new FunctionMetadata();
            BindingMetadata  triggerMetadata  = BindingMetadata.Create(JObject.Parse("{\"type\": \"blobTrigger\",\"name\": \"req\",\"direction\": \"in\", \"blobPath\": \"test\"}"));
            BindingMetadata  bindingMetadata  = BindingMetadata.Create(JObject.Parse("{\"type\": \"unknownbinding\",\"name\": \"blob\",\"direction\": \"in\"}"));

            functionMetadata.Bindings.Add(triggerMetadata);
            functionMetadata.Bindings.Add(bindingMetadata);

            var ex = await Assert.ThrowsAsync <FunctionConfigurationException>(async() =>
            {
                var(created, descriptor) = await _provider.TryCreate(functionMetadata);
            });

            Assert.Contains("The binding type(s) 'unknownbinding' are not registered", ex.Message);
        }
Example #13
0
        public void VerifyResolvedBindings_WithNoBindingMatch_ThrowsExpectedException()
        {
            FunctionMetadata functionMetadata = new FunctionMetadata();
            BindingMetadata  triggerMetadata  = BindingMetadata.Create(JObject.Parse("{\"type\": \"blobTrigger\",\"name\": \"req\",\"direction\": \"in\", \"blobPath\": \"test\"}"));
            BindingMetadata  bindingMetadata  = BindingMetadata.Create(JObject.Parse("{\"type\": \"unknownbinding\",\"name\": \"blob\",\"direction\": \"in\"}"));

            functionMetadata.Bindings.Add(triggerMetadata);
            functionMetadata.Bindings.Add(bindingMetadata);

            var ex = Assert.Throws <FunctionConfigurationException>(() =>
            {
                _provider.TryCreate(functionMetadata, out FunctionDescriptor descriptor);
            });

            Assert.Contains("unknownbinding", ex.Message);
        }
Example #14
0
        public void GenerateTimerTriggerFunction()
        {
            BindingMetadata trigger = BindingMetadata.Create(new JObject
            {
                { "type", "TimerTrigger" },
                { "name", "timerInfo" },
                { "schedule", "* * * * * *" },
                { "runOnStartup", true },
                { "direction", "in" }
            });
            MethodInfo method = GenerateMethod(trigger);

            VerifyCommonProperties(method);

            // verify trigger parameter
            ParameterInfo parameter = method.GetParameters()[0];

            Assert.Equal("timerInfo", parameter.Name);
            Assert.Equal(typeof(TimerInfo), parameter.ParameterType);
            TimerTriggerAttribute attribute = parameter.GetCustomAttribute <TimerTriggerAttribute>();

            Assert.Equal("* * * * * *", attribute.ScheduleExpression);
            Assert.True(attribute.UseMonitor);
            Assert.True(attribute.RunOnStartup);

            trigger = BindingMetadata.Create(new JObject
            {
                { "type", "TimerTrigger" },
                { "name", "timerInfo" },
                { "schedule", "* * * * * *" },
                { "useMonitor", false },
                { "direction", "in" }
            });
            method = GenerateMethod(trigger);

            VerifyCommonProperties(method);

            // verify trigger parameter
            parameter = method.GetParameters()[0];
            Assert.Equal("timerInfo", parameter.Name);
            Assert.Equal(typeof(TimerInfo), parameter.ParameterType);
            attribute = parameter.GetCustomAttribute <TimerTriggerAttribute>();
            Assert.Equal("* * * * * *", attribute.ScheduleExpression);
            Assert.False(attribute.UseMonitor);
            Assert.False(attribute.RunOnStartup);
        }
        private static FunctionMetadata ParseFunctionMetadata(string functionName, JObject configMetadata)
        {
            FunctionMetadata functionMetadata = new FunctionMetadata
            {
                Name = functionName
            };

            JValue triggerDisabledValue = null;
            JArray bindingArray         = (JArray)configMetadata["bindings"];

            if (bindingArray == null || bindingArray.Count == 0)
            {
                throw new FormatException("At least one binding must be declared.");
            }

            if (bindingArray != null)
            {
                foreach (JObject binding in bindingArray)
                {
                    BindingMetadata bindingMetadata = BindingMetadata.Create(binding);
                    functionMetadata.Bindings.Add(bindingMetadata);
                    if (bindingMetadata.IsTrigger)
                    {
                        triggerDisabledValue = (JValue)binding["disabled"];
                    }
                }
            }

            // A function can be disabled at the trigger or function level
            if (IsDisabled(triggerDisabledValue) ||
                IsDisabled((JValue)configMetadata["disabled"]))
            {
                functionMetadata.IsDisabled = true;
            }

            JToken value = null;

            if (configMetadata.TryGetValue("excluded", StringComparison.OrdinalIgnoreCase, out value) &&
                value.Type == JTokenType.Boolean)
            {
                functionMetadata.IsExcluded = (bool)value;
            }

            return(functionMetadata);
        }
        public static FunctionBinding CreateBindingFromHost(IHost host, JObject json)
        {
            var bindingProviders = host.Services.GetServices <IScriptBindingProvider>();
            var context          = new ScriptBindingContext(json);

            ScriptBinding scriptBinding = null;

            bindingProviders.FirstOrDefault(p => p.TryCreate(context, out scriptBinding));

            if (scriptBinding != null)
            {
                BindingMetadata bindingMetadata = BindingMetadata.Create(json);
                var             config          = new ScriptJobHostOptions();
                return(new ExtensionBinding(config, scriptBinding, bindingMetadata));
            }

            return(null);
        }
        public virtual async Task <ImmutableArray <FunctionMetadata> > ReadMetadataAsync()
        {
            string metadataFile = Path.Combine(_options.Value.FunctionMetadataFileDrectory, _fileName);

            if (File.Exists(metadataFile))
            {
                using (var fs = File.OpenText(metadataFile))
                {
                    using (var js = new JsonTextReader(fs))
                    {
                        JArray functionMetadataJson = (JArray)await JToken.ReadFromAsync(js);

                        var functionList = new List <FunctionMetadata>();

                        foreach (JObject function in functionMetadataJson)
                        {
                            FunctionMetadata metadata = function.ToObject <FunctionMetadata>();

                            // We need to re-add these by going through the BindingMetadata factory
                            metadata.Bindings.Clear();

                            JArray bindingArray = (JArray)function["bindings"];
                            if (bindingArray == null || bindingArray.Count == 0)
                            {
                                throw new FormatException("At least one binding must be declared.");
                            }

                            foreach (JObject binding in bindingArray)
                            {
                                metadata.Bindings.Add(BindingMetadata.Create(binding));
                            }

                            functionList.Add(metadata);
                        }

                        return(functionList.ToImmutableArray());
                    }
                }
            }
            else
            {
                return(ImmutableArray <FunctionMetadata> .Empty);
            }
        }
Example #18
0
        public void VerifyResolvedBindings_WithValidBindingMatch_DoesNotThrow()
        {
            FunctionMetadata functionMetadata = new FunctionMetadata();
            BindingMetadata  triggerMetadata  = BindingMetadata.Create(JObject.Parse("{\"type\": \"httpTrigger\",\"name\": \"req\",\"direction\": \"in\"}"));
            BindingMetadata  bindingMetadata  = BindingMetadata.Create(JObject.Parse("{\"type\": \"http\",\"name\": \"$return\",\"direction\": \"out\"}"));

            functionMetadata.Bindings.Add(triggerMetadata);
            functionMetadata.Bindings.Add(bindingMetadata);
            try
            {
                _provider.TryCreate(functionMetadata, out FunctionDescriptor descriptor);
                Assert.True(true, "No exception thrown");
            }
            catch (Exception ex)
            {
                Assert.True(false, "Exception not expected:" + ex.Message);
                throw;
            }
        }
Example #19
0
        private FunctionMetadata GetFunctionMetadata(string functionName)
        {
            var assembly         = Assembly.GetExecutingAssembly();
            var functionMetadata = new FunctionMetadata()
            {
                Name = functionName,
                FunctionDirectory = null,
                ScriptFile        = $"assembly:{assembly.FullName}",
                EntryPoint        = $"{assembly.GetName().Name}.{typeof(OpenApiTriggerFunctionProvider).Name}.{functionName}",
                Language          = "DotNetAssembly"
            };

            var jo      = JObject.FromObject(this._bindings[functionName]);
            var binding = BindingMetadata.Create(jo);

            functionMetadata.Bindings.Add(binding);

            return(functionMetadata);
        }
        public void GenerateHttpTriggerFunction()
        {
            BindingMetadata trigger = BindingMetadata.Create(new JObject
            {
                { "type", "HttpTrigger" },
                { "name", "req" }
            });
            MethodInfo method = GenerateMethod(trigger);

            VerifyCommonProperties(method);

            // verify trigger parameter
            ParameterInfo parameter = method.GetParameters()[0];

            Assert.Equal("req", parameter.Name);
            Assert.Equal(typeof(HttpRequestMessage), parameter.ParameterType);
            NoAutomaticTriggerAttribute attribute = method.GetCustomAttribute <NoAutomaticTriggerAttribute>();

            Assert.NotNull(attribute);
        }
        public FunctionInvokerBaseTests()
        {
            _metricsLogger      = new TestMetricsLogger();
            _testLoggerProvider = new TestLoggerProvider();

            ILoggerFactory loggerFactory = new LoggerFactory();

            loggerFactory.AddProvider(_testLoggerProvider);

            var eventManager = new ScriptEventManager();

            var metadata = new FunctionMetadata
            {
                Name       = "TestFunction",
                ScriptFile = "index.js",
                Language   = "node"
            };
            JObject binding = JObject.FromObject(new
            {
                type      = "manualTrigger",
                name      = "manual",
                direction = "in"
            });

            metadata.Bindings.Add(BindingMetadata.Create(binding));

            var metadataManager = new MockMetadataManager(new[] { metadata });

            _host = new HostBuilder()
                    .ConfigureDefaultTestWebScriptHost()
                    .ConfigureServices(s =>
            {
                s.AddSingleton <IFunctionMetadataManager>(metadataManager);
            })
                    .Build();

            _scriptHost = _host.GetScriptHost();
            _scriptHost.InitializeAsync().Wait();

            _invoker = new MockInvoker(_scriptHost, _metricsLogger, metadataManager, metadata, loggerFactory);
        }
        internal static FunctionMetadata ValidateBindings(IEnumerable <string> rawBindings, FunctionMetadata function)
        {
            HashSet <string> bindingNames = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            foreach (string binding in rawBindings)
            {
                var functionBinding = BindingMetadata.Create(JObject.Parse(binding));

                Utility.ValidateBinding(functionBinding);

                // Ensure no duplicate binding names exist
                if (bindingNames.Contains(functionBinding.Name))
                {
                    throw new InvalidOperationException(string.Format("Multiple bindings with name '{0}' discovered. Binding names must be unique.", functionBinding.Name));
                }
                else
                {
                    bindingNames.Add(functionBinding.Name);
                }

                // add binding to function.Bindings once validation is complete
                function.Bindings.Add(functionBinding);
            }

            // ensure there is at least one binding after validation
            if (function.Bindings == null || function.Bindings.Count == 0)
            {
                throw new FormatException("At least one binding must be declared.");
            }

            // ensure that there is a trigger binding
            var triggerMetadata = function.InputBindings.FirstOrDefault(p => p.IsTrigger);

            if (triggerMetadata == null)
            {
                throw new InvalidOperationException("No trigger binding specified. A function must have a trigger input binding.");
            }

            return(function);
        }
        public void GenerateBlobTriggerFunction()
        {
            BindingMetadata trigger = BindingMetadata.Create(new JObject
            {
                { "type", "blobTrigger" },
                { "name", "input" },
                { "direction", "in" },
                { "path", "foo/bar" }
            });
            MethodInfo method = GenerateMethod(trigger);

            VerifyCommonProperties(method);

            // verify trigger parameter
            ParameterInfo parameter = method.GetParameters()[0];

            Assert.Equal("input", parameter.Name);
            Assert.Equal(typeof(Stream), parameter.ParameterType);
            BlobTriggerAttribute attribute = parameter.GetCustomAttribute <BlobTriggerAttribute>();

            Assert.Equal("foo/bar", attribute.BlobPath);
        }
        public void GenerateQueueTriggerFunction()
        {
            BindingMetadata trigger = BindingMetadata.Create(new JObject
            {
                { "type", "QueueTrigger" },
                { "name", "input" },
                { "direction", "in" },
                { "queueName", "test" }
            });
            MethodInfo method = GenerateMethod(trigger);

            VerifyCommonProperties(method);

            // verify trigger parameter
            ParameterInfo parameter = method.GetParameters()[0];

            Assert.Equal("input", parameter.Name);
            Assert.Equal(typeof(string), parameter.ParameterType);
            QueueTriggerAttribute attribute = parameter.GetCustomAttribute <QueueTriggerAttribute>();

            Assert.Equal("test", attribute.QueueName);
        }