예제 #1
0
        internal async Task <bool> Add(InstanceName instance, string location)
        {
            string rgName = instance.ResourceGroupName;

            if (!await azure.ResourceGroups.ContainAsync(rgName))
            {
                logger.WriteVerbose($"Creating resource group {rgName}");
                await azure.ResourceGroups
                .Define(rgName)
                .WithRegion(location)
                .CreateAsync();

                logger.WriteInfo($"Resource group {rgName} created.");
            }

            // TODO the template should create a Storage account and/or a Key Vault
            var    resourceName = "aggregator.cli.Instances.instance-template.json";
            string armTemplateString;
            var    assembly = Assembly.GetExecutingAssembly();

            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
                using (StreamReader reader = new StreamReader(stream))
                {
                    armTemplateString = await reader.ReadToEndAsync();
                }

            var parsedTemplate = JObject.Parse(armTemplateString);

            // sanity checks
            if (parsedTemplate.SelectToken("parameters.appName") == null)
            {
                // not good, blah
                logger.WriteWarning($"Something is wrong with the ARM template");
            }

            string appName        = instance.FunctionAppName;
            var    templateParams = new Dictionary <string, Dictionary <string, object> > {
                { "appName", new Dictionary <string, object> {
                      { "value", appName }
                  } }
            };

            string deploymentName = SdkContext.RandomResourceName("aggregator", 24);

            logger.WriteInfo($"Started deployment {deploymentName}");
            var deployment = await azure.Deployments.Define(deploymentName)
                             .WithExistingResourceGroup(rgName)
                             .WithTemplate(armTemplateString)
                             .WithParameters(templateParams)
                             .WithMode(DeploymentMode.Incremental)
                             .CreateAsync();

            // poll
            const int PollIntervalInSeconds = 3;
            int       totalDelay            = 0;

            while (!(StringComparer.OrdinalIgnoreCase.Equals(deployment.ProvisioningState, "Succeeded") ||
                     StringComparer.OrdinalIgnoreCase.Equals(deployment.ProvisioningState, "Failed") ||
                     StringComparer.OrdinalIgnoreCase.Equals(deployment.ProvisioningState, "Cancelled")))
            {
                SdkContext.DelayProvider.Delay(PollIntervalInSeconds * 1000);
                totalDelay += PollIntervalInSeconds;
                logger.WriteVerbose($"Deployment running ({totalDelay}s)");
                await deployment.RefreshAsync();
            }
            logger.WriteInfo($"Deployment {deployment.ProvisioningState}");

            // check runtime package
            logger.WriteVerbose($"Checking runtime package version");
            var    package = new FunctionRuntimePackage();
            string zipPath = package.RuntimePackageFile;

            (string rel_name, DateTimeOffset? rel_when, string rel_url) = await package.FindVersion();

            logger.WriteVerbose($"Downloading runtime package {rel_name}");
            await package.Download(rel_url);

            logger.WriteInfo($"Runtime package downloaded.");

            // upload
            logger.WriteVerbose($"Uploading runtime package to {instance.DnsHostName}");
            bool ok = await package.UploadRuntimeZip(instance, azure, logger);

            if (ok)
            {
                logger.WriteInfo($"Runtime package uploaded to {instance.PlainName}.");
                // TODO requires VSTS logon!!!!!!!!!
                var vstsLogonData = VstsLogon.Load().connection;
                if (vstsLogonData.Mode == VstsTokenType.PAT)
                {
                    logger.WriteVerbose($"Saving VSTS token");
                    ok = await ChangeAppSettings(instance, vstsLogonData);

                    logger.WriteInfo($"VSTS token saved");
                }
                else
                {
                    logger.WriteWarning($"VSTS token type {vstsLogonData.Mode} is unsupported");
                    ok = false;
                }
            }
            return(ok);
        }
