Good progress
This commit is contained in:
parent
83d184177a
commit
48dda1735c
|
@ -7,11 +7,11 @@ namespace CodexPlugin
|
||||||
{
|
{
|
||||||
public class CodexAccess : ILogHandler
|
public class CodexAccess : ILogHandler
|
||||||
{
|
{
|
||||||
private readonly BaseLog log;
|
private readonly ILog log;
|
||||||
private readonly ITimeSet timeSet;
|
private readonly ITimeSet timeSet;
|
||||||
private bool hasContainerCrashed;
|
private bool hasContainerCrashed;
|
||||||
|
|
||||||
public CodexAccess(BaseLog log, RunningContainer container, ITimeSet timeSet, Address address)
|
public CodexAccess(ILog log, RunningContainer container, ITimeSet timeSet, Address address)
|
||||||
{
|
{
|
||||||
this.log = log;
|
this.log = log;
|
||||||
Container = container;
|
Container = container;
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace CodexPlugin
|
||||||
{
|
{
|
||||||
public interface ICodexNodeFactory
|
public interface ICodexNodeFactory
|
||||||
{
|
{
|
||||||
//OnlineCodexNode CreateOnlineCodexNode(CodexAccess access, CodexNodeGroup group);
|
OnlineCodexNode CreateOnlineCodexNode(CodexAccess access, CodexNodeGroup group);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CodexNodeFactory : ICodexNodeFactory
|
public class CodexNodeFactory : ICodexNodeFactory
|
||||||
|
@ -19,11 +19,11 @@ namespace CodexPlugin
|
||||||
// this.marketplaceAccessFactory = marketplaceAccessFactory;
|
// this.marketplaceAccessFactory = marketplaceAccessFactory;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//public OnlineCodexNode CreateOnlineCodexNode(CodexAccess access, CodexNodeGroup group)
|
public OnlineCodexNode CreateOnlineCodexNode(CodexAccess access, CodexNodeGroup group)
|
||||||
//{
|
{
|
||||||
// var metricsAccess = metricsAccessFactory.CreateMetricsAccess(access.Container);
|
//var metricsAccess = metricsAccessFactory.CreateMetricsAccess(access.Container);
|
||||||
// var marketplaceAccess = marketplaceAccessFactory.CreateMarketplaceAccess(access);
|
//var marketplaceAccess = marketplaceAccessFactory.CreateMarketplaceAccess(access);
|
||||||
// return new OnlineCodexNode(lifecycle, access, group, metricsAccess, marketplaceAccess);
|
return new OnlineCodexNode(/*lifecycle,*/ access, group/*, metricsAccess, marketplaceAccess*/);
|
||||||
//}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
using KubernetesWorkflow;
|
using DistTestCore;
|
||||||
|
using KubernetesWorkflow;
|
||||||
|
using Logging;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
namespace CodexPlugin
|
namespace CodexPlugin
|
||||||
{
|
{
|
||||||
public interface ICodexNodeGroup : IEnumerable<IOnlineCodexNode>
|
public interface ICodexNodeGroup : IEnumerable<IOnlineCodexNode>
|
||||||
{
|
{
|
||||||
ICodexSetup BringOffline();
|
void BringOffline();
|
||||||
IOnlineCodexNode this[int index] { get; }
|
IOnlineCodexNode this[int index] { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,12 +15,12 @@ namespace CodexPlugin
|
||||||
{
|
{
|
||||||
//private readonly TestLifecycle lifecycle;
|
//private readonly TestLifecycle lifecycle;
|
||||||
|
|
||||||
public CodexNodeGroup(/*TestLifecycle lifecycle, */CodexSetup setup, RunningContainers[] containers, ICodexNodeFactory codexNodeFactory)
|
public CodexNodeGroup(/*TestLifecycle lifecycle, CodexSetup setup,*/ILog log, ITimeSet timeSet, RunningContainers[] containers, ICodexNodeFactory codexNodeFactory)
|
||||||
{
|
{
|
||||||
//this.lifecycle = lifecycle;
|
//this.lifecycle = lifecycle;
|
||||||
Setup = setup;
|
//Setup = setup;
|
||||||
Containers = containers;
|
Containers = containers;
|
||||||
Nodes = containers.Containers().Select(c => CreateOnlineCodexNode(c, codexNodeFactory)).ToArray();
|
Nodes = containers.Containers().Select(c => CreateOnlineCodexNode(c, log, timeSet, codexNodeFactory)).ToArray();
|
||||||
Version = new CodexDebugVersionResponse();
|
Version = new CodexDebugVersionResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,20 +32,18 @@ namespace CodexPlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICodexSetup BringOffline()
|
public void BringOffline()
|
||||||
{
|
{
|
||||||
//lifecycle.CodexStarter.BringOffline(this);
|
//lifecycle.CodexStarter.BringOffline(this);
|
||||||
|
|
||||||
var result = Setup;
|
//var result = Setup;
|
||||||
// Clear everything. Prevent accidental use.
|
// Clear everything. Prevent accidental use.
|
||||||
Setup = null!;
|
//Setup = null!;
|
||||||
Nodes = Array.Empty<OnlineCodexNode>();
|
Nodes = Array.Empty<OnlineCodexNode>();
|
||||||
Containers = null!;
|
Containers = null!;
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodexSetup Setup { get; private set; }
|
//public CodexSetup Setup { get; private set; }
|
||||||
public RunningContainers[] Containers { get; private set; }
|
public RunningContainers[] Containers { get; private set; }
|
||||||
public OnlineCodexNode[] Nodes { get; private set; }
|
public OnlineCodexNode[] Nodes { get; private set; }
|
||||||
public CodexDebugVersionResponse Version { get; private set; }
|
public CodexDebugVersionResponse Version { get; private set; }
|
||||||
|
@ -78,11 +78,10 @@ namespace CodexPlugin
|
||||||
Version = first;
|
Version = first;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OnlineCodexNode CreateOnlineCodexNode(RunningContainer c, ICodexNodeFactory factory)
|
private OnlineCodexNode CreateOnlineCodexNode(RunningContainer c, ILog log, ITimeSet timeSet, ICodexNodeFactory factory)
|
||||||
{
|
{
|
||||||
//var access = new CodexAccess(lifecycle.Log, c, lifecycle.TimeSet, lifecycle.Configuration.GetAddress(c));
|
var access = new CodexAccess(log, c, timeSet, c.Address);
|
||||||
//return factory.CreateOnlineCodexNode(access, this);
|
return factory.CreateOnlineCodexNode(access, this);
|
||||||
return null!;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,32 @@
|
||||||
using KubernetesWorkflow;
|
using DistTestCore;
|
||||||
|
using KubernetesWorkflow;
|
||||||
using Logging;
|
using Logging;
|
||||||
|
|
||||||
namespace CodexPlugin
|
namespace CodexPlugin
|
||||||
{
|
{
|
||||||
public class CodexStarter //: BaseStarter
|
public class CodexStarter
|
||||||
{
|
{
|
||||||
|
private readonly IPluginActions pluginActions;
|
||||||
|
|
||||||
//public CodexStarter(TestLifecycle lifecycle)
|
//public CodexStarter(TestLifecycle lifecycle)
|
||||||
// : base(lifecycle)
|
// : base(lifecycle)
|
||||||
//{
|
//{
|
||||||
//}
|
//}
|
||||||
|
|
||||||
public List<CodexNodeGroup> RunningGroups { get; } = new List<CodexNodeGroup>();
|
public CodexStarter(IPluginActions pluginActions)
|
||||||
|
{
|
||||||
|
this.pluginActions = pluginActions;
|
||||||
|
}
|
||||||
|
|
||||||
public ICodexNodeGroup BringOnline(CodexSetup codexSetup)
|
public RunningContainers[] BringOnline(CodexSetup codexSetup)
|
||||||
{
|
{
|
||||||
//LogSeparator();
|
//LogSeparator();
|
||||||
//LogStart($"Starting {codexSetup.Describe()}...");
|
//LogStart($"Starting {codexSetup.Describe()}...");
|
||||||
//var gethStartResult = lifecycle.GethStarter.BringOnlineMarketplaceFor(codexSetup);
|
//var gethStartResult = lifecycle.GethStarter.BringOnlineMarketplaceFor(codexSetup);
|
||||||
|
|
||||||
//var startupConfig = CreateStartupConfig(gethStartResult, codexSetup);
|
var startupConfig = CreateStartupConfig(/*gethStartResult,*/ codexSetup);
|
||||||
|
|
||||||
//var containers = StartCodexContainers(startupConfig, codexSetup.NumberOfNodes, codexSetup.Location);
|
return StartCodexContainers(startupConfig, codexSetup.NumberOfNodes, codexSetup.Location);
|
||||||
|
|
||||||
//var metricAccessFactory = CollectMetrics(codexSetup, containers);
|
//var metricAccessFactory = CollectMetrics(codexSetup, containers);
|
||||||
|
|
||||||
|
@ -38,7 +44,26 @@ namespace CodexPlugin
|
||||||
//LogSeparator();
|
//LogSeparator();
|
||||||
|
|
||||||
//return group;
|
//return group;
|
||||||
return null!;
|
}
|
||||||
|
|
||||||
|
public ICodexNodeGroup WrapCodexContainers(RunningContainers[] containers)
|
||||||
|
{
|
||||||
|
//var metricAccessFactory = CollectMetrics(codexSetup, containers);
|
||||||
|
|
||||||
|
var codexNodeFactory = new CodexNodeFactory();// (lifecycle, metricAccessFactory, gethStartResult.MarketplaceAccessFactory);
|
||||||
|
|
||||||
|
return CreateCodexGroup(/*codexSetup,*/ containers, codexNodeFactory);
|
||||||
|
//lifecycle.SetCodexVersion(group.Version);
|
||||||
|
|
||||||
|
//var nl = Environment.NewLine;
|
||||||
|
//var podInfos = string.Join(nl, containers.Containers().Select(c => $"Container: '{c.Name}' runs at '{c.Pod.PodInfo.K8SNodeName}'={c.Pod.PodInfo.Ip}"));
|
||||||
|
//LogEnd($"Started {codexSetup.NumberOfNodes} nodes " +
|
||||||
|
// $"of image '{containers.Containers().First().Recipe.Image}' " +
|
||||||
|
// $"and version '{group.Version}'{nl}" +
|
||||||
|
// podInfos);
|
||||||
|
//LogSeparator();
|
||||||
|
|
||||||
|
//return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BringOffline(CodexNodeGroup group)
|
public void BringOffline(CodexNodeGroup group)
|
||||||
|
@ -50,7 +75,6 @@ namespace CodexPlugin
|
||||||
// StopCrashWatcher(c);
|
// StopCrashWatcher(c);
|
||||||
// workflow.Stop(c);
|
// workflow.Stop(c);
|
||||||
//}
|
//}
|
||||||
//RunningGroups.Remove(group);
|
|
||||||
//LogEnd("Stopped.");
|
//LogEnd("Stopped.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,8 +82,6 @@ namespace CodexPlugin
|
||||||
{
|
{
|
||||||
//var workflow = CreateWorkflow();
|
//var workflow = CreateWorkflow();
|
||||||
//workflow.DeleteTestResources();
|
//workflow.DeleteTestResources();
|
||||||
|
|
||||||
//RunningGroups.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DownloadLog(RunningContainer container, ILogHandler logHandler, int? tailLines)
|
public void DownloadLog(RunningContainer container, ILogHandler logHandler, int? tailLines)
|
||||||
|
@ -82,52 +104,51 @@ namespace CodexPlugin
|
||||||
// return new CodexNodeMetricsAccessFactory(lifecycle, runningContainers);
|
// return new CodexNodeMetricsAccessFactory(lifecycle, runningContainers);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//private StartupConfig CreateStartupConfig(GethStartResult gethStartResult, CodexSetup codexSetup)
|
private StartupConfig CreateStartupConfig(/*GethStartResult gethStartResult, */ CodexSetup codexSetup)
|
||||||
//{
|
{
|
||||||
// var startupConfig = new StartupConfig();
|
var startupConfig = new StartupConfig();
|
||||||
// startupConfig.NameOverride = codexSetup.NameOverride;
|
startupConfig.NameOverride = codexSetup.NameOverride;
|
||||||
// startupConfig.Add(codexSetup);
|
startupConfig.CreateCrashWatcher = true;
|
||||||
// startupConfig.Add(gethStartResult);
|
startupConfig.Add(codexSetup);
|
||||||
// return startupConfig;
|
//startupConfig.Add(gethStartResult);
|
||||||
//}
|
return startupConfig;
|
||||||
|
}
|
||||||
|
|
||||||
//private RunningContainers[] StartCodexContainers(StartupConfig startupConfig, int numberOfNodes, Location location)
|
private RunningContainers[] StartCodexContainers(StartupConfig startupConfig, int numberOfNodes, Location location)
|
||||||
//{
|
{
|
||||||
// var result = new List<RunningContainers>();
|
var result = new List<RunningContainers>();
|
||||||
// var recipe = new CodexContainerRecipe();
|
var recipe = new CodexContainerRecipe();
|
||||||
// for (var i = 0; i < numberOfNodes; i++)
|
for (var i = 0; i < numberOfNodes; i++)
|
||||||
// {
|
{
|
||||||
// var workflow = CreateWorkflow();
|
var workflow = pluginActions.CreateWorkflow();
|
||||||
// var rc = workflow.Start(1, location, recipe, startupConfig);
|
result.Add(workflow.Start(1, location, recipe, startupConfig));
|
||||||
// CreateCrashWatcher(workflow, rc);
|
}
|
||||||
// result.Add(rc);
|
return result.ToArray();
|
||||||
// }
|
}
|
||||||
// return result.ToArray();
|
|
||||||
//}
|
|
||||||
|
|
||||||
//private CodexNodeGroup CreateCodexGroup(CodexSetup codexSetup, RunningContainers[] runningContainers, CodexNodeFactory codexNodeFactory)
|
private CodexNodeGroup CreateCodexGroup(/*CodexSetup codexSetup, */RunningContainers[] runningContainers, CodexNodeFactory codexNodeFactory)
|
||||||
//{
|
{
|
||||||
// var group = new CodexNodeGroup(lifecycle, codexSetup, runningContainers, codexNodeFactory);
|
var group = new CodexNodeGroup(pluginActions.GetLog(), pluginActions.GetTimeSet(), /*lifecycle, codexSetup,*/ runningContainers, codexNodeFactory);
|
||||||
// RunningGroups.Add(group);
|
|
||||||
|
|
||||||
// try
|
try
|
||||||
// {
|
{
|
||||||
// Stopwatch.Measure(lifecycle.Log, "EnsureOnline", group.EnsureOnline, debug: true);
|
Stopwatch.Measure(pluginActions.GetLog(), "EnsureOnline", group.EnsureOnline, debug: true);
|
||||||
// }
|
}
|
||||||
// catch
|
catch
|
||||||
// {
|
{
|
||||||
// CodexNodesNotOnline(runningContainers);
|
CodexNodesNotOnline(runningContainers);
|
||||||
// throw;
|
throw;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// return group;
|
return group;
|
||||||
//}
|
}
|
||||||
|
|
||||||
//private void CodexNodesNotOnline(RunningContainers[] runningContainers)
|
private void CodexNodesNotOnline(RunningContainers[] runningContainers)
|
||||||
//{
|
{
|
||||||
// Log("Codex nodes failed to start");
|
pluginActions.GetLog().Log("Codex nodes failed to start");
|
||||||
// foreach (var container in runningContainers.Containers()) lifecycle.DownloadLog(container);
|
// todo:
|
||||||
//}
|
//foreach (var container in runningContainers.Containers()) lifecycle.DownloadLog(container);
|
||||||
|
}
|
||||||
|
|
||||||
//private StartupWorkflow CreateWorkflow()
|
//private StartupWorkflow CreateWorkflow()
|
||||||
//{
|
//{
|
||||||
|
@ -139,12 +160,6 @@ namespace CodexPlugin
|
||||||
// Log("----------------------------------------------------------------------------");
|
// Log("----------------------------------------------------------------------------");
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//private void CreateCrashWatcher(StartupWorkflow workflow, RunningContainers rc)
|
|
||||||
//{
|
|
||||||
// var c = rc.Containers.Single();
|
|
||||||
// c.CrashWatcher = workflow.CreateCrashWatcher(c);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//private void StopCrashWatcher(RunningContainers containers)
|
//private void StopCrashWatcher(RunningContainers containers)
|
||||||
//{
|
//{
|
||||||
// foreach (var c in containers.Containers)
|
// foreach (var c in containers.Containers)
|
||||||
|
|
|
@ -5,24 +5,26 @@ namespace CodexPlugin
|
||||||
{
|
{
|
||||||
public static class DistTestExtensions
|
public static class DistTestExtensions
|
||||||
{
|
{
|
||||||
public static RunningContainers StartCodexNodes(this DistTest distTest, int number, Action<ICodexSetup> setup)
|
public static Plugin Plugin { get; internal set; } = null!;
|
||||||
|
|
||||||
|
public static RunningContainers[] StartCodexNodes(this DistTest distTest, int number, Action<ICodexSetup> setup)
|
||||||
{
|
{
|
||||||
return null!;
|
return Plugin.StartCodexNodes(number, setup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ICodexNodeGroup WrapCodexContainers(this DistTest distTest, RunningContainers containers)
|
public static ICodexNodeGroup WrapCodexContainers(this DistTest distTest, RunningContainers containers)
|
||||||
{
|
{
|
||||||
return null!;
|
return Plugin.WrapCodexContainers(containers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IOnlineCodexNode SetupCodexNode(this DistTest distTest, Action<ICodexSetup> setup)
|
public static IOnlineCodexNode SetupCodexNode(this DistTest distTest, Action<ICodexSetup> setup)
|
||||||
{
|
{
|
||||||
return null!;
|
return Plugin.SetupCodexNode(setup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ICodexNodeGroup SetupCodexNodes(this DistTest distTest, int number)
|
public static ICodexNodeGroup SetupCodexNodes(this DistTest distTest, int number)
|
||||||
{
|
{
|
||||||
return null!;
|
return Plugin.SetupCodexNodes(number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using DistTestCore.Logs;
|
using DistTestCore.Logs;
|
||||||
using FileUtils;
|
using FileUtils;
|
||||||
using Logging;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Utils;
|
using Utils;
|
||||||
|
|
||||||
|
@ -18,7 +17,7 @@ namespace CodexPlugin
|
||||||
//IMetricsAccess Metrics { get; }
|
//IMetricsAccess Metrics { get; }
|
||||||
//IMarketplaceAccess Marketplace { get; }
|
//IMarketplaceAccess Marketplace { get; }
|
||||||
CodexDebugVersionResponse Version { get; }
|
CodexDebugVersionResponse Version { get; }
|
||||||
ICodexSetup BringOffline();
|
void BringOffline();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnlineCodexNode : IOnlineCodexNode
|
public class OnlineCodexNode : IOnlineCodexNode
|
||||||
|
@ -108,13 +107,13 @@ namespace CodexPlugin
|
||||||
return null!; // lifecycle.DownloadLog(CodexAccess.Container, tailLines);
|
return null!; // lifecycle.DownloadLog(CodexAccess.Container, tailLines);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICodexSetup BringOffline()
|
public void BringOffline()
|
||||||
{
|
{
|
||||||
if (Group.Count() > 1) throw new InvalidOperationException("Codex-nodes that are part of a group cannot be " +
|
if (Group.Count() > 1) throw new InvalidOperationException("Codex-nodes that are part of a group cannot be " +
|
||||||
"individually shut down. Use 'BringOffline()' on the group object to stop the group. This method is only " +
|
"individually shut down. Use 'BringOffline()' on the group object to stop the group. This method is only " +
|
||||||
"available for codex-nodes in groups of 1.");
|
"available for codex-nodes in groups of 1.");
|
||||||
|
|
||||||
return Group.BringOffline();
|
Group.BringOffline();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnsureOnlineGetVersionResponse()
|
public void EnsureOnlineGetVersionResponse()
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
using DistTestCore;
|
||||||
|
using KubernetesWorkflow;
|
||||||
|
|
||||||
|
namespace CodexPlugin
|
||||||
|
{
|
||||||
|
public class Plugin : IProjectPlugin
|
||||||
|
{
|
||||||
|
private readonly CodexStarter codexStarter;
|
||||||
|
|
||||||
|
public Plugin(IPluginActions actions)
|
||||||
|
{
|
||||||
|
codexStarter = new CodexStarter(actions);
|
||||||
|
|
||||||
|
DistTestExtensions.Plugin = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RunningContainers[] StartCodexNodes(int numberOfNodes, Action<ICodexSetup> setup)
|
||||||
|
{
|
||||||
|
var codexSetup = new CodexSetup(numberOfNodes, CodexLogLevel.Trace);
|
||||||
|
setup(codexSetup);
|
||||||
|
return codexStarter.BringOnline(codexSetup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICodexNodeGroup WrapCodexContainers(RunningContainers[] containers)
|
||||||
|
{
|
||||||
|
return codexStarter.WrapCodexContainers(containers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IOnlineCodexNode SetupCodexNode(Action<ICodexSetup> setup)
|
||||||
|
{
|
||||||
|
return null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICodexNodeGroup SetupCodexNodes(int number)
|
||||||
|
{
|
||||||
|
var rc = StartCodexNodes(1, s => { });
|
||||||
|
return WrapCodexContainers(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,6 @@ namespace DistTestCore
|
||||||
private readonly string dataFilesPath;
|
private readonly string dataFilesPath;
|
||||||
//private readonly CodexLogLevel codexLogLevel;
|
//private readonly CodexLogLevel codexLogLevel;
|
||||||
private readonly string k8sNamespacePrefix;
|
private readonly string k8sNamespacePrefix;
|
||||||
private static RunnerLocation? runnerLocation = null;
|
|
||||||
|
|
||||||
public Configuration()
|
public Configuration()
|
||||||
{
|
{
|
||||||
|
@ -59,20 +58,6 @@ namespace DistTestCore
|
||||||
// return codexLogLevel;
|
// return codexLogLevel;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
public Address GetAddress(RunningContainer container)
|
|
||||||
{
|
|
||||||
if (runnerLocation == null)
|
|
||||||
{
|
|
||||||
runnerLocation = RunnerLocationUtils.DetermineRunnerLocation(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runnerLocation == RunnerLocation.InternalToCluster)
|
|
||||||
{
|
|
||||||
return container.ClusterInternalAddress;
|
|
||||||
}
|
|
||||||
return container.ClusterExternalAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetEnvVarOrDefault(string varName, string defaultValue)
|
private static string GetEnvVarOrDefault(string varName, string defaultValue)
|
||||||
{
|
{
|
||||||
var v = Environment.GetEnvironmentVariable(varName);
|
var v = Environment.GetEnvironmentVariable(varName);
|
||||||
|
@ -88,56 +73,5 @@ namespace DistTestCore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum RunnerLocation
|
|
||||||
{
|
|
||||||
ExternalToCluster,
|
|
||||||
InternalToCluster,
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class RunnerLocationUtils
|
|
||||||
{
|
|
||||||
private static bool alreadyDidThat = false;
|
|
||||||
|
|
||||||
public static RunnerLocation DetermineRunnerLocation(RunningContainer container)
|
|
||||||
{
|
|
||||||
// We want to be sure we don't ping more often than strictly necessary.
|
|
||||||
// If we have already determined the location during this application
|
|
||||||
// lifetime, don't do it again.
|
|
||||||
if (alreadyDidThat) throw new Exception("We already did that.");
|
|
||||||
alreadyDidThat = true;
|
|
||||||
|
|
||||||
if (PingHost(container.Pod.PodInfo.Ip))
|
|
||||||
{
|
|
||||||
return RunnerLocation.InternalToCluster;
|
|
||||||
}
|
|
||||||
if (PingHost(Format(container.ClusterExternalAddress)))
|
|
||||||
{
|
|
||||||
return RunnerLocation.ExternalToCluster;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception("Unable to determine runner location.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string Format(Address host)
|
|
||||||
{
|
|
||||||
return host.Host
|
|
||||||
.Replace("http://", "")
|
|
||||||
.Replace("https://", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool PingHost(string host)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var pinger = new Ping();
|
|
||||||
PingReply reply = pinger.Send(host);
|
|
||||||
return reply.Status == IPStatus.Success;
|
|
||||||
}
|
|
||||||
catch (PingException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,19 +9,19 @@ namespace DistTestCore
|
||||||
{
|
{
|
||||||
public class Http
|
public class Http
|
||||||
{
|
{
|
||||||
private readonly BaseLog log;
|
private readonly ILog log;
|
||||||
private readonly ITimeSet timeSet;
|
private readonly ITimeSet timeSet;
|
||||||
private readonly Address address;
|
private readonly Address address;
|
||||||
private readonly string baseUrl;
|
private readonly string baseUrl;
|
||||||
private readonly Action<HttpClient> onClientCreated;
|
private readonly Action<HttpClient> onClientCreated;
|
||||||
private readonly string? logAlias;
|
private readonly string? logAlias;
|
||||||
|
|
||||||
public Http(BaseLog log, ITimeSet timeSet, Address address, string baseUrl, string? logAlias = null)
|
public Http(ILog log, ITimeSet timeSet, Address address, string baseUrl, string? logAlias = null)
|
||||||
: this(log, timeSet, address, baseUrl, DoNothing, logAlias)
|
: this(log, timeSet, address, baseUrl, DoNothing, logAlias)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Http(BaseLog log, ITimeSet timeSet, Address address, string baseUrl, Action<HttpClient> onClientCreated, string? logAlias = null)
|
public Http(ILog log, ITimeSet timeSet, Address address, string baseUrl, Action<HttpClient> onClientCreated, string? logAlias = null)
|
||||||
{
|
{
|
||||||
this.log = log;
|
this.log = log;
|
||||||
this.timeSet = timeSet;
|
this.timeSet = timeSet;
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
using KubernetesWorkflow;
|
||||||
|
using Logging;
|
||||||
|
|
||||||
|
namespace DistTestCore
|
||||||
|
{
|
||||||
|
public class PluginManager : IPluginActions
|
||||||
|
{
|
||||||
|
private readonly BaseLog log;
|
||||||
|
private readonly Configuration configuration;
|
||||||
|
private readonly string testNamespace;
|
||||||
|
private readonly WorkflowCreator workflowCreator;
|
||||||
|
private readonly ITimeSet timeSet;
|
||||||
|
private readonly List<IProjectPlugin> projectPlugins = new List<IProjectPlugin>();
|
||||||
|
|
||||||
|
public PluginManager(BaseLog log, Configuration configuration, ITimeSet timeSet, string testNamespace)
|
||||||
|
{
|
||||||
|
this.log = log;
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.timeSet = timeSet;
|
||||||
|
this.testNamespace = testNamespace;
|
||||||
|
workflowCreator = new WorkflowCreator(log, configuration.GetK8sConfiguration(timeSet), testNamespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IStartupWorkflow CreateWorkflow()
|
||||||
|
{
|
||||||
|
return workflowCreator.CreateWorkflow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILog GetLog()
|
||||||
|
{
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITimeSet GetTimeSet()
|
||||||
|
{
|
||||||
|
return timeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitializeAllPlugins()
|
||||||
|
{
|
||||||
|
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||||
|
var pluginTypes = assemblies.SelectMany(a => a.GetTypes().Where(t => typeof(IProjectPlugin).IsAssignableFrom(t))).ToArray();
|
||||||
|
|
||||||
|
foreach (var pluginType in pluginTypes)
|
||||||
|
{
|
||||||
|
IPluginActions actions = this;
|
||||||
|
var plugin = (IProjectPlugin)Activator.CreateInstance(pluginType, args: actions)!;
|
||||||
|
projectPlugins.Add(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IProjectPlugin
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// probably seggregate this out.
|
||||||
|
public interface IPluginActions
|
||||||
|
{
|
||||||
|
IStartupWorkflow CreateWorkflow();
|
||||||
|
ILog GetLog();
|
||||||
|
ITimeSet GetTimeSet();
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,14 @@ namespace DistTestCore
|
||||||
testStart = DateTime.UtcNow;
|
testStart = DateTime.UtcNow;
|
||||||
//CodexVersion = null;
|
//CodexVersion = null;
|
||||||
|
|
||||||
|
// the plugin manager is starting to look like the testlifecycle, that's bad because they are not supposed to be doing the same things:
|
||||||
|
// pluginmanager should be useful for disttest-deployer-continuoustest, everyone!
|
||||||
|
// but testlifecycle should be a disttest specific user of the plugin manager.
|
||||||
|
// disttest requires a hook by which it can keep track of containers created?? (does it?) /namespace used? for the purpose of cleaning up.
|
||||||
|
|
||||||
|
//var pluginManager = new PluginManager(Log, configuration, timeSet, testNamespace);
|
||||||
|
//pluginManager.InitializeAllPlugins();
|
||||||
|
|
||||||
Log.WriteLogTag();
|
Log.WriteLogTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using Utils;
|
||||||
|
|
||||||
|
namespace KubernetesWorkflow
|
||||||
|
{
|
||||||
|
internal enum RunnerLocation
|
||||||
|
{
|
||||||
|
ExternalToCluster,
|
||||||
|
InternalToCluster,
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class RunnerLocationUtils
|
||||||
|
{
|
||||||
|
private static RunnerLocation? knownLocation = null;
|
||||||
|
|
||||||
|
internal static RunnerLocation DetermineRunnerLocation(RunningContainer container)
|
||||||
|
{
|
||||||
|
if (knownLocation != null) return knownLocation.Value;
|
||||||
|
|
||||||
|
if (PingHost(container.Pod.PodInfo.Ip))
|
||||||
|
{
|
||||||
|
knownLocation = RunnerLocation.InternalToCluster;
|
||||||
|
}
|
||||||
|
if (PingHost(Format(container.ClusterExternalAddress)))
|
||||||
|
{
|
||||||
|
knownLocation = RunnerLocation.ExternalToCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (knownLocation == null) throw new Exception("Unable to determine location relative to kubernetes cluster.");
|
||||||
|
return knownLocation.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Format(Address host)
|
||||||
|
{
|
||||||
|
return host.Host
|
||||||
|
.Replace("http://", "")
|
||||||
|
.Replace("https://", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool PingHost(string host)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var pinger = new Ping();
|
||||||
|
PingReply reply = pinger.Send(host);
|
||||||
|
return reply.Status == IPStatus.Success;
|
||||||
|
}
|
||||||
|
catch (PingException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,19 @@ namespace KubernetesWorkflow
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public CrashWatcher? CrashWatcher { get; set; }
|
public CrashWatcher? CrashWatcher { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public Address Address
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (RunnerLocationUtils.DetermineRunnerLocation(this) == RunnerLocation.InternalToCluster)
|
||||||
|
{
|
||||||
|
return ClusterInternalAddress;
|
||||||
|
}
|
||||||
|
return ClusterExternalAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RunningContainersExtensions
|
public static class RunningContainersExtensions
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
private readonly List<object> configs = new List<object>();
|
private readonly List<object> configs = new List<object>();
|
||||||
|
|
||||||
public string? NameOverride { get; set; }
|
public string? NameOverride { get; set; }
|
||||||
|
public bool CreateCrashWatcher { get; set; }
|
||||||
|
|
||||||
public void Add(object config)
|
public void Add(object config)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,17 @@ using Utils;
|
||||||
|
|
||||||
namespace KubernetesWorkflow
|
namespace KubernetesWorkflow
|
||||||
{
|
{
|
||||||
public class StartupWorkflow
|
public interface IStartupWorkflow
|
||||||
|
{
|
||||||
|
RunningContainers Start(int numberOfContainers, Location location, ContainerRecipeFactory recipeFactory, StartupConfig startupConfig);
|
||||||
|
void Stop(RunningContainers runningContainers);
|
||||||
|
void DownloadContainerLog(RunningContainer container, ILogHandler logHandler, int? tailLines);
|
||||||
|
string ExecuteCommand(RunningContainer container, string command, params string[] args);
|
||||||
|
void DeleteAllResources();// !!! delete namespace then!?
|
||||||
|
void DeleteTestResources(); // !!! do not mention tests. what are we deleting?
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StartupWorkflow : IStartupWorkflow
|
||||||
{
|
{
|
||||||
private readonly BaseLog log;
|
private readonly BaseLog log;
|
||||||
private readonly WorkflowNumberSource numberSource;
|
private readonly WorkflowNumberSource numberSource;
|
||||||
|
@ -26,18 +36,15 @@ namespace KubernetesWorkflow
|
||||||
return K8s(controller =>
|
return K8s(controller =>
|
||||||
{
|
{
|
||||||
var recipes = CreateRecipes(numberOfContainers, recipeFactory, startupConfig);
|
var recipes = CreateRecipes(numberOfContainers, recipeFactory, startupConfig);
|
||||||
|
|
||||||
var runningPod = controller.BringOnline(recipes, location);
|
var runningPod = controller.BringOnline(recipes, location);
|
||||||
|
var containers = CreateContainers(runningPod, recipes, startupConfig);
|
||||||
|
|
||||||
return new RunningContainers(startupConfig, runningPod, CreateContainers(runningPod, recipes, startupConfig));
|
if (startupConfig.CreateCrashWatcher) CreateCrashWatchers(controller, containers);
|
||||||
|
|
||||||
|
return new RunningContainers(startupConfig, runningPod, containers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public CrashWatcher CreateCrashWatcher(RunningContainer container)
|
|
||||||
{
|
|
||||||
return K8s(controller => controller.CreateCrashWatcher(container));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop(RunningContainers runningContainers)
|
public void Stop(RunningContainers runningContainers)
|
||||||
{
|
{
|
||||||
K8s(controller =>
|
K8s(controller =>
|
||||||
|
@ -78,6 +85,14 @@ namespace KubernetesWorkflow
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateCrashWatchers(K8sController controller, RunningContainer[] runningContainers)
|
||||||
|
{
|
||||||
|
foreach (var container in runningContainers)
|
||||||
|
{
|
||||||
|
container.CrashWatcher = controller.CreateCrashWatcher(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private RunningContainer[] CreateContainers(RunningPod runningPod, ContainerRecipe[] recipes, StartupConfig startupConfig)
|
private RunningContainer[] CreateContainers(RunningPod runningPod, ContainerRecipe[] recipes, StartupConfig startupConfig)
|
||||||
{
|
{
|
||||||
log.Debug();
|
log.Debug();
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace KubernetesWorkflow
|
||||||
this.testNamespace = testNamespace.ToLowerInvariant();
|
this.testNamespace = testNamespace.ToLowerInvariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StartupWorkflow CreateWorkflow()
|
public IStartupWorkflow CreateWorkflow()
|
||||||
{
|
{
|
||||||
var workflowNumberSource = new WorkflowNumberSource(numberSource.GetNextNumber(),
|
var workflowNumberSource = new WorkflowNumberSource(numberSource.GetNextNumber(),
|
||||||
containerNumberSource);
|
containerNumberSource);
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
using Utils;
|
using System.Diagnostics;
|
||||||
|
using Utils;
|
||||||
|
|
||||||
namespace Logging
|
namespace Logging
|
||||||
{
|
{
|
||||||
public abstract class BaseLog
|
public interface ILog
|
||||||
|
{
|
||||||
|
void Log(string message);
|
||||||
|
void Debug(string message = "", int skipFrames = 0);
|
||||||
|
void Error(string message);
|
||||||
|
LogFile CreateSubfile(string ext = "log");
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class BaseLog : ILog
|
||||||
{
|
{
|
||||||
private readonly NumberSource subfileNumberSource = new NumberSource(0);
|
private readonly NumberSource subfileNumberSource = new NumberSource(0);
|
||||||
private readonly bool debug;
|
private readonly bool debug;
|
||||||
|
|
|
@ -5,25 +5,25 @@ namespace Logging
|
||||||
public class Stopwatch
|
public class Stopwatch
|
||||||
{
|
{
|
||||||
private readonly DateTime start = DateTime.UtcNow;
|
private readonly DateTime start = DateTime.UtcNow;
|
||||||
private readonly BaseLog log;
|
private readonly ILog log;
|
||||||
private readonly string name;
|
private readonly string name;
|
||||||
private readonly bool debug;
|
private readonly bool debug;
|
||||||
|
|
||||||
private Stopwatch(BaseLog log, string name, bool debug)
|
private Stopwatch(ILog log, string name, bool debug)
|
||||||
{
|
{
|
||||||
this.log = log;
|
this.log = log;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.debug = debug;
|
this.debug = debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Measure(BaseLog log, string name, Action action, bool debug = false)
|
public static void Measure(ILog log, string name, Action action, bool debug = false)
|
||||||
{
|
{
|
||||||
var sw = Begin(log, name, debug);
|
var sw = Begin(log, name, debug);
|
||||||
action();
|
action();
|
||||||
sw.End();
|
sw.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T Measure<T>(BaseLog log, string name, Func<T> action, bool debug = false)
|
public static T Measure<T>(ILog log, string name, Func<T> action, bool debug = false)
|
||||||
{
|
{
|
||||||
var sw = Begin(log, name, debug);
|
var sw = Begin(log, name, debug);
|
||||||
var result = action();
|
var result = action();
|
||||||
|
@ -31,22 +31,22 @@ namespace Logging
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stopwatch Begin(BaseLog log)
|
public static Stopwatch Begin(ILog log)
|
||||||
{
|
{
|
||||||
return Begin(log, "");
|
return Begin(log, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stopwatch Begin(BaseLog log, string name)
|
public static Stopwatch Begin(ILog log, string name)
|
||||||
{
|
{
|
||||||
return Begin(log, name, false);
|
return Begin(log, name, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stopwatch Begin(BaseLog log, bool debug)
|
public static Stopwatch Begin(ILog log, bool debug)
|
||||||
{
|
{
|
||||||
return Begin(log, "", debug);
|
return Begin(log, "", debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stopwatch Begin(BaseLog log, string name, bool debug)
|
public static Stopwatch Begin(ILog log, string name, bool debug)
|
||||||
{
|
{
|
||||||
return new Stopwatch(log, name, debug);
|
return new Stopwatch(log, name, debug);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CodexPlugin\CodexPlugin.csproj" />
|
<ProjectReference Include="..\CodexPlugin\CodexPlugin.csproj" />
|
||||||
<ProjectReference Include="..\ContinuousTests\ContinuousTests.csproj" />
|
|
||||||
<ProjectReference Include="..\DistTestCore\DistTestCore.csproj" />
|
<ProjectReference Include="..\DistTestCore\DistTestCore.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue