예제 #1
0
 public RuleWrapper(AggregatorConfiguration configuration, ILogger logger, string ruleName, string functionDirectory)
 {
     this.configuration     = configuration;
     this.logger            = logger;
     this.ruleName          = ruleName;
     this.functionDirectory = functionDirectory;
 }
예제 #2
0
        static public AggregatorConfiguration Read(Microsoft.Extensions.Configuration.IConfiguration config)
        {
            var ac = new AggregatorConfiguration();

            Enum.TryParse(config["Aggregator_VstsTokenType"], out VstsTokenType vtt);
            ac.VstsTokenType = vtt;
            ac.VstsToken     = config["Aggregator_VstsToken"];
            return(ac);
        }
        static public AggregatorConfiguration Read(Microsoft.Extensions.Configuration.IConfiguration config)
        {
            var ac = new AggregatorConfiguration();

            Enum.TryParse(config["Aggregator_VstsTokenType"], out DevOpsTokenType vtt);
            ac.DevOpsTokenType = vtt;
            ac.DevOpsToken     = config["Aggregator_VstsToken"];
            ac.SaveMode        = Enum.TryParse(config["Aggregator_SaveMode"], out SaveMode sm)
                ? sm
                : SaveMode.Default;
            return(ac);
        }
예제 #4
0
        public async Task <HttpResponseMessage> Run(HttpRequestMessage req)
        {
            log.Verbose($"Context: {context.InvocationId} {context.FunctionName} {context.FunctionDirectory} {context.FunctionAppDirectory}");

            // TODO
            string aggregatorVersion = null;

            try
            {
                string rule = context.FunctionName;
                log.Info($"Welcome to {rule}");
            }
            catch (Exception ex)
            {
                log.Warning($"Failed parsing headers: {ex.Message}");
            }

            // Get request body
            string jsonContent = await req.Content.ReadAsStringAsync();

            dynamic data      = JsonConvert.DeserializeObject(jsonContent);
            string  eventType = data.eventType;

            // sanity check
            if (!VstsEvents.IsValidEvent(eventType) ||
                data.publisherId != VstsEvents.PublisherId)
            {
                return(req.CreateResponse(HttpStatusCode.BadRequest, new
                {
                    error = "Not a good VSTS post..."
                }));
            }

            var config = new ConfigurationBuilder()
                         .SetBasePath(context.FunctionAppDirectory)
                         .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
                         .AddEnvironmentVariables()
                         .Build();
            var configuration = AggregatorConfiguration.Read(config);

            var    logger     = new TraceWriterLogger(log);
            var    wrapper    = new RuleWrapper(configuration, logger, context.FunctionName, context.FunctionDirectory);
            string execResult = await wrapper.Execute(aggregatorVersion, data);

            log.Info($"Returning {execResult}");

            var resp = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StringContent(execResult)
            };

            return(resp);
        }
예제 #5
0
        public static AggregatorConfiguration ExtendFromUrl(AggregatorConfiguration configuration, Uri requestUri)
        {
            var parameters = System.Web.HttpUtility.ParseQueryString(requestUri.Query);

            bool dryRun = bool.TryParse(parameters["dryRun"], out dryRun) && dryRun;

            configuration.DryRun = dryRun;

            if (Enum.TryParse(parameters["saveMode"], out SaveMode saveMode))
            {
                configuration.SaveMode = saveMode;
            }

            return(configuration);
        }
