protected void ConfigureAzure()
        {
            // First try to acquire a token from the MSI endpoint
            var creds             = default(AzureCredentials);
            var credentialFactory = new AzureCredentialsFactory();

            // If the ResourceManagementClient does exist, already, just return it.
            if (this.AzureMgmt != null)
            {
                return;
            }
            else
            {
                this.logger.LogInformation("ResourcesRepository.ConfigureAzure() instantiating Azure Management Client...");
            }

            // Try acquiring a token (requires refactoring, learning new Fluent libraries as lots has changed from last time (a while ago))
            this.ClientId     = Environment.GetEnvironmentVariable(Constants.CLIENT_ID_ENV);
            this.ClientSecret = Environment.GetEnvironmentVariable(Constants.CLIENT_SECRET_ENV);
            this.TenantId     = Environment.GetEnvironmentVariable(Constants.TENANT_ID_ENV);

            // The tenant Id is always required (due to eventual RBAC assignments using Graph library which needs the tenant ID)
            if (string.IsNullOrWhiteSpace(this.TenantId))
            {
                throw new Exception($"Missing configuration for {Constants.TENANT_ID_ENV} which is always required!");
            }

            // If not all details for a service principal are present, try MSI.
            this.CredentialsUseSp = !(string.IsNullOrWhiteSpace(this.ClientId) || string.IsNullOrWhiteSpace(this.ClientSecret));
            if (this.CredentialsUseSp)
            {
                creds = credentialFactory.FromServicePrincipal(this.ClientId, this.ClientSecret, this.TenantId, AzureEnvironment.AzureGlobalCloud);
            }
            else
            {
                this.logger.LogInformation($"Incomplete details for service principal in environment (clientId, clientSecret or tenantId misssing), trying managed service identity.");
                try
                {
                    this.logger.LogInformation("ResourceGroupRepository - acquire token from local MSI.");
                    creds = credentialFactory.FromMSI(new MSILoginInformation(MSIResourceType.VirtualMachine),
                                                      AzureEnvironment.AzureGlobalCloud,
                                                      tenantId: this.TenantId)
                            .WithDefaultSubscription(this.SubscriptionId);
                }
                catch (MSILoginException msiex)
                {
                    this.logger.LogError($"Failed to acquire token for ResourceProviderRepository with managed service identity: {msiex.Message}!");
                    throw new Exception("Failed acquiring token!", msiex);
                }
            }

            // Token acquired, successfully. Now configure the API Endpoint
            this.AzureMgmt = Azure.Configure()
                             .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
                             .Authenticate(creds)
                             .WithSubscription(this.SubscriptionId);

            this.logger.LogInformation("ResourcesRepository.ConfigureAzure() succeeded creating fluent Azure Management Client!");
        }
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            int operationDelay   = 60000; //1min
            var resoureGroupName = System.Environment.GetEnvironmentVariable("RESOURCE_GROUP_NAME", EnvironmentVariableTarget.Process);
            var vmScalesetName   = System.Environment.GetEnvironmentVariable("VMSS_NAME", EnvironmentVariableTarget.Process);
            var subscriptionId   = System.Environment.GetEnvironmentVariable("SUBSCRIPTION_ID", EnvironmentVariableTarget.Process);

            string  COUNT       = req.Query["COUNT"];
            string  requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data        = JsonConvert.DeserializeObject(requestBody);

            COUNT = COUNT ?? data?.COUNT;

            int ftdCountInt = Convert.ToInt32(COUNT);

            log.LogWarning("FtdScaleOut:::: count str {0}, count int {1}", COUNT, ftdCountInt);
            log.LogWarning("FtdScaleOut:::: FTD ScaleOut Started (RG : {0}, VMSS: {1}, Count: {2})", resoureGroupName.ToString(), vmScalesetName.ToString(), ftdCountInt);

            var factory          = new AzureCredentialsFactory();
            var msiCred          = factory.FromMSI(new MSILoginInformation(MSIResourceType.AppService), AzureEnvironment.AzureGlobalCloud);
            var azure            = Azure.Configure().WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic).Authenticate(msiCred).WithSubscription(subscriptionId);
            var vMachineScaleSet = azure.VirtualMachineScaleSets.GetByResourceGroup(resoureGroupName, vmScalesetName);

            log.LogWarning("FtdScaleOut:::: Current VMSS Capacity : {0}", vMachineScaleSet.Capacity.ToString());
            var computeManagementClient = new ComputeManagementClient(msiCred)
            {
                SubscriptionId = azure.SubscriptionId
            };
            var update = computeManagementClient.VirtualMachineScaleSets.CreateOrUpdateWithHttpMessagesAsync(resoureGroupName, vmScalesetName,
                                                                                                             new VirtualMachineScaleSet
            {
                Location      = vMachineScaleSet.RegionName,
                Overprovision = false,
                Sku           = new Sku
                {
                    Capacity = vMachineScaleSet.Capacity + ftdCountInt,
                    Name     = vMachineScaleSet.Sku.Sku.Name,
                    Tier     = vMachineScaleSet.Sku.Sku.Tier
                }
            });

            log.LogInformation("FtdScaleOut:::: FTD Scale Out Started... Please wait");
            update.Wait(operationDelay);
            log.LogInformation("FtdScaleOut:::: FTD Scale Out Status : {0}", update.Status.ToString());

            if ("WaitingForActivation" != update.Status.ToString())
            {
                log.LogError("FtdScaleOut:::: ScaleOut Operation failed (Status : {0})", update.Status.ToString());
                return((ActionResult) new BadRequestObjectResult("ERROR: ScaleOut Operation failed"));
            }

            vMachineScaleSet = azure.VirtualMachineScaleSets.GetByResourceGroup(resoureGroupName, vmScalesetName);
            log.LogWarning("FtdScaleOut:::: Post ScaleOut VMSS Capacity : {0}", vMachineScaleSet.Capacity.ToString());
            return((ActionResult) new OkObjectResult("SUCCESS"));
        }
Beispiel #3
0
        public static async Task <IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestMessage req, ILogger log)
        {
            AzureCredentialsFactory factory = new AzureCredentialsFactory();
            AzureCredentials        msiCred = factory.FromMSI(new MSILoginInformation(MSIResourceType.AppService), AzureEnvironment.AzureGlobalCloud);
            var azure = Azure.Configure().WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic).Authenticate(msiCred).WithDefaultSubscription();

            var nsg = azure.NetworkSecurityGroups.GetByResourceGroup("TestNSGRG", "RSTestNSG1");

            return((ActionResult) new OkObjectResult(string.Format("NSG {0} found with {1} default security rules", nsg.Name, nsg.DefaultSecurityRules.Count)));
        }
