Skip to content

Commit fc8f725

Browse files
committed
feat(client): add async/sync variants
BREAKING CHANGE: all calls that were async before are now sync. There are async variants of all calls with the Async suffix. Signed-off-by: Christoph Bühler <[email protected]>
1 parent ddea816 commit fc8f725

File tree

10 files changed

+445
-85
lines changed

10 files changed

+445
-85
lines changed

examples/Operator/Controller/V1TestEntityController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ public async Task ReconcileAsync(V1TestEntity entity)
3838
entity = await _finalizer2(entity);
3939

4040
entity.Status.Status = "Reconciling";
41-
entity = await _client.UpdateStatus(entity);
41+
entity = await _client.UpdateStatusAsync(entity);
4242
entity.Status.Status = "Reconciled";
43-
await _client.UpdateStatus(entity);
43+
await _client.UpdateStatusAsync(entity);
4444
}
4545

4646
public Task DeletedAsync(V1TestEntity entity)

examples/Operator/todos.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,5 @@
1010
- cache?
1111
- try .net 8 AOT?
1212
- client:
13-
// TODO: make all sync calls as well.
1413
// TODO: test list / get call.
1514
// TODO: update list call

src/KubeOps.KubernetesClient/IKubernetesClient.cs

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ public interface IKubernetesClient<TEntity> : IDisposable
4545
/// </summary>
4646
/// <param name="downwardApiEnvName">Customizable name of the env var to check for the namespace.</param>
4747
/// <returns>A string containing the current namespace (or a fallback of it).</returns>
48-
Task<string> GetCurrentNamespace(string downwardApiEnvName = "POD_NAMESPACE");
48+
Task<string> GetCurrentNamespaceAsync(string downwardApiEnvName = "POD_NAMESPACE");
49+
50+
/// <inheritdoc cref="GetCurrentNamespaceAsync" />
51+
string GetCurrentNamespace(string downwardApiEnvName = "POD_NAMESPACE");
4952

5053
/// <summary>
5154
/// Fetch and return an entity from the Kubernetes API.
@@ -56,15 +59,18 @@ public interface IKubernetesClient<TEntity> : IDisposable
5659
/// If it is omitted, the entity must be a cluster wide entity.
5760
/// </param>
5861
/// <returns>The found entity of the given type, or null otherwise.</returns>
59-
Task<TEntity?> Get(string name, string? @namespace = null);
62+
Task<TEntity?> GetAsync(string name, string? @namespace = null);
63+
64+
/// <inheritdoc cref="GetAsync"/>
65+
TEntity? Get(string name, string? @namespace = null);
6066

