public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "subscriptions/{SUBSCRIPTIONID}/resourceGroups/{RESOURCEGROUPNAME}/providers/Microsoft.DevTestLab/labs/{LABNAME}/virtualmachines/{VIRTUALMACHINENAME}")] HttpRequest req, string subscriptionId, string resourceGroupName, string labName, string virtualMachineName, ILogger log) { log.LogInformation($"Function to apply the Windows Update artifact on VM {virtualMachineName} in lab {labName} in subscription {subscriptionId} started processing at {DateTime.Now}"); // Authentication helper, keeps track of the access token and encapsulates authentication into Azure & DTL Client var authenticationHelper = new Authentication(log); await authenticationHelper.RetrieveAccessTokenAsync(); // login to the DevTest Labs APIs var dtlClient = authenticationHelper.LoginToDevTestLabsAPIs(subscriptionId); var azureClient = authenticationHelper.LoginToAzure(subscriptionId); var devTestLabsHelper = new DevTestLabs(azureClient, dtlClient, log); // Get the lab's resource id (which also confirms the lab exists) string labResourceId = await devTestLabsHelper.GetDevTestLabResourceId(resourceGroupName, labName); // Get the virtual machine LabVirtualMachine vm = await devTestLabsHelper.GetDevTestLabVirtualMachine(resourceGroupName, labName, virtualMachineName); // Let's make sure the VM is OK to apply artifacts if (await devTestLabsHelper.IsVirtualMachineReadyForArtifacts(vm)) { var artifactRequest = new ApplyArtifactsRequest(new List <ArtifactInstallProperties> { new ArtifactInstallProperties($"{labResourceId}/artifactSources/public repo/artifacts/windows-install-windows-updates") }); // We fire off the request to apply artifacts, but we don't wait until it's complete before wrapping up the function // If we wanted to wait, we would use "dtlClient.VirtualMachines.ApplyArtifactsAsync()" instead dtlClient.VirtualMachines.BeginApplyArtifacts(resourceGroupName, labName, virtualMachineName, artifactRequest); } else { log.LogError($"The VM must be running to apply artifacts! ResourceGroupName '{resourceGroupName}', LabName '{labName}', VM '{virtualMachineName}'"); return(new ContentResult() { Content = Content.GetHtmlResponse(Content.responseType.VirtualMachineNotRunning, false), ContentType = "text/html", StatusCode = 200 }); } return(new ContentResult() { Content = Content.GetHtmlResponse(Content.responseType.VirtualMachineSuccess, true), ContentType = "text/html", StatusCode = 200 }); }
public async Task <bool> IsVirtualMachineReadyForArtifacts(LabVirtualMachine vm) { // 1st, we have to first check the lab machine provisioning state (this ensures that the VM isn't creating, deleting, applying artifacts, etc) if (vm.ProvisioningState == "Succeeded") { // 2nd, we need to ensure that the underlying compute has provisioning state == succeeded and power state == running string powerState, provisioningState; if (vm.ComputeVm != null) { // If we already have the Compute VM, let's use it directly rather than query Azure again powerState = (from s in vm.ComputeVm.Statuses where s.Code.Contains("PowerState/") select s).FirstOrDefault()?.Code.Replace("PowerState/", "").ToLower(); provisioningState = (from s in vm.ComputeVm.Statuses where s.Code.Contains("ProvisioningState/") select s).FirstOrDefault()?.Code.Replace("ProvisioningState/", "").ToLower(); } else { // We don't have the compute VM, so we need the underlying resource status to continue var computeVm = await azureClient.VirtualMachines.GetByIdAsync(vm.ComputeId); powerState = computeVm.PowerState?.Value.Replace("PowerState/", "").ToLower(); provisioningState = computeVm.ProvisioningState.Replace("ProvisioningState/", "").ToLower(); } if (powerState == "running" && provisioningState == "succeeded") { return(true); } else { log.LogInformation($" .. Virtual machine '{vm.Name}' has PowerState '{powerState}' and ProvisioningState '{provisioningState}', cannot apply artifacts "); return(false); } } else { log.LogInformation($" .. Virtual machine '{vm.Name}' has DTL ProvisioningState '{vm.ProvisioningState}', cannot apply artifacts "); return(false); } }
/// <summary> /// Create virtual machines in a Lab. This operation can take a while to /// complete. /// </summary> /// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='resourceGroupName'> /// The name of the resource group. /// </param> /// <param name='name'> /// The name of the lab. /// </param> /// <param name='labVirtualMachine'> /// </param> /// <param name='cancellationToken'> /// The cancellation token. /// </param> public static async Task BeginCreateEnvironmentAsync(this ILabOperations operations, string resourceGroupName, string name, LabVirtualMachine labVirtualMachine, CancellationToken cancellationToken = default(CancellationToken)) { await operations.BeginCreateEnvironmentWithHttpMessagesAsync(resourceGroupName, name, labVirtualMachine, null, cancellationToken).ConfigureAwait(false); }
/// <summary> /// Create virtual machines in a Lab. This operation can take a while to /// complete. /// </summary> /// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='resourceGroupName'> /// The name of the resource group. /// </param> /// <param name='name'> /// The name of the lab. /// </param> /// <param name='labVirtualMachine'> /// </param> public static void BeginCreateEnvironment(this ILabOperations operations, string resourceGroupName, string name, LabVirtualMachine labVirtualMachine) { Task.Factory.StartNew(s => ((ILabOperations)s).BeginCreateEnvironmentAsync(resourceGroupName, name, labVirtualMachine), operations, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap().GetAwaiter().GetResult(); }
/// <summary> /// Modify properties of virtual machines. /// </summary> /// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='resourceGroupName'> /// The name of the resource group. /// </param> /// <param name='labName'> /// The name of the lab. /// </param> /// <param name='name'> /// The name of the virtual Machine. /// </param> /// <param name='labVirtualMachine'> /// </param> /// <param name='cancellationToken'> /// The cancellation token. /// </param> public static async Task <LabVirtualMachine> PatchResourceAsync(this IVirtualMachineOperations operations, string resourceGroupName, string labName, string name, LabVirtualMachine labVirtualMachine, CancellationToken cancellationToken = default(CancellationToken)) { using (var _result = await operations.PatchResourceWithHttpMessagesAsync(resourceGroupName, labName, name, labVirtualMachine, null, cancellationToken).ConfigureAwait(false)) { return(_result.Body); } }
/// <summary> /// Modify properties of virtual machines. /// </summary> /// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='resourceGroupName'> /// The name of the resource group. /// </param> /// <param name='labName'> /// The name of the lab. /// </param> /// <param name='name'> /// The name of the virtual Machine. /// </param> /// <param name='labVirtualMachine'> /// </param> public static LabVirtualMachine PatchResource(this IVirtualMachineOperations operations, string resourceGroupName, string labName, string name, LabVirtualMachine labVirtualMachine) { return(Task.Factory.StartNew(s => ((IVirtualMachineOperations)s).PatchResourceAsync(resourceGroupName, labName, name, labVirtualMachine), operations, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap().GetAwaiter().GetResult()); }