Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Octopus.Tentacle.Kubernetes.Tests.Integration.KubernetesAgent;

public abstract class KubernetesAgentIntegrationTest
public abstract class KubernetesAgentIntegrationTest(int agentMajorVersion)
{
KubernetesAgentInstaller? kubernetesAgentInstaller;
KubeCtlTool? kubeCtl;
Expand All @@ -27,10 +27,12 @@ public abstract class KubernetesAgentIntegrationTest

protected readonly IDictionary<string, string> CustomHelmValues = new Dictionary<string, string>();

HalibutRuntime serverHalibutRuntime;
HalibutRuntime serverHalibutRuntime = null!;

string? agentThumbprint;

protected int AgentMajorVersion { get; } = agentMajorVersion;

[OneTimeSetUp]
public async Task OneTimeSetUp()
{
Expand All @@ -39,6 +41,7 @@ public async Task OneTimeSetUp()
KubernetesTestsGlobalContext.Instance.HelmExePath,
KubernetesTestsGlobalContext.Instance.KubeCtlExePath,
KubernetesTestsGlobalContext.Instance.KubeConfigPath,
AgentMajorVersion,
KubernetesTestsGlobalContext.Instance.Logger);

kubeCtl = new KubeCtlTool(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Octopus.Tentacle.Kubernetes.Tests.Integration.KubernetesAgent;

public class KubernetesAgentMetricsIntegrationTest : KubernetesAgentIntegrationTest
public class KubernetesAgentMetricsIntegrationTest() : KubernetesAgentIntegrationTest(KubernetesAgentMajorVersion.Latest)
{
readonly ISystemLog systemLog = new SystemLog();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@

namespace Octopus.Tentacle.Kubernetes.Tests.Integration.KubernetesAgent;

[TestFixture]
public class KubernetesScriptServiceV1IntegrationTest : KubernetesAgentIntegrationTest
[TestFixture(KubernetesAgentMajorVersion.V2)]
[TestFixture(KubernetesAgentMajorVersion.V3)]
public class KubernetesScriptServiceV1IntegrationTest(int agentMajorVersion) : KubernetesAgentIntegrationTest(agentMajorVersion)
{
IRecordedMethodUsages recordedMethodUsages = null!;

Expand Down Expand Up @@ -196,7 +197,7 @@ public async Task TentaclePodIsTerminatedDuringScriptExecution_ShouldRestartAndP
// Arrange
var logs = new List<ProcessOutput>();
var scriptCompleted = false;
const int count = 100;
const int count = 60;
var semaphoreSlim = new SemaphoreSlim(0, 1);

var builder = new ExecuteKubernetesScriptCommandBuilder(LoggingUtils.CurrentTestHash())
Expand Down Expand Up @@ -341,6 +342,11 @@ Task ScriptCompleted(CancellationToken ct)
[Test]
public async Task NfsPodIsTerminatedDuringNormalScriptExecution_ScriptFails()
{
if (AgentMajorVersion != KubernetesAgentMajorVersion.V2)
{
Assert.Ignore("NFS is only tested against V2");
}

// Arrange
var logs = new List<ProcessOutput>();
var scriptCompleted = false;
Expand Down Expand Up @@ -395,6 +401,11 @@ Task ScriptCompleted(CancellationToken ct)
[Test]
public async Task NfsPodIsTerminatedDuringRawScriptExecution_ShouldRestartAndPickUpPodStatus()
{
if (AgentMajorVersion != KubernetesAgentMajorVersion.V2)
{
Assert.Ignore("NFS is only tested against V2");
}

// Arrange
var logs = new List<ProcessOutput>();
var scriptCompleted = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Octopus.Tentacle.Kubernetes.Tests.Integration;

public static class KubernetesAgentMajorVersion
{
public const int V2 = 2;
public const int V3 = 3;

public static int Latest => V3;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ public class KubernetesClientCompatibilityTests
{
static readonly object[] TestClusterVersions =
[
new object[] {new ClusterVersion(1, 35)},
new object[] {new ClusterVersion(1, 34)},
new object[] {new ClusterVersion(1, 33)}
new object[] { new ClusterVersion(1, 35) },
new object[] { new ClusterVersion(1, 34) },
new object[] { new ClusterVersion(1, 33) }
];

KubernetesTestsGlobalContext? testContext;
Expand Down Expand Up @@ -66,6 +66,7 @@ public async Task TearDown()
await cancellationTokenSource.CancelAsync();
cancellationTokenSource.Dispose();
}

clusterInstaller?.Dispose();
testContext?.Dispose();

Expand All @@ -76,11 +77,11 @@ public async Task TearDown()
}

[Test]
[TestCaseSource(nameof(TestClusterVersions))]
public async Task RunSimpleScript(ClusterVersion clusterVersion)
[Combinatorial]
public async Task RunSimpleScript([ValueSource(nameof(TestClusterVersions))] ClusterVersion clusterVersion, [Values(KubernetesAgentMajorVersion.V2, KubernetesAgentMajorVersion.V3)] int agentVersion)
{
await SetUp(clusterVersion);
await SetUp(clusterVersion, agentVersion);

// Arrange
var logs = new List<ProcessOutput>();
var scriptCompleted = false;
Expand Down Expand Up @@ -120,18 +121,19 @@ Task ScriptCompleted(CancellationToken ct)
return Task.CompletedTask;
}
}
async Task SetUp(ClusterVersion clusterVersion)

async Task SetUp(ClusterVersion clusterVersion, int agentMajorVersion)
{
testContext = new KubernetesTestsGlobalContext(logger);

await SetupCluster(clusterVersion);

kubernetesAgentInstaller = new KubernetesAgentInstaller(
testContext.TemporaryDirectory,
testContext.HelmExePath,
testContext.KubeCtlExePath,
testContext.KubeConfigPath,
agentMajorVersion,
testContext.Logger);

//create a new server halibut runtime
Expand Down Expand Up @@ -159,7 +161,7 @@ async Task SetUp(ClusterVersion clusterVersion)
recordedMethodUsages = recordedUsages;
});
}

async Task SetupCluster(ClusterVersion clusterVersion)
{
clusterInstaller = new KubernetesClusterInstaller(testContext.TemporaryDirectory, kindExePath, helmExePath, kubeCtlPath, testContext.Logger);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@
</ItemGroup>

<ItemGroup>
<None Remove="Setup\agent-values.yaml" />
<EmbeddedResource Include="Setup\agent-values.yaml">
<EmbeddedResource Include="Setup\agent-values-v2.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="Setup\agent-values-v3.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="Setup\kind-config.yaml" />
<None Remove="Setup\local-network-routing.yaml" />
<EmbeddedResource Include="Setup\docker-desktop-network-routing.yaml">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ public class KubernetesAgentInstaller
readonly TemporaryDirectory temporaryDirectory;
readonly ILogger logger;
readonly string kubeConfigPath;
readonly int agentMajorVersion;

bool isAgentInstalled;

public KubernetesAgentInstaller(TemporaryDirectory temporaryDirectory, string helmExePath, string kubeCtlExePath, string kubeConfigPath, ILogger logger)
public KubernetesAgentInstaller(TemporaryDirectory temporaryDirectory, string helmExePath, string kubeCtlExePath, string kubeConfigPath, int agentMajorVersion, ILogger logger)
{
this.temporaryDirectory = temporaryDirectory;
this.helmExePath = helmExePath;
this.kubeCtlExePath = kubeCtlExePath;
this.kubeConfigPath = kubeConfigPath;
this.agentMajorVersion = agentMajorVersion;
this.logger = logger;

AgentName = Guid.NewGuid().ToString("N");
Expand Down Expand Up @@ -88,7 +90,7 @@ string ToHelmCommandArgs(IDictionary<string, string> customValues)

async Task<string> WriteValuesFile(int listeningPort)
{
using var reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStreamFromPartialName("agent-values.yaml"));
using var reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStreamFromPartialName($"agent-values-v{agentMajorVersion}.yaml"));

var valuesFile = await reader.ReadToEndAsync();

Expand Down Expand Up @@ -135,11 +137,11 @@ string BuildAgentInstallArguments(string valuesFilePath, string? tentacleImageAn
return string.Join(" ", args.WhereNotNull());
}

static string GetChartVersion()
string GetChartVersion()
{
var customHelmChartVersion = Environment.GetEnvironmentVariable("KubernetesIntegrationTests_HelmChartVersion");

return !string.IsNullOrWhiteSpace(customHelmChartVersion) ? customHelmChartVersion : "2.*.*";
return !string.IsNullOrWhiteSpace(customHelmChartVersion) ? customHelmChartVersion : $"{agentMajorVersion}.*.*";
}

static string? GetImageAndRepository(string? tentacleImageAndTag)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
agent:
acceptEula: "Y"
name: "#{TargetName}"
serverCommsAddress: "#{ServerCommsAddress}"
serverUrl: "https://this.is.not.required.com/"
bearerToken: "this-is-a-fake-bearer-token"
space: "Default"

deploymentTarget:
enabled: true
initial:
environments: ["development"]
tags: ["Testing Cluster", "another-testing-cluster"]
enabled: "true"

image:
repository: docker.packages.octopushq.com/octopusdeploy/kubernetes-agent-tentacle

testing:
tentacle:
configMap:
data: #{ConfigMapData}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public KubernetesPodTemplateService(IKubernetesClientConfigProvider configProvid
return scriptPodTemplate;
}

public async Task<ScriptPodTemplateCustomResource?> GetOldestScriptPodTemplateCustomResource(CancellationToken cancellationToken)
async Task<ScriptPodTemplateCustomResource?> GetOldestScriptPodTemplateCustomResource(CancellationToken cancellationToken)
{
return await RetryPolicy.ExecuteAsync(async () =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ async Task CreatePod(StartKubernetesScriptCommandV1 command, IScriptWorkspace wo

pod.Spec.InitContainers = await CreateInitContainers(command, podName, homeDir, workspacePath, tentacleScriptLog, scriptPodTemplate?.ScriptInitContainerSpec);
pod.Spec.Containers = await CreateScriptContainers(command, podName, scriptName, homeDir, workspacePath, workspace.ScriptArguments, tentacleScriptLog, scriptPodTemplate);
pod.Spec.ImagePullSecrets = imagePullSecretNames;
pod.Spec.ImagePullSecrets = Merge(imagePullSecretNames, scriptPodTemplate?.PodSpec?.ImagePullSecrets);
pod.Spec.ServiceAccountName = serviceAccountName;
pod.Spec.Volumes = Merge(pod.Spec.Volumes, CreateVolumes(command));

Expand Down
24 changes: 12 additions & 12 deletions source/Octopus.Tentacle/Kubernetes/ScriptPodTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ public class ScriptPodTemplate
[JsonPropertyName("watchdogContainerSpec")]
public V1Container? WatchdogContainerSpec { get; set; }

public static ScriptPodTemplate? GetScriptPodTemplateFromDeployment(V1Deployment deployment)
public static ScriptPodTemplate GetScriptPodTemplateFromDeployment(V1Deployment deployment)
{
var template = new ScriptPodTemplate
{
PodMetadata = new PodMetadata
{
Labels = deployment.Spec.Template.Metadata.Labels.Clone(),
Annotations = deployment.Spec.Template.Metadata.Annotations.Clone(),
Labels = deployment.Spec.Template.Metadata.Labels?.Clone(),
Annotations = deployment.Spec.Template.Metadata.Annotations?.Clone(),
},
PodSpec = deployment.Spec.Template.Spec.Clone(),
ScriptContainerSpec = deployment.Spec.Template.Spec.Containers.First(c => c.Name == ContainerNames.PodTemplateScriptContainerName).Clone(),
ScriptInitContainerSpec = deployment.Spec.Template.Spec.Containers.First(c => c.Name == ContainerNames.PodTemplateScriptContainerName).Clone(),
WatchdogContainerSpec = deployment.Spec.Template.Spec.Containers.First(c => c.Name == ContainerNames.PodTemplateWatchdogContainerName).Clone()
ScriptContainerSpec = deployment.Spec.Template.Spec.Containers.FirstOrDefault(c => c.Name == ContainerNames.PodTemplateScriptContainerName)?.Clone(),
ScriptInitContainerSpec = deployment.Spec.Template.Spec.Containers.FirstOrDefault(c => c.Name == ContainerNames.PodTemplateScriptContainerName)?.Clone(),
WatchdogContainerSpec = deployment.Spec.Template.Spec.Containers.FirstOrDefault(c => c.Name == ContainerNames.PodTemplateWatchdogContainerName)?.Clone()
};

// The deployment will have the containers, we should not pull them in here though - we overwrite them and programatically create them later
Expand All @@ -43,15 +43,15 @@ public class ScriptPodTemplate
return template;
}

public static ScriptPodTemplate? GetScriptPodTemplateFromCustomResource(ScriptPodTemplateCustomResource scriptPodTemplateCustomResource)
public static ScriptPodTemplate GetScriptPodTemplateFromCustomResource(ScriptPodTemplateCustomResource scriptPodTemplateCustomResource)
{
var template = new ScriptPodTemplate
{
PodMetadata = scriptPodTemplateCustomResource.Spec.PodMetadata.Clone(),
PodSpec = scriptPodTemplateCustomResource.Spec.PodSpec.Clone(),
ScriptContainerSpec = scriptPodTemplateCustomResource.Spec.ScriptContainerSpec.Clone(),
ScriptInitContainerSpec = scriptPodTemplateCustomResource.Spec.ScriptContainerSpec.Clone(),
WatchdogContainerSpec = scriptPodTemplateCustomResource.Spec.WatchdogContainerSpec.Clone()
PodMetadata = scriptPodTemplateCustomResource.Spec.PodMetadata?.Clone(),
PodSpec = scriptPodTemplateCustomResource.Spec.PodSpec?.Clone(),
ScriptContainerSpec = scriptPodTemplateCustomResource.Spec.ScriptContainerSpec?.Clone(),
ScriptInitContainerSpec = scriptPodTemplateCustomResource.Spec.ScriptContainerSpec?.Clone(),
WatchdogContainerSpec = scriptPodTemplateCustomResource.Spec.WatchdogContainerSpec?.Clone()
};
return template;
}
Expand Down