6167
/// <summary>
6268
/// Fetch and return a list of entities from the Kubernetes API.
6369
/// </summary>
6470
/// <param name="namespace">If the entities are namespaced, provide the name of the namespace.</param>
6571
/// <param name="labelSelector">A string, representing an optional label selector for filtering fetched objects.</param>
6672
/// <returns>A list of Kubernetes entities.</returns>
67-
Task<IList<TEntity>> List(
73+
Task<IList<TEntity>> ListAsync(
6874
string? @namespace = null,
6975
string? labelSelector = null);
7076

@@ -76,7 +82,17 @@ Task<IList<TEntity>> List(
7682
/// </param>
7783
/// <param name="labelSelectors">A list of label-selectors to apply to the search.</param>
7884
/// <returns>A list of Kubernetes entities.</returns>
79-
Task<IList<TEntity>> List(
85+
Task<IList<TEntity>> ListAsync(
86+
string? @namespace = null,
87+
params LabelSelector[] labelSelectors);
88+
89+
/// <inheritdoc cref="ListAsync(string?,string?)"/>
90+
IList<TEntity> List(
91+
string? @namespace = null,
92+
string? labelSelector = null);
93+
94+
/// <inheritdoc cref="ListAsync(string?,LabelSelector[])"/>
95+
IList<TEntity> List(
8096
string? @namespace = null,
8197
params LabelSelector[] labelSelectors);
8298

@@ -86,61 +102,89 @@ Task<IList<TEntity>> List(
86102
/// </summary>
87103
/// <param name="entity">The entity in question.</param>
88104
/// <returns>The saved instance of the entity.</returns>
89-
async Task<TEntity> Save(TEntity entity) => await Get(entity.Name(), entity.Namespace()) switch
105+
async Task<TEntity> SaveAsync(TEntity entity) => await GetAsync(entity.Name(), entity.Namespace()) switch
106+
{
107+
{ } e => await UpdateAsync(entity.WithResourceVersion(e)),
108+
_ => await CreateAsync(entity),
109+
};
110+
111+
/// <inheritdoc cref="SaveAsync"/>
112+
TEntity Save(TEntity entity) => Get(entity.Name(), entity.Namespace()) switch
90113
{
91-
{ } e => await Update(entity.WithResourceVersion(e)),
92-
_ => await Create(entity),
114+
{ } e => Update(entity.WithResourceVersion(e)),
115+
_ => Create(entity),
93116
};
94117

95118
/// <summary>
96119
/// Create the given entity on the Kubernetes API.
97120
/// </summary>
98121
/// <param name="entity">The entity instance.</param>
99122
/// <returns>The created instance of the entity.</returns>
100-
Task<TEntity> Create(TEntity entity);
123+
Task<TEntity> CreateAsync(TEntity entity);
124+
125+
/// <inheritdoc cref="CreateAsync"/>
126+
TEntity Create(TEntity entity);
101127

102128
/// <summary>
103129
/// Update the given entity on the Kubernetes API.
104130
/// </summary>
105131
/// <param name="entity">The entity instance.</param>
106132
/// <returns>The updated instance of the entity.</returns>
107-
Task<TEntity> Update(TEntity entity);
133+
Task<TEntity> UpdateAsync(TEntity entity);
134+
135+
/// <inheritdoc cref="UpdateAsync"/>
136+
TEntity Update(TEntity entity);
108137

109138
/// <summary>
110139
/// Update the status object of a given entity on the Kubernetes API.
111140
/// </summary>
112141
/// <param name="entity">The entity that contains a status object.</param>
142+
/// <returns>The entity with the updated status.</returns>
143+
Task<TEntity> UpdateStatusAsync(TEntity entity);
144+
145+
/// <inheritdoc cref="UpdateStatusAsync"/>
146+
TEntity UpdateStatus(TEntity entity);
147+
148+
/// <inheritdoc cref="Delete(TEntity)"/>
113149
/// <returns>A task that completes when the call was made.</returns>
114-
public Task<TEntity> UpdateStatus(TEntity entity);
150+
Task DeleteAsync(TEntity entity);
151+
152+
/// <inheritdoc cref="Delete(IEnumerable{TEntity})"/>
153+
/// <returns>A task that completes when the call was made.</returns>
154+
Task DeleteAsync(IEnumerable<TEntity> entities);
155+
156+
/// <inheritdoc cref="Delete(TEntity[])"/>
157+
/// <returns>A task that completes when the call was made.</returns>
158+
Task DeleteAsync(params TEntity[] entities);
159+
160+
/// <inheritdoc cref="Delete(string,string?)"/>
161+
/// <returns>A task that completes when the call was made.</returns>
162+
Task DeleteAsync(string name, string? @namespace = null);
115163

116164
/// <summary>
117165
/// Delete a given entity from the Kubernetes API.
118166
/// </summary>
119167
/// <param name="entity">The entity in question.</param>
120-
/// <returns>A task that completes when the call was made.</returns>
121-
Task Delete(TEntity entity);
168+
void Delete(TEntity entity);
122169

123170
/// <summary>
124171
/// Delete a given list of entities from the Kubernetes API.
125172
/// </summary>
126173
/// <param name="entities">The entities in question.</param>
127-
/// <returns>A task that completes when the calls were made.</returns>
128-
Task Delete(IEnumerable<TEntity> entities);
174+
void Delete(IEnumerable<TEntity> entities);
129175

130176
/// <summary>
131177
/// Delete a given list of entities from the Kubernetes API.
132178
/// </summary>
133179
/// <param name="entities">The entities in question.</param>
134-
/// <returns>A task that completes when the calls were made.</returns>
135-
Task Delete(params TEntity[] entities);
180+
void Delete(params TEntity[] entities);
136181

137182
/// <summary>
138183
/// Delete a given entity by name from the Kubernetes API.
139184
/// </summary>
140185
/// <param name="name">The name of the entity.</param>
141186
/// <param name="namespace">The optional namespace of the entity.</param>
142-
/// <returns>A task that completes when the call was made.</returns>
143-
Task Delete(string name, string? @namespace = null);
187+
void Delete(string name, string? @namespace = null);
144188

145189
/// <summary>
146190
/// Create a entity watcher on the Kubernetes API.

src/KubeOps.KubernetesClient/KubernetesClient.cs

Lines changed: 124 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public KubernetesClient(EntityMetadata metadata, KubernetesClientConfiguration c
7272
public Uri BaseUri => _client.BaseUri;
7373

7474
/// <inheritdoc />
75-
public async Task<string> GetCurrentNamespace(string downwardApiEnvName = "POD_NAMESPACE")
75+
public async Task<string> GetCurrentNamespaceAsync(string downwardApiEnvName = "POD_NAMESPACE")
7676
{
7777
if (_clientConfig.Namespace is { } configValue)
7878
{
@@ -94,7 +94,29 @@ public async Task<string> GetCurrentNamespace(string downwardApiEnvName = "POD_N
9494
}
9595

9696
/// <inheritdoc />
97-
public async Task<TEntity?> Get(string name, string? @namespace = null)
97+
public string GetCurrentNamespace(string downwardApiEnvName = "POD_NAMESPACE")
98+
{
99+
if (_clientConfig.Namespace is { } configValue)
100+
{
101+
return configValue;
102+
}
103+
104+
if (Environment.GetEnvironmentVariable(downwardApiEnvName) is { } envValue)
105+
{
106+
return envValue;
107+
}
108+
109+
if (File.Exists(DownwardApiNamespaceFile))
110+
{
111+
var ns = File.ReadAllText(DownwardApiNamespaceFile);
112+
return ns.Trim();
113+
}
114+
115+
return DefaultNamespace;
116+
}
117+
118+
/// <inheritdoc />
119+
public async Task<TEntity?> GetAsync(string name, string? @namespace = null)
98120
{
99121
var list = @namespace switch
100122
{
@@ -119,7 +141,32 @@ public async Task<string> GetCurrentNamespace(string downwardApiEnvName = "POD_N
119141
}
120142

121143
/// <inheritdoc />
122-
public async Task<IList<TEntity>> List(string? @namespace = null, string? labelSelector = null)
144+
public TEntity? Get(string name, string? @namespace = null)
145+
{
146+
var list = @namespace switch
147+
{
148+
null => _client.CustomObjects.ListClusterCustomObject<EntityList<TEntity>>(
149+
_metadata.Group ?? string.Empty,
150+
_metadata.Version,
151+
_metadata.PluralName,
152+
fieldSelector: $"metadata.name={name}"),
153+
_ => _client.CustomObjects.ListNamespacedCustomObject<EntityList<TEntity>>(
154+
_metadata.Group ?? string.Empty,
155+
_metadata.Version,
156+
@namespace,
157+
_metadata.PluralName,
158+
fieldSelector: $"metadata.name={name}"),
159+
};
160+
161+
return list switch
162+
{
163+
{ Items: [var existing] } => existing,
164+
_ => default,
165+
};
166+
}
167+
168+
/// <inheritdoc />
169+
public async Task<IList<TEntity>> ListAsync(string? @namespace = null, string? labelSelector = null)
123170
=> (@namespace switch
124171
{
125172
null => await _client.CustomObjects.ListClusterCustomObjectAsync<EntityList<TEntity>>(
@@ -136,27 +183,56 @@ public async Task<IList<TEntity>> List(string? @namespace = null, string? labelS
136183
}).Items;
137184

138185
/// <inheritdoc />
139-
public Task<IList<TEntity>> List(string? @namespace = null, params LabelSelector[] labelSelectors)
186+
public Task<IList<TEntity>> ListAsync(string? @namespace = null, params LabelSelector[] labelSelectors)
187+
=> ListAsync(@namespace, labelSelectors.ToExpression());
188+
189+
/// <inheritdoc />
190+
public IList<TEntity> List(string? @namespace = null, string? labelSelector = null)
191+
=> (@namespace switch
192+
{
193+
null => _client.CustomObjects.ListClusterCustomObject<EntityList<TEntity>>(
194+
_metadata.Group ?? string.Empty,
195+
_metadata.Version,
196+
_metadata.PluralName,
197+
labelSelector: labelSelector),
198+
_ => _client.CustomObjects.ListNamespacedCustomObject<EntityList<TEntity>>(
199+
_metadata.Group ?? string.Empty,
200+
_metadata.Version,
201+
@namespace,
202+
_metadata.PluralName,
203+
labelSelector: labelSelector),
204+
}).Items;
205+
206+
/// <inheritdoc />
207+
public IList<TEntity> List(string? @namespace = null, params LabelSelector[] labelSelectors)
140208
=> List(@namespace, labelSelectors.ToExpression());
141209

142210
/// <inheritdoc />
143-
public Task<TEntity> Create(TEntity entity)
211+
public Task<TEntity> CreateAsync(TEntity entity)
144212
=> entity.Namespace() switch
145213
{
146214
{ } ns => _genericClient.CreateNamespacedAsync(entity, ns),
147215
null => _genericClient.CreateAsync(entity),
148216
};
149217

150218
/// <inheritdoc />
151-
public Task<TEntity> Update(TEntity entity)
219+
public TEntity Create(TEntity entity)
220+
=> CreateAsync(entity).GetAwaiter().GetResult();
221+
222+
/// <inheritdoc />
223+
public Task<TEntity> UpdateAsync(TEntity entity)
152224
=> entity.Namespace() switch
153225
{
154226
{ } ns => _genericClient.ReplaceNamespacedAsync(entity, ns, entity.Name()),
155227
null => _genericClient.ReplaceAsync(entity, entity.Name()),
156228
};
157229

158230
/// <inheritdoc />
159-
public Task<TEntity> UpdateStatus(TEntity entity)
231+
public TEntity Update(TEntity entity)
232+
=> UpdateAsync(entity).GetAwaiter().GetResult();
233+
234+
/// <inheritdoc />
235+
public Task<TEntity> UpdateStatusAsync(TEntity entity)
160236
=> entity.Namespace() switch
161237
{
162238
{ } ns => _client.CustomObjects.ReplaceNamespacedCustomObjectStatusAsync<TEntity>(
@@ -175,20 +251,39 @@ public Task<TEntity> UpdateStatus(TEntity entity)
175251
};
176252

177253
/// <inheritdoc />
178-
public Task Delete(TEntity entity) => Delete(
254+
public TEntity UpdateStatus(TEntity entity)
255+
=> entity.Namespace() switch
256+
{
257+
{ } ns => _client.CustomObjects.ReplaceNamespacedCustomObjectStatus<TEntity>(
258+
entity,
259+
_metadata.Group ?? string.Empty,
260+
_metadata.Version,
261+
ns,
262+
_metadata.PluralName,
263+
entity.Name()),
264+
_ => _client.CustomObjects.ReplaceClusterCustomObjectStatus<TEntity>(
265+
entity,
266+
_metadata.Group ?? string.Empty,
267+
_metadata.Version,
268+
_metadata.PluralName,
269+
entity.Name()),
270+
};
271+
272+
/// <inheritdoc />
273+
public Task DeleteAsync(TEntity entity) => DeleteAsync(
179274
entity.Name(),
180275
entity.Namespace());
181276

182277
/// <inheritdoc />
183-
public Task Delete(IEnumerable<TEntity> entities) =>
184-
Task.WhenAll(entities.Select(Delete));
278+
public Task DeleteAsync(IEnumerable<TEntity> entities) =>
279+
Task.WhenAll(entities.Select(DeleteAsync));
185280

186281
/// <inheritdoc />
187-
public Task Delete(params TEntity[] entities) =>
188-
Task.WhenAll(entities.Select(Delete));
282+
public Task DeleteAsync(params TEntity[] entities) =>
283+
Task.WhenAll(entities.Select(DeleteAsync));
189284

190285
/// <inheritdoc />
191-
public async Task Delete(string name, string? @namespace = null)
286+
public async Task DeleteAsync(string name, string? @namespace = null)
192287
{
193288
try
194289
{
@@ -208,6 +303,22 @@ public async Task Delete(string name, string? @namespace = null)
208303
}
209304
}
210305

306+
/// <inheritdoc />
307+
public void Delete(TEntity entity)
308+
=> DeleteAsync(entity).GetAwaiter().GetResult();
309+
310+
/// <inheritdoc />
311+
public void Delete(IEnumerable<TEntity> entities)
312+
=> DeleteAsync(entities).GetAwaiter().GetResult();
313+
314+
/// <inheritdoc />
315+
public void Delete(params TEntity[] entities)
316+
=> DeleteAsync(entities).GetAwaiter().GetResult();
317+
318+
/// <inheritdoc />
319+
public void Delete(string name, string? @namespace = null)
320+
=> DeleteAsync(name, @namespace).GetAwaiter().GetResult();
321+
211322
/// <inheritdoc />
212323
public Watcher<TEntity> Watch(
213324
Action<WatchEventType, TEntity> onEvent,

src/KubeOps.Operator/Builder/OperatorBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public IOperatorBuilder AddFinalizer<TImplementation, TEntity>(string identifier
7272
identifier,
7373
entity.Kind,
7474
entity.Name());
75-
return await client.Update(entity);
75+
return await client.UpdateAsync(entity);
7676
});
7777

7878
return this;

src/KubeOps.Operator/Watcher/ResourceWatcher{TEntity}.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ private async Task ReconcileFinalizer(TEntity entity)
202202

203203
await finalizer.FinalizeAsync(entity);
204204
entity.RemoveFinalizer(identifier);
205-
await _client.Update(entity);
205+
await _client.UpdateAsync(entity);
206206
_logger.LogInformation(
207207
"""Entity "{kind}/{name}" finalized with "{finalizer}".""",
208208
entity.Kind,

0 commit comments

Comments
 (0)