Skip to content

Commit 68a90d2

Browse files
authored
Merge pull request Azure#2849 from krkhan/dev
Add support for querying encryption status from the AzureDiskEncryptionForLinux extension
2 parents d300324 + a9b53c4 commit 68a90d2

File tree

7 files changed

+222
-17
lines changed

7 files changed

+222
-17
lines changed

src/ResourceManager/Compute/Commands.Compute/Extension/AzureDiskEncryption/AzureDiskEncryptionExtensionConstants.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public static class AzureDiskEncryptionExtensionConstants
2323
public const string aadClientSecretParameterSet = "AAD Client Secret Parameters";
2424
public const string enableEncryptionOperation = "EnableEncryption";
2525
public const string disableEncryptionOperation = "DisableEncryption";
26+
public const string queryEncryptionStatusOperation = "QueryEncryptionStatus";
27+
public const string encryptionResultOsKey = "os";
28+
public const string encryptionResultDataKey = "data";
2629
public const string aadClientIDKey = "AADClientID";
2730
public const string aadClientSecretKey = "AADClientSecret";
2831
public const string aadClientCertThumbprintKey = "AADClientCertThumbprint";

src/ResourceManager/Compute/Commands.Compute/Extension/AzureDiskEncryption/AzureDiskEncryptionExtensionContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public AzureDiskEncryptionExtensionContext(PSVirtualMachineExtension psExt)
9494
ProtectedSettings = psExt.ProtectedSettings;
9595
ProvisioningState = psExt.ProvisioningState;
9696
Statuses = psExt.Statuses;
97+
SubStatuses = psExt.SubStatuses;
9798

9899
InitializeAzureDiskEncryptionMembers(psExt);
99100
}

src/ResourceManager/Compute/Commands.Compute/Extension/AzureDiskEncryption/DisableAzureDiskEncryption.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,20 @@ public override void ExecuteCmdlet()
231231

232232
currentOSType = virtualMachineResponse.StorageProfile.OsDisk.OsType;
233233

234+
if (OperatingSystemTypes.Linux.Equals(currentOSType) &&
235+
!AzureDiskEncryptionExtensionContext.VolumeTypeData.Equals(VolumeType, StringComparison.InvariantCultureIgnoreCase))
236+
{
237+
ThrowTerminatingError(
238+
new ErrorRecord(
239+
new ArgumentException(
240+
string.Format(
241+
CultureInfo.CurrentUICulture,
242+
"Disabling encryption is only allowed on Data volumes for Linux VMs.")),
243+
"InvalidType",
244+
ErrorCategory.NotImplemented,
245+
null));
246+
}
247+
234248
if (this.ShouldProcess(VMName, Properties.Resources.DisableDiskEncryptionAction)
235249
&& (this.Force.IsPresent ||
236250
this.ShouldContinue(Properties.Resources.DisableAzureDiskEncryptionConfirmation, Properties.Resources.DisableAzureDiskEncryptionCaption)))

src/ResourceManager/Compute/Commands.Compute/Extension/AzureDiskEncryption/GetAzureDiskEncryptionStatus.cs

Lines changed: 196 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616
using Microsoft.Azure.Commands.Compute.Models;
1717
using Microsoft.Azure.Management.Compute;
1818
using Microsoft.Azure.Management.Compute.Models;
19+
using Microsoft.Rest.Azure;
20+
using Newtonsoft.Json;
1921
using System;
22+
using System.Collections;
23+
using System.Collections.Generic;
2024
using System.Globalization;
2125
using System.Management.Automation;
2226

@@ -45,6 +49,140 @@ public class GetAzureDiskEncryptionStatusCommand : VirtualMachineExtensionBaseCm
4549
[ValidateNotNullOrEmpty]
4650
public string VMName { get; set; }
4751

