Skip to content
This repository was archived by the owner on Nov 1, 2023. It is now read-only.

Commit 124f50d

Browse files
authored
Report extension errors (#2846)
Old failure message: ``` failed to launch extension ``` New failure message: ``` failed to launch extension(s): Errors for extension 'CustomScriptExtension': :Error: ProvisioningState/failed/3 (Provisioning failed) - Failed to download all specified files. Exiting. Error Message: The remote server returned an error: (400) Bad Request. ```
1 parent e0e6981 commit 124f50d

File tree

1 file changed

+41
-18
lines changed

1 file changed

+41
-18
lines changed

src/ApiService/ApiService/onefuzzlib/VmOperations.cs

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
using System.Threading.Tasks;
1+
using System.Text;
2+
using System.Threading.Tasks;
23
using Azure;
4+
using Azure.Core;
35
using Azure.ResourceManager.Compute;
46
using Azure.ResourceManager.Compute.Models;
5-
using Newtonsoft.Json;
67

78
namespace Microsoft.OneFuzz.Service;
89

@@ -153,7 +154,7 @@ public async System.Threading.Tasks.Task DeleteVm(string name) {
153154

154155

155156
public async Task<OneFuzzResult<bool>> AddExtensions(Vm vm, Dictionary<string, VirtualMachineExtensionData> extensions) {
156-
var status = new List<string>();
157+
var statuses = new List<(string extName, string state)>();
157158
var toCreate = new List<KeyValuePair<string, VirtualMachineExtensionData>>();
158159
foreach (var extensionConfig in extensions) {
159160
var extensionName = extensionConfig.Key;
@@ -164,7 +165,7 @@ public async Task<OneFuzzResult<bool>> AddExtensions(Vm vm, Dictionary<string, V
164165
_logTracer.Info(
165166
$"vm extension state: {vm.Name:Tag:VmName} - {extensionName:Tag:ExtensionName} - {extension.ProvisioningState:Tag:ExtensionProvisioningState}"
166167
);
167-
status.Add(extension.ProvisioningState);
168+
statuses.Add((extensionName, extension.ProvisioningState));
168169
} else {
169170
toCreate.Add(extensionConfig);
170171
}
@@ -175,19 +176,15 @@ public async Task<OneFuzzResult<bool>> AddExtensions(Vm vm, Dictionary<string, V
175176
await CreateExtension(vm.Name, config.Key, config.Value);
176177
}
177178
} else {
178-
if (status.All(s => string.Equals(s, "Succeeded", StringComparison.Ordinal))) {
179-
return OneFuzzResult<bool>.Ok(true);
180-
} else if (status.Any(s => string.Equals(s, "Failed", StringComparison.Ordinal))) {
181-
return OneFuzzResult<bool>.Error(
182-
ErrorCode.VM_CREATE_FAILED,
183-
"failed to launch extension"
184-
);
185-
} else if (!(status.Contains("Creating") || status.Contains("Updating"))) {
186-
_logTracer.Error($"vm agent - unknown state {vm.Name:Tag:VmName}: {JsonConvert.SerializeObject(status):Tag:Status}");
179+
if (statuses.All(s => s.state == "Succeeded")) {
180+
return OneFuzzResult.Ok(true);
181+
} else if (statuses.Any(s => s.state == "Failed")) {
182+
var errors = await GetExtensionErrors(vm.Name, statuses.Where(s => s.state == "Failed").Select(s => s.extName));
183+
return OneFuzzResult<bool>.Error(ErrorCode.VM_CREATE_FAILED, "failed to launch extension(s): " + errors);
187184
}
188185
}
189186

190-
return OneFuzzResult<bool>.Ok(false);
187+
return OneFuzzResult.Ok(false);
191188
}
192189

193190
public async Task<OneFuzzResultVoid> Create(Vm vm) {
@@ -223,16 +220,21 @@ public async Task<OneFuzzResultVoid> Create(Vm vm) {
223220
}
224221
}
225222

223+
private ResourceIdentifier GetVirtualMachineIdentifier(string vmName)
224+
=> VirtualMachineResource.CreateResourceIdentifier(
225+
_context.Creds.GetSubscription(),
226+
_context.Creds.GetBaseResourceGroup(),
227+
vmName);
228+
226229
public async Async.Task CreateExtension(string vmName, string extensionName, VirtualMachineExtensionData extension) {
227230
_logTracer.Info($"creating extension: {_context.Creds.GetBaseResourceGroup():Tag:ResourceGroup} - {vmName:Tag:VmName} - {extensionName:Tag:ExtensionName}");
228-
var vm = await _context.Creds.GetResourceGroupResource().GetVirtualMachineAsync(vmName);
229231

232+
var vm = _context.Creds.ArmClient.GetVirtualMachineResource(GetVirtualMachineIdentifier(vmName));
230233
try {
231-
_ = await vm.Value.GetVirtualMachineExtensions().CreateOrUpdateAsync(
234+
_ = await vm.GetVirtualMachineExtensions().CreateOrUpdateAsync(
232235
WaitUntil.Started,
233236
extensionName,
234-
extension
235-
);
237+
extension);
236238
} catch (RequestFailedException ex) when
237239
(ex.Status == 409 &&
238240
(ex.Message.Contains("VM is marked for deletion") || ex.Message.Contains("The request failed due to conflict with a concurrent request."))) {
@@ -241,6 +243,27 @@ public async Async.Task CreateExtension(string vmName, string extensionName, Vir
241243
return;
242244
}
243245

246+
public async Async.Task<string> GetExtensionErrors(string vmName, IEnumerable<string> extensionNames) {
247+
var vmResource = _context.Creds.ArmClient.GetVirtualMachineResource(GetVirtualMachineIdentifier(vmName));
248+
var vmData = await vmResource.GetAsync(InstanceViewTypes.InstanceView);
249+
250+
var result = new StringBuilder();
251+
foreach (var extensionName in extensionNames) {
252+
result.Append($"Errors for extension '{extensionName}':");
253+
var extensionData = vmData.Value.Data.InstanceView.Extensions.FirstOrDefault(ext => ext.Name == extensionName);
254+
if (extensionData is null) {
255+
result.Append($" (cannot get errors - extension was not found on target VM)\n");
256+
} else {
257+
result.Append('\n');
258+
foreach (var status in extensionData.Statuses) {
259+
result.Append($"{status.Time}:{status.Level}: {status.Code} ({status.DisplayStatus}) - {status.Message}\n");
260+
}
261+
}
262+
}
263+
264+
return result.ToString();
265+
}
266+
244267
async Task<OneFuzzResultVoid> CreateVm(
245268
string name,
246269
Region location,

0 commit comments

Comments
 (0)