Skip to content

Commit fa97c83

Browse files
committed
Use script pod template custom resource to create pods and containers
1 parent 036ae2d commit fa97c83

File tree

5 files changed

+237
-88
lines changed

5 files changed

+237
-88
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Net;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using k8s;
7+
using k8s.Autorest;
8+
using k8s.Models;
9+
using Octopus.Tentacle.Core.Diagnostics;
10+
11+
namespace Octopus.Tentacle.Kubernetes
12+
{
13+
public interface IKubernetesCustomResourceService
14+
{
15+
Task<ScriptPodTemplateCustomResource?> GetOldestScriptPodTemplateCustomResource(CancellationToken cancellationToken);
16+
}
17+
18+
public class KubernetesCustomResourceService : KubernetesService, IKubernetesCustomResourceService
19+
{
20+
public KubernetesCustomResourceService(IKubernetesClientConfigProvider configProvider, ISystemLog log)
21+
: base(configProvider, log)
22+
{
23+
}
24+
25+
public async Task<ScriptPodTemplateCustomResource?> GetOldestScriptPodTemplateCustomResource(CancellationToken cancellationToken)
26+
{
27+
return await RetryPolicy.ExecuteAsync(async () =>
28+
{
29+
ScriptPodTemplateCustomResourceList resourceList;
30+
try
31+
{
32+
resourceList = await Client.CustomObjects.ListNamespacedCustomObjectAsync<ScriptPodTemplateCustomResourceList>(
33+
"agent.octopus.com",
34+
"v1beta1",
35+
KubernetesConfig.Namespace,
36+
"scriptpodtemplates",
37+
cancellationToken: cancellationToken);
38+
}
39+
catch (HttpOperationException opException)
40+
when (opException.Response.StatusCode == HttpStatusCode.NotFound)
41+
{
42+
return null;
43+
}
44+
45+
return resourceList.Items.OrderBy(r => r.Metadata.CreationTimestamp).FirstOrDefault();
46+
});
47+
}
48+
49+
//These are only ever deserialized from JSON
50+
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
51+
class ScriptPodTemplateCustomResourceList : KubernetesObject
52+
{
53+
public V1ListMeta Metadata { get; set; }
54+
public List<ScriptPodTemplateCustomResource> Items { get; set; }
55+
}
56+
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
57+
}
58+
}

source/Octopus.Tentacle/Kubernetes/KubernetesModule.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ protected override void Load(ContainerBuilder builder)
3434
builder.RegisterType<KubernetesPodContainerResolver>().As<IKubernetesPodContainerResolver>().SingleInstance();
3535
builder.RegisterType<KubernetesConfigMapService>().As<IKubernetesConfigMapService>().SingleInstance();
3636
builder.RegisterType<KubernetesSecretService>().As<IKubernetesSecretService>().SingleInstance();
37+
builder.RegisterType<KubernetesCustomResourceService>().As<IKubernetesCustomResourceService>().SingleInstance();
3738

3839
builder.RegisterType<KubernetesScriptPodCreator>().As<IKubernetesScriptPodCreator>().SingleInstance();
3940
builder.RegisterType<KubernetesRawScriptPodCreator>().As<IKubernetesRawScriptPodCreator>().SingleInstance();

