internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var validHostingPlanSkus  = new string[] { "Y1", "F1", "D1", "B1", "S1", "S2", "S3", "P1", "P2", "P3", "P1V2", "P2V2", "P3V2" };
            var validHostingPlanTiers = new string[] { "Dynamic", "Free", "Shared", "Basic", "Standard", "Premium" };

            if (!validHostingPlanSkus.Contains(HostingPlanSku))
            {
                Logger.WriteError($"Invalid value for hostingPlanSku: must be one of {String.Join(",", validHostingPlanSkus)}");
                return(ExitCodes.InvalidArguments);
            }
            if (!validHostingPlanTiers.Contains(HostingPlanTier))
            {
                Logger.WriteError($"Invalid value for hostingPlanTier: must be one of {String.Join(",", validHostingPlanTiers)}");
                return(ExitCodes.InvalidArguments);
            }
            var tuning = new AggregatorInstances.InstanceFineTuning
            {
                AppInsightLocation = string.IsNullOrWhiteSpace(AppInsightLocation) ? Location : AppInsightLocation,
                HostingPlanSku     = HostingPlanSku,
                HostingPlanTier    = HostingPlanTier
            };

            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon() // need the token, so we can save it in the app settings
                          .BuildAsync(cancellationToken);

            context.ResourceGroupDeprecationCheck(this.ResourceGroup);
            var  instances = new AggregatorInstances(context.Azure, context.Logger, context.Naming);
            var  instance  = context.Naming.GetInstanceCreateNames(Name, ResourceGroup);
            bool ok        = await instances.AddAsync(instance, Location, RequiredVersion, SourceUrl, tuning, cancellationToken);

            return(ok ? ExitCodes.Success : ExitCodes.Failure);
        }
        internal async Task <(string url, string key)> GetInvocationUrlAndKey(InstanceName instance, string rule, CancellationToken cancellationToken)
        {
            var instances = new AggregatorInstances(_azure, _logger);
            var kudu      = new KuduApi(instance, _azure, _logger);

            // see https://github.com/projectkudu/kudu/wiki/Functions-API
            using (var client = new HttpClient())
                using (var request = await kudu.GetRequestAsync(HttpMethod.Post, $"api/functions/{rule}/listsecrets", cancellationToken))
                {
                    using (var response = await client.SendAsync(request, cancellationToken))
                    {
                        if (response.IsSuccessStatusCode)
                        {
                            using (var stream = await response.Content.ReadAsStreamAsync())
                                using (var sr = new StreamReader(stream))
                                    using (var jtr = new JsonTextReader(sr))
                                    {
                                        var js     = new JsonSerializer();
                                        var secret = js.Deserialize <KuduSecret>(jtr);

                                        (string url, string key)invocation = (GetInvocationUrl(instance, rule), secret.Key);
                                        return(invocation);
                                    }
                        }

                        string error = await response.Content.ReadAsStringAsync();

                        _logger.WriteError($"Failed to retrieve function key: {error}");
                        throw new InvalidOperationException("Failed to retrieve function key.");
                    }
                }
        }