Beispiel #4
0
        public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestMessage req, TraceWriter log)
        {
            log.Info("Getting request body params");
            dynamic data = await req.Content.ReadAsAsync <object>();

            string subscriptionId    = data?.subscriptionId;
            string resourceGroupName = data?.resourceGroupName;
            string vmName            = data?.vmName;

            if (subscriptionId == null || resourceGroupName == null || vmName == null)
            {
                return(req.CreateResponse(HttpStatusCode.BadRequest, "Please pass all 3 required parameters in the request body"));
            }

            log.Info("Setting authentication to use MSI");
            AzureCredentialsFactory f = new AzureCredentialsFactory();
            var msi = new MSILoginInformation(MSIResourceType.AppService);

            var msiCred = f.FromMSI(msi, AzureEnvironment.AzureGlobalCloud);

            var azureAuth = Azure.Configure()
                            .WithLogLevel(HttpLoggingDelegatingHandler.Level.BodyAndHeaders)
                            .Authenticate(msiCred);

            log.Info("Authenticating with Azure using MSI");
            var azure = azureAuth.WithSubscription(subscriptionId);

            log.Info("Acquiring VM from Azure");
            var vm = azure.VirtualMachines.GetByResourceGroup(resourceGroupName, vmName);

            log.Info("Checking VM Id");
            log.Info(vm.Id.ToString());

            log.Info("Checking VM Powerstate");
            log.Info("VM Powerstate : " + vm.PowerState.ToString());

            bool vmStarting = false;

            if (vm.PowerState.ToString() == "PowerState/running")
            {
                log.Info("VM is already running");
            }
            else
            {
                log.Info("Starting vm " + vmName);
                await vm.StartAsync();

                vmStarting = true;
            }

            return(vmStarting == false
            ? req.CreateResponse(HttpStatusCode.OK, "VM was already started")
            : req.CreateResponse(HttpStatusCode.OK, "VM started"));
        }
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            int     operationDelay   = 90000; //1.5min
            var     resoureGroupName = System.Environment.GetEnvironmentVariable("RESOURCE_GROUP_NAME", EnvironmentVariableTarget.Process);
            var     vmScalesetName   = System.Environment.GetEnvironmentVariable("VMSS_NAME", EnvironmentVariableTarget.Process);
            var     subscriptionId   = System.Environment.GetEnvironmentVariable("SUBSCRIPTION_ID", EnvironmentVariableTarget.Process);
            string  instanceid       = req.Query["instanceid"];
            string  requestBody      = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data             = JsonConvert.DeserializeObject(requestBody);

            instanceid = instanceid ?? data?.instanceid;
            int vmssCapacity = 0;

            if (null == instanceid)
            {
                log.LogError("FtdScaleIn:::: Invalid FTD Instance Id for ScaleIn");
                return((ActionResult) new BadRequestObjectResult("ERROR: Invalid FTD Instance Id for ScaleIn"));
            }

            log.LogWarning("FtdScaleIn:::: FTD Scale-In Started (RG : {0}, VMSS: {1}, FTD InstanceId to Delete: {2} )", resoureGroupName.ToString(), vmScalesetName.ToString(), instanceid);

            var factory = new AzureCredentialsFactory();
            var msiCred = factory.FromMSI(new MSILoginInformation(MSIResourceType.AppService), AzureEnvironment.AzureGlobalCloud);
            var azure   = Azure.Configure().WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic).Authenticate(msiCred).WithSubscription(subscriptionId);

            var vMachineScaleSet = azure.VirtualMachineScaleSets.GetByResourceGroup(resoureGroupName, vmScalesetName);

            vmssCapacity = vMachineScaleSet.Capacity;
            log.LogInformation("FtdScaleIn:::: Current VMSS Capacity : {0}", vmssCapacity);

            var computeManagementClient = new ComputeManagementClient(msiCred)
            {
                SubscriptionId = azure.SubscriptionId
            };
            //var del = computeManagementClient.VirtualMachineScaleSetVMs.DeleteWithHttpMessagesAsync(resoureGroupName, vmScalesetName, instanceid).Result;
            var del = computeManagementClient.VirtualMachineScaleSetVMs.DeleteWithHttpMessagesAsync(resoureGroupName, vmScalesetName, instanceid);

            del.Wait(operationDelay);

            vMachineScaleSet = azure.VirtualMachineScaleSets.GetByResourceGroup(resoureGroupName, vmScalesetName);
            log.LogInformation("FtdScaleIn:::: Post ScaleIn VMSS Capacity : {0}", vMachineScaleSet.Capacity.ToString());

            if ((vmssCapacity - 1) != vMachineScaleSet.Capacity)
            {
                log.LogError("FtdScaleIn:::: Failed ScaleIn Operation (vmss capacity: {0})", vMachineScaleSet.Capacity);
                return((ActionResult) new BadRequestObjectResult("ERROR: Failed ScaleIn Operation. Don't worry, Azure may be taking longer time to delete, but eventually it may delete"));
            }

            return((ActionResult) new OkObjectResult("SUCCESS"));
        }
        private static IAzure Authenticate(string subscriptionId, IConfiguration config)
        {
            // Check if the Azure Function runs locally
            var debug = config["Debug"];

            if (!string.IsNullOrWhiteSpace(debug) &&
                string.Compare(debug, "true", 0) == 0)
            {
                // Specifies the client id of the service principal to use when debugging locally
                var clientId = config["ClientId"];
                if (string.IsNullOrWhiteSpace(clientId))
                {
                    throw new ArgumentNullException(nameof(clientId), $"{nameof(clientId)} app setting cannot be null or empty.");
                }

                // Specifies the client secret of the service principal to use when debugging locally
                var clientSecret = config["ClientSecret"];
                if (string.IsNullOrWhiteSpace(clientSecret))
                {
                    throw new ArgumentNullException(nameof(clientSecret), $"{nameof(clientSecret)} app setting cannot be null or empty.");
                }

                // Specifies the tenant id to use when debugging locally
                var tenantId = config["TenantId"];
                if (string.IsNullOrWhiteSpace(tenantId))
                {
                    throw new ArgumentNullException(nameof(tenantId), $"{nameof(tenantId)} app setting cannot be null or empty.");
                }

                var creds = new AzureCredentialsFactory().FromServicePrincipal(clientId, clientSecret, tenantId, AzureEnvironment.AzureGlobalCloud);
                return(Azure.Authenticate(creds).WithSubscription(subscriptionId));
            }
            else
            {
                var factory     = new AzureCredentialsFactory();
                var credentials = factory.FromMSI(new MSILoginInformation(MSIResourceType.AppService),
                                                  AzureEnvironment.AzureGlobalCloud);
                return(Azure.Configure().
                       WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic).
                       Authenticate(credentials).WithSubscription(subscriptionId));
            }
        }
Beispiel #7
0
        public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req, TraceWriter log)
        {
            log.Info("Getting request body params");
            dynamic data = await req.Content.ReadAsAsync <object>();

            string subscriptionId = data?.subscriptionId;

            if (subscriptionId == null)
            {
                return(req.CreateResponse(HttpStatusCode.BadRequest, "Please pass subscriptionId in the request body"));
            }


            log.Info("Setting credentials from MSI");
            AzureCredentialsFactory f = new AzureCredentialsFactory();
            var msi = new MSILoginInformation(MSIResourceType.AppService);

            var msiCred = f.FromMSI(msi, AzureEnvironment.AzureGlobalCloud);

            var azureAuth = Azure.Configure()
                            .WithLogLevel(HttpLoggingDelegatingHandler.Level.BodyAndHeaders)
                            .Authenticate(msiCred);

            log.Info("Authenticating with Azure using MSI");
            var azure = azureAuth.WithSubscription(subscriptionId);

            log.Info("Getting list of VMs");
            var vms = azure.VirtualMachines.List();

            log.Info("Creating stringlist");
            var vmstringlist = string.Join(", ", (from vm in vms
                                                  select vm.Name).ToList());

            log.Info("Debug: " + vmstringlist);

            var vmDto = (from vm in vms
                         select new { name = vm.Name, powerstate = vm.PowerState.ToString(), resourcegroupname = vm.ResourceGroupName }).ToList();


            return(req.CreateResponse(HttpStatusCode.OK, vmDto));
        }
Beispiel #8
0
            public static AzureCredentials GetAzureCreds(bool UseMSI)
            {
                //MSI Login
                AzureCredentialsFactory f   = new AzureCredentialsFactory();
                MSILoginInformation     msi = new MSILoginInformation(MSIResourceType.AppService);
                AzureCredentials        creds;


                if (UseMSI == true)
                {
                    //MSI
                    creds = f.FromMSI(msi, AzureEnvironment.AzureGlobalCloud);
                }
                else
                {
                    //Service Principal
                    creds = f.FromServicePrincipal(Helpers.GlobalConfigs.ApplicationId, Helpers.GlobalConfigs.AuthenticationKey, Helpers.GlobalConfigs.TenantId, AzureEnvironment.AzureGlobalCloud);
                }

                return(creds);
            }
Beispiel #9
0
                //Gets AzureCredentials Object Using SDK Helper Classes
                public static AzureCredentials GetAzureCreds(bool UseMSI)
                {
                    //MSI Login
                    AzureCredentialsFactory f   = new AzureCredentialsFactory();
                    MSILoginInformation     msi = new MSILoginInformation(MSIResourceType.AppService);
                    AzureCredentials        creds;


                    if (UseMSI == true)
                    {
                        //MSI
                        creds = f.FromMSI(msi, AzureEnvironment.AzureGlobalCloud);
                    }
                    else
                    {
                        //Service Principal
                        creds = f.FromServicePrincipal(Shared._DownstreamAuthOptionsDirect.ClientId, Shared._DownstreamAuthOptionsDirect.ClientSecret, Shared._DownstreamAuthOptionsDirect.TenantId, AzureEnvironment.AzureGlobalCloud);
                    }

                    return(creds);
                }