source/Octopus.Tentacle/Kubernetes/KubernetesRawScriptPodCreator.cs

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public KubernetesRawScriptPodCreator(
2525
IKubernetesPodService podService,
2626
IKubernetesPodMonitor podMonitor,
2727
IKubernetesSecretService secretService,
28+
IKubernetesCustomResourceService customResourceService,
2829
IKubernetesPodContainerResolver containerResolver,
2930
IApplicationInstanceSelector appInstanceSelector,
3031
ISystemLog log,
@@ -33,31 +34,40 @@ public KubernetesRawScriptPodCreator(
3334
KubernetesPhysicalFileSystem kubernetesPhysicalFileSystem,
3435
IScriptPodLogEncryptionKeyProvider scriptPodLogEncryptionKeyProvider,
3536
ScriptIsolationMutex scriptIsolationMutex)
36-
: base(podService, podMonitor, secretService, containerResolver, appInstanceSelector, log, scriptLogProvider, homeConfiguration, kubernetesPhysicalFileSystem, scriptPodLogEncryptionKeyProvider, scriptIsolationMutex)
37+
: base(podService, podMonitor, secretService, customResourceService, containerResolver, appInstanceSelector, log, scriptLogProvider, homeConfiguration, kubernetesPhysicalFileSystem, scriptPodLogEncryptionKeyProvider, scriptIsolationMutex)
3738
{
3839
this.containerResolver = containerResolver;
3940
}
4041

41-
protected override async Task<IList<V1Container>> CreateInitContainers(StartKubernetesScriptCommandV1 command, string podName, string homeDir, string workspacePath, InMemoryTentacleScriptLog tentacleScriptLog)
42+
protected override async Task<IList<V1Container>> CreateInitContainers(StartKubernetesScriptCommandV1 command, string podName, string homeDir, string workspacePath, InMemoryTentacleScriptLog tentacleScriptLog, V1Container? containerSpec)
4243
{
43-
var container = new V1Container
44+
V1Container container;
45+
if (containerSpec is not null)
4446
{
45-
Name = $"{podName}-init",
46-
Image = command.PodImageConfiguration?.Image ?? await containerResolver.GetContainerImageForCluster(),
47-
ImagePullPolicy = KubernetesConfig.ScriptPodPullPolicy,
48-
Command = new List<string> { "sh", "-c", GetInitExecutionScript("/nfs-mount", homeDir, workspacePath) },
49-
VolumeMounts = new List<V1VolumeMount> { new("/nfs-mount", "init-nfs-volume"), new(homeDir, "tentacle-home") },
50-
Resources = GetScriptPodResourceRequirements(tentacleScriptLog)
51-
};
47+
container = containerSpec;
48+
}
49+
else
50+
{
51+
container = new V1Container
52+
{
53+
Resources = GetScriptPodResourceRequirements(tentacleScriptLog)
54+
};
55+
}
56+
57+
container.Name = $"{podName}-init";
58+
container.Image = command.PodImageConfiguration?.Image ?? await containerResolver.GetContainerImageForCluster();
59+
container.ImagePullPolicy = KubernetesConfig.ScriptPodPullPolicy;
60+
container.Command = new List<string> { "sh", "-c", GetInitExecutionScript("/nfs-mount", homeDir, workspacePath) };
61+
container.VolumeMounts = new List<V1VolumeMount> { new("/nfs-mount", "init-nfs-volume"), new(homeDir, "tentacle-home") };
5262

5363
return new List<V1Container> { container };
5464
}
55-
56-
protected override async Task<IList<V1Container>> CreateScriptContainers(StartKubernetesScriptCommandV1 command, string podName, string scriptName, string homeDir, string workspacePath, string[]? scriptArguments, InMemoryTentacleScriptLog tentacleScriptLog)
65+
66+
protected override async Task<IList<V1Container>> CreateScriptContainers(StartKubernetesScriptCommandV1 command, string podName, string scriptName, string homeDir, string workspacePath, string[]? scriptArguments, InMemoryTentacleScriptLog tentacleScriptLog, ScriptPodTemplateSpec? spec)
5767
{
5868
return new List<V1Container>
5969
{
60-
await CreateScriptContainer(command, podName, scriptName, homeDir, workspacePath, scriptArguments, tentacleScriptLog)
70+
await CreateScriptContainer(command, podName, scriptName, homeDir, workspacePath, scriptArguments, tentacleScriptLog, spec?.ScriptContainerSpec)
6171
};
6272
}
6373

@@ -82,7 +92,7 @@ protected override IList<V1Volume> CreateVolumes(StartKubernetesScriptCommandV1
8292
};
8393
}
8494

85-
string GetInitExecutionScript(string nfsVolumeDirectory, string homeDir, string workspacePath)
95+
static string GetInitExecutionScript(string nfsVolumeDirectory, string homeDir, string workspacePath)
8696
{
8797
var nfsWorkspacePath = Path.Combine(nfsVolumeDirectory, workspacePath);
8898
var homeWorkspacePath = Path.Combine(homeDir, workspacePath);

0 commit comments

Comments
 (0)