52+
[Alias("ExtensionName")]
53+
[Parameter(
54+
Mandatory = false,
55+
Position = 2,
56+
ValueFromPipelineByPropertyName = true,
57+
HelpMessage = "The extension name. If this parameter is not specified, default values used are AzureDiskEncryption for Windows VMs and AzureDiskEncryptionForLinux for Linux VMs")]
58+
[ValidateNotNullOrEmpty]
59+
public string Name { get; set; }
60+
61+
private VirtualMachineExtension GetVmExtensionParameters(VirtualMachine vmParameters, OSType currentOSType)
62+
{
63+
Hashtable publicSettings = new Hashtable();
64+
Hashtable protectedSettings = new Hashtable();
65+
66+
publicSettings.Add(AzureDiskEncryptionExtensionConstants.encryptionOperationKey, AzureDiskEncryptionExtensionConstants.queryEncryptionStatusOperation);
67+
publicSettings.Add(AzureDiskEncryptionExtensionConstants.sequenceVersionKey, Guid.NewGuid().ToString());
68+
69+
if (vmParameters == null)
70+
{
71+
ThrowTerminatingError(new ErrorRecord(new ApplicationException(string.Format(CultureInfo.CurrentUICulture, "Get-AzureDiskEncryptionExtension can enable encryption only on a VM that was already created ")),
72+
"InvalidResult",
73+
ErrorCategory.InvalidResult,
74+
null));
75+
}
76+
77+
VirtualMachineExtension vmExtensionParameters = null;
78+
79+
if (OSType.Windows.Equals(currentOSType))
80+
{
81+
this.Name = this.Name ?? AzureDiskEncryptionExtensionContext.ExtensionDefaultName;
82+
vmExtensionParameters = new VirtualMachineExtension
83+
{
84+
Location = vmParameters.Location,
85+
Publisher = AzureDiskEncryptionExtensionContext.ExtensionDefaultPublisher,
86+
VirtualMachineExtensionType = AzureDiskEncryptionExtensionContext.ExtensionDefaultName,
87+
TypeHandlerVersion = AzureDiskEncryptionExtensionContext.ExtensionDefaultVersion,
88+
Settings = publicSettings,
89+
ProtectedSettings = protectedSettings
90+
};
91+
}
92+
else if (OSType.Linux.Equals(currentOSType))
93+
{
94+
this.Name = this.Name ?? AzureDiskEncryptionExtensionContext.LinuxExtensionDefaultName;
95+
vmExtensionParameters = new VirtualMachineExtension
96+
{
97+
Location = vmParameters.Location,
98+
Publisher = AzureDiskEncryptionExtensionContext.LinuxExtensionDefaultPublisher,
99+
VirtualMachineExtensionType = AzureDiskEncryptionExtensionContext.LinuxExtensionDefaultName,
100+
TypeHandlerVersion = AzureDiskEncryptionExtensionContext.LinuxExtensionDefaultVersion,
101+
Settings = publicSettings,
102+
ProtectedSettings = protectedSettings
103+
};
104+
}
105+
106+
return vmExtensionParameters;
107+
}
108+
109+
private string GetExtensionStatusMessage(OSType currentOSType, bool returnSubstatusMessage=false)
110+
{
111+
AzureOperationResponse<VirtualMachineExtension> extensionResult = this.VirtualMachineExtensionClient.GetWithInstanceView(this.ResourceGroupName, this.VMName, this.Name);
112+
if (extensionResult == null)
113+
{
114+
ThrowTerminatingError(new ErrorRecord(new ApplicationFailedException(string.Format(CultureInfo.CurrentUICulture, "Failed to retrieve extension status")),
115+
"InvalidResult",
116+
ErrorCategory.InvalidResult,
117+
null));
118+
}
119+
120+
PSVirtualMachineExtension returnedExtension = extensionResult.ToPSVirtualMachineExtension(
121+
this.ResourceGroupName, this.VMName);
122+
123+
if ((returnedExtension == null) ||
124+
(string.IsNullOrWhiteSpace(returnedExtension.Publisher)) ||
125+
(string.IsNullOrWhiteSpace(returnedExtension.ExtensionType)))
126+
{
127+
ThrowTerminatingError(new ErrorRecord(new ApplicationFailedException(string.Format(CultureInfo.CurrentUICulture, "Missing extension publisher and type info")),
128+
"InvalidResult",
129+
ErrorCategory.InvalidResult,
130+
null));
131+
}
132+
bool publisherMatch = false;
133+
if (OSType.Linux.Equals(currentOSType))
134+
{
135+
if (returnedExtension.Publisher.Equals(AzureDiskEncryptionExtensionContext.LinuxExtensionDefaultPublisher, StringComparison.InvariantCultureIgnoreCase) &&
136+
returnedExtension.ExtensionType.Equals(AzureDiskEncryptionExtensionContext.LinuxExtensionDefaultName, StringComparison.InvariantCultureIgnoreCase))
137+
{
138+
publisherMatch = true;
139+
}
140+
}
141+
else if (OSType.Windows.Equals(currentOSType))
142+
{
143+
if (returnedExtension.Publisher.Equals(AzureDiskEncryptionExtensionContext.ExtensionDefaultPublisher, StringComparison.InvariantCultureIgnoreCase) &&
144+
returnedExtension.ExtensionType.Equals(AzureDiskEncryptionExtensionContext.ExtensionDefaultName, StringComparison.InvariantCultureIgnoreCase))
145+
{
146+
publisherMatch = true;
147+
}
148+
}
149+
if (publisherMatch)
150+
{
151+
AzureDiskEncryptionExtensionContext context = new AzureDiskEncryptionExtensionContext(returnedExtension);
152+
if ((context == null) ||
153+
(context.Statuses == null) ||
154+
(context.Statuses.Count < 1) ||
155+
(string.IsNullOrWhiteSpace(context.Statuses[0].Message)))
156+
{
157+
throw new KeyNotFoundException(string.Format(CultureInfo.CurrentUICulture, "Invalid extension status"));
158+
}
159+
160+
if (returnSubstatusMessage)
161+
{
162+
if((context == null) ||
163+
(context.SubStatuses == null) ||
164+
(context.SubStatuses.Count < 1))
165+
{
166+
throw new KeyNotFoundException(string.Format(CultureInfo.CurrentUICulture, "Invalid extension substatus"));
167+
}
168+
else
169+
{
170+
return context.SubStatuses[0].Message;
171+
}
172+
}
173+
174+
return context.Statuses[0].Message;
175+
}
176+
else
177+
{
178+
ThrowTerminatingError(new ErrorRecord(new ApplicationFailedException(string.Format(CultureInfo.CurrentUICulture, "Extension publisher and type mismatched")),
179+
"InvalidResult",
180+
ErrorCategory.InvalidResult,
181+
null));
182+
}
183+
return null;
184+
}
185+
48186
private OSType GetOSType(VirtualMachine vmParameters)
49187
{
50188
if (vmParameters == null || vmParameters.StorageProfile == null || vmParameters.StorageProfile.OsDisk == null)
@@ -209,17 +347,72 @@ public override void ExecuteCmdlet()
209347
EncryptionStatus osVolumeEncrypted = IsOsVolumeEncrypted(vmParameters);
210348
DiskEncryptionSettings osVolumeEncryptionSettings = GetOsVolumeEncryptionSettings(vmParameters);
211349
EncryptionStatus dataVolumesEncrypted = AreDataVolumesEncrypted(vmParameters);
350+
AzureDiskEncryptionStatusContext encryptionStatus = null;
351+
string progressMessage = null;
212352

213353
OSType osType = GetOSType(vmParameters);
214354
switch (osType)
215355
{
216356
case OSType.Windows:
217-
case OSType.Linux:
218-
AzureDiskEncryptionStatusContext encryptionStatus = new AzureDiskEncryptionStatusContext
357+
try
358+
{
359+
progressMessage = GetExtensionStatusMessage(osType);
360+
}
361+
catch(KeyNotFoundException)
362+
{
363+
progressMessage = string.Format(CultureInfo.CurrentUICulture, "Extension status not available on the VM");
364+
}
365+
366+
encryptionStatus = new AzureDiskEncryptionStatusContext
219367
{
220368
OsVolumeEncrypted = osVolumeEncrypted,
221369
DataVolumesEncrypted = dataVolumesEncrypted,
222-
OsVolumeEncryptionSettings = osVolumeEncryptionSettings
370+
OsVolumeEncryptionSettings = osVolumeEncryptionSettings,
371+
ProgressMessage = progressMessage
372+
};
373+
WriteObject(encryptionStatus);
374+
break;
375+
case OSType.Linux:
376+
VirtualMachine virtualMachineResponse = this.ComputeClient.ComputeManagementClient.VirtualMachines.GetWithInstanceView(
377+
this.ResourceGroupName, VMName).Body;
378+
VirtualMachineExtension parameters = GetVmExtensionParameters(virtualMachineResponse, osType);
379+
380+
this.VirtualMachineExtensionClient.CreateOrUpdateWithHttpMessagesAsync(
381+
this.ResourceGroupName,
382+
this.VMName,
383+
this.Name,
384+
parameters).GetAwaiter().GetResult();
385+
386+
Dictionary<string, string> encryptionStatusParsed = null;
387+
try
388+
{
389+
string encryptionStatusJson = GetExtensionStatusMessage(osType, returnSubstatusMessage: true);
390+
encryptionStatusParsed = JsonConvert.DeserializeObject<Dictionary<string, string>>(encryptionStatusJson);
391+
}
392+
catch(KeyNotFoundException)
393+
{
394+
encryptionStatusParsed = new Dictionary<string, string>()
395+
{
396+
{ AzureDiskEncryptionExtensionConstants.encryptionResultOsKey, EncryptionStatus.Unknown.ToString() },
397+
{ AzureDiskEncryptionExtensionConstants.encryptionResultDataKey, EncryptionStatus.Unknown.ToString() }
398+
};
399+
}
400+
401+
try
402+
{
403+
progressMessage = GetExtensionStatusMessage(osType);
404+
}
405+
catch(KeyNotFoundException)
406+
{
407+
progressMessage = string.Format(CultureInfo.CurrentUICulture, "Extension status not available on the VM");
408+
}
409+
410+
encryptionStatus = new AzureDiskEncryptionStatusContext
411+
{
412+
OsVolumeEncrypted = (EncryptionStatus)Enum.Parse(typeof(EncryptionStatus), encryptionStatusParsed[AzureDiskEncryptionExtensionConstants.encryptionResultOsKey]),
413+
DataVolumesEncrypted = (EncryptionStatus)Enum.Parse(typeof(EncryptionStatus), encryptionStatusParsed[AzureDiskEncryptionExtensionConstants.encryptionResultDataKey]),
414+
OsVolumeEncryptionSettings = osVolumeEncryptionSettings,
415+
ProgressMessage = progressMessage
223416
};
224417
WriteObject(encryptionStatus);
225418
break;

src/ResourceManager/Compute/Commands.Compute/Extension/AzureDiskEncryption/SetAzureDiskEncryptionExtension.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -430,20 +430,6 @@ public override void ExecuteCmdlet()
430430

431431
currentOSType = virtualMachineResponse.StorageProfile.OsDisk.OsType;
432432

433-
if (OperatingSystemTypes.Linux.Equals(currentOSType) &&
434-
!AzureDiskEncryptionExtensionContext.VolumeTypeData.Equals(VolumeType, StringComparison.InvariantCultureIgnoreCase))
435-
{
436-
ThrowTerminatingError(
437-
new ErrorRecord(
438-
new ArgumentException(
439-
string.Format(
440-
CultureInfo.CurrentUICulture,
441-
"Enabling encryption is only allowed on Data volumes for Linux VMs.")),
442-
"InvalidType",
443-
ErrorCategory.NotImplemented,
444-
null));
445-
}
446-
447433
if (OperatingSystemTypes.Linux.Equals(currentOSType))
448434
{
449435
CreateVMBackupForLinx();

src/ResourceManager/Compute/Commands.Compute/Microsoft.Azure.Commands.Compute.format.ps1xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,10 @@
556556
<Label>OsVolumeEncryptionSettings</Label>
557557
<PropertyName>OsVolumeEncryptionSettings</PropertyName>
558558
</ListItem>
559+
<ListItem>
560+
<Label>ProgressMessage</Label>
561+
<PropertyName>ProgressMessage</PropertyName>
562+
</ListItem>
559563
</ListItems>
560564
</ListEntry>
561565
</ListEntries>

src/ResourceManager/Compute/Commands.Compute/Models/AzureDiskEncryptionStatusContext.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ enum EncryptionStatus
2121
{
2222
Encrypted,
2323
NotEncrypted,
24+
NotMounted,
25+
EncryptionInProgress,
26+
VMRestartPending,
2427
Unknown
2528
}
2629

@@ -29,5 +32,6 @@ class AzureDiskEncryptionStatusContext
2932
public EncryptionStatus OsVolumeEncrypted { get; set; }
3033
public DiskEncryptionSettings OsVolumeEncryptionSettings { get; set; }
3134
public EncryptionStatus DataVolumesEncrypted { get; set; }
35+
public string ProgressMessage { get; set; }
3236
}
3337
}

0 commit comments

Comments
 (0)