Deploys codex-contracts along with geth bootstrap node.
This commit is contained in:
parent
a12a4fb154
commit
f06216b931
|
@ -35,7 +35,7 @@ namespace DistTestCore
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
GlobalTestFailure.HasFailed = true;
|
GlobalTestFailure.HasFailed = true;
|
||||||
Error($"Global setup cleanup failed with: {ex}");
|
fixtureLog.Error($"Global setup cleanup failed with: {ex}");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ namespace DistTestCore
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Error("Cleanup failed: " + ex.Message);
|
fixtureLog.Error("Cleanup failed: " + ex.Message);
|
||||||
GlobalTestFailure.HasFailed = true;
|
GlobalTestFailure.HasFailed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,36 +82,6 @@ namespace DistTestCore
|
||||||
return new CodexSetup(lifecycle.CodexStarter, numberOfNodes);
|
return new CodexSetup(lifecycle.CodexStarter, numberOfNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void IncludeLogsAndMetricsOnTestFailure()
|
|
||||||
{
|
|
||||||
var result = TestContext.CurrentContext.Result;
|
|
||||||
if (result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Failed)
|
|
||||||
{
|
|
||||||
fixtureLog.MarkAsFailed();
|
|
||||||
|
|
||||||
if (IsDownloadingLogsAndMetricsEnabled())
|
|
||||||
{
|
|
||||||
Log("Downloading all CodexNode logs and metrics because of test failure...");
|
|
||||||
DownloadAllLogs();
|
|
||||||
DownloadAllMetrics();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log("Skipping download of all CodexNode logs and metrics due to [DontDownloadLogsAndMetricsOnFailure] attribute.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Log(string msg)
|
|
||||||
{
|
|
||||||
lifecycle.Log.Log(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Error(string msg)
|
|
||||||
{
|
|
||||||
lifecycle.Log.Error(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateNewTestLifecycle()
|
private void CreateNewTestLifecycle()
|
||||||
{
|
{
|
||||||
Stopwatch.Measure(fixtureLog, $"Setup for {GetCurrentTestName()}", () =>
|
Stopwatch.Measure(fixtureLog, $"Setup for {GetCurrentTestName()}", () =>
|
||||||
|
@ -133,6 +103,26 @@ namespace DistTestCore
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void IncludeLogsAndMetricsOnTestFailure()
|
||||||
|
{
|
||||||
|
var result = TestContext.CurrentContext.Result;
|
||||||
|
if (result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Failed)
|
||||||
|
{
|
||||||
|
fixtureLog.MarkAsFailed();
|
||||||
|
|
||||||
|
if (IsDownloadingLogsAndMetricsEnabled())
|
||||||
|
{
|
||||||
|
lifecycle.Log.Log("Downloading all CodexNode logs and metrics because of test failure...");
|
||||||
|
DownloadAllLogs();
|
||||||
|
DownloadAllMetrics();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lifecycle.Log.Log("Skipping download of all CodexNode logs and metrics due to [DontDownloadLogsAndMetricsOnFailure] attribute.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string GetTestDuration()
|
private string GetTestDuration()
|
||||||
{
|
{
|
||||||
var testDuration = DateTime.UtcNow - testStart;
|
var testDuration = DateTime.UtcNow - testStart;
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
using KubernetesWorkflow;
|
||||||
|
|
||||||
|
namespace DistTestCore.Marketplace
|
||||||
|
{
|
||||||
|
public class CodexContractsContainerConfig
|
||||||
|
{
|
||||||
|
public CodexContractsContainerConfig(string bootstrapNodeIp, Port jsonRpcPort)
|
||||||
|
{
|
||||||
|
BootstrapNodeIp = bootstrapNodeIp;
|
||||||
|
JsonRpcPort = jsonRpcPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BootstrapNodeIp { get; }
|
||||||
|
public Port JsonRpcPort { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using KubernetesWorkflow;
|
||||||
|
|
||||||
|
namespace DistTestCore.Marketplace
|
||||||
|
{
|
||||||
|
public class CodexContractsContainerRecipe : ContainerRecipeFactory
|
||||||
|
{
|
||||||
|
public const string DockerImage = "thatbenbierens/codex-contracts-deployment";
|
||||||
|
|
||||||
|
protected override string Image => DockerImage;
|
||||||
|
|
||||||
|
protected override void Initialize(StartupConfig startupConfig)
|
||||||
|
{
|
||||||
|
var config = startupConfig.Get<CodexContractsContainerConfig>();
|
||||||
|
|
||||||
|
var ip = config.BootstrapNodeIp;
|
||||||
|
var port = config.JsonRpcPort.Number;
|
||||||
|
|
||||||
|
AddEnvVar("DISTTEST_NETWORK_URL", $"http://{ip}:{port}");
|
||||||
|
AddEnvVar("HARDHAT_NETWORK", "codexdisttestnetwork");
|
||||||
|
AddEnvVar("KEEP_ALIVE", "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
using KubernetesWorkflow;
|
||||||
|
using Utils;
|
||||||
|
|
||||||
|
namespace DistTestCore.Marketplace
|
||||||
|
{
|
||||||
|
public class CodexContractsStarter
|
||||||
|
{
|
||||||
|
private const string readyString = "Done! Sleeping indefinitely...";
|
||||||
|
private readonly TestLifecycle lifecycle;
|
||||||
|
private readonly WorkflowCreator workflowCreator;
|
||||||
|
|
||||||
|
public CodexContractsStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator)
|
||||||
|
{
|
||||||
|
this.lifecycle = lifecycle;
|
||||||
|
this.workflowCreator = workflowCreator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start(RunningContainer bootstrapContainer)
|
||||||
|
{
|
||||||
|
var workflow = workflowCreator.CreateWorkflow();
|
||||||
|
var startupConfig = CreateStartupConfig(bootstrapContainer);
|
||||||
|
|
||||||
|
lifecycle.Log.Log("Deploying Codex contracts...");
|
||||||
|
var containers = workflow.Start(1, Location.Unspecified, new CodexContractsContainerRecipe(), startupConfig);
|
||||||
|
if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected 1 Codex contracts container to be created. Test infra failure.");
|
||||||
|
var container = containers.Containers[0];
|
||||||
|
|
||||||
|
WaitUntil(() =>
|
||||||
|
{
|
||||||
|
var logHandler = new ContractsReadyLogHandler(readyString);
|
||||||
|
workflow.DownloadContainerLog(container, logHandler);
|
||||||
|
return logHandler.Found;
|
||||||
|
});
|
||||||
|
|
||||||
|
lifecycle.Log.Log("Contracts deployed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WaitUntil(Func<bool> predicate)
|
||||||
|
{
|
||||||
|
Time.WaitUntil(predicate, TimeSpan.FromMinutes(2), TimeSpan.FromSeconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private StartupConfig CreateStartupConfig(RunningContainer bootstrapContainer)
|
||||||
|
{
|
||||||
|
var startupConfig = new StartupConfig();
|
||||||
|
var contractsConfig = new CodexContractsContainerConfig(bootstrapContainer.Pod.Ip, bootstrapContainer.Recipe.GetPortByTag(GethContainerRecipe.HttpPortTag));
|
||||||
|
startupConfig.Add(contractsConfig);
|
||||||
|
return startupConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ContractsReadyLogHandler : LogHandler
|
||||||
|
{
|
||||||
|
private readonly string targetString;
|
||||||
|
|
||||||
|
public ContractsReadyLogHandler(string targetString)
|
||||||
|
{
|
||||||
|
this.targetString = targetString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Found { get; private set; }
|
||||||
|
|
||||||
|
protected override void ProcessLine(string line)
|
||||||
|
{
|
||||||
|
if (line.Contains(targetString)) Found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,11 +7,13 @@ namespace DistTestCore.Marketplace
|
||||||
private const string bootstrapGenesisJsonBase64 = "ewogICAgImNvbmZpZyI6IHsKICAgICAgImNoYWluSWQiOiA3ODk5ODgsCiAgICAgICJob21lc3RlYWRCbG9jayI6IDAsCiAgICAgICJlaXAxNTBCbG9jayI6IDAsCiAgICAgICJlaXAxNTVCbG9jayI6IDAsCiAgICAgICJlaXAxNThCbG9jayI6IDAsCiAgICAgICJieXphbnRpdW1CbG9jayI6IDAsCiAgICAgICJjb25zdGFudGlub3BsZUJsb2NrIjogMCwKICAgICAgInBldGVyc2J1cmdCbG9jayI6IDAsCiAgICAgICJpc3RhbmJ1bEJsb2NrIjogMCwKICAgICAgIm11aXJHbGFjaWVyQmxvY2siOiAwLAogICAgICAiYmVybGluQmxvY2siOiAwLAogICAgICAibG9uZG9uQmxvY2siOiAwLAogICAgICAiYXJyb3dHbGFjaWVyQmxvY2siOiAwLAogICAgICAiZ3JheUdsYWNpZXJCbG9jayI6IDAsCiAgICAgICJjbGlxdWUiOiB7CiAgICAgICAgInBlcmlvZCI6IDUsCiAgICAgICAgImVwb2NoIjogMzAwMDAKICAgICAgfQogICAgfSwKICAgICJkaWZmaWN1bHR5IjogIjEiLAogICAgImdhc0xpbWl0IjogIjgwMDAwMDAwMCIsCiAgICAiZXh0cmFkYXRhIjogIjB4MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMEFDQ09VTlRfSEVSRTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAiLAogICAgImFsbG9jIjogewogICAgICAiMHhBQ0NPVU5UX0hFUkUiOiB7ICJiYWxhbmNlIjogIjUwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAiIH0KICAgIH0KICB9";
|
private const string bootstrapGenesisJsonBase64 = "ewogICAgImNvbmZpZyI6IHsKICAgICAgImNoYWluSWQiOiA3ODk5ODgsCiAgICAgICJob21lc3RlYWRCbG9jayI6IDAsCiAgICAgICJlaXAxNTBCbG9jayI6IDAsCiAgICAgICJlaXAxNTVCbG9jayI6IDAsCiAgICAgICJlaXAxNThCbG9jayI6IDAsCiAgICAgICJieXphbnRpdW1CbG9jayI6IDAsCiAgICAgICJjb25zdGFudGlub3BsZUJsb2NrIjogMCwKICAgICAgInBldGVyc2J1cmdCbG9jayI6IDAsCiAgICAgICJpc3RhbmJ1bEJsb2NrIjogMCwKICAgICAgIm11aXJHbGFjaWVyQmxvY2siOiAwLAogICAgICAiYmVybGluQmxvY2siOiAwLAogICAgICAibG9uZG9uQmxvY2siOiAwLAogICAgICAiYXJyb3dHbGFjaWVyQmxvY2siOiAwLAogICAgICAiZ3JheUdsYWNpZXJCbG9jayI6IDAsCiAgICAgICJjbGlxdWUiOiB7CiAgICAgICAgInBlcmlvZCI6IDUsCiAgICAgICAgImVwb2NoIjogMzAwMDAKICAgICAgfQogICAgfSwKICAgICJkaWZmaWN1bHR5IjogIjEiLAogICAgImdhc0xpbWl0IjogIjgwMDAwMDAwMCIsCiAgICAiZXh0cmFkYXRhIjogIjB4MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMEFDQ09VTlRfSEVSRTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAiLAogICAgImFsbG9jIjogewogICAgICAiMHhBQ0NPVU5UX0hFUkUiOiB7ICJiYWxhbmNlIjogIjUwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAiIH0KICAgIH0KICB9";
|
||||||
private readonly TestLifecycle lifecycle;
|
private readonly TestLifecycle lifecycle;
|
||||||
private readonly WorkflowCreator workflowCreator;
|
private readonly WorkflowCreator workflowCreator;
|
||||||
|
private readonly CodexContractsStarter codexContractsStarter;
|
||||||
|
|
||||||
public GethBootstrapNodeStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator)
|
public GethBootstrapNodeStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator)
|
||||||
{
|
{
|
||||||
this.lifecycle = lifecycle;
|
this.lifecycle = lifecycle;
|
||||||
this.workflowCreator = workflowCreator;
|
this.workflowCreator = workflowCreator;
|
||||||
|
codexContractsStarter = new CodexContractsStarter(lifecycle, workflowCreator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GethBootstrapNodeInfo StartGethBootstrapNode()
|
public GethBootstrapNodeInfo StartGethBootstrapNode()
|
||||||
|
@ -22,18 +24,26 @@ namespace DistTestCore.Marketplace
|
||||||
var workflow = workflowCreator.CreateWorkflow();
|
var workflow = workflowCreator.CreateWorkflow();
|
||||||
var containers = workflow.Start(1, Location.Unspecified, new GethContainerRecipe(), startupConfig);
|
var containers = workflow.Start(1, Location.Unspecified, new GethContainerRecipe(), startupConfig);
|
||||||
if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected 1 Geth bootstrap node to be created. Test infra failure.");
|
if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected 1 Geth bootstrap node to be created. Test infra failure.");
|
||||||
|
var bootstrapContainer = containers.Containers[0];
|
||||||
|
|
||||||
var extractor = new GethInfoExtractor(workflow, containers.Containers[0]);
|
var extractor = new GethInfoExtractor(workflow, bootstrapContainer);
|
||||||
var account = extractor.ExtractAccount();
|
var account = extractor.ExtractAccount();
|
||||||
var genesisJsonBase64 = extractor.ExtractGenesisJsonBase64();
|
var genesisJsonBase64 = extractor.ExtractGenesisJsonBase64();
|
||||||
var pubKey = extractor.ExtractPubKey();
|
var pubKey = extractor.ExtractPubKey();
|
||||||
var discoveryPort = containers.Containers[0].Recipe.GetPortByTag(GethContainerRecipe.DiscoveryPortTag);
|
var discoveryPort = bootstrapContainer.Recipe.GetPortByTag(GethContainerRecipe.DiscoveryPortTag);
|
||||||
|
|
||||||
Log($"Geth bootstrap node started with account '{account}'");
|
Log($"Geth bootstrap node started with account '{account}'");
|
||||||
|
|
||||||
|
DeployCodexContracts(bootstrapContainer);
|
||||||
|
|
||||||
return new GethBootstrapNodeInfo(containers, account, genesisJsonBase64, pubKey, discoveryPort);
|
return new GethBootstrapNodeInfo(containers, account, genesisJsonBase64, pubKey, discoveryPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DeployCodexContracts(RunningContainer bootstrapContainer)
|
||||||
|
{
|
||||||
|
codexContractsStarter.Start(bootstrapContainer);
|
||||||
|
}
|
||||||
|
|
||||||
private StartupConfig CreateBootstrapStartupConfig()
|
private StartupConfig CreateBootstrapStartupConfig()
|
||||||
{
|
{
|
||||||
var config = new StartupConfig();
|
var config = new StartupConfig();
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace DistTestCore.Marketplace
|
||||||
if (config.IsBootstrapNode)
|
if (config.IsBootstrapNode)
|
||||||
{
|
{
|
||||||
AddEnvVar("IS_BOOTSTRAP", "1");
|
AddEnvVar("IS_BOOTSTRAP", "1");
|
||||||
var exposedPort = AddExposedPort();
|
var exposedPort = AddExposedPort(tag: HttpPortTag);
|
||||||
return $"--http.port {exposedPort.Number} --discovery.port {discovery.Number} --nodiscover";
|
return $"--http.port {exposedPort.Number} --discovery.port {discovery.Number} --nodiscover";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using k8s;
|
using k8s;
|
||||||
using k8s.Models;
|
using k8s.Models;
|
||||||
|
using Utils;
|
||||||
|
|
||||||
namespace KubernetesWorkflow
|
namespace KubernetesWorkflow
|
||||||
{
|
{
|
||||||
|
@ -345,18 +346,7 @@ namespace KubernetesWorkflow
|
||||||
|
|
||||||
private void WaitUntil(Func<bool> predicate)
|
private void WaitUntil(Func<bool> predicate)
|
||||||
{
|
{
|
||||||
var start = DateTime.UtcNow;
|
Time.WaitUntil(predicate, cluster.K8sOperationTimeout(), cluster.WaitForK8sServiceDelay());
|
||||||
var state = predicate();
|
|
||||||
while (!state)
|
|
||||||
{
|
|
||||||
if (DateTime.UtcNow - start > cluster.K8sOperationTimeout())
|
|
||||||
{
|
|
||||||
throw new TimeoutException("K8s operation timed out.");
|
|
||||||
}
|
|
||||||
|
|
||||||
cluster.WaitForK8sServiceDelay();
|
|
||||||
state = predicate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -22,5 +22,21 @@
|
||||||
result += $"{d.Seconds} secs";
|
result += $"{d.Seconds} secs";
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void WaitUntil(Func<bool> predicate, TimeSpan timeout, TimeSpan retryTime)
|
||||||
|
{
|
||||||
|
var start = DateTime.UtcNow;
|
||||||
|
var state = predicate();
|
||||||
|
while (!state)
|
||||||
|
{
|
||||||
|
if (DateTime.UtcNow - start > timeout)
|
||||||
|
{
|
||||||
|
throw new TimeoutException("Operation timed out.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Sleep(retryTime);
|
||||||
|
state = predicate();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue