src/common/Kubernetes/IKubernetesClient.cs (171 lines of code) (raw):
// --------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
// --------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using k8s;
using k8s.Autorest;
using k8s.Models;
using Microsoft.BridgeToKubernetes.Common.Attributes;
using Microsoft.BridgeToKubernetes.RoutingManager.Traefik;
namespace Microsoft.BridgeToKubernetes.Common.Kubernetes
{
/// <summary>
/// Kubernetes resource types.
/// </summary>
internal enum KubernetesResourceType
{
/// <summary>
/// Namespace.
/// </summary>
[StringValue("Namespace")]
Namespace,
/// <summary>
/// Pod.
/// </summary>
[StringValue("Pod")]
Pod,
/// <summary>
/// Deployment.
/// </summary>
[StringValue("Deployment")]
Deployment,
/// <summary>
/// Service
/// </summary>
[StringValue("Service")]
Service,
/// <summary>
/// Secret.
/// </summary>
[StringValue("Secret")]
Secret,
/// <summary>
/// Config map.
/// </summary>
[StringValue("ConfigMap")]
ConfigMap,
/// <summary>
/// Daemon set.
/// </summary>
[StringValue("DaemonSet")]
DaemonSet,
/// <summary>
/// Stateful Set
/// </summary>
[StringValue("StatefulSet")]
StatefulSet,
/// <summary>
/// Ingress
/// </summary>
[StringValue("Ingress")]
Ingress,
/// <summary>
/// IngressRoute - this is a CRD supported by Traefik
/// </summary>
/// <remarks>https://github.com/projectcontour/contour/blob/main/design/ingressroute-design.md</remarks>
[StringValue("IngressRoute")]
IngressRoute,
/// <summary>
/// Mutating Webhook
/// </summary>
[StringValue("MutatingWebhookConfiguration")]
MutatingWebhookConfiguration,
/// <summary>
/// Cluster Role binding
/// </summary>
[StringValue("ClusterRoleBinding")]
ClusterRoleBinding,
/// <summary>
/// Service Account
/// </summary>
[StringValue("ServiceAccount")]
ServiceAccount,
/// <summary>
/// ClusterRole
/// </summary>
[StringValue("ClusterRole")]
ClusterRole,
/// <summary>
/// Job
/// </summary>
[StringValue("Job")]
Job
}
/// <summary>
/// IKubernetesClient interface encapsulates Kubernetes functionalities Bridge to Kubernetes uses.
/// </summary>
/// <remarks>
/// This interface is intended to represent vanilla Kubernetes functionality ONLY.
/// E.g. Methods should only deal with types from the <see cref="k8s.Models"/> namespace, NOT any of our clones/extensions.
/// Anything considered "Mindaro-specific" should live somewhere else.
/// </remarks>
internal interface IKubernetesClient
{
string HostName { get; }
/// <summary>
/// Retrieve the list of user namespaces.
/// </summary>
/// <param name="labels">Labels to filter the namespaces on.</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<V1NamespaceList> ListNamespacesAsync(IEnumerable<KeyValuePair<string, string>> labels = null, CancellationToken cancellationToken = default(CancellationToken));
#region Pods
/// <summary>
/// Get first pod that matches with input label
/// </summary>
Task<V1Pod> GetFirstNamespacedPodWithLabelWithRunningContainerAsync(string namespaceName, string containerName, KeyValuePair<string, string> label, CancellationToken cancellationToken);
/// <summary>
/// List all pods that belong to a deployment
/// </summary>
Task<V1PodList> ListPodsForDeploymentAsync(string namespaceName, string deploymentName, CancellationToken cancellationToken);
/// <summary>
/// Get V1 pod.
/// </summary>
Task<V1Pod> GetV1PodAsync(string namespaceName, string podName, CancellationToken cancellationToken);
/// <summary>
/// List pods in specified namespace.
/// </summary>
Task<V1PodList> ListPodsInNamespaceAsync(string namespaceName, IEnumerable<KeyValuePair<string, string>> labels = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Creates a pod from the pod spec.
/// </summary>
Task<V1Pod> CreateV1PodAsync(string namespaceName, V1Pod pod, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Patch a namespaced pod.
/// </summary>
Task<V1Pod> PatchV1PodAsync(string namespaceName, string podName, V1Patch podPatch, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Delete V1 pod.
/// </summary>
Task DeleteV1PodAsync(string namespaceName, string podName, CancellationToken cancellationToken);
/// <summary>
/// Watch pod in the namespace
/// </summary>
Task<HttpOperationResponse<V1PodList>> WatchV1PodAsync(string namespaceName, string podName, int timeoutSeconds, CancellationToken cancellationToken);
/// <summary>
/// Start port forwarding one or more ports for a pod
/// </summary>
Task<WebSocket> WebSocketPodPortForwardAsync(string namespaceName, string podName, IEnumerable<int> remotePorts, string webSocketProtocol = null, CancellationToken cancellationToken = default(CancellationToken));
#endregion Pods
#region Services
/// <summary>
/// Get a V1 service in a namespace
/// </summary>
Task<V1Service> GetV1ServiceAsync(string namespaceName, string serviceName, CancellationToken cancellationToken);
/// <summary>
/// List services in specified namespace.
/// </summary>
Task<V1ServiceList> ListServicesInNamespaceAsync(string namespaceName, IEnumerable<KeyValuePair<string, string>> labels = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Creates or replace a service from the service spec.
/// </summary>
Task<V1Service> CreateOrReplaceV1ServiceAsync(string namespaceName, V1Service service, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Replaces a service from the service spec
/// </summary>
Task<V1Service> ReplaceV1ServiceAsync(string namespaceName, V1Service service, string name, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Deletes a service from the namespace
/// </summary>
Task<V1Service> DeleteV1ServiceAsync(string namespaceName, string name, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Create a service in a namespace
/// </summary>
Task<V1Service> CreateNamespacedServiceAsync(string namespaceName, V1Service service, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Lists the load balancer services in a namespace
/// </summary>
public Task<IEnumerable<V1Service>> ListLoadBalancerServicesInNamespaceAsync(string namespaceName, CancellationToken cancellationToken);
#endregion Services
#region Endpoints
/// <summary>
/// Retrieves an endpoint object in the specified namespace
/// </summary>
Task<V1Endpoints> GetEndpointInNamespaceAsync(string endpointName, string namespaceName, CancellationToken cancellationToken);
/// <summary>
/// List endpoints in specified namespace.
/// </summary>
Task<V1EndpointsList> ListEndpointsInNamespaceAsync(string namespaceName, CancellationToken cancellationToken, IEnumerable<KeyValuePair<string, string>> labels = null);
#endregion Endpoints
#region Replica Sets
/// <summary>
/// Get V1 replica set
/// </summary>
Task<V1ReplicaSet> GetV1ReplicaSetAsync(string namespaceName, string replicaSetName, CancellationToken cancellationToken);
/// <summary>
/// List replica sets in specified namespace.
/// </summary>
Task<V1ReplicaSetList> ListReplicaSetsInNamespaceAsync(string namespaceName, IEnumerable<KeyValuePair<string, string>> labels = null, CancellationToken cancellationToken = default(CancellationToken));
#endregion Replica Sets
#region Stateful Sets
/// <summary>
/// Get V1 stateful set
/// </summary>
Task<V1StatefulSet> GetV1StatefulSetAsync(string namespaceName, string statefulSetName, CancellationToken cancellationToken);
/// <summary>
/// List all pods that belong to a stateful set
/// </summary>
Task<V1PodList> ListPodsForStatefulSetAsync(string namespaceName, string statefulSetName, CancellationToken cancellationToken);
/// <summary>
/// Patch a namespaced stateful set.
/// </summary>
Task<V1StatefulSet> PatchV1StatefulSetAsync(string namespaceName, string statefulSetName, V1Patch statefulSetPatch, CancellationToken cancellationToken = default(CancellationToken));
#endregion Stateful Sets
#region Deployments
/// <summary>
/// Create or replace a namespaced deployment.
/// </summary>
Task<V1Deployment> CreateOrReplaceV1DeploymentAsync(string namespaceName, V1Deployment deployment, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Creates a namespaced deployment.
/// </summary>
Task<V1Deployment> CreateNamespacedDeploymentAsync(string namespaceName, V1Deployment deployment, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Replaces a namespaced deployment.
/// </summary>
Task<V1Deployment> ReplaceNamespacedDeploymentAsync(string namespaceName, V1Deployment deployment, string name, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Read a namespaced deployment status.
/// </summary>
Task<V1Deployment> ReadNamespacedDeploymentStatusAsync(string namespaceName, string name, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// List deployments in specified namespace
/// </summary>
Task<V1DeploymentList> ListDeploymentsInNamespaceAsync(string namespaceName, CancellationToken cancellationToken);
/// <summary>
/// List deployments in specified namespace
/// </summary>
Task<V1Status> DeleteDeploymentsInNamespaceAsync(string namespaceName, string name, CancellationToken cancellationToken);
/// <summary>
/// Patch a namespaced deployment.
/// </summary>
Task<V1Deployment> PatchV1DeploymentAsync(string namespaceName, string deploymentName, V1Patch deploymentPatch, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Watch deployment in the namespace
/// </summary>
Task<HttpOperationResponse<V1DeploymentList>> WatchV1DeploymentAsync(string namespaceName, string deploymentName, int timeoutSeconds, CancellationToken cancellationToken);
/// <summary>
/// Get V1 deployment
/// </summary>
Task<V1Deployment> GetV1DeploymentAsync(string namespaceName, string deploymentName, CancellationToken cancellationToken);
#endregion Deployments
#region Secrets
/// <summary>
/// Read a secret in specified namespace
/// </summary>
Task<V1Secret> ReadNamespacedSecretAsync(string namespaceName, string secretName, CancellationToken cancellationToken);
/// <summary>
/// Creates a secret in the specified namespace
/// </summary>
Task<V1Secret> CreateNamespacedSecretAsync(string namespaceName, V1Secret secret, CancellationToken cancellationToken);
#endregion Secrets
#region Jobs
/// <summary>
/// Creates a job in the specified namespace
/// </summary>
Task<V1Job> CreateNamespacedJobAsync(string namespaceName, V1Job job, CancellationToken cancellationToken);
#endregion Jobs
#region Ingress
/// <summary>
/// List ingresses in a namespace
/// </summary>
Task<V1IngressList> ListIngressesInNamespaceAsync(string namespaceName, CancellationToken cancellationToken);
/// <summary>
/// Create an ingress in a namespace
/// </summary>
Task<V1Ingress> CreateNamespacedIngressAsync(string namespaceName, V1Ingress body, CancellationToken cancellationToken);
/// <summary>
/// Deletes an ingress from a namespace
/// </summary>
Task<V1Status> DeleteNamespacedIngressAsync(string namespaceName, string name, CancellationToken cancellationToken);
/// <summary>
/// Replaces an ingress in a namespace
/// </summary>
Task<V1Ingress> ReplaceNamespacedIngress1Async(string namespaceName, V1Ingress body, string name, CancellationToken cancellationToken);
#endregion Ingress
#region IngressRoute
/// <summary>
/// List IngressRoutes (CRD for Traefik) in a namespace
/// </summary>
/// <remarks><see cref="IngressRoute"/>IngressRoute</remarks>
Task<IEnumerable<IngressRoute>> ListNamespacedIngressRoutesAsync(string namespaceName, CancellationToken cancellationToken);
/// <summary>
/// Create an IngressRoute in a namespace
/// </summary>
/// <remarks><see cref="IngressRoute"/>IngressRoute</remarks>
Task<bool> ApplyNamespacedIngressRouteAsync(string namespaceName, IngressRoute ingressRoute, CancellationToken cancellationToken);
/// <summary>
/// Delete an IngressRoute in a namespace
/// </summary>
/// <remarks><see cref="IngressRoute"/>IngressRoute</remarks>
Task<bool> DeleteNamespacedIngressRouteAsync(string namespaceName, string ingressRouteName, CancellationToken cancellationToken);
#endregion IngressRoute
#region ConfigMap
/// <summary>
/// Get config map in a namespace
/// </summary>
Task<V1ConfigMap> GetConfigMapAsync(string namespaceName, string configMapName, CancellationToken cancellationToken);
/// <summary>
/// Create config map in a namespace
/// </summary>
Task<V1ConfigMap> CreateNamespacedConfigMapAsync(string namespaceName, V1ConfigMap configMap, CancellationToken cancellationToken);
/// <summary>
/// Delete a config map from a namespace
/// </summary>
Task<V1Status> DeleteNamespacedConfigMapAsync(string namespaceName, string name, CancellationToken cancellationToken);
/// <summary>
/// Replaces a config map in a namespace
/// </summary>
Task<V1ConfigMap> ReplaceNamespacedConfigMapAsync(string namespaceName, V1ConfigMap configMap, string name, CancellationToken cancellationToken);
/// <summary>
/// Lists the config maps in a namespace
/// </summary>
Task<V1ConfigMapList> ListNamespacedConfigMapAsync(string namespaceName, CancellationToken cancellationToken);
#endregion ConfigMap
/// <summary>
/// Create or replace V1 service account
/// </summary>
/// <returns></returns>
Task CreateServiceAccountIfNotExists(string namespaceName, V1ServiceAccount v1ServiceAccount, CancellationToken cancellationToken);
/// <summary>
/// Create or replace namespaced role
/// </summary>
Task<V1Role> CreateOrReplaceV1RoleInNamespaceAsync(V1Role v1Role, string namespaceName, CancellationToken cancellationToken);
/// <summary>
/// Create or replace namespaced role binding
/// </summary>
Task<V1RoleBinding> CreateOrReplaceV1RoleBindingInNamespaceAsync(V1RoleBinding V1RoleBinding, string namespaceName, CancellationToken cancellationToken);
/// <summary>
/// Execute a kubectl command asynchronously with retries
/// </summary>
/// <returns>kubectl exit code</returns>
Task<int> InvokeShortRunningKubectlCommandWithRetriesAsync(
KubernetesCommandName commandName,
string command,
Action<string> onStdOut = null,
Action<string> onStdErr = null,
bool logOutput = false,
long maxWaitTimeInSeconds = 300,
uint numberOfAttempts = 3,
long delayIntervalInMilliseconds = 10000,
long maxDelayIntervalInSeconds = 30,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Execute a short running kubectl command and log the result as a dependency call
/// </summary>
/// <returns>kubectl exit code</returns>
int InvokeShortRunningKubectlCommand(
KubernetesCommandName commandName,
string command,
Action<string> onStdOut = null,
Action<string> onStdErr = null,
bool logOutput = false,
bool shouldIgnoreErrors = false,
int timeoutMs = 30000,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Execute a long-running kubectl command and log the result as a dependency call
/// </summary>
/// <returns>kubectl exit code</returns>
int InvokeLongRunningKubectlCommand(
KubernetesCommandName commandName,
string command,
Action<string> onStdOut = null,
Action<string> onStdErr = null,
bool logOutput = false,
bool shouldIgnoreErrors = false,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Execute a kubectl command asynchronously and log the result as a dependency call
/// </summary>
/// <returns>kubectl exit code</returns>
Task<int> InvokeShortRunningKubectlCommandAsync(
KubernetesCommandName commandName,
string command,
Action<string> onStdOut = null,
Action<string> onStdErr = null,
bool logOutput = false,
bool shouldIgnoreErrors = false,
int timeoutMs = 30000,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Execute a kubectl command on every item in a collection in parallel and log the overall result as a dependency call
/// </summary>
Task InvokeShortRunningKubectlCommandForEachAsync<T>(
T[] items,
KubernetesCommandName commandName,
Func<T, string> command,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Get all the environment variables seen from within the specified container
/// </summary>
/// <param name="namespaceName"></param>
/// <param name="podName"></param>
/// <param name="containerName"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IDictionary<string, string>> GetContainerEnvironmentAsync(
string namespaceName,
string podName,
string containerName,
CancellationToken cancellationToken);
}
}