diff --git a/CodexNetDeployer/ArgOrVar.cs b/CodexNetDeployer/ArgOrVar.cs index df70171..90c34ae 100644 --- a/CodexNetDeployer/ArgOrVar.cs +++ b/CodexNetDeployer/ArgOrVar.cs @@ -9,6 +9,7 @@ public static readonly ArgVar KubeNamespace = new ArgVar("kube-namespace", "KUBENAMESPACE", "Kubernetes namespace to be used for deployment."); public static readonly ArgVar NumberOfCodexNodes = new ArgVar("nodes", "NODES", "Number of Codex nodes to be created."); public static readonly ArgVar StorageQuota = new ArgVar("storage-quota", "STORAGEQUOTA", "Storage quota in megabytes used by each Codex node."); + public static readonly ArgVar LogLevel = new ArgVar("log-level", "LOGLEVEL", "Log level used by each Codex node. [Trace, Debug*, Info, Warn, Error]"); private readonly string[] args; @@ -53,11 +54,13 @@ "The deployer will set up the required supporting services, deploy the Codex on-chain contracts, start and bootstrap the Codex instances. " + "All Kubernetes objects will be created in the namespace provided, allowing you to easily find, modify, and delete them afterwards." + nl); + Console.WriteLine("CodexNetDeployer assumes you are running this tool from *outside* the Kubernetes cluster you want to deploy to. " + + "If you are running this from a container inside the cluster, add the argument '--internal'." + nl); Console.Write("\t[ CLI argument ] or [ Environment variable ]"); Console.CursorLeft = 70; Console.Write("(Description)" + nl); - var fields = GetType().GetFields();// System.Reflection.BindingFlags.Public & System.Reflection.BindingFlags.Static); + var fields = GetType().GetFields(); foreach (var field in fields) { var value = (ArgVar)field.GetValue(null)!; diff --git a/CodexNetDeployer/Configuration.cs b/CodexNetDeployer/Configuration.cs index 3abb7a4..0a3504c 100644 --- a/CodexNetDeployer/Configuration.cs +++ b/CodexNetDeployer/Configuration.cs @@ -1,4 +1,6 @@ -namespace CodexNetDeployer +using DistTestCore; + +namespace CodexNetDeployer { public class Configuration { @@ -9,7 +11,9 @@ string kubeConfigFile, string kubeNamespace, int? numberOfCodexNodes, - int? storageQuota) + int? storageQuota, + string codexLogLevel, + TestRunnerLocation runnerLocation) { CodexImage = codexImage; GethImage = gethImage; @@ -18,6 +22,8 @@ KubeNamespace = kubeNamespace; NumberOfCodexNodes = numberOfCodexNodes; StorageQuota = storageQuota; + CodexLogLevel = codexLogLevel; + RunnerLocation = runnerLocation; } public string CodexImage { get; } @@ -27,6 +33,8 @@ public string KubeNamespace { get; } public int? NumberOfCodexNodes { get; } public int? StorageQuota { get; } + public string CodexLogLevel { get; } + public TestRunnerLocation RunnerLocation { get; } public void PrintConfig() { diff --git a/CodexNetDeployer/Deployer.cs b/CodexNetDeployer/Deployer.cs new file mode 100644 index 0000000..0683e5c --- /dev/null +++ b/CodexNetDeployer/Deployer.cs @@ -0,0 +1,41 @@ +using DistTestCore; +using DistTestCore.Codex; +using Utils; + +namespace CodexNetDeployer +{ + public class Deployer + { + private readonly Configuration config; + + public Deployer(Configuration config) + { + this.config = config; + } + + public void Deploy() + { + var log = new NullLog(); + var lifecycleConfig = new DistTestCore.Configuration + ( + kubeConfigFile: config.KubeConfigFile, + logPath: "null", + logDebug: false, + dataFilesPath: "notUsed", + codexLogLevel: ParseEnum.Parse(config.CodexLogLevel), + runnerLocation: config.RunnerLocation + ); + + var timeset = new DefaultTimeSet(); + var kubeConfig = new KubernetesWorkflow.Configuration( + k8sNamespacePrefix: config.KubeNamespace, + kubeConfigFile: config.KubeConfigFile, + operationTimeout: timeset.K8sOperationTimeout(), + retryDelay: timeset.WaitForK8sServiceDelay()); + + var lifecycle = new TestLifecycle(log, lifecycleConfig, timeset); + var workflowCreator = new KubernetesWorkflow.WorkflowCreator(log, kubeConfig); + var starter = new CodexStarter(lifecycle, workflowCreator); + } + } +} diff --git a/CodexNetDeployer/NullLog.cs b/CodexNetDeployer/NullLog.cs new file mode 100644 index 0000000..c64190b --- /dev/null +++ b/CodexNetDeployer/NullLog.cs @@ -0,0 +1,41 @@ +using Logging; + +namespace CodexNetDeployer +{ + public class NullLog : TestLog + { + public NullLog() : base("NULL", false, "NULL") + { + } + + protected override LogFile CreateLogFile() + { + return null!; + } + + public override void Log(string message) + { + } + + public override void Debug(string message = "", int skipFrames = 0) + { + } + + public override void Error(string message) + { + Console.WriteLine("Error: " + message); + } + + public override void MarkAsFailed() + { + } + + public override void AddStringReplace(string from, string to) + { + } + + public override void Delete() + { + } + } +} diff --git a/CodexNetDeployer/Program.cs b/CodexNetDeployer/Program.cs index 64a445f..582d2a1 100644 --- a/CodexNetDeployer/Program.cs +++ b/CodexNetDeployer/Program.cs @@ -1,6 +1,8 @@ using CodexNetDeployer; +using DistTestCore; using DistTestCore.Codex; using DistTestCore.Marketplace; +using Configuration = CodexNetDeployer.Configuration; public class Program { @@ -17,6 +19,12 @@ public class Program return; } + var location = TestRunnerLocation.ExternalToCluster; + if (args.Any(a => a == "--internal")) + { + location = TestRunnerLocation.InternalToCluster; + } + var config = new Configuration( codexImage: argOrVar.Get(ArgOrVar.CodexImage, CodexContainerRecipe.DockerImage), gethImage: argOrVar.Get(ArgOrVar.GethImage, GethContainerRecipe.DockerImage), @@ -24,7 +32,9 @@ public class Program kubeConfigFile: argOrVar.Get(ArgOrVar.KubeConfigFile), kubeNamespace: argOrVar.Get(ArgOrVar.KubeNamespace), numberOfCodexNodes: argOrVar.GetInt(ArgOrVar.NumberOfCodexNodes), - storageQuota: argOrVar.GetInt(ArgOrVar.StorageQuota) + storageQuota: argOrVar.GetInt(ArgOrVar.StorageQuota), + codexLogLevel: argOrVar.Get(ArgOrVar.LogLevel), + runnerLocation: location ); Console.WriteLine("Using:"); @@ -41,6 +51,9 @@ public class Program return; } + var deployer = new Deployer(config); + deployer.Deploy(); + Console.WriteLine("Done!"); } } diff --git a/DistTestCore/Configuration.cs b/DistTestCore/Configuration.cs index af76127..03514cd 100644 --- a/DistTestCore/Configuration.cs +++ b/DistTestCore/Configuration.cs @@ -19,8 +19,18 @@ namespace DistTestCore logPath = GetEnvVarOrDefault("LOGPATH", "CodexTestLogs"); logDebug = GetEnvVarOrDefault("LOGDEBUG", "false").ToLowerInvariant() == "true"; dataFilesPath = GetEnvVarOrDefault("DATAFILEPATH", "TestDataFiles"); - codexLogLevel = ParseEnum(GetEnvVarOrDefault("LOGLEVEL", nameof(CodexLogLevel.Trace))); - runnerLocation = ParseEnum(GetEnvVarOrDefault("RUNNERLOCATION", nameof(TestRunnerLocation.ExternalToCluster))); + codexLogLevel = ParseEnum.Parse(GetEnvVarOrDefault("LOGLEVEL", nameof(CodexLogLevel.Trace))); + runnerLocation = ParseEnum.Parse(GetEnvVarOrDefault("RUNNERLOCATION", nameof(TestRunnerLocation.ExternalToCluster))); + } + + public Configuration(string? kubeConfigFile, string logPath, bool logDebug, string dataFilesPath, CodexLogLevel codexLogLevel, TestRunnerLocation runnerLocation) + { + this.kubeConfigFile = kubeConfigFile; + this.logPath = logPath; + this.logDebug = logDebug; + this.dataFilesPath = dataFilesPath; + this.codexLogLevel = codexLogLevel; + this.runnerLocation = runnerLocation; } public KubernetesWorkflow.Configuration GetK8sConfiguration(ITimeSet timeSet) @@ -75,11 +85,6 @@ namespace DistTestCore if (v == null) return defaultValue; return v; } - - private static T ParseEnum(string value) - { - return (T)Enum.Parse(typeof(T), value, true); - } } public enum TestRunnerLocation diff --git a/Logging/BaseLog.cs b/Logging/BaseLog.cs index 2c69f9c..c312256 100644 --- a/Logging/BaseLog.cs +++ b/Logging/BaseLog.cs @@ -25,12 +25,12 @@ namespace Logging } } - public void Log(string message) + public virtual void Log(string message) { LogFile.Write(ApplyReplacements(message)); } - public void Debug(string message = "", int skipFrames = 0) + public virtual void Debug(string message = "", int skipFrames = 0) { if (debug) { @@ -40,25 +40,25 @@ namespace Logging } } - public void Error(string message) + public virtual void Error(string message) { Log($"[ERROR] {message}"); } - public void MarkAsFailed() + public virtual void MarkAsFailed() { if (hasFailed) return; hasFailed = true; LogFile.ConcatToFilename("_FAILED"); } - public void AddStringReplace(string from, string to) + public virtual void AddStringReplace(string from, string to) { if (string.IsNullOrWhiteSpace(from)) return; replacements.Add(new BaseLogStringReplacement(from, to)); } - public void Delete() + public virtual void Delete() { File.Delete(LogFile.FullFilename); } diff --git a/Utils/ParseEnum.cs b/Utils/ParseEnum.cs new file mode 100644 index 0000000..3b3d0cb --- /dev/null +++ b/Utils/ParseEnum.cs @@ -0,0 +1,10 @@ +namespace Utils +{ + public static class ParseEnum + { + public static T Parse(string value) + { + return (T)Enum.Parse(typeof(T), value, true); + } + } +}