Merge branch 'feature/labeling-pods'

This commit is contained in:
benbierens 2023-08-10 14:25:43 +02:00
commit ea767e23ae
No known key found for this signature in database
GPG Key ID: FE44815D96D0A1AA
31 changed files with 204 additions and 127 deletions

View File

@ -8,16 +8,14 @@ namespace CodexNetDeployer
public class CodexNodeStarter public class CodexNodeStarter
{ {
private readonly Configuration config; private readonly Configuration config;
private readonly WorkflowCreator workflowCreator;
private readonly TestLifecycle lifecycle; private readonly TestLifecycle lifecycle;
private readonly GethStartResult gethResult; private readonly GethStartResult gethResult;
private string bootstrapSpr = ""; private string bootstrapSpr = "";
private int validatorsLeft; private int validatorsLeft;
public CodexNodeStarter(Configuration config, WorkflowCreator workflowCreator, TestLifecycle lifecycle, GethStartResult gethResult, int numberOfValidators) public CodexNodeStarter(Configuration config, TestLifecycle lifecycle, GethStartResult gethResult, int numberOfValidators)
{ {
this.config = config; this.config = config;
this.workflowCreator = workflowCreator;
this.lifecycle = lifecycle; this.lifecycle = lifecycle;
this.gethResult = gethResult; this.gethResult = gethResult;
validatorsLeft = numberOfValidators; validatorsLeft = numberOfValidators;
@ -26,7 +24,7 @@ namespace CodexNetDeployer
public RunningContainer? Start(int i) public RunningContainer? Start(int i)
{ {
Console.Write($" - {i} = "); Console.Write($" - {i} = ");
var workflow = workflowCreator.CreateWorkflow(); var workflow = lifecycle.WorkflowCreator.CreateWorkflow();
var workflowStartup = new StartupConfig(); var workflowStartup = new StartupConfig();
workflowStartup.Add(gethResult); workflowStartup.Add(gethResult);
workflowStartup.Add(CreateCodexStartupConfig(bootstrapSpr, i, validatorsLeft)); workflowStartup.Add(CreateCodexStartupConfig(bootstrapSpr, i, validatorsLeft));

View File

@ -47,6 +47,10 @@ namespace CodexNetDeployer
[Uniform("record-metrics", "rm", "RECORDMETRICS", false, "If true, metrics will be collected for all Codex nodes.")] [Uniform("record-metrics", "rm", "RECORDMETRICS", false, "If true, metrics will be collected for all Codex nodes.")]
public bool RecordMetrics { get; set; } = false; public bool RecordMetrics { get; set; } = false;
[Uniform("teststype-podlabel", "ttpl", "TESTSTYPE-PODLABEL", false, "Each kubernetes pod will be created with a label 'teststype' with value 'continuous'. " +
"set this option to override the label value.")]
public string TestsTypePodLabel { get; set; } = "continuous";
public TestRunnerLocation RunnerLocation { get; set; } = TestRunnerLocation.InternalToCluster; public TestRunnerLocation RunnerLocation { get; set; } = TestRunnerLocation.InternalToCluster;
public List<string> Validate() public List<string> Validate()

View File

@ -21,7 +21,7 @@ namespace CodexNetDeployer
public CodexDeployment Deploy() public CodexDeployment Deploy()
{ {
Log("Initializing..."); Log("Initializing...");
var (workflowCreator, lifecycle) = CreateFacilities(); var lifecycle = CreateTestLifecycle();
Log("Preparing configuration..."); Log("Preparing configuration...");
// We trick the Geth companion node into unlocking all of its accounts, by saying we want to start 999 codex nodes. // We trick the Geth companion node into unlocking all of its accounts, by saying we want to start 999 codex nodes.
@ -30,7 +30,7 @@ namespace CodexNetDeployer
setup.MetricsEnabled = config.RecordMetrics; setup.MetricsEnabled = config.RecordMetrics;
Log("Creating Geth instance and deploying contracts..."); Log("Creating Geth instance and deploying contracts...");
var gethStarter = new GethStarter(lifecycle, workflowCreator); var gethStarter = new GethStarter(lifecycle);
var gethResults = gethStarter.BringOnlineMarketplaceFor(setup); var gethResults = gethStarter.BringOnlineMarketplaceFor(setup);
Log("Geth started. Codex contracts deployed."); Log("Geth started. Codex contracts deployed.");
@ -44,7 +44,7 @@ namespace CodexNetDeployer
Log("Starting Codex nodes..."); Log("Starting Codex nodes...");
// Each node must have its own IP, so it needs it own pod. Start them 1 at a time. // Each node must have its own IP, so it needs it own pod. Start them 1 at a time.
var codexStarter = new CodexNodeStarter(config, workflowCreator, lifecycle, gethResults, config.NumberOfValidators!.Value); var codexStarter = new CodexNodeStarter(config, lifecycle, gethResults, config.NumberOfValidators!.Value);
var codexContainers = new List<RunningContainer>(); var codexContainers = new List<RunningContainer>();
for (var i = 0; i < config.NumberOfCodexNodes; i++) for (var i = 0; i < config.NumberOfCodexNodes; i++)
{ {
@ -57,7 +57,7 @@ namespace CodexNetDeployer
return new CodexDeployment(gethResults, codexContainers.ToArray(), prometheusContainer, CreateMetadata()); return new CodexDeployment(gethResults, codexContainers.ToArray(), prometheusContainer, CreateMetadata());
} }
private (WorkflowCreator, TestLifecycle) CreateFacilities() private TestLifecycle CreateTestLifecycle()
{ {
var kubeConfig = GetKubeConfig(config.KubeConfigFile); var kubeConfig = GetKubeConfig(config.KubeConfigFile);
@ -68,19 +68,11 @@ namespace CodexNetDeployer
logDebug: false, logDebug: false,
dataFilesPath: "notUsed", dataFilesPath: "notUsed",
codexLogLevel: config.CodexLogLevel, codexLogLevel: config.CodexLogLevel,
runnerLocation: config.RunnerLocation runnerLocation: config.RunnerLocation,
k8sNamespacePrefix: config.KubeNamespace
); );
var kubeFlowConfig = new KubernetesWorkflow.Configuration( return new TestLifecycle(log, lifecycleConfig, timeset, config.TestsTypePodLabel, string.Empty);
k8sNamespacePrefix: config.KubeNamespace,
kubeConfigFile: kubeConfig,
operationTimeout: timeset.K8sOperationTimeout(),
retryDelay: timeset.WaitForK8sServiceDelay());
var workflowCreator = new WorkflowCreator(log, kubeFlowConfig, testNamespacePostfix: string.Empty);
var lifecycle = new TestLifecycle(log, lifecycleConfig, timeset, workflowCreator);
return (workflowCreator, lifecycle);
} }
private RunningContainer? StartMetricsService(TestLifecycle lifecycle, CodexSetup setup, List<RunningContainer> codexContainers) private RunningContainer? StartMetricsService(TestLifecycle lifecycle, CodexSetup setup, List<RunningContainer> codexContainers)

View File

@ -9,5 +9,5 @@ dotnet run \
--min-price=1024 \ --min-price=1024 \
--max-collateral=1024 \ --max-collateral=1024 \
--max-duration=3600000 \ --max-duration=3600000 \
--block-ttl=120 \ --block-ttl=300 \
-y --record-metrics=true

View File

@ -25,7 +25,7 @@ public class Program
if (!Directory.Exists(config.OutputPath)) Directory.CreateDirectory(config.OutputPath); if (!Directory.Exists(config.OutputPath)) Directory.CreateDirectory(config.OutputPath);
var k8sFactory = new K8sFactory(); var k8sFactory = new K8sFactory();
var (_, lifecycle) = k8sFactory.CreateFacilities(config.KubeConfigFile, config.OutputPath, "dataPath", config.CodexDeployment.Metadata.KubeNamespace, new DefaultTimeSet(), new NullLog(), config.RunnerLocation); var lifecycle = k8sFactory.CreateTestLifecycle(config.KubeConfigFile, config.OutputPath, "dataPath", config.CodexDeployment.Metadata.KubeNamespace, new DefaultTimeSet(), new NullLog(), config.RunnerLocation);
foreach (var container in config.CodexDeployment.CodexContainers) foreach (var container in config.CodexDeployment.CodexContainers)
{ {

View File

@ -60,8 +60,8 @@ namespace ContinuousTests
if (string.IsNullOrEmpty(test.CustomK8sNamespace)) return; if (string.IsNullOrEmpty(test.CustomK8sNamespace)) return;
log.Log($"Clearing namespace '{test.CustomK8sNamespace}'..."); log.Log($"Clearing namespace '{test.CustomK8sNamespace}'...");
var (workflowCreator, _) = k8SFactory.CreateFacilities(config.KubeConfigFile, config.LogPath, config.DataPath, test.CustomK8sNamespace, new DefaultTimeSet(), log, config.RunnerLocation); var lifecycle = k8SFactory.CreateTestLifecycle(config.KubeConfigFile, config.LogPath, config.DataPath, test.CustomK8sNamespace, new DefaultTimeSet(), log, config.RunnerLocation);
workflowCreator.CreateWorkflow().DeleteTestResources(); lifecycle.WorkflowCreator.CreateWorkflow().DeleteTestResources();
} }
private void StartLogDownloader(TaskFactory taskFactory) private void StartLogDownloader(TaskFactory taskFactory)
@ -71,7 +71,7 @@ namespace ContinuousTests
var path = Path.Combine(config.LogPath, "containers"); var path = Path.Combine(config.LogPath, "containers");
if (!Directory.Exists(path)) Directory.CreateDirectory(path); if (!Directory.Exists(path)) Directory.CreateDirectory(path);
var (_, lifecycle) = k8SFactory.CreateFacilities(config.KubeConfigFile, config.LogPath, config.DataPath, config.CodexDeployment.Metadata.KubeNamespace, new DefaultTimeSet(), new NullLog(), config.RunnerLocation); var lifecycle = k8SFactory.CreateTestLifecycle(config.KubeConfigFile, config.LogPath, config.DataPath, config.CodexDeployment.Metadata.KubeNamespace, new DefaultTimeSet(), new NullLog(), config.RunnerLocation);
var downloader = new ContinuousLogDownloader(lifecycle, config.CodexDeployment, path, cancelToken); var downloader = new ContinuousLogDownloader(lifecycle, config.CodexDeployment, path, cancelToken);
taskFactory.Run(downloader.Run); taskFactory.Run(downloader.Run);

View File

@ -1,13 +1,12 @@
using DistTestCore.Codex; using DistTestCore.Codex;
using DistTestCore; using DistTestCore;
using KubernetesWorkflow;
using Logging; using Logging;
namespace ContinuousTests namespace ContinuousTests
{ {
public class K8sFactory public class K8sFactory
{ {
public (WorkflowCreator, TestLifecycle) CreateFacilities(string kubeConfigFile, string logPath, string dataFilePath, string customNamespace, ITimeSet timeSet, BaseLog log, TestRunnerLocation runnerLocation) public TestLifecycle CreateTestLifecycle(string kubeConfigFile, string logPath, string dataFilePath, string customNamespace, ITimeSet timeSet, BaseLog log, TestRunnerLocation runnerLocation)
{ {
var kubeConfig = GetKubeConfig(kubeConfigFile); var kubeConfig = GetKubeConfig(kubeConfigFile);
var lifecycleConfig = new DistTestCore.Configuration var lifecycleConfig = new DistTestCore.Configuration
@ -17,19 +16,11 @@ namespace ContinuousTests
logDebug: false, logDebug: false,
dataFilesPath: dataFilePath, dataFilesPath: dataFilePath,
codexLogLevel: CodexLogLevel.Debug, codexLogLevel: CodexLogLevel.Debug,
runnerLocation: runnerLocation runnerLocation: runnerLocation,
k8sNamespacePrefix: customNamespace
); );
var kubeFlowConfig = new KubernetesWorkflow.Configuration( return new TestLifecycle(log, lifecycleConfig, timeSet, "continuous-tests", string.Empty);
k8sNamespacePrefix: customNamespace,
kubeConfigFile: kubeConfig,
operationTimeout: timeSet.K8sOperationTimeout(),
retryDelay: timeSet.WaitForK8sServiceDelay());
var workflowCreator = new WorkflowCreator(log, kubeFlowConfig, testNamespacePostfix: string.Empty);
var lifecycle = new TestLifecycle(log, lifecycleConfig, timeSet, workflowCreator);
return (workflowCreator, lifecycle);
} }
private static string? GetKubeConfig(string kubeConfigFile) private static string? GetKubeConfig(string kubeConfigFile)

View File

@ -40,8 +40,8 @@ namespace ContinuousTests
public void RunNode(CodexAccess bootstrapNode, Action<CodexAccess, MarketplaceAccess, TestLifecycle> operation, TestToken mintTestTokens) public void RunNode(CodexAccess bootstrapNode, Action<CodexAccess, MarketplaceAccess, TestLifecycle> operation, TestToken mintTestTokens)
{ {
var (workflowCreator, lifecycle) = CreateFacilities(); var lifecycle = CreateTestLifecycle();
var flow = workflowCreator.CreateWorkflow(); var flow = lifecycle.WorkflowCreator.CreateWorkflow();
try try
{ {
@ -89,9 +89,9 @@ namespace ContinuousTests
} }
} }
private (WorkflowCreator, TestLifecycle) CreateFacilities() private TestLifecycle CreateTestLifecycle()
{ {
return k8SFactory.CreateFacilities(config.KubeConfigFile, config.LogPath, config.DataPath, customNamespace, timeSet, log, config.RunnerLocation); return k8SFactory.CreateTestLifecycle(config.KubeConfigFile, config.LogPath, config.DataPath, customNamespace, timeSet, log, config.RunnerLocation);
} }
} }
} }

View File

@ -138,7 +138,7 @@ namespace ContinuousTests
private void DownloadClusterLogs() private void DownloadClusterLogs()
{ {
var k8sFactory = new K8sFactory(); var k8sFactory = new K8sFactory();
var (_, lifecycle) = k8sFactory.CreateFacilities(config.KubeConfigFile, config.LogPath, "dataPath", config.CodexDeployment.Metadata.KubeNamespace, new DefaultTimeSet(), new NullLog(), config.RunnerLocation); var lifecycle = k8sFactory.CreateTestLifecycle(config.KubeConfigFile, config.LogPath, "dataPath", config.CodexDeployment.Metadata.KubeNamespace, new DefaultTimeSet(), new NullLog(), config.RunnerLocation);
foreach (var container in config.CodexDeployment.CodexContainers) foreach (var container in config.CodexDeployment.CodexContainers)
{ {
@ -221,7 +221,7 @@ namespace ContinuousTests
private DistTestCore.Configuration CreateFileManagerConfiguration() private DistTestCore.Configuration CreateFileManagerConfiguration()
{ {
return new DistTestCore.Configuration(null, string.Empty, false, dataFolder, return new DistTestCore.Configuration(null, string.Empty, false, dataFolder,
CodexLogLevel.Error, config.RunnerLocation); CodexLogLevel.Error, config.RunnerLocation, string.Empty);
} }
} }
} }

View File

@ -1,18 +1,15 @@
using KubernetesWorkflow; using Logging;
using Logging;
namespace DistTestCore namespace DistTestCore
{ {
public class BaseStarter public class BaseStarter
{ {
protected readonly TestLifecycle lifecycle; protected readonly TestLifecycle lifecycle;
protected readonly WorkflowCreator workflowCreator;
private Stopwatch? stopwatch; private Stopwatch? stopwatch;
public BaseStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator) public BaseStarter(TestLifecycle lifecycle)
{ {
this.lifecycle = lifecycle; this.lifecycle = lifecycle;
this.workflowCreator = workflowCreator;
} }
protected void LogStart(string msg) protected void LogStart(string msg)

View File

@ -14,6 +14,7 @@ namespace DistTestCore.Codex
public static readonly TimeSpan MaxUploadTimePerMegabyte = TimeSpan.FromSeconds(2.0); public static readonly TimeSpan MaxUploadTimePerMegabyte = TimeSpan.FromSeconds(2.0);
public static readonly TimeSpan MaxDownloadTimePerMegabyte = TimeSpan.FromSeconds(2.0); public static readonly TimeSpan MaxDownloadTimePerMegabyte = TimeSpan.FromSeconds(2.0);
public override string AppName => "codex";
public override string Image { get; } public override string Image { get; }
public CodexContainerRecipe() public CodexContainerRecipe()

View File

@ -8,8 +8,8 @@ namespace DistTestCore
{ {
public class CodexStarter : BaseStarter public class CodexStarter : BaseStarter
{ {
public CodexStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator) public CodexStarter(TestLifecycle lifecycle)
: base(lifecycle, workflowCreator) : base(lifecycle)
{ {
} }
@ -121,7 +121,7 @@ namespace DistTestCore
private StartupWorkflow CreateWorkflow() private StartupWorkflow CreateWorkflow()
{ {
return workflowCreator.CreateWorkflow(); return lifecycle.WorkflowCreator.CreateWorkflow();
} }
private void LogSeparator() private void LogSeparator()

View File

@ -12,6 +12,7 @@ namespace DistTestCore
private readonly string dataFilesPath; private readonly string dataFilesPath;
private readonly CodexLogLevel codexLogLevel; private readonly CodexLogLevel codexLogLevel;
private readonly TestRunnerLocation runnerLocation; private readonly TestRunnerLocation runnerLocation;
private readonly string k8sNamespacePrefix;
public Configuration() public Configuration()
{ {
@ -21,9 +22,10 @@ namespace DistTestCore
dataFilesPath = GetEnvVarOrDefault("DATAFILEPATH", "TestDataFiles"); dataFilesPath = GetEnvVarOrDefault("DATAFILEPATH", "TestDataFiles");
codexLogLevel = ParseEnum.Parse<CodexLogLevel>(GetEnvVarOrDefault("LOGLEVEL", nameof(CodexLogLevel.Trace))); codexLogLevel = ParseEnum.Parse<CodexLogLevel>(GetEnvVarOrDefault("LOGLEVEL", nameof(CodexLogLevel.Trace)));
runnerLocation = ParseEnum.Parse<TestRunnerLocation>(GetEnvVarOrDefault("RUNNERLOCATION", nameof(TestRunnerLocation.ExternalToCluster))); runnerLocation = ParseEnum.Parse<TestRunnerLocation>(GetEnvVarOrDefault("RUNNERLOCATION", nameof(TestRunnerLocation.ExternalToCluster)));
k8sNamespacePrefix = "ct-";
} }
public Configuration(string? kubeConfigFile, string logPath, bool logDebug, string dataFilesPath, CodexLogLevel codexLogLevel, TestRunnerLocation runnerLocation) public Configuration(string? kubeConfigFile, string logPath, bool logDebug, string dataFilesPath, CodexLogLevel codexLogLevel, TestRunnerLocation runnerLocation, string k8sNamespacePrefix)
{ {
this.kubeConfigFile = kubeConfigFile; this.kubeConfigFile = kubeConfigFile;
this.logPath = logPath; this.logPath = logPath;
@ -31,12 +33,13 @@ namespace DistTestCore
this.dataFilesPath = dataFilesPath; this.dataFilesPath = dataFilesPath;
this.codexLogLevel = codexLogLevel; this.codexLogLevel = codexLogLevel;
this.runnerLocation = runnerLocation; this.runnerLocation = runnerLocation;
this.k8sNamespacePrefix = k8sNamespacePrefix;
} }
public KubernetesWorkflow.Configuration GetK8sConfiguration(ITimeSet timeSet) public KubernetesWorkflow.Configuration GetK8sConfiguration(ITimeSet timeSet)
{ {
return new KubernetesWorkflow.Configuration( return new KubernetesWorkflow.Configuration(
k8sNamespacePrefix: "ct-", k8sNamespacePrefix: k8sNamespacePrefix,
kubeConfigFile: kubeConfigFile, kubeConfigFile: kubeConfigFile,
operationTimeout: timeSet.K8sOperationTimeout(), operationTimeout: timeSet.K8sOperationTimeout(),
retryDelay: timeSet.WaitForK8sServiceDelay() retryDelay: timeSet.WaitForK8sServiceDelay()

View File

@ -13,6 +13,7 @@ namespace DistTestCore
[Parallelizable(ParallelScope.All)] [Parallelizable(ParallelScope.All)]
public abstract class DistTest public abstract class DistTest
{ {
private const string TestsType = "dist-tests";
private readonly Configuration configuration = new Configuration(); private readonly Configuration configuration = new Configuration();
private readonly Assembly[] testAssemblies; private readonly Assembly[] testAssemblies;
private readonly FixtureLog fixtureLog; private readonly FixtureLog fixtureLog;
@ -52,7 +53,7 @@ namespace DistTestCore
{ {
Stopwatch.Measure(fixtureLog, "Global setup", () => Stopwatch.Measure(fixtureLog, "Global setup", () =>
{ {
var wc = new WorkflowCreator(fixtureLog, configuration.GetK8sConfiguration(GetTimeSet())); var wc = new WorkflowCreator(fixtureLog, configuration.GetK8sConfiguration(GetTimeSet()), new PodLabels(TestsType, null!), string.Empty);
wc.CreateWorkflow().DeleteAllResources(); wc.CreateWorkflow().DeleteAllResources();
}); });
} }
@ -195,7 +196,9 @@ namespace DistTestCore
{ {
lock (lifecycleLock) lock (lifecycleLock)
{ {
lifecycles.Add(testName, new TestLifecycle(fixtureLog.CreateTestLog(), configuration, GetTimeSet())); var testNamespace = Guid.NewGuid().ToString();
var lifecycle = new TestLifecycle(fixtureLog.CreateTestLog(), configuration, GetTimeSet(), TestsType, testNamespace);
lifecycles.Add(testName, lifecycle);
} }
}); });
} }
@ -206,7 +209,7 @@ namespace DistTestCore
var testResult = GetTestResult(); var testResult = GetTestResult();
var testDuration = lifecycle.GetTestDuration(); var testDuration = lifecycle.GetTestDuration();
fixtureLog.Log($"{GetCurrentTestName()} = {testResult} ({testDuration})"); fixtureLog.Log($"{GetCurrentTestName()} = {testResult} ({testDuration})");
statusLog.ConcludeTest(testResult, testDuration, GetCodexId(lifecycle)); statusLog.ConcludeTest(testResult, testDuration, lifecycle.GetApplicationIds());
Stopwatch.Measure(fixtureLog, $"Teardown for {GetCurrentTestName()}", () => Stopwatch.Measure(fixtureLog, $"Teardown for {GetCurrentTestName()}", () =>
{ {
lifecycle.Log.EndTest(); lifecycle.Log.EndTest();
@ -216,14 +219,6 @@ namespace DistTestCore
}); });
} }
private static string GetCodexId(TestLifecycle lifecycle)
{
var v = lifecycle.CodexVersion;
if (v == null) return new CodexContainerRecipe().Image;
if (v.version != "untagged build") return v.version;
return v.revision;
}
private ITimeSet GetTimeSet() private ITimeSet GetTimeSet()
{ {
if (ShouldUseLongTimeouts()) return new LongTimeSet(); if (ShouldUseLongTimeouts()) return new LongTimeSet();

View File

@ -1,5 +1,4 @@
using DistTestCore.Marketplace; using DistTestCore.Marketplace;
using KubernetesWorkflow;
namespace DistTestCore namespace DistTestCore
{ {
@ -8,13 +7,13 @@ namespace DistTestCore
private readonly MarketplaceNetworkCache marketplaceNetworkCache; private readonly MarketplaceNetworkCache marketplaceNetworkCache;
private readonly GethCompanionNodeStarter companionNodeStarter; private readonly GethCompanionNodeStarter companionNodeStarter;
public GethStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator) public GethStarter(TestLifecycle lifecycle)
: base(lifecycle, workflowCreator) : base(lifecycle)
{ {
marketplaceNetworkCache = new MarketplaceNetworkCache( marketplaceNetworkCache = new MarketplaceNetworkCache(
new GethBootstrapNodeStarter(lifecycle, workflowCreator), new GethBootstrapNodeStarter(lifecycle),
new CodexContractsStarter(lifecycle, workflowCreator)); new CodexContractsStarter(lifecycle));
companionNodeStarter = new GethCompanionNodeStarter(lifecycle, workflowCreator); companionNodeStarter = new GethCompanionNodeStarter(lifecycle);
} }
public GethStartResult BringOnlineMarketplaceFor(CodexSetup codexSetup) public GethStartResult BringOnlineMarketplaceFor(CodexSetup codexSetup)

View File

@ -7,12 +7,8 @@ namespace DistTestCore.Marketplace
public const string MarketplaceAddressFilename = "/hardhat/deployments/codexdisttestnetwork/Marketplace.json"; public const string MarketplaceAddressFilename = "/hardhat/deployments/codexdisttestnetwork/Marketplace.json";
public const string MarketplaceArtifactFilename = "/hardhat/artifacts/contracts/Marketplace.sol/Marketplace.json"; public const string MarketplaceArtifactFilename = "/hardhat/artifacts/contracts/Marketplace.sol/Marketplace.json";
public override string Image { get; } public override string AppName => "codex-contracts";
public override string Image => "codexstorage/dist-tests-codex-contracts-eth:sha-d6fbfdc";
public CodexContractsContainerRecipe()
{
Image = "codexstorage/dist-tests-codex-contracts-eth:sha-d6fbfdc";
}
protected override void Initialize(StartupConfig startupConfig) protected override void Initialize(StartupConfig startupConfig)
{ {

View File

@ -6,8 +6,8 @@ namespace DistTestCore.Marketplace
public class CodexContractsStarter : BaseStarter public class CodexContractsStarter : BaseStarter
{ {
public CodexContractsStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator) public CodexContractsStarter(TestLifecycle lifecycle)
: base(lifecycle, workflowCreator) : base(lifecycle)
{ {
} }
@ -15,7 +15,7 @@ namespace DistTestCore.Marketplace
{ {
LogStart("Deploying Codex Marketplace..."); LogStart("Deploying Codex Marketplace...");
var workflow = workflowCreator.CreateWorkflow(); var workflow = lifecycle.WorkflowCreator.CreateWorkflow();
var startupConfig = CreateStartupConfig(bootstrapNode.RunningContainers.Containers[0]); var startupConfig = CreateStartupConfig(bootstrapNode.RunningContainers.Containers[0]);
var containers = workflow.Start(1, Location.Unspecified, new CodexContractsContainerRecipe(), startupConfig); var containers = workflow.Start(1, Location.Unspecified, new CodexContractsContainerRecipe(), startupConfig);

View File

@ -4,8 +4,8 @@ namespace DistTestCore.Marketplace
{ {
public class GethBootstrapNodeStarter : BaseStarter public class GethBootstrapNodeStarter : BaseStarter
{ {
public GethBootstrapNodeStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator) public GethBootstrapNodeStarter(TestLifecycle lifecycle)
: base(lifecycle, workflowCreator) : base(lifecycle)
{ {
} }
@ -14,7 +14,7 @@ namespace DistTestCore.Marketplace
LogStart("Starting Geth bootstrap node..."); LogStart("Starting Geth bootstrap node...");
var startupConfig = CreateBootstrapStartupConfig(); var startupConfig = CreateBootstrapStartupConfig();
var workflow = workflowCreator.CreateWorkflow(); var workflow = lifecycle.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 bootstrapContainer = containers.Containers[0];

View File

@ -7,8 +7,8 @@ namespace DistTestCore.Marketplace
{ {
private int companionAccountIndex = 0; private int companionAccountIndex = 0;
public GethCompanionNodeStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator) public GethCompanionNodeStarter(TestLifecycle lifecycle)
: base(lifecycle, workflowCreator) : base(lifecycle)
{ {
} }
@ -18,7 +18,7 @@ namespace DistTestCore.Marketplace
var config = CreateCompanionNodeStartupConfig(marketplace.Bootstrap, codexSetup.NumberOfNodes); var config = CreateCompanionNodeStartupConfig(marketplace.Bootstrap, codexSetup.NumberOfNodes);
var workflow = workflowCreator.CreateWorkflow(); var workflow = lifecycle.WorkflowCreator.CreateWorkflow();
var containers = workflow.Start(1, Location.Unspecified, new GethContainerRecipe(), CreateStartupConfig(config)); var containers = workflow.Start(1, Location.Unspecified, new GethContainerRecipe(), CreateStartupConfig(config));
if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected one Geth companion node to be created. Test infra failure."); if (containers.Containers.Length != 1) throw new InvalidOperationException("Expected one Geth companion node to be created. Test infra failure.");
var container = containers.Containers[0]; var container = containers.Containers[0];

View File

@ -10,12 +10,8 @@ namespace DistTestCore.Marketplace
public const string DiscoveryPortTag = "disc_port"; public const string DiscoveryPortTag = "disc_port";
public const string AccountsFilename = "accounts.csv"; public const string AccountsFilename = "accounts.csv";
public override string Image { get; } public override string AppName => "geth";
public override string Image => "codexstorage/dist-tests-geth:sha-b788a2d";
public GethContainerRecipe()
{
Image = "codexstorage/dist-tests-geth:sha-b788a2d";
}
protected override void Initialize(StartupConfig startupConfig) protected override void Initialize(StartupConfig startupConfig)
{ {

View File

@ -4,12 +4,8 @@ namespace DistTestCore.Metrics
{ {
public class PrometheusContainerRecipe : ContainerRecipeFactory public class PrometheusContainerRecipe : ContainerRecipeFactory
{ {
public override string Image { get; } public override string AppName => "prometheus";
public override string Image => "codexstorage/dist-tests-prometheus:sha-f97d7fd";
public PrometheusContainerRecipe()
{
Image = "codexstorage/dist-tests-prometheus:sha-f97d7fd";
}
protected override void Initialize(StartupConfig startupConfig) protected override void Initialize(StartupConfig startupConfig)
{ {

View File

@ -7,8 +7,8 @@ namespace DistTestCore
{ {
public class PrometheusStarter : BaseStarter public class PrometheusStarter : BaseStarter
{ {
public PrometheusStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator) public PrometheusStarter(TestLifecycle lifecycle)
: base(lifecycle, workflowCreator) : base(lifecycle)
{ {
} }
@ -18,7 +18,7 @@ namespace DistTestCore
var startupConfig = new StartupConfig(); var startupConfig = new StartupConfig();
startupConfig.Add(new PrometheusStartupConfig(GeneratePrometheusConfig(containers.Containers()))); startupConfig.Add(new PrometheusStartupConfig(GeneratePrometheusConfig(containers.Containers())));
var workflow = workflowCreator.CreateWorkflow(); var workflow = lifecycle.WorkflowCreator.CreateWorkflow();
var runningContainers = workflow.Start(1, Location.Unspecified, new PrometheusContainerRecipe(), startupConfig); var runningContainers = workflow.Start(1, Location.Unspecified, new PrometheusContainerRecipe(), startupConfig);
if (runningContainers.Containers.Length != 1) throw new InvalidOperationException("Expected only 1 Prometheus container to be created."); if (runningContainers.Containers.Length != 1) throw new InvalidOperationException("Expected only 1 Prometheus container to be created.");

View File

@ -1,5 +1,7 @@
using DistTestCore.Codex; using DistTestCore.Codex;
using DistTestCore.Logs; using DistTestCore.Logs;
using DistTestCore.Marketplace;
using DistTestCore.Metrics;
using KubernetesWorkflow; using KubernetesWorkflow;
using Logging; using Logging;
using Utils; using Utils;
@ -10,21 +12,19 @@ namespace DistTestCore
{ {
private readonly DateTime testStart; private readonly DateTime testStart;
public TestLifecycle(BaseLog log, Configuration configuration, ITimeSet timeSet) public TestLifecycle(BaseLog log, Configuration configuration, ITimeSet timeSet, string testsType, string testNamespace)
: this(log, configuration, timeSet, new WorkflowCreator(log, configuration.GetK8sConfiguration(timeSet)))
{
}
public TestLifecycle(BaseLog log, Configuration configuration, ITimeSet timeSet, WorkflowCreator workflowCreator)
{ {
Log = log; Log = log;
Configuration = configuration; Configuration = configuration;
TimeSet = timeSet; TimeSet = timeSet;
var podLabels = new PodLabels(testsType, GetApplicationIds());
WorkflowCreator = new WorkflowCreator(log, configuration.GetK8sConfiguration(timeSet), podLabels, testNamespace);
FileManager = new FileManager(Log, configuration); FileManager = new FileManager(Log, configuration);
CodexStarter = new CodexStarter(this, workflowCreator); CodexStarter = new CodexStarter(this);
PrometheusStarter = new PrometheusStarter(this, workflowCreator); PrometheusStarter = new PrometheusStarter(this);
GethStarter = new GethStarter(this, workflowCreator); GethStarter = new GethStarter(this);
testStart = DateTime.UtcNow; testStart = DateTime.UtcNow;
CodexVersion = null; CodexVersion = null;
@ -34,6 +34,7 @@ namespace DistTestCore
public BaseLog Log { get; } public BaseLog Log { get; }
public Configuration Configuration { get; } public Configuration Configuration { get; }
public ITimeSet TimeSet { get; } public ITimeSet TimeSet { get; }
public WorkflowCreator WorkflowCreator { get; }
public FileManager FileManager { get; } public FileManager FileManager { get; }
public CodexStarter CodexStarter { get; } public CodexStarter CodexStarter { get; }
public PrometheusStarter PrometheusStarter { get; } public PrometheusStarter PrometheusStarter { get; }
@ -68,5 +69,23 @@ namespace DistTestCore
{ {
if (CodexVersion == null) CodexVersion = version; if (CodexVersion == null) CodexVersion = version;
} }
public ApplicationIds GetApplicationIds()
{
return new ApplicationIds(
codexId: GetCodexId(),
gethId: new GethContainerRecipe().Image,
prometheusId: new PrometheusContainerRecipe().Image,
codexContractsId: new CodexContractsContainerRecipe().Image
);
}
private string GetCodexId()
{
var v = CodexVersion;
if (v == null) return new CodexContainerRecipe().Image;
if (v.version != "untagged build") return v.version;
return v.revision;
}
} }
} }

View File

@ -27,6 +27,7 @@
return recipe; return recipe;
} }
public abstract string AppName { get; }
public abstract string Image { get; } public abstract string Image { get; }
protected int ContainerNumber { get; private set; } = 0; protected int ContainerNumber { get; private set; } = 0;
protected int Index { get; private set; } = 0; protected int Index { get; private set; } = 0;

View File

@ -11,14 +11,16 @@ namespace KubernetesWorkflow
private readonly K8sCluster cluster; private readonly K8sCluster cluster;
private readonly KnownK8sPods knownPods; private readonly KnownK8sPods knownPods;
private readonly WorkflowNumberSource workflowNumberSource; private readonly WorkflowNumberSource workflowNumberSource;
private readonly PodLabels podLabels;
private readonly K8sClient client; private readonly K8sClient client;
public K8sController(BaseLog log, K8sCluster cluster, KnownK8sPods knownPods, WorkflowNumberSource workflowNumberSource, string testNamespace) public K8sController(BaseLog log, K8sCluster cluster, KnownK8sPods knownPods, WorkflowNumberSource workflowNumberSource, string testNamespace, PodLabels podLabels)
{ {
this.log = log; this.log = log;
this.cluster = cluster; this.cluster = cluster;
this.knownPods = knownPods; this.knownPods = knownPods;
this.workflowNumberSource = workflowNumberSource; this.workflowNumberSource = workflowNumberSource;
this.podLabels = podLabels;
client = new K8sClient(cluster.GetK8sClientConfig()); client = new K8sClient(cluster.GetK8sClientConfig());
K8sTestNamespace = cluster.Configuration.K8sNamespacePrefix + testNamespace; K8sTestNamespace = cluster.Configuration.K8sNamespacePrefix + testNamespace;
@ -362,7 +364,7 @@ namespace KubernetesWorkflow
private IDictionary<string, string> GetSelector() private IDictionary<string, string> GetSelector()
{ {
return new Dictionary<string, string> { { "codex-test-node", "dist-test-" + workflowNumberSource.WorkflowNumber } }; return podLabels.GetLabels();
} }
private IDictionary<string, string> GetRunnerNamespaceSelector() private IDictionary<string, string> GetRunnerNamespaceSelector()

View File

@ -0,0 +1,52 @@
using Logging;
namespace KubernetesWorkflow
{
public class PodLabels
{
private readonly Dictionary<string, string> labels = new Dictionary<string, string>();
private PodLabels(PodLabels source)
{
labels = source.labels.ToDictionary(p => p.Key, p => p.Value);
}
public PodLabels(string testsType, ApplicationIds applicationIds)
{
Add("tests-type", testsType);
Add("runid", NameUtils.GetRunId());
Add("testid", NameUtils.GetTestId());
Add("category", NameUtils.GetCategoryName());
Add("fixturename", NameUtils.GetRawFixtureName());
Add("testname", NameUtils.GetTestMethodName());
if (applicationIds == null) return;
Add("codexid", applicationIds.CodexId);
Add("gethid", applicationIds.GethId);
Add("prometheusid", applicationIds.PrometheusId);
Add("codexcontractsid", applicationIds.CodexContractsId);
}
public PodLabels GetLabelsForAppName(string appName)
{
var pl = new PodLabels(this);
pl.Add("app", appName);
return pl;
}
private void Add(string key, string value)
{
labels.Add(key,
value.ToLowerInvariant()
.Replace(":","-")
.Replace("/", "-")
.Replace("\\", "-")
);
}
internal Dictionary<string, string> GetLabels()
{
return labels;
}
}
}

View File

@ -10,19 +10,23 @@ namespace KubernetesWorkflow
private readonly K8sCluster cluster; private readonly K8sCluster cluster;
private readonly KnownK8sPods knownK8SPods; private readonly KnownK8sPods knownK8SPods;
private readonly string testNamespace; private readonly string testNamespace;
private readonly PodLabels podLabels;
private readonly RecipeComponentFactory componentFactory = new RecipeComponentFactory(); private readonly RecipeComponentFactory componentFactory = new RecipeComponentFactory();
internal StartupWorkflow(BaseLog log, WorkflowNumberSource numberSource, K8sCluster cluster, KnownK8sPods knownK8SPods, string testNamespace) internal StartupWorkflow(BaseLog log, WorkflowNumberSource numberSource, K8sCluster cluster, KnownK8sPods knownK8SPods, string testNamespace, PodLabels podLabels)
{ {
this.log = log; this.log = log;
this.numberSource = numberSource; this.numberSource = numberSource;
this.cluster = cluster; this.cluster = cluster;
this.knownK8SPods = knownK8SPods; this.knownK8SPods = knownK8SPods;
this.testNamespace = testNamespace; this.testNamespace = testNamespace;
this.podLabels = podLabels;
} }
public RunningContainers Start(int numberOfContainers, Location location, ContainerRecipeFactory recipeFactory, StartupConfig startupConfig) public RunningContainers Start(int numberOfContainers, Location location, ContainerRecipeFactory recipeFactory, StartupConfig startupConfig)
{ {
var pl = podLabels.GetLabelsForAppName(recipeFactory.AppName);
return K8s(controller => return K8s(controller =>
{ {
var recipes = CreateRecipes(numberOfContainers, recipeFactory, startupConfig); var recipes = CreateRecipes(numberOfContainers, recipeFactory, startupConfig);
@ -30,7 +34,7 @@ namespace KubernetesWorkflow
var runningPod = controller.BringOnline(recipes, location); var runningPod = controller.BringOnline(recipes, location);
return new RunningContainers(startupConfig, runningPod, CreateContainers(runningPod, recipes, startupConfig)); return new RunningContainers(startupConfig, runningPod, CreateContainers(runningPod, recipes, startupConfig));
}); }, pl);
} }
public void Stop(RunningContainers runningContainers) public void Stop(RunningContainers runningContainers)
@ -147,14 +151,22 @@ namespace KubernetesWorkflow
private void K8s(Action<K8sController> action) private void K8s(Action<K8sController> action)
{ {
var controller = new K8sController(log, cluster, knownK8SPods, numberSource, testNamespace); var controller = new K8sController(log, cluster, knownK8SPods, numberSource, testNamespace, podLabels);
action(controller); action(controller);
controller.Dispose(); controller.Dispose();
} }
private T K8s<T>(Func<K8sController, T> action) private T K8s<T>(Func<K8sController, T> action)
{ {
var controller = new K8sController(log, cluster, knownK8SPods, numberSource, testNamespace); var controller = new K8sController(log, cluster, knownK8SPods, numberSource, testNamespace, podLabels);
var result = action(controller);
controller.Dispose();
return result;
}
private T K8s<T>(Func<K8sController, T> action, PodLabels labels)
{
var controller = new K8sController(log, cluster, knownK8SPods, numberSource, testNamespace, labels);
var result = action(controller); var result = action(controller);
controller.Dispose(); controller.Dispose();
return result; return result;

View File

@ -10,18 +10,15 @@ namespace KubernetesWorkflow
private readonly KnownK8sPods knownPods = new KnownK8sPods(); private readonly KnownK8sPods knownPods = new KnownK8sPods();
private readonly K8sCluster cluster; private readonly K8sCluster cluster;
private readonly BaseLog log; private readonly BaseLog log;
private readonly PodLabels podLabels;
private readonly string testNamespace; private readonly string testNamespace;
public WorkflowCreator(BaseLog log, Configuration configuration) public WorkflowCreator(BaseLog log, Configuration configuration, PodLabels podLabels, string testNamespace)
: this(log, configuration, Guid.NewGuid().ToString().ToLowerInvariant())
{
}
public WorkflowCreator(BaseLog log, Configuration configuration, string testNamespacePostfix)
{ {
cluster = new K8sCluster(configuration); cluster = new K8sCluster(configuration);
this.log = log; this.log = log;
testNamespace = testNamespacePostfix; this.podLabels = podLabels;
this.testNamespace = testNamespace.ToLowerInvariant();
} }
public StartupWorkflow CreateWorkflow() public StartupWorkflow CreateWorkflow()
@ -29,7 +26,7 @@ namespace KubernetesWorkflow
var workflowNumberSource = new WorkflowNumberSource(numberSource.GetNextNumber(), var workflowNumberSource = new WorkflowNumberSource(numberSource.GetNextNumber(),
containerNumberSource); containerNumberSource);
return new StartupWorkflow(log, workflowNumberSource, cluster, knownPods, testNamespace); return new StartupWorkflow(log, workflowNumberSource, cluster, knownPods, testNamespace, podLabels);
} }
} }
} }

18
Logging/ApplicationIds.cs Normal file
View File

@ -0,0 +1,18 @@
namespace Logging
{
public class ApplicationIds
{
public ApplicationIds(string codexId, string gethId, string prometheusId, string codexContractsId)
{
CodexId = codexId;
GethId = gethId;
PrometheusId = prometheusId;
CodexContractsId = codexContractsId;
}
public string CodexId { get; }
public string GethId { get; }
public string PrometheusId { get; }
public string CodexContractsId { get; }
}
}

View File

@ -22,6 +22,7 @@ namespace Logging
public static string GetRawFixtureName() public static string GetRawFixtureName()
{ {
var test = TestContext.CurrentContext.Test; var test = TestContext.CurrentContext.Test;
if (test.ClassName!.Contains("AdhocContext")) return "none";
var className = test.ClassName!.Substring(test.ClassName.LastIndexOf('.') + 1); var className = test.ClassName!.Substring(test.ClassName.LastIndexOf('.') + 1);
return className.Replace('.', '-'); return className.Replace('.', '-');
} }
@ -29,6 +30,7 @@ namespace Logging
public static string GetCategoryName() public static string GetCategoryName()
{ {
var test = TestContext.CurrentContext.Test; var test = TestContext.CurrentContext.Test;
if (test.ClassName!.Contains("AdhocContext")) return "none";
return test.ClassName!.Substring(0, test.ClassName.LastIndexOf('.')); return test.ClassName!.Substring(0, test.ClassName.LastIndexOf('.'));
} }
@ -45,7 +47,7 @@ namespace Logging
private static string GetEnvVar(string name) private static string GetEnvVar(string name)
{ {
var v = Environment.GetEnvironmentVariable(name); var v = Environment.GetEnvironmentVariable(name);
if (string.IsNullOrEmpty(v)) return $"EnvVar'{name}'NotSet"; if (string.IsNullOrEmpty(v)) return $"EnvVar-{name}-NotSet";
return v; return v;
} }

View File

@ -14,7 +14,7 @@ namespace Logging
fixtureName = NameUtils.GetRawFixtureName(); fixtureName = NameUtils.GetRawFixtureName();
} }
public void ConcludeTest(string resultStatus, string testDuration, string codexId) public void ConcludeTest(string resultStatus, string testDuration, ApplicationIds applicationIds)
{ {
Write(new StatusLogJson Write(new StatusLogJson
{ {
@ -22,7 +22,10 @@ namespace Logging
runid = NameUtils.GetRunId(), runid = NameUtils.GetRunId(),
status = resultStatus, status = resultStatus,
testid = NameUtils.GetTestId(), testid = NameUtils.GetTestId(),
codexid = codexId, codexid = applicationIds.CodexId,
gethid = applicationIds.GethId,
prometheusid = applicationIds.PrometheusId,
codexcontractsid = applicationIds.CodexContractsId,
category = NameUtils.GetCategoryName(), category = NameUtils.GetCategoryName(),
fixturename = fixtureName, fixturename = fixtureName,
testname = NameUtils.GetTestMethodName(), testname = NameUtils.GetTestMethodName(),
@ -53,6 +56,9 @@ namespace Logging
public string status { get; set; } = string.Empty; public string status { get; set; } = string.Empty;
public string testid { get; set; } = string.Empty; public string testid { get; set; } = string.Empty;
public string codexid { get; set; } = string.Empty; public string codexid { get; set; } = string.Empty;
public string gethid { get; set; } = string.Empty;
public string prometheusid { get; set; } = string.Empty;
public string codexcontractsid { get; set; } = string.Empty;
public string category { get; set; } = string.Empty; public string category { get; set; } = string.Empty;
public string fixturename { get; set; } = string.Empty; public string fixturename { get; set; } = string.Empty;
public string testname { get; set; } = string.Empty; public string testname { get; set; } = string.Empty;