Skip to content

Commit d64d32f

Browse files
author
Christoph Bühler
committed
feat(Kubernetes Client): add version / namespace calls.
This adds the possibility to fetch the version of the actual kubernetes cluster via the client. This adds the possiblity to fetch the used namespace via downwardAPI, file, or default from kubernetes.
1 parent 4dd0073 commit d64d32f

File tree

6 files changed

+116
-18
lines changed

6 files changed

+116
-18
lines changed

src/KubeOps.Testing/MockKubernetesClient.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public class MockKubernetesClient : IKubernetesClient
2424

2525
public object? UpdateResult { get; set; }
2626

27+
public Task<string> GetCurrentNamespace(string downwardApiEnvName = "POD_NAMESPACE") =>
28+
Task.FromResult("default");
29+
30+
public Task<VersionInfo> GetServerVersion() => Task.FromResult(new VersionInfo());
31+
2732
public Task<TResource?> Get<TResource>(string name, string? @namespace = null)
2833
where TResource : class, IKubernetesObject<V1ObjectMeta>
2934
=> Task.FromResult(GetResult as TResource);

src/KubeOps/Operator/Builder/OperatorBuilder.cs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,26 +118,24 @@ internal IOperatorBuilder AddOperatorBase(OperatorSettings settings)
118118
Services.AddTransient<EntitySerializer>();
119119

120120
Services.AddTransient<IKubernetesClient, KubernetesClient>();
121+
Services.AddSingleton(KubernetesClientConfiguration.BuildDefaultConfig());
121122
Services.AddSingleton<IKubernetes>(
122-
_ =>
123+
services => new Kubernetes(
124+
services.GetRequiredService<KubernetesClientConfiguration>(),
125+
new ClientUrlFixer())
123126
{
124-
var config = KubernetesClientConfiguration.BuildDefaultConfig();
125-
126-
return new Kubernetes(config, new ClientUrlFixer())
127+
SerializationSettings =
128+
{
129+
ContractResolver = new NamingConvention(),
130+
Converters = new List<JsonConverter>
131+
{ new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy() } },
132+
},
133+
DeserializationSettings =
127134
{
128-
SerializationSettings =
129-
{
130-
ContractResolver = new NamingConvention(),
131-
Converters = new List<JsonConverter>
132-
{ new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy() } },
133-
},
134-
DeserializationSettings =
135-
{
136-
ContractResolver = new NamingConvention(),
137-
Converters = new List<JsonConverter>
138-
{ new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy() } },
139-
},
140-
};
135+
ContractResolver = new NamingConvention(),
136+
Converters = new List<JsonConverter>
137+
{ new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy() } },
138+
},
141139
});
142140

143141
Services.AddTransient(typeof(IResourceCache<>), typeof(ResourceCache<>));

src/KubeOps/Operator/Client/IKubernetesClient.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,36 @@ public interface IKubernetesClient
1212
{
1313
IKubernetes ApiClient { get; }
1414

15+
/// <summary>
16+
/// Returns the name of the current namespace.
17+
/// To determine the current namespace the following places (in the given order) are checked:
18+
/// <list type="number">
19+
/// <item>
20+
/// <description>The created kubernetes configuration (from file / incluster)</description>
21+
/// </item>
22+
/// <item>
23+
/// <description>
24+
/// The env variable given as the param to the function (default "POD_NAMESPACE")
25+
/// which can be provided by the <a href="https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/#capabilities-of-the-downward-api">kubernetes downward API</a>
26+
/// </description>
27+
/// </item>
28+
/// <item>
29+
/// <description>
30+
/// The fallback secret file if running on the cluster
31+
/// (/var/run/secrets/kubernetes.io/serviceaccount/namespace)
32+
/// </description>
33+
/// </item>
34+
/// <item>
35+
/// <description>"default"</description>
36+
/// </item>
37+
/// </list>
38+
/// </summary>
39+
/// <param name="downwardApiEnvName">Customizable name of the env var to check for the namespace.</param>
40+
/// <returns>A string containing the current namespace (or a fallback of it).</returns>
41+
Task<string> GetCurrentNamespace(string downwardApiEnvName = "POD_NAMESPACE");
42+
43+
Task<VersionInfo> GetServerVersion();
44+
1545
Task<TResource?> Get<TResource>(string name, string? @namespace = null)
1646
where TResource : class, IKubernetesObject<V1ObjectMeta>;
1747

src/KubeOps/Operator/Client/KubernetesClient.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.IO;
34
using System.Linq;
45
using System.Net;
56
using System.Threading;
@@ -16,13 +17,42 @@ namespace KubeOps.Operator.Client
1617
{
1718
internal class KubernetesClient : IKubernetesClient
1819
{
19-
public KubernetesClient(IKubernetes apiClient)
20+
private const string DownwardApiNamespaceFile = "/var/run/secrets/kubernetes.io/serviceaccount/namespace";
21+
private const string DefaultNamespace = "default";
22+
23+
private readonly KubernetesClientConfiguration _clientConfig;
24+
25+
public KubernetesClient(IKubernetes apiClient, KubernetesClientConfiguration clientConfig)
2026
{
27+
_clientConfig = clientConfig;
2128
ApiClient = apiClient;
2229
}
2330

2431
public IKubernetes ApiClient { get; }
2532

33+
public async Task<string> GetCurrentNamespace(string downwardApiEnvName = "POD_NAMESPACE")
34+
{
35+
if (_clientConfig.Namespace != null)
36+
{
37+
return _clientConfig.Namespace;
38+
}
39+
40+
if (Environment.GetEnvironmentVariable(downwardApiEnvName) != null)
41+
{
42+
return Environment.GetEnvironmentVariable(downwardApiEnvName) ?? string.Empty;
43+
}
44+
45+
if (File.Exists(DownwardApiNamespaceFile))
46+
{
47+
var ns = await File.ReadAllTextAsync(DownwardApiNamespaceFile) ?? string.Empty;
48+
return ns.Trim();
49+
}
50+
51+
return DefaultNamespace;
52+
}
53+
54+
public Task<VersionInfo> GetServerVersion() => ApiClient.GetCodeAsync();
55+
2656
public async Task<TResource?> Get<TResource>(
2757
string name,
2858
string? @namespace = null)

src/KubeOps/Operator/Commands/RunOperator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Threading.Tasks;
22
using KubeOps.Operator.Commands.Generators;
33
using KubeOps.Operator.Commands.Management;
4+
using KubeOps.Operator.Commands.Utilities;
45
using McMaster.Extensions.CommandLineUtils;
56
using Microsoft.Extensions.Hosting;
67

@@ -10,6 +11,7 @@ namespace KubeOps.Operator.Commands
1011
[Subcommand(typeof(Generator))]
1112
[Subcommand(typeof(Install))]
1213
[Subcommand(typeof(Uninstall))]
14+
[Subcommand(typeof(Version))]
1315
internal class RunOperator
1416
{
1517
private readonly IHost _host;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Threading.Tasks;
2+
using KubeOps.Operator.Client;
3+
using McMaster.Extensions.CommandLineUtils;
4+
5+
namespace KubeOps.Operator.Commands.Utilities
6+
{
7+
[Command(
8+
"version",
9+
"v",
10+
Description = "Prints the actual server version of the connected kubernetes cluster.")]
11+
internal class Version
12+
{
13+
private readonly IKubernetesClient _client;
14+
15+
public Version(IKubernetesClient client)
16+
{
17+
_client = client;
18+
}
19+
20+
public async Task<int> OnExecuteAsync(CommandLineApplication app)
21+
{
22+
var version = await _client.GetServerVersion();
23+
await app.Out.WriteLineAsync(
24+
$@"The kubernetes api reported the following version:
25+
Git-Version: {version.GitVersion}
26+
Major: {version.Major}
27+
Minor: {version.Minor}
28+
Platform: {version.Platform}");
29+
30+
return ExitCodes.Success;
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)