예제 #2
0
        internal async Task <bool> AddAsync(InstanceName instance, string location, string requiredVersion, string sourceUrl, CancellationToken cancellationToken)
        {
            string rgName = instance.ResourceGroupName;

            logger.WriteVerbose($"Checking if Resource Group {rgName} already exists");
            if (!await azure.ResourceGroups.ContainAsync(rgName, cancellationToken))
            {
                if (instance.IsCustom)
                {
                    logger.WriteError($"Resource group {rgName} is custom and cannot be created.");
                    return(false);
                }

                logger.WriteVerbose($"Creating resource group {rgName}");
                await azure.ResourceGroups
                .Define(rgName)
                .WithRegion(location)
                .CreateAsync();

                logger.WriteInfo($"Resource group {rgName} created.");
            }

            // IDEA the template should create a Storage account and/or a Key Vault for Rules' use
            // TODO https://github.com/gjlumsden/AzureFunctionsSlots suggest that slots must be created in template
            var    resourceName = "aggregator.cli.Instances.instance-template.json";
            string armTemplateString;
            var    assembly = Assembly.GetExecutingAssembly();

            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
                using (StreamReader reader = new StreamReader(stream))
                {
                    armTemplateString = await reader.ReadToEndAsync();
                }

            var parsedTemplate = JObject.Parse(armTemplateString);

            // sanity checks
            if (parsedTemplate.SelectToken("parameters.appName") == null)
            {
                // not good, blah
                logger.WriteWarning($"Something is wrong with the ARM template");
            }

            string appName        = instance.FunctionAppName;
            var    infoVersion    = GetCustomAttribute <AssemblyInformationalVersionAttribute>();
            var    templateParams = new Dictionary <string, Dictionary <string, object> > {
                // TODO give use more control by setting more parameters
                { "location", new Dictionary <string, object> {
                      { "value", location }
                  } },
                { "storageAccountType", new Dictionary <string, object> {
                      { "value", "Standard_LRS" }
                  } },
                { "appName", new Dictionary <string, object> {
                      { "value", appName }
                  } },
                { "aggregatorVersion", new Dictionary <string, object> {
                      { "value", infoVersion.InformationalVersion }
                  } },
                { "hostingPlanSkuName", new Dictionary <string, object> {
                      { "value", "Y1" }
                  } },
                { "hostingPlanSkuTier", new Dictionary <string, object> {
                      { "value", "Dynamic" }
                  } },
            };

            string deploymentName = SdkContext.RandomResourceName("aggregator", 24);

            logger.WriteInfo($"Started deployment (id: {deploymentName})");
            var deployment = await azure.Deployments.Define(deploymentName)
                             .WithExistingResourceGroup(rgName)
                             .WithTemplate(armTemplateString)
                             .WithParameters(templateParams)
                             .WithMode(DeploymentMode.Incremental)
                             .CreateAsync(cancellationToken);

            // poll
            const int pollIntervalInSeconds = 3;
            int       totalDelay            = 0;

            while (!(StringComparer.OrdinalIgnoreCase.Equals(deployment.ProvisioningState, "Succeeded") ||
                     StringComparer.OrdinalIgnoreCase.Equals(deployment.ProvisioningState, "Failed") ||
                     StringComparer.OrdinalIgnoreCase.Equals(deployment.ProvisioningState, "Cancelled")))
            {
                SdkContext.DelayProvider.Delay(pollIntervalInSeconds * 1000);
                totalDelay += pollIntervalInSeconds;
                logger.WriteVerbose($"Deployment running ({totalDelay}s)");
                await deployment.RefreshAsync(cancellationToken);
            }
            logger.WriteInfo($"Deployment {deployment.ProvisioningState}");

            // check runtime package
            var  package = new FunctionRuntimePackage(logger);
            bool ok      = await package.UpdateVersionAsync(requiredVersion, sourceUrl, instance, azure, cancellationToken);

            if (ok)
            {
                var devopsLogonData = DevOpsLogon.Load().connection;
                if (devopsLogonData.Mode == DevOpsTokenType.PAT)
                {
                    logger.WriteVerbose($"Saving Azure DevOps token");
                    ok = await ChangeAppSettingsAsync(instance, devopsLogonData, SaveMode.Default, cancellationToken);

                    if (ok)
                    {
                        logger.WriteInfo($"Azure DevOps token saved");
                    }
                    else
                    {
                        logger.WriteError($"Failed to save Azure DevOps token");
                    }
                }
                else
                {
                    logger.WriteWarning($"Azure DevOps token type {devopsLogonData.Mode} is unsupported");
                    ok = false;
                }
            }
            return(ok);
        }
