diff --git a/src/KubernetesClient/GenericClient.cs b/src/KubernetesClient/GenericClient.cs index 277c6be22..e6c48c05d 100644 --- a/src/KubernetesClient/GenericClient.cs +++ b/src/KubernetesClient/GenericClient.cs @@ -1,3 +1,4 @@ +using k8s.Models; using System.Threading; using System.Threading.Tasks; @@ -86,6 +87,34 @@ public async Task DeleteNamespacedAsync(string ns, string name, Cancellati return KubernetesJson.Deserialize(resp.Body.ToString()); } + public async Task PatchAsync(V1Patch patch, string name, CancellationToken cancel = default) + where T : IKubernetesObject + { + var resp = await kubernetes.CustomObjects.PatchClusterCustomObjectWithHttpMessagesAsync(patch, group, version, plural, name, cancellationToken: cancel).ConfigureAwait(false); + return KubernetesJson.Deserialize(resp.Body.ToString()); + } + + public async Task PatchNamespacedAsync(V1Patch patch, string ns, string name, CancellationToken cancel = default) + where T : IKubernetesObject + { + var resp = await kubernetes.CustomObjects.PatchNamespacedCustomObjectWithHttpMessagesAsync(patch, group, version, ns, plural, name, cancellationToken: cancel).ConfigureAwait(false); + return KubernetesJson.Deserialize(resp.Body.ToString()); + } + + public async Task ReplaceAsync(T obj, string name, CancellationToken cancel = default) + where T : IKubernetesObject + { + var resp = await kubernetes.CustomObjects.ReplaceClusterCustomObjectWithHttpMessagesAsync(obj, group, version, plural, name, cancellationToken: cancel).ConfigureAwait(false); + return KubernetesJson.Deserialize(resp.Body.ToString()); + } + + public async Task ReplaceNamespacedAsync(T obj, string ns, string name, CancellationToken cancel = default) + where T : IKubernetesObject + { + var resp = await kubernetes.CustomObjects.ReplaceNamespacedCustomObjectWithHttpMessagesAsync(obj, group, version, ns, plural, name, cancellationToken: cancel).ConfigureAwait(false); + return KubernetesJson.Deserialize(resp.Body.ToString()); + } + public void Dispose() { Dispose(true); diff --git a/tests/E2E.Tests/MinikubeTests.cs b/tests/E2E.Tests/MinikubeTests.cs index 1ee33a43f..de68c2fd6 100644 --- a/tests/E2E.Tests/MinikubeTests.cs +++ b/tests/E2E.Tests/MinikubeTests.cs @@ -504,45 +504,78 @@ void Cleanup() { Cleanup(); - await genericPods.CreateNamespacedAsync( - new V1Pod() - { - Metadata = new V1ObjectMeta { Name = podName, }, - Spec = new V1PodSpec + // create + list + { + await genericPods.CreateNamespacedAsync( + new V1Pod() { - Containers = new[] { new V1Container() { Name = "k8scsharp-e2e", Image = "nginx", }, }, + Metadata = new V1ObjectMeta { Name = podName, Labels = new Dictionary { { "place", "holder" }, }, }, + Spec = new V1PodSpec + { + Containers = new[] { new V1Container() { Name = "k8scsharp-e2e", Image = "nginx", }, }, + }, }, - }, - namespaceParameter).ConfigureAwait(false); + namespaceParameter).ConfigureAwait(false); - var pods = await genericPods.ListNamespacedAsync(namespaceParameter).ConfigureAwait(false); - Assert.Contains(pods.Items, p => p.Metadata.Name == podName); + var pods = await genericPods.ListNamespacedAsync(namespaceParameter).ConfigureAwait(false); + Assert.Contains(pods.Items, p => p.Metadata.Name == podName); + } - int retry = 5; - while (retry-- > 0) + // replace + get { - try - { - await genericPods.DeleteNamespacedAsync(namespaceParameter, podName).ConfigureAwait(false); - } - catch (HttpOperationException e) + var pod = await genericPods.ReadNamespacedAsync(namespaceParameter, podName).ConfigureAwait(false); + var old = JsonSerializer.SerializeToDocument(pod); + + var newlabels = new Dictionary(pod.Metadata.Labels) { ["test"] = "generic-test-jsonpatch" }; + pod.Metadata.Labels = newlabels; + + var expected = JsonSerializer.SerializeToDocument(pod); + var patch = old.CreatePatch(expected); + + await genericPods.PatchNamespacedAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), namespaceParameter, podName).ConfigureAwait(false); + var pods = await genericPods.ListNamespacedAsync(namespaceParameter).ConfigureAwait(false); + Assert.Contains(pods.Items, p => p.Labels().Contains(new KeyValuePair("test", "generic-test-jsonpatch"))); + } + + // replace + get + { + var pod = await genericPods.ReadNamespacedAsync(namespaceParameter, podName).ConfigureAwait(false); + pod.Spec.Containers[0].Image = "httpd"; + await genericPods.ReplaceNamespacedAsync(pod, namespaceParameter, podName).ConfigureAwait(false); + + pod = await genericPods.ReadNamespacedAsync(namespaceParameter, podName).ConfigureAwait(false); + Assert.Equal("httpd", pod.Spec.Containers[0].Image); + } + + // delete + list + { + V1PodList pods = new V1PodList(); + int retry = 5; + while (retry-- > 0) { - if (e.Response.StatusCode == System.Net.HttpStatusCode.NotFound) + try { - return; + await genericPods.DeleteNamespacedAsync(namespaceParameter, podName).ConfigureAwait(false); + } + catch (HttpOperationException e) + { + if (e.Response.StatusCode == System.Net.HttpStatusCode.NotFound) + { + return; + } } - } - pods = await genericPods.ListNamespacedAsync(namespaceParameter).ConfigureAwait(false); - if (!pods.Items.Any(p => p.Metadata.Name == podName)) - { - break; + pods = await genericPods.ListNamespacedAsync(namespaceParameter).ConfigureAwait(false); + if (!pods.Items.Any(p => p.Metadata.Name == podName)) + { + break; + } + + await Task.Delay(TimeSpan.FromSeconds(2.5)).ConfigureAwait(false); } - await Task.Delay(TimeSpan.FromSeconds(2.5)).ConfigureAwait(false); + Assert.DoesNotContain(pods.Items, p => p.Metadata.Name == podName); } - - Assert.DoesNotContain(pods.Items, p => p.Metadata.Name == podName); } finally {