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

Commit

Permalink
Add networking related operations for C# refactor (#2216)
Browse files Browse the repository at this point in the history
* Add some networking related operations

* Add nsg operations

* Fix tests

* Use creds from context

* Use creds from context

* PR comment
  • Loading branch information
tevoinea authored Aug 4, 2022
1 parent 8a8fe9a commit d0f0fc5
Show file tree
Hide file tree
Showing 5 changed files with 430 additions and 35 deletions.
21 changes: 14 additions & 7 deletions src/ApiService/ApiService/TestHooks/IpOperationsTestHooks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ public async Task<HttpResponseData> GetPublicNic([HttpTrigger(AuthorizationLevel
var name = query["name"];

var nic = await _ipOps.GetPublicNic(rg, name);

var resp = req.CreateResponse(HttpStatusCode.OK);
await resp.WriteStringAsync(nic.Get().Value.Data.Name);
return resp;
if (nic != null) {
var resp = req.CreateResponse(HttpStatusCode.OK);
await resp.WriteStringAsync((await nic.GetAsync()).Value.Data.Name);
return resp;
} else {
return req.CreateResponse(HttpStatusCode.NotFound);
}
}

[Function("GetIpTestHook")]
Expand All @@ -45,9 +48,13 @@ public async Task<HttpResponseData> GetIp([HttpTrigger(AuthorizationLevel.Anonym

var ip = await _ipOps.GetIp(rg, name);

var resp = req.CreateResponse(HttpStatusCode.OK);
await resp.WriteStringAsync(ip.Get().Value.Data.Name);
return resp;
if (ip != null) {
var resp = req.CreateResponse(HttpStatusCode.OK);
await resp.WriteStringAsync((await ip.GetAsync()).Value.Data.Name);
return resp;
} else {
return req.CreateResponse(HttpStatusCode.NotFound);
}
}


Expand Down
154 changes: 142 additions & 12 deletions src/ApiService/ApiService/onefuzzlib/IpOperations.cs
Original file line number Diff line number Diff line change
@@ -1,45 +1,175 @@
using Azure;
using System.Threading.Tasks;
using Azure;
using Azure.ResourceManager.Network;
using Azure.ResourceManager.Network.Models;

namespace Microsoft.OneFuzz.Service;

public interface IIpOperations {
public Async.Task<NetworkInterfaceResource> GetPublicNic(string resourceGroup, string name);
public Async.Task<NetworkInterfaceResource?> GetPublicNic(string resourceGroup, string name);

public Async.Task<PublicIPAddressResource> GetIp(string resourceGroup, string name);
public Async.Task<OneFuzzResultVoid> CreatePublicNic(string resourceGroup, string name, string region, Nsg? nsg);

public Async.Task<string?> GetPublicIp(string resourceId);

public Async.Task<PublicIPAddressResource?> GetIp(string resourceGroup, string name);

public Async.Task DeleteNic(string resourceGroup, string name);

public Async.Task DeleteIp(string resourceGroup, string name);

public Async.Task CreateIp(string resourceGroup, string name, string region);
}

public class IpOperations : IIpOperations {
private ILogTracer _logTracer;

private ICreds _creds;

public IpOperations(ILogTracer log, ICreds creds) {
private IOnefuzzContext _context;

public IpOperations(ILogTracer log, IOnefuzzContext context) {
_logTracer = log;
_creds = creds;
_context = context;
}

public async Async.Task<NetworkInterfaceResource> GetPublicNic(string resourceGroup, string name) {
public async Async.Task<NetworkInterfaceResource?> GetPublicNic(string resourceGroup, string name) {
_logTracer.Info($"getting nic: {resourceGroup} {name}");
return await _creds.GetResourceGroupResource().GetNetworkInterfaceAsync(name);
try {
return await _context.Creds.GetResourceGroupResource().GetNetworkInterfaceAsync(name);
} catch (RequestFailedException) {
return null;
}
}

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}");
return await _creds.GetResourceGroupResource().GetPublicIPAddressAsync(name);

try {
return await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(name);
} catch (RequestFailedException) {
return null;
}
}

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);
await _context.Creds.GetResourceGroupResource().GetNetworkInterfaceAsync(name).Result.Value.DeleteAsync(WaitUntil.Started);
}

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);
await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(name).Result.Value.DeleteAsync(WaitUntil.Started);
}

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.
_logTracer.Info($"getting ip for {resourceId}");
var resource = await (_context.Creds.GetData(_context.Creds.ParseResourceId(resourceId)));
var networkInterfaces = await _context.Creds.GetResourceGroupResource().GetNetworkInterfaceAsync(
resource.Data.Name
);
var publicIpConfigResource = (await networkInterfaces.Value.GetNetworkInterfaceIPConfigurations().FirstAsync());
publicIpConfigResource = await publicIpConfigResource.GetAsync();
var publicIp = publicIpConfigResource.Data.PublicIPAddress;
if (publicIp == null) {
return null;
}
resource = _context.Creds.ParseResourceId(publicIp.Id);
try {
resource = await _context.Creds.GetData(resource);
var publicIpResource = await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(
resource.Data.Name
);
return publicIpResource.Value.Data.IPAddress;
} catch (RequestFailedException) {
return null;
}
}

public async Task<OneFuzzResultVoid> CreatePublicNic(string resourceGroup, string name, string region, Nsg? nsg) {
_logTracer.Info($"creating nic for {resourceGroup}:{name} in {region}");

var network = await Network.Create(region, _context);
var subnetId = await network.GetId();

if (string.IsNullOrEmpty(subnetId)) {
await network.Create();
return OneFuzzResultVoid.Ok;
}

if (nsg != null) {
var subnet = await network.GetSubnet();
if (subnet != null && subnet.Data.NetworkSecurityGroup == null) {
var vnet = await network.GetVnet();
var result = await _context.NsgOperations.AssociateSubnet(nsg.Name, vnet!, subnet);
if (!result.IsOk) {
return OneFuzzResultVoid.Error(result.ErrorV);
}
return OneFuzzResultVoid.Ok;
}
}

var ip = await GetIp(resourceGroup, name);
if (ip == null) {
await CreateIp(resourceGroup, name, region);
return OneFuzzResultVoid.Ok;
}

var networkInterface = new NetworkInterfaceData {
Location = region,
};

networkInterface.IPConfigurations.Add(new NetworkInterfaceIPConfigurationData {
Name = "myIPConfig",
PublicIPAddress = ip?.Data,
Subnet = new SubnetData {
Id = subnetId
}
}
);

var onefuzzOwner = _context.ServiceConfiguration.OneFuzzOwner;
if (!string.IsNullOrEmpty(onefuzzOwner)) {
if (!networkInterface.Tags.TryAdd("OWNER", onefuzzOwner)) {
_logTracer.Warning($"Failed to add tag 'OWNER':{onefuzzOwner} to nic {resourceGroup}:{name}");
}
}

try {
await _context.Creds.GetResourceGroupResource().GetNetworkInterfaces().CreateOrUpdateAsync(
WaitUntil.Started,
name,
networkInterface
);
} catch (RequestFailedException ex) {
if (!ex.ToString().Contains("RetryableError")) {
return OneFuzzResultVoid.Error(
ErrorCode.VM_CREATE_FAILED,
$"unable to create nic: {ex}"
);
}
}

return OneFuzzResultVoid.Ok;
}

public async Async.Task CreateIp(string resourceGroup, string name, string region) {
var ipParams = new PublicIPAddressData() {
Location = region,
PublicIPAllocationMethod = IPAllocationMethod.Dynamic
};

var onefuzzOwner = _context.ServiceConfiguration.OneFuzzOwner;
if (!string.IsNullOrEmpty(onefuzzOwner)) {
if (!ipParams.Tags.TryAdd("OWNER", onefuzzOwner)) {
_logTracer.Warning($"Failed to add tag 'OWNER':{onefuzzOwner} to ip {resourceGroup}:{name}");
}
}

await _context.Creds.GetResourceGroupResource().GetPublicIPAddresses().CreateOrUpdateAsync(
WaitUntil.Started, name, ipParams
);
return;
}
}
23 changes: 21 additions & 2 deletions src/ApiService/ApiService/onefuzzlib/Network.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ public class Network {
private readonly string _region;
private readonly IOnefuzzContext _context;

private readonly NetworkConfig _networkConfig;

// This was generated randomly and should be preserved moving forwards
static Guid NETWORK_GUID_NAMESPACE = Guid.Parse("372977ad-b533-416a-b1b4-f770898e0b11");

public Network(string region, string group, string name, IOnefuzzContext context) {
public Network(string region, string group, string name, IOnefuzzContext context, NetworkConfig networkConfig) {
_region = region;
_group = group;
_name = name;
_context = context;
_networkConfig = networkConfig;
}

public static async Async.Task<Network> Create(string region, IOnefuzzContext context) {
Expand All @@ -38,13 +41,29 @@ public static async Async.Task<Network> Create(string region, IOnefuzzContext co
}


return new Network(region, group, name, context);
return new Network(region, group, name, context, networkConfig);
}

public Async.Task<SubnetResource?> GetSubnet() {
return _context.Subnet.GetSubnet(_name, _name);
}

public async Async.Task<string?> GetId() {
return await _context.Subnet.GetSubnetId(this._name, this._name);
}

public async Async.Task<OneFuzzResultVoid> Create() {
if (!await Exists()) {
return await _context.Subnet.CreateVirtualNetwork(_group, _name, _region, _networkConfig);
}

return OneFuzzResultVoid.Ok;
}

public async Async.Task<bool> Exists() {
return !string.IsNullOrEmpty(await GetId());
}

internal Async.Task<VirtualNetworkResource?> GetVnet() {
return _context.Subnet.GetVnet(_name);
}
Expand Down
Loading

0 comments on commit d0f0fc5

Please sign in to comment.