Example #1
0
        public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestMessage req, TraceWriter log)
        {
            var payload = await req.Content.ReadAsStringAsync();

            var nodes = JsonConvert.DeserializeObject <Request>(payload);

            if (nodes.nodes == null || nodes.nodes.Length == 0)
            {
                return(req.CreateErrorResponse(HttpStatusCode.BadRequest, "Nodes payload not found."));
            }

            List <string> deallocatedVMs = new List <string>();

            foreach (var node in nodes.nodes)
            {
                log.Info($"Reported {node.nodeId} has {node.rooms} rooms");
                //get the state of the corresponding VM
                var vm = await TableStorageHelper.Instance.GetVMByID(node.nodeId.Trim());

                if (node.rooms == 0)
                {
                    if (vm == null)
                    {
                        log.Error($"VM {vm.VMID} not found in DB");
                        continue;
                    }
                    if (vm.State == VMState.MarkedForDeallocation)
                    {
                        deallocatedVMs.Add(vm.VMID);

                        //VM has zero rooms and marked for deallocation
                        //it's fate is sealed, bye bye! :)
                        await AzureAPIHelper.DeallocateVMAsync(vm.VMID, vm.ResourceGroup);

                        //mark it with the deallocating state in table storage
                        //VMMonitor Function will be called when it is finally deallocated
                        vm.State = VMState.Deallocating;
                    }
                }
                vm.RoomsNumber = node.rooms;
                await TableStorageHelper.Instance.ModifyVMDetailsAsync(vm);
            }

            var resp = req.CreateResponse(HttpStatusCode.OK);

            resp.Content = new StringContent(JsonConvert.SerializeObject(new { VMsInDeallocatingState = deallocatedVMs }));
            return(resp);
        }
Example #2
0
        public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "node/deallocate")] HttpRequestMessage req, TraceWriter log)
        {
            log.Info("MarkVMForDeallocation Function was called");
            // Get POST body
            dynamic data = JsonConvert.DeserializeObject(await req.Content.ReadAsStringAsync());

            // Set name to query string or body data
            string vmName = data?.vmName;

            //trim it just in case
            vmName = vmName.Trim();

            var vm = await TableStorageHelper.Instance.GetVMByID(vmName);

            if (vm == null)
            {
                return(req.CreateErrorResponse(HttpStatusCode.BadRequest, $"VM {vmName} not found"));
            }

            //set the state of the requested VM as MarkedForDeallocation
            vm.State = VMState.MarkedForDeallocation;

            //however, if there are no games running on this VM, deallocate it immediately
            if (vm.RoomsNumber == 0)
            {
                log.Info($"VM with ID {vmName} has zero game rooms so it will be deallocated immediately");
                await AzureAPIHelper.DeallocateVMAsync(vm.VMID, vm.ResourceGroup);

                vm.State = VMState.Deallocating;
            }

            //modify the VM state in the DB with the new value
            await TableStorageHelper.Instance.ModifyVMDetailsAsync(vm);

            return(vmName == null
                ? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a vmName in the request body")
                : req.CreateResponse(HttpStatusCode.OK, JsonConvert.SerializeObject(vm)));
        }
        public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = "VMMonitor")] HttpRequestMessage req, TraceWriter log)
        {
            dynamic dataobject = await req.Content.ReadAsAsync <object>();

            //log.Info(dataobject.ToString());

            log.Info("----------------------------------------------");

            //get Azure Monitor detailed activity log
            var activityLog = dataobject.data.context.activityLog;

            log.Info(activityLog.ToString());

            //confirm that this is indeed a VM operation
            if (activityLog.operationName.ToString().StartsWith(VM_OPERATION))
            {
                string resourceGroup = activityLog.resourceGroupName;  //get the resource group
                //get the VM ID
                string resourceId = activityLog.resourceId.ToString(); // returns /subscriptions/6bd0e514-c783-4dac-92d2-6788744eee7a/resourceGroups/lala3/providers/Microsoft.Compute/virtualMachines/lala3
                string VMID       = resourceId.Substring(resourceId.LastIndexOf('/') + 1);

                var vm = await TableStorageHelper.Instance.GetVMByID(VMID);

                if (vm == null)
                {
                    log.Info($"VM {VMID} was not found in our DB, skipping");
                    return(req.CreateResponse(HttpStatusCode.OK));
                }

                if (activityLog.status == OPERATION_FAILED)
                {
                    vm.State = VMState.Failed;
                    log.Error($"VM {VMID} is failed: {activityLog.subStatus}");
                    await TableStorageHelper.Instance.ModifyVMDetailsAsync(vm);

                    return(req.CreateResponse(HttpStatusCode.InternalServerError));
                }

                if (activityLog.status != OPERATION_SUCCEEDED)
                {
                    log.Error($"VM {VMID} is in a state we aren't interested in: <{activityLog.status}>");
                    return(req.CreateResponse(HttpStatusCode.OK));
                }

                string operationName = (string)activityLog.operationName;
                string ip;
                switch (operationName)
                {
                case CREATE_VM_OPERATION:
                    log.Info($"VM with name {VMID} created");
                    //when the VM is finally created we need to i)set its state as Running and ii)get its Public IP
                    ip = await AzureAPIHelper.GetVMPublicIP(VMID, resourceGroup);

                    vm.State = VMState.Running;
                    break;

                case RESTART_VM_OPERATION:
                    log.Info($"VM with name {VMID} rebooted");
                    vm.State = VMState.Running;
                    break;

                case DEALLOCATE_VM_OPERATION:
                    log.Info($"VM with name {VMID} deallocated");
                    //when the VM is deallocated its public IP is removed, too
                    vm.State = VMState.Deallocated;
                    break;

                case START_VM_OPERATION:
                    log.Info($"VM with name {VMID} started - was deallocated before");
                    //when the VM is started from deallocation it gets a new public IP, so add it to the DB
                    vm.IP = await AzureAPIHelper.GetVMPublicIP(VMID, resourceGroup);

                    vm.State = VMState.Running;
                    break;
                }
                await TableStorageHelper.Instance.ModifyVMDetailsAsync(vm);

                log.Info("----------------------------------------------");
                return(req.CreateResponse(HttpStatusCode.OK, $"WebHook call for VM:'{VMID}' with operation:'{activityLog.operationName}' and status:'{activityLog.status}' was successful"));
            }
            else
            {
                string msg = "No VM operation, something went wrong";
                log.Error(msg);
                return(req.CreateErrorResponse(HttpStatusCode.BadRequest, msg));
            }
        }