示例#3
0
        internal async Task <(string url, string key)> GetInvocationUrlAndKey(InstanceName instance, string rule)
        {
            var instances = new AggregatorInstances(azure, logger);
            var kudu      = new KuduApi(instance, azure, logger);

            logger.WriteVerbose($"Querying Function key...");
            // see https://github.com/projectkudu/kudu/wiki/Functions-API
            using (var client = new HttpClient())
                using (var request = await kudu.GetRequestAsync(HttpMethod.Post, $"api/functions/{rule}/listsecrets"))
                {
                    using (var response = await client.SendAsync(request))
                    {
                        if (response.IsSuccessStatusCode)
                        {
                            using (var stream = await response.Content.ReadAsStreamAsync())
                                using (var sr = new StreamReader(stream))
                                    using (var jtr = new JsonTextReader(sr))
                                    {
                                        var js     = new JsonSerializer();
                                        var secret = js.Deserialize <KuduSecret>(jtr);

                                        (string url, string key)invocation = (GetInvocationUrl(instance, rule), secret.Key);
                                        logger.WriteInfo($"Function key retrieved.");
                                        return(invocation);
                                    }
                        }
                        else
                        {
                            return(default);
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .BuildAsync(cancellationToken);

            context.ResourceGroupDeprecationCheck(this.ResourceGroup);
            var instances = new AggregatorInstances(context.Azure, context.Logger, context.Naming);

            if (!string.IsNullOrEmpty(Location))
            {
                context.Logger.WriteVerbose($"Searching aggregator instances in {Location} Region...");
                return(await ListByLocationAsync(context, instances, cancellationToken));
            }
            else if (!string.IsNullOrEmpty(ResourceGroup))
            {
                context.Logger.WriteVerbose($"Searching aggregator instances in {ResourceGroup} Resource Group...");
                return(await ListInResourceGroupAsync(context, instances, cancellationToken));
            }
            else
            {
                context.Logger.WriteVerbose($"Searching aggregator instances in whole subscription...");
                return(await ListAllAsync(context, instances, cancellationToken));
            }
        }
示例#5
0
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var validHostingPlanSkus  = new string[] { "Y1", "F1", "D1", "B1", "S1", "S2", "S3", "P1", "P2", "P3", "P1V2", "P2V2", "P3V2" };
            var validHostingPlanTiers = new string[] { "Dynamic", "Free", "Shared", "Basic", "Standard", "Premium" };

            if (!validHostingPlanSkus.Contains(HostingPlanSku))
            {
                Logger.WriteError($"Invalid value for hostingPlanSku: must be one of {String.Join(",", validHostingPlanSkus)}");
                return(2);
            }
            if (!validHostingPlanTiers.Contains(HostingPlanTier))
            {
                Logger.WriteError($"Invalid value for hostingPlanTier: must be one of {String.Join(",", validHostingPlanTiers)}");
                return(2);
            }

            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon() // need the token, so we can save it in the app settings
                          .BuildAsync(cancellationToken);

            var  instances = new AggregatorInstances(context.Azure, context.Logger);
            var  instance  = new InstanceName(Name, ResourceGroup);
            bool ok        = await instances.AddAsync(instance, Location, RequiredVersion, SourceUrl, cancellationToken);

            return(ok ? 0 : 1);
        }
示例#6
0
        internal async Task <IEnumerable <KuduFunction> > ListAsync(InstanceName instance)
        {
            var instances = new AggregatorInstances(azure, logger);
            var kudu      = new KuduApi(instance, azure, logger);

            logger.WriteInfo($"Retrieving Functions in {instance.PlainName}...");
            using (var client = new HttpClient())
                using (var request = await kudu.GetRequestAsync(HttpMethod.Get, $"api/functions"))
                    using (var response = await client.SendAsync(request))
                    {
                        var stream = await response.Content.ReadAsStreamAsync();

                        if (response.IsSuccessStatusCode)
                        {
                            using (var sr = new StreamReader(stream))
                                using (var jtr = new JsonTextReader(sr))
                                {
                                    var js           = new JsonSerializer();
                                    var functionList = js.Deserialize <KuduFunction[]>(jtr);
                                    return(functionList);
                                }
                        }
                        else
                        {
                            logger.WriteError($"{response.ReasonPhrase} {await response.Content.ReadAsStringAsync()}");
                            return(new KuduFunction[0]);
                        }
                    }
        }
示例#7
0
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .BuildAsync(cancellationToken);

            var  instance  = context.Naming.Instance(Instance, ResourceGroup);
            var  instances = new AggregatorInstances(context.Azure, context.Logger, context.Naming);
            bool ok        = await instances.StreamLogsAsync(instance, cancellationToken);

            return(ok ? ExitCodes.Success : ExitCodes.Failure);
        }
示例#8
0
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .BuildAsync(cancellationToken);

            var  instance  = new InstanceName(Instance, ResourceGroup);
            var  instances = new AggregatorInstances(context.Azure, context.Logger);
            bool ok        = await instances.StreamLogsAsync(instance, cancellationToken);

            return(ok ? 0 : 1);
        }
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon() // need the token, so we can save it in the app settings
                          .BuildAsync(cancellationToken);

            var  instances = new AggregatorInstances(context.Azure, context.Logger);
            var  instance  = new InstanceName(Name, ResourceGroup);
            bool ok        = await instances.AddAsync(instance, Location, RequiredVersion, cancellationToken);

            return(ok ? 0 : 1);
        }
示例#10
0
        internal override async Task <int> RunAsync()
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithVstsLogon() // need the token, so we can save it in the app settings
                          .Build();

            var  instances = new AggregatorInstances(context.Azure, context.Logger);
            var  instance  = new InstanceName(Name);
            bool ok        = await instances.Add(instance, Location);

            return(ok ? 0 : 1);
        }
        private async Task <int> ListByLocationAsync(CommandContext context, AggregatorInstances instances, CancellationToken cancellationToken)
        {
            var found = await instances.ListByLocationAsync(Location, cancellationToken);

            bool any = false;

            foreach (var dataObject in found)
            {
                context.Logger.WriteOutput(dataObject);
                any = true;
            }
            if (!any)
            {
                context.Logger.WriteInfo($"No aggregator instances found in {Location}.");
            }
            return(0);
        }
