167 lines
7.1 KiB
C#
Raw Normal View History

2024-06-19 17:25:18 -07:00
using System.Text;
2024-06-14 11:53:19 -07:00
using Azure;
using Azure.Core;
using Azure.ResourceManager;
using Azure.ResourceManager.ContainerInstance;
using Azure.ResourceManager.ContainerInstance.Models;
using Azure.ResourceManager.Resources;
using Azure.Storage.Files.Shares;
using DevTeam.Options;
2024-06-14 11:53:19 -07:00
using Microsoft.Extensions.Options;
namespace DevTeam.Backend;
2024-06-14 11:53:19 -07:00
public class AzureService : IManageAzure
{
private readonly AzureOptions _azSettings;
private readonly ILogger<AzureService> _logger;
private readonly ArmClient _client;
public AzureService(IOptions<AzureOptions> azOptions, ILogger<AzureService> logger, ArmClient client)
{
2024-06-19 17:25:18 -07:00
ArgumentNullException.ThrowIfNull(azOptions);
ArgumentNullException.ThrowIfNull(logger);
ArgumentNullException.ThrowIfNull(client);
2024-06-14 11:53:19 -07:00
_azSettings = azOptions.Value;
_logger = logger;
_client = client;
}
public async Task DeleteSandbox(string sandboxId)
{
try
{
var resourceGroupResourceId = ResourceGroupResource.CreateResourceIdentifier(_azSettings.SubscriptionId, _azSettings.ContainerInstancesResourceGroup);
var resourceGroupResource = _client.GetResourceGroupResource(resourceGroupResourceId);
var collection = resourceGroupResource.GetContainerGroups();
var containerGroup = await collection.GetAsync(sandboxId);
await containerGroup.Value.DeleteAsync(WaitUntil.Started);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting sandbox");
throw;
}
}
public async Task<bool> IsSandboxCompleted(string sandboxId)
{
try
{
var resourceGroupResourceId = ResourceGroupResource.CreateResourceIdentifier(_azSettings.SubscriptionId, _azSettings.ContainerInstancesResourceGroup);
var resourceGroupResource = _client.GetResourceGroupResource(resourceGroupResourceId);
var collection = resourceGroupResource.GetContainerGroups();
var containerGroup = await collection.GetAsync(sandboxId);
return containerGroup.Value.Data.ProvisioningState == "Succeeded"
&& containerGroup.Value.Data.Containers.First().InstanceView.CurrentState.State == "Terminated";
}
catch (Exception ex)
{
_logger.LogError(ex, "Error checking sandbox status");
2024-06-19 17:25:18 -07:00
throw;
2024-06-14 11:53:19 -07:00
}
}
public async Task RunInSandbox(string org, string repo, long parentIssueNumber, long issueNumber)
{
try
{
2024-06-19 17:25:18 -07:00
var runId = $"sk-sandbox-{org}-{repo}-{parentIssueNumber}-{issueNumber}".ToUpperInvariant();
2024-06-14 11:53:19 -07:00
var resourceGroupResourceId = ResourceGroupResource.CreateResourceIdentifier(_azSettings.SubscriptionId, _azSettings.ContainerInstancesResourceGroup);
var resourceGroupResource = _client.GetResourceGroupResource(resourceGroupResourceId);
var scriptPath = $"/azfiles/output/{org}-{repo}/{parentIssueNumber}/{issueNumber}/run.sh";
var collection = resourceGroupResource.GetContainerGroups();
var data = new ContainerGroupData(new AzureLocation(_azSettings.Location), new ContainerInstanceContainer[]
{
2024-06-19 17:25:18 -07:00
new ContainerInstanceContainer(runId, _azSettings.SandboxImage,new ContainerResourceRequirements(new ContainerResourceRequestsContent(1.5,1)))
2024-06-14 11:53:19 -07:00
{
Command = { "/bin/bash", $"{scriptPath}" },
VolumeMounts =
{
new ContainerVolumeMount("azfiles","/azfiles/")
{
IsReadOnly = false,
}
},
}}, ContainerInstanceOperatingSystemType.Linux)
{
Volumes =
{
new ContainerVolume("azfiles")
{
AzureFile = new ContainerInstanceAzureFileVolume(_azSettings.FilesShareName,_azSettings.FilesAccountName)
{
StorageAccountKey = _azSettings.FilesAccountKey
},
},
},
RestartPolicy = ContainerGroupRestartPolicy.Never,
Sku = ContainerGroupSku.Standard,
Priority = ContainerGroupPriority.Regular
};
await collection.CreateOrUpdateAsync(WaitUntil.Completed, runId, data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error running sandbox");
2024-06-19 17:25:18 -07:00
throw;
2024-06-14 11:53:19 -07:00
}
2024-06-19 17:25:18 -07:00
2024-06-14 11:53:19 -07:00
}
public async Task Store(string org, string repo, long parentIssueNumber, long issueNumber, string filename, string extension, string dir, string output)
{
2024-06-19 17:25:18 -07:00
ArgumentNullException.ThrowIfNull(output);
2024-06-14 11:53:19 -07:00
try
{
var connectionString = $"DefaultEndpointsProtocol=https;AccountName={_azSettings.FilesAccountName};AccountKey={_azSettings.FilesAccountKey};EndpointSuffix=core.windows.net";
var parentDirName = $"{dir}/{org}-{repo}";
var fileName = $"{filename}.{extension}";
var share = new ShareClient(connectionString, _azSettings.FilesShareName);
await share.CreateIfNotExistsAsync();
await share.GetDirectoryClient($"{dir}").CreateIfNotExistsAsync(); ;
var parentDir = share.GetDirectoryClient(parentDirName);
await parentDir.CreateIfNotExistsAsync();
var parentIssueDir = parentDir.GetSubdirectoryClient($"{parentIssueNumber}");
await parentIssueDir.CreateIfNotExistsAsync();
var directory = parentIssueDir.GetSubdirectoryClient($"{issueNumber}");
await directory.CreateIfNotExistsAsync();
var file = directory.GetFileClient(fileName);
// hack to enable script to save files in the same directory
var cwdHack = "#!/bin/bash\n cd $(dirname $0)";
2024-06-19 17:25:18 -07:00
var contents = extension == "sh" ? output.Replace("#!/bin/bash", cwdHack, StringComparison.Ordinal) : output;
2024-06-14 11:53:19 -07:00
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
{
await file.CreateAsync(stream.Length);
await file.UploadRangeAsync(
new HttpRange(0, stream.Length),
stream);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error storing output");
2024-06-19 17:25:18 -07:00
throw;
2024-06-14 11:53:19 -07:00
}
}
}
public interface IManageAzure
{
Task Store(string org, string repo, long parentIssueNumber, long issueNumber, string filename, string extension, string dir, string output);
Task RunInSandbox(string org, string repo, long parentIssueNumber, long issueNumber);
Task<bool> IsSandboxCompleted(string sandboxId);
Task DeleteSandbox(string sandboxId);
2024-06-19 17:25:18 -07:00
}