Example #4
0
        public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = "node/create")] HttpRequestMessage req, TraceWriter log, ExecutionContext context)
        {
            var content = await req.Content.ReadAsStringAsync();

            var nodeParams = JsonConvert.DeserializeObject <NodeParameters>(content);

            var err = ValidateRequest(req, nodeParams, log);

            if (err != null)
            {
                return(err);
            }

            //find out if there is any VM in MarkedForDeallocation state
            var vm = (await TableStorageHelper.Instance.GetMatchingVMsInStateAsync(
                          nodeParams.ResourceGroup, nodeParams.Region,
                          nodeParams.Size, VMState.MarkedForDeallocation))
                     .FirstOrDefault();

            if (vm != null)
            {
                //set it as running so as not to be deallocated when game rooms are 0
                vm.State = VMState.Running;
                await TableStorageHelper.Instance.ModifyVMDetailsAsync(vm);

                //we're done, this VM can now be used
                return(req.CreateResponse(HttpStatusCode.OK,
                                          JsonConvert.SerializeObject(vm),
                                          "application/json"));
            }

            //search if there are any deallocated VMs
            var deallocatedVM = (await TableStorageHelper.Instance
                                 .GetMatchingVMsInStateAsync(nodeParams.ResourceGroup, nodeParams.Region, nodeParams.Size, VMState.Deallocated))
                                .FirstOrDefault();

            //no deallocated VMs, so let's create a new one
            if (deallocatedVM == null)
            {
                string vmName = "node" + System.Guid.NewGuid().ToString("N").Substring(0, 7);
                string sshKey = ConfigurationManager.AppSettings["VM_ADMIN_KEY"]?.ToString()
                                ?? System.IO.File.ReadAllText(context.FunctionAppDirectory + "/default_key_rsa.pub");
                string deploymentTemplate = System.IO.File.ReadAllText(context.FunctionAppDirectory + "/vmDeploy.json");

                await DeployNodeAsync(vmName, nodeParams, sshKey, deploymentTemplate, log);

                var details = new VMDetails(vmName, nodeParams.ResourceGroup, VMState.Creating,
                                            nodeParams.Size, nodeParams.Region);
                await TableStorageHelper.Instance.AddVMEntityAsync(details);

                return(req.CreateResponse(HttpStatusCode.OK,
                                          JsonConvert.SerializeObject(details),
                                          "application/json"));
            }
            else//there's at least one deallocated VM, so start the .First() one
            {
                await AzureAPIHelper.StartDeallocatedVMAsync(deallocatedVM);

                deallocatedVM.State = VMState.Creating;
                await TableStorageHelper.Instance.ModifyVMDetailsAsync(deallocatedVM);

                return(req.CreateResponse(HttpStatusCode.OK,
                                          JsonConvert.SerializeObject(deallocatedVM),
                                          "application/json"));
            }
        }