예제 #3
0
        public static int Main(string[] args)
        {
            var mainTimer = new Stopwatch();

            mainTimer.Start();

            var save = Console.ForegroundColor;

            Telemetry.TrackEvent("CLI Start");

            using (var cancellationTokenSource = new CancellationTokenSource())
            {
                void cancelEventHandler(object sender, ConsoleCancelEventArgs e)
                {
                    // call methods to clean up
                    Console.ForegroundColor = save;
                    if (!cancellationTokenSource.IsCancellationRequested)
                    {
                        cancellationTokenSource.Cancel();
                    }
                }

                Console.CancelKeyPress += cancelEventHandler;
                var cancellationToken = cancellationTokenSource.Token;

                bool versionCheckEnabled = !EnvironmentVariables.GetAsBool("AGGREGATOR_NEW_VERSION_CHECK_DISABLED", false);
                if (versionCheckEnabled)
                {
                    var tempLogger = new ConsoleLogger(false);
                    var verChecker = new FunctionRuntimePackage(tempLogger);
                    (bool upgrade, string newversion) = verChecker.IsCliUpgradable().Result;
                    if (upgrade)
                    {
                        // bug user
                        tempLogger.WriteWarning($"A new version ({newversion}) of Aggregator CLI is available, please upgrade.");
                    }
                }

                var parser = new Parser(settings =>
                {
                    settings.CaseSensitive = false;
                    // fails see https://github.com/commandlineparser/commandline/issues/198
                    settings.CaseInsensitiveEnumValues = true;
                });
                var types = new Type[]
                {
                    typeof(CreateTestCommand), typeof(CleanupTestCommand),
                    typeof(LogonAzureCommand), typeof(LogonDevOpsCommand), typeof(LogoffCommand), typeof(LogonEnvCommand),
                    typeof(ListInstancesCommand), typeof(InstallInstanceCommand), typeof(UpdateInstanceCommand),
                    typeof(UninstallInstanceCommand), typeof(ConfigureInstanceCommand), typeof(StreamLogsCommand),
                    typeof(ListRulesCommand), typeof(AddRuleCommand), typeof(RemoveRuleCommand),
                    typeof(ConfigureRuleCommand), typeof(UpdateRuleCommand), typeof(InvokeRuleCommand),
                    typeof(ListMappingsCommand), typeof(MapRuleCommand), typeof(UnmapRuleCommand), typeof(UpdateMappingsCommand),
                    typeof(MapLocalRuleCommand)
                };
                var parserResult = parser.ParseArguments(args, types);
                int rc           = ExitCodes.Unexpected;
                parserResult
                .WithParsed <CreateTestCommand>(cmd => rc        = cmd.Run(cancellationToken))
                .WithParsed <CleanupTestCommand>(cmd => rc       = cmd.Run(cancellationToken))
                .WithParsed <LogonAzureCommand>(cmd => rc        = cmd.Run(cancellationToken))
                .WithParsed <LogonDevOpsCommand>(cmd => rc       = cmd.Run(cancellationToken))
                .WithParsed <LogoffCommand>(cmd => rc            = cmd.Run(cancellationToken))
                .WithParsed <LogonEnvCommand>(cmd => rc          = cmd.Run(cancellationToken))
                .WithParsed <ListInstancesCommand>(cmd => rc     = cmd.Run(cancellationToken))
                .WithParsed <InstallInstanceCommand>(cmd => rc   = cmd.Run(cancellationToken))
                .WithParsed <UpdateInstanceCommand>(cmd => rc    = cmd.Run(cancellationToken))
                .WithParsed <UninstallInstanceCommand>(cmd => rc = cmd.Run(cancellationToken))
                .WithParsed <ConfigureInstanceCommand>(cmd => rc = cmd.Run(cancellationToken))
                .WithParsed <ListRulesCommand>(cmd => rc         = cmd.Run(cancellationToken))
                .WithParsed <AddRuleCommand>(cmd => rc           = cmd.Run(cancellationToken))
                .WithParsed <RemoveRuleCommand>(cmd => rc        = cmd.Run(cancellationToken))
                .WithParsed <ConfigureRuleCommand>(cmd => rc     = cmd.Run(cancellationToken))
                .WithParsed <StreamLogsCommand>(cmd => rc        = cmd.Run(cancellationToken))
                .WithParsed <UpdateRuleCommand>(cmd => rc        = cmd.Run(cancellationToken))
                .WithParsed <InvokeRuleCommand>(cmd => rc        = cmd.Run(cancellationToken))
                .WithParsed <ListMappingsCommand>(cmd => rc      = cmd.Run(cancellationToken))
                .WithParsed <MapRuleCommand>(cmd => rc           = cmd.Run(cancellationToken))
                .WithParsed <UnmapRuleCommand>(cmd => rc         = cmd.Run(cancellationToken))
                .WithParsed <UpdateMappingsCommand>(cmd => rc    = cmd.Run(cancellationToken))
                .WithParsed <MapLocalRuleCommand>(cmd => rc      = cmd.Run(cancellationToken))
                .WithNotParsed(errs =>
                {
                    var helpText = HelpText.AutoBuild(parserResult);
                    Console.Error.Write(helpText);
                    rc = ExitCodes.InvalidArguments;
                });


                mainTimer.Stop();
                Telemetry.TrackEvent("CLI End", null,
                                     new Dictionary <string, double> {
                    { "RunDuration", mainTimer.ElapsedMilliseconds }
                });

                Telemetry.Shutdown();

                Console.ForegroundColor = save;
                Console.CancelKeyPress -= cancelEventHandler;
                return(rc);
            }
        }
예제 #4
0
        private static async Task <Dictionary <string, string> > UpdateDefaultFilesAsync(FunctionRuntimePackage package)
        {
            var uploadFiles = new Dictionary <string, string>();

            using (var archive = System.IO.Compression.ZipFile.OpenRead(package.RuntimePackageFile))
            {
                var entry = archive.Entries
                            .Single(e => string.Equals("aggregator-function.dll", e.Name, StringComparison.OrdinalIgnoreCase));

                using (var assemblyStream = entry.Open())
                {
                    await uploadFiles.AddFunctionDefaultFiles(assemblyStream);
                }
            }
            //TODO handle FileNotFound Exception when trying to get resource content, and resource not found
            return(uploadFiles);
        }