Beispiel #10
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            var subscriptionId = System.Environment.GetEnvironmentVariable("SUBSCRIPTION_ID", EnvironmentVariableTarget.Process);

            string  COUNT       = req.Query["COUNT"];
            string  requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data        = JsonConvert.DeserializeObject(requestBody);

            COUNT = COUNT ?? data?.COUNT;

            string  TYPE         = req.Query["TYPE"];
            string  requestBody1 = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data1        = JsonConvert.DeserializeObject(requestBody);

            TYPE = TYPE ?? data?.TYPE;

            int ftdCountInt = Convert.ToInt32(COUNT);
            int index       = 1;

            if ("REGULAR" == TYPE)
            {
                log.LogWarning("GetFtdPublicIp:::: This is regular scale-out ");
            }
            else if ("INIT" == TYPE)
            {
                log.LogWarning("GetFtdPublicIp:::: This is initial deployment");
            }
            else
            {
                return((ActionResult) new BadRequestObjectResult("ERROR: Invalid request TYPE"));
            }
            var resoureGroupName     = System.Environment.GetEnvironmentVariable("RESOURCE_GROUP_NAME", EnvironmentVariableTarget.Process);
            var vmScalesetName       = System.Environment.GetEnvironmentVariable("VMSS_NAME", EnvironmentVariableTarget.Process);
            var networkInterfaceName = System.Environment.GetEnvironmentVariable("MNGT_NET_INTERFACE_NAME", EnvironmentVariableTarget.Process);
            var ipConfigurationName  = System.Environment.GetEnvironmentVariable("MNGT_IP_CONFIG_NAME", EnvironmentVariableTarget.Process);
            var publicIpAddressName  = System.Environment.GetEnvironmentVariable("MNGT_PUBLIC_IP_NAME", EnvironmentVariableTarget.Process);

            log.LogWarning("GetFtdPublicIp:::: Getting Public IP of new FTD (RG : {0}, VMSS: {1} )", resoureGroupName.ToString(), vmScalesetName.ToString());
            log.LogInformation("GetFtdPublicIp:::: Network Interface name : {0}, IP Configuration Name : {1}, Public IP Address Name : {2}", networkInterfaceName, ipConfigurationName, publicIpAddressName);

            var factory = new AzureCredentialsFactory();
            var msiCred = factory.FromMSI(new MSILoginInformation(MSIResourceType.AppService), AzureEnvironment.AzureGlobalCloud);
            var azure   = Azure.Configure().WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic).Authenticate(msiCred).WithSubscription(subscriptionId);

            var NmClient = new NetworkManagementClient(msiCred)
            {
                SubscriptionId = azure.SubscriptionId
            };
            var    interfaceList = NmClient.NetworkInterfaces.ListVirtualMachineScaleSetNetworkInterfaces(resoureGroupName, vmScalesetName);
            string vmindex       = "";
            string tmpVmindex    = "";
            int    intVmindex    = 0;
            var    vmlist        = azure.VirtualMachineScaleSets.GetByResourceGroup(resoureGroupName, vmScalesetName);
            var    vmStatus      = "";
            var    tmpVmName     = "ERROR";

            //ToDo: This logic should be simplified with just one loop of vmlist, no need of interfaceList
            foreach (var netInterface in interfaceList)
            {
                if (netInterface.IpConfigurations[0].PublicIPAddress != null)
                {
                    var tmpIntfName   = netInterface.IpConfigurations[0].PublicIPAddress.Id.Split('/').GetValue(12);
                    var tmpConfigName = netInterface.IpConfigurations[0].PublicIPAddress.Id.Split('/').GetValue(14);
                    var tmpPubIpName  = netInterface.IpConfigurations[0].PublicIPAddress.Id.Split('/').GetValue(16);

                    if ((tmpIntfName.ToString() == networkInterfaceName) && (tmpConfigName.ToString() == ipConfigurationName) && (tmpPubIpName.ToString() == publicIpAddressName))
                    {
                        vmindex  = netInterface.IpConfigurations[0].PublicIPAddress.Id.Split('/').GetValue(10).ToString();
                        vmStatus = "ON";
                        foreach (var vm in vmlist.VirtualMachines.List())
                        {
                            if (vm.InstanceId == vmindex)
                            {
                                if (null == vm.PowerState)
                                {
                                    vmStatus = "OFF";
                                }
                                if (null != vm.Name)
                                {
                                    tmpVmName = vm.Name;
                                }
                                break;
                            }
                        }
                        //Azure bug, VM will be present in Azure DB for long time even after deletion
                        if ("OFF" == vmStatus)
                        {
                            log.LogError("GetFtdPublicIp:::: VM index :{0} is in unknown state..skip", vmindex);
                            continue;
                        }
                        //Azure bug, some times even deleted VMs are still attahed to network interfaces
                        if ("ERROR" == tmpVmName)
                        {
                            log.LogError("GetFtdPublicIp:::: VM index :{0} VM name not found...skip", vmindex);
                            continue;
                        }
                        if ("INIT" == TYPE)
                        {
                            if (index == ftdCountInt)
                            {
                                //index >100 is just to safegaurd this loop..its has no other logic
                                break;
                            }
                            index++;
                        }
                        else
                        {
                            //Azure bug: Some time it will mix indexes and does not preserve sequence
                            if (Convert.ToInt32(vmindex) < intVmindex)
                            {
                                log.LogWarning("GetFtdPublicIp:::: Azure index jumbling detected");
                                vmindex = intVmindex.ToString();
                            }
                            else
                            {
                                intVmindex = Convert.ToInt32(vmindex);
                                log.LogInformation("GetFtdPublicIp:::: Assigning vmindex = {0}", vmindex);
                            }
                        }
                    }
                }
            }

            var publicIp = NmClient.PublicIPAddresses.GetVirtualMachineScaleSetPublicIPAddress(resoureGroupName, vmScalesetName, vmindex, networkInterfaceName, ipConfigurationName, publicIpAddressName).IpAddress;

            if (null == publicIp)
            {
                log.LogError("GetFtdPublicIp:::: Unable to get Public IP of new FTD (index {0}", vmindex);
                return((ActionResult) new BadRequestObjectResult("ERROR: Unable to get Public IP of new FTD"));
            }
            log.LogInformation("GetFtdPublicIp:::: Public IP of New FTD (VM index {0}) = {1}", vmindex, publicIp);

            //find VM name from index
            string vmname    = "";
            string privateIp = "";
            var    vmss      = azure.VirtualMachineScaleSets.GetByResourceGroup(resoureGroupName, vmScalesetName);

            foreach (var vm in vmss.VirtualMachines.List())
            {
                if (vm.InstanceId == vmindex)
                {
                    vmname = vm.Name;
                    foreach (var netintf in vm.ListNetworkInterfaces())
                    {
                        privateIp = netintf.PrimaryPrivateIP;
                        break;
                    }
                    break;
                }
            }

            var commandStr = "{ \"ftdDevName\": \"" + vmname + "\", \"ftdPublicIp\": \"" + publicIp + "\", \"ftdPrivateIp\" : \"" + privateIp + "\"  }";

            return((ActionResult) new OkObjectResult(commandStr));
        }
