using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using k8s.Models;
using k8s.Util.Common.Generic.Options;
using Microsoft.Rest;
using Microsoft.Rest.Serialization;
namespace k8s.Util.Common.Generic
{
///
///
/// The Generic kubernetes api provides a unified client interface for not only the non-core-group
/// built-in resources from kubernetes but also the custom-resources models meet the following
/// requirements:
///
/// 1. there's a `V1ObjectMeta` field in the model along with its getter/setter. 2. there's a
/// `V1ListMeta` field in the list model along with its getter/setter. - supports Json
/// serialization/deserialization. 3. the generic kubernetes api covers all the basic operations over
/// the custom resources including {get, list, watch, create, update, patch, delete}.
///
/// - For kubernetes-defined failures, the server will return a {@link V1Status} with 4xx/5xx
/// code. The status object will be nested in {@link KubernetesApiResponse#getStatus()} - For the
/// other unknown reason (including network, JVM..), throws an unchecked exception.
///
public class GenericKubernetesApi
{
private readonly string _apiGroup;
private readonly string _apiVersion;
private readonly string _resourcePlural;
private readonly IKubernetes _client;
///
/// Initializes a new instance of the class.
///
/// the api group">
/// the api version">
/// the resource plural, e.g. "jobs"">
/// optional client">
public GenericKubernetesApi(string apiGroup = default, string apiVersion = default, string resourcePlural = default, IKubernetes apiClient = default)
{
_apiGroup = apiGroup ?? throw new ArgumentNullException(nameof(apiGroup));
_apiVersion = apiVersion ?? throw new ArgumentNullException(nameof(apiVersion));
_resourcePlural = resourcePlural ?? throw new ArgumentNullException(nameof(resourcePlural));
_client = apiClient ?? new Kubernetes(KubernetesClientConfiguration.BuildDefaultConfig());
}
public TimeSpan ClientTimeout => _client.HttpClient.Timeout;
public void SetClientTimeout(TimeSpan value)
{
_client.HttpClient.Timeout = value;
}
///
/// Get kubernetes object.
///
/// the object type
/// the object name
/// the token
/// The object
public Task GetAsync(string name, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return GetAsync(name, new GetOptions(), cancellationToken);
}
///
/// Get kubernetes object under the namespaceProperty.
///
/// the object type
/// the namespaceProperty
/// the name
/// the token
/// the kubernetes object
public Task GetAsync(string namespaceProperty, string name, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return GetAsync(namespaceProperty, name, new GetOptions(), cancellationToken);
}
///
/// List kubernetes object cluster-scoped.
///
/// the object type
/// the token
/// the kubernetes object
public Task ListAsync(CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return ListAsync(new ListOptions(), cancellationToken);
}
///
/// List kubernetes object under the namespaceProperty.
///
/// the object type
/// the namespace
/// the token
/// the kubernetes object
public Task ListAsync(string namespaceProperty, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return ListAsync(namespaceProperty, new ListOptions(), cancellationToken);
}
///
/// Create kubernetes object, if the namespaceProperty in the object is present, it will send a
/// namespaceProperty-scoped requests, vice versa.
///
/// the object type
/// the object
/// the token
/// the kubernetes object
public Task CreateAsync(T obj, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return CreateAsync(obj, new CreateOptions(), cancellationToken);
}
///
/// Create kubernetes object, if the namespaceProperty in the object is present, it will send a
/// namespaceProperty-scoped requests, vice versa.
///
/// the object
/// the token
/// the object type
/// the kubernetes object
public Task UpdateAsync(T obj, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return UpdateAsync(obj, new UpdateOptions(), cancellationToken);
}
///
/// Patch kubernetes object.
///
/// the name
/// the string patch content
/// the token
/// the object type
/// the kubernetes object
public Task PatchAsync(string name, object patch, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return PatchAsync(name, patch, new PatchOptions(), cancellationToken);
}
///
/// Patch kubernetes object under the namespaceProperty.
///
/// the namespaceProperty
/// the name
/// the string patch content
/// the token
/// the object type
/// the kubernetes object
public Task PatchAsync(string namespaceProperty, string name, object patch, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return PatchAsync(namespaceProperty, name, patch, new PatchOptions(), cancellationToken);
}
///
/// Delete kubernetes object.
///
/// the name
/// the token
/// the object type
/// the kubernetes object
public Task DeleteAsync(string name, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return DeleteAsync(name, new V1DeleteOptions(), cancellationToken);
}
///
/// Delete kubernetes object under the namespaceProperty.
///
/// the namespaceProperty
/// the name
/// the token
/// the object type
/// the kubernetes object
public Task DeleteAsync(string namespaceProperty, string name, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return DeleteAsync(namespaceProperty, name, new V1DeleteOptions(), cancellationToken);
}
///
/// Creates a cluster-scoped Watch on the resource.
///
/// action on event
/// action on error
/// action on closed
/// the token
/// the object type
/// the watchable
public Watcher Watch(Action onEvent, Action onError = default, Action onClosed = default, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return Watch(new ListOptions(), onEvent, onError, onClosed, cancellationToken);
}
///
/// Creates a namespaceProperty-scoped Watch on the resource.
///
/// the object type
/// the namespaceProperty
/// action on event
/// action on error
/// action on closed
/// the token
/// the watchable
public Watcher Watch(string namespaceProperty, Action onEvent, Action onError = default, Action onClosed = default,
CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
return Watch(namespaceProperty, new ListOptions(), onEvent, onError, onClosed, cancellationToken);
}
// TODO(yue9944882): watch one resource?
///
/// Get kubernetes object.
///
/// the object type
/// the name
/// the get options
/// the token
/// the kubernetes object
public async Task GetAsync(string name, GetOptions getOptions, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name));
}
var resp = await _client.GetClusterCustomObjectWithHttpMessagesAsync(group: _apiGroup, plural: _resourcePlural, version: _apiVersion, name: name, cancellationToken: cancellationToken)
.ConfigureAwait(false);
return SafeJsonConvert.DeserializeObject(resp.Body.ToString());
}
///
/// Get kubernetes object.
///
/// the object type
/// the namespaceProperty
/// the name
/// the get options
/// the token
/// the kubernetes object
public async Task GetAsync(string namespaceProperty, string name, GetOptions getOptions, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name));
}
if (string.IsNullOrEmpty(namespaceProperty))
{
throw new ArgumentNullException(nameof(namespaceProperty));
}
var resp = await _client.GetNamespacedCustomObjectWithHttpMessagesAsync(group: _apiGroup, plural: _resourcePlural, version: _apiVersion, name: name, namespaceParameter: namespaceProperty,
cancellationToken: cancellationToken).ConfigureAwait(false);
return SafeJsonConvert.DeserializeObject(resp.Body.ToString());
}
///
/// List kubernetes object.
///
/// the object type
/// the list options
/// the token
/// the kubernetes object
public async Task ListAsync(ListOptions listOptions, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
if (listOptions == null)
{
throw new ArgumentNullException(nameof(listOptions));
}
var resp = await _client.ListClusterCustomObjectWithHttpMessagesAsync(group: _apiGroup, plural: _resourcePlural, version: _apiVersion, resourceVersion: listOptions.ResourceVersion,
continueParameter: listOptions.Continue, fieldSelector: listOptions.FieldSelector, labelSelector: listOptions.LabelSelector, limit: listOptions.Limit,
timeoutSeconds: listOptions.TimeoutSeconds, cancellationToken: cancellationToken).ConfigureAwait(false);
return SafeJsonConvert.DeserializeObject(resp.Body.ToString());
}
///
/// List kubernetes object.
///
/// the object type
/// the namespaceProperty
/// the list options
/// the token
/// the kubernetes object
public async Task ListAsync(string namespaceProperty, ListOptions listOptions, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
if (listOptions == null)
{
throw new ArgumentNullException(nameof(listOptions));
}
if (string.IsNullOrEmpty(namespaceProperty))
{
throw new ArgumentNullException(nameof(namespaceProperty));
}
var resp = await _client.ListNamespacedCustomObjectWithHttpMessagesAsync(group: _apiGroup, plural: _resourcePlural, version: _apiVersion, resourceVersion: listOptions.ResourceVersion,
continueParameter: listOptions.Continue, fieldSelector: listOptions.FieldSelector, labelSelector: listOptions.LabelSelector, limit: listOptions.Limit,
timeoutSeconds: listOptions.TimeoutSeconds, namespaceParameter: namespaceProperty, cancellationToken: cancellationToken).ConfigureAwait(false);
return SafeJsonConvert.DeserializeObject(resp.Body.ToString());
}
///
/// Create kubernetes object.
///
/// the object type
/// the object
/// the create options
/// the token
/// the kubernetes object
public async Task CreateAsync(T obj, CreateOptions createOptions, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}
if (createOptions == null)
{
throw new ArgumentNullException(nameof(createOptions));
}
V1ObjectMeta objectMeta = obj.Metadata;
var isNamespaced = !string.IsNullOrEmpty(objectMeta.NamespaceProperty);
if (isNamespaced)
{
return await CreateAsync(objectMeta.NamespaceProperty, obj, createOptions, cancellationToken).ConfigureAwait(false);
}
var resp = await _client.CreateClusterCustomObjectWithHttpMessagesAsync(body: obj, group: _apiGroup, plural: _resourcePlural, version: _apiVersion, dryRun: createOptions.DryRun,
fieldManager: createOptions.FieldManager, cancellationToken: cancellationToken).ConfigureAwait(false);
return SafeJsonConvert.DeserializeObject(resp.Body.ToString());
}
///
/// Create namespaced kubernetes object.
///
/// the object type
/// the namespace
/// the object
/// the create options
/// the token
/// the kubernetes object
public async Task CreateAsync(string namespaceProperty, T obj, CreateOptions createOptions, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}
if (createOptions == null)
{
throw new ArgumentNullException(nameof(createOptions));
}
var resp = await _client.CreateNamespacedCustomObjectWithHttpMessagesAsync(body: obj, group: _apiGroup, plural: _resourcePlural, version: _apiVersion,
namespaceParameter: namespaceProperty, dryRun: createOptions.DryRun, fieldManager: createOptions.FieldManager, cancellationToken: cancellationToken).ConfigureAwait(false);
return SafeJsonConvert.DeserializeObject(resp.Body.ToString());
}
///
/// Update kubernetes object.
///
/// the object type
/// the object
/// the update options
/// the token
/// the kubernetes object
public async Task UpdateAsync(T obj, UpdateOptions updateOptions, CancellationToken cancellationToken = default)
where T : class, IKubernetesObject
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}
if (updateOptions == null)
{
throw new ArgumentNullException(nameof(updateOptions));
}
V1ObjectMeta objectMeta = obj.Metadata;
var isNamespaced = !string.IsNullOrEmpty(objectMeta.NamespaceProperty);
HttpOperationResponse