public async Task AddVMEntityAsync(VMDetails newVM)
        {
            ValidateVMDetails(newVM);

            CloudTable     table           = tableClient.GetTableReference(tableName);
            TableOperation insertOperation = TableOperation.Insert(newVM);
            await table.ExecuteAsync(insertOperation);
        }
        public async Task ModifyVMDetailsAsync(VMDetails updatedVM)
        {
            ValidateVMDetails(updatedVM);
            updatedVM.ETag = "*"; //required for the Merge operation

            CloudTable table = tableClient.GetTableReference(tableName);

            TableOperation updateOperation = TableOperation.Merge(updatedVM);
            var            x = await table.ExecuteAsync(updateOperation);
        }
        public void ValidateVMDetails(VMDetails entity)
        {
            if (string.IsNullOrEmpty(entity.VMID))
            {
                throw new ArgumentException($"{nameof(entity.VMID)} should not be null");
            }

            if (string.IsNullOrEmpty(entity.ResourceGroup))
            {
                throw new ArgumentException($"{nameof(entity.ResourceGroup)} should not be null");
            }
        }
        public async Task ModifyVMStateByIdAsync(string VMID, VMState state)
        {
            if (string.IsNullOrEmpty(VMID))
            {
                throw new Exception($"{nameof(VMID)} should have a value");
            }

            CloudTable table = tableClient.GetTableReference(tableName);

            VMDetails vm = await GetVMByID(VMID);

            vm.State = state;
            TableOperation updateOperation = TableOperation.Merge(vm);
            await table.ExecuteAsync(updateOperation);
        }
        public static async Task StartDeallocatedVMAsync(VMDetails vm)
        {
            // not awaiting here intentionally, since we want to return response immediately
            var task = AzureMgmtCredentials.Instance.Azure
                       .VirtualMachines.StartAsync(vm.ResourceGroup, vm.VMID);

            // we do not wait for VM start to complete
            // so let's give it few seconds to start and return in case we have deployment exception
            // like service principal error
            await Task.WhenAny(task, Task.Delay(1000));

            if (task.IsCompleted && task.IsFaulted)
            {
                throw task.Exception;
            }
        }
Example #6
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"));
            }
        }