mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-15 19:38:11 +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.Core" Version="1.25.0" />
|
||||||
<PackageReference Include="Azure.Identity" Version="1.6.0" />
|
<PackageReference Include="Azure.Identity" Version="1.6.0" />
|
||||||
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.10.0" />
|
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.10.0" />
|
||||||
<PackageReference Include="Azure.ResourceManager" Version="1.0.0" />
|
<PackageReference Include="Azure.ResourceManager" Version="1.2.1" />
|
||||||
<PackageReference Include="Azure.ResourceManager.Network" Version="1.0.0-beta.7" />
|
<PackageReference Include="Azure.ResourceManager.Network" Version="1.0.0" />
|
||||||
<PackageReference Include="Azure.ResourceManager.Resources" 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.Queues" Version="12.11.0" />
|
||||||
<PackageReference Include="Azure.Storage.Blobs" Version="12.13.0" />
|
<PackageReference Include="Azure.Storage.Blobs" Version="12.13.0" />
|
||||||
<PackageReference Include="Microsoft.Graph" Version="4.24.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
|
// 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
|
// and have no NIC associated with it then delete the NSG
|
||||||
await foreach (var nsg in nsgOpertions.ListNsgs()) {
|
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) {
|
if (nsg.Data.NetworkInterfaces.Count == 0 && nsg.Data.Subnets.Count == 0) {
|
||||||
await nsgOpertions.StartDeleteNsg(nsg.Data.Name);
|
await nsgOpertions.StartDeleteNsg(nsg.Data.Name);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ public record ProxyHeartbeat
|
|||||||
(
|
(
|
||||||
Region Region,
|
Region Region,
|
||||||
Guid ProxyId,
|
Guid ProxyId,
|
||||||
List<ProxyForward> Forwards,
|
List<Forward> Forwards,
|
||||||
DateTimeOffset TimeStamp
|
DateTimeOffset TimeStamp
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ public record Forward
|
|||||||
public record ProxyForward
|
public record ProxyForward
|
||||||
(
|
(
|
||||||
[PartitionKey] Region Region,
|
[PartitionKey] Region Region,
|
||||||
[RowKey] string Port,
|
[RowKey] long Port,
|
||||||
Guid ScalesetId,
|
Guid ScalesetId,
|
||||||
Guid MachineId,
|
Guid MachineId,
|
||||||
Guid? ProxyId,
|
Guid? ProxyId,
|
||||||
|
@ -139,3 +139,25 @@ public record JobSearch(
|
|||||||
);
|
);
|
||||||
|
|
||||||
public record NodeAddSshKeyPost(Guid MachineId, string PublicKey);
|
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);
|
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 path = GetScalesetIdentityResourcePath();
|
||||||
var uid = ArmClient.GetGenericResource(new ResourceIdentifier(path));
|
var uid = ArmClient.GetGenericResource(new ResourceIdentifier(path));
|
||||||
|
|
||||||
|
|
||||||
var resource = await uid.GetAsync();
|
var resource = await uid.GetAsync();
|
||||||
var principalId = resource.Value.Data.Properties.ToObjectFromJson<ScaleSetIdentity>().principalId;
|
var principalId = resource.Value.Data.Properties.ToObjectFromJson<ScaleSetIdentity>().principalId;
|
||||||
return new Guid(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;
|
||||||
|
using Azure.Core;
|
||||||
using Azure.ResourceManager.Network;
|
using Azure.ResourceManager.Network;
|
||||||
using Azure.ResourceManager.Network.Models;
|
using Azure.ResourceManager.Network.Models;
|
||||||
|
using Faithlife.Utility;
|
||||||
|
|
||||||
namespace Microsoft.OneFuzz.Service;
|
namespace Microsoft.OneFuzz.Service;
|
||||||
|
|
||||||
@ -18,18 +22,22 @@ public interface IIpOperations {
|
|||||||
|
|
||||||
public Async.Task DeleteIp(string resourceGroup, string name);
|
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 Async.Task CreateIp(string resourceGroup, string name, string region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class IpOperations : IIpOperations {
|
public class IpOperations : IIpOperations {
|
||||||
private ILogTracer _logTracer;
|
private ILogTracer _logTracer;
|
||||||
|
|
||||||
|
|
||||||
private IOnefuzzContext _context;
|
private IOnefuzzContext _context;
|
||||||
|
private readonly NetworkInterfaceQuery _networkInterfaceQuery;
|
||||||
|
|
||||||
public IpOperations(ILogTracer log, IOnefuzzContext context) {
|
public IpOperations(ILogTracer log, IOnefuzzContext context) {
|
||||||
_logTracer = log;
|
_logTracer = log;
|
||||||
_context = context;
|
_context = context;
|
||||||
|
_networkInterfaceQuery = new NetworkInterfaceQuery(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Async.Task<NetworkInterfaceResource?> GetPublicNic(string resourceGroup, string name) {
|
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) {
|
public async Async.Task<PublicIPAddressResource?> GetIp(string resourceGroup, string name) {
|
||||||
_logTracer.Info($"getting ip {resourceGroup}:{name}");
|
_logTracer.Info($"getting ip {resourceGroup}:{name}");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(name);
|
return await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(name);
|
||||||
} catch (RequestFailedException) {
|
} catch (RequestFailedException) {
|
||||||
@ -61,6 +68,16 @@ public class IpOperations : IIpOperations {
|
|||||||
await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(name).Result.Value.DeleteAsync(WaitUntil.Started);
|
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) {
|
public async Task<string?> GetPublicIp(string resourceId) {
|
||||||
// TODO: Parts of this function seem redundant, but I'm mirroring
|
// TODO: Parts of this function seem redundant, but I'm mirroring
|
||||||
// the python code exactly. We should revisit this.
|
// the python code exactly. We should revisit this.
|
||||||
@ -75,7 +92,8 @@ public class IpOperations : IIpOperations {
|
|||||||
if (publicIp == null) {
|
if (publicIp == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
resource = _context.Creds.ParseResourceId(publicIp.Id);
|
|
||||||
|
resource = _context.Creds.ParseResourceId(publicIp.Id!);
|
||||||
try {
|
try {
|
||||||
resource = await _context.Creds.GetData(resource);
|
resource = await _context.Creds.GetData(resource);
|
||||||
var publicIpResource = await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(
|
var publicIpResource = await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(
|
||||||
@ -93,7 +111,7 @@ public class IpOperations : IIpOperations {
|
|||||||
var network = await Network.Create(region, _context);
|
var network = await Network.Create(region, _context);
|
||||||
var subnetId = await network.GetId();
|
var subnetId = await network.GetId();
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(subnetId)) {
|
if (subnetId is not null) {
|
||||||
await network.Create();
|
await network.Create();
|
||||||
return OneFuzzResultVoid.Ok;
|
return OneFuzzResultVoid.Ok;
|
||||||
}
|
}
|
||||||
@ -157,7 +175,7 @@ public class IpOperations : IIpOperations {
|
|||||||
public async Async.Task CreateIp(string resourceGroup, string name, string region) {
|
public async Async.Task CreateIp(string resourceGroup, string name, string region) {
|
||||||
var ipParams = new PublicIPAddressData() {
|
var ipParams = new PublicIPAddressData() {
|
||||||
Location = region,
|
Location = region,
|
||||||
PublicIPAllocationMethod = IPAllocationMethod.Dynamic
|
PublicIPAllocationMethod = NetworkIPAllocationMethod.Dynamic
|
||||||
};
|
};
|
||||||
|
|
||||||
var onefuzzOwner = _context.ServiceConfiguration.OneFuzzOwner;
|
var onefuzzOwner = _context.ServiceConfiguration.OneFuzzOwner;
|
||||||
@ -172,4 +190,52 @@ public class IpOperations : IIpOperations {
|
|||||||
);
|
);
|
||||||
return;
|
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;
|
namespace Microsoft.OneFuzz.Service;
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ public class Network {
|
|||||||
return _context.Subnet.GetSubnet(_name, _name);
|
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);
|
return await _context.Subnet.GetSubnetId(this._name, this._name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +62,8 @@ public class Network {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Async.Task<bool> Exists() {
|
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() {
|
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;
|
namespace Microsoft.OneFuzz.Service;
|
||||||
|
|
||||||
|
|
||||||
public interface IProxyForwardOperations : IOrm<ProxyForward> {
|
public interface IProxyForwardOperations : IOrm<ProxyForward> {
|
||||||
IAsyncEnumerable<ProxyForward> SearchForward(Guid? scalesetId = null, string? region = null, Guid? machineId = null, Guid? proxyId = null, int? dstPort = null);
|
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 {
|
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)
|
public ProxyForwardOperations(ILogTracer log, IOnefuzzContext context)
|
||||||
: base(log, context) {
|
: base(log, context) {
|
||||||
|
|
||||||
@ -29,4 +35,68 @@ public class ProxyForwardOperations : Orm<ProxyForward>, IProxyForwardOperations
|
|||||||
|
|
||||||
return QueryAsync(filter);
|
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);
|
Async.Task SaveProxyConfig(Proxy proxy);
|
||||||
bool IsOutdated(Proxy proxy);
|
bool IsOutdated(Proxy proxy);
|
||||||
Async.Task<Proxy?> GetOrCreate(string region);
|
Async.Task<Proxy?> GetOrCreate(string region);
|
||||||
|
|
||||||
}
|
}
|
||||||
public class ProxyOperations : StatefulOrm<Proxy, VmState, ProxyOperations>, IProxyOperations {
|
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) {
|
if (entry.EndTime < DateTimeOffset.UtcNow) {
|
||||||
await _context.ProxyForwardOperations.Delete(entry);
|
await _context.ProxyForwardOperations.Delete(entry);
|
||||||
} else {
|
} 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;
|
return forwards;
|
||||||
|
@ -115,10 +115,6 @@ public sealed class Storage : IStorage, IDisposable {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(account.Data.PrimaryEndpoints.Blob)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!account.Data.Tags.ContainsKey(storageTypeTagKey)
|
if (!account.Data.Tags.ContainsKey(storageTypeTagKey)
|
||||||
|| account.Data.Tags[storageTypeTagKey] != "corpus") {
|
|| account.Data.Tags[storageTypeTagKey] != "corpus") {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Azure;
|
using Azure;
|
||||||
|
using Azure.Core;
|
||||||
using Azure.ResourceManager.Network;
|
using Azure.ResourceManager.Network;
|
||||||
|
|
||||||
namespace Microsoft.OneFuzz.Service;
|
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<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 {
|
public class Subnet : ISubnet {
|
||||||
@ -75,7 +76,7 @@ public class Subnet : ISubnet {
|
|||||||
return null;
|
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);
|
var subnet = await this.GetSubnet(name, subnetName);
|
||||||
if (subnet != null) {
|
if (subnet != null) {
|
||||||
return subnet.Id;
|
return subnet.Id;
|
||||||
|
@ -115,6 +115,7 @@ public class VmssOperations : IVmssOperations {
|
|||||||
public async Async.Task<OneFuzzResult<VirtualMachineScaleSetVmResource>> GetInstanceVm(Guid name, Guid vmId) {
|
public async Async.Task<OneFuzzResult<VirtualMachineScaleSetVmResource>> GetInstanceVm(Guid name, Guid vmId) {
|
||||||
_log.Info($"get instance ID for scaleset node: {name}:{vmId}");
|
_log.Info($"get instance ID for scaleset node: {name}:{vmId}");
|
||||||
var scaleSet = GetVmssResource(name);
|
var scaleSet = GetVmssResource(name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await foreach (var vm in scaleSet.GetVirtualMachineScaleSetVms().AsAsyncEnumerable()) {
|
await foreach (var vm in scaleSet.GetVirtualMachineScaleSetVms().AsAsyncEnumerable()) {
|
||||||
var response = await vm.GetAsync();
|
var response = await vm.GetAsync();
|
||||||
|
@ -232,6 +232,8 @@ public class EntityConverter {
|
|||||||
return Guid.Parse(entity.GetString(ef.kind.ToString()));
|
return Guid.Parse(entity.GetString(ef.kind.ToString()));
|
||||||
else if (ef.type == typeof(int))
|
else if (ef.type == typeof(int))
|
||||||
return int.Parse(entity.GetString(ef.kind.ToString()));
|
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)
|
else if (ef.type.IsClass)
|
||||||
return ef.type.GetConstructor(new[] { typeof(string) })!.Invoke(new[] { entity.GetString(ef.kind.ToString()) });
|
return ef.type.GetConstructor(new[] { typeof(string) })!.Invoke(new[] { entity.GetString(ef.kind.ToString()) });
|
||||||
else {
|
else {
|
||||||
|
@ -55,11 +55,11 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager": {
|
"Azure.ResourceManager": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.0.0, )",
|
"requested": "[1.2.1, )",
|
||||||
"resolved": "1.0.0",
|
"resolved": "1.2.1",
|
||||||
"contentHash": "UGaoiPcJ8a9Et030+F3zc2KhTssPAgPm7uXm4E9kyNI4jYYenUe6zj2J1bTimaTfcOZnn5scSjSYxKtZCzftcA==",
|
"contentHash": "Ac7sSSLVbeJJGtw5JouMxZMHTKSokHu5NgCqlIpZM84SwpDpBK7j8sugUcDEryMPGO+BPeK42bTPJBEEs0DRQA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.24.0",
|
"Azure.Core": "1.25.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -87,12 +87,12 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager.Network": {
|
"Azure.ResourceManager.Network": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.0.0-beta.7, )",
|
"requested": "[1.0.0, )",
|
||||||
"resolved": "1.0.0-beta.7",
|
"resolved": "1.0.0",
|
||||||
"contentHash": "Ih8tb6OwxEEEEXATVzgX6oHJzVr9p4X6GfOfBnNAI3aIt9+G8blyQLltaCcJAGJ+dO1sBT/Nalgj/HinO+cBlw==",
|
"contentHash": "BhN2ULPSgi7vPmllXycYbGUBF/r9fI4zklGbuCBWPCNm2hJrFRQOwUy1NYy2UmLBRHtcAK7zp376n+lylsyjAg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.24.0",
|
"Azure.Core": "1.25.0",
|
||||||
"Azure.ResourceManager": "1.0.0",
|
"Azure.ResourceManager": "1.2.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -109,12 +109,12 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager.Storage": {
|
"Azure.ResourceManager.Storage": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.0.0-beta.8, )",
|
"requested": "[1.0.0-beta.11, )",
|
||||||
"resolved": "1.0.0-beta.8",
|
"resolved": "1.0.0-beta.11",
|
||||||
"contentHash": "tlVqStqG53lyGxr0dRq2KSkFdeC/+NQImWgsRXD9o5R4qBia4cx7zAGYBlnDeUxh1WldSZF5ZsBi2n5SAwxbxQ==",
|
"contentHash": "w7hOgG4yUFTRrJ65FzHeIQH8wFPczSJG12SnFiA9HrcvoceD/8CflIk5aPHzqc6moB3A1od0lwGciluovsHMbg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.24.0",
|
"Azure.Core": "1.25.0",
|
||||||
"Azure.ResourceManager": "1.0.0",
|
"Azure.ResourceManager": "1.2.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -94,10 +94,10 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager": {
|
"Azure.ResourceManager": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.0.0",
|
"resolved": "1.2.1",
|
||||||
"contentHash": "UGaoiPcJ8a9Et030+F3zc2KhTssPAgPm7uXm4E9kyNI4jYYenUe6zj2J1bTimaTfcOZnn5scSjSYxKtZCzftcA==",
|
"contentHash": "Ac7sSSLVbeJJGtw5JouMxZMHTKSokHu5NgCqlIpZM84SwpDpBK7j8sugUcDEryMPGO+BPeK42bTPJBEEs0DRQA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.24.0",
|
"Azure.Core": "1.25.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -123,11 +123,11 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager.Network": {
|
"Azure.ResourceManager.Network": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.0.0-beta.7",
|
"resolved": "1.0.0",
|
||||||
"contentHash": "Ih8tb6OwxEEEEXATVzgX6oHJzVr9p4X6GfOfBnNAI3aIt9+G8blyQLltaCcJAGJ+dO1sBT/Nalgj/HinO+cBlw==",
|
"contentHash": "BhN2ULPSgi7vPmllXycYbGUBF/r9fI4zklGbuCBWPCNm2hJrFRQOwUy1NYy2UmLBRHtcAK7zp376n+lylsyjAg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.24.0",
|
"Azure.Core": "1.25.0",
|
||||||
"Azure.ResourceManager": "1.0.0",
|
"Azure.ResourceManager": "1.2.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -143,11 +143,11 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager.Storage": {
|
"Azure.ResourceManager.Storage": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.0.0-beta.8",
|
"resolved": "1.0.0-beta.11",
|
||||||
"contentHash": "tlVqStqG53lyGxr0dRq2KSkFdeC/+NQImWgsRXD9o5R4qBia4cx7zAGYBlnDeUxh1WldSZF5ZsBi2n5SAwxbxQ==",
|
"contentHash": "w7hOgG4yUFTRrJ65FzHeIQH8wFPczSJG12SnFiA9HrcvoceD/8CflIk5aPHzqc6moB3A1od0lwGciluovsHMbg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.24.0",
|
"Azure.Core": "1.25.0",
|
||||||
"Azure.ResourceManager": "1.0.0",
|
"Azure.ResourceManager": "1.2.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2127,12 +2127,12 @@
|
|||||||
"Azure.Data.Tables": "12.5.0",
|
"Azure.Data.Tables": "12.5.0",
|
||||||
"Azure.Identity": "1.6.0",
|
"Azure.Identity": "1.6.0",
|
||||||
"Azure.Messaging.EventGrid": "4.10.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.Compute": "1.0.0-beta.8",
|
||||||
"Azure.ResourceManager.Monitor": "1.0.0-beta.2",
|
"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.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.Security.KeyVault.Secrets": "4.3.0",
|
||||||
"Azure.Storage.Blobs": "12.13.0",
|
"Azure.Storage.Blobs": "12.13.0",
|
||||||
"Azure.Storage.Queues": "12.11.0",
|
"Azure.Storage.Queues": "12.11.0",
|
||||||
|
@ -112,7 +112,7 @@ namespace Tests {
|
|||||||
arg =>
|
arg =>
|
||||||
new ProxyForward(
|
new ProxyForward(
|
||||||
Region: arg.Item1.Item1,
|
Region: arg.Item1.Item1,
|
||||||
Port: arg.Item1.Item2.ToString(),
|
Port: arg.Item1.Item2,
|
||||||
ScalesetId: arg.Item1.Item3,
|
ScalesetId: arg.Item1.Item3,
|
||||||
MachineId: arg.Item1.Item4,
|
MachineId: arg.Item1.Item4,
|
||||||
ProxyId: arg.Item1.Item5,
|
ProxyId: arg.Item1.Item5,
|
||||||
|
@ -113,10 +113,10 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager": {
|
"Azure.ResourceManager": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.0.0",
|
"resolved": "1.2.1",
|
||||||
"contentHash": "UGaoiPcJ8a9Et030+F3zc2KhTssPAgPm7uXm4E9kyNI4jYYenUe6zj2J1bTimaTfcOZnn5scSjSYxKtZCzftcA==",
|
"contentHash": "Ac7sSSLVbeJJGtw5JouMxZMHTKSokHu5NgCqlIpZM84SwpDpBK7j8sugUcDEryMPGO+BPeK42bTPJBEEs0DRQA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.24.0",
|
"Azure.Core": "1.25.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -142,11 +142,11 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager.Network": {
|
"Azure.ResourceManager.Network": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.0.0-beta.7",
|
"resolved": "1.0.0",
|
||||||
"contentHash": "Ih8tb6OwxEEEEXATVzgX6oHJzVr9p4X6GfOfBnNAI3aIt9+G8blyQLltaCcJAGJ+dO1sBT/Nalgj/HinO+cBlw==",
|
"contentHash": "BhN2ULPSgi7vPmllXycYbGUBF/r9fI4zklGbuCBWPCNm2hJrFRQOwUy1NYy2UmLBRHtcAK7zp376n+lylsyjAg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.24.0",
|
"Azure.Core": "1.25.0",
|
||||||
"Azure.ResourceManager": "1.0.0",
|
"Azure.ResourceManager": "1.2.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -162,11 +162,11 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager.Storage": {
|
"Azure.ResourceManager.Storage": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.0.0-beta.8",
|
"resolved": "1.0.0-beta.11",
|
||||||
"contentHash": "tlVqStqG53lyGxr0dRq2KSkFdeC/+NQImWgsRXD9o5R4qBia4cx7zAGYBlnDeUxh1WldSZF5ZsBi2n5SAwxbxQ==",
|
"contentHash": "w7hOgG4yUFTRrJ65FzHeIQH8wFPczSJG12SnFiA9HrcvoceD/8CflIk5aPHzqc6moB3A1od0lwGciluovsHMbg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.24.0",
|
"Azure.Core": "1.25.0",
|
||||||
"Azure.ResourceManager": "1.0.0",
|
"Azure.ResourceManager": "1.2.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2254,12 +2254,12 @@
|
|||||||
"Azure.Data.Tables": "12.5.0",
|
"Azure.Data.Tables": "12.5.0",
|
||||||
"Azure.Identity": "1.6.0",
|
"Azure.Identity": "1.6.0",
|
||||||
"Azure.Messaging.EventGrid": "4.10.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.Compute": "1.0.0-beta.8",
|
||||||
"Azure.ResourceManager.Monitor": "1.0.0-beta.2",
|
"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.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.Security.KeyVault.Secrets": "4.3.0",
|
||||||
"Azure.Storage.Blobs": "12.13.0",
|
"Azure.Storage.Blobs": "12.13.0",
|
||||||
"Azure.Storage.Queues": "12.11.0",
|
"Azure.Storage.Queues": "12.11.0",
|
||||||
|
Reference in New Issue
Block a user