Beispiel #11
0
        public static void Run([TimerTrigger("0 0 15 * * *")] TimerInfo myTimer, TraceWriter log)  // 10:00AM eastern
        {
            log.Info($"{DateTime.Now} : Function starting...");
            int    sqlOffenses = 0;
            string botToken    = Environment.GetEnvironmentVariable("botToken");
            string ruleChange  = Environment.GetEnvironmentVariable("UpdateRules");
            string whiteList   = Environment.GetEnvironmentVariable("WhiteList");

            if (string.IsNullOrEmpty(botToken))
            {
                log.Error($"{DateTime.Now} : One or more of the required app settings is missing, check the Azure portal to verify all parameters.");
                return;
            }

            var slackClient = new SlackClient(new HttpClient(), botToken);
            var slackPost   = new SlackPost {
                Channel = Environment.GetEnvironmentVariable("channel"), Text = "Azure SQL FW Auditor findings"
            };

            if (!bool.TryParse(ruleChange, out bool updateFwSetting))
            {
                updateFwSetting = false;
                log.Info($"{DateTime.Now} : Unable to parse 'UpdateRules' setting {ruleChange}. Defaulting to False");
            }
            else
            {
                log.Info($"{DateTime.Now} : UpdateRules variable set to {updateFwSetting}");
            }


            AzureCredentialsFactory credFactorty = new AzureCredentialsFactory();
            var msi       = new MSILoginInformation(MSIResourceType.AppService);
            var msiCred   = credFactorty.FromMSI(msi, AzureEnvironment.AzureGlobalCloud);
            var azureAuth = Azure.Configure()
                            .WithLogLevel(HttpLoggingDelegatingHandler.Level.BodyAndHeaders)
                            .Authenticate(msiCred);


            var approvedRanges = string.IsNullOrEmpty(whiteList) ? ipRanges.ToList() : ipRanges.Union(whiteList.Split(',')).ToList();

            log.Info($"{DateTime.Now} : Authenticated into tenant... Pulling subscriptions");
            var fields = new List <SlackField>();

            foreach (var sub in azureAuth.Subscriptions.List())
            {
                log.Verbose($"{DateTime.Now} : Logging into subscription : {sub.SubscriptionId.ToString()}");
                var azure = Azure.Configure()
                            .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
                            .Authenticate(msiCred).WithSubscription(sub.SubscriptionId.ToString());

                // loop through the sql servers in the subscription
                foreach (var server in azure.SqlServers.List())
                {
                    var outOfRangeRules = server.FirewallRules.List().Where(ruleDef => IsIpInRange(ruleDef.StartIPAddress, approvedRanges) == false || IsIpInRange(ruleDef.EndIPAddress, approvedRanges) == false);
                    // process all the rules that are deemed bad
                    foreach (var firewallRule in outOfRangeRules)
                    {
                        var field = new SlackField {
                            Short = false, Title = " ",
                        };

                        // The appsetting is set to true, so we try and delete the rule.
                        if (updateFwSetting)
                        {
                            try
                            {
                                firewallRule.Delete();
                                field.Value = $"Server - {server.Name}, Firewall Rule(s) : \r\n>{firewallRule.Name} : {firewallRule.StartIPAddress} - {firewallRule.EndIPAddress} *Deleted : YES*";
                            }
                            catch (Exception e)
                            {
                                field.Value = $"Server - {server.Name}, Firewall Rule(s) : \r\n>{firewallRule.Name} : {firewallRule.StartIPAddress} - {firewallRule.EndIPAddress} *Deleted : NO, encountered exception*";
                                log.Warning($"{DateTime.Now} : {e.Message}");
                            }
                        }
                        else
                        {
                            field.Value = $"{server.Name}, Firewall Rule(s) : \r\n>{firewallRule.Name} : {firewallRule.StartIPAddress} - {firewallRule.EndIPAddress} *Deleted : NO, deletion not enabled.*";
                            log.Info($"{DateTime.Now} : FW setting {updateFwSetting} firewall rule {firewallRule.Name} will be left to fester here");
                        }

                        sqlOffenses++;
                    }

                    // Once its clean we add in missing ranges
                    AddInMissingIpRanges(log, server);
                }
            }

            if (fields.Any())
            {
                slackPost.Attachments = new List <SlackAttachment>()
                {
                    new SlackAttachment {
                        Fields = fields, Color = "ok", Title = " ",
                    }
                };
                _ = slackClient.PostToSlackAsync(slackPost);
            }
        }
