Skip to content

Commit 24df9db

Browse files
authored
Update Kubernetes Client package to v15 (#1051)
1 parent 266b088 commit 24df9db

15 files changed

+359
-125
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
1-
using Halibut;
2-
using Halibut.Diagnostics;
3-
using Halibut.Diagnostics.LogCreators;
4-
using Halibut.Logging;
1+
using System;
2+
using Halibut;
53
using Octopus.Tentacle.Client;
6-
using Octopus.Tentacle.Client.Retries;
7-
using Octopus.Tentacle.Client.Scripts;
84
using Octopus.Tentacle.CommonTestUtils;
9-
using Octopus.Tentacle.Contracts.Observability;
105
using Octopus.Tentacle.Kubernetes.Tests.Integration.Setup;
116
using Octopus.Tentacle.Kubernetes.Tests.Integration.Tooling;
127
using Octopus.Tentacle.Tests.Integration.Common.Builders.Decorators;
138
using Octopus.Tentacle.Tests.Integration.Common.Logging;
149

15-
namespace Octopus.Tentacle.Kubernetes.Tests.Integration;
10+
namespace Octopus.Tentacle.Kubernetes.Tests.Integration.KubernetesAgent;
1611

1712
public abstract class KubernetesAgentIntegrationTest
1813
{
@@ -23,9 +18,7 @@ public abstract class KubernetesAgentIntegrationTest
2318
protected ILogger? Logger { get; private set; }
2419

2520
protected KubernetesAgentInstaller KubernetesAgentInstaller => kubernetesAgentInstaller ?? throw new InvalidOperationException("Expected kubernetesAgentInstaller to be set");
26-
27-
protected HalibutRuntime ServerHalibutRuntime { get; private set; } = null!;
28-
21+
2922
protected TentacleClient TentacleClient { get; private set; } = null!;
3023

3124
protected CancellationToken CancellationToken { get; private set; }
@@ -34,6 +27,8 @@ public abstract class KubernetesAgentIntegrationTest
3427

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

30+
HalibutRuntime serverHalibutRuntime;
31+
3732
string? agentThumbprint;
3833

3934
[OneTimeSetUp]
@@ -54,12 +49,13 @@ public async Task OneTimeSetUp()
5449
KubernetesTestsGlobalContext.Instance.Logger);
5550

5651
//create a new server halibut runtime
57-
var listeningPort = BuildServerHalibutRuntimeAndListen();
52+
serverHalibutRuntime = SetupHelpers.BuildServerHalibutRuntime();
53+
var listeningPort = serverHalibutRuntime.Listen();
5854

5955
agentThumbprint = await kubernetesAgentInstaller.InstallAgent(listeningPort, KubernetesTestsGlobalContext.Instance.TentacleImageAndTag, CustomHelmValues);
6056

6157
//trust the generated cert thumbprint
62-
ServerHalibutRuntime.Trust(agentThumbprint);
58+
serverHalibutRuntime.Trust(agentThumbprint);
6359
}
6460

6561
[SetUp]
@@ -76,7 +72,7 @@ public void SetUp()
7672
CancellationToken = cancellationTokenSource.Token;
7773

7874
//each test should get its own tentacle client, so it gets its own builders
79-
BuildTentacleClient();
75+
TentacleClient = SetupHelpers.BuildTentacleClient(KubernetesAgentInstaller.SubscriptionId, agentThumbprint, serverHalibutRuntime, ConfigureTentacleServiceDecoratorBuilder);
8076
}
8177

8278
[TearDown]
@@ -91,45 +87,14 @@ public async Task TearDown()
9187
cancellationTokenSource?.Dispose();
9288
}
9389

94-
protected virtual TentacleServiceDecoratorBuilder ConfigureTentacleServiceDecoratorBuilder(TentacleServiceDecoratorBuilder builder) => builder;
95-
96-
void BuildTentacleClient()
97-
{
98-
var endpoint = new ServiceEndPoint(KubernetesAgentInstaller.SubscriptionId, agentThumbprint, ServerHalibutRuntime.TimeoutsAndLimits);
99-
100-
var retrySettings = new RpcRetrySettings(true, TimeSpan.FromMinutes(2));
101-
var clientOptions = new TentacleClientOptions(retrySettings);
102-
103-
TentacleClient.CacheServiceWasNotFoundResponseMessages(ServerHalibutRuntime);
104-
105-
var builder = new TentacleServiceDecoratorBuilder();
106-
ConfigureTentacleServiceDecoratorBuilder(builder);
107-
108-
TentacleClient = new TentacleClient(
109-
endpoint,
110-
ServerHalibutRuntime,
111-
new PollingTentacleScriptObserverBackoffStrategy(),
112-
new NoTentacleClientObserver(),
113-
clientOptions,
114-
builder.Build());
115-
}
116-
117-
int BuildServerHalibutRuntimeAndListen()
90+
protected virtual void ConfigureTentacleServiceDecoratorBuilder(TentacleServiceDecoratorBuilder builder)
11891
{
119-
var serverHalibutRuntimeBuilder = new HalibutRuntimeBuilder()
120-
.WithServerCertificate(TestCertificates.Server)
121-
.WithHalibutTimeoutsAndLimits(HalibutTimeoutsAndLimits.RecommendedValues())
122-
.WithLogFactory(new TestContextLogCreator("Server", LogLevel.Trace).ToCachingLogFactory());
123-
124-
ServerHalibutRuntime = serverHalibutRuntimeBuilder.Build();
125-
126-
return ServerHalibutRuntime.Listen();
12792
}
12893

