wiring up started
This commit is contained in:
parent
e45ed0c21e
commit
ee0193c879
@ -1,5 +1,6 @@
|
||||
using CodexOpenApi;
|
||||
using Core;
|
||||
using GethPlugin;
|
||||
using Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Utils;
|
||||
@ -10,12 +11,14 @@ namespace CodexPlugin
|
||||
{
|
||||
private readonly ILog log;
|
||||
private readonly IPluginTools tools;
|
||||
private readonly ICodexInstance instance;
|
||||
private readonly IProcessControl processControl;
|
||||
private ICodexInstance instance;
|
||||
private readonly Mapper mapper = new Mapper();
|
||||
|
||||
public CodexAccess(IPluginTools tools, ICodexInstance instance, ICrashWatcher crashWatcher)
|
||||
public CodexAccess(IPluginTools tools, IProcessControl processControl, ICodexInstance instance, ICrashWatcher crashWatcher)
|
||||
{
|
||||
this.tools = tools;
|
||||
this.processControl = processControl;
|
||||
this.instance = instance;
|
||||
log = tools.GetLog();
|
||||
CrashWatcher = crashWatcher;
|
||||
@ -25,6 +28,14 @@ namespace CodexPlugin
|
||||
|
||||
public ICrashWatcher CrashWatcher { get; }
|
||||
|
||||
public void Stop(bool waitTillStopped)
|
||||
{
|
||||
CrashWatcher.Stop();
|
||||
processControl.Stop(instance);
|
||||
// Prevents accidental use after stop:
|
||||
instance = null!;
|
||||
}
|
||||
|
||||
public string GetImageName()
|
||||
{
|
||||
return instance.ImageName;
|
||||
@ -192,20 +203,18 @@ namespace CodexPlugin
|
||||
//);
|
||||
}
|
||||
|
||||
public Address? GetMetricsEndpoint()
|
||||
{
|
||||
return instance.GetMetricsEndpoint();
|
||||
}
|
||||
|
||||
public EthAccount? GetEthAccount()
|
||||
{
|
||||
return instance.GetEthAccount();
|
||||
}
|
||||
|
||||
public void DeleteDataDirFolder()
|
||||
{
|
||||
//try
|
||||
//{
|
||||
// var containerNumber = Container.Containers.First().Recipe.Number;
|
||||
// var dataDir = $"datadir{containerNumber}";
|
||||
// var workflow = tools.CreateWorkflow();
|
||||
// workflow.ExecuteCommand(Container.Containers.First(), "rm", "-Rfv", $"/codex/{dataDir}/repo");
|
||||
// Log("Deleted repo folder.");
|
||||
//}
|
||||
//catch (Exception e)
|
||||
//{
|
||||
// Log("Unable to delete repo folder: " + e);
|
||||
//}
|
||||
instance.DeleteDataDirFolder();
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,8 @@
|
||||
using Utils;
|
||||
using Core;
|
||||
using GethPlugin;
|
||||
using KubernetesWorkflow.Types;
|
||||
using Logging;
|
||||
using Utils;
|
||||
|
||||
namespace CodexPlugin
|
||||
{
|
||||
@ -10,5 +14,67 @@ namespace CodexPlugin
|
||||
Address DiscoveryEndpoint { get; }
|
||||
Address ApiEndpoint { get; }
|
||||
void DeleteDataDirFolder();
|
||||
EthAccount? GetEthAccount();
|
||||
Address? GetMetricsEndpoint();
|
||||
}
|
||||
|
||||
public class CodexContainerInstance : ICodexInstance
|
||||
{
|
||||
private readonly RunningContainer container;
|
||||
private readonly IPluginTools tools;
|
||||
private readonly ILog log;
|
||||
private readonly Address? metricsAddress = null;
|
||||
private readonly EthAccount? ethAccount = null;
|
||||
|
||||
public CodexContainerInstance(IPluginTools tools, ILog log, RunningPod pod)
|
||||
{
|
||||
container = pod.Containers.Single();
|
||||
this.tools = tools;
|
||||
this.log = log;
|
||||
Name = container.Name;
|
||||
ImageName = container.Recipe.Image;
|
||||
StartUtc = container.Recipe.RecipeCreatedUtc;
|
||||
|
||||
DiscoveryEndpoint = container.GetAddress(CodexContainerRecipe.DiscoveryPortTag);
|
||||
ApiEndpoint = container.GetAddress(CodexContainerRecipe.ApiPortTag);
|
||||
|
||||
if (pod.StartupConfig.Get<CodexSetup>().MetricsEnabled)
|
||||
{
|
||||
metricsAddress = container.GetAddress(CodexContainerRecipe.MetricsPortTag);
|
||||
}
|
||||
ethAccount = container.Recipe.Additionals.Get<EthAccount>();
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string ImageName { get; }
|
||||
public DateTime StartUtc { get; }
|
||||
public Address DiscoveryEndpoint { get; }
|
||||
public Address ApiEndpoint { get; }
|
||||
|
||||
public void DeleteDataDirFolder()
|
||||
{
|
||||
try
|
||||
{
|
||||
var dataDirVar = container.Recipe.EnvVars.Single(e => e.Name == "CODEX_DATA_DIR");
|
||||
var dataDir = dataDirVar.Value;
|
||||
var workflow = tools.CreateWorkflow();
|
||||
workflow.ExecuteCommand(container, "rm", "-Rfv", $"/codex/{dataDir}/repo");
|
||||
log.Log("Deleted repo folder.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Log("Unable to delete repo folder: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public EthAccount? GetEthAccount()
|
||||
{
|
||||
return ethAccount;
|
||||
}
|
||||
|
||||
public Address? GetMetricsEndpoint()
|
||||
{
|
||||
return metricsAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,18 +52,15 @@ namespace CodexPlugin
|
||||
private readonly ILog log;
|
||||
private readonly IPluginTools tools;
|
||||
private readonly ICodexNodeHooks hooks;
|
||||
private readonly EthAccount? ethAccount;
|
||||
private readonly TransferSpeeds transferSpeeds;
|
||||
private string peerId = string.Empty;
|
||||
private string nodeId = string.Empty;
|
||||
private readonly CodexAccess codexAccess;
|
||||
|
||||
public CodexNode(IPluginTools tools, CodexAccess codexAccess, CodexNodeGroup group, IMarketplaceAccess marketplaceAccess, ICodexNodeHooks hooks, EthAccount? ethAccount)
|
||||
public CodexNode(IPluginTools tools, CodexAccess codexAccess, IMarketplaceAccess marketplaceAccess, ICodexNodeHooks hooks)
|
||||
{
|
||||
this.tools = tools;
|
||||
this.ethAccount = ethAccount;
|
||||
this.codexAccess = codexAccess;
|
||||
Group = group;
|
||||
Marketplace = marketplaceAccess;
|
||||
this.hooks = hooks;
|
||||
Version = new DebugInfoVersion();
|
||||
@ -74,15 +71,17 @@ namespace CodexPlugin
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
hooks.OnNodeStarting(codexAccess.GetStartUtc(), codexAccess.GetImageName(), ethAccount);
|
||||
hooks.OnNodeStarting(codexAccess.GetStartUtc(), codexAccess.GetImageName(), codexAccess.GetEthAccount());
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
InitializePeerNodeId();
|
||||
InitializeLogReplacements();
|
||||
|
||||
hooks.OnNodeStarted(peerId, nodeId);
|
||||
}
|
||||
|
||||
public CodexNodeGroup Group { get; }
|
||||
public IMarketplaceAccess Marketplace { get; }
|
||||
public DebugInfoVersion Version { get; private set; }
|
||||
public ITransferSpeeds TransferSpeeds { get => transferSpeeds; }
|
||||
@ -91,8 +90,9 @@ namespace CodexPlugin
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new Exception("todo");
|
||||
//return new MetricsScrapeTarget(CodexAccess.Container.Containers.First(), CodexContainerRecipe.MetricsPortTag);
|
||||
var address = codexAccess.GetMetricsEndpoint();
|
||||
if (address == null) throw new Exception("Metrics ScrapeTarget accessed, but node was not started with EnableMetrics()");
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ namespace CodexPlugin
|
||||
get
|
||||
{
|
||||
EnsureMarketplace();
|
||||
return ethAccount!.EthAddress;
|
||||
return codexAccess.GetEthAccount()!.EthAddress;
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ namespace CodexPlugin
|
||||
get
|
||||
{
|
||||
EnsureMarketplace();
|
||||
return ethAccount!;
|
||||
return codexAccess.GetEthAccount()!;
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,27 +261,7 @@ namespace CodexPlugin
|
||||
{
|
||||
Log("Stopping...");
|
||||
hooks.OnNodeStopping();
|
||||
codexAccess.CrashWatcher.Stop();
|
||||
Group.Stop(this, waitTillStopped);
|
||||
}
|
||||
|
||||
public void EnsureOnlineGetVersionResponse()
|
||||
{
|
||||
var debugInfo = Time.Retry(codexAccess.GetDebugInfo, "ensure online");
|
||||
peerId = debugInfo.Id;
|
||||
nodeId = debugInfo.Table.LocalNode.NodeId;
|
||||
var nodeName = codexAccess.Container.Name;
|
||||
|
||||
if (!debugInfo.Version.IsValid())
|
||||
{
|
||||
throw new Exception($"Invalid version information received from Codex node {GetName()}: {debugInfo.Version}");
|
||||
}
|
||||
|
||||
log.AddStringReplace(peerId, nodeName);
|
||||
log.AddStringReplace(CodexUtils.ToShortId(peerId), nodeName);
|
||||
log.AddStringReplace(debugInfo.Table.LocalNode.NodeId, nodeName);
|
||||
log.AddStringReplace(CodexUtils.ToShortId(debugInfo.Table.LocalNode.NodeId), nodeName);
|
||||
Version = debugInfo.Version;
|
||||
codexAccess.Stop(waitTillStopped);
|
||||
}
|
||||
|
||||
public Address GetDiscoveryEndpoint()
|
||||
@ -299,6 +279,29 @@ namespace CodexPlugin
|
||||
return $"CodexNode:{GetName()}";
|
||||
}
|
||||
|
||||
private void InitializePeerNodeId()
|
||||
{
|
||||
var debugInfo = Time.Retry(codexAccess.GetDebugInfo, "ensure online");
|
||||
if (!debugInfo.Version.IsValid())
|
||||
{
|
||||
throw new Exception($"Invalid version information received from Codex node {GetName()}: {debugInfo.Version}");
|
||||
}
|
||||
|
||||
peerId = debugInfo.Id;
|
||||
nodeId = debugInfo.Table.LocalNode.NodeId;
|
||||
Version = debugInfo.Version;
|
||||
}
|
||||
|
||||
private void InitializeLogReplacements()
|
||||
{
|
||||
var nodeName = GetName();
|
||||
|
||||
log.AddStringReplace(peerId, nodeName);
|
||||
log.AddStringReplace(CodexUtils.ToShortId(peerId), nodeName);
|
||||
log.AddStringReplace(nodeId, nodeName);
|
||||
log.AddStringReplace(CodexUtils.ToShortId(nodeId), nodeName);
|
||||
}
|
||||
|
||||
private string[] GetPeerMultiAddresses(CodexNode peer, DebugInfo peerInfo)
|
||||
{
|
||||
var peerId = peer.GetDiscoveryEndpoint().Host
|
||||
@ -377,7 +380,7 @@ namespace CodexPlugin
|
||||
|
||||
private void EnsureMarketplace()
|
||||
{
|
||||
if (ethAccount == null) throw new Exception("Marketplace is not enabled for this Codex node. Please start it with the option '.EnableMarketplace(...)' to enable it.");
|
||||
if (codexAccess.GetEthAccount() == null) throw new Exception("Marketplace is not enabled for this Codex node. Please start it with the option '.EnableMarketplace(...)' to enable it.");
|
||||
}
|
||||
|
||||
private void Log(string msg)
|
||||
|
@ -1,15 +1,11 @@
|
||||
using CodexPlugin.Hooks;
|
||||
using Core;
|
||||
using GethPlugin;
|
||||
using KubernetesWorkflow;
|
||||
using KubernetesWorkflow.Types;
|
||||
|
||||
namespace CodexPlugin
|
||||
{
|
||||
public interface ICodexNodeFactory
|
||||
{
|
||||
CodexNode CreateOnlineCodexNode(CodexAccess access, CodexNodeGroup group);
|
||||
ContainerCrashWatcher CreateCrashWatcher(RunningContainer c);
|
||||
CodexNode CreateOnlineCodexNode(CodexAccess access);
|
||||
}
|
||||
|
||||
public class CodexNodeFactory : ICodexNodeFactory
|
||||
@ -23,31 +19,17 @@ namespace CodexPlugin
|
||||
this.codexHooksFactory = codexHooksFactory;
|
||||
}
|
||||
|
||||
public CodexNode CreateOnlineCodexNode(CodexAccess access, CodexNodeGroup group)
|
||||
public CodexNode CreateOnlineCodexNode(CodexAccess access)
|
||||
{
|
||||
var ethAccount = GetEthAccount(access);
|
||||
var hooks = codexHooksFactory.CreateHooks(access.Container.Name);
|
||||
|
||||
var marketplaceAccess = GetMarketplaceAccess(access, ethAccount, hooks);
|
||||
return new CodexNode(tools, access, group, marketplaceAccess, hooks, ethAccount);
|
||||
var hooks = codexHooksFactory.CreateHooks(access.GetName());
|
||||
var marketplaceAccess = GetMarketplaceAccess(access, hooks);
|
||||
return new CodexNode(tools, access, marketplaceAccess, hooks);
|
||||
}
|
||||
|
||||
private IMarketplaceAccess GetMarketplaceAccess(CodexAccess codexAccess, EthAccount? ethAccount, ICodexNodeHooks hooks)
|
||||
private IMarketplaceAccess GetMarketplaceAccess(CodexAccess codexAccess, ICodexNodeHooks hooks)
|
||||
{
|
||||
if (ethAccount == null) return new MarketplaceUnavailable();
|
||||
if (codexAccess.GetEthAccount() == null) return new MarketplaceUnavailable();
|
||||
return new MarketplaceAccess(tools.GetLog(), codexAccess, hooks);
|
||||
}
|
||||
|
||||
private EthAccount? GetEthAccount(CodexAccess access)
|
||||
{
|
||||
var ethAccount = access.Container.Containers.Single().Recipe.Additionals.Get<EthAccount>();
|
||||
if (ethAccount == null) return null;
|
||||
return ethAccount;
|
||||
}
|
||||
|
||||
public ContainerCrashWatcher CreateCrashWatcher(RunningContainer c)
|
||||
{
|
||||
return tools.CreateWorkflow().CreateCrashWatcher(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,18 +7,16 @@ namespace CodexPlugin
|
||||
{
|
||||
public interface ICodexNodeGroup : IEnumerable<ICodexNode>, IHasManyMetricScrapeTargets
|
||||
{
|
||||
void BringOffline(bool waitTillStopped);
|
||||
void Stop(bool waitTillStopped);
|
||||
ICodexNode this[int index] { get; }
|
||||
}
|
||||
|
||||
public class CodexNodeGroup : ICodexNodeGroup
|
||||
{
|
||||
private readonly CodexStarter starter;
|
||||
private CodexNode[] nodes;
|
||||
private readonly CodexNode[] nodes;
|
||||
|
||||
public CodexNodeGroup(CodexStarter starter, IPluginTools tools, CodexNode[] nodes)
|
||||
public CodexNodeGroup(IPluginTools tools, CodexNode[] nodes)
|
||||
{
|
||||
this.starter = starter;
|
||||
this.nodes = nodes;
|
||||
Version = new DebugInfoVersion();
|
||||
}
|
||||
@ -31,17 +29,14 @@ namespace CodexPlugin
|
||||
}
|
||||
}
|
||||
|
||||
public void BringOffline(bool waitTillStopped)
|
||||
public void Stop(bool waitTillStopped)
|
||||
{
|
||||
starter.BringOffline(this, waitTillStopped);
|
||||
// Clear everything. Prevent accidental use.
|
||||
nodes = Array.Empty<CodexNode>();
|
||||
foreach (var node in Nodes) node.Stop(waitTillStopped);
|
||||
}
|
||||
|
||||
public void Stop(CodexNode node, bool waitTillStopped)
|
||||
{
|
||||
starter.Stop(node, waitTillStopped);
|
||||
nodes = nodes.Where(n => n != node).ToArray();
|
||||
node.Stop(waitTillStopped);
|
||||
}
|
||||
|
||||
public ICodexNode[] Nodes => nodes;
|
||||
@ -65,7 +60,7 @@ namespace CodexPlugin
|
||||
|
||||
public void EnsureOnline()
|
||||
{
|
||||
foreach (var node in nodes) node.EnsureOnlineGetVersionResponse();
|
||||
foreach (var node in nodes) node.Initialize();
|
||||
var versionResponses = Nodes.Select(n => n.Version);
|
||||
|
||||
var first = versionResponses.First();
|
||||
@ -76,7 +71,6 @@ namespace CodexPlugin
|
||||
}
|
||||
|
||||
Version = first;
|
||||
foreach (var node in nodes) node.Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,16 @@ using GethPlugin;
|
||||
using KubernetesWorkflow;
|
||||
using KubernetesWorkflow.Types;
|
||||
using Logging;
|
||||
using Utils;
|
||||
|
||||
namespace CodexPlugin
|
||||
{
|
||||
public class CodexStarter
|
||||
public class CodexStarter : IProcessControl
|
||||
{
|
||||
private readonly IPluginTools pluginTools;
|
||||
private readonly CodexContainerRecipe recipe = new CodexContainerRecipe();
|
||||
private readonly ApiChecker apiChecker;
|
||||
private readonly Dictionary<ICodexInstance, RunningPod> podMap = new Dictionary<ICodexInstance, RunningPod>();
|
||||
private DebugInfoVersion? versionResponse;
|
||||
|
||||
public CodexStarter(IPluginTools pluginTools)
|
||||
@ -46,6 +48,17 @@ namespace CodexPlugin
|
||||
return containers;
|
||||
}
|
||||
|
||||
public void Stop(ICodexInstance instance, bool waitTillStopped)
|
||||
{
|
||||
Log($"Stopping node...");
|
||||
var pod = podMap[instance];
|
||||
podMap.Remove(instance);
|
||||
|
||||
var workflow = pluginTools.CreateWorkflow();
|
||||
workflow.Stop(pod, waitTillStopped);
|
||||
Log("Stopped.");
|
||||
}
|
||||
|
||||
public ICodexNodeGroup WrapCodexContainers(CoreInterface coreInterface, RunningPod[] containers)
|
||||
{
|
||||
var codexNodeFactory = new CodexNodeFactory(pluginTools, HooksFactory);
|
||||
@ -58,24 +71,6 @@ namespace CodexPlugin
|
||||
return group;
|
||||
}
|
||||
|
||||
public void BringOffline(CodexNodeGroup group, bool waitTillStopped)
|
||||
{
|
||||
Log($"Stopping {group.Describe()}...");
|
||||
foreach (var node in group)
|
||||
{
|
||||
node.Stop(waitTillStopped);
|
||||
}
|
||||
Log("Stopped.");
|
||||
}
|
||||
|
||||
public void Stop(CodexNode pod, bool waitTillStopped)
|
||||
{
|
||||
Log($"Stopping node...");
|
||||
var workflow = pluginTools.CreateWorkflow();
|
||||
workflow.Stop(pod, waitTillStopped);
|
||||
Log("Stopped.");
|
||||
}
|
||||
|
||||
public string GetCodexId()
|
||||
{
|
||||
if (versionResponse != null) return versionResponse.Version;
|
||||
@ -118,7 +113,10 @@ namespace CodexPlugin
|
||||
|
||||
private CodexNodeGroup CreateCodexGroup(CoreInterface coreInterface, RunningPod[] runningContainers, CodexNodeFactory codexNodeFactory)
|
||||
{
|
||||
var group = new CodexNodeGroup(this, pluginTools, runningContainers, codexNodeFactory);
|
||||
var instances = runningContainers.Select(CreateInstance).ToArray();
|
||||
var accesses = instances.Select(CreateAccess).ToArray();
|
||||
var nodes = accesses.Select(codexNodeFactory.CreateOnlineCodexNode).ToArray();
|
||||
var group = new CodexNodeGroup(pluginTools, nodes);
|
||||
|
||||
try
|
||||
{
|
||||
@ -133,6 +131,25 @@ namespace CodexPlugin
|
||||
return group;
|
||||
}
|
||||
|
||||
private CodexAccess CreateAccess(ICodexInstance instance)
|
||||
{
|
||||
var crashWatcher = CreateCrashWatcher(instance);
|
||||
return new CodexAccess(pluginTools, this, instance, crashWatcher);
|
||||
}
|
||||
|
||||
private ICrashWatcher CreateCrashWatcher(ICodexInstance instance)
|
||||
{
|
||||
var pod = podMap[instance];
|
||||
return pluginTools.CreateWorkflow().CreateCrashWatcher(pod.Containers.Single());
|
||||
}
|
||||
|
||||
private ICodexInstance CreateInstance(RunningPod pod)
|
||||
{
|
||||
var instance = new CodexContainerInstance(pluginTools, pluginTools.GetLog(), pod);
|
||||
podMap.Add(instance, pod);
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void CodexNodesNotOnline(CoreInterface coreInterface, RunningPod[] runningContainers)
|
||||
{
|
||||
Log("Codex nodes failed to start");
|
||||
|
7
ProjectPlugins/CodexPlugin/ProcessControl.cs
Normal file
7
ProjectPlugins/CodexPlugin/ProcessControl.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace CodexPlugin
|
||||
{
|
||||
public interface IProcessControl
|
||||
{
|
||||
void Stop(ICodexInstance instance, bool waitTillStopped);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user