Beispiel #12
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogWarning("AutoScaleManager:::: Task to check Scaling requirement.. Started (ASM Version : V3.1)");
            var subscriptionId          = System.Environment.GetEnvironmentVariable("SUBSCRIPTION_ID", EnvironmentVariableTarget.Process);
            var resoureGroupName        = System.Environment.GetEnvironmentVariable("RESOURCE_GROUP_NAME", EnvironmentVariableTarget.Process);
            var vmScalesetName          = System.Environment.GetEnvironmentVariable("VMSS_NAME", EnvironmentVariableTarget.Process);
            var minFTDCountStr          = System.Environment.GetEnvironmentVariable("MIN_FTD_COUNT", EnvironmentVariableTarget.Process);
            var maxFTDCountStr          = System.Environment.GetEnvironmentVariable("MAX_FTD_COUNT", EnvironmentVariableTarget.Process);
            var sampleTimeMin           = System.Environment.GetEnvironmentVariable("SAMPLING_TIME_MIN", EnvironmentVariableTarget.Process);
            var scaleOutThresholdCpuStr = System.Environment.GetEnvironmentVariable("SCALE_OUT_THRESHLD_CPU", EnvironmentVariableTarget.Process);
            var scaleInThresholdCpuStr  = System.Environment.GetEnvironmentVariable("SCALE_IN_THRESHLD_CPU", EnvironmentVariableTarget.Process);
            var scaleOutThresholdMemStr = System.Environment.GetEnvironmentVariable("SCALE_OUT_THRESHLD_MEM", EnvironmentVariableTarget.Process);
            var scaleInThresholdMemStr  = System.Environment.GetEnvironmentVariable("SCALE_IN_THRESHLD_MEM", EnvironmentVariableTarget.Process);
            var initialDeployMethod     = System.Environment.GetEnvironmentVariable("INITIAL_DEPLOYMENT_MODE", EnvironmentVariableTarget.Process); //supported STEP / BULK
            var scalingPolicy           = System.Environment.GetEnvironmentVariable("SCALING_POLICY", EnvironmentVariableTarget.Process);          // POLICY-1 / POLICY-2
            var metrics = System.Environment.GetEnvironmentVariable("SCALING_METRICS_LIST", EnvironmentVariableTarget.Process).ToLower();

            int    minFTDCount          = Convert.ToInt32(minFTDCountStr);
            int    maxFTDCount          = Convert.ToInt32(maxFTDCountStr);
            double scaleOutThresholdCpu = Convert.ToDouble(scaleOutThresholdCpuStr);
            double scaleInThresholdCpu  = Convert.ToDouble(scaleInThresholdCpuStr);
            double scaleOutThresholdMem = Convert.ToDouble(scaleOutThresholdMemStr);
            double scaleInThresholdMem  = Convert.ToDouble(scaleInThresholdMemStr);
            int    currentVmCapacity    = 0;
            string scaleStr             = "";

            log.LogInformation("CPU Scale Out threshold: {0}%, Scale In threshold : {1}%", scaleOutThresholdCpu, scaleInThresholdCpu);
            // log.LogInformation("Memory Scale Out threshold: {0}%, Scale In threshold : {1}%", scaleOutThresholdMem, scaleInThresholdMem);

            //Reject if CPU scale Out Threshold < scale In Threshold
            if (scaleOutThresholdCpu <= scaleInThresholdCpu)
            {
                log.LogError("AutoScaleManager:::: CPU metrics ScaleOut Threshold ({0}) is less than or equal to ScaleIn Threshold ({1}) this is not correct", scaleOutThresholdCpu, scaleInThresholdCpu);
                return((ActionResult) new BadRequestObjectResult("ERROR: CPU Metrics ScaleOut threshold is less than or equal to ScaleIn threshold"));
            }

            //Validate Metrics
            if ((!metrics.Contains("cpu")) && (!metrics.Contains("memory")))
            {
                log.LogError("AutoScaleManager:::: Invalid metrics specified : {0} (valid metrics are CPU or CPU, Memory)", metrics);
                return((ActionResult) new BadRequestObjectResult("ERROR: Invalid Metrics..Can not continue"));
            }


            //Check FMC connection, If we can not connect to FMC do not continue
            log.LogInformation("AutoScaleManager:::: Checking FMC connection");

            var    getAuth   = new fmcAuthClass();
            string authToken = getAuth.getFmcAuthToken(log);

            if ("ERROR" == authToken)
            {
                log.LogError("AutoScaleManager:::: Failed to connect to FMC..Can not continue");
                return((ActionResult) new BadRequestObjectResult("ERROR: Failed to connet to FMC..Can not continue"));
            }

            log.LogInformation("AutoScaleManager:::: Sampling Resource Utilization at {0}min Average", sampleTimeMin);

            var factory = new AzureCredentialsFactory();
            var msiCred = factory.FromMSI(new MSILoginInformation(MSIResourceType.AppService), AzureEnvironment.AzureGlobalCloud);
            var azure   = Azure.Configure().WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic).Authenticate(msiCred).WithSubscription(subscriptionId);

            string resourceUri = null;
            var    vmss        = azure.VirtualMachineScaleSets.GetByResourceGroup(resoureGroupName, vmScalesetName);

            resourceUri = vmss.Id;

            if (null == resourceUri)
            {
                log.LogError("AutoScaleManager:::: Unable to get resource uri");
                return((ActionResult) new BadRequestObjectResult("ERROR: Unable to get resource uri"));
            }

            currentVmCapacity = vmss.Capacity;
            log.LogWarning("AutoScaleManager:::: Current capacity of VMSS : {0}", currentVmCapacity);

            //If the VMSS capacity is '0' consider this as first deployment and spawn 'minimum FTD count' at a time
            if ((0 == currentVmCapacity) && (0 != minFTDCount))
            {
                log.LogWarning("AutoScaleManager:::: Current VMSS capacity is 0, considering it as first deployment (min FTD count needed : {0}", minFTDCount);
                if ("BULK" == initialDeployMethod)
                {
                    log.LogWarning("AutoScaleManager:::: Selected initial deployment mode is BULK");
                    log.LogWarning("AutoScaleManager:::: Deploying {0} number of FTDvs in scale set", minFTDCount);
                    scaleStr = "{ \"COMMAND\": \"SCALEOUT\", \"COUNT\": \"" + minFTDCount + "\", \"TYPE\": \"INIT\" }";
                    return((ActionResult) new OkObjectResult(scaleStr));
                }
                else
                {
                    log.LogWarning("AutoScaleManager:::: BULK method is not selected for initial deployment.. proceeding with STEP");
                    scaleStr = "{ \"COMMAND\": \"SCALEOUT\", \"COUNT\": \"1\", \"TYPE\": \"REGULAR\"}";
                    return((ActionResult) new OkObjectResult(scaleStr));
                }
            }

            //If current capacity is less than minimum FTD count requied then we need to scale-out
            if (currentVmCapacity < minFTDCount)
            {
                log.LogWarning("AutoScaleManager:::: Current VMSS Capacity({0}) is less than minimum FTD count ({1}) needed.. time to SCALE-OUT", currentVmCapacity, minFTDCount);
                scaleStr = "{ \"COMMAND\": \"SCALEOUT\", \"COUNT\": \"1\", \"TYPE\": \"REGULAR\"}";
                return((ActionResult) new OkObjectResult(scaleStr));
            }


            //-------------------------------------------------Scaling decission based on Metrics------------------------------------------------------
            log.LogWarning("AutoScaleManager:::: Scaling Policy : {0}", scalingPolicy);

            var sampleIntervalMin = System.TimeSpan.FromMinutes(Convert.ToDouble(sampleTimeMin));
            MonitorManagementClient metricClient = new MonitorManagementClient(msiCred);
            double ftdCpuUsage            = 0;
            double groupCpuUsage          = 0;
            double consolidatedCpuUsage   = 0;
            bool   scaleInRejectFlag      = false;
            double minFtdCpuUsage         = 9999;
            string leastCpuLoadedFtd      = "";
            string leastCpuLoadedFtdIndex = "";
            bool   memoryMetricsEnabled   = false;

            double ftdMemUsage                   = 0;
            double groupMemUsage                 = 0;
            double consolidatedMemUsage          = 0;
            string ftdNameWithHighMemUtilization = "";

            //Get FTD's Memory if 'Memory' metrics is enabled
            if (metrics.Contains("memory"))
            {
                memoryMetricsEnabled = true;
                log.LogInformation("Memory metrics enabled");
                log.LogInformation("Memory Scale Out threshold: {0}%, Scale In threshold : {1}%", scaleOutThresholdMem, scaleInThresholdMem);

                //Reject if Memory scale Out Threshold < scale In Threshold
                if (scaleOutThresholdMem <= scaleInThresholdMem)
                {
                    log.LogError("AutoScaleManager:::: Memory metrics ScaleOut Threshold ({0}) is less than or equal to ScaleIn Threshold ({1}) this is not correct", scaleOutThresholdMem, scaleInThresholdMem);
                    return((ActionResult) new BadRequestObjectResult("ERROR: Memory Metrics ScaleOut threshold is less than or equal to ScaleIn threshold"));
                }

                var getMetrics = new getMetricsClass();
                var getId      = new getDevIdByNameClass();
                var devIds     = getId.getAllDevId(authToken, log);
                if ("ERROR" == devIds)
                {
                    log.LogError("AutoScaleManager::::Unable to get device IDs");
                    return((ActionResult) new StatusCodeResult(StatusCodes.Status500InternalServerError));
                }
                //parse json object
                JObject o = JObject.Parse(devIds);

                foreach (var vm in vmss.VirtualMachines.List())
                {
                    var vmName = vm.Name.ToString();
                    var devId  = "";
                    try
                    {
                        foreach (var item in o["items"])
                        {
                            if (vmName == item["name"].ToString())
                            {
                                devId = item["id"].ToString();
                                break;
                            }
                        }
                        if (0 == devId.Length)
                        {
                            log.LogError("AutoScaleManager:::: Unable to get Device ID for Device Name({0})", vmName);
                            return((ActionResult) new StatusCodeResult(StatusCodes.Status500InternalServerError));
                        }
                    }
                    catch
                    {
                        log.LogError("AutoScaleManager:::: Exception Occoured while parsing device id response");
                        return((ActionResult) new StatusCodeResult(StatusCodes.Status500InternalServerError));
                    }

                    ftdMemUsage = Convert.ToDouble(getMetrics.getFtdMemoryMetrics(devId, authToken, log));
                    if (-1 == ftdMemUsage)
                    {
                        log.LogError("AutoScaleManager:::: Failed to get Memory usage of {0}", vmName);
                        return((ActionResult) new StatusCodeResult(StatusCodes.Status500InternalServerError));
                    }
                    if (ftdMemUsage > scaleInThresholdMem)
                    {
                        //No need to Scale-In
                        scaleInRejectFlag = true;
                    }
                    log.LogInformation("AutoScaleManager:::: Memory usage of {0} is {1} %", vmName, ftdMemUsage);
                    if ("POLICY-1" == scalingPolicy)
                    {
                        if (ftdMemUsage > scaleOutThresholdMem)
                        {
                            log.LogWarning("AutoScaleManager:::: FTD {0} has Memory Utilization of {1} % which is greater than Scale Out threshold", vmName, ftdMemUsage);
                            ftdNameWithHighMemUtilization = vmName;
                            break;
                        }
                    }
                    else if ("POLICY-2" == scalingPolicy)
                    {
                        groupMemUsage += ftdMemUsage;
                    }
                }
                groupMemUsage /= vmss.Capacity;
                if ("POLICY-2" == scalingPolicy)
                {
                    log.LogInformation("AutoScaleManager:::: Group Memory average usage : {0} %", groupMemUsage);
                }
            }
            else
            {
                //Memory metrics not enabled, reset thresholds
                scaleOutThresholdMem = 0;
            }


            if ("POLICY-2" == scalingPolicy)
            {
                log.LogInformation("AutoScaleManager:::: Scaling Policy-2 Selected..Getting average CPU utilization of scale set");
                var response = await metricClient.Metrics.ListAsync(resourceUri, null, null, sampleIntervalMin, "Percentage CPU", "Average");

                foreach (var metric in response.Value)
                {
                    foreach (var series in metric.Timeseries)
                    {
                        foreach (var point in series.Data)
                        {
                            if (point.Average.HasValue)
                            {
                                groupCpuUsage = point.Average.Value;
                                log.LogDebug("AutoScaleManager:::: avg cpu: {0}", groupCpuUsage);
                            }
                        }
                    }
                }
                log.LogInformation("AutoScaleManager:::: Group CPU average usage : {0} %", groupCpuUsage);
            }

            foreach (var vm in vmss.VirtualMachines.List())
            {
                var vmName = vm.Name;
                ftdCpuUsage = 0;
                //Metrics filter
                ODataQuery <MetadataValue> odataFilterMetrics = new ODataQuery <MetadataValue>(string.Format("VMName eq '{0}'", vmName));

                // log.LogInformation("AutoScaleManager:::: Getting Metrics for : {0}", vmName);
                var response = await metricClient.Metrics.ListAsync(resourceUri, odataFilterMetrics, null, sampleIntervalMin, "Percentage CPU", "Average");

                foreach (var metric in response.Value)
                {
                    foreach (var series in metric.Timeseries)
                    {
                        foreach (var point in series.Data)
                        {
                            if (point.Average.HasValue)
                            {
                                ftdCpuUsage = point.Average.Value;
                                log.LogDebug("AutoScaleManager:::: avg cpu: {0}", ftdCpuUsage);
                            }
                        }
                    }
                }

                log.LogInformation("AutoScaleManager:::: Avg CPU Utilizatio of VM({0}) in last {1}min : {2}%", vmName, sampleTimeMin, ftdCpuUsage);

                //Maintain the FTD with minimum utilization to scale-in if needed
                if (ftdCpuUsage < minFtdCpuUsage)
                {
                    minFtdCpuUsage         = ftdCpuUsage;
                    leastCpuLoadedFtd      = vmName;
                    leastCpuLoadedFtdIndex = vm.InstanceId;
                }

                if ("POLICY-1" == scalingPolicy)
                {
                    //Average usage of individual Instance
                    consolidatedCpuUsage = ftdCpuUsage;
                    consolidatedMemUsage = ftdMemUsage;
                }
                else if ("POLICY-2" == scalingPolicy)
                {
                    //Scale Set average utilization
                    consolidatedCpuUsage = groupCpuUsage;
                    consolidatedMemUsage = groupMemUsage;
                }
                else
                {
                    log.LogError("AutoScaleManager:::: Invalid Scaling Policy {0}", scalingPolicy);
                    return((ActionResult) new BadRequestObjectResult("ERROR: Invalid Scaling Policy"));
                }

                //If CPU utilization is greater than scale-out threshold then Scale-Out
                //Note: if memory metrics is not enabled then consolidatedMemUsage will be always 0
                if ((consolidatedCpuUsage > scaleOutThresholdCpu) || (consolidatedMemUsage > scaleOutThresholdMem))
                {
                    //If current capacity is equal to max FTD count required then do nothing
                    //If current capacity is more than max FTD count (This should never happen) do nothing
                    if (currentVmCapacity >= maxFTDCount)
                    {
                        log.LogWarning("AutoScaleManager:::: Current VMSS Capacity({0}) is greater than or equal to max FTD count ({1}) needed.. No action needed", currentVmCapacity, maxFTDCount);
                        return((ActionResult) new OkObjectResult("NOACTION"));
                    }
                    if ("POLICY-1" == scalingPolicy)
                    {
                        log.LogWarning("AutoScaleManager:::: Avg CPU Utilizatio of VM({0}) in last {1}min is {2}% ", vmName, sampleTimeMin, consolidatedCpuUsage);
                        if (memoryMetricsEnabled && (consolidatedMemUsage > scaleOutThresholdMem))
                        {
                            log.LogWarning("AutoScaleManager:::: Avg Memory Utilizatio of VM({0}) is {1}% ", ftdNameWithHighMemUtilization, consolidatedMemUsage);
                        }
                        log.LogWarning("AutoScaleManager:::: Time to SCALE OUT");
                    }
                    else if ("POLICY-2" == scalingPolicy)
                    {
                        log.LogWarning("AutoScaleManager:::: Avg CPU Utilizatio of Scale Set in last {0}min is {1}% ", sampleTimeMin, consolidatedCpuUsage);
                        if (memoryMetricsEnabled)
                        {
                            log.LogWarning("AutoScaleManager:::: Avg Memory Utilizatio of Scale Set is {0}% ", consolidatedMemUsage);
                        }
                        log.LogWarning("AutoScaleManager:::: Average resource utilization of scale set is more than Scale Out threshold.. Time to SCALE OUT");
                    }
                    scaleStr = "{ \"COMMAND\": \"SCALEOUT\", \"COUNT\": \"1\", \"TYPE\": \"REGULAR\" }";
                    return((ActionResult) new OkObjectResult(scaleStr));
                }
                //If any VM's CPU utilization is greater than scale-in threshold then Scale-In is not needed
                else if (ftdCpuUsage > scaleInThresholdCpu)
                {
                    scaleInRejectFlag = true;
                }
            }

            //if scaleInRejectFlag is not set, it means all the VM's CPU & Memory utilization is less than or equal to Scale-In threshold
            //Hence considering only least CPU consuming FTDv for Scale-In operation
            if (false == scaleInRejectFlag)
            {
                //If current capacity is less than or equal to minimum FTD count requied then scale-in should not be done
                if (currentVmCapacity <= minFTDCount)
                {
                    log.LogWarning("AutoScaleManager:::: Scale-In needed but Current VMSS Capacity({0}) is less than or equal to minimum FTD count ({1}) needed.. No Action done", currentVmCapacity, minFTDCount);
                    return((ActionResult) new OkObjectResult("NOACTION"));
                }
                var networkInterfaceName = System.Environment.GetEnvironmentVariable("MNGT_NET_INTERFACE_NAME", EnvironmentVariableTarget.Process);
                var ipConfigurationName  = System.Environment.GetEnvironmentVariable("MNGT_IP_CONFIG_NAME", EnvironmentVariableTarget.Process);
                var publicIpAddressName  = System.Environment.GetEnvironmentVariable("MNGT_PUBLIC_IP_NAME", EnvironmentVariableTarget.Process);

                var NmClient = new NetworkManagementClient(msiCred)
                {
                    SubscriptionId = azure.SubscriptionId
                };
                var publicIp = NmClient.PublicIPAddresses.GetVirtualMachineScaleSetPublicIPAddress(resoureGroupName, vmScalesetName, leastCpuLoadedFtdIndex, networkInterfaceName, ipConfigurationName, publicIpAddressName).IpAddress;

                log.LogWarning("AutoScaleManager:::: CPU Utilization of all the FTD's is less than or equal to CPU Scale-In threshold({0}%).. Time to SCALE-IN", scaleInThresholdCpu);
                if (memoryMetricsEnabled)
                {
                    log.LogWarning("AutoScaleManager:::: Memory Utilization of all the FTD's is less than or equal to Memory Scale-In threshold({0}%).. Time to SCALE-IN", scaleInThresholdMem);
                }
                log.LogWarning("AutoScaleManager:::: Least loaded FTD is : {0} with Utilization : {1}%", leastCpuLoadedFtd, minFtdCpuUsage);
                scaleStr = "{ \"COMMAND\": \"SCALEIN\", \"ftdDevName\": \"" + leastCpuLoadedFtd + "\", \"ftdPublicIp\": \"" + publicIp + "\", \"instanceid\" : \"" + leastCpuLoadedFtdIndex + "\"  }";

                return((ActionResult) new OkObjectResult(scaleStr));
            }
            //Scaling not needed
            log.LogWarning("AutoScaleManager:::: FTD scaleset utilization is within threshold.. no action needed");
            return((ActionResult) new OkObjectResult("NOACTION"));
        }
Beispiel #13
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            try
            {
                log.LogInformation("Getting request body params");
                string  requestBody       = await new StreamReader(req.Body).ReadToEndAsync();
                dynamic data              = JsonConvert.DeserializeObject(requestBody);
                string  subscriptionId    = data?.subscriptionId;
                string  resourceGroupName = data?.resourceGroupName;
                bool?   useVmStartAwait   = data?.wait;
                string  vmName            = data?.vmName;

                if (subscriptionId == null || resourceGroupName == null || vmName == null)
                {
                    return(new BadRequestObjectResult("Please pass all 3 required parameters in the request body"));
                }

                if (useVmStartAwait == null)
                {
                    useVmStartAwait = false;
                }

                log.LogInformation("Setting authentication to use MSI");
                AzureCredentialsFactory f = new AzureCredentialsFactory();
                var msi = new MSILoginInformation(MSIResourceType.AppService);

                var msiCred = f.FromMSI(msi, AzureEnvironment.AzureGlobalCloud);

                var azureAuth = Azure.Configure()
                                .WithLogLevel(HttpLoggingDelegatingHandler.Level.BodyAndHeaders)
                                .Authenticate(msiCred);

                log.LogInformation("Authenticating with Azure using MSI");
                var azure = azureAuth.WithSubscription(subscriptionId);

                log.LogInformation("Acquiring VM from Azure");
                var vm = azure.VirtualMachines.GetByResourceGroup(resourceGroupName, vmName);

                log.LogInformation("Checking VM Id");
                log.LogInformation(vm.Id.ToString());

                log.LogInformation("Checking VM Powerstate");
                log.LogInformation("VM Powerstate : " + vm.PowerState.ToString());

                bool vmStarting = false;
                if (vm.PowerState.ToString() == "PowerState/running")
                {
                    log.LogInformation("VM is already running");
                }
                else
                {
                    if (useVmStartAwait.Value)
                    {
                        log.LogInformation("Async Starting vm " + vmName);
                        await vm.StartAsync();
                    }
                    else
                    {
                        log.LogInformation("Sync Starting vm " + vmName);
                        vm.Start();
                    }

                    vmStarting = true;
                }

                return(vmStarting == false
                ? (ActionResult) new OkObjectResult("VM was already started")
                : (ActionResult) new OkObjectResult("VM started"));
            }
            catch (System.Exception ex)
            {
                log.LogError(ex.Message);
                throw;
            }
        }
        public static async Task Run([TimerTrigger("0 0 9 * * *")] TimerInfo myTimer, ILogger log)
        {
            log.LogInformation("Running Resource Tagger...");
            string ownerTagName = Environment.GetEnvironmentVariable("OwnerTag");

            if (String.IsNullOrEmpty(ownerTagName))
            {
                log.LogCritical("Please set the OwnerTag environment variables");
                return;
            }
            string subscriptionIds = Environment.GetEnvironmentVariable("SubscriptionIds");

            if (String.IsNullOrEmpty(subscriptionIds))
            {
                log.LogCritical("Please set the SubscriptionIds environment variables");
                return;
            }

            Azure.IAuthenticated azure;
            AzureCredentials     azureCreds;

            if (Environment.GetEnvironmentVariable("UseManagedIdendity") == "true")
            {
                log.LogInformation("Using Managed Identity");
                AzureCredentialsFactory factory = new AzureCredentialsFactory();
                MSILoginInformation     msi     = new MSILoginInformation(MSIResourceType.AppService);
                azureCreds = factory.FromMSI(msi, AzureEnvironment.AzureGlobalCloud);
            }
            else
            {
                log.LogInformation("Using Service Principal");
                string clientId     = Environment.GetEnvironmentVariable("ClientId");
                string clientSecret = Environment.GetEnvironmentVariable("ClientSecret");
                string tenantId     = Environment.GetEnvironmentVariable("TenantId");

                AzureCredentialsFactory factory = new AzureCredentialsFactory();
                azureCreds = factory.FromServicePrincipal(clientId, clientSecret, tenantId,
                                                          AzureEnvironment.AzureGlobalCloud);
            }
            azure = Azure.Configure().Authenticate(azureCreds);

            foreach (var subscriptionId in subscriptionIds.Split(",", StringSplitOptions.RemoveEmptyEntries))
            {
                log.LogInformation($"Looking for new resources without an owner tag in subscription {subscriptionId}");

                var azureSub       = azure.WithSubscription(subscriptionId);
                var insightsClient = new Microsoft.Azure.Insights.InsightsClient(azureCreds);
                insightsClient.SubscriptionId = subscriptionId;

                var resourceGroups = azureSub.ResourceGroups.List();
                foreach (var group in resourceGroups)
                {
                    log.LogTrace($"Looking at resource group {group.Name}");
                    try
                    {
                        var defaultKeyValuePair = default(KeyValuePair <String, String>);
                        var ownerTag            = defaultKeyValuePair;
                        if (group.Tags != null)
                        {
                            ownerTag = group.Tags.Where(tag => tag.Key.Equals(ownerTagName, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
                        }

                        if (ownerTag.Equals(defaultKeyValuePair))
                        {
                            String startTime  = DateTime.Now.ToUniversalTime().AddHours(-25).ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
                            String endTime    = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
                            String resourceId = group.Id;

                            string unknownOwner            = "unknown";
                            string newOwner                = unknownOwner;
                            var    resourceGroupCreateLogs = await GetCreationLogs(startTime, endTime, resourceId, OPERATION_RESOURCEGROUP_WRITE, insightsClient);

                            if (resourceGroupCreateLogs.Length == 0)
                            {
                                log.LogInformation($"Resource group {group.Name}: did not find create operation - trying again");
                                startTime = DateTime.Now.ToUniversalTime().AddDays(-90).ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
                                resourceGroupCreateLogs = await GetCreationLogs(startTime, endTime, resourceId, OPERATION_RESOURCEGROUP_WRITE, insightsClient);
                            }
                            if (resourceGroupCreateLogs.Length != 0)
                            {
                                newOwner = resourceGroupCreateLogs[0].Caller;
                            }

                            if (!unknownOwner.Equals(newOwner))
                            {
                                await group.Update().WithTag(ownerTagName, newOwner).ApplyAsync();

                                log.LogInformation($"Resource group {group.Name} tagged with owner {newOwner}");
                            }
                            else
                            {
                                log.LogInformation($"Resource group {group.Name}: did not find create operation, please tag manually");
                            }
                        }
                        else
                        {
                            log.LogTrace($"Resource group {group.Name} is already owned by {ownerTag.Value}");
                        }
                    }
                    catch (Exception ex)
                    {
                        log.LogError("Exception: " + ex);
                    }
                }
            }
        }
Beispiel #15
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogWarning("AutoScaleManager:::: Task to check Scaling requirement.. Started (ASM Version : V2.0)");
            var resoureGroupName     = System.Environment.GetEnvironmentVariable("RESOURCE_GROUP_NAME", EnvironmentVariableTarget.Process);
            var vmScalesetName       = System.Environment.GetEnvironmentVariable("VMSS_NAME", EnvironmentVariableTarget.Process);
            var minFTDCountStr       = System.Environment.GetEnvironmentVariable("MIN_FTD_COUNT", EnvironmentVariableTarget.Process);
            var maxFTDCountStr       = System.Environment.GetEnvironmentVariable("MAX_FTD_COUNT", EnvironmentVariableTarget.Process);
            var sampleTimeMin        = System.Environment.GetEnvironmentVariable("SAMPLING_TIME_MIN", EnvironmentVariableTarget.Process);
            var scaleOutThresholdStr = System.Environment.GetEnvironmentVariable("SCALE_OUT_THRESHLD", EnvironmentVariableTarget.Process);
            var scaleInThresholdStr  = System.Environment.GetEnvironmentVariable("SCALE_IN_THRESHLD", EnvironmentVariableTarget.Process);
            var initialDeployMethod  = System.Environment.GetEnvironmentVariable("INITIAL_DEPLOYMENT_MODE", EnvironmentVariableTarget.Process); //supported STEP / BULK
            var scalingPolicy        = System.Environment.GetEnvironmentVariable("SCALING_POLICY", EnvironmentVariableTarget.Process);          // POLICY-1 / POLICY-2
            var subscriptionId       = System.Environment.GetEnvironmentVariable("SUBSCRIPTION_ID", EnvironmentVariableTarget.Process);

            int    minFTDCount       = Convert.ToInt32(minFTDCountStr);
            int    maxFTDCount       = Convert.ToInt32(maxFTDCountStr);
            double scaleOutThreshold = Convert.ToDouble(scaleOutThresholdStr);
            double scaleInThreshold  = Convert.ToDouble(scaleInThresholdStr);
            int    currentVmCapacity = 0;
            string scaleStr          = "";

            //Reject if scaleOutThreshold < scaleInThreshold
            if (scaleOutThreshold <= scaleInThreshold)
            {
                log.LogError("AutoScaleManager:::: ScaleOut Threshold ({0}) is less than or equal to ScaleIn Threshold ({1}) this is not correct", scaleOutThreshold, scaleInThreshold);
                return((ActionResult) new BadRequestObjectResult("ERROR: ScaleOut threshold is less than or equal to ScaleIn threshold"));
            }

            //Check FMC connection, If we can not connect to FMC do not continue
            log.LogInformation("AutoScaleManager:::: Checking FMC connection");

            var    getAuth   = new fmcAuthClass();
            string authToken = getAuth.getFmcAuthToken(log);

            if ("ERROR" == authToken)
            {
                log.LogError("AutoScaleManager:::: Failed to connect to FMC..Can not continue");
                return((ActionResult) new BadRequestObjectResult("ERROR: Failed to connet to FMC..Can not continue"));
            }

            log.LogInformation("AutoScaleManager:::: Sampling Resource Utilization at {0}min Average", sampleTimeMin);

            var factory = new AzureCredentialsFactory();
            var msiCred = factory.FromMSI(new MSILoginInformation(MSIResourceType.AppService), AzureEnvironment.AzureGlobalCloud);
            var azure   = Azure.Configure().WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic).Authenticate(msiCred).WithSubscription(subscriptionId);

            string resourceUri = null;
            var    vmss        = azure.VirtualMachineScaleSets.GetByResourceGroup(resoureGroupName, vmScalesetName);

            resourceUri = vmss.Id;

            if (null == resourceUri)
            {
                log.LogError("AutoScaleManager:::: Unable to get resource uri");
                return((ActionResult) new BadRequestObjectResult("ERROR: Unable to get resource uri"));
            }

            currentVmCapacity = vmss.Capacity;
            log.LogWarning("AutoScaleManager:::: Current capacity of VMSS : {0}", currentVmCapacity);

            //If the VMSS capacity is '0' consider this as first deployment and spawn 'minimum FTD count' at a time
            if ((0 == currentVmCapacity) && (0 != minFTDCount))
            {
                log.LogWarning("AutoScaleManager:::: Current VMSS capacity is 0, considering it as first deployment (min FTD count needed : {0}", minFTDCount);
                if ("BULK" == initialDeployMethod)
                {
                    log.LogWarning("AutoScaleManager:::: Selected initial deployment mode is BULK");
                    log.LogWarning("AutoScaleManager:::: Deploying {0} number of FTDvs in scale set", minFTDCount);
                    scaleStr = "{ \"COMMAND\": \"SCALEOUT\", \"COUNT\": \"" + minFTDCount + "\", \"TYPE\": \"INIT\" }";
                    return((ActionResult) new OkObjectResult(scaleStr));
                }
                else
                {
                    log.LogWarning("AutoScaleManager:::: BULK method is not selected for initial deployment.. proceeding with STEP");
                    scaleStr = "{ \"COMMAND\": \"SCALEOUT\", \"COUNT\": \"1\", \"TYPE\": \"REGULAR\"}";
                    return((ActionResult) new OkObjectResult(scaleStr));
                }
            }

            //If current capacity is less than minimum FTD count requied then we need to scale-out
            if (currentVmCapacity < minFTDCount)
            {
                log.LogWarning("AutoScaleManager:::: Current VMSS Capacity({0}) is less than minimum FTD count ({1}) needed.. time to SCALE-OUT", currentVmCapacity, minFTDCount);
                scaleStr = "{ \"COMMAND\": \"SCALEOUT\", \"COUNT\": \"1\", \"TYPE\": \"REGULAR\"}";
                return((ActionResult) new OkObjectResult(scaleStr));
            }


            //-------------------------------------------------Scaling decission based on Metrics------------------------------------------------------
            var sampleIntervalMin = System.TimeSpan.FromMinutes(Convert.ToDouble(sampleTimeMin));
            MonitorManagementClient metricClient = new MonitorManagementClient(msiCred);
            double ftdUsage            = 0;
            double groupUsage          = 0;
            double consolidatedUsage   = 0;
            bool   scaleInRejectFlag   = false;
            double minFtdUsage         = 9999;
            string leastLoadedFtd      = "";
            string leastLoadedFtdIndex = "";

            log.LogWarning("AutoScaleManager:::: Scaling Policy : {0}", scalingPolicy);
            if ("POLICY-2" == scalingPolicy)
            {
                log.LogInformation("AutoScaleManager:::: Scaling Policy-2 Selected..Getting average CPU utilization of scale set");
                var response = await metricClient.Metrics.ListAsync(resourceUri, null, null, sampleIntervalMin, "Percentage CPU", "Average");

                foreach (var metric in response.Value)
                {
                    foreach (var series in metric.Timeseries)
                    {
                        foreach (var point in series.Data)
                        {
                            if (point.Average.HasValue)
                            {
                                groupUsage = point.Average.Value;
                                log.LogDebug("AutoScaleManager:::: avg cpu: {0}", ftdUsage);
                            }
                        }
                    }
                }
                log.LogInformation("AutoScaleManager:::: Group average usage : {0}", groupUsage);
            }

            foreach (var vm in vmss.VirtualMachines.List())
            {
                var vmName = vm.Name;
                ftdUsage = 0;
                //Metrics filter
                ODataQuery <MetadataValue> odataFilterMetrics = new ODataQuery <MetadataValue>(string.Format("VMName eq '{0}'", vmName));

                log.LogInformation("AutoScaleManager:::: Getting Metrics for : {0}", vmName);
                var response = await metricClient.Metrics.ListAsync(resourceUri, odataFilterMetrics, null, sampleIntervalMin, "Percentage CPU", "Average");

                foreach (var metric in response.Value)
                {
                    foreach (var series in metric.Timeseries)
                    {
                        foreach (var point in series.Data)
                        {
                            if (point.Average.HasValue)
                            {
                                ftdUsage = point.Average.Value;
                                log.LogDebug("AutoScaleManager:::: avg cpu: {0}", ftdUsage);
                            }
                        }
                    }
                }

                log.LogInformation("AutoScaleManager:::: Avg CPU Utilizatio of VM({0}) in last {1}min : {2}%", vmName, sampleTimeMin, ftdUsage);

                //Maintain the FTD with minimum utilization to scale-in if needed
                if (ftdUsage < minFtdUsage)
                {
                    minFtdUsage         = ftdUsage;
                    leastLoadedFtd      = vmName;
                    leastLoadedFtdIndex = vm.InstanceId;
                }

                if ("POLICY-1" == scalingPolicy)
                {
                    //Average usage of individual Instance
                    consolidatedUsage = ftdUsage;
                }
                else if ("POLICY-2" == scalingPolicy)
                {
                    //Scale Set average utilization
                    consolidatedUsage = groupUsage;
                }
                else
                {
                    log.LogError("Invalid Scaling Policy {0}", scalingPolicy);
                    return((ActionResult) new BadRequestObjectResult("ERROR: Invalid Scaling Policy"));
                }

                //If CPU utilization is greater than scale-out threshold then Scale-Out
                if (consolidatedUsage > scaleOutThreshold)
                {
                    //If current capacity is equal to max FTD count required then do nothing
                    //If current capacity is more than max FTD count (This should never happen) do nothing
                    if (currentVmCapacity >= maxFTDCount)
                    {
                        log.LogWarning("AutoScaleManager:::: Current VMSS Capacity({0}) is greater than or equal to max FTD count ({1}) needed.. No action needed", currentVmCapacity, maxFTDCount);
                        return((ActionResult) new OkObjectResult("NOACTION"));
                    }
                    if ("POLICY-1" == scalingPolicy)
                    {
                        log.LogWarning("AutoScaleManager:::: Avg CPU Utilizatio of VM({0}) in last {1}min is {2}% which is greater than ScaleOut threshold({3}%) .. Time to SCALE-OUT", vmName, sampleTimeMin, consolidatedUsage, scaleOutThreshold);
                    }
                    else if ("POLICY-2" == scalingPolicy)
                    {
                        log.LogWarning("AutoScaleManager:::: Avg CPU Utilizatio of Scale Set in last {0}min is {1}% which is greater than ScaleOut threshold({2}%) .. Time to SCALE-OUT", sampleTimeMin, consolidatedUsage, scaleOutThreshold);
                    }
                    scaleStr = "{ \"COMMAND\": \"SCALEOUT\", \"COUNT\": \"1\", \"TYPE\": \"REGULAR\" }";
                    return((ActionResult) new OkObjectResult(scaleStr));
                }
                //If any VM's CPU utilization is greater than scale-in threshold then Scale-In is not needed
                else if (ftdUsage > scaleInThreshold)
                {
                    scaleInRejectFlag = true;
                }
            }

            //if scaleInRejectFlag is not set, it means all the VM's CPU utilization is less than or equal to Scale-In threshold
            if (false == scaleInRejectFlag)
            {
                //If current capacity is less than or equal to minimum FTD count requied then scale-in should not be done
                if (currentVmCapacity <= minFTDCount)
                {
                    log.LogWarning("AutoScaleManager:::: Scale-In needed but Current VMSS Capacity({0}) is less than or equal to minimum FTD count ({1}) needed.. No Action done", currentVmCapacity, minFTDCount);
                    return((ActionResult) new OkObjectResult("NOACTION"));
                }
                var networkInterfaceName = System.Environment.GetEnvironmentVariable("MNGT_NET_INTERFACE_NAME", EnvironmentVariableTarget.Process);
                var ipConfigurationName  = System.Environment.GetEnvironmentVariable("MNGT_IP_CONFIG_NAME", EnvironmentVariableTarget.Process);
                var publicIpAddressName  = System.Environment.GetEnvironmentVariable("MNGT_PUBLIC_IP_NAME", EnvironmentVariableTarget.Process);

                var NmClient = new NetworkManagementClient(msiCred)
                {
                    SubscriptionId = azure.SubscriptionId
                };
                var publicIp = NmClient.PublicIPAddresses.GetVirtualMachineScaleSetPublicIPAddress(resoureGroupName, vmScalesetName, leastLoadedFtdIndex, networkInterfaceName, ipConfigurationName, publicIpAddressName).IpAddress;

                log.LogWarning("AutoScaleManager:::: CPU Utilization of all the FTD's is less than or equal to Scale-In threshold({0}%).. Time to SCALE-IN", scaleInThreshold);
                log.LogWarning("AutoScaleManager:::: Least loaded FTD is : {0} with Utilization : {1}%", leastLoadedFtd, minFtdUsage);
                scaleStr = "{ \"COMMAND\": \"SCALEIN\", \"ftdDevName\": \"" + leastLoadedFtd + "\", \"ftdPublicIp\": \"" + publicIp + "\", \"instanceid\" : \"" + leastLoadedFtdIndex + "\"  }";

                return((ActionResult) new OkObjectResult(scaleStr));
            }
            //Scaling not needed
            log.LogWarning("AutoScaleManager:::: FTD scaleset utilization is within threshold.. no action needed");
            return((ActionResult) new OkObjectResult("NOACTION"));
        }