internal async Task <bool> ChangeAppSettings(InstanceName instance, string location, SaveMode saveMode)
        {
            bool ok;
            var  devopsLogonData = DevOpsLogon.Load().connection;

            if (devopsLogonData.Mode == DevOpsTokenType.PAT)
            {
                logger.WriteVerbose($"Saving Azure DevOps token");
                ok = await ChangeAppSettings(instance, devopsLogonData, saveMode);

                logger.WriteInfo($"Azure DevOps token saved");
            }
            else
            {
                logger.WriteWarning($"Azure DevOps token type {devopsLogonData.Mode} is unsupported");
                ok = false;
            }
            return(ok);
        }
        internal async Task <bool> ChangeAppSettings(InstanceName instance, DevOpsLogon devopsLogonData, SaveMode saveMode)
        {
            var webFunctionApp = await azure
                                 .AppServices
                                 .WebApps
                                 .GetByResourceGroupAsync(
                instance.ResourceGroupName,
                instance.FunctionAppName);

            var configuration = new AggregatorConfiguration
            {
                DevOpsTokenType = devopsLogonData.Mode,
                DevOpsToken     = devopsLogonData.Token,
                SaveMode        = saveMode
            };

            configuration.Write(webFunctionApp);
            return(true);
        }
예제 #3
0
        internal async Task <IEnumerable <ILogDataObject> > ListInResourceGroupAsync(string resourceGroup, CancellationToken cancellationToken)
        {
            var runtime = new FunctionRuntimePackage(logger);
            var apps    = await azure.AppServices.FunctionApps.ListByResourceGroupAsync(resourceGroup, cancellationToken : cancellationToken);

            var result = new List <InstanceOutputData>();

            foreach (var app in apps)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var name = InstanceName.FromFunctionAppName(app.Name, resourceGroup);
                result.Add(new InstanceOutputData(
                               name.PlainName,
                               app.Region.Name,
                               await runtime.GetDeployedRuntimeVersion(name, azure, cancellationToken))
                           );
            }
            return(result);
        }
예제 #4
0
        internal async Task <bool> AddAsync(InstanceName instance, string ruleName, string filePath, CancellationToken cancellationToken)
        {
            _logger.WriteInfo($"Validate rule file {filePath}");
            var preprocessedRule = await LoadAndValidateRule(ruleName, filePath, cancellationToken);

            if (preprocessedRule == null)
            {
                _logger.WriteError("Rule file is invalid");
                return(false);
            }
            _logger.WriteInfo("Rule file is valid");

            _logger.WriteVerbose($"Layout rule files");
            var inMemoryFiles = await PackagingFilesAsync(ruleName, preprocessedRule);

            using (var assemblyStream = await FunctionRuntimePackage.GetDeployedFunctionEntrypoint(instance, _azure, _logger, cancellationToken))
            {
                await inMemoryFiles.AddFunctionDefaultFiles(assemblyStream);
            }
            _logger.WriteInfo($"Packaging rule {ruleName} complete.");

            _logger.WriteVerbose($"Uploading rule files to {instance.PlainName}");
            bool ok = await UploadRuleFilesAsync(instance, ruleName, inMemoryFiles, cancellationToken);

            if (ok)
            {
                _logger.WriteInfo($"All {ruleName} files successfully uploaded to {instance.PlainName}.");
            }

            if (preprocessedRule.Impersonate)
            {
                _logger.WriteInfo($"Configure {ruleName} to execute impersonated.");
                ok &= await ConfigureAsync(instance, ruleName, impersonate : true, cancellationToken : cancellationToken);

                if (ok)
                {
                    _logger.WriteInfo($"Updated {ruleName} configuration successfully.");
                }
            }

            return(ok);
        }
        internal async Task <bool> RemoveRuleEventAsync(string @event, InstanceName instance, string projectName, string rule)
        {
            logger.WriteInfo($"Querying the Azure DevOps subscriptions for rule(s) {instance.PlainName}/{rule}");
            var serviceHooksClient = devops.GetClient <ServiceHooksPublisherHttpClient>();
            var subscriptions      = await serviceHooksClient.QuerySubscriptionsAsync(DevOpsEvents.PublisherId);

            var ruleSubs = subscriptions
                           // TODO can we trust this equality?
                           // && s.ActionDescription == $"To host {instance.DnsHostName}"
                           .Where(s => s.ConsumerInputs["url"].ToString().StartsWith(
                                      instance.FunctionAppUrl));

            if (@event != "*")
            {
                ruleSubs = ruleSubs.Where(s => s.EventType == @event);
            }
            if (projectName != "*")
            {
                logger.WriteVerbose($"Reading Azure DevOps project data...");
                var projectClient = devops.GetClient <ProjectHttpClient>();
                var project       = await projectClient.GetProject(projectName);

                logger.WriteInfo($"Project {projectName} data read.");

                ruleSubs = ruleSubs.Where(s => s.PublisherInputs["projectId"] == project.Id.ToString());
            }
            if (rule != "*")
            {
                ruleSubs = ruleSubs
                           .Where(s => s.ConsumerInputs["url"].ToString().StartsWith(
                                      AggregatorRules.GetInvocationUrl(instance, rule)));
            }
            foreach (var ruleSub in ruleSubs)
            {
                logger.WriteVerbose($"Deleting subscription {ruleSub.EventDescription} {ruleSub.EventType}...");
                await serviceHooksClient.DeleteSubscriptionAsync(ruleSub.Id);

                logger.WriteInfo($"Subscription {ruleSub.EventDescription} {ruleSub.EventType} deleted.");
            }

            return(true);
        }
예제 #6
0
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon()
                          .BuildAsync(cancellationToken);

            var instance = new InstanceName(Name, ResourceGroup);

            if (!Mappings)
            {
                var mappings = new AggregatorMappings(context.Devops, context.Azure, context.Logger);
                _ = await mappings.RemoveInstanceAsync(instance);
            }

            var instances = new AggregatorInstances(context.Azure, context.Logger);
            var ok        = await instances.RemoveAsync(instance, Location);

            return(ok ? 0 : 1);
        }
예제 #7
0
        internal async Task <bool> AddAsync(InstanceName instance, string name, string filePath)
        {
            var kudu = new KuduApi(instance, azure, logger);

            logger.WriteVerbose($"Layout rule files");
            string baseDirPath = LayoutRuleFiles(name, filePath);

            logger.WriteInfo($"Packaging {filePath} into rule {name} complete.");

            logger.WriteVerbose($"Uploading rule files to {instance.PlainName}");
            bool ok = await UploadRuleFiles(instance, name, baseDirPath);

            if (ok)
            {
                logger.WriteInfo($"All {name} files uploaded to {instance.PlainName}.");
            }
            CleanupRuleFiles(baseDirPath);
            logger.WriteInfo($"Cleaned local working directory.");
            return(ok);
        }
예제 #8
0
        internal IEnumerable <(string rule, string project, string events)> List(InstanceName instance)
        {
            var serviceHooksClient = vsts.GetClient <ServiceHooksPublisherHttpClient>();
            var subscriptions      = serviceHooksClient
                                     .QuerySubscriptionsAsync()
                                     .Result
                                     .Where(s
                                            => s.PublisherId == "tfs" &&
                                            s.ConsumerInputs["url"].ToString().StartsWith(
                                                instance.FunctionAppUrl)
                                            );

            foreach (var subscription in subscriptions)
            {
                yield return(
                    subscription.ConsumerInputs["url"],
                    subscription.PublisherInputs["projectId"],
                    subscription.EventType
                    );
            }
        }
예제 #9
0
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon()
                          .BuildAsync(cancellationToken);

            var  mappings = new AggregatorMappings(context.Devops, context.Azure, context.Logger);
            bool ok       = DevOpsEvents.IsValidEvent(Event);

            if (!ok)
            {
                context.Logger.WriteError($"Invalid event type.");
                return(2);
            }

            var instance = new InstanceName(Instance, ResourceGroup);
            var id       = await mappings.AddAsync(Project, Event, instance, Rule, cancellationToken);

            return(id.Equals(Guid.Empty) ? 1 : 0);
        }