示例#12
0
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon()
                          .BuildAsync(cancellationToken);

            var instance  = new InstanceName(Instance, ResourceGroup);
            var instances = new AggregatorInstances(context.Azure, context.Logger);
            var boards    = new Boards(context.Devops, context.Logger);

            var streamTask = instances.StreamLogsAsync(instance, lastLinePattern: this.LastLinePattern, cancellationToken: cancellationToken);
            int id         = await boards.CreateWorkItemAsync(this.Project, this.Title, cancellationToken);

            streamTask.Wait(cancellationToken);
            return(id > 0 ? 0 : 1);
        }
示例#13
0
        private static async Task <int> ListAllAsync(CommandContext context, AggregatorInstances instances)
        {
            var found = await instances.ListAllAsync();

            bool any = false;

            foreach (var item in found)
            {
                context.Logger.WriteOutput(
                    item,
                    (data) => $"Instance {item.name} in {item.region} region");
                any = true;
            }
            if (!any)
            {
                context.Logger.WriteInfo("No aggregator instances found.");
            }
            return(0);
        }
示例#14
0
        private async Task <int> ListInResourceGroupAsync(CommandContext context, AggregatorInstances instances)
        {
            var found = await instances.ListInResourceGroupAsync(ResourceGroup);

            bool any = false;

            foreach (var name in found)
            {
                context.Logger.WriteOutput(
                    name,
                    (data) => $"Instance {name}");
                any = true;
            }
            if (!any)
            {
                context.Logger.WriteInfo("No aggregator instances found.");
            }
            return(0);
        }
示例#15
0
        private async Task <int> ListByLocationAsync(CommandContext context, AggregatorInstances instances)
        {
            var found = await instances.ListByLocationAsync(Location);

            bool any = false;

            foreach (var name in found)
            {
                context.Logger.WriteOutput(
                    name,
                    (data) => $"Instance {name}");
                any = true;
            }
            if (!any)
            {
                context.Logger.WriteInfo($"No aggregator instances found in {Location}.");
            }
            return(0);
        }
        private async Task <int> ListInResourceGroupAsync(CommandContext context, AggregatorInstances instances, CancellationToken cancellationToken)
        {
            var found = await instances.ListInResourceGroupAsync(ResourceGroup, cancellationToken);

            bool any = false;

            foreach (var dataObject in found)
            {
                context.Logger.WriteOutput(dataObject);
                any = true;
            }

            if (!any)
            {
                context.Logger.WriteInfo($"No aggregator instances found in {ResourceGroup} Resource Group.");
            }

            return(ExitCodes.Success);
        }
示例#17
0
        internal override async Task <int> RunAsync()
        {
            var context = await Context
                          .WithAzureLogon()
                          .Build();

            var instances = new AggregatorInstances(context.Azure, context.Logger);

            if (string.IsNullOrEmpty(Location))
            {
                context.Logger.WriteVerbose($"Searching aggregator instances in subscription...");
                return(await ListAllAsync(context, instances));
            }
            else
            {
                context.Logger.WriteVerbose($"Searching aggregator instances in {Location}...");
                return(await ListByLocationAsync(context, instances));
            }
        }
示例#18
0
        internal async Task <bool> RemoveAsync(InstanceName instance, string name)
        {
            var kudu      = new KuduApi(instance, azure, logger);
            var instances = new AggregatorInstances(azure, logger);

            // 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}"))
                    using (var response = await client.SendAsync(request))
                    {
                        bool ok = response.IsSuccessStatusCode;
                        if (!ok)
                        {
                            logger.WriteError($"Failed removing Function {name} from {instance.PlainName} with {response.ReasonPhrase}");
                        }
                        return(ok);
                    }
        }
示例#19
0
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon()
                          .BuildAsync(cancellationToken);

            var instance = context.Naming.Instance(Name, ResourceGroup);

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

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

            return(ok ? 0 : 1);
        }
示例#20
0
        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon()
                          .BuildAsync(cancellationToken);

            var instance  = context.Naming.Instance(Instance, ResourceGroup);
            var instances = new AggregatorInstances(context.Azure, context.Logger, context.Naming);
            var boards    = new Boards(context.Devops, context.Logger);

            int id = await boards.CreateWorkItemAsync(this.Project, this.Title, cancellationToken);

            // wait for the Event to be processed in AzDO, sent via WebHooks, and the Function to run
            Thread.Sleep(new TimeSpan(0, 2, 0));

            await instances.ReadLogAsync(instance, this.RuleName, -1, cancellationToken : cancellationToken);

            return(id > 0 ? 0 : 1);
        }
        private static async Task <int> ListAllAsync(CommandContext context, AggregatorInstances instances, CancellationToken cancellationToken)
        {
            var found = await instances.ListAllAsync(cancellationToken);

            bool any = false;

            foreach (var dataObject in found)
            {
                context.Logger.WriteOutput(dataObject);
                any = true;
            }
            if (!any)
            {
                context.Logger.WriteInfo("No aggregator instances found.");
                return(ExitCodes.NotFound);
            }
            else
            {
                return(ExitCodes.Success);
            }
        }
        // TODO add --swap.slot to support App Service Deployment Slots


        internal override async Task <int> RunAsync()
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon() // need the token, so we can save it in the app settings
                          .Build();

            var  instances = new AggregatorInstances(context.Azure, context.Logger);
            var  instance  = new InstanceName(Name, ResourceGroup);
            bool ok        = false;

            if (Authentication)
            {
                ok = await instances.ChangeAppSettings(instance, Location, SaveMode);
            }
            else
            {
                context.Logger.WriteError($"Unsupported command option(s)");
            }
            return(ok ? 0 : 1);
        }
