Sets up local builder in codex plugin.
This commit is contained in:
parent
453a1a35a2
commit
0f12bcd086
|
@ -16,12 +16,9 @@ namespace CodexPlugin
|
|||
public static readonly TimeSpan MaxDownloadTimePerMegabyte = TimeSpan.FromSeconds(2.0);
|
||||
|
||||
public override string AppName => "codex";
|
||||
public override string Image { get; }
|
||||
public override string Image => GetDockerImage();
|
||||
|
||||
public CodexContainerRecipe()
|
||||
{
|
||||
Image = GetDockerImage();
|
||||
}
|
||||
public static string DockerImageOverride { get; set; } = string.Empty;
|
||||
|
||||
protected override void Initialize(StartupConfig startupConfig)
|
||||
{
|
||||
|
@ -122,6 +119,7 @@ namespace CodexPlugin
|
|||
{
|
||||
var image = Environment.GetEnvironmentVariable("CODEXDOCKERIMAGE");
|
||||
if (!string.IsNullOrEmpty(image)) return image;
|
||||
if (!string.IsNullOrEmpty(DockerImageOverride)) return DockerImageOverride;
|
||||
return DefaultDockerImage;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
using CodexPlugin;
|
||||
using Logging;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CodexNetDeployer
|
||||
{
|
||||
public class LocalCodexBuilder
|
||||
{
|
||||
private readonly ILog log;
|
||||
private readonly string? repoPath;
|
||||
private readonly string? dockerUsername;
|
||||
|
||||
public LocalCodexBuilder(ILog log, string? repoPath, string? dockerUsername)
|
||||
{
|
||||
this.log = log;
|
||||
this.repoPath = repoPath;
|
||||
this.dockerUsername = dockerUsername;
|
||||
}
|
||||
|
||||
public LocalCodexBuilder(ILog log, string? repoPath)
|
||||
: this(log, repoPath, Environment.GetEnvironmentVariable("DOCKERUSERNAME"))
|
||||
{
|
||||
}
|
||||
|
||||
public LocalCodexBuilder(ILog log)
|
||||
: this(log, Environment.GetEnvironmentVariable("CODEXREPOPATH"))
|
||||
{
|
||||
}
|
||||
|
||||
public void Intialize()
|
||||
{
|
||||
if (!IsEnabled()) return;
|
||||
|
||||
if (string.IsNullOrEmpty(dockerUsername)) throw new Exception("Docker username required. (Pass to constructor or set 'DOCKERUSERNAME' environment variable.)");
|
||||
if (string.IsNullOrEmpty(repoPath)) throw new Exception("Codex repo path required. (Pass to constructor or set 'CODEXREPOPATH' environment variable.)");
|
||||
if (!Directory.Exists(repoPath)) throw new Exception($"Path '{repoPath}' does not exist.");
|
||||
var files = Directory.GetFiles(repoPath);
|
||||
if (!files.Any(f => f.ToLowerInvariant().EndsWith("codex.nim"))) throw new Exception($"Path '{repoPath}' does not appear to be the Codex repo root.");
|
||||
|
||||
Log($"Codex docker image will be built in path '{repoPath}'.");
|
||||
Log("Please note this can take several minutes. If you're not trying to use a Codex image with local code changes,");
|
||||
Log("Consider using the default test image or consider setting the 'CODEXDOCKERIMAGE' environment variable to use an already built image.");
|
||||
CodexContainerRecipe.DockerImageOverride = $"Using docker image locally built in path '{repoPath}'.";
|
||||
}
|
||||
|
||||
public void Build()
|
||||
{
|
||||
if (!IsEnabled()) return;
|
||||
Log("Docker login...");
|
||||
DockerLogin();
|
||||
|
||||
Log($"Logged in. Building Codex image in path '{repoPath}'...");
|
||||
|
||||
var customImage = GenerateImageName();
|
||||
Docker($"build", "-t", customImage, "-f", "./codex.Dockerfile",
|
||||
"--build-arg=\"MAKE_PARALLEL=4\"",
|
||||
"--build-arg=\"NIMFLAGS=-d:disableMarchNative -d:codex_enable_api_debug_peers=true -d:codex_enable_api_debug_fetch=true -d:codex_enable_simulated_proof_failures\"",
|
||||
"--build-arg=\"NAT_IP_AUTO=true\"",
|
||||
"..");
|
||||
|
||||
Log($"Image '{customImage}' built successfully. Pushing...");
|
||||
|
||||
Docker("push", customImage);
|
||||
|
||||
CodexContainerRecipe.DockerImageOverride = customImage;
|
||||
Log("Image pushed. Good to go!");
|
||||
}
|
||||
|
||||
private void DockerLogin()
|
||||
{
|
||||
var dockerPassword = Environment.GetEnvironmentVariable("DOCKERPASSWORD");
|
||||
|
||||
if (string.IsNullOrEmpty(dockerUsername) || string.IsNullOrEmpty(dockerPassword))
|
||||
{
|
||||
Log("Environment variable 'DOCKERPASSWORD' not provided.");
|
||||
Log("Trying system default...");
|
||||
Docker("login");
|
||||
}
|
||||
else
|
||||
{
|
||||
Docker("login", "-u", dockerUsername, "-p", dockerPassword);
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateImageName()
|
||||
{
|
||||
return $"{dockerUsername!}/nim-codex-autoimage:{Guid.NewGuid().ToString().ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
private void Docker(params string[] args)
|
||||
{
|
||||
var dockerPath = Path.Combine(repoPath!, "docker");
|
||||
|
||||
var startInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = "docker",
|
||||
Arguments = string.Join(" ", args),
|
||||
WorkingDirectory = dockerPath,
|
||||
};
|
||||
var process = Process.Start(startInfo);
|
||||
if (process == null) throw new Exception("Failed to start docker process.");
|
||||
if (!process.WaitForExit(TimeSpan.FromMinutes(10))) throw new Exception("Docker processed timed out after 10 minutes.");
|
||||
if (process.ExitCode != 0) throw new Exception("Docker process exited with error.");
|
||||
}
|
||||
|
||||
private bool IsEnabled()
|
||||
{
|
||||
return !string.IsNullOrEmpty(repoPath);
|
||||
}
|
||||
|
||||
private void Log(string msg)
|
||||
{
|
||||
log.Log(msg);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using ArgsUniform;
|
||||
using CodexPlugin;
|
||||
using static Org.BouncyCastle.Math.EC.ECCurve;
|
||||
|
||||
namespace CodexNetDeployer
|
||||
{
|
||||
|
@ -14,6 +15,10 @@ namespace CodexNetDeployer
|
|||
[Uniform("kube-namespace", "kn", "KUBENAMESPACE", true, "Kubernetes namespace to be used for deployment.")]
|
||||
public string KubeNamespace { get; set; } = string.Empty;
|
||||
|
||||
[Uniform("codex-local-repo", "cr", "CODEXLOCALREPOPATH", false, "If set, instead of using the default Codex docker image, the local repository will be used to build an image. " +
|
||||
"This requires the 'DOCKERUSERNAME' and 'DOCKERPASSWORD' environment variables to be set.")]
|
||||
public string CodexLocalRepoPath { get; set; } = string.Empty;
|
||||
|
||||
[Uniform("nodes", "n", "NODES", true, "Number of Codex nodes to be created.")]
|
||||
public int? NumberOfCodexNodes { get; set; }
|
||||
|
||||
|
@ -59,13 +64,44 @@ namespace CodexNetDeployer
|
|||
|
||||
[Uniform("check-connect", "cc", "CHECKCONNECT", false, "If true, deployer check ensure peer-connectivity between all deployed nodes after deployment. Default is false.")]
|
||||
public bool CheckPeerConnection { get; set; } = false;
|
||||
|
||||
public List<string> Validate()
|
||||
|
||||
public Configuration()
|
||||
{
|
||||
// dotnet run \
|
||||
//--kube - config =/ opt / kubeconfig.yaml \
|
||||
//--kube -namespace=codex-continuous-tests \
|
||||
//--nodes=5 \
|
||||
//--validators=3 \
|
||||
//--log-level=Trace \
|
||||
//--storage-quota=2048 \
|
||||
//--storage-sell=1024 \
|
||||
//--min-price=1024 \
|
||||
//--max-collateral=1024 \
|
||||
//--max-duration=3600000 \
|
||||
//--block-ttl=180 \
|
||||
//--block-mi=120 \
|
||||
//--block-mn=10000 \
|
||||
//--metrics=1 \
|
||||
//--check-connect=1
|
||||
|
||||
KubeNamespace = "autodockertest";
|
||||
NumberOfCodexNodes = 3;
|
||||
NumberOfValidators = 1;
|
||||
StorageQuota = 2048;
|
||||
StorageSell = 1024;
|
||||
|
||||
CodexLocalRepoPath = "D:/Projects/nim-codex";
|
||||
}
|
||||
|
||||
public List<string> Validate()
|
||||
{
|
||||
var errors = new List<string>();
|
||||
|
||||
StringIsSet(nameof(KubeNamespace), KubeNamespace, errors);
|
||||
StringIsSet(nameof(KubeConfigFile), KubeConfigFile, errors);
|
||||
StringIsSet(nameof(TestsTypePodLabel), TestsTypePodLabel, errors);
|
||||
|
||||
ForEachProperty(
|
||||
onString: (n, v) => StringIsSet(n, v, errors),
|
||||
onInt: (n, v) => IntIsOverZero(n, v, errors));
|
||||
|
||||
if (NumberOfValidators > NumberOfCodexNodes)
|
||||
|
@ -80,12 +116,11 @@ namespace CodexNetDeployer
|
|||
return errors;
|
||||
}
|
||||
|
||||
private void ForEachProperty(Action<string, string> onString, Action<string, int?> onInt)
|
||||
private void ForEachProperty(Action<string, int?> onInt)
|
||||
{
|
||||
var properties = GetType().GetProperties();
|
||||
foreach (var p in properties)
|
||||
{
|
||||
if (p.PropertyType == typeof(string)) onString(p.Name, (string)p.GetValue(this)!);
|
||||
if (p.PropertyType == typeof(int?)) onInt(p.Name, (int?)p.GetValue(this)!);
|
||||
if (p.PropertyType == typeof(int)) onInt(p.Name, (int)p.GetValue(this)!);
|
||||
}
|
||||
|
|
|
@ -13,11 +13,13 @@ namespace CodexNetDeployer
|
|||
private readonly Configuration config;
|
||||
private readonly PeerConnectivityChecker peerConnectivityChecker;
|
||||
private readonly EntryPoint entryPoint;
|
||||
private readonly LocalCodexBuilder localCodexBuilder;
|
||||
|
||||
public Deployer(Configuration config)
|
||||
{
|
||||
this.config = config;
|
||||
peerConnectivityChecker = new PeerConnectivityChecker();
|
||||
localCodexBuilder = new LocalCodexBuilder(new ConsoleLog(), config.CodexLocalRepoPath);
|
||||
|
||||
ProjectPlugin.Load<CodexPlugin.CodexPlugin>();
|
||||
ProjectPlugin.Load<CodexContractsPlugin.CodexContractsPlugin>();
|
||||
|
@ -30,6 +32,8 @@ namespace CodexNetDeployer
|
|||
{
|
||||
var ep = CreateEntryPoint(new ConsoleLog());
|
||||
|
||||
localCodexBuilder.Intialize();
|
||||
|
||||
Log("Using plugins:" + Environment.NewLine);
|
||||
var metadata = ep.GetPluginMetadata();
|
||||
var longestKey = metadata.Keys.Max(k => k.Length);
|
||||
|
@ -44,6 +48,8 @@ namespace CodexNetDeployer
|
|||
|
||||
public CodexDeployment Deploy()
|
||||
{
|
||||
localCodexBuilder.Build();
|
||||
|
||||
Log("Initializing...");
|
||||
var ci = entryPoint.CreateInterface();
|
||||
|
||||
|
|
Loading…
Reference in New Issue