예제 #6
0
        public async Task <HttpResponseMessage> RunAsync(HttpRequestMessage req, CancellationToken cancellationToken)
        {
            _log.LogDebug($"Context: {_context.InvocationId} {_context.FunctionName} {_context.FunctionDirectory} {_context.FunctionAppDirectory}");

            var aggregatorVersion = GetCustomAttribute <System.Reflection.AssemblyInformationalVersionAttribute>()?.InformationalVersion;

            try
            {
                var rule = _context.FunctionName;
                _log.LogInformation($"Aggregator v{aggregatorVersion} executing rule '{rule}'");
            }
            catch (Exception ex)
            {
                _log.LogWarning($"Failed parsing request headers: {ex.Message}");
            }

            cancellationToken.ThrowIfCancellationRequested();

            // Get request body
            var jsonContent = await req.Content.ReadAsStringAsync();

            if (string.IsNullOrWhiteSpace(jsonContent))
            {
                _log.LogWarning($"Failed parsing request body: empty");

                var resp = new HttpResponseMessage(HttpStatusCode.BadRequest)
                {
                    Content = new StringContent("Request body is empty")
                };
                return(resp);
            }

            dynamic data      = JsonConvert.DeserializeObject(jsonContent);
            string  eventType = data.eventType;

            // sanity check
            if (!DevOpsEvents.IsValidEvent(eventType) ||
                data.publisherId != DevOpsEvents.PublisherId)
            {
                return(req.CreateResponse(HttpStatusCode.BadRequest, new
                {
                    error = "Not a good Azure DevOps post..."
                }));
            }

            if (data.resource.url == "http://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/wit/workItems/5")
            {
                var resp = req.CreateResponse(HttpStatusCode.OK, new
                {
                    message = $"Hello from Aggregator v{aggregatorVersion} executing rule '{_context.FunctionName}'"
                });
                resp.Headers.Add("X-Aggregator-Version", aggregatorVersion);
                resp.Headers.Add("X-Aggregator-Rule", _context.FunctionName);
                return(resp);
            }

            var config = new ConfigurationBuilder()
                         .SetBasePath(_context.FunctionAppDirectory)
                         .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
                         .AddEnvironmentVariables()
                         .Build();
            var configuration = AggregatorConfiguration.Read(config);

            configuration = InvokeOptions.ExtendFromUrl(configuration, req.RequestUri);

            var logger  = new ForwarderLogger(_log);
            var wrapper = new RuleWrapper(configuration, logger, _context.FunctionName, _context.FunctionDirectory);

            try
            {
                string execResult = await wrapper.ExecuteAsync(data, cancellationToken);

                if (string.IsNullOrEmpty(execResult))
                {
                    var resp = new HttpResponseMessage(HttpStatusCode.OK);
                    return(resp);
                }
                else
                {
                    _log.LogInformation($"Returning '{execResult}' from '{_context.FunctionName}'");

                    var resp = new HttpResponseMessage(HttpStatusCode.OK)
                    {
                        Content = new StringContent(execResult)
                    };
                    return(resp);
                }
            }
            catch (Exception ex)
            {
                _log.LogWarning($"Rule '{_context.FunctionName}' failed: {ex.Message}");

                var resp = new HttpResponseMessage(HttpStatusCode.NotImplemented)
                {
                    Content = new StringContent(ex.Message)
                };
                return(resp);
            }
        }