示例#23
0
        // TODO add --swap.slot to support App Service Deployment Slots


        internal override async Task <int> RunAsync(CancellationToken cancellationToken)
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithDevOpsLogon() // need the token, so we can save it in the app settings
                          .BuildAsync(cancellationToken);

            var instances = new AggregatorInstances(context.Azure, context.Logger, context.Naming);
            var instance  = context.Naming.Instance(Name, ResourceGroup);

            if (Authentication)
            {
                bool ok = await instances.ChangeAppSettingsAsync(instance, Location, SaveMode, cancellationToken);

                return(ok ? ExitCodes.Success : ExitCodes.Failure);
            }
            else
            {
                context.Logger.WriteError($"Unsupported command option(s)");
                return(ExitCodes.InvalidArguments);
            }
        }
示例#24
0
        internal override async Task <int> RunAsync()
        {
            var context = await Context
                          .WithAzureLogon()
                          .WithVstsLogon()
                          .Build();

            var instance = new InstanceName(Name);

            bool ok;

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

            var instances = new AggregatorInstances(context.Azure, context.Logger);

            ok = await instances.Remove(instance, Location);

            return(ok ? 0 : 1);
        }
示例#25
0
        private async Task <bool> UploadRuleFiles(InstanceName instance, string name, string baseDirPath)
        {
            /*
             * PUT /api/vfs/{path}
             * Puts a file at path.
             *
             * PUT /api/vfs/{path}/
             * Creates a directory at path. The path can be nested, e.g. `folder1/folder2`.
             *
             * Note: when updating or deleting a file, ETag behavior will apply. You can pass a If-Match: "*" header to disable the ETag check.
             */
            var    kudu        = new KuduApi(instance, azure, logger);
            string relativeUrl = $"api/vfs/site/wwwroot/{name}/";

            var instances = new AggregatorInstances(azure, logger);

            using (var client = new HttpClient())
            {
                bool exists = false;

                // check if function already exists
                using (var request = await kudu.GetRequestAsync(HttpMethod.Head, relativeUrl))
                {
                    logger.WriteVerbose($"Checking if function {name} already exists in {instance.PlainName}...");
                    using (var response = await client.SendAsync(request))
                    {
                        exists = response.IsSuccessStatusCode;
                    }
                }

                if (!exists)
                {
                    logger.WriteVerbose($"Creating function {name} in {instance.PlainName}...");
                    using (var request = await kudu.GetRequestAsync(HttpMethod.Put, relativeUrl))
                    {
                        using (var response = await client.SendAsync(request))
                        {
                            bool ok = response.IsSuccessStatusCode;
                            if (!ok)
                            {
                                logger.WriteError($"Upload failed with {response.ReasonPhrase}");
                                return(ok);
                            }
                        }
                    }
                    logger.WriteInfo($"Function {name} created.");
                }

                var files = Directory.EnumerateFiles(baseDirPath, "*", SearchOption.AllDirectories);
                foreach (var file in files)
                {
                    logger.WriteVerbose($"Uploading {Path.GetFileName(file)} to {instance.PlainName}...");
                    string fileUrl = $"{relativeUrl}{Path.GetFileName(file)}";
                    using (var request = await kudu.GetRequestAsync(HttpMethod.Put, fileUrl))
                    {
                        //HACK -> request.Headers.IfMatch.Add(new EntityTagHeaderValue("*", false)); <- won't work
                        request.Headers.Add("If-Match", "*");
                        request.Content = new StringContent(File.ReadAllText(file));
                        using (var response = await client.SendAsync(request))
                        {
                            bool ok = response.IsSuccessStatusCode;
                            if (!ok)
                            {
                                logger.WriteError($"Failed uploading {file} with {response.ReasonPhrase}");
                                return(ok);
                            }
                        }
                    }
                    logger.WriteInfo($"{Path.GetFileName(file)} uploaded to {instance.PlainName}.");
                }//for
            }
            return(true);
        }