diff --git a/Framework/Core/Http.cs b/Framework/Core/Http.cs index 968bdb7..192152f 100644 --- a/Framework/Core/Http.cs +++ b/Framework/Core/Http.cs @@ -93,7 +93,7 @@ namespace Core { var response = PostJsonString(route, body); if (response == null) throw new Exception("Received no response."); - var result = JsonConvert.DeserializeObject(response); + var result = Deserialize(response); if (result == null) throw new Exception("Failed to deserialize response"); return result; }, $"HTTO-POST-JSON: {route}"); diff --git a/Framework/KubernetesWorkflow/ContainerRecipe.cs b/Framework/KubernetesWorkflow/ContainerRecipe.cs index 5123b8d..4cc5099 100644 --- a/Framework/KubernetesWorkflow/ContainerRecipe.cs +++ b/Framework/KubernetesWorkflow/ContainerRecipe.cs @@ -112,15 +112,21 @@ public class VolumeMount { - public VolumeMount(string volumeName, string mountPath, string resourceQuantity) + public VolumeMount(string volumeName, string mountPath, string? subPath = null, string? resourceQuantity = null, string? secret = null, string? hostPath = null) { VolumeName = volumeName; MountPath = mountPath; + SubPath = subPath; ResourceQuantity = resourceQuantity; + Secret = secret; + HostPath = hostPath; } public string VolumeName { get; } public string MountPath { get; } - public string ResourceQuantity { get; } + public string? SubPath { get; } + public string? ResourceQuantity { get; } + public string? Secret { get; } + public string? HostPath { get; } } } diff --git a/Framework/KubernetesWorkflow/ContainerRecipeFactory.cs b/Framework/KubernetesWorkflow/ContainerRecipeFactory.cs index 5fa9980..d5273dd 100644 --- a/Framework/KubernetesWorkflow/ContainerRecipeFactory.cs +++ b/Framework/KubernetesWorkflow/ContainerRecipeFactory.cs @@ -97,12 +97,18 @@ namespace KubernetesWorkflow podAnnotations.Add(name, value); } + protected void AddVolume(string name, string mountPath, string? subPath = null, string? secret = null, string? hostPath = null) + { + var size = 10.MB().ToSuffixNotation(); + volumeMounts.Add(new VolumeMount(name, mountPath, subPath, size, secret, hostPath)); + } + protected void AddVolume(string mountPath, ByteSize volumeSize) { volumeMounts.Add(new VolumeMount( $"autovolume-{Guid.NewGuid().ToString().ToLowerInvariant()}", mountPath, - volumeSize.ToSuffixNotation())); + resourceQuantity: volumeSize.ToSuffixNotation())); } protected void Additional(object userData) diff --git a/Framework/KubernetesWorkflow/K8sController.cs b/Framework/KubernetesWorkflow/K8sController.cs index f77b473..422e167 100644 --- a/Framework/KubernetesWorkflow/K8sController.cs +++ b/Framework/KubernetesWorkflow/K8sController.cs @@ -9,15 +9,14 @@ namespace KubernetesWorkflow { private readonly ILog log; private readonly K8sCluster cluster; - private readonly KnownK8sPods knownPods; private readonly WorkflowNumberSource workflowNumberSource; private readonly K8sClient client; + private const string podLabelKey = "pod-uuid"; - public K8sController(ILog log, K8sCluster cluster, KnownK8sPods knownPods, WorkflowNumberSource workflowNumberSource, string k8sNamespace) + public K8sController(ILog log, K8sCluster cluster, WorkflowNumberSource workflowNumberSource, string k8sNamespace) { this.log = log; this.cluster = cluster; - this.knownPods = knownPods; this.workflowNumberSource = workflowNumberSource; client = new K8sClient(cluster.GetK8sClientConfig()); @@ -34,13 +33,30 @@ namespace KubernetesWorkflow log.Debug(); EnsureNamespace(); - var deploymentName = CreateDeployment(containerRecipes, location); + var podLabel = K8sNameUtils.Format(Guid.NewGuid().ToString()); + var deploymentName = CreateDeployment(containerRecipes, location, podLabel); var (serviceName, servicePortsMap) = CreateService(containerRecipes); - var podInfo = FetchNewPod(); + + var pod = FindPodByLabel(podLabel); + var podInfo = CreatePodInfo(pod); return new RunningPod(cluster, podInfo, deploymentName, serviceName, servicePortsMap.ToArray()); } + private V1Pod FindPodByLabel(string podLabel) + { + var pods = client.Run(c => c.ListNamespacedPod(K8sNamespace)); + foreach (var pod in pods.Items) + { + var label = pod.GetLabel(podLabelKey); + if (label == podLabel) + { + return pod; + } + } + throw new Exception("Unable to find pod by label."); + } + public void Stop(RunningPod pod) { log.Debug(); @@ -299,7 +315,7 @@ namespace KubernetesWorkflow #region Deployment management - private string CreateDeployment(ContainerRecipe[] containerRecipes, ILocation location) + private string CreateDeployment(ContainerRecipe[] containerRecipes, ILocation location, string podLabel) { var deploymentSpec = new V1Deployment { @@ -316,7 +332,7 @@ namespace KubernetesWorkflow { Metadata = new V1ObjectMeta { - Labels = GetSelector(containerRecipes), + Labels = GetSelector(containerRecipes, podLabel), Annotations = GetAnnotations(containerRecipes) }, Spec = new V1PodSpec @@ -363,6 +379,13 @@ namespace KubernetesWorkflow return containerRecipes.First().PodLabels.GetLabels(); } + private IDictionary GetSelector(ContainerRecipe[] containerRecipes, string podLabel) + { + var labels = containerRecipes.First().PodLabels.Clone(); + labels.Add(podLabelKey, podLabel); + return labels.GetLabels(); + } + private IDictionary GetRunnerNamespaceSelector() { return new Dictionary { { "kubernetes.io/metadata.name", "default" } }; @@ -441,7 +464,8 @@ namespace KubernetesWorkflow return new V1VolumeMount { Name = v.VolumeName, - MountPath = v.MountPath + MountPath = v.MountPath, + SubPath = v.SubPath, }; } @@ -457,28 +481,28 @@ namespace KubernetesWorkflow private V1Volume CreateVolume(VolumeMount v) { - client.Run(c => c.CreateNamespacedPersistentVolumeClaim(new V1PersistentVolumeClaim + CreatePersistentVolumeClaimIfNeeded(v); + + if (!string.IsNullOrEmpty(v.HostPath)) { - ApiVersion = "v1", - Metadata = new V1ObjectMeta + return new V1Volume { - Name = v.VolumeName - }, - Spec = new V1PersistentVolumeClaimSpec - { - AccessModes = new List + Name = v.VolumeName, + HostPath = new V1HostPathVolumeSource { - "ReadWriteOnce" - }, - Resources = new V1ResourceRequirements - { - Requests = new Dictionary - { - {"storage", new ResourceQuantity(v.ResourceQuantity) } - } + Path = v.HostPath } - } - }, K8sNamespace)); + }; + } + + if (!string.IsNullOrEmpty(v.Secret)) + { + return new V1Volume + { + Name = v.VolumeName, + Secret = CreateVolumeSecret(v) + }; + } return new V1Volume { @@ -490,6 +514,50 @@ namespace KubernetesWorkflow }; } + private void CreatePersistentVolumeClaimIfNeeded(VolumeMount v) + { + var pvcs = client.Run(c => c.ListNamespacedPersistentVolumeClaim(K8sNamespace)); + if (pvcs != null && pvcs.Items.Any(i => i.Name() == v.VolumeName)) return; + + client.Run(c => c.CreateNamespacedPersistentVolumeClaim(new V1PersistentVolumeClaim + { + ApiVersion = "v1", + Metadata = new V1ObjectMeta + { + Name = v.VolumeName, + }, + Spec = new V1PersistentVolumeClaimSpec + { + AccessModes = new List + { + "ReadWriteOnce" + }, + Resources = CreateVolumeResourceRequirements(v), + }, + }, K8sNamespace)); + } + + private V1SecretVolumeSource CreateVolumeSecret(VolumeMount v) + { + if (string.IsNullOrWhiteSpace(v.Secret)) return null!; + return new V1SecretVolumeSource + { + SecretName = v.Secret + }; + } + + private V1ResourceRequirements CreateVolumeResourceRequirements(VolumeMount v) + { + if (v.ResourceQuantity == null) return null!; + return new V1ResourceRequirements + { + Requests = new Dictionary() + { + {"storage", new ResourceQuantity(v.ResourceQuantity) } + } + }; + } + private List CreateEnv(ContainerRecipe recipe) { return recipe.EnvVars.Select(CreateEnvVar).ToList(); @@ -720,22 +788,15 @@ namespace KubernetesWorkflow return new CrashWatcher(log, cluster.GetK8sClientConfig(), K8sNamespace, container); } - private PodInfo FetchNewPod() + private PodInfo CreatePodInfo(V1Pod pod) { - var pods = client.Run(c => c.ListNamespacedPod(K8sNamespace)).Items; - - var newPods = pods.Where(p => !knownPods.Contains(p.Name())).ToArray(); - if (newPods.Length != 1) throw new InvalidOperationException("Expected only 1 pod to be created. Test infra failure."); - - var newPod = newPods.Single(); - var name = newPod.Name(); - var ip = newPod.Status.PodIP; - var k8sNodeName = newPod.Spec.NodeName; + var name = pod.Name(); + var ip = pod.Status.PodIP; + var k8sNodeName = pod.Spec.NodeName; if (string.IsNullOrEmpty(name)) throw new InvalidOperationException("Invalid pod name received. Test infra failure."); if (string.IsNullOrEmpty(ip)) throw new InvalidOperationException("Invalid pod IP received. Test infra failure."); - knownPods.Add(name); return new PodInfo(name, ip, k8sNodeName); } } diff --git a/Framework/KubernetesWorkflow/KnownK8sPods.cs b/Framework/KubernetesWorkflow/KnownK8sPods.cs deleted file mode 100644 index 6d80eb6..0000000 --- a/Framework/KubernetesWorkflow/KnownK8sPods.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace KubernetesWorkflow -{ - public class KnownK8sPods - { - private readonly List knownActivePodNames = new List(); - - public bool Contains(string name) - { - return knownActivePodNames.Contains(name); - } - - public void Add(string name) - { - knownActivePodNames.Add(name); - } - } -} diff --git a/Framework/KubernetesWorkflow/StartupWorkflow.cs b/Framework/KubernetesWorkflow/StartupWorkflow.cs index 1cd5eb1..b34cb75 100644 --- a/Framework/KubernetesWorkflow/StartupWorkflow.cs +++ b/Framework/KubernetesWorkflow/StartupWorkflow.cs @@ -22,17 +22,15 @@ namespace KubernetesWorkflow private readonly ILog log; private readonly WorkflowNumberSource numberSource; private readonly K8sCluster cluster; - private readonly KnownK8sPods knownK8SPods; private readonly string k8sNamespace; private readonly RecipeComponentFactory componentFactory = new RecipeComponentFactory(); private readonly LocationProvider locationProvider; - internal StartupWorkflow(ILog log, WorkflowNumberSource numberSource, K8sCluster cluster, KnownK8sPods knownK8SPods, string k8sNamespace) + internal StartupWorkflow(ILog log, WorkflowNumberSource numberSource, K8sCluster cluster, string k8sNamespace) { this.log = log; this.numberSource = numberSource; this.cluster = cluster; - this.knownK8SPods = knownK8SPods; this.k8sNamespace = k8sNamespace; locationProvider = new LocationProvider(log, K8s); @@ -196,7 +194,7 @@ namespace KubernetesWorkflow { try { - var controller = new K8sController(log, cluster, knownK8SPods, numberSource, k8sNamespace); + var controller = new K8sController(log, cluster, numberSource, k8sNamespace); action(controller); controller.Dispose(); } @@ -211,7 +209,7 @@ namespace KubernetesWorkflow { try { - var controller = new K8sController(log, cluster, knownK8SPods, numberSource, k8sNamespace); + var controller = new K8sController(log, cluster, numberSource, k8sNamespace); var result = action(controller); controller.Dispose(); return result; diff --git a/Framework/KubernetesWorkflow/WorkflowCreator.cs b/Framework/KubernetesWorkflow/WorkflowCreator.cs index 213db92..d70b0bc 100644 --- a/Framework/KubernetesWorkflow/WorkflowCreator.cs +++ b/Framework/KubernetesWorkflow/WorkflowCreator.cs @@ -7,7 +7,6 @@ namespace KubernetesWorkflow { private readonly NumberSource numberSource = new NumberSource(0); private readonly NumberSource containerNumberSource = new NumberSource(0); - private readonly KnownK8sPods knownPods = new KnownK8sPods(); private readonly K8sCluster cluster; private readonly ILog log; private readonly Configuration configuration; @@ -26,7 +25,7 @@ namespace KubernetesWorkflow var workflowNumberSource = new WorkflowNumberSource(numberSource.GetNextNumber(), containerNumberSource); - return new StartupWorkflow(log, workflowNumberSource, cluster, knownPods, GetNamespace(namespaceOverride)); + return new StartupWorkflow(log, workflowNumberSource, cluster, GetNamespace(namespaceOverride)); } private string GetNamespace(string? namespaceOverride) diff --git a/ProjectPlugins/DeployAndRunPlugin/CoreInterfaceExtensions.cs b/ProjectPlugins/DeployAndRunPlugin/CoreInterfaceExtensions.cs new file mode 100644 index 0000000..262e27d --- /dev/null +++ b/ProjectPlugins/DeployAndRunPlugin/CoreInterfaceExtensions.cs @@ -0,0 +1,13 @@ +using Core; +using KubernetesWorkflow; + +namespace DeployAndRunPlugin +{ + public static class CoreInterfaceExtensions + { + public static RunningContainer DeployAndRunContinuousTests(this CoreInterface ci, RunConfig runConfig) + { + return ci.GetPlugin().Run(runConfig); + } + } +} diff --git a/ProjectPlugins/DeployAndRunPlugin/DeployAndRunContainerRecipe.cs b/ProjectPlugins/DeployAndRunPlugin/DeployAndRunContainerRecipe.cs new file mode 100644 index 0000000..9692225 --- /dev/null +++ b/ProjectPlugins/DeployAndRunPlugin/DeployAndRunContainerRecipe.cs @@ -0,0 +1,49 @@ +using KubernetesWorkflow; + +namespace DeployAndRunPlugin +{ + public class DeployAndRunContainerRecipe : ContainerRecipeFactory + { + public override string AppName => "deploy-and-run"; + public override string Image => "thatbenbierens/dist-tests-deployandrun:initial"; + + protected override void Initialize(StartupConfig config) + { + var setup = config.Get(); + + if (setup.CodexImageOverride != null) + { + AddEnvVar("CODEXDOCKERIMAGE", setup.CodexImageOverride); + } + + AddEnvVar("DNR_REP", setup.Replications.ToString()); + AddEnvVar("DNR_NAME", setup.Name); + AddEnvVar("DNR_FILTER", setup.Filter); + AddEnvVar("DNR_DURATION", setup.Duration.TotalSeconds.ToString()); + + AddEnvVar("KUBECONFIG", "/opt/kubeconfig.yaml"); + AddEnvVar("LOGPATH", "/var/log/codex-continuous-tests"); + + AddVolume(name: "kubeconfig", mountPath: "/opt/kubeconfig.yaml", subPath: "kubeconfig.yaml", secret: "codex-dist-tests-app-kubeconfig"); + AddVolume(name: "logs", mountPath: "/var/log/codex-continuous-tests", hostPath: "/var/log/codex-continuous-tests"); + } + } + + public class RunConfig + { + public RunConfig(string name, string filter, TimeSpan duration, int replications, string? codexImageOverride = null) + { + Name = name; + Filter = filter; + Duration = duration; + Replications = replications; + CodexImageOverride = codexImageOverride; + } + + public string Name { get; } + public string Filter { get; } + public TimeSpan Duration { get; } + public int Replications { get; } + public string? CodexImageOverride { get; } + } +} \ No newline at end of file diff --git a/ProjectPlugins/DeployAndRunPlugin/DeployAndRunPlugin.cs b/ProjectPlugins/DeployAndRunPlugin/DeployAndRunPlugin.cs new file mode 100644 index 0000000..82d80e0 --- /dev/null +++ b/ProjectPlugins/DeployAndRunPlugin/DeployAndRunPlugin.cs @@ -0,0 +1,36 @@ +using Core; +using KubernetesWorkflow; + +namespace DeployAndRunPlugin +{ + public class DeployAndRunPlugin : IProjectPlugin + { + private readonly IPluginTools tools; + + public DeployAndRunPlugin(IPluginTools tools) + { + this.tools = tools; + } + + public void Announce() + { + tools.GetLog().Log("Deploy-and-Run plugin loaded."); + } + + public void Decommission() + { + } + + public RunningContainer Run(RunConfig config) + { + var workflow = tools.CreateWorkflow(); + var startupConfig = new StartupConfig(); + startupConfig.NameOverride = "dnr-" + config.Name; + startupConfig.Add(config); + + var location = workflow.GetAvailableLocations().Get("fixed-s-4vcpu-16gb-amd-yz8rd"); + var containers = workflow.Start(1, location, new DeployAndRunContainerRecipe(), startupConfig); + return containers.Containers.Single(); + } + } +} diff --git a/ProjectPlugins/DeployAndRunPlugin/DeployAndRunPlugin.csproj b/ProjectPlugins/DeployAndRunPlugin/DeployAndRunPlugin.csproj new file mode 100644 index 0000000..66d0737 --- /dev/null +++ b/ProjectPlugins/DeployAndRunPlugin/DeployAndRunPlugin.csproj @@ -0,0 +1,14 @@ + + + + net7.0 + enable + enable + + + + + + + + diff --git a/Tests/CodexContinuousTests/ContinuousTestRunner.cs b/Tests/CodexContinuousTests/ContinuousTestRunner.cs index 2566d1d..8461f7f 100644 --- a/Tests/CodexContinuousTests/ContinuousTestRunner.cs +++ b/Tests/CodexContinuousTests/ContinuousTestRunner.cs @@ -53,22 +53,25 @@ namespace ContinuousTests if (!filteredTests.Any()) { overviewLog.Log("No tests selected."); - return; + Cancellation.Cts.Cancel(); } - var testLoops = filteredTests.Select(t => new TestLoop(entryPointFactory, taskFactory, config, overviewLog, t.GetType(), t.RunTestEvery, startupChecker, cancelToken)).ToArray(); - - foreach (var testLoop in testLoops) + else { - if (cancelToken.IsCancellationRequested) break; + var testLoops = filteredTests.Select(t => new TestLoop(entryPointFactory, taskFactory, config, overviewLog, t.GetType(), t.RunTestEvery, startupChecker, cancelToken)).ToArray(); - overviewLog.Log("Launching test-loop for " + testLoop.Name); - testLoop.Begin(); - Thread.Sleep(TimeSpan.FromSeconds(5)); + foreach (var testLoop in testLoops) + { + if (cancelToken.IsCancellationRequested) break; + + overviewLog.Log("Launching test-loop for " + testLoop.Name); + testLoop.Begin(); + Thread.Sleep(TimeSpan.FromSeconds(5)); + } + + overviewLog.Log("Finished launching test-loops."); + WaitUntilFinished(overviewLog, statusLog, startTime, testLoops); + overviewLog.Log("Stopping all test-loops..."); } - - overviewLog.Log("Finished launching test-loops."); - WaitUntilFinished(overviewLog, statusLog, startTime, testLoops); - overviewLog.Log("Stopping all test-loops..."); taskFactory.WaitAll(); overviewLog.Log("All tasks cancelled."); diff --git a/Tests/CodexContinuousTests/deploy-and-run.sh b/Tests/CodexContinuousTests/deploy-and-run.sh index fdd620c..3d778ad 100644 --- a/Tests/CodexContinuousTests/deploy-and-run.sh +++ b/Tests/CodexContinuousTests/deploy-and-run.sh @@ -1,8 +1,9 @@ set -e -replication=5 -name=testnamehere -filter=TwoClient +replication=$DNR_REP +name=$DNR_NAME +filter=$DNR_FILTER +duration=$DNR_DURATION echo "Deploying..." cd ../../Tools/CodexNetDeployer @@ -45,7 +46,10 @@ do --filter=$filter \ --cleanup=1 \ --full-container-logs=1 \ - --target-duration=172800 # 48 hours + --target-duration=$duration sleep 30 done + +echo "Done! Sleeping indefinitely..." +while true; do sleep 1d; done diff --git a/Tools/TestClusterStarter/ClusterTestSpec.cs b/Tools/TestClusterStarter/ClusterTestSpec.cs new file mode 100644 index 0000000..88b18c2 --- /dev/null +++ b/Tools/TestClusterStarter/ClusterTestSpec.cs @@ -0,0 +1,42 @@ +using KubernetesWorkflow; + +namespace TestClusterStarter +{ + public class ClusterTestSetup + { + public ClusterTestSetup(ClusterTestSpec[] specs) + { + Specs = specs; + } + + public ClusterTestSpec[] Specs { get; } + } + + public class ClusterTestSpec + { + public ClusterTestSpec(string name, string filter, int replication, int durationSeconds, string? codexImageOverride) + { + Name = name; + Filter = filter; + Replication = replication; + DurationSeconds = durationSeconds; + CodexImageOverride = codexImageOverride; + } + + public string Name { get; } + public string Filter { get; } + public int Replication { get; } + public int DurationSeconds { get; } + public string? CodexImageOverride { get; } + } + + public class ClusterTestDeployment + { + public ClusterTestDeployment(RunningContainer[] containers) + { + Containers = containers; + } + + public RunningContainer[] Containers { get; } + } +} diff --git a/Tools/TestClusterStarter/Configuration.cs b/Tools/TestClusterStarter/Configuration.cs new file mode 100644 index 0000000..8e30d93 --- /dev/null +++ b/Tools/TestClusterStarter/Configuration.cs @@ -0,0 +1,10 @@ +using ArgsUniform; + +namespace TestClusterStarter +{ + public class Configuration + { + [Uniform("kube-config", "kc", "KUBECONFIG", true, "Path to Kubeconfig file. Use 'null' (default) to use local cluster.")] + public string KubeConfigFile { get; set; } = "null"; + } +} diff --git a/Tools/TestClusterStarter/Program.cs b/Tools/TestClusterStarter/Program.cs new file mode 100644 index 0000000..2830661 --- /dev/null +++ b/Tools/TestClusterStarter/Program.cs @@ -0,0 +1,50 @@ +using ArgsUniform; +using Core; +using DeployAndRunPlugin; +using KubernetesWorkflow; +using Logging; +using Newtonsoft.Json; +using TestClusterStarter; + +public class Program +{ + private const string SpecsFile = "TestSpecs.json"; + + public static void Main(string[] args) + { + var argsUniform = new ArgsUniform(() => { }, args); + var config = argsUniform.Parse(); + + ProjectPlugin.Load(); + + if (!File.Exists(SpecsFile)) + { + File.WriteAllText(SpecsFile, JsonConvert.SerializeObject(new ClusterTestSetup(new[] + { + new ClusterTestSpec("example", "peer", 2, Convert.ToInt32(TimeSpan.FromDays(2).TotalSeconds), "imageoverride") + }))); + return; + } + var specs = JsonConvert.DeserializeObject(File.ReadAllText(SpecsFile))!; + + var kConfig = new KubernetesWorkflow.Configuration(config.KubeConfigFile, TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(10), kubernetesNamespace: "default"); + var entryPoint = new EntryPoint(new ConsoleLog(), kConfig, "datafolder"); + var ci = entryPoint.CreateInterface(); + + var rcs = new List(); + foreach (var spec in specs.Specs) + { + var rc = ci.DeployAndRunContinuousTests(new RunConfig( + name: spec.Name, + filter: spec.Filter, + duration: TimeSpan.FromSeconds(spec.DurationSeconds), + replications: spec.Replication, + codexImageOverride: spec.CodexImageOverride)); + + rcs.Add(rc); + } + + var deployment = new ClusterTestDeployment(rcs.ToArray()); + File.WriteAllText("clustertest-deployment.json", JsonConvert.SerializeObject(deployment, Formatting.Indented)); + } +} diff --git a/Tools/TestClusterStarter/TestClusterStarter.csproj b/Tools/TestClusterStarter/TestClusterStarter.csproj new file mode 100644 index 0000000..5522cbe --- /dev/null +++ b/Tools/TestClusterStarter/TestClusterStarter.csproj @@ -0,0 +1,21 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + + + + + + + + diff --git a/cs-codex-dist-testing.sln b/cs-codex-dist-testing.sln index 585e002..944f83b 100644 --- a/cs-codex-dist-testing.sln +++ b/cs-codex-dist-testing.sln @@ -47,6 +47,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BiblioTech", "Tools\BiblioT EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodexDiscordBotPlugin", "ProjectPlugins\CodexDiscordBotPlugin\CodexDiscordBotPlugin.csproj", "{FB96A58B-F7F0-490A-9A85-72A96A018042}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestClusterStarter", "Tools\TestClusterStarter\TestClusterStarter.csproj", "{3E38A906-C2FC-43DC-8CA2-FC07C79CF3CA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeployAndRunPlugin", "ProjectPlugins\DeployAndRunPlugin\DeployAndRunPlugin.csproj", "{1CC5AF82-8924-4C7E-BFF1-3125D86E53FB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -125,6 +129,14 @@ Global {FB96A58B-F7F0-490A-9A85-72A96A018042}.Debug|Any CPU.Build.0 = Debug|Any CPU {FB96A58B-F7F0-490A-9A85-72A96A018042}.Release|Any CPU.ActiveCfg = Release|Any CPU {FB96A58B-F7F0-490A-9A85-72A96A018042}.Release|Any CPU.Build.0 = Release|Any CPU + {3E38A906-C2FC-43DC-8CA2-FC07C79CF3CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E38A906-C2FC-43DC-8CA2-FC07C79CF3CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E38A906-C2FC-43DC-8CA2-FC07C79CF3CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E38A906-C2FC-43DC-8CA2-FC07C79CF3CA}.Release|Any CPU.Build.0 = Release|Any CPU + {1CC5AF82-8924-4C7E-BFF1-3125D86E53FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CC5AF82-8924-4C7E-BFF1-3125D86E53FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CC5AF82-8924-4C7E-BFF1-3125D86E53FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CC5AF82-8924-4C7E-BFF1-3125D86E53FB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -148,6 +160,8 @@ Global {3417D508-E2F4-4974-8988-BB124046D9E2} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3} {078ABA6D-A04E-4F62-A44C-EA66F1B66548} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3} {FB96A58B-F7F0-490A-9A85-72A96A018042} = {8F1F1C2A-E313-4E0C-BE40-58FB0BA91124} + {3E38A906-C2FC-43DC-8CA2-FC07C79CF3CA} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3} + {1CC5AF82-8924-4C7E-BFF1-3125D86E53FB} = {8F1F1C2A-E313-4E0C-BE40-58FB0BA91124} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {237BF0AA-9EC4-4659-AD9A-65DEB974250C} diff --git a/docker/build-deployandrun.bat b/docker/build-deployandrun.bat new file mode 100644 index 0000000..8af14b0 --- /dev/null +++ b/docker/build-deployandrun.bat @@ -0,0 +1,2 @@ +docker build -f deployandrun.Dockerfile -t thatbenbierens/dist-tests-deployandrun:initial .. +docker push thatbenbierens/dist-tests-deployandrun:initial diff --git a/docker/deployandrun.Dockerfile b/docker/deployandrun.Dockerfile new file mode 100644 index 0000000..869f017 --- /dev/null +++ b/docker/deployandrun.Dockerfile @@ -0,0 +1,12 @@ +FROM mcr.microsoft.com/dotnet/sdk:7.0 + +RUN apt-get update && apt-get install -y screen +WORKDIR /app +COPY --chmod=0755 docker/docker-dnr-entrypoint.sh / +COPY ./Tools ./Tools +COPY ./Tests ./Tests +COPY ./Framework ./Framework +COPY ./ProjectPlugins ./ProjectPlugins + +ENTRYPOINT ["/docker-dnr-entrypoint.sh"] +CMD ["/bin/bash", "deploy-and-run.sh"] diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 98af246..510f654 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -9,3 +9,12 @@ services: - KUBECONFIG=/opt/kubeconfig - LOGPATH=/opt/logs - RUNNERLOCATION=ExternalToCluster + + continuous-test-run: + image: thatbenbierens/dist-tests-deployandrun:initial + environment: + # - CODEXDOCKERIMAGE=imageoverride + - DNR_REP=3 + - DNR_NAME=Tryout + - DNR_FILTER=PeernBeer + - DNR_DURATION=172800 diff --git a/docker/docker-dnr-entrypoint.sh b/docker/docker-dnr-entrypoint.sh new file mode 100644 index 0000000..5475acb --- /dev/null +++ b/docker/docker-dnr-entrypoint.sh @@ -0,0 +1,5 @@ +#!/bin/bash +echo "Running continuous tests..." +cd /app/Tests/CodexContinuousTests +exec "$@" +