예제 #7
0
        public async Task <HttpResponseMessage> RunAsync(HttpRequestMessage req, CancellationToken cancellationToken)
        {
            _log.LogDebug($"Context: {_context.InvocationId} {_context.FunctionName} {_context.FunctionDirectory} {_context.FunctionAppDirectory}");

            var ruleName          = _context.FunctionName;
            var aggregatorVersion = GetCustomAttribute <System.Reflection.AssemblyInformationalVersionAttribute>()?.InformationalVersion;

            _log.LogInformation($"Aggregator v{aggregatorVersion} executing rule '{ruleName}'");
            cancellationToken.ThrowIfCancellationRequested();

            // Get request body
            var eventData = await GetWebHookEvent(req);

            if (eventData == null)
            {
                return(req.CreateErrorResponse(HttpStatusCode.BadRequest, "Request body is empty"));
            }

            // sanity check
            if (!DevOpsEvents.IsValidEvent(eventData.EventType) ||
                eventData.PublisherId != DevOpsEvents.PublisherId)
            {
                return(req.CreateErrorResponse(HttpStatusCode.BadRequest, "Not a good Azure DevOps post..."));
            }

            var eventContext = CreateContextFromEvent(eventData);

            if (eventContext.IsTestEvent())
            {
                return(req.CreateTestEventResponse(aggregatorVersion, ruleName));
            }

            var configContext = GetConfigurationContext();
            var configuration = AggregatorConfiguration.ReadConfiguration(configContext)
                                .UpdateFromUrl(ruleName, req.RequestUri);

            var logger       = new ForwarderLogger(_log);
            var ruleProvider = new AzureFunctionRuleProvider(logger, _context.FunctionDirectory);
            var ruleExecutor = new RuleExecutor(logger, configuration);

            using (_log.BeginScope($"WorkItem #{eventContext.WorkItemPayload.WorkItem.Id}"))
            {
                try
                {
                    var rule = await ruleProvider.GetRule(ruleName);

                    var execResult = await ruleExecutor.ExecuteAsync(rule, eventContext, cancellationToken);

                    if (string.IsNullOrEmpty(execResult))
                    {
                        return(req.CreateResponse(HttpStatusCode.OK));
                    }
                    else
                    {
                        _log.LogInformation($"Returning '{execResult}' from '{rule.Name}'");
                        return(req.CreateResponse(HttpStatusCode.OK, execResult));
                    }
                }
                catch (Exception ex)
                {
                    _log.LogWarning($"Rule '{ruleName}' failed: {ex.Message}");
                    return(req.CreateErrorResponse(HttpStatusCode.NotImplemented, ex));
                }
            }
        }
        public async Task <IActionResult> RunAsync(/*HttpRequest request, */ WebHookEvent eventData, CancellationToken cancellationToken)
        {
            _log.LogDebug($"Context: {_executionContext.InvocationId} {_executionContext.FunctionName} {_executionContext.FunctionDirectory} {_executionContext.FunctionAppDirectory}");

            var ruleName          = _executionContext.FunctionName;
            var aggregatorVersion = RequestHelper.AggregatorVersion;

            _log.LogInformation($"Aggregator v{aggregatorVersion} executing rule '{ruleName}'");
            cancellationToken.ThrowIfCancellationRequested();

            if (eventData == null)
            {
                return(BadRequest("Request body is empty"));
            }

            // sanity check
            if (!DevOpsEvents.IsValidEvent(eventData.EventType) ||
                eventData.PublisherId != DevOpsEvents.PublisherId)
            {
                _log.LogDebug("return BadRequest");
                return(BadRequest(new { Error = "Not a good Azure DevOps post..." }));
            }

            var helper       = new RequestHelper(_log);
            var eventContext = helper.CreateContextFromEvent(eventData);

            if (eventContext.IsTestEvent())
            {
                Response.AddCustomHeaders(aggregatorVersion, ruleName);
                return(RespondToTestEventMessage(aggregatorVersion, ruleName));
            }

            var configContext = GetConfigurationContext();
            var configuration = AggregatorConfiguration.ReadConfiguration(configContext)
                                .UpdateFromUrl(ruleName, GetRequestUri());

            var logger       = new ForwarderLogger(_log);
            var ruleProvider = new AzureFunctionRuleProvider(logger, _executionContext.FunctionDirectory);
            var ruleExecutor = new RuleExecutor(logger, configuration);

            using (_log.BeginScope($"WorkItem #{eventContext.WorkItemPayload.WorkItem.Id}"))
            {
                try
                {
                    var rule = await ruleProvider.GetRule(ruleName);

                    var execResult = await ruleExecutor.ExecuteAsync(rule, eventContext, cancellationToken);

                    if (string.IsNullOrEmpty(execResult))
                    {
                        return(Ok());
                    }
                    else
                    {
                        _log.LogInformation($"Returning '{execResult}' from '{rule.Name}'");
                        return(Ok(execResult));
                    }
                }
                catch (Exception ex)
                {
                    _log.LogWarning($"Rule '{ruleName}' failed: {ex.Message}");
                    return(BadRequest(ex.Message));
                }
            }
        }
        public async Task <HttpResponseMessage> Run(HttpRequestMessage req)
        {
            log.LogDebug($"Context: {context.InvocationId} {context.FunctionName} {context.FunctionDirectory} {context.FunctionAppDirectory}");

            var aggregatorVersion = GetCustomAttribute <System.Reflection.AssemblyInformationalVersionAttribute>()?.InformationalVersion;

            try
            {
                string rule = context.FunctionName;
                log.LogInformation($"Aggregator v{aggregatorVersion} executing rule '{rule}'");
            }
            catch (Exception ex)
            {
                log.LogWarning($"Failed parsing request headers: {ex.Message}");
            }

            // Get request body
            string jsonContent = await req.Content.ReadAsStringAsync();

            if (string.IsNullOrWhiteSpace(jsonContent))
            {
                log.LogWarning($"Failed parsing request body: empty");

                var resp = new HttpResponseMessage(HttpStatusCode.BadRequest)
                {
                    Content = new StringContent("Request body is empty")
                };
                return(resp);
            }
            dynamic data      = JsonConvert.DeserializeObject(jsonContent);
            string  eventType = data.eventType;

            // sanity check
            if (!DevOpsEvents.IsValidEvent(eventType) ||
                data.publisherId != DevOpsEvents.PublisherId)
            {
                return(req.CreateResponse(HttpStatusCode.BadRequest, new
                {
                    error = "Not a good Azure DevOps post..."
                }));
            }

            var config = new ConfigurationBuilder()
                         .SetBasePath(context.FunctionAppDirectory)
                         .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
                         .AddEnvironmentVariables()
                         .Build();
            var configuration = AggregatorConfiguration.Read(config);

            var logger  = new ForwarderLogger(log);
            var wrapper = new RuleWrapper(configuration, logger, context.FunctionName, context.FunctionDirectory);

            try
            {
                string execResult = await wrapper.Execute(data);

                if (string.IsNullOrEmpty(execResult))
                {
                    var resp = new HttpResponseMessage(HttpStatusCode.OK);
                    return(resp);
                }
                else
                {
                    log.LogInformation($"Returning '{execResult}' from '{context.FunctionName}'");

                    var resp = new HttpResponseMessage(HttpStatusCode.OK)
                    {
                        Content = new StringContent(execResult)
                    };
                    return(resp);
                }
            }
            catch (Exception ex)
            {
                log.LogWarning($"Rule '{context.FunctionName}' failed: {ex.Message}");

                var resp = new HttpResponseMessage(HttpStatusCode.NotImplemented)
                {
                    Content = new StringContent(ex.Message)
                };
                return(resp);
            }
        }