mirror of
https://github.com/logos-storage/logos-storage-nim-cs-dist-tests.git
synced 2026-01-02 13:33:07 +00:00
126 lines
4.1 KiB
C#
126 lines
4.1 KiB
C#
using System.Diagnostics;
|
|
using Logging;
|
|
|
|
namespace CodexContractsPlugin
|
|
{
|
|
public interface ICodexDockerImageProvider
|
|
{
|
|
string GetCodexDockerImage();
|
|
}
|
|
|
|
public class VersionRegistry
|
|
{
|
|
private ICodexDockerImageProvider provider = new ExceptionProvider();
|
|
private static readonly Dictionary<string, string> cache = new Dictionary<string, string>();
|
|
private static readonly object cacheLock = new object();
|
|
private readonly ILog log;
|
|
|
|
public VersionRegistry(ILog log)
|
|
{
|
|
this.log = log;
|
|
}
|
|
|
|
public void SetProvider(ICodexDockerImageProvider provider)
|
|
{
|
|
this.provider = provider;
|
|
}
|
|
|
|
public string GetContractsDockerImage()
|
|
{
|
|
try
|
|
{
|
|
var codexImage = provider.GetCodexDockerImage();
|
|
return GetContractsDockerImage(codexImage);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
throw new Exception("Failed to get contracts docker image.", exc);
|
|
}
|
|
}
|
|
|
|
private string GetContractsDockerImage(string codexImage)
|
|
{
|
|
lock (cacheLock)
|
|
{
|
|
if (cache.TryGetValue(codexImage, out string? value))
|
|
{
|
|
return value;
|
|
}
|
|
var result = GetContractsImage(codexImage);
|
|
cache.Add(codexImage, result);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
private string GetContractsImage(string codexImage)
|
|
{
|
|
var inspectResult = InspectCodexImage(codexImage);
|
|
var image = ParseCodexContractsImageName(inspectResult);
|
|
log.Log($"From codex docker image '{codexImage}', determined codex-contracts docker image: '{image}'");
|
|
return image;
|
|
}
|
|
|
|
private string InspectCodexImage(string img)
|
|
{
|
|
Execute("docker", $"pull {img}");
|
|
return Execute("docker", $"inspect {img}");
|
|
}
|
|
|
|
private string ParseCodexContractsImageName(string inspectResult)
|
|
{
|
|
// It is a nice json structure. But we only need this one line.
|
|
// "storage.codex.nim-codex.blockchain-image": "codexstorage/codex-contracts-eth:sha-0bf1385-dist-tests"
|
|
var lines = inspectResult.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
|
var line = lines.Single(l => l.Contains("storage.codex.nim-codex.blockchain-image"));
|
|
var tokens = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
|
return tokens.Last().Replace("\"", "").Trim();
|
|
}
|
|
|
|
private string Execute(string cmd, string args)
|
|
{
|
|
var startInfo = new ProcessStartInfo(
|
|
fileName: cmd,
|
|
arguments: args
|
|
);
|
|
startInfo.RedirectStandardOutput = true;
|
|
startInfo.RedirectStandardError = true;
|
|
|
|
var process = Process.Start(startInfo);
|
|
if (process == null)
|
|
{
|
|
throw new Exception("Failed to start: " + cmd + args);
|
|
}
|
|
KillAfterTimeout(process);
|
|
|
|
process.WaitForExit();
|
|
return process.StandardOutput.ReadToEnd();
|
|
}
|
|
|
|
private void KillAfterTimeout(Process process)
|
|
{
|
|
// There's a known issue that some docker commands on some platforms
|
|
// will fail to stop on their own. This has been known since 2019 and it's not fixed.
|
|
// So we will issue a kill to the process ourselves if it exceeds a timeout.
|
|
|
|
Task.Run(() =>
|
|
{
|
|
Thread.Sleep(TimeSpan.FromSeconds(30.0));
|
|
|
|
if (process != null && !process.HasExited)
|
|
{
|
|
process.Kill();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
internal class ExceptionProvider : ICodexDockerImageProvider
|
|
{
|
|
public string GetCodexDockerImage()
|
|
{
|
|
throw new InvalidOperationException("CodexContractsPlugin has not yet received a CodexDockerImageProvider " +
|
|
"and so cannot select a compatible contracts docker image.");
|
|
}
|
|
}
|
|
}
|