예제 #10
0
        internal async Task <bool> RemoveAsync(InstanceName instance, string name, CancellationToken cancellationToken)
        {
            var kudu = GetKudu(instance);

            // undocumented but works, see https://github.com/projectkudu/kudu/wiki/Functions-API
            _logger.WriteInfo($"Removing Function {name} in {instance.PlainName}...");
            using (var client = new HttpClient())
                using (var request = await kudu.GetRequestAsync(HttpMethod.Delete, $"api/functions/{name}", cancellationToken))
                    using (var response = await client.SendAsync(request, cancellationToken))
                    {
                        bool ok = response.IsSuccessStatusCode;
                        if (!ok)
                        {
                            _logger.WriteError($"Failed removing Function {name} from {instance.PlainName} with {response.ReasonPhrase}");
                        }

                        return(ok);
                    }

            //TODO BobSilent remove configuration (Enable/Disable or Impersonate)
        }
예제 #11
0
        internal async Task <IEnumerable <MappingOutputData> > ListAsync(InstanceName instance, string projectName)
        {
            logger.WriteVerbose($"Searching aggregator mappings in Azure DevOps...");
            var serviceHooksClient = devops.GetClient <ServiceHooksPublisherHttpClient>();
            var subscriptions      = await serviceHooksClient.QuerySubscriptionsAsync();

            var filteredSubs = instance != null
                    ? subscriptions.Where(s
                                          => s.PublisherId == DevOpsEvents.PublisherId &&
                                          s.ConsumerInputs.GetValue("url", "").StartsWith(
                                              instance.FunctionAppUrl, StringComparison.OrdinalIgnoreCase))
                    : subscriptions.Where(s
                                          => s.PublisherId == DevOpsEvents.PublisherId
                                          // HACK
                                          && s.ConsumerInputs.GetValue("url", "").IndexOf("aggregator.azurewebsites.net") > 8);

            var projectClient = devops.GetClient <ProjectHttpClient>();
            var projects      = await projectClient.GetProjects();

            var projectsDict = projects.ToDictionary(p => p.Id);

            var result = new List <MappingOutputData>();

            foreach (var subscription in filteredSubs)
            {
                var foundProject = projectsDict[
                    new Guid(subscription.PublisherInputs["projectId"])
                                   ];
                if (!string.IsNullOrEmpty(projectName) && foundProject.Name != projectName)
                {
                    continue;
                }
                Uri    ruleUrl      = new Uri(subscription.ConsumerInputs.GetValue("url", MagicConstants.MissingUrl));
                string ruleFullName = GetRuleFullName(ruleUrl);
                result.Add(
                    new MappingOutputData(instance, ruleFullName, ruleUrl.IsImpersonationEnabled(), foundProject.Name, subscription.EventType, subscription.Status.ToString())
                    );
            }
            return(result);
        }
예제 #12
0
        private async Task <bool> UploadRuntimeZip(InstanceName instance, byte[] zipContent)
        {
            var kudu = new KuduApi(instance, azure, logger);
            // POST /api/zipdeploy?isAsync=true
            // Deploy from zip asynchronously. The Location header of the response will contain a link to a pollable deployment status.
            var body = new ByteArrayContent(zipContent);

            using (var client = new HttpClient())
                using (var request = await kudu.GetRequestAsync(HttpMethod.Post, $"api/zipdeploy"))
                {
                    request.Content = body;
                    using (var response = await client.SendAsync(request))
                    {
                        bool ok = response.IsSuccessStatusCode;
                        if (!ok)
                        {
                            logger.WriteError($"Upload failed with {response.ReasonPhrase}");
                        }
                        return(ok);
                    }
                }
        }
예제 #13
0
        internal override async Task <int> RunAsync()
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon()
                          .Build();

            var rules = new AggregatorRules(context.Azure, context.Logger);

            if (Local)
            {
                bool ok = await rules.InvokeLocalAsync(Project, Event, WorkItemId, Source, DryRun, SaveMode);

                return(ok ? 0 : 1);
            }
            else
            {
                var instance = new InstanceName(Instance, ResourceGroup);
                context.Logger.WriteWarning("Not implemented yet.");
                return(2);
            }
        }
예제 #14
0
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .BuildAsync(cancellationToken);

            var  instance = new InstanceName(Instance, ResourceGroup);
            var  rules    = new AggregatorRules(context.Azure, context.Logger);
            bool any      = false;

            foreach (var item in await rules.ListAsync(instance, cancellationToken))
            {
                cancellationToken.ThrowIfCancellationRequested();
                context.Logger.WriteOutput(new RuleOutputData(instance, item));
                any = true;
            }

            if (!any)
            {
                context.Logger.WriteInfo($"No rules found in aggregator instance {instance.PlainName}.");
            }

            return(0);
        }