Refactor timer repro part2 (#1852)

* Implement the rest of the function

* Initial implementation

* Pulling new formatting

* format

* Fixes after testing

* PR comments
This commit is contained in:
Teo Voinea
2022-05-03 08:09:00 -04:00
committed by GitHub
parent e6a0906b6c
commit 8c73f84b87
12 changed files with 136 additions and 33 deletions

View File

@ -130,4 +130,4 @@ csharp_preserve_single_line_blocks = true
[*.{cs}]
dotnet_diagnostic.IDE0005.severity = warning
dotnet_diagnostic.IDE0005.severity = warning

View File

@ -30,7 +30,7 @@ public enum ErrorCode {
public enum VmState {
Init,
ExtensionsLaunched,
ExtensionsLaunch,
ExtensionsFailed,
VmAllocationFailed,
Running,
@ -192,7 +192,7 @@ public static class VmStateHelper {
return
new[]{
VmState.Init,
VmState.ExtensionsLaunched,
VmState.ExtensionsLaunch,
VmState.Stopping
};
});
@ -204,7 +204,7 @@ public static class VmStateHelper {
return
new[]{
VmState.Init,
VmState.ExtensionsLaunched,
VmState.ExtensionsLaunch,
VmState.ExtensionsFailed,
VmState.VmAllocationFailed,
VmState.Running,

View File

@ -471,8 +471,8 @@ public record TeamsTemplate();
public record GithubIssuesTemplate();
public record Repro(
DateTimeOffset Timestamp,
Guid VmId,
[PartitionKey] Guid VmId,
[RowKey] Guid _,
Guid TaskId,
ReproConfig Config,
VmState State,
@ -589,6 +589,7 @@ public record Job(
public UserInfo? UserInfo { get; set; }
}
public record Nsg(string Name, Region Region);
public record WorkUnit(
Guid JobId,

View File

@ -84,6 +84,7 @@ public class Program {
.AddScoped<IVmOperations, VmOperations>()
.AddScoped<ISecretsOperations, SecretsOperations>()
.AddScoped<IJobOperations, JobOperations>()
.AddScoped<INsgOperations, NsgOperations>()
.AddScoped<IScheduler, Scheduler>()
.AddScoped<IConfig, Config>()
.AddScoped<ILogAnalytics, LogAnalytics>()

View File

@ -10,7 +10,7 @@ public partial class TimerProxy {
private readonly IScalesetOperations _scalesetOperations;
private readonly INsg _nsg;
private readonly INsgOperations _nsg;
private readonly ICreds _creds;
@ -18,7 +18,7 @@ public partial class TimerProxy {
private readonly ISubnet _subnet;
public TimerProxy(ILogTracer logTracer, IProxyOperations proxies, IScalesetOperations scalesets, INsg nsg, ICreds creds, IConfigOperations configOperations, ISubnet subnet) {
public TimerProxy(ILogTracer logTracer, IProxyOperations proxies, IScalesetOperations scalesets, INsgOperations nsg, ICreds creds, IConfigOperations configOperations, ISubnet subnet) {
_logger = logTracer;
_proxYOperations = proxies;
_scalesetOperations = scalesets;

View File

@ -15,10 +15,23 @@ public class TimerRepro {
_reproOperations = reproOperations;
}
// [Function("TimerRepro")]
public async Async.Task Run([TimerTrigger("00:00:30")] TimerInfo myTimer) {
var expired = _reproOperations.SearchExpired();
await foreach (var repro in expired) {
_log.Info($"stopping repro: {repro?.VmId}");
_log.Info($"stopping repro: {repro.VmId}");
await _reproOperations.Stopping(repro);
}
var expiredVmIds = expired.Select(repro => repro?.VmId);
await foreach (var repro in _reproOperations.SearchStates(VmStateHelper.NeedsWork())) {
if (await expiredVmIds.ContainsAsync(repro.VmId)) {
// this VM already got processed during the expired phase
continue;
}
_log.Info($"update repro: {repro.VmId}");
await _reproOperations.ProcessStateUpdates(repro);
}
}

View File

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using Azure;
using Azure.ResourceManager.Compute;
namespace Microsoft.OneFuzz.Service;
@ -19,8 +20,19 @@ public class DiskOperations : IDiskOperations {
_creds = creds;
}
public Task<bool> DeleteDisk(string resourceGroup, string name) {
throw new NotImplementedException();
public async Task<bool> DeleteDisk(string resourceGroup, string name) {
try {
_logTracer.Info($"deleting disks {resourceGroup} : {name}");
var disk = await _creds.GetResourceGroupResource().GetDiskAsync(name);
if (disk != null) {
await disk.Value.DeleteAsync(WaitUntil.Started);
return true;
}
} catch (Exception e) {
_logTracer.Error($"unable to delete disk: {name} {e.Message}");
_logTracer.Exception(e);
}
return false;
}
public DiskCollection ListDisks(string resourceGroup) {

View File

@ -1,4 +1,5 @@
using Azure.ResourceManager.Network;
using Azure;
using Azure.ResourceManager.Network;
namespace Microsoft.OneFuzz.Service;
@ -32,11 +33,13 @@ public class IpOperations : IIpOperations {
return await _creds.GetResourceGroupResource().GetPublicIPAddressAsync(name);
}
public Async.Task DeleteNic(string resourceGroup, string name) {
throw new NotImplementedException();
public async System.Threading.Tasks.Task DeleteNic(string resourceGroup, string name) {
_logTracer.Info($"deleting nic {resourceGroup}:{name}");
await _creds.GetResourceGroupResource().GetNetworkInterfaceAsync(name).Result.Value.DeleteAsync(WaitUntil.Started);
}
public Async.Task DeleteIp(string resourceGroup, string name) {
throw new NotImplementedException();
public async System.Threading.Tasks.Task DeleteIp(string resourceGroup, string name) {
_logTracer.Info($"deleting ip {resourceGroup}:{name}");
await _creds.GetResourceGroupResource().GetPublicIPAddressAsync(name).Result.Value.DeleteAsync(WaitUntil.Started);
}
}

View File

@ -3,24 +3,24 @@ using Azure.ResourceManager.Network;
namespace Microsoft.OneFuzz.Service {
public interface INsg {
public interface INsgOperations {
Async.Task<NetworkSecurityGroupResource?> GetNsg(string name);
public Async.Task<Error?> AssociateSubnet(string name, VirtualNetworkResource vnet, SubnetResource subnet);
IAsyncEnumerable<NetworkSecurityGroupResource> ListNsgs();
bool OkToDelete(HashSet<string> active_regions, string nsg_region, string nsg_name);
Async.Task<bool> StartDeleteNsg(string name);
Async.Task DissociateNic(NetworkInterfaceResource nic);
Async.Task<OneFuzzResultVoid> DissociateNic(Nsg nsg, NetworkInterfaceResource nic);
}
public class Nsg : INsg {
public class NsgOperations : INsgOperations {
private readonly ICreds _creds;
private readonly ILogTracer _logTracer;
public Nsg(ICreds creds, ILogTracer logTracer) {
public NsgOperations(ICreds creds, ILogTracer logTracer) {
_creds = creds;
_logTracer = logTracer;
}
@ -46,8 +46,54 @@ namespace Microsoft.OneFuzz.Service {
return null;
}
public Async.Task DissociateNic(NetworkInterfaceResource nic) {
throw new NotImplementedException();
public async Async.Task<OneFuzzResultVoid> DissociateNic(Nsg nsg, NetworkInterfaceResource nic) {
if (nic.Data.NetworkSecurityGroup == null) {
return OneFuzzResultVoid.Ok();
}
var azureNsg = await GetNsg(nsg.Name);
if (azureNsg == null) {
return OneFuzzResultVoid.Error(
ErrorCode.UNABLE_TO_FIND,
new[] { $"cannot update nsg rules. nsg {nsg.Name} not found" }
);
}
if (azureNsg.Data.Id != nic.Data.NetworkSecurityGroup.Id) {
return OneFuzzResultVoid.Error(
ErrorCode.UNABLE_TO_UPDATE,
new[] {
"network interface is not associated with this nsg.",
$"nsg: {azureNsg.Id}, nic: {nic.Data.Name}, nic.nsg: {nic.Data.NetworkSecurityGroup.Id}"
}
);
}
_logTracer.Info($"dissociating nic {nic.Data.Name} with nsg: {_creds.GetBaseResourceGroup()} {nsg.Name}");
nic.Data.NetworkSecurityGroup = null;
try {
await _creds.GetResourceGroupResource()
.GetNetworkInterfaces()
.CreateOrUpdateAsync(WaitUntil.Started, nic.Data.Name, nic.Data);
} catch (Exception e) {
if (IsConcurrentRequestError(e.Message)) {
/*
logging.debug(
"dissociate nsg with nic had conflicts with ",
"concurrent request, ignoring %s",
err,
)
*/
return OneFuzzResultVoid.Ok();
}
return OneFuzzResultVoid.Error(
ErrorCode.UNABLE_TO_UPDATE,
new[] {
$"Unable to dissociate nsg {nsg.Name} with nic {nic.Data.Name} due to {e.Message} {e.StackTrace}"
}
);
}
return OneFuzzResultVoid.Ok();
}
public async Async.Task<NetworkSecurityGroupResource?> GetNsg(string name) {
@ -76,5 +122,9 @@ namespace Microsoft.OneFuzz.Service {
await nsg.Value.DeleteAsync(WaitUntil.Completed);
return true;
}
private static bool IsConcurrentRequestError(string err) {
return err.Contains("The request failed due to conflict with a concurrent request");
}
}
}

View File

@ -3,7 +3,11 @@
namespace Microsoft.OneFuzz.Service;
public interface IReproOperations : IStatefulOrm<Repro, VmState> {
public IAsyncEnumerable<Repro?> SearchExpired();
public IAsyncEnumerable<Repro> SearchExpired();
public System.Threading.Tasks.Task Stopping(Repro repro);
public IAsyncEnumerable<Repro> SearchStates(IEnumerable<VmState>? States);
}
public class ReproOperations : StatefulOrm<Repro, VmState>, IReproOperations {
@ -30,7 +34,7 @@ public class ReproOperations : StatefulOrm<Repro, VmState>, IReproOperations {
_vmOperations = vmOperations;
}
public IAsyncEnumerable<Repro?> SearchExpired() {
public IAsyncEnumerable<Repro> SearchExpired() {
return QueryAsync(filter: $"end_time lt datetime'{DateTime.UtcNow.ToString("o")}'");
}
@ -86,4 +90,15 @@ public class ReproOperations : StatefulOrm<Repro, VmState>, IReproOperations {
_logTracer.Info($"vm stopped: {repro.VmId}");
await Delete(repro);
}
public IAsyncEnumerable<Repro> SearchStates(IEnumerable<VmState>? states) {
string? queryString = null;
if (states != null) {
queryString = string.Join(
" or ",
states.Select(s => $"state eq '{s}'")
);
}
return QueryAsync(queryString);
}
}

View File

@ -58,8 +58,10 @@ public class TaskOperations : StatefulOrm<Task, TaskState>, ITaskOperations {
queryString += " and ";
}
var statesString = string.Join(",", states);
queryString += $"state in ({statesString})";
queryString += "(" + string.Join(
" or ",
states.Select(s => $"state eq '{s}'")
) + ")";
}
return QueryAsync(filter: queryString);
@ -69,7 +71,6 @@ public class TaskOperations : StatefulOrm<Task, TaskState>, ITaskOperations {
throw new NotImplementedException();
}
public IAsyncEnumerable<Task> SearchExpired() {
var timeFilter = $"end_time lt Datetime'{DateTimeOffset.UtcNow.ToString("o") }'";
return QueryAsync(filter: timeFilter);

View File

@ -1,4 +1,5 @@
using Azure.ResourceManager.Compute;
using Azure;
using Azure.ResourceManager.Compute;
namespace Microsoft.OneFuzz.Service;
@ -23,11 +24,14 @@ public class VmOperations : IVmOperations {
private IDiskOperations _diskOperations;
public VmOperations(ILogTracer log, ICreds creds, IIpOperations ipOperations, IDiskOperations diskOperations) {
private INsgOperations _nsgOperations;
public VmOperations(ILogTracer log, ICreds creds, IIpOperations ipOperations, IDiskOperations diskOperations, INsgOperations nsgOperations) {
_logTracer = log;
_creds = creds;
_ipOperations = ipOperations;
_diskOperations = diskOperations;
_nsgOperations = nsgOperations;
}
public async Async.Task<bool> IsDeleted(Vm vm) {
return !(await HasComponents(vm.Name));
@ -72,7 +76,7 @@ public class VmOperations : IVmOperations {
_logTracer.Info($"deleting vm components {resourceGroup}:{name}");
if (GetVm(name) != null) {
_logTracer.Info($"deleting vm {resourceGroup}:{name}");
DeleteVm(name);
await DeleteVm(name);
return false;
}
@ -80,7 +84,7 @@ public class VmOperations : IVmOperations {
if (nic != null) {
_logTracer.Info($"deleting nic {resourceGroup}:{name}");
if (nic.Data.NetworkSecurityGroup != null && nsg != null) {
await nsg.DissociateNic(nic);
await _nsgOperations.DissociateNic((Nsg)nsg, nic);
return false;
}
await _ipOperations.DeleteNic(resourceGroup, name);
@ -108,7 +112,10 @@ public class VmOperations : IVmOperations {
return true;
}
public void DeleteVm(string name) {
throw new NotImplementedException();
public async System.Threading.Tasks.Task DeleteVm(string name) {
_logTracer.Info($"deleting vm: {_creds.GetBaseResourceGroup()} {name}");
await _creds.GetResourceGroupResource()
.GetVirtualMachineAsync(name).Result.Value
.DeleteAsync(WaitUntil.Started);
}
}