12994
[OneTimeTearDown]
13095
public async Task OneTimeTearDown()
13196
{
132-
await ServerHalibutRuntime.DisposeAsync();
97+
await serverHalibutRuntime.DisposeAsync();
13398
kubernetesAgentInstaller?.Dispose();
13499
}
135100
}

source/Octopus.Tentacle.Kubernetes.Tests.Integration/KubernetesAgentMetricsIntegrationTest.cs renamed to source/Octopus.Tentacle.Kubernetes.Tests.Integration/KubernetesAgent/KubernetesAgentMetricsIntegrationTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using Octopus.Tentacle.Diagnostics;
77
using Octopus.Tentacle.Kubernetes.Diagnostics;
88

9-
namespace Octopus.Tentacle.Kubernetes.Tests.Integration;
9+
namespace Octopus.Tentacle.Kubernetes.Tests.Integration.KubernetesAgent;
1010

1111
public class KubernetesAgentMetricsIntegrationTest : KubernetesAgentIntegrationTest
1212
{
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using Octopus.Tentacle.Kubernetes.Tests.Integration.Setup;
3+
4+
namespace Octopus.Tentacle.Kubernetes.Tests.Integration.KubernetesAgent;
5+
6+
[SetUpFixture]
7+
public class KubernetesClusterOneTimeSetUp
8+
{
9+
KubernetesClusterInstaller? installer;
10+
11+
[OneTimeSetUp]
12+
public async Task OneTimeSetUp()
13+
{
14+
var toolDownloader = new RequiredToolDownloader(KubernetesTestsGlobalContext.Instance.TemporaryDirectory, KubernetesTestsGlobalContext.Instance.Logger);
15+
var (kindExePath, helmExePath, kubeCtlPath) = await toolDownloader.DownloadRequiredTools(CancellationToken.None);
16+
17+
installer = new KubernetesClusterInstaller(KubernetesTestsGlobalContext.Instance.TemporaryDirectory, kindExePath, helmExePath, kubeCtlPath, KubernetesTestsGlobalContext.Instance.Logger);
18+
await installer.InstallLatestSupported();
19+
20+
KubernetesTestsGlobalContext.Instance.TentacleImageAndTag = SetupHelpers.GetTentacleImageAndTag(kindExePath, installer);
21+
KubernetesTestsGlobalContext.Instance.SetToolExePaths(helmExePath, kubeCtlPath);
22+
KubernetesTestsGlobalContext.Instance.KubeConfigPath = installer.KubeConfigPath;
23+
}
24+
25+
[OneTimeTearDown]
26+
public void OneTimeTearDown()
27+
{
28+
installer?.Dispose();
29+
KubernetesTestsGlobalContext.Instance.Dispose();
30+
}
31+
}

source/Octopus.Tentacle.Kubernetes.Tests.Integration/KubernetesScriptServiceV1IntegrationTest.cs renamed to source/Octopus.Tentacle.Kubernetes.Tests.Integration/KubernetesAgent/KubernetesScriptServiceV1IntegrationTest.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,28 @@
1+
using System;
12
using FluentAssertions;
23
using FluentAssertions.Execution;
3-
using Octopus.Client.Model.Endpoints;
44
using Octopus.Tentacle.Client.Scripts.Models;
55
using Octopus.Tentacle.Client.Scripts.Models.Builders;
66
using Octopus.Tentacle.CommonTestUtils;
77
using Octopus.Tentacle.CommonTestUtils.Diagnostics;
88
using Octopus.Tentacle.Contracts;
9-
using Octopus.Tentacle.Contracts.Capabilities;
109
using Octopus.Tentacle.Contracts.ClientServices;
11-
using Octopus.Tentacle.Contracts.KubernetesScriptServiceV1;
12-
using Octopus.Tentacle.Tests.Integration.Common.Builders.Decorators;
1310
using Octopus.Tentacle.Kubernetes.Tests.Integration.Util;
11+
using Octopus.Tentacle.Tests.Integration.Common.Builders.Decorators;
1412
using Octopus.Tentacle.Tests.Integration.Common.Builders.Decorators.Proxies;
1513

16-
namespace Octopus.Tentacle.Kubernetes.Tests.Integration;
14+
namespace Octopus.Tentacle.Kubernetes.Tests.Integration.KubernetesAgent;
1715

1816
[TestFixture]
1917
public class KubernetesScriptServiceV1IntegrationTest : KubernetesAgentIntegrationTest
2018
{
2119
IRecordedMethodUsages recordedMethodUsages = null!;
2220

23-
protected override TentacleServiceDecoratorBuilder ConfigureTentacleServiceDecoratorBuilder(TentacleServiceDecoratorBuilder builder)
21+
protected override void ConfigureTentacleServiceDecoratorBuilder(TentacleServiceDecoratorBuilder builder)
2422
{
2523
builder.RecordMethodUsages<IAsyncClientKubernetesScriptServiceV1>(out var recordedUsages);
2624

2725
recordedMethodUsages = recordedUsages;
28-
29-
return builder;
3026
}
3127

3228
[Test]
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
using System;
2+
using FluentAssertions;
3+
using Halibut;
4+
using Octopus.Tentacle.Client;
5+
using Octopus.Tentacle.Client.Scripts.Models;
6+
using Octopus.Tentacle.Client.Scripts.Models.Builders;
7+
using Octopus.Tentacle.CommonTestUtils;
8+
using Octopus.Tentacle.CommonTestUtils.Diagnostics;
9+
using Octopus.Tentacle.Contracts;
10+
using Octopus.Tentacle.Contracts.ClientServices;
11+
using Octopus.Tentacle.Kubernetes.Tests.Integration.Setup;
12+
using Octopus.Tentacle.Kubernetes.Tests.Integration.Util;
13+
using Octopus.Tentacle.Tests.Integration.Common.Builders.Decorators;
14+
using Octopus.Tentacle.Tests.Integration.Common.Builders.Decorators.Proxies;
15+
using Octopus.Tentacle.Tests.Integration.Common.Logging;
16+
17+
namespace Octopus.Tentacle.Kubernetes.Tests.Integration;
18+
19+
[TestFixture]
20+
public class KubernetesClientCompatibilityTests
21+
{
22+
static readonly object[] TestClusterVersions =
23+
[
24+
new object[] {new ClusterVersion(1, 31)},
25+
new object[] {new ClusterVersion(1, 30)},
26+
new object[] {new ClusterVersion(1, 29)},
27+
new object[] {new ClusterVersion(1, 28)},
28+
];
29+
30+
KubernetesTestsGlobalContext? testContext;
31+
ILogger logger = null!;
32+
TemporaryDirectory toolsTemporaryDirectory;
33+
string kindExePath;
34+
string helmExePath;
35+
string kubeCtlPath;
36+
KubernetesClusterInstaller? clusterInstaller;
37+
KubernetesAgentInstaller? kubernetesAgentInstaller;
38+
HalibutRuntime serverHalibutRuntime = null!;
39+
string? agentThumbprint;
40+
TraceLogFileLogger? traceLogFileLogger;
41+
CancellationToken cancellationToken;
42+
CancellationTokenSource? cancellationTokenSource;
43+
TentacleClient tentacleClient = null!;
44+
IRecordedMethodUsages recordedMethodUsages = null!;
45+
46+
[OneTimeSetUp]
47+
public async Task OneTimeSetup()
48+
{
49+
logger = new SerilogLoggerBuilder().Build();
50+
toolsTemporaryDirectory = new TemporaryDirectory();
51+
var toolDownloader = new RequiredToolDownloader(toolsTemporaryDirectory, logger);
52+
(kindExePath, helmExePath, kubeCtlPath) = await toolDownloader.DownloadRequiredTools(CancellationToken.None);
53+
}
54+
55+
[OneTimeTearDown]
56+
public void OneTimeTearDown()
57+
{
58+
toolsTemporaryDirectory.Dispose();
59+
}
60+
61+
[TearDown]
62+
public async Task TearDown()
63+
{
64+
if (traceLogFileLogger is not null) await traceLogFileLogger.DisposeAsync();
65+
if (cancellationTokenSource is not null)
66+
{
67+
await cancellationTokenSource.CancelAsync();
68+
cancellationTokenSource.Dispose();
69+
}
70+
clusterInstaller?.Dispose();
71+
testContext?.Dispose();
72+
73+
traceLogFileLogger = null;
74+
cancellationTokenSource = null;
75+
clusterInstaller = null;
76+
testContext = null;
77+
}
78+
79+
[Test]
80+
[TestCaseSource(nameof(TestClusterVersions))]
81+
public async Task RunSimpleScript(ClusterVersion clusterVersion)
82+
{
83+
await SetUp(clusterVersion);
84+
85+
// Arrange
86+
var logs = new List<ProcessOutput>();
87+
var scriptCompleted = false;
88+
89+
var builder = new ExecuteKubernetesScriptCommandBuilder(LoggingUtils.CurrentTestHash())
90+
.WithScriptBody(script => script
91+
.Print("Hello World")
92+
.PrintNTimesWithDelay("Yep", 30, TimeSpan.FromMilliseconds(100)));
93+
94+
var command = builder.Build();
95+
96+
// Act
97+
var result = await tentacleClient.ExecuteScript(command, StatusReceived, ScriptCompleted, new InMemoryLog(), cancellationToken);
98+
99+
// Assert
100+
logs.Should().Contain(po => po.Text.StartsWith("[POD EVENT]")); // Verify that we are receiving some pod events
101+
logs.Should().Contain(po => po.Source == ProcessOutputSource.StdOut && po.Text == "Hello World");
102+
scriptCompleted.Should().BeTrue();
103+
result.ExitCode.Should().Be(0);
104+
result.State.Should().Be(ProcessState.Complete);
105+
106+
recordedMethodUsages.For(nameof(IAsyncClientKubernetesScriptServiceV1.StartScriptAsync)).Started.Should().Be(1);
107+
recordedMethodUsages.For(nameof(IAsyncClientKubernetesScriptServiceV1.GetStatusAsync)).Started.Should().BeGreaterThan(1);
108+
recordedMethodUsages.For(nameof(IAsyncClientKubernetesScriptServiceV1.CompleteScriptAsync)).Started.Should().Be(1);
109+
recordedMethodUsages.For(nameof(IAsyncClientKubernetesScriptServiceV1.CancelScriptAsync)).Started.Should().Be(0);
110+
111+
return;
112+
113+
void StatusReceived(ScriptExecutionStatus status)
114+
{
115+
logs.AddRange(status.Logs);
116+
}
117+
118+
Task ScriptCompleted(CancellationToken ct)
119+
{
120+
scriptCompleted = true;
121+
return Task.CompletedTask;
122+
}
123+
}
124+
125+
async Task SetUp(ClusterVersion clusterVersion)
126+
{
127+
testContext = new KubernetesTestsGlobalContext(logger);
128+
129+
await SetupCluster(clusterVersion);
130+
131+
kubernetesAgentInstaller = new KubernetesAgentInstaller(
132+
testContext.TemporaryDirectory,
133+
testContext.HelmExePath,
134+
testContext.KubeCtlExePath,
135+
testContext.KubeConfigPath,
136+
testContext.Logger);
137+
138+
//create a new server halibut runtime
139+
serverHalibutRuntime = SetupHelpers.BuildServerHalibutRuntime();
140+
var listeningPort = serverHalibutRuntime.Listen();
141+
142+
agentThumbprint = await kubernetesAgentInstaller.InstallAgent(listeningPort, testContext.TentacleImageAndTag, new Dictionary<string, string>());
143+
144+
//trust the generated cert thumbprint
145+
serverHalibutRuntime.Trust(agentThumbprint);
146+
147+
traceLogFileLogger = new TraceLogFileLogger(LoggingUtils.CurrentTestHash());
148+
logger = new SerilogLoggerBuilder()
149+
.SetTraceLogFileLogger(traceLogFileLogger)
150+
.Build()
151+
.ForContext(GetType());
152+
153+
cancellationTokenSource = new CancellationTokenSource();
154+
cancellationTokenSource.CancelAfter(TimeSpan.FromMinutes(5));
155+
cancellationToken = cancellationTokenSource.Token;
156+
157+
tentacleClient = SetupHelpers.BuildTentacleClient(kubernetesAgentInstaller.SubscriptionId, agentThumbprint, serverHalibutRuntime, builder =>
158+
{
159+
builder.RecordMethodUsages<IAsyncClientKubernetesScriptServiceV1>(out var recordedUsages);
160+
recordedMethodUsages = recordedUsages;
161+
});
162+
}
163+
164+
async Task SetupCluster(ClusterVersion clusterVersion)
165+
{
166+
clusterInstaller = new KubernetesClusterInstaller(testContext.TemporaryDirectory, kindExePath, helmExePath, kubeCtlPath, testContext.Logger);
167+
await clusterInstaller.Install(clusterVersion);
168+
169+
testContext.TentacleImageAndTag = SetupHelpers.GetTentacleImageAndTag(kindExePath, clusterInstaller);
170+
testContext.SetToolExePaths(helmExePath, kubeCtlPath);
171+
testContext.KubeConfigPath = clusterInstaller.KubeConfigPath;
172+
}
173+
}

0 commit comments

Comments
 (0)