mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-15 03:18:07 +00:00
migrate proxy (#2206)
* migrate proxy function * - added private ip address query - updated Azure.ResourceManager.Storage to non beta release * remove comment * extracting nework interface query * format * Update src/ApiService/ApiService/Functions/Proxy.cs Co-authored-by: Teo Voinea <58236992+tevoinea@users.noreply.github.com> * fix function name * Fix merge conflict Co-authored-by: Teo Voinea <58236992+tevoinea@users.noreply.github.com>
This commit is contained in:
@ -23,10 +23,10 @@
|
||||
<PackageReference Include="Azure.Core" Version="1.25.0" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.6.0" />
|
||||
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.10.0" />
|
||||
<PackageReference Include="Azure.ResourceManager" Version="1.0.0" />
|
||||
<PackageReference Include="Azure.ResourceManager.Network" Version="1.0.0-beta.7" />
|
||||
<PackageReference Include="Azure.ResourceManager" Version="1.2.1" />
|
||||
<PackageReference Include="Azure.ResourceManager.Network" Version="1.0.0" />
|
||||
<PackageReference Include="Azure.ResourceManager.Resources" Version="1.0.0" />
|
||||
<PackageReference Include="Azure.ResourceManager.Storage" Version="1.0.0-beta.8" />
|
||||
<PackageReference Include="Azure.ResourceManager.Storage" Version="1.0.0-beta.11" />
|
||||
<PackageReference Include="Azure.Storage.Queues" Version="12.11.0" />
|
||||
<PackageReference Include="Azure.Storage.Blobs" Version="12.13.0" />
|
||||
<PackageReference Include="Microsoft.Graph" Version="4.24.0" />
|
||||
|
172
src/ApiService/ApiService/Functions/Proxy.cs
Normal file
172
src/ApiService/ApiService/Functions/Proxy.cs
Normal file
@ -0,0 +1,172 @@
|
||||
using System.Net;
|
||||
using Microsoft.Azure.Functions.Worker;
|
||||
using Microsoft.Azure.Functions.Worker.Http;
|
||||
using VmProxy = Microsoft.OneFuzz.Service.Proxy;
|
||||
|
||||
namespace Microsoft.OneFuzz.Service.Functions;
|
||||
|
||||
public class Proxy {
|
||||
private readonly ILogTracer _log;
|
||||
private readonly IEndpointAuthorization _auth;
|
||||
private readonly IOnefuzzContext _context;
|
||||
|
||||
public Proxy(ILogTracer log, IEndpointAuthorization auth, IOnefuzzContext context) {
|
||||
_log = log;
|
||||
_auth = auth;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
[Function("proxy")]
|
||||
public Async.Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Anonymous, "GET", "PATCH", "POST", "DELETE")] HttpRequestData req) {
|
||||
return _auth.CallIfUser(req, r => r.Method switch {
|
||||
"GET" => Get(r),
|
||||
"PATCH" => Patch(r),
|
||||
"POST" => Post(r),
|
||||
"DELETE" => Delete(r),
|
||||
_ => throw new InvalidOperationException("Unsupported HTTP method"),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private ProxyGetResult GetResult(ProxyForward proxyForward, VmProxy? proxy) {
|
||||
var forward = _context.ProxyForwardOperations.ToForward(proxyForward);
|
||||
|
||||
if (proxy == null
|
||||
|| (proxy.State != VmState.Running && proxy.State != VmState.ExtensionsLaunch)
|
||||
|| proxy.Heartbeat == null
|
||||
|| !proxy.Heartbeat.Forwards.Contains(forward)
|
||||
) {
|
||||
return new ProxyGetResult(null, Forward: forward);
|
||||
}
|
||||
|
||||
return new ProxyGetResult(proxy.Ip, forward);
|
||||
}
|
||||
|
||||
private async Async.Task<HttpResponseData> Get(HttpRequestData req) {
|
||||
var request = await RequestHandling.ParseRequest<ProxyGet>(req);
|
||||
if (!request.IsOk) {
|
||||
return await _context.RequestHandling.NotOk(
|
||||
req,
|
||||
request.ErrorV,
|
||||
"ProxyGet");
|
||||
}
|
||||
|
||||
var proxyGet = request.OkV;
|
||||
switch ((proxyGet.ScalesetId, proxyGet.MachineId, proxyGet.DstPort)) {
|
||||
case (Guid scalesetId, Guid machineId, int dstPort):
|
||||
var scaleset = await _context.ScalesetOperations.GetById(scalesetId);
|
||||
if (!scaleset.IsOk) {
|
||||
return await _context.RequestHandling.NotOk(req, scaleset.ErrorV, "ProxyGet");
|
||||
}
|
||||
|
||||
var proxy = await _context.ProxyOperations.GetOrCreate(scaleset.OkV.Region);
|
||||
var forwards = await _context.ProxyForwardOperations.SearchForward(scalesetId: scalesetId,
|
||||
machineId: machineId, dstPort: dstPort).ToListAsync();
|
||||
|
||||
if (!forwards.Any()) {
|
||||
return await _context.RequestHandling.NotOk(req, new Error(ErrorCode.INVALID_REQUEST, new[] { "no forwards for scaleset and node" }), "debug_proxy get");
|
||||
}
|
||||
|
||||
var response = req.CreateResponse();
|
||||
await response.WriteAsJsonAsync(GetResult(forwards[0], proxy));
|
||||
return response;
|
||||
|
||||
case (null, null, null):
|
||||
var proxies = await _context.ProxyOperations.SearchAll()
|
||||
.Select(p => new ProxyInfo(p.Region, p.ProxyId, p.State)).ToListAsync();
|
||||
|
||||
var r = req.CreateResponse();
|
||||
await r.WriteAsJsonAsync(new ProxyList(proxies));
|
||||
return r;
|
||||
default:
|
||||
return await _context.RequestHandling.NotOk(req, new Error(ErrorCode.INVALID_REQUEST, new[] { "ProxyGet must provide all or none of the following: scaleset_id, machine_id, dst_port" }), "debug_proxy get");
|
||||
}
|
||||
}
|
||||
|
||||
private async Async.Task<HttpResponseData> Post(HttpRequestData req) {
|
||||
var request = await RequestHandling.ParseRequest<ProxyCreate>(req);
|
||||
if (!request.IsOk) {
|
||||
return await _context.RequestHandling.NotOk(
|
||||
req,
|
||||
request.ErrorV,
|
||||
"ProxyCreate");
|
||||
}
|
||||
|
||||
var scaleset = await _context.ScalesetOperations.GetById(request.OkV.MachineId);
|
||||
if (!scaleset.IsOk) {
|
||||
return await _context.RequestHandling.NotOk(req, scaleset.ErrorV, "debug_proxy create");
|
||||
}
|
||||
|
||||
var forwardResult = await _context.ProxyForwardOperations.UpdateOrCreate(
|
||||
region: scaleset.OkV.Region,
|
||||
scalesetId: scaleset.OkV.ScalesetId,
|
||||
machineId: request.OkV.MachineId,
|
||||
dstPort: request.OkV.DstPort,
|
||||
duration: request.OkV.Duration
|
||||
);
|
||||
|
||||
if (!forwardResult.IsOk) {
|
||||
return await _context.RequestHandling.NotOk(req, forwardResult.ErrorV, "debug_proxy create");
|
||||
}
|
||||
|
||||
var proxy = await _context.ProxyOperations.GetOrCreate(scaleset.OkV.Region);
|
||||
if (proxy != null) {
|
||||
var updated = forwardResult.OkV with { ProxyId = proxy.ProxyId };
|
||||
await _context.ProxyForwardOperations.Update(updated);
|
||||
await _context.ProxyOperations.SaveProxyConfig(proxy);
|
||||
}
|
||||
|
||||
var response = req.CreateResponse();
|
||||
var result = GetResult(forwardResult.OkV, proxy);
|
||||
await response.WriteAsJsonAsync(result);
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Async.Task<HttpResponseData> Patch(HttpRequestData req) {
|
||||
var request = await RequestHandling.ParseRequest<ProxyReset>(req);
|
||||
if (!request.IsOk) {
|
||||
return await _context.RequestHandling.NotOk(
|
||||
req,
|
||||
request.ErrorV,
|
||||
"ProxyReset");
|
||||
}
|
||||
|
||||
var proxyList = await _context.ProxyOperations.SearchByPartitionKeys(new[] { $"{request.OkV.Region}" }).ToListAsync();
|
||||
|
||||
foreach (var proxy in proxyList) {
|
||||
await _context.ProxyOperations.SetState(proxy, VmState.Stopping);
|
||||
}
|
||||
|
||||
var response = req.CreateResponse(HttpStatusCode.OK);
|
||||
await response.WriteAsJsonAsync(new BoolResult(proxyList.Any()));
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
private async Async.Task<HttpResponseData> Delete(HttpRequestData req) {
|
||||
var request = await RequestHandling.ParseRequest<ProxyDelete>(req);
|
||||
if (!request.IsOk) {
|
||||
return await _context.RequestHandling.NotOk(
|
||||
req,
|
||||
request.ErrorV,
|
||||
"debug_proxy delet");
|
||||
}
|
||||
|
||||
var regions = await _context.ProxyForwardOperations.RemoveForward(
|
||||
scalesetId: request.OkV.ScalesetId,
|
||||
machineId: request.OkV.MachineId,
|
||||
dstPort: request.OkV.DstPort
|
||||
);
|
||||
|
||||
foreach (var region in regions) {
|
||||
var proxy = await _context.ProxyOperations.GetOrCreate(region);
|
||||
if (proxy != null) {
|
||||
await _context.ProxyOperations.SaveProxyConfig(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
var response = req.CreateResponse(HttpStatusCode.OK);
|
||||
await response.WriteAsJsonAsync(new BoolResult(true));
|
||||
return response;
|
||||
}
|
||||
}
|
@ -78,7 +78,7 @@ public class TimerProxy {
|
||||
// if there are NSGs with name same as the region that they are allocated
|
||||
// and have no NIC associated with it then delete the NSG
|
||||
await foreach (var nsg in nsgOpertions.ListNsgs()) {
|
||||
if (nsgOpertions.OkToDelete(regions, nsg.Data.Location, nsg.Data.Name)) {
|
||||
if (nsgOpertions.OkToDelete(regions, nsg.Data.Location!, nsg.Data.Name)) {
|
||||
if (nsg.Data.NetworkInterfaces.Count == 0 && nsg.Data.Subnets.Count == 0) {
|
||||
await nsgOpertions.StartDeleteNsg(nsg.Data.Name);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public record ProxyHeartbeat
|
||||
(
|
||||
Region Region,
|
||||
Guid ProxyId,
|
||||
List<ProxyForward> Forwards,
|
||||
List<Forward> Forwards,
|
||||
DateTimeOffset TimeStamp
|
||||
);
|
||||
|
||||
@ -119,7 +119,7 @@ public record Forward
|
||||
public record ProxyForward
|
||||
(
|
||||
[PartitionKey] Region Region,
|
||||
[RowKey] string Port,
|
||||
[RowKey] long Port,
|
||||
Guid ScalesetId,
|
||||
Guid MachineId,
|
||||
Guid? ProxyId,
|
||||
|
@ -139,3 +139,25 @@ public record JobSearch(
|
||||
);
|
||||
|
||||
public record NodeAddSshKeyPost(Guid MachineId, string PublicKey);
|
||||
|
||||
public record ProxyGet(
|
||||
Guid? ScalesetId,
|
||||
Guid? MachineId,
|
||||
int? DstPort);
|
||||
|
||||
public record ProxyCreate(
|
||||
Guid ScalesetId,
|
||||
Guid MachineId,
|
||||
int DstPort,
|
||||
int Duration
|
||||
);
|
||||
|
||||
public record ProxyDelete(
|
||||
Guid ScalesetId,
|
||||
Guid MachineId,
|
||||
int? DstPort
|
||||
);
|
||||
|
||||
public record ProxyReset(
|
||||
string Region
|
||||
);
|
||||
|
@ -101,3 +101,19 @@ public class BaseResponseConverter : JsonConverter<BaseResponse> {
|
||||
JsonSerializer.Serialize(writer, value, eventType, options);
|
||||
}
|
||||
}
|
||||
|
||||
public record ProxyGetResult(
|
||||
string? Ip,
|
||||
Forward Forward
|
||||
);
|
||||
|
||||
public record ProxyInfo(
|
||||
string Region,
|
||||
Guid ProxyId,
|
||||
VmState State
|
||||
);
|
||||
|
||||
public record ProxyList(
|
||||
List<ProxyInfo> Proxies
|
||||
);
|
||||
|
||||
|
@ -103,6 +103,7 @@ public class Creds : ICreds {
|
||||
var path = GetScalesetIdentityResourcePath();
|
||||
var uid = ArmClient.GetGenericResource(new ResourceIdentifier(path));
|
||||
|
||||
|
||||
var resource = await uid.GetAsync();
|
||||
var principalId = resource.Value.Data.Properties.ToObjectFromJson<ScaleSetIdentity>().principalId;
|
||||
return new Guid(principalId);
|
||||
|
@ -1,7 +1,11 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Azure;
|
||||
using Azure.Core;
|
||||
using Azure.ResourceManager.Network;
|
||||
using Azure.ResourceManager.Network.Models;
|
||||
using Faithlife.Utility;
|
||||
|
||||
namespace Microsoft.OneFuzz.Service;
|
||||
|
||||
@ -18,18 +22,22 @@ public interface IIpOperations {
|
||||
|
||||
public Async.Task DeleteIp(string resourceGroup, string name);
|
||||
|
||||
public Async.Task<string?> GetScalesetInstanceIp(Guid scalesetId, Guid machineId);
|
||||
|
||||
public Async.Task CreateIp(string resourceGroup, string name, string region);
|
||||
}
|
||||
|
||||
|
||||
public class IpOperations : IIpOperations {
|
||||
private ILogTracer _logTracer;
|
||||
|
||||
|
||||
private IOnefuzzContext _context;
|
||||
private readonly NetworkInterfaceQuery _networkInterfaceQuery;
|
||||
|
||||
public IpOperations(ILogTracer log, IOnefuzzContext context) {
|
||||
_logTracer = log;
|
||||
_context = context;
|
||||
_networkInterfaceQuery = new NetworkInterfaceQuery(context);
|
||||
}
|
||||
|
||||
public async Async.Task<NetworkInterfaceResource?> GetPublicNic(string resourceGroup, string name) {
|
||||
@ -43,7 +51,6 @@ public class IpOperations : IIpOperations {
|
||||
|
||||
public async Async.Task<PublicIPAddressResource?> GetIp(string resourceGroup, string name) {
|
||||
_logTracer.Info($"getting ip {resourceGroup}:{name}");
|
||||
|
||||
try {
|
||||
return await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(name);
|
||||
} catch (RequestFailedException) {
|
||||
@ -61,6 +68,16 @@ public class IpOperations : IIpOperations {
|
||||
await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(name).Result.Value.DeleteAsync(WaitUntil.Started);
|
||||
}
|
||||
|
||||
public async Task<string?> GetScalesetInstanceIp(Guid scalesetId, Guid machineId) {
|
||||
var instance = await _context.VmssOperations.GetInstanceId(scalesetId, machineId);
|
||||
if (!instance.IsOk) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var ips = await _networkInterfaceQuery.ListInstancePrivateIps(scalesetId, instance.OkV);
|
||||
return ips.FirstOrDefault();
|
||||
}
|
||||
|
||||
public async Task<string?> GetPublicIp(string resourceId) {
|
||||
// TODO: Parts of this function seem redundant, but I'm mirroring
|
||||
// the python code exactly. We should revisit this.
|
||||
@ -75,7 +92,8 @@ public class IpOperations : IIpOperations {
|
||||
if (publicIp == null) {
|
||||
return null;
|
||||
}
|
||||
resource = _context.Creds.ParseResourceId(publicIp.Id);
|
||||
|
||||
resource = _context.Creds.ParseResourceId(publicIp.Id!);
|
||||
try {
|
||||
resource = await _context.Creds.GetData(resource);
|
||||
var publicIpResource = await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(
|
||||
@ -93,7 +111,7 @@ public class IpOperations : IIpOperations {
|
||||
var network = await Network.Create(region, _context);
|
||||
var subnetId = await network.GetId();
|
||||
|
||||
if (string.IsNullOrEmpty(subnetId)) {
|
||||
if (subnetId is not null) {
|
||||
await network.Create();
|
||||
return OneFuzzResultVoid.Ok;
|
||||
}
|
||||
@ -157,7 +175,7 @@ public class IpOperations : IIpOperations {
|
||||
public async Async.Task CreateIp(string resourceGroup, string name, string region) {
|
||||
var ipParams = new PublicIPAddressData() {
|
||||
Location = region,
|
||||
PublicIPAllocationMethod = IPAllocationMethod.Dynamic
|
||||
PublicIPAllocationMethod = NetworkIPAllocationMethod.Dynamic
|
||||
};
|
||||
|
||||
var onefuzzOwner = _context.ServiceConfiguration.OneFuzzOwner;
|
||||
@ -172,4 +190,52 @@ public class IpOperations : IIpOperations {
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Query the Scaleset network interface using the rest api directly because
|
||||
/// the api does not seems to support this :
|
||||
/// https://github.com/Azure/azure-sdk-for-net/issues/30253#issuecomment-1202447362
|
||||
/// </summary>
|
||||
class NetworkInterfaceQuery {
|
||||
record IpConfigurationsProperties(string privateIPAddress);
|
||||
|
||||
record IpConfigurations(IpConfigurationsProperties properties);
|
||||
|
||||
record NetworkInterfaceProperties(List<IpConfigurations> ipConfigurations);
|
||||
|
||||
record NetworkInterface(NetworkInterfaceProperties properties);
|
||||
|
||||
record ValueList<T>(List<T> value);
|
||||
|
||||
private readonly IOnefuzzContext _context;
|
||||
|
||||
public NetworkInterfaceQuery(IOnefuzzContext context) {
|
||||
_context = context;
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<string>> ListInstancePrivateIps(Guid scalesetId, string instanceId) {
|
||||
|
||||
var token = _context.Creds.GetIdentity().GetToken(
|
||||
new TokenRequestContext(
|
||||
new[] { $"https://management.azure.com" }));
|
||||
|
||||
using HttpClient client = new HttpClient();
|
||||
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token.Token);
|
||||
var baseUrl = new Uri($"https://management.azure.com/");
|
||||
// https://docs.microsoft.com/en-us/rest/api/virtualnetwork/network-interface-in-vm-ss/get-virtual-machine-scale-set-network-interface?tabs=HTTP
|
||||
var requestURl = baseUrl + $"subscriptions/{_context.Creds.GetSubscription()}/resourceGroups/{_context.Creds.GetBaseResourceGroup()}/providers/Microsoft.Compute/virtualMachineScaleSets/{scalesetId}/virtualMachines/{instanceId}/networkInterfaces?api-version=2021-08-01";
|
||||
var response = await client.GetAsync(requestURl);
|
||||
if (response.IsSuccessStatusCode) {
|
||||
var responseStream = await response.Content.ReadAsStreamAsync();
|
||||
var nics = await JsonSerializer.DeserializeAsync<ValueList<NetworkInterface>>(responseStream);
|
||||
if (nics != null)
|
||||
return nics.value.SelectMany(x => x.properties.ipConfigurations.Select(i => i.properties.privateIPAddress)).WhereNotNull().ToList();
|
||||
}
|
||||
return new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Azure.ResourceManager.Network;
|
||||
using Azure.Core;
|
||||
using Azure.ResourceManager.Network;
|
||||
|
||||
namespace Microsoft.OneFuzz.Service;
|
||||
|
||||
@ -48,7 +49,7 @@ public class Network {
|
||||
return _context.Subnet.GetSubnet(_name, _name);
|
||||
}
|
||||
|
||||
public async Async.Task<string?> GetId() {
|
||||
public async Async.Task<ResourceIdentifier?> GetId() {
|
||||
return await _context.Subnet.GetSubnetId(this._name, this._name);
|
||||
}
|
||||
|
||||
@ -61,7 +62,8 @@ public class Network {
|
||||
}
|
||||
|
||||
public async Async.Task<bool> Exists() {
|
||||
return !string.IsNullOrEmpty(await GetId());
|
||||
var id = await GetId();
|
||||
return id is not null;
|
||||
}
|
||||
|
||||
internal Async.Task<VirtualNetworkResource?> GetVnet() {
|
||||
|
@ -1,14 +1,20 @@
|
||||
using ApiService.OneFuzzLib.Orm;
|
||||
using System.Threading.Tasks;
|
||||
using ApiService.OneFuzzLib.Orm;
|
||||
|
||||
namespace Microsoft.OneFuzz.Service;
|
||||
|
||||
|
||||
public interface IProxyForwardOperations : IOrm<ProxyForward> {
|
||||
IAsyncEnumerable<ProxyForward> SearchForward(Guid? scalesetId = null, string? region = null, Guid? machineId = null, Guid? proxyId = null, int? dstPort = null);
|
||||
Forward ToForward(ProxyForward proxyForward);
|
||||
Task<OneFuzzResult<ProxyForward>> UpdateOrCreate(string region, Guid scalesetId, Guid machineId, int dstPort, int duration);
|
||||
Task<HashSet<string>> RemoveForward(Guid scalesetId, Guid? machineId = null, int? dstPort = null, Guid? proxyId = null);
|
||||
}
|
||||
|
||||
|
||||
public class ProxyForwardOperations : Orm<ProxyForward>, IProxyForwardOperations {
|
||||
private static readonly List<int> PORT_RANGES = Enumerable.Range(28000, 32000 - 28000).ToList();
|
||||
|
||||
public ProxyForwardOperations(ILogTracer log, IOnefuzzContext context)
|
||||
: base(log, context) {
|
||||
|
||||
@ -29,4 +35,68 @@ public class ProxyForwardOperations : Orm<ProxyForward>, IProxyForwardOperations
|
||||
|
||||
return QueryAsync(filter);
|
||||
}
|
||||
|
||||
public Forward ToForward(ProxyForward proxyForward) {
|
||||
return new Forward(proxyForward.Port, proxyForward.DstPort, proxyForward.DstIp);
|
||||
}
|
||||
|
||||
public async Task<OneFuzzResult<ProxyForward>> UpdateOrCreate(string region, Guid scalesetId, Guid machineId, int dstPort, int duration) {
|
||||
var privateIp = await _context.IpOperations.GetScalesetInstanceIp(scalesetId, machineId);
|
||||
|
||||
if (privateIp == null) {
|
||||
return OneFuzzResult<ProxyForward>.Error(ErrorCode.UNABLE_TO_PORT_FORWARD, new[] { "no private ip for node" });
|
||||
}
|
||||
|
||||
var entries =
|
||||
await this.SearchForward(scalesetId: scalesetId, region: region, machineId: machineId, dstPort: dstPort).ToListAsync();
|
||||
|
||||
var firstEntry = entries.FirstOrDefault();
|
||||
if (firstEntry != null) {
|
||||
var updated = firstEntry with { EndTime = DateTimeOffset.UtcNow + TimeSpan.FromHours(duration) };
|
||||
await this.Update(updated);
|
||||
return OneFuzzResult.Ok(updated);
|
||||
}
|
||||
|
||||
var exisiting = entries.Select(x => x.Port).ToHashSet();
|
||||
|
||||
foreach (var port in PORT_RANGES) {
|
||||
|
||||
if (exisiting.Contains(port)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var entry = new ProxyForward(
|
||||
Region: region,
|
||||
Port: port,
|
||||
ScalesetId: scalesetId,
|
||||
MachineId: machineId,
|
||||
DstIp: privateIp,
|
||||
DstPort: dstPort,
|
||||
EndTime: DateTimeOffset.UtcNow + TimeSpan.FromHours(duration),
|
||||
ProxyId: null
|
||||
);
|
||||
|
||||
var result = await Insert(entry);
|
||||
if (!result.IsOk) {
|
||||
_logTracer.Info($"port is already used {entry}");
|
||||
}
|
||||
|
||||
return OneFuzzResult.Ok(entry);
|
||||
}
|
||||
|
||||
return OneFuzzResult<ProxyForward>.Error(ErrorCode.UNABLE_TO_PORT_FORWARD, new[] { "all forward ports used" });
|
||||
|
||||
}
|
||||
|
||||
public async Task<HashSet<string>> RemoveForward(Guid scalesetId, Guid? machineId, int? dstPort, Guid? proxyId) {
|
||||
var entries = await SearchForward(scalesetId: scalesetId, machineId: machineId, proxyId: proxyId, dstPort: dstPort).ToListAsync();
|
||||
|
||||
var regions = new HashSet<string>();
|
||||
foreach (var entry in entries) {
|
||||
regions.Add(entry.Region);
|
||||
await Delete(entry);
|
||||
}
|
||||
|
||||
return regions;
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ public interface IProxyOperations : IStatefulOrm<Proxy, VmState> {
|
||||
Async.Task SaveProxyConfig(Proxy proxy);
|
||||
bool IsOutdated(Proxy proxy);
|
||||
Async.Task<Proxy?> GetOrCreate(string region);
|
||||
|
||||
}
|
||||
public class ProxyOperations : StatefulOrm<Proxy, VmState, ProxyOperations>, IProxyOperations {
|
||||
|
||||
@ -126,7 +127,7 @@ public class ProxyOperations : StatefulOrm<Proxy, VmState, ProxyOperations>, IPr
|
||||
if (entry.EndTime < DateTimeOffset.UtcNow) {
|
||||
await _context.ProxyForwardOperations.Delete(entry);
|
||||
} else {
|
||||
forwards.Add(new Forward(long.Parse(entry.Port), entry.DstPort, entry.DstIp));
|
||||
forwards.Add(new Forward(entry.Port, entry.DstPort, entry.DstIp));
|
||||
}
|
||||
}
|
||||
return forwards;
|
||||
|
@ -115,10 +115,6 @@ public sealed class Storage : IStorage, IDisposable {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(account.Data.PrimaryEndpoints.Blob)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!account.Data.Tags.ContainsKey(storageTypeTagKey)
|
||||
|| account.Data.Tags[storageTypeTagKey] != "corpus") {
|
||||
continue;
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using Azure;
|
||||
using Azure.Core;
|
||||
using Azure.ResourceManager.Network;
|
||||
|
||||
namespace Microsoft.OneFuzz.Service;
|
||||
@ -12,7 +13,7 @@ public interface ISubnet {
|
||||
|
||||
Async.Task<OneFuzzResultVoid> CreateVirtualNetwork(string resourceGroup, string name, string region, NetworkConfig networkConfig);
|
||||
|
||||
Async.Task<string?> GetSubnetId(string name, string subnetName);
|
||||
Async.Task<ResourceIdentifier?> GetSubnetId(string name, string subnetName);
|
||||
}
|
||||
|
||||
public class Subnet : ISubnet {
|
||||
@ -75,7 +76,7 @@ public class Subnet : ISubnet {
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<string?> GetSubnetId(string name, string subnetName) {
|
||||
public async Task<ResourceIdentifier?> GetSubnetId(string name, string subnetName) {
|
||||
var subnet = await this.GetSubnet(name, subnetName);
|
||||
if (subnet != null) {
|
||||
return subnet.Id;
|
||||
|
@ -115,6 +115,7 @@ public class VmssOperations : IVmssOperations {
|
||||
public async Async.Task<OneFuzzResult<VirtualMachineScaleSetVmResource>> GetInstanceVm(Guid name, Guid vmId) {
|
||||
_log.Info($"get instance ID for scaleset node: {name}:{vmId}");
|
||||
var scaleSet = GetVmssResource(name);
|
||||
|
||||
try {
|
||||
await foreach (var vm in scaleSet.GetVirtualMachineScaleSetVms().AsAsyncEnumerable()) {
|
||||
var response = await vm.GetAsync();
|
||||
|
@ -232,6 +232,8 @@ public class EntityConverter {
|
||||
return Guid.Parse(entity.GetString(ef.kind.ToString()));
|
||||
else if (ef.type == typeof(int))
|
||||
return int.Parse(entity.GetString(ef.kind.ToString()));
|
||||
else if (ef.type == typeof(long))
|
||||
return long.Parse(entity.GetString(ef.kind.ToString()));
|
||||
else if (ef.type.IsClass)
|
||||
return ef.type.GetConstructor(new[] { typeof(string) })!.Invoke(new[] { entity.GetString(ef.kind.ToString()) });
|
||||
else {
|
||||
|
@ -55,11 +55,11 @@
|
||||
},
|
||||
"Azure.ResourceManager": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.0.0, )",
|
||||
"resolved": "1.0.0",
|
||||
"contentHash": "UGaoiPcJ8a9Et030+F3zc2KhTssPAgPm7uXm4E9kyNI4jYYenUe6zj2J1bTimaTfcOZnn5scSjSYxKtZCzftcA==",
|
||||
"requested": "[1.2.1, )",
|
||||
"resolved": "1.2.1",
|
||||
"contentHash": "Ac7sSSLVbeJJGtw5JouMxZMHTKSokHu5NgCqlIpZM84SwpDpBK7j8sugUcDEryMPGO+BPeK42bTPJBEEs0DRQA==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.24.0",
|
||||
"Azure.Core": "1.25.0",
|
||||
"System.Text.Json": "4.7.2"
|
||||
}
|
||||
},
|
||||
@ -87,12 +87,12 @@
|
||||
},
|
||||
"Azure.ResourceManager.Network": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.0.0-beta.7, )",
|
||||
"resolved": "1.0.0-beta.7",
|
||||
"contentHash": "Ih8tb6OwxEEEEXATVzgX6oHJzVr9p4X6GfOfBnNAI3aIt9+G8blyQLltaCcJAGJ+dO1sBT/Nalgj/HinO+cBlw==",
|
||||
"requested": "[1.0.0, )",
|
||||
"resolved": "1.0.0",
|
||||
"contentHash": "BhN2ULPSgi7vPmllXycYbGUBF/r9fI4zklGbuCBWPCNm2hJrFRQOwUy1NYy2UmLBRHtcAK7zp376n+lylsyjAg==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.24.0",
|
||||
"Azure.ResourceManager": "1.0.0",
|
||||
"Azure.Core": "1.25.0",
|
||||
"Azure.ResourceManager": "1.2.0",
|
||||
"System.Text.Json": "4.7.2"
|
||||
}
|
||||
},
|
||||
@ -109,12 +109,12 @@
|
||||
},
|
||||
"Azure.ResourceManager.Storage": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.0.0-beta.8, )",
|
||||
"resolved": "1.0.0-beta.8",
|
||||
"contentHash": "tlVqStqG53lyGxr0dRq2KSkFdeC/+NQImWgsRXD9o5R4qBia4cx7zAGYBlnDeUxh1WldSZF5ZsBi2n5SAwxbxQ==",
|
||||
"requested": "[1.0.0-beta.11, )",
|
||||
"resolved": "1.0.0-beta.11",
|
||||
"contentHash": "w7hOgG4yUFTRrJ65FzHeIQH8wFPczSJG12SnFiA9HrcvoceD/8CflIk5aPHzqc6moB3A1od0lwGciluovsHMbg==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.24.0",
|
||||
"Azure.ResourceManager": "1.0.0",
|
||||
"Azure.Core": "1.25.0",
|
||||
"Azure.ResourceManager": "1.2.0",
|
||||
"System.Text.Json": "4.7.2"
|
||||
}
|
||||
},
|
||||
|
@ -94,10 +94,10 @@
|
||||
},
|
||||
"Azure.ResourceManager": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.0",
|
||||
"contentHash": "UGaoiPcJ8a9Et030+F3zc2KhTssPAgPm7uXm4E9kyNI4jYYenUe6zj2J1bTimaTfcOZnn5scSjSYxKtZCzftcA==",
|
||||
"resolved": "1.2.1",
|
||||
"contentHash": "Ac7sSSLVbeJJGtw5JouMxZMHTKSokHu5NgCqlIpZM84SwpDpBK7j8sugUcDEryMPGO+BPeK42bTPJBEEs0DRQA==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.24.0",
|
||||
"Azure.Core": "1.25.0",
|
||||
"System.Text.Json": "4.7.2"
|
||||
}
|
||||
},
|
||||
@ -123,11 +123,11 @@
|
||||
},
|
||||
"Azure.ResourceManager.Network": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.0-beta.7",
|
||||
"contentHash": "Ih8tb6OwxEEEEXATVzgX6oHJzVr9p4X6GfOfBnNAI3aIt9+G8blyQLltaCcJAGJ+dO1sBT/Nalgj/HinO+cBlw==",
|
||||
"resolved": "1.0.0",
|
||||
"contentHash": "BhN2ULPSgi7vPmllXycYbGUBF/r9fI4zklGbuCBWPCNm2hJrFRQOwUy1NYy2UmLBRHtcAK7zp376n+lylsyjAg==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.24.0",
|
||||
"Azure.ResourceManager": "1.0.0",
|
||||
"Azure.Core": "1.25.0",
|
||||
"Azure.ResourceManager": "1.2.0",
|
||||
"System.Text.Json": "4.7.2"
|
||||
}
|
||||
},
|
||||
@ -143,11 +143,11 @@
|
||||
},
|
||||
"Azure.ResourceManager.Storage": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.0-beta.8",
|
||||
"contentHash": "tlVqStqG53lyGxr0dRq2KSkFdeC/+NQImWgsRXD9o5R4qBia4cx7zAGYBlnDeUxh1WldSZF5ZsBi2n5SAwxbxQ==",
|
||||
"resolved": "1.0.0-beta.11",
|
||||
"contentHash": "w7hOgG4yUFTRrJ65FzHeIQH8wFPczSJG12SnFiA9HrcvoceD/8CflIk5aPHzqc6moB3A1od0lwGciluovsHMbg==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.24.0",
|
||||
"Azure.ResourceManager": "1.0.0",
|
||||
"Azure.Core": "1.25.0",
|
||||
"Azure.ResourceManager": "1.2.0",
|
||||
"System.Text.Json": "4.7.2"
|
||||
}
|
||||
},
|
||||
@ -2127,12 +2127,12 @@
|
||||
"Azure.Data.Tables": "12.5.0",
|
||||
"Azure.Identity": "1.6.0",
|
||||
"Azure.Messaging.EventGrid": "4.10.0",
|
||||
"Azure.ResourceManager": "1.0.0",
|
||||
"Azure.ResourceManager": "1.2.1",
|
||||
"Azure.ResourceManager.Compute": "1.0.0-beta.8",
|
||||
"Azure.ResourceManager.Monitor": "1.0.0-beta.2",
|
||||
"Azure.ResourceManager.Network": "1.0.0-beta.7",
|
||||
"Azure.ResourceManager.Network": "1.0.0",
|
||||
"Azure.ResourceManager.Resources": "1.0.0",
|
||||
"Azure.ResourceManager.Storage": "1.0.0-beta.8",
|
||||
"Azure.ResourceManager.Storage": "1.0.0-beta.11",
|
||||
"Azure.Security.KeyVault.Secrets": "4.3.0",
|
||||
"Azure.Storage.Blobs": "12.13.0",
|
||||
"Azure.Storage.Queues": "12.11.0",
|
||||
|
@ -112,7 +112,7 @@ namespace Tests {
|
||||
arg =>
|
||||
new ProxyForward(
|
||||
Region: arg.Item1.Item1,
|
||||
Port: arg.Item1.Item2.ToString(),
|
||||
Port: arg.Item1.Item2,
|
||||
ScalesetId: arg.Item1.Item3,
|
||||
MachineId: arg.Item1.Item4,
|
||||
ProxyId: arg.Item1.Item5,
|
||||
|
@ -113,10 +113,10 @@
|
||||
},
|
||||
"Azure.ResourceManager": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.0",
|
||||
"contentHash": "UGaoiPcJ8a9Et030+F3zc2KhTssPAgPm7uXm4E9kyNI4jYYenUe6zj2J1bTimaTfcOZnn5scSjSYxKtZCzftcA==",
|
||||
"resolved": "1.2.1",
|
||||
"contentHash": "Ac7sSSLVbeJJGtw5JouMxZMHTKSokHu5NgCqlIpZM84SwpDpBK7j8sugUcDEryMPGO+BPeK42bTPJBEEs0DRQA==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.24.0",
|
||||
"Azure.Core": "1.25.0",
|
||||
"System.Text.Json": "4.7.2"
|
||||
}
|
||||
},
|
||||
@ -142,11 +142,11 @@
|
||||
},
|
||||
"Azure.ResourceManager.Network": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.0-beta.7",
|
||||
"contentHash": "Ih8tb6OwxEEEEXATVzgX6oHJzVr9p4X6GfOfBnNAI3aIt9+G8blyQLltaCcJAGJ+dO1sBT/Nalgj/HinO+cBlw==",
|
||||
"resolved": "1.0.0",
|
||||
"contentHash": "BhN2ULPSgi7vPmllXycYbGUBF/r9fI4zklGbuCBWPCNm2hJrFRQOwUy1NYy2UmLBRHtcAK7zp376n+lylsyjAg==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.24.0",
|
||||
"Azure.ResourceManager": "1.0.0",
|
||||
"Azure.Core": "1.25.0",
|
||||
"Azure.ResourceManager": "1.2.0",
|
||||
"System.Text.Json": "4.7.2"
|
||||
}
|
||||
},
|
||||
@ -162,11 +162,11 @@
|
||||
},
|
||||
"Azure.ResourceManager.Storage": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.0-beta.8",
|
||||
"contentHash": "tlVqStqG53lyGxr0dRq2KSkFdeC/+NQImWgsRXD9o5R4qBia4cx7zAGYBlnDeUxh1WldSZF5ZsBi2n5SAwxbxQ==",
|
||||
"resolved": "1.0.0-beta.11",
|
||||
"contentHash": "w7hOgG4yUFTRrJ65FzHeIQH8wFPczSJG12SnFiA9HrcvoceD/8CflIk5aPHzqc6moB3A1od0lwGciluovsHMbg==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.24.0",
|
||||
"Azure.ResourceManager": "1.0.0",
|
||||
"Azure.Core": "1.25.0",
|
||||
"Azure.ResourceManager": "1.2.0",
|
||||
"System.Text.Json": "4.7.2"
|
||||
}
|
||||
},
|
||||
@ -2254,12 +2254,12 @@
|
||||
"Azure.Data.Tables": "12.5.0",
|
||||
"Azure.Identity": "1.6.0",
|
||||
"Azure.Messaging.EventGrid": "4.10.0",
|
||||
"Azure.ResourceManager": "1.0.0",
|
||||
"Azure.ResourceManager": "1.2.1",
|
||||
"Azure.ResourceManager.Compute": "1.0.0-beta.8",
|
||||
"Azure.ResourceManager.Monitor": "1.0.0-beta.2",
|
||||
"Azure.ResourceManager.Network": "1.0.0-beta.7",
|
||||
"Azure.ResourceManager.Network": "1.0.0",
|
||||
"Azure.ResourceManager.Resources": "1.0.0",
|
||||
"Azure.ResourceManager.Storage": "1.0.0-beta.8",
|
||||
"Azure.ResourceManager.Storage": "1.0.0-beta.11",
|
||||
"Azure.Security.KeyVault.Secrets": "4.3.0",
|
||||
"Azure.Storage.Blobs": "12.13.0",
|
||||
"Azure.Storage.Queues": "12.11.0",
|
||||
|
Reference in New Issue
Block a user