Skip to content

Commit 42bc8ee

Browse files
author
Christoph Bühler
committed
feat(client): Add Kubernetes Client package
BREAKING CHANGE: The IKubernetesClient interface and implementation now require the TEntity typeparam instead of each method providing one. The implementation is instanced with EntityMetadata to allow the operator to inject the clients for each entity.
1 parent bcd1f52 commit 42bc8ee

24 files changed

+523
-396
lines changed

KubeOps.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Transpiler.Test", "
4747
EndProject
4848
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.Transpiler", "src\KubeOps.Transpiler\KubeOps.Transpiler.csproj", "{A793FC08-E76C-448B-BE93-88C137D2C7AB}"
4949
EndProject
50+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.KubernetesClient", "src\KubeOps.KubernetesClient\KubeOps.KubernetesClient.csproj", "{C2C6FF06-2B9D-4FAC-A039-3DC1E007DE3B}"
51+
EndProject
52+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubeOps.KubernetesClient.Test", "test\KubeOps.KubernetesClient.Test\KubeOps.KubernetesClient.Test.csproj", "{25F767E5-7A74-459B-83CC-39519461F38B}"
53+
EndProject
5054
Global
5155
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5256
Debug|Any CPU = Debug|Any CPU
@@ -68,6 +72,8 @@ Global
6872
{BC6E6D3C-6404-4B01-9D72-AA16FEEBFF5C} = {C587731F-8191-4A19-8662-B89A60FE79A1}
6973
{47914451-147D-427E-B150-9C47DBF28F2C} = {C587731F-8191-4A19-8662-B89A60FE79A1}
7074
{A793FC08-E76C-448B-BE93-88C137D2C7AB} = {4DB01062-6DC5-4028-BB72-C0619C2F5F2E}
75+
{C2C6FF06-2B9D-4FAC-A039-3DC1E007DE3B} = {4DB01062-6DC5-4028-BB72-C0619C2F5F2E}
76+
{25F767E5-7A74-459B-83CC-39519461F38B} = {C587731F-8191-4A19-8662-B89A60FE79A1}
7177
EndGlobalSection
7278
GlobalSection(ProjectConfigurationPlatforms) = postSolution
7379
{E9A0B04E-D90E-4B94-90E0-DD3666B098FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -118,5 +124,13 @@ Global
118124
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
119125
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
120126
{A793FC08-E76C-448B-BE93-88C137D2C7AB}.Release|Any CPU.Build.0 = Release|Any CPU
127+
{C2C6FF06-2B9D-4FAC-A039-3DC1E007DE3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
128+
{C2C6FF06-2B9D-4FAC-A039-3DC1E007DE3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
129+
{C2C6FF06-2B9D-4FAC-A039-3DC1E007DE3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
130+
{C2C6FF06-2B9D-4FAC-A039-3DC1E007DE3B}.Release|Any CPU.Build.0 = Release|Any CPU
131+
{25F767E5-7A74-459B-83CC-39519461F38B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
132+
{25F767E5-7A74-459B-83CC-39519461F38B}.Debug|Any CPU.Build.0 = Debug|Any CPU
133+
{25F767E5-7A74-459B-83CC-39519461F38B}.Release|Any CPU.ActiveCfg = Release|Any CPU
134+
{25F767E5-7A74-459B-83CC-39519461F38B}.Release|Any CPU.Build.0 = Release|Any CPU
121135
EndGlobalSection
122136
EndGlobal

src/KubeOps.Abstractions/Builder/IOperatorBuilder.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ public interface IOperatorBuilder
1919
IServiceCollection Services { get; }
2020

2121
/// <summary>
22-
/// Add metadata for an entity to the operator.
22+
/// Add an entity with its metadata to the operator.
2323
/// Metadata must be added for each entity to be used in
2424
/// controllers and other elements.
2525
/// </summary>
2626
/// <param name="metadata">The metadata of the entity.</param>
2727
/// <typeparam name="TEntity">The type of the entity.</typeparam>
2828
/// <returns>The builder for chaining.</returns>
29-
IOperatorBuilder AddEntityMetadata<TEntity>(EntityMetadata metadata)
29+
IOperatorBuilder AddEntity<TEntity>(EntityMetadata metadata)
3030
where TEntity : IKubernetesObject<V1ObjectMeta>;
3131

3232
/// <summary>
@@ -48,7 +48,7 @@ IOperatorBuilder AddController<TImplementation, TEntity>()
4848
/// <typeparam name="TImplementation">Implementation type of the controller.</typeparam>
4949
/// <typeparam name="TEntity">Entity type.</typeparam>
5050
/// <returns>The builder for chaining.</returns>
51-
IOperatorBuilder AddController<TImplementation, TEntity>(EntityMetadata metadata)
51+
IOperatorBuilder AddControllerWithEntity<TImplementation, TEntity>(EntityMetadata metadata)
5252
where TImplementation : class, IEntityController<TEntity>
5353
where TEntity : IKubernetesObject<V1ObjectMeta>;
5454
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using k8s;
2+
using k8s.Models;
3+
4+
namespace KubeOps.Abstractions.Entities;
5+
6+
/// <summary>
7+
/// Type for a list of entities.
8+
/// </summary>
9+
/// <typeparam name="T">Type for the list entries.</typeparam>
10+
public class EntityList<T> : KubernetesObject
11+
where T : IKubernetesObject
12+
{
13+
/// <summary>
14+
/// Official list metadata object of kubernetes.
15+
/// </summary>
16+
public V1ListMeta Metadata { get; set; } = new();
17+
18+
/// <summary>
19+
/// The list of items.
20+
/// </summary>
21+
public IList<T> Items { get; set; } = new List<T>();
22+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using k8s;
2+
using k8s.Models;
3+
4+
namespace KubeOps.Abstractions.Entities;
5+
6+
/// <summary>
7+
/// Method extensions for <see cref="IKubernetesObject{TMetadata}"/>.
8+
/// </summary>
9+
public static class Extensions
10+
{
11+
/// <summary>
12+
/// Sets the resource version of the specified Kubernetes object to the specified value.
13+
/// </summary>
14+
/// <typeparam name="TEntity">The type of the Kubernetes object.</typeparam>
15+
/// <param name="entity">The Kubernetes object.</param>
16+
/// <param name="resourceVersion">The resource version to set.</param>
17+
/// <returns>The Kubernetes object with the updated resource version.</returns>
18+
public static TEntity WithResourceVersion<TEntity>(
19+
this TEntity entity,
20+
string resourceVersion)
21+
where TEntity : IKubernetesObject<V1ObjectMeta>
22+
{
23+
entity.EnsureMetadata().ResourceVersion = resourceVersion;
24+
return entity;
25+
}
26+
27+
/// <summary>
28+
/// Sets the resource version of the specified Kubernetes object to the resource version of another object.
29+
/// </summary>
30+
/// <typeparam name="TEntity">The type of the Kubernetes object.</typeparam>
31+
/// <param name="entity">The Kubernetes object.</param>
32+
/// <param name="other">The other Kubernetes object.</param>
33+
/// <returns>The Kubernetes object with the updated resource version.</returns>
34+
public static TEntity WithResourceVersion<TEntity>(
35+
this TEntity entity,
36+
TEntity other)
37+
where TEntity : IKubernetesObject<V1ObjectMeta>
38+
{
39+
entity.EnsureMetadata().ResourceVersion = other.ResourceVersion();
40+
return entity;
41+
}
42+
}

src/KubeOps.Generator/EntityDefinitions/EntityDefinitionGenerator.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using KubeOps.Generator.SyntaxReceiver;
2+
13
using Microsoft.CodeAnalysis;
24
using Microsoft.CodeAnalysis.CSharp;
35
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -93,7 +95,7 @@ public void Execute(GeneratorExecutionContext context)
9395
MemberAccessExpression(
9496
SyntaxKind.SimpleMemberAccessExpression,
9597
IdentifierName("builder"),
96-
GenericName(Identifier("AddEntityMetadata"))
98+
GenericName(Identifier("AddEntity"))
9799
.WithTypeArgumentList(
98100
TypeArgumentList(
99101
SingletonSeparatedList<TypeSyntax>(
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
using Microsoft.CodeAnalysis.CSharp.Syntax;
2-
3-
namespace KubeOps.Generator.EntityDefinitions;
4-
5-
public record struct AttributedEntity(
6-
ClassDeclarationSyntax Class,
7-
string Kind,
8-
string Version,
9-
string? Group,
10-
string? Plural);
1+
using Microsoft.CodeAnalysis.CSharp.Syntax;
2+
3+
namespace KubeOps.Generator.SyntaxReceiver;
4+
5+
public record struct AttributedEntity(
6+
ClassDeclarationSyntax Class,
7+
string Kind,
8+
string Version,
9+
string? Group,
10+
string? Plural);
Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,40 @@
1-
using Microsoft.CodeAnalysis;
2-
using Microsoft.CodeAnalysis.CSharp.Syntax;
3-
4-
namespace KubeOps.Generator.EntityDefinitions;
5-
6-
public class KubernetesEntitySyntaxReceiver : ISyntaxContextReceiver
7-
{
8-
private const string KindName = "Kind";
9-
private const string GroupName = "Group";
10-
private const string PluralName = "Plural";
11-
private const string VersionName = "ApiVersion";
12-
private const string DefaultVersion = "v1";
13-
14-
public List<AttributedEntity> Entities { get; } = new();
15-
16-
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
17-
{
18-
if (context.Node is not ClassDeclarationSyntax { AttributeLists.Count: > 0 } cls ||
19-
cls.AttributeLists.SelectMany(a => a.Attributes)
20-
.FirstOrDefault(a => a.Name.ToString() == "KubernetesEntity") is not { } attr)
21-
{
22-
return;
23-
}
24-
25-
Entities.Add(new(
26-
cls,
27-
GetArgumentValue(attr, KindName) ?? cls.Identifier.ToString(),
28-
GetArgumentValue(attr, VersionName) ?? DefaultVersion,
29-
GetArgumentValue(attr, GroupName),
30-
GetArgumentValue(attr, PluralName)));
31-
}
32-
33-
private static string? GetArgumentValue(AttributeSyntax attr, string argName) =>
34-
attr.ArgumentList?.Arguments.FirstOrDefault(a => a.NameEquals?.Name.ToString() == argName) is
35-
{ Expression: LiteralExpressionSyntax { Token.ValueText: { } value } }
36-
? value
37-
: null;
38-
}
1+
using KubeOps.Generator.EntityDefinitions;
2+
3+
using Microsoft.CodeAnalysis;
4+
using Microsoft.CodeAnalysis.CSharp.Syntax;
5+
6+
namespace KubeOps.Generator.SyntaxReceiver;
7+
8+
public class KubernetesEntitySyntaxReceiver : ISyntaxContextReceiver
9+
{
10+
private const string KindName = "Kind";
11+
private const string GroupName = "Group";
12+
private const string PluralName = "Plural";
13+
private const string VersionName = "ApiVersion";
14+
private const string DefaultVersion = "v1";
15+
16+
public List<AttributedEntity> Entities { get; } = new();
17+
18+
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
19+
{
20+
if (context.Node is not ClassDeclarationSyntax { AttributeLists.Count: > 0 } cls ||
21+
cls.AttributeLists.SelectMany(a => a.Attributes)
22+
.FirstOrDefault(a => a.Name.ToString() == "KubernetesEntity") is not { } attr)
23+
{
24+
return;
25+
}
26+
27+
Entities.Add(new(
28+
cls,
29+
GetArgumentValue(attr, KindName) ?? cls.Identifier.ToString(),
30+
GetArgumentValue(attr, VersionName) ?? DefaultVersion,
31+
GetArgumentValue(attr, GroupName),
32+
GetArgumentValue(attr, PluralName)));
33+
}
34+
35+
private static string? GetArgumentValue(AttributeSyntax attr, string argName) =>
36+
attr.ArgumentList?.Arguments.FirstOrDefault(a => a.NameEquals?.Name.ToString() == argName) is
37+
{ Expression: LiteralExpressionSyntax { Token.ValueText: { } value } }
38+
? value
39+
: null;
40+
}

0 commit comments

Comments
 (0)