├── doc ├── index.md ├── CONTRIBUTING.md ├── toc.yml ├── .gitignore └── docfx.json ├── tests ├── KubernetesClient.Tests │ ├── assets │ │ ├── token1 │ │ ├── token2 │ │ ├── mock-gcloud.cmd │ │ ├── mock-gcloud.sh │ │ ├── kubeconfig.preferences-extensions.yml │ │ ├── kubeconfig.no-user.yml │ │ ├── kubeconfig.user-not-found.yml │ │ ├── elliptic-client.key │ │ ├── kubeconfig.tls-skip-http.yml │ │ ├── kubeconfig.no-current-context.yml │ │ ├── kubeconfig.as-user-extra.yml │ │ ├── kubeconfig.no-cluster.yml │ │ ├── kubeconfig.no-credentials.yml │ │ ├── kubeconfig.wildcard-ipv6.yml │ │ ├── kubeconfig.no-server.yml │ │ ├── kubeconfig.wildcard-ipv4.yml │ │ ├── kubeconfig.wildcard-ipv6_2.yml │ │ ├── kubeconfig.tls-servername.yml │ │ ├── kubeconfig.tls-skip.yml │ │ ├── kubeconfig.tls-no-skip.yml │ │ ├── kubeconfig.user-pass.yml │ │ ├── kubeconfig.cluster-missmatch.yml │ │ ├── gcloud-config-helper.json │ │ ├── elliptic.crt │ │ ├── kubeconfig.cluster-extensions.yml │ │ ├── kubeconfig.user-oidc.yml │ │ ├── kubeconfig.no-context.yml │ │ ├── kubeconfig.no-context-details.yml │ │ ├── ca2.crt │ │ ├── ca.crt │ │ ├── ca-bundle-root.crt │ │ ├── ca-bundle-intermediate.crt │ │ ├── client.crt │ │ ├── ca-data.txt │ │ ├── client-certificate-data.txt │ │ └── client.key │ ├── AssemblyInfo.cs │ ├── OperatingSystems.cs │ ├── ItemsEnumTests.cs │ ├── UtilityTests.cs │ ├── IntOrStringTests.cs │ ├── TokenFileAuthTests.cs │ ├── OperatingSystemDependentFactAttribute.cs │ ├── ExternalExecutionTests.cs │ ├── Mock │ │ ├── MockWebSocketBuilder.cs │ │ └── Server │ │ │ └── Startup.cs │ ├── TaskAssert.cs │ └── KubernetesClient.Tests.csproj ├── E2E.Tests │ ├── Onebyone.cs │ ├── MinikubeFactAttribute.cs │ ├── KubectlTests.cs │ └── E2E.Tests.csproj ├── SkipTestLogger │ └── SkipTestLogger.csproj ├── Kubectl.Tests │ ├── KubectlTests.cs │ ├── Kubectl.Tests.csproj │ └── KubectlTests.Version.cs ├── E2E.Aot.Tests │ └── E2E.Aot.Tests.csproj └── KubernetesClient.Classic.Tests │ └── KubernetesClient.Classic.Tests.csproj ├── logo.png ├── .devcontainer └── devcontainer.json ├── csharp.settings ├── examples ├── yaml │ ├── yaml.csproj │ └── Program.cs ├── resize │ ├── resize.csproj │ └── Program.cs ├── exec │ ├── exec.csproj │ └── Exec.cs ├── logs │ ├── logs.csproj │ └── Logs.cs ├── attach │ ├── attach.csproj │ └── Attach.cs ├── generic │ ├── generic.csproj │ └── Generic.cs ├── labels │ ├── labels.csproj │ └── PodList.cs ├── simple │ ├── simple.csproj │ └── PodList.cs ├── aks-kubelogin │ ├── aks-kubelogin.csproj │ ├── README.md │ └── Program.cs ├── clientset │ ├── clientset.csproj │ └── Program.cs ├── patch │ ├── patch.csproj │ └── Program.cs ├── portforward │ └── portforward.csproj ├── watch │ ├── watch.csproj │ └── Program.cs ├── namespace │ └── namespace.csproj ├── customResource │ ├── config │ │ ├── yaml-cr-instance.yaml │ │ └── crd.yaml │ ├── customResource.csproj │ ├── cResource.cs │ ├── Utils.cs │ ├── CustomResourceDefinition.cs │ └── README.md ├── webApiDependencyInjection │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── webApiDependencyInjection.csproj │ ├── Program.cs │ └── Controllers │ │ ├── ExampleDependencyInjectionOnMethodController.cs │ │ └── ExampleDependencyInjectionOnConstructorController.cs ├── workerServiceDependencyInjection │ ├── appsettings.json │ ├── appsettings.Development.json │ ├── workerServiceDependencyInjection.csproj │ ├── Program.cs │ └── Worker.cs ├── cp │ └── cp.csproj ├── Directory.Build.props ├── metrics │ └── metrics.csproj ├── Directory.Build.targets ├── csrApproval │ └── csrApproval.csproj ├── restart │ └── restart.csproj ├── patch-aot │ ├── patch-aot.csproj │ └── Program.cs ├── aot │ ├── aot.csproj │ └── Program.cs └── openTelemetryConsole │ ├── openTelemetryConsole.csproj │ └── Program.cs ├── code-of-conduct.md ├── global.json ├── OWNERS ├── src ├── LibKubernetesGenerator │ ├── IScriptObjectHelper.cs │ ├── generators │ │ └── LibKubernetesGenerator │ │ │ └── LibKubernetesGenerator.csproj │ ├── VersionGenerator.cs │ ├── templates │ │ ├── IKubernetes.cs.template │ │ ├── AbstractKubernetes.cs.template │ │ ├── ClientSet.cs.template │ │ ├── SourceGenerationContext.cs.template │ │ ├── GroupClient.cs.template │ │ └── Model.cs.template │ ├── EmbedResource.cs │ ├── ScriptObjectFactory.cs │ ├── UtilHelper.cs │ ├── SourceGenerationContextGenerator.cs │ └── GeneratorExecutionContextExt.cs ├── KubernetesClient.Aot │ ├── KubeConfigModels │ │ ├── StaticContext.cs │ │ ├── ExecCredentialResponseContext.cs │ │ ├── User.cs │ │ ├── Context.cs │ │ ├── Cluster.cs │ │ ├── AuthProvider.cs │ │ ├── ContextDetails.cs │ │ ├── ExecCredentialResponse.cs │ │ ├── ExternalExecution.cs │ │ └── ClusterEndpoint.cs │ ├── Global.cs │ └── V1PatchJsonConverter.cs ├── KubernetesClient │ ├── IKubernetes.cs │ ├── Models │ │ ├── GeneratedModelVersion.cs │ │ ├── V1PodTemplateSpec.cs │ │ ├── ISpec.cs │ │ ├── IMetadata.cs │ │ ├── IStatus.cs │ │ ├── ContainerMetrics.cs │ │ ├── IItems.cs │ │ ├── V1Status.cs │ │ ├── V1PatchJsonConverter.cs │ │ ├── KubernetesDateTimeYamlConverter.cs │ │ ├── KubernetesEntityAttribute.cs │ │ ├── PodMetricsList.cs │ │ ├── NodeMetricsList.cs │ │ ├── IntOrString.cs │ │ ├── NodeMetrics.cs │ │ ├── PodMetrics.cs │ │ ├── IntOrStringJsonConverter.cs │ │ ├── IntOrStringYamlConverter.cs │ │ ├── ResourceQuantityJsonConverter.cs │ │ ├── ResourceQuantityYamlConverter.cs │ │ ├── V1Patch.cs │ │ ├── V1Status.ObjectView.cs │ │ └── KubernetesList.cs │ ├── Global.cs │ ├── GeneratedApiVersion.cs │ ├── ClientSets │ │ ├── ClientSet.cs │ │ └── ResourceClient.cs │ ├── LeaderElection │ │ ├── LeaderElectionConfig.cs │ │ └── ResourceLock │ │ │ ├── MetaObjectAnnotationLock.cs │ │ │ ├── MultiLock.cs │ │ │ ├── EndpointsLock.cs │ │ │ └── ConfigMapLock.cs │ ├── Exceptions │ │ ├── KubeConfigException.cs │ │ └── KubernetesClientException.cs │ ├── KubeConfigModels │ │ ├── User.cs │ │ ├── Cluster.cs │ │ ├── NamedExtension.cs │ │ ├── AuthProvider.cs │ │ ├── ExecCredentialResponse.cs │ │ ├── Context.cs │ │ ├── ContextDetails.cs │ │ └── ExternalExecution.cs │ ├── StreamType.cs │ ├── Utilities.cs │ ├── KubernetesClient.csproj │ ├── Authentication │ │ ├── ITokenProvider.cs │ │ ├── ServiceClientCredentials.cs │ │ ├── ExecTokenProvider.cs │ │ └── StringTokenProvider.cs │ ├── ExecAsyncCallback.cs │ ├── FloatEmitter.cs │ ├── SourceGenerationContext.cs │ ├── Autorest │ │ ├── HttpExtensions.cs │ │ ├── HttpRequestMessageWrapper.cs │ │ └── HttpResponseMessageWrapper.cs │ ├── IKubernetes.Exec.cs │ ├── FileSystem.cs │ ├── Extensions.cs │ ├── KubernetesObject.cs │ └── ChannelIndex.cs ├── KubernetesClient.Classic │ ├── IsExternalInit.cs │ ├── Global.cs │ └── Kubernetes.Websocket.Netstandard.cs ├── KubernetesClient.Kubectl │ ├── Beta │ │ ├── AsyncKubectl.cs │ │ ├── Kubectl.cs │ │ ├── Kubectl.Version.cs │ │ ├── Kubectl.Cordon.cs │ │ ├── Kubectl.Delete.cs │ │ ├── AsyncKubectl.Version.cs │ │ ├── AsyncKubectl.Cordon.cs │ │ ├── AsyncKubectl.Delete.cs │ │ ├── Kubectl.Top.cs │ │ └── Kubectl.Patch.cs │ └── KubernetesClient.Kubectl.csproj └── nuget.proj ├── Directory.Build.targets ├── nuget.config ├── .gitignore ├── kubernetes-client.proj ├── version.json ├── stylecop.json ├── SECURITY_CONTACTS ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md ├── workflows │ ├── draft.yaml │ ├── docfx.yaml │ └── nuget.yaml └── dependabot.yml ├── .gitattributes └── CONTRIBUTING.md /doc/index.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /doc/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ../CONTRIBUTING.md -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/token1: -------------------------------------------------------------------------------- 1 | token1 2 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/token2: -------------------------------------------------------------------------------- 1 | token2 2 | -------------------------------------------------------------------------------- /doc/toc.yml: -------------------------------------------------------------------------------- 1 | - name: API Documentation 2 | href: api/k8s.yml 3 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kubernetes-client/csharp/HEAD/logo.png -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "mcr.microsoft.com/dotnet/sdk:8.0" 3 | } -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/mock-gcloud.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | type %~dp0\gcloud-config-helper.json 3 | -------------------------------------------------------------------------------- /csharp.settings: -------------------------------------------------------------------------------- 1 | export KUBERNETES_BRANCH=v1.34.0 2 | export CLIENT_VERSION=0.0.1 3 | export PACKAGE_NAME=k8s 4 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | [assembly: CollectionBehavior(DisableTestParallelization = true)] 4 | -------------------------------------------------------------------------------- /examples/yaml/yaml.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | 5 | -------------------------------------------------------------------------------- /examples/resize/resize.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | 5 | -------------------------------------------------------------------------------- /examples/exec/exec.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/logs/logs.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Community Code of Conduct 2 | 3 | Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /examples/attach/attach.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/generic/generic.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/labels/labels.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/simple/simple.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/aks-kubelogin/aks-kubelogin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | 5 | -------------------------------------------------------------------------------- /examples/clientset/clientset.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/patch/patch.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/portforward/portforward.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/watch/watch.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | ############### 2 | # folder # 3 | ############### 4 | /**/DROP/ 5 | /**/TEMP/ 6 | /**/packages/ 7 | /**/bin/ 8 | /**/obj/ 9 | _site 10 | 11 | api -------------------------------------------------------------------------------- /examples/namespace/namespace.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/E2E.Tests/Onebyone.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace k8s.E2E; 4 | 5 | [CollectionDefinition(nameof(Onebyone), DisableParallelization = true)] 6 | public class Onebyone 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /examples/customResource/config/yaml-cr-instance.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: csharp.com/v1alpha1 2 | kind: CResource 3 | metadata: 4 | name: cr-instance-paris 5 | namespace: default 6 | spec: 7 | cityName: Paris 8 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/mock-gcloud.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPT=$(readlink -f "$0") 3 | SCRIPTPATH=$(dirname "$SCRIPT") 4 | OUTPUT_JSON=$SCRIPTPATH/gcloud-config-helper.json 5 | cat $OUTPUT_JSON 6 | -------------------------------------------------------------------------------- /examples/webApiDependencyInjection/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.preferences-extensions.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Config 3 | preferences: 4 | colors: true 5 | extensions: 6 | - name: foo 7 | extension: 8 | foo: bar 9 | -------------------------------------------------------------------------------- /examples/workerServiceDependencyInjection/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.Hosting.Lifetime": "Information" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.100", 4 | "rollForward": "latestMajor" 5 | }, 6 | "msbuild-sdks": { 7 | "Microsoft.Build.Traversal": "4.1.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | approvers: 4 | - brendandburns 5 | - tg123 6 | reviewers: 7 | - brendandburns 8 | - tg123 9 | emeritus_approvers: 10 | - krabhishek8260 # 4/4/2022 11 | -------------------------------------------------------------------------------- /examples/workerServiceDependencyInjection/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.Hosting.Lifetime": "Information" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/IScriptObjectHelper.cs: -------------------------------------------------------------------------------- 1 | using Scriban.Runtime; 2 | 3 | namespace LibKubernetesGenerator; 4 | 5 | internal interface IScriptObjectHelper 6 | { 7 | void RegisterHelper(ScriptObject scriptObject); 8 | } 9 | -------------------------------------------------------------------------------- /examples/webApiDependencyInjection/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/KubeConfigModels/StaticContext.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels; 4 | 5 | [YamlStaticContext] 6 | public partial class StaticContext : YamlDotNet.Serialization.StaticContext 7 | { 8 | } -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/KubernetesClient/IKubernetes.cs: -------------------------------------------------------------------------------- 1 | namespace k8s; 2 | 3 | public partial interface IKubernetes : IDisposable 4 | { 5 | /// 6 | /// The base URI of the service. 7 | /// 8 | Uri BaseUri { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /examples/cp/cp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/KubernetesClient.Classic/IsExternalInit.cs: -------------------------------------------------------------------------------- 1 | // IntOrString.cs(7,36): error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit' is not defined or imported 2 | namespace System.Runtime.CompilerServices 3 | { 4 | internal static class IsExternalInit { } 5 | } -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/KubeConfigModels/ExecCredentialResponseContext.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.KubeConfigModels 2 | { 3 | [JsonSerializable(typeof(ExecCredentialResponse))] 4 | internal partial class ExecCredentialResponseContext : JsonSerializerContext 5 | { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .vs 3 | obj/ 4 | bin/ 5 | **/TestResults 6 | 7 | # User-specific VS files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # JetBrains Rider 14 | .idea/ 15 | *.sln.iml 16 | 17 | launchSettings.json 18 | *.DotSettings 19 | 20 | *.sln -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/Beta/AsyncKubectl.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.kubectl.beta; 2 | 3 | public partial class AsyncKubectl 4 | { 5 | private readonly IKubernetes client; 6 | 7 | public AsyncKubectl(IKubernetes client) 8 | { 9 | this.client = client; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/Beta/Kubectl.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.kubectl.beta; 2 | 3 | public partial class Kubectl 4 | { 5 | private readonly AsyncKubectl client; 6 | 7 | public Kubectl(IKubernetes client) 8 | { 9 | this.client = new AsyncKubectl(client); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | net9.0 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/customResource/customResource.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /kubernetes-client.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/GeneratedModelVersion.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models; 2 | 3 | public static class GeneratedModelVersion 4 | { 5 | public const string AssemblyVersion = ThisAssembly.AssemblyInformationalVersion; 6 | public const string SwaggerVersion = ThisAssembly.KubernetesSwaggerVersion; 7 | } 8 | -------------------------------------------------------------------------------- /examples/metrics/metrics.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tests/SkipTestLogger/SkipTestLogger.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/generators/LibKubernetesGenerator/LibKubernetesGenerator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | $(DefineConstants);GENERATE_BASIC; 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/V1PodTemplateSpec.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | /// 4 | /// Partial implementation of the IMetadata interface 5 | /// to open this class up to ModelExtensions methods 6 | /// 7 | public partial record V1PodTemplateSpec : IMetadata 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/Beta/Kubectl.Version.cs: -------------------------------------------------------------------------------- 1 | using static k8s.kubectl.beta.AsyncKubectl; 2 | 3 | namespace k8s.kubectl.beta; 4 | 5 | public partial class Kubectl 6 | { 7 | // TODO should auto generate this 8 | public KubernetesSDKVersion Version() 9 | { 10 | return client.Version().GetAwaiter().GetResult(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/nuget.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/webApiDependencyInjection/webApiDependencyInjection.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | enable 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/csrApproval/csrApproval.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/restart/restart.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/Global.cs: -------------------------------------------------------------------------------- 1 | global using k8s.Autorest; 2 | global using k8s.Models; 3 | global using System; 4 | global using System.Collections.Generic; 5 | global using System.IO; 6 | global using System.Linq; 7 | global using System.Text.Json; 8 | global using System.Text.Json.Serialization; 9 | global using System.Threading; 10 | global using System.Threading.Tasks; 11 | -------------------------------------------------------------------------------- /src/KubernetesClient/Global.cs: -------------------------------------------------------------------------------- 1 | global using k8s.Autorest; 2 | global using k8s.Models; 3 | global using System; 4 | global using System.Collections.Generic; 5 | global using System.IO; 6 | global using System.Linq; 7 | global using System.Text.Json; 8 | global using System.Text.Json.Serialization; 9 | global using System.Threading; 10 | global using System.Threading.Tasks; 11 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "18.0", 4 | "publicReleaseRefSpec": [ 5 | "^refs/heads/master$", 6 | "^refs/tags/v\\d+\\.\\d+\\.\\d+" 7 | ], 8 | "cloudBuild": { 9 | "setVersionVariables": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/workerServiceDependencyInjection/workerServiceDependencyInjection.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | enable 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/KubernetesClient.Classic/Global.cs: -------------------------------------------------------------------------------- 1 | global using k8s.Autorest; 2 | global using k8s.Models; 3 | global using System; 4 | global using System.Collections.Generic; 5 | global using System.IO; 6 | global using System.Linq; 7 | global using System.Text.Json; 8 | global using System.Text.Json.Serialization; 9 | global using System.Threading; 10 | global using System.Threading.Tasks; 11 | -------------------------------------------------------------------------------- /stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": 3 | "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 4 | "settings": { 5 | "orderingRules": { 6 | "systemUsingDirectivesFirst": false, 7 | "usingDirectivesPlacement": "outsideNamespace" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.no-user.yml: -------------------------------------------------------------------------------- 1 | --- 2 | current-context: federal-context 3 | apiVersion: v1 4 | clusters: 5 | - cluster: 6 | certificate-authority: assets/ca.crt 7 | server: https://horse.org:4443 8 | name: horse-cluster 9 | contexts: 10 | - context: 11 | cluster: horse-cluster 12 | namespace: chisel-ns 13 | name: federal-context 14 | kind: Config -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/Beta/Kubectl.Cordon.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.kubectl.beta; 2 | 3 | public partial class Kubectl 4 | { 5 | public void Cordon(string nodeName) 6 | { 7 | client.Cordon(nodeName).GetAwaiter().GetResult(); 8 | } 9 | 10 | public void Uncordon(string nodeName) 11 | { 12 | client.Uncordon(nodeName).GetAwaiter().GetResult(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/patch-aot/patch-aot.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | enable 5 | enable 6 | true 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/KubernetesClient/GeneratedApiVersion.cs: -------------------------------------------------------------------------------- 1 | namespace k8s; 2 | 3 | public static class GeneratedApiVersion 4 | { 5 | // Now API version is the same as model version 6 | // Change this if api is generated from a separate swagger spec 7 | 8 | public const string AssemblyVersion = GeneratedModelVersion.AssemblyVersion; 9 | public const string SwaggerVersion = GeneratedModelVersion.SwaggerVersion; 10 | } 11 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.user-not-found.yml: -------------------------------------------------------------------------------- 1 | --- 2 | current-context: federal-context 3 | apiVersion: v1 4 | clusters: 5 | - cluster: 6 | certificate-authority: assets/ca.crt 7 | server: https://horse.org:4443 8 | name: horse-cluster 9 | contexts: 10 | - context: 11 | cluster: horse-cluster 12 | namespace: chisel-ns 13 | user: green-user 14 | name: federal-context 15 | kind: Config -------------------------------------------------------------------------------- /tests/E2E.Tests/MinikubeFactAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace k8s.E2E 5 | { 6 | public sealed class MinikubeFactAttribute : FactAttribute 7 | { 8 | private static readonly bool HasEnv = !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("K8S_E2E_MINIKUBE")); 9 | 10 | public override string Skip => !HasEnv ? "K8S_E2_MINIKUBE not set" : null; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/elliptic-client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MIHcAgEBBEIAgsWy6kCIIGCuedLfU0zqElm7H9VwpzKWK3ITjtG8QPEJfw0vEqVL 3 | Ly4aVsZ8dH7lP6Ykz90lAxLPwMJTL7fht9qgBwYFK4EEACOhgYkDgYYABADJVVPm 4 | PwRHH96uMREAJMrznGswswqMerCY8wqGjAMDHCWE/bvbGROhRzZM5WNuI/C7d5oV 5 | YpagbVVgIi3L4Jr+hgDuAmK4AExQYcZWVcPqLe/kv7i5xxAT2MJwuto7QJeR7ffh 6 | YzbpOXqgQBrJW2Fdgh/mTAKHrtP/nDOsioRWzxl2zQ== 7 | -----END EC PRIVATE KEY----- 8 | -------------------------------------------------------------------------------- /examples/aot/aot.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | enable 5 | enable 6 | true 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/OperatingSystems.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace k8s.Tests 4 | { 5 | [Flags] 6 | public enum OperatingSystems 7 | { 8 | /// Windows operating system. 9 | Windows = 1, 10 | 11 | /// Linux operating system. 12 | Linux = 2, 13 | 14 | /// OSX operating system. 15 | OSX = 4, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/aot/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | 3 | var config = KubernetesClientConfiguration.BuildDefaultConfig(); 4 | IKubernetes client = new Kubernetes(config); 5 | Console.WriteLine("Starting Request!"); 6 | 7 | var list = client.CoreV1.ListNamespacedPod("default"); 8 | foreach (var item in list.Items) 9 | { 10 | Console.WriteLine(item.Metadata.Name); 11 | } 12 | 13 | if (list.Items.Count == 0) 14 | { 15 | Console.WriteLine("Empty!"); 16 | } -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.tls-skip-http.yml: -------------------------------------------------------------------------------- 1 | --- 2 | current-context: federal-context 3 | apiVersion: v1 4 | clusters: 5 | - cluster: 6 | server: http://horse.org 7 | name: horse-cluster 8 | contexts: 9 | - context: 10 | cluster: horse-cluster 11 | namespace: chisel-ns 12 | user: green-user 13 | name: federal-context 14 | kind: Config 15 | users: 16 | - name: green-user 17 | user: 18 | password: secret 19 | username: admin -------------------------------------------------------------------------------- /examples/simple/PodList.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using System; 3 | 4 | var config = KubernetesClientConfiguration.BuildDefaultConfig(); 5 | IKubernetes client = new Kubernetes(config); 6 | Console.WriteLine("Starting Request!"); 7 | 8 | var list = client.CoreV1.ListNamespacedPod("default"); 9 | foreach (var item in list.Items) 10 | { 11 | Console.WriteLine(item.Metadata.Name); 12 | } 13 | 14 | if (list.Items.Count == 0) 15 | { 16 | Console.WriteLine("Empty!"); 17 | } 18 | -------------------------------------------------------------------------------- /examples/openTelemetryConsole/openTelemetryConsole.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.no-current-context.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | clusters: 4 | - cluster: 5 | certificate-authority: assets/ca.crt 6 | server: https://horse.org:4443 7 | name: horse-cluster 8 | contexts: 9 | - context: 10 | cluster: horse-cluster 11 | namespace: chisel-ns 12 | user: green-user 13 | name: federal-context 14 | kind: Config 15 | users: 16 | - name: green-user 17 | user: 18 | password: secret 19 | username: admin -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/ItemsEnumTests.cs: -------------------------------------------------------------------------------- 1 | using k8s.Models; 2 | using Xunit; 3 | 4 | namespace k8s.Tests; 5 | 6 | public class ItemsEnumTests 7 | { 8 | [Fact] 9 | public void EnsureIItemsEnumerable() 10 | { 11 | var pods = new V1PodList 12 | { 13 | Items = new[] { new V1Pod() }, 14 | }; 15 | 16 | // ensure no sytax err 17 | foreach (var pod in pods) 18 | { 19 | Assert.NotNull(pod); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/yaml/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using k8s.Models; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | var typeMap = new Dictionary 7 | { 8 | { "v1/Pod", typeof(V1Pod) }, 9 | { "v1/Service", typeof(V1Service) }, 10 | { "apps/v1/Deployment", typeof(V1Deployment) }, 11 | }; 12 | 13 | var objects = await KubernetesYaml.LoadAllFromFileAsync(args[0], typeMap).ConfigureAwait(false); 14 | 15 | foreach (var obj in objects) 16 | { 17 | Console.WriteLine(obj); 18 | } 19 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/VersionGenerator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using NSwag; 3 | 4 | namespace LibKubernetesGenerator; 5 | 6 | internal class VersionGenerator 7 | { 8 | public void Generate(OpenApiDocument swagger, IncrementalGeneratorPostInitializationContext context) 9 | { 10 | context.AddSource("k8sver.cs", $"// \n" + "internal static partial class ThisAssembly { internal const string KubernetesSwaggerVersion = \"" + swagger.Info.Version + "\";}"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/KubernetesClient/ClientSets/ClientSet.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.ClientSets 2 | { 3 | /// 4 | /// Represents a base class for clients that interact with Kubernetes resources. 5 | /// Provides shared functionality for derived resource-specific clients. 6 | /// 7 | public partial class ClientSet 8 | { 9 | private readonly Kubernetes _kubernetes; 10 | 11 | public ClientSet(Kubernetes kubernetes) 12 | { 13 | _kubernetes = kubernetes; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/templates/IKubernetes.cs.template: -------------------------------------------------------------------------------- 1 | // 2 | // Code generated by https://github.com/kubernetes-client/csharp/tree/master/src/LibKubernetesGenerator 3 | // Changes may cause incorrect behavior and will be lost if the code is 4 | // regenerated. 5 | // 6 | 7 | namespace k8s; 8 | 9 | /// 10 | /// 11 | public partial interface IKubernetes 12 | { 13 | {{for group in groups}} 14 | I{{group}}Operations {{group}} { get; } 15 | {{end}} 16 | } -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.as-user-extra.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | clusters: 3 | - cluster: 4 | certificate-authority: assets/ca.crt 5 | server: https://10.20.0.56:8443 6 | name: minikube 7 | contexts: 8 | - context: 9 | cluster: minikube 10 | user: minikube 11 | name: minikube 12 | current-context: minikube 13 | kind: Config 14 | preferences: {} 15 | users: 16 | - name: minikube 17 | user: 18 | as-user-extra: {} 19 | client-certificate: assets/client.crt 20 | client-key: assets/client.key 21 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.no-cluster.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | contexts: 7 | - context: 8 | cluster: horse-cluster 9 | namespace: chisel-ns 10 | user: green-user 11 | name: federal-context 12 | kind: Config 13 | users: 14 | - name: green-user 15 | user: 16 | password: secret 17 | username: admin -------------------------------------------------------------------------------- /src/KubernetesClient/Models/ISpec.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models; 2 | 3 | /// 4 | /// Represents a Kubernetes object that has a spec 5 | /// 6 | /// type of Kubernetes object 7 | public interface ISpec 8 | { 9 | /// 10 | /// Gets or sets specification of the desired behavior of the entity. More 11 | /// info: 12 | /// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status 13 | /// 14 | T Spec { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/templates/AbstractKubernetes.cs.template: -------------------------------------------------------------------------------- 1 | // 2 | // Code generated by https://github.com/kubernetes-client/csharp/tree/master/src/LibKubernetesGenerator 3 | // Changes may cause incorrect behavior and will be lost if the code is 4 | // regenerated. 5 | // 6 | 7 | namespace k8s; 8 | 9 | /// 10 | /// 11 | public abstract partial class AbstractKubernetes 12 | { 13 | {{for group in groups}} 14 | public I{{group}}Operations {{group}} => this; 15 | {{end}} 16 | } 17 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/templates/ClientSet.cs.template: -------------------------------------------------------------------------------- 1 | // 2 | // Code generated by https://github.com/kubernetes-client/csharp/tree/master/src/LibKubernetesGenerator 3 | // Changes may cause incorrect behavior and will be lost if the code is 4 | // regenerated. 5 | // 6 | 7 | namespace k8s.ClientSets; 8 | 9 | /// 10 | /// 11 | public partial class ClientSet 12 | { 13 | {{for group in groups}} 14 | public {{group}}GroupClient {{group}} => new {{group}}GroupClient(_kubernetes); 15 | {{end}} 16 | } 17 | -------------------------------------------------------------------------------- /src/KubernetesClient/ClientSets/ResourceClient.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.ClientSets 2 | { 3 | /// 4 | /// Represents a set of Kubernetes clients for interacting with the Kubernetes API. 5 | /// This class provides access to various client implementations for managing Kubernetes resources. 6 | /// 7 | public abstract class ResourceClient 8 | { 9 | protected Kubernetes Client { get; } 10 | 11 | public ResourceClient(Kubernetes kubernetes) 12 | { 13 | Client = kubernetes; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/KubernetesClient.Kubectl.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0;net9.0;net10.0 5 | enable 6 | enable 7 | k8s.kubectl 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/KubernetesClient/LeaderElection/LeaderElectionConfig.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.LeaderElection 2 | { 3 | public class LeaderElectionConfig 4 | { 5 | public ILock Lock { get; set; } 6 | 7 | public TimeSpan LeaseDuration { get; set; } = TimeSpan.FromSeconds(15); 8 | 9 | public TimeSpan RenewDeadline { get; set; } = TimeSpan.FromSeconds(10); 10 | 11 | public TimeSpan RetryPeriod { get; set; } = TimeSpan.FromSeconds(2); 12 | 13 | public LeaderElectionConfig(ILock @lock) 14 | { 15 | Lock = @lock; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/templates/SourceGenerationContext.cs.template: -------------------------------------------------------------------------------- 1 | // 2 | // Code generated by https://github.com/kubernetes-client/csharp/tree/master/src/LibKubernetesGenerator 3 | // Changes may cause incorrect behavior and will be lost if the code is regenerated. 4 | // 5 | #if NET8_0_OR_GREATER 6 | namespace k8s 7 | { 8 | {{ for definition in definitions }} 9 | [JsonSerializable(typeof({{ GetClassName definition }}))] 10 | {{ end }} 11 | public partial class SourceGenerationContext : JsonSerializerContext 12 | { 13 | } 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /src/KubernetesClient/Exceptions/KubeConfigException.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Exceptions 2 | { 3 | /// 4 | /// The exception that is thrown when the kube config is invalid 5 | /// 6 | public class KubeConfigException : Exception 7 | { 8 | public KubeConfigException() 9 | { 10 | } 11 | 12 | public KubeConfigException(string message) 13 | : base(message) 14 | { 15 | } 16 | 17 | public KubeConfigException(string message, Exception inner) 18 | : base(message, inner) 19 | { 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/IMetadata.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models; 2 | 3 | /// 4 | /// Kubernetes object that exposes metadata 5 | /// 6 | /// Type of metadata exposed. Usually this will be either 7 | /// for lists or for objects 8 | public interface IMetadata 9 | { 10 | /// 11 | /// Gets or sets standard object's metadata. More info: 12 | /// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata 13 | /// 14 | T Metadata { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/EmbedResource.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Reflection; 3 | 4 | namespace LibKubernetesGenerator; 5 | 6 | internal static class EmbedResource 7 | { 8 | public static string GetResource(string name) 9 | { 10 | var assembly = Assembly.GetExecutingAssembly(); 11 | 12 | var resourceName = assembly.GetName().Name + "." + name; 13 | 14 | using var stream = assembly.GetManifestResourceStream(resourceName); 15 | using var reader = new StreamReader(stream ?? throw new FileNotFoundException(resourceName)); 16 | return reader.ReadToEnd(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/customResource/config/crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: customresources.csharp.com 5 | spec: 6 | group: csharp.com 7 | versions: 8 | - name: v1alpha1 9 | storage: true 10 | served: true 11 | schema: 12 | openAPIV3Schema: 13 | type: object 14 | properties: 15 | spec: 16 | type: object 17 | properties: 18 | cityName: 19 | type: string 20 | names: 21 | kind: CResource 22 | plural: customresources 23 | scope: Namespaced 24 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.no-credentials.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | certificate-authority: assets/ca.crt 9 | server: https://horse.org:4443 10 | name: horse-cluster 11 | contexts: 12 | - context: 13 | cluster: horse-cluster 14 | namespace: chisel-ns 15 | user: green-user 16 | name: federal-context 17 | kind: Config 18 | users: 19 | - name: green-user 20 | user: -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv6.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | server: https://[::]:443 9 | name: horse-cluster 10 | contexts: 11 | - context: 12 | cluster: horse-cluster 13 | namespace: chisel-ns 14 | user: green-user 15 | name: federal-context 16 | kind: Config 17 | users: 18 | - name: green-user 19 | user: 20 | password: secret 21 | username: admin 22 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.no-server.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | certificate-authority: path/to/my/cafile 9 | name: horse-cluster 10 | contexts: 11 | - context: 12 | cluster: horse-cluster 13 | namespace: chisel-ns 14 | user: green-user 15 | name: federal-context 16 | kind: Config 17 | users: 18 | - name: green-user 19 | user: 20 | password: secret 21 | username: admin -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv4.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | server: https://0.0.0.0:443 9 | name: horse-cluster 10 | contexts: 11 | - context: 12 | cluster: horse-cluster 13 | namespace: chisel-ns 14 | user: green-user 15 | name: federal-context 16 | kind: Config 17 | users: 18 | - name: green-user 19 | user: 20 | password: secret 21 | username: admin 22 | -------------------------------------------------------------------------------- /examples/workerServiceDependencyInjection/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using workerServiceDependencyInjection; 3 | 4 | IHost host = Host.CreateDefaultBuilder(args) 5 | .ConfigureServices(services => 6 | { 7 | // Load kubernetes configuration 8 | var kubernetesClientConfig = KubernetesClientConfiguration.BuildDefaultConfig(); 9 | 10 | // Register Kubernetes client interface as sigleton 11 | services.AddSingleton(_ => new Kubernetes(kubernetesClientConfig)); 12 | 13 | services.AddHostedService(); 14 | }) 15 | .Build(); 16 | 17 | await host.RunAsync().ConfigureAwait(false); 18 | -------------------------------------------------------------------------------- /src/KubernetesClient/Exceptions/KubernetesClientException.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Exceptions 2 | { 3 | /// 4 | /// The exception that is thrown when there is a client exception 5 | /// 6 | public class KubernetesClientException : Exception 7 | { 8 | public KubernetesClientException() 9 | { 10 | } 11 | 12 | public KubernetesClientException(string message) 13 | : base(message) 14 | { 15 | } 16 | 17 | public KubernetesClientException(string message, Exception inner) 18 | : base(message, inner) 19 | { 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv6_2.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | server: https://[0:0:0:0:0:0:0:0]:443 9 | name: horse-cluster 10 | contexts: 11 | - context: 12 | cluster: horse-cluster 13 | namespace: chisel-ns 14 | user: green-user 15 | name: federal-context 16 | kind: Config 17 | users: 18 | - name: green-user 19 | user: 20 | password: secret 21 | username: admin 22 | -------------------------------------------------------------------------------- /examples/generic/Generic.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using k8s.Models; 3 | using System; 4 | 5 | var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); 6 | IKubernetes client = new Kubernetes(config); 7 | var generic = new GenericClient(client, "", "v1", "nodes"); 8 | var node = await generic.ReadAsync("kube0").ConfigureAwait(false); 9 | Console.WriteLine(node.Metadata.Name); 10 | 11 | var genericPods = new GenericClient(client, "", "v1", "pods"); 12 | var pods = await genericPods.ListNamespacedAsync("default").ConfigureAwait(false); 13 | foreach (var pod in pods.Items) 14 | { 15 | Console.WriteLine(pod.Metadata.Name); 16 | } 17 | -------------------------------------------------------------------------------- /SECURITY_CONTACTS: -------------------------------------------------------------------------------- 1 | # Defined below are the security contacts for this repo. 2 | # 3 | # They are the contact point for the Product Security Team to reach out 4 | # to for triaging and handling of incoming issues. 5 | # 6 | # The below names agree to abide by the 7 | # [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy) 8 | # and will be removed and replaced if they violate that agreement. 9 | # 10 | # DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE 11 | # INSTRUCTIONS AT https://kubernetes.io/security/ 12 | 13 | brendandburns 14 | tg123 15 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.tls-servername.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | server: https://horse.org:443 9 | tls-server-name: pony 10 | name: horse-cluster 11 | contexts: 12 | - context: 13 | cluster: horse-cluster 14 | namespace: chisel-ns 15 | user: green-user 16 | name: federal-context 17 | kind: Config 18 | users: 19 | - name: green-user 20 | user: 21 | password: secret 22 | username: admin 23 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.tls-skip.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | insecure-skip-tls-verify: true 9 | server: https://horse.org:443 10 | name: horse-cluster 11 | contexts: 12 | - context: 13 | cluster: horse-cluster 14 | namespace: chisel-ns 15 | user: green-user 16 | name: federal-context 17 | kind: Config 18 | users: 19 | - name: green-user 20 | user: 21 | password: secret 22 | username: admin -------------------------------------------------------------------------------- /src/KubernetesClient/Models/IStatus.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | /// 4 | /// Kubernetes object that exposes status 5 | /// 6 | /// The type of status object 7 | public interface IStatus 8 | { 9 | /// 10 | /// Gets or sets most recently observed status of the object. This data 11 | /// may not be up to date. Populated by the system. Read-only. More 12 | /// info: 13 | /// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status 14 | /// 15 | T Status { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.tls-no-skip.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | insecure-skip-tls-verify: false 9 | server: https://horse.org:443 10 | name: horse-cluster 11 | contexts: 12 | - context: 13 | cluster: horse-cluster 14 | namespace: chisel-ns 15 | user: green-user 16 | name: federal-context 17 | kind: Config 18 | users: 19 | - name: green-user 20 | user: 21 | password: secret 22 | username: admin 23 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.user-pass.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | certificate-authority: assets/ca.crt 9 | server: https://horse.org:4443 10 | name: horse-cluster 11 | contexts: 12 | - context: 13 | cluster: horse-cluster 14 | namespace: chisel-ns 15 | user: green-user 16 | name: federal-context 17 | kind: Config 18 | users: 19 | - name: green-user 20 | user: 21 | password: secret 22 | username: admin 23 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.cluster-missmatch.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | certificate-authority: path/to/my/cafile 9 | server: https://horse.org:4443 10 | name: bad-name-cluster 11 | contexts: 12 | - context: 13 | cluster: horse-cluster 14 | namespace: chisel-ns 15 | user: green-user 16 | name: federal-context 17 | kind: Config 18 | users: 19 | - name: green-user 20 | user: 21 | password: secret 22 | username: admin -------------------------------------------------------------------------------- /src/KubernetesClient/KubeConfigModels/User.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Relates nicknames to auth information. 7 | /// 8 | public class User 9 | { 10 | /// 11 | /// Gets or sets the auth information. 12 | /// 13 | [YamlMember(Alias = "user")] 14 | public UserCredentials UserCredentials { get; set; } 15 | 16 | /// 17 | /// Gets or sets the nickname for this auth information. 18 | /// 19 | [YamlMember(Alias = "name")] 20 | public string Name { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/KubernetesClient/KubeConfigModels/Cluster.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Relates nicknames to cluster information. 7 | /// 8 | public class Cluster 9 | { 10 | /// 11 | /// Gets or sets the cluster information. 12 | /// 13 | [YamlMember(Alias = "cluster")] 14 | public ClusterEndpoint ClusterEndpoint { get; set; } 15 | 16 | /// 17 | /// Gets or sets the nickname for this Cluster. 18 | /// 19 | [YamlMember(Alias = "name")] 20 | public string Name { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/KubernetesClient/StreamType.cs: -------------------------------------------------------------------------------- 1 | namespace k8s 2 | { 3 | /// 4 | /// When creating a object, specify to properly handle 5 | /// the underlying communication. 6 | /// 7 | public enum StreamType 8 | { 9 | /// 10 | /// This object is used to stream a remote command or attach to a remote 11 | /// container. 12 | /// 13 | RemoteCommand, 14 | 15 | /// 16 | /// This object is used in port forwarding. 17 | /// 18 | PortForward, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/ContainerMetrics.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | /// 4 | /// Describes the resource usage metrics of a container pull from metrics server API. 5 | /// 6 | public class ContainerMetrics 7 | { 8 | /// 9 | /// Defines container name corresponding to the one from pod.spec.containers. 10 | /// 11 | [JsonPropertyName("name")] 12 | public string Name { get; set; } 13 | 14 | /// 15 | /// The resource usage. 16 | /// 17 | [JsonPropertyName("usage")] 18 | public IDictionary Usage { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/KubeConfigModels/User.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Relates nicknames to auth information. 7 | /// 8 | [YamlSerializable] 9 | public class User 10 | { 11 | /// 12 | /// Gets or sets the auth information. 13 | /// 14 | [YamlMember(Alias = "user")] 15 | public UserCredentials UserCredentials { get; set; } 16 | 17 | /// 18 | /// Gets or sets the nickname for this auth information. 19 | /// 20 | [YamlMember(Alias = "name")] 21 | public string Name { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/logs/Logs.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using System; 3 | 4 | var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); 5 | IKubernetes client = new Kubernetes(config); 6 | Console.WriteLine("Starting Request!"); 7 | 8 | var list = client.CoreV1.ListNamespacedPod("default"); 9 | if (list.Items.Count == 0) 10 | { 11 | Console.WriteLine("No pods!"); 12 | return; 13 | } 14 | 15 | var pod = list.Items[0]; 16 | 17 | var response = await client.CoreV1.ReadNamespacedPodLogWithHttpMessagesAsync( 18 | pod.Metadata.Name, 19 | pod.Metadata.NamespaceProperty, container: pod.Spec.Containers[0].Name, follow: true).ConfigureAwait(false); 20 | var stream = response.Body; 21 | stream.CopyTo(Console.OpenStandardOutput()); 22 | -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/KubeConfigModels/Context.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Relates nicknames to context information. 7 | /// 8 | [YamlSerializable] 9 | public class Context 10 | { 11 | /// 12 | /// Gets or sets the context information. 13 | /// 14 | [YamlMember(Alias = "context")] 15 | public ContextDetails ContextDetails { get; set; } 16 | 17 | /// 18 | /// Gets or sets the nickname for this context. 19 | /// 20 | [YamlMember(Alias = "name")] 21 | public string Name { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/KubeConfigModels/Cluster.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Relates nicknames to cluster information. 7 | /// 8 | [YamlSerializable] 9 | public class Cluster 10 | { 11 | /// 12 | /// Gets or sets the cluster information. 13 | /// 14 | [YamlMember(Alias = "cluster")] 15 | public ClusterEndpoint ClusterEndpoint { get; set; } 16 | 17 | /// 18 | /// Gets or sets the nickname for this Cluster. 19 | /// 20 | [YamlMember(Alias = "name")] 21 | public string Name { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/KubernetesClient/KubeConfigModels/NamedExtension.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// relates nicknames to extension information 7 | /// 8 | public class NamedExtension 9 | { 10 | /// 11 | /// Gets or sets the nickname for this extension. 12 | /// 13 | [YamlMember(Alias = "name")] 14 | public string Name { get; set; } 15 | 16 | /// 17 | /// Get or sets the extension information. 18 | /// 19 | [YamlMember(Alias = "extension")] 20 | public dynamic Extension { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/Beta/Kubectl.Delete.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.kubectl.beta; 2 | 3 | public partial class Kubectl 4 | { 5 | /// 6 | /// Delete a Kubernetes resource by name. 7 | /// 8 | /// The type of Kubernetes resource to delete. 9 | /// The name of the resource. 10 | /// The namespace of the resource (for namespaced resources). Optional. 11 | /// The deleted resource. 12 | public T Delete(string name, string? @namespace = null) 13 | where T : IKubernetesObject 14 | { 15 | return client.DeleteAsync(name, @namespace).GetAwaiter().GetResult(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/templates/GroupClient.cs.template: -------------------------------------------------------------------------------- 1 | // 2 | // Code generated by https://github.com/kubernetes-client/csharp/tree/master/src/LibKubernetesGenerator 3 | // Changes may cause incorrect behavior and will be lost if the code is 4 | // regenerated. 5 | // 6 | 7 | namespace k8s.ClientSets; 8 | 9 | 10 | /// 11 | /// 12 | public partial class {{name}}GroupClient 13 | { 14 | private readonly Kubernetes _kubernetes; 15 | 16 | {{for client in clients}} 17 | public {{client}}Client {{client}} => new {{client}}Client(_kubernetes); 18 | {{end}} 19 | 20 | public {{name}}GroupClient(Kubernetes kubernetes) 21 | { 22 | _kubernetes = kubernetes; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/gcloud-config-helper.json: -------------------------------------------------------------------------------- 1 | { 2 | "configuration": { 3 | "active_configuration": "default", 4 | "properties": { 5 | "compute": { 6 | "region": "us-east1", 7 | "zone": "us-east1-b" 8 | }, 9 | "core": { 10 | "account": "some@account.io", 11 | "disable_usage_reporting": "True", 12 | "project": "fe-astakhov" 13 | } 14 | } 15 | }, 16 | "credential": { 17 | "access_token": "ACCESS-TOKEN", 18 | "token_expiry": "2020-03-20T07:09:20Z" 19 | }, 20 | "sentinels": { 21 | "config_sentinel": "C:\\Users\\Andrew\\AppData\\Roaming\\gcloud\\config_sentinel" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/ScriptObjectFactory.cs: -------------------------------------------------------------------------------- 1 | using Scriban.Runtime; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace LibKubernetesGenerator; 6 | 7 | internal class ScriptObjectFactory 8 | { 9 | private readonly List scriptObjectHelpers; 10 | 11 | public ScriptObjectFactory(IEnumerable scriptObjectHelpers) 12 | { 13 | this.scriptObjectHelpers = scriptObjectHelpers.ToList(); 14 | } 15 | 16 | public ScriptObject CreateScriptObject() 17 | { 18 | var scriptObject = new ScriptObject(); 19 | foreach (var helper in scriptObjectHelpers) 20 | { 21 | helper.RegisterHelper(scriptObject); 22 | } 23 | 24 | return scriptObject; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/KubernetesClient/KubeConfigModels/AuthProvider.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Contains information that describes identity information. This is use to tell the kubernetes cluster who you are. 7 | /// 8 | public class AuthProvider 9 | { 10 | /// 11 | /// Gets or sets the nickname for this auth provider. 12 | /// 13 | [YamlMember(Alias = "name")] 14 | public string Name { get; set; } 15 | 16 | /// 17 | /// Gets or sets the configuration for this auth provider 18 | /// 19 | [YamlMember(Alias = "config")] 20 | public Dictionary Config { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/KubernetesClient/Utilities.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace k8s 4 | { 5 | internal static class Utilities 6 | { 7 | internal static void AddQueryParameter(StringBuilder sb, string key, string value) 8 | { 9 | if (sb == null) 10 | { 11 | throw new ArgumentNullException(nameof(sb)); 12 | } 13 | 14 | if (string.IsNullOrEmpty(key)) 15 | { 16 | throw new ArgumentNullException(nameof(key)); 17 | } 18 | 19 | sb.Append(sb.Length != 0 ? '&' : '?').Append(Uri.EscapeDataString(key)).Append('='); 20 | if (!string.IsNullOrEmpty(value)) 21 | { 22 | sb.Append(Uri.EscapeDataString(value)); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/IItems.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models; 2 | 3 | /// 4 | /// Kubernetes object that exposes list of objects 5 | /// 6 | /// type of the objects 7 | public interface IItems 8 | { 9 | /// 10 | /// Gets or sets list of objects. More info: 11 | /// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md 12 | /// 13 | IList Items { get; set; } 14 | } 15 | 16 | public static class ItemsExt 17 | { 18 | public static IEnumerator GetEnumerator(this IItems items) 19 | { 20 | if (items is null) 21 | { 22 | throw new ArgumentNullException(nameof(items)); 23 | } 24 | 25 | return items.Items.GetEnumerator(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/V1Status.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace k8s.Models 4 | { 5 | public partial record V1Status 6 | { 7 | /// Converts a object into a short description of the status. 8 | /// string description of the status 9 | public override string ToString() 10 | { 11 | var reason = Reason; 12 | if (string.IsNullOrEmpty(reason) && Code.GetValueOrDefault() != 0) 13 | { 14 | reason = ((HttpStatusCode)Code.Value).ToString(); 15 | } 16 | 17 | return string.IsNullOrEmpty(Message) ? string.IsNullOrEmpty(reason) ? Status : reason : 18 | string.IsNullOrEmpty(reason) ? Message : $"{reason} - {Message}"; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/KubeConfigModels/AuthProvider.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Contains information that describes identity information. This is use to tell the kubernetes cluster who you are. 7 | /// 8 | [YamlSerializable] 9 | public class AuthProvider 10 | { 11 | /// 12 | /// Gets or sets the nickname for this auth provider. 13 | /// 14 | [YamlMember(Alias = "name")] 15 | public string Name { get; set; } 16 | 17 | /// 18 | /// Gets or sets the configuration for this auth provider 19 | /// 20 | [YamlMember(Alias = "config")] 21 | public Dictionary Config { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/KubernetesClient/KubernetesClient.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0;net9.0;net10.0 5 | k8s 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/elliptic.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICBTCCAWYCFDt3JLija7g4s9TNSFI8p9topHs4MAoGCCqGSM49BAMCMEExCzAJ 3 | BgNVBAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UE 4 | CgwKS3ViZXJuZXRlczAeFw0yMTEwMjAwMDA2MDdaFw0yMTExMTkwMDA2MDdaMEEx 5 | CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTETMBEG 6 | A1UECgwKS3ViZXJuZXRlczCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAMlVU+Y/ 7 | BEcf3q4xEQAkyvOcazCzCox6sJjzCoaMAwMcJYT9u9sZE6FHNkzlY24j8Lt3mhVi 8 | lqBtVWAiLcvgmv6GAO4CYrgATFBhxlZVw+ot7+S/uLnHEBPYwnC62jtAl5Ht9+Fj 9 | Nuk5eqBAGslbYV2CH+ZMAoeu0/+cM6yKhFbPGXbNMAoGCCqGSM49BAMCA4GMADCB 10 | iAJCAL8VpSq+rs+h/BmNu/z0KCWsfQv7zOZOTOqYJ/5NzaBlEhejj8ktfvWTJ3SR 11 | jHIMWdK+SAJva1v1tzaTi5z7KiYuAkIApijJv9yr/Ex4okg6zB/LgsTio67fm4DG 12 | 9Yrw9KVtUbskcYjcpLVbT78cQjeDyDg1dYtHpdl7Z7p+jga/nPb/HKU= 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.cluster-extensions.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | clusters: 3 | - cluster: 4 | extensions: 5 | - extension: 6 | last-update: Wed, 27 Jan 2021 11:44:41 UTC 7 | provider: minikube.sigs.k8s.io 8 | version: v1.17.0 9 | name: cluster_info 10 | server: https://192.168.49.2:8443 11 | name: minikube 12 | contexts: 13 | - context: 14 | cluster: minikube 15 | extensions: 16 | - extension: 17 | last-update: Wed, 27 Jan 2021 11:44:41 UTC 18 | provider: minikube.sigs.k8s.io 19 | version: v1.17.0 20 | name: context_info 21 | namespace: default 22 | user: minikube 23 | name: minikube 24 | current-context: minikube 25 | kind: Config 26 | preferences: {} 27 | users: 28 | - name: minikube 29 | user: 30 | password: secret 31 | username: admin 32 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.user-oidc.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | certificate-authority: assets/ca.crt 9 | server: https://horse.org:4443 10 | name: horse-cluster 11 | contexts: 12 | - context: 13 | cluster: horse-cluster 14 | namespace: chisel-ns 15 | user: green-user 16 | name: federal-context 17 | kind: Config 18 | users: 19 | - name: green-user 20 | user: 21 | auth-provider: 22 | config: 23 | client-id: CLIENT_ID 24 | client-secret: CLIENT_SECRET 25 | id-token: ID_TOKEN 26 | idp-issuer-url: IDP_ISSUER_URL 27 | refresh-token: REFRESH_TOKEN 28 | name: oidc 29 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.no-context.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | server: http://cow.org:8080 9 | name: cow-cluster 10 | - cluster: 11 | certificate-authority: assets/ca.crt 12 | server: https://horse.org:4443 13 | name: horse-cluster 14 | - cluster: 15 | insecure-skip-tls-verify: true 16 | server: https://pig.org:443 17 | name: pig-cluster 18 | kind: Config 19 | users: 20 | - name: blue-user 21 | user: 22 | token: blue-token 23 | - name: green-user 24 | user: 25 | client-certificate: assets/client.crt 26 | client-key: assets/client.key 27 | - name: black-user 28 | user: 29 | token: black-token -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/Beta/AsyncKubectl.Version.cs: -------------------------------------------------------------------------------- 1 | using k8s.Models; 2 | 3 | namespace k8s.kubectl.beta; 4 | 5 | public partial class AsyncKubectl 6 | { 7 | private const string AsssemblyVersion = ThisAssembly.AssemblyInformationalVersion; 8 | 9 | public record KubernetesSDKVersion 10 | { 11 | public string ClientVersion { get; init; } = AsssemblyVersion; 12 | 13 | public string ClientSwaggerVersion { get; init; } = GeneratedApiVersion.SwaggerVersion; 14 | 15 | public VersionInfo ServerVersion { get; init; } = default!; 16 | } 17 | 18 | public async Task Version(CancellationToken cancellationToken = default) 19 | { 20 | var serverVersion = await client.Version.GetCodeAsync(cancellationToken).ConfigureAwait(false); 21 | return new KubernetesSDKVersion { ServerVersion = serverVersion }; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/KubernetesClient/Authentication/ITokenProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. See License.txt in the project root for license information. 3 | 4 | using System.Net.Http.Headers; 5 | 6 | #pragma warning disable SA1606 7 | #pragma warning disable SA1614 8 | namespace k8s.Authentication 9 | { 10 | /// 11 | /// Interface to a source of access tokens. 12 | /// 13 | public interface ITokenProvider 14 | { 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// AuthenticationHeaderValue 20 | Task GetAuthenticationHeaderAsync(CancellationToken cancellationToken); 21 | } 22 | } 23 | #pragma warning restore SA1614 24 | #pragma warning restore SA1606 25 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/V1PatchJsonConverter.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | public sealed class V1PatchJsonConverter : JsonConverter 4 | { 5 | public override V1Patch Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 6 | { 7 | throw new NotImplementedException(); 8 | } 9 | 10 | public override void Write(Utf8JsonWriter writer, V1Patch value, JsonSerializerOptions options) 11 | { 12 | if (writer == null) 13 | { 14 | throw new ArgumentNullException(nameof(writer)); 15 | } 16 | 17 | var content = value?.Content; 18 | if (content is string s) 19 | { 20 | writer.WriteRawValue(s); 21 | return; 22 | } 23 | 24 | JsonSerializer.Serialize(writer, content, options); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/UtilHelper.cs: -------------------------------------------------------------------------------- 1 | using NSwag; 2 | using Scriban.Runtime; 3 | 4 | namespace LibKubernetesGenerator 5 | { 6 | internal class UtilHelper : IScriptObjectHelper 7 | { 8 | public void RegisterHelper(ScriptObject scriptObject) 9 | { 10 | scriptObject.Import(nameof(IfKindIs), IfKindIs); 11 | } 12 | 13 | public static bool IfKindIs(OpenApiParameter parameter, string kind) 14 | { 15 | if (parameter != null) 16 | { 17 | if (kind == "query" && parameter.Kind == OpenApiParameterKind.Query) 18 | { 19 | return true; 20 | } 21 | else if (kind == "path" && parameter.Kind == OpenApiParameterKind.Path) 22 | { 23 | return true; 24 | } 25 | } 26 | 27 | return false; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/kubeconfig.no-context-details.yml: -------------------------------------------------------------------------------- 1 | # Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ 2 | # WARNING: File includes minor fixes 3 | --- 4 | current-context: federal-context 5 | apiVersion: v1 6 | clusters: 7 | - cluster: 8 | server: http://cow.org:8080 9 | name: cow-cluster 10 | - cluster: 11 | certificate-authority: assets/ca.crt 12 | server: https://horse.org:4443 13 | name: horse-cluster 14 | - cluster: 15 | insecure-skip-tls-verify: true 16 | server: https://pig.org:443 17 | name: pig-cluster 18 | contexts: 19 | - name: federal-context 20 | kind: Config 21 | users: 22 | - name: blue-user 23 | user: 24 | token: blue-token 25 | - name: green-user 26 | user: 27 | client-certificate: assets/client.crt 28 | client-key: assets/client.key 29 | - name: black-user 30 | user: 31 | token: black-token -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/V1PatchJsonConverter.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | public sealed class V1PatchJsonConverter : JsonConverter 4 | { 5 | public override V1Patch Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 6 | { 7 | throw new NotImplementedException(); 8 | } 9 | 10 | public override void Write(Utf8JsonWriter writer, V1Patch value, JsonSerializerOptions options) 11 | { 12 | if (writer == null) 13 | { 14 | throw new ArgumentNullException(nameof(writer)); 15 | } 16 | 17 | var content = value?.Content; 18 | if (content is string s) 19 | { 20 | writer.WriteRawValue(s); 21 | return; 22 | } 23 | 24 | throw new NotSupportedException("only string json patch is supported"); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Kubernetes C# SDK Client Version** 14 | e.g. `9.0.1` 15 | 16 | **Server Kubernetes Version** 17 | e.g. `1.22.3` 18 | 19 | **Dotnet Runtime Version** 20 | e.g. net6 21 | 22 | **To Reproduce** 23 | Steps to reproduce the behavior: 24 | 25 | **Expected behavior** 26 | A clear and concise description of what you expected to happen. 27 | 28 | **KubeConfig** 29 | If applicable, add a KubeConfig file with secrets redacted. 30 | 31 | **Where do you run your app with Kubernetes SDK (please complete the following information):** 32 | - OS: [e.g. Linux] 33 | - Environment [e.g. container] 34 | - Cloud [e.g. Azure] 35 | 36 | **Additional context** 37 | Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/KubernetesDateTimeYamlConverter.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Core; 2 | using YamlDotNet.Serialization; 3 | 4 | namespace k8s.Models; 5 | 6 | public sealed class KubernetesDateTimeYamlConverter : IYamlTypeConverter 7 | { 8 | private static readonly KubernetesDateTimeOffsetYamlConverter OffsetConverter = new(); 9 | 10 | public bool Accepts(Type type) => type == typeof(DateTime); 11 | 12 | public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) 13 | { 14 | var dto = (DateTimeOffset)OffsetConverter.ReadYaml(parser, typeof(DateTimeOffset), rootDeserializer); 15 | return dto.DateTime; 16 | } 17 | 18 | public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) 19 | { 20 | var date = new DateTimeOffset((DateTime)value); 21 | OffsetConverter.WriteYaml(emitter, date, typeof(DateTimeOffset), serializer); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/SourceGenerationContextGenerator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using NSwag; 3 | 4 | namespace LibKubernetesGenerator 5 | { 6 | internal class SourceGenerationContextGenerator 7 | { 8 | private readonly ScriptObjectFactory scriptObjectFactory; 9 | 10 | public SourceGenerationContextGenerator(ScriptObjectFactory scriptObjectFactory) 11 | { 12 | this.scriptObjectFactory = scriptObjectFactory; 13 | } 14 | 15 | public void Generate(OpenApiDocument swagger, IncrementalGeneratorPostInitializationContext context) 16 | { 17 | var definitions = swagger.Definitions.Values; 18 | var sc = scriptObjectFactory.CreateScriptObject(); 19 | sc.SetValue("definitions", definitions, true); 20 | 21 | context.RenderToContext("SourceGenerationContext.cs.template", sc, "SourceGenerationContext.g.cs"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/E2E.Tests/KubectlTests.cs: -------------------------------------------------------------------------------- 1 | using k8s.kubectl.beta; 2 | using System.Linq; 3 | using Xunit; 4 | 5 | namespace k8s.E2E; 6 | 7 | [Collection(nameof(Onebyone))] 8 | public class KubectlTests 9 | { 10 | [MinikubeFact] 11 | public void CordonTest() 12 | { 13 | var client = MinikubeTests.CreateClient(); 14 | 15 | var node = client.CoreV1.ListNode().Items.First(); 16 | var nodeName = node.Metadata.Name; 17 | 18 | var kubectl = new Kubectl(client); 19 | 20 | // cordon 21 | kubectl.Cordon(nodeName); 22 | 23 | // check node status 24 | var cordonNode = client.CoreV1.ReadNode(nodeName); 25 | Assert.True(cordonNode.Spec.Unschedulable); 26 | 27 | // uncordon 28 | kubectl.Uncordon(nodeName); 29 | cordonNode = client.CoreV1.ReadNode(nodeName); 30 | Assert.True(cordonNode.Spec.Unschedulable == null || cordonNode.Spec.Unschedulable == false); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/webApiDependencyInjection/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | 3 | var builder = WebApplication.CreateBuilder(args); 4 | 5 | // Load kubernetes configuration 6 | var kubernetesClientConfig = KubernetesClientConfiguration.BuildDefaultConfig(); 7 | 8 | // Register Kubernetes client interface as sigleton 9 | builder.Services.AddSingleton(_ => new Kubernetes(kubernetesClientConfig)); 10 | 11 | // Add services to the container. 12 | builder.Services.AddEndpointsApiExplorer(); 13 | builder.Services.AddSwaggerGen(); 14 | 15 | builder.Services.AddControllers(); 16 | 17 | var app = builder.Build(); 18 | 19 | // Configure the HTTP request pipeline. 20 | if (app.Environment.IsDevelopment()) 21 | { 22 | app.UseSwagger(); 23 | app.UseSwaggerUI(); 24 | } 25 | 26 | app.UseAuthorization(); 27 | 28 | app.MapControllers(); 29 | 30 | // Start the service 31 | app.Run(); 32 | 33 | 34 | // Swagger ui can be accesse at: http://localhost:/swagger 35 | -------------------------------------------------------------------------------- /src/KubernetesClient.Classic/Kubernetes.Websocket.Netstandard.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Security; 2 | using System.Security.Cryptography.X509Certificates; 3 | 4 | namespace k8s; 5 | 6 | public partial class Kubernetes 7 | { 8 | partial void BeforeRequest() 9 | { 10 | System.Net.ServicePointManager.ServerCertificateValidationCallback += ServerCertificateValidationCallback; 11 | } 12 | 13 | partial void AfterRequest() 14 | { 15 | System.Net.ServicePointManager.ServerCertificateValidationCallback -= ServerCertificateValidationCallback; 16 | } 17 | 18 | private bool ServerCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, 19 | SslPolicyErrors sslPolicyErrors) 20 | { 21 | if (SkipTlsVerify) 22 | { 23 | return true; 24 | } 25 | 26 | return CertificateValidationCallBack(sender, CaCerts, certificate, chain, sslPolicyErrors); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/KubernetesClient/ExecAsyncCallback.cs: -------------------------------------------------------------------------------- 1 | namespace k8s 2 | { 3 | /// 4 | /// A prototype for a callback which asynchronously processes the standard input, standard output and standard error of a command executing in 5 | /// a container. 6 | /// 7 | /// 8 | /// The standard input stream of the process. 9 | /// 10 | /// 11 | /// The standard output stream of the process. 12 | /// 13 | /// 14 | /// The standard error stream of the remote process. 15 | /// 16 | /// 17 | /// A which represents the asynchronous processing of the process input, output and error streams. This task 18 | /// should complete once you're done interacting with the remote process. 19 | /// 20 | public delegate Task ExecAsyncCallback(Stream stdIn, Stream stdOut, Stream stdErr); 21 | } 22 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/KubernetesEntityAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | /// 4 | /// Describes object type in Kubernetes 5 | /// 6 | [AttributeUsage(AttributeTargets.Class)] 7 | public sealed class KubernetesEntityAttribute : Attribute 8 | { 9 | /// 10 | /// The Kubernetes named schema this object is based on. 11 | /// 12 | public string Kind { get; set; } 13 | 14 | /// 15 | /// The Group this Kubernetes type belongs to. 16 | /// 17 | public string Group { get; set; } 18 | 19 | /// 20 | /// The API Version this Kubernetes type belongs to. 21 | /// 22 | public string ApiVersion { get; set; } 23 | 24 | /// 25 | /// The plural name of the entity. 26 | /// 27 | public string PluralName { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/customResource/cResource.cs: -------------------------------------------------------------------------------- 1 | using k8s.Models; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace customResource 5 | { 6 | public class CResource : CustomResource 7 | { 8 | public override string ToString() 9 | { 10 | var labels = "{"; 11 | foreach (var kvp in Metadata.Labels) 12 | { 13 | labels += kvp.Key + " : " + kvp.Value + ", "; 14 | } 15 | 16 | labels = labels.TrimEnd(',', ' ') + "}"; 17 | 18 | return $"{Metadata.Name} (Labels: {labels}), Spec: {Spec.CityName}"; 19 | } 20 | } 21 | 22 | public record CResourceSpec 23 | { 24 | [JsonPropertyName("cityName")] 25 | public string CityName { get; set; } 26 | } 27 | 28 | public record CResourceStatus : V1Status 29 | { 30 | [JsonPropertyName("temperature")] 31 | public string Temperature { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/exec/Exec.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using k8s.Models; 3 | using System; 4 | using System.Threading.Tasks; 5 | 6 | var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); 7 | IKubernetes client = new Kubernetes(config); 8 | Console.WriteLine("Starting Request!"); 9 | 10 | var list = client.CoreV1.ListNamespacedPod("default"); 11 | var pod = list.Items[0]; 12 | await ExecInPod(client, pod).ConfigureAwait(false); 13 | 14 | async Task ExecInPod(IKubernetes client, V1Pod pod) 15 | { 16 | var webSocket = 17 | await client.WebSocketNamespacedPodExecAsync(pod.Metadata.Name, "default", "ls", 18 | pod.Spec.Containers[0].Name).ConfigureAwait(false); 19 | 20 | var demux = new StreamDemuxer(webSocket); 21 | demux.Start(); 22 | 23 | var buff = new byte[4096]; 24 | var stream = demux.GetStream(1, 1); 25 | var read = stream.Read(buff, 0, 4096); 26 | var str = System.Text.Encoding.Default.GetString(buff); 27 | Console.WriteLine(str); 28 | } 29 | -------------------------------------------------------------------------------- /examples/patch-aot/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using k8s.Models; 3 | 4 | var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); 5 | IKubernetes client = new Kubernetes(config); 6 | Console.WriteLine("Starting Request!"); 7 | 8 | var pod = client.CoreV1.ListNamespacedPod("default").Items.First(); 9 | var name = pod.Metadata.Name; 10 | PrintLabels(pod); 11 | 12 | var patchStr = @" 13 | { 14 | ""metadata"": { 15 | ""labels"": { 16 | ""test"": ""test"" 17 | } 18 | } 19 | }"; 20 | 21 | client.CoreV1.PatchNamespacedPod(new V1Patch(patchStr, V1Patch.PatchType.MergePatch), name, "default"); 22 | PrintLabels(client.CoreV1.ReadNamespacedPod(name, "default")); 23 | 24 | static void PrintLabels(V1Pod pod) 25 | { 26 | Console.WriteLine($"Labels: for {pod.Metadata.Name}"); 27 | foreach (var (k, v) in pod.Metadata.Labels) 28 | { 29 | Console.WriteLine($"{k} : {v}"); 30 | } 31 | 32 | Console.WriteLine("=-=-=-=-=-=-=-=-=-=-="); 33 | } 34 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/UtilityTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Xunit; 4 | 5 | namespace k8s.Tests 6 | { 7 | public class UtilityTests 8 | { 9 | [Fact] 10 | public void TestQueryStringUtilities() 11 | { 12 | var sb = new StringBuilder(); 13 | Assert.Throws(() => Utilities.AddQueryParameter(null, "key", "value")); 14 | Assert.Throws(() => Utilities.AddQueryParameter(sb, null, "value")); 15 | Assert.Throws(() => Utilities.AddQueryParameter(sb, "", "value")); 16 | 17 | Utilities.AddQueryParameter(sb, "key", "value"); 18 | Utilities.AddQueryParameter(sb, "key", "a=b"); 19 | Utilities.AddQueryParameter(sb, "+key", null); 20 | Utilities.AddQueryParameter(sb, "ekey", ""); 21 | Assert.Equal("?key=value&key=a%3Db&%2Bkey=&ekey=", sb.ToString()); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /doc/docfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": [ 3 | { 4 | "src": [ 5 | { 6 | "files": [ 7 | "KubernetesClient/bin/Release/net8.0/KubernetesClient.dll" 8 | ], 9 | "src": "../src" 10 | } 11 | ], 12 | "dest": "api", 13 | "disableGitFeatures": false, 14 | "disableDefaultFilter": false 15 | } 16 | ], 17 | "build": { 18 | "content": [ 19 | { 20 | "files": [ 21 | "api/**.yml", 22 | "index.md", 23 | "CONTRIBUTING.md", 24 | "toc.yml" 25 | ] 26 | } 27 | ], 28 | "dest": "_site", 29 | "globalMetadataFiles": [], 30 | "fileMetadataFiles": [], 31 | "template": [ 32 | "default" 33 | ], 34 | "postProcessors": [], 35 | "markdownEngineName": "markdig", 36 | "noLangKeyword": false, 37 | "keepFileLink": false, 38 | "cleanupCacheHistory": false, 39 | "disableGitFeatures": false 40 | } 41 | } -------------------------------------------------------------------------------- /src/KubernetesClient/Models/PodMetricsList.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | public class PodMetricsList : IMetadata 4 | { 5 | /// 6 | /// Defines the versioned schema of this representation of an object. 7 | /// 8 | [JsonPropertyName("apiVersion")] 9 | public string ApiVersion { get; set; } 10 | 11 | /// 12 | /// Defines the REST resource this object represents. 13 | /// 14 | [JsonPropertyName("kind")] 15 | public string Kind { get; set; } 16 | 17 | /// 18 | /// The kubernetes standard object's metadata. 19 | /// 20 | [JsonPropertyName("metadata")] 21 | public V1ObjectMeta Metadata { get; set; } 22 | 23 | /// 24 | /// The list of pod metrics. 25 | /// 26 | [JsonPropertyName("items")] 27 | public IEnumerable Items { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/NodeMetricsList.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | public class NodeMetricsList : IMetadata 4 | { 5 | /// 6 | /// Defines the versioned schema of this representation of an object. 7 | /// 8 | [JsonPropertyName("apiVersion")] 9 | public string ApiVersion { get; set; } 10 | 11 | /// 12 | /// Defines the REST resource this object represents. 13 | /// 14 | [JsonPropertyName("kind")] 15 | public string Kind { get; set; } 16 | 17 | /// 18 | /// The kubernetes standard object's metadata. 19 | /// 20 | [JsonPropertyName("metadata")] 21 | public V1ObjectMeta Metadata { get; set; } 22 | 23 | /// 24 | /// The list of node metrics. 25 | /// 26 | [JsonPropertyName("items")] 27 | public IEnumerable Items { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/patch/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using k8s.Models; 3 | using System; 4 | using System.Linq; 5 | 6 | var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); 7 | IKubernetes client = new Kubernetes(config); 8 | Console.WriteLine("Starting Request!"); 9 | 10 | var pod = client.CoreV1.ListNamespacedPod("default").Items.First(); 11 | var name = pod.Metadata.Name; 12 | PrintLabels(pod); 13 | 14 | var patchStr = @" 15 | { 16 | ""metadata"": { 17 | ""labels"": { 18 | ""test"": ""test"" 19 | } 20 | } 21 | }"; 22 | 23 | client.CoreV1.PatchNamespacedPod(new V1Patch(patchStr, V1Patch.PatchType.MergePatch), name, "default"); 24 | PrintLabels(client.CoreV1.ReadNamespacedPod(name, "default")); 25 | 26 | void PrintLabels(V1Pod pod) 27 | { 28 | Console.WriteLine($"Labels: for {pod.Metadata.Name}"); 29 | foreach (var (k, v) in pod.Metadata.Labels) 30 | { 31 | Console.WriteLine($"{k} : {v}"); 32 | } 33 | 34 | Console.WriteLine("=-=-=-=-=-=-=-=-=-=-="); 35 | } 36 | -------------------------------------------------------------------------------- /.github/workflows/draft.yaml: -------------------------------------------------------------------------------- 1 | name: Draft Release 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | 10 | jobs: 11 | draft: 12 | 13 | runs-on: windows-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v6 17 | with: 18 | fetch-depth: 0 19 | 20 | - name: Setup dotnet 21 | uses: actions/setup-dotnet@v5 22 | with: 23 | dotnet-version: | 24 | 8.0.x 25 | 9.0.x 26 | 10.0.x 27 | 28 | - name: dotnet restore 29 | run: dotnet restore --verbosity minimal --configfile nuget.config 30 | 31 | - name: dotnet test 32 | run: dotnet test 33 | 34 | - uses: dotnet/nbgv@master 35 | with: 36 | setAllVars: true 37 | 38 | - name: create release 39 | shell: pwsh 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | run: | 43 | gh release create -d --generate-notes v$env:NBGV_NuGetPackageVersion 44 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/IntOrString.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | [JsonConverter(typeof(IntOrStringJsonConverter))] 4 | public class IntOrString 5 | { 6 | public string Value { get; private init; } 7 | 8 | public static implicit operator IntOrString(int v) 9 | { 10 | return Convert.ToString(v); 11 | } 12 | 13 | public static implicit operator IntOrString(long v) 14 | { 15 | return Convert.ToString(v); 16 | } 17 | 18 | public static implicit operator string(IntOrString v) 19 | { 20 | return v?.Value; 21 | } 22 | 23 | public static implicit operator IntOrString(string v) 24 | { 25 | return new IntOrString { Value = v }; 26 | } 27 | 28 | public override string ToString() 29 | { 30 | return Value; 31 | } 32 | 33 | public int ToInt() 34 | { 35 | return int.Parse(Value); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/attach/Attach.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using k8s.Models; 3 | using System; 4 | using System.Threading.Tasks; 5 | 6 | var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); 7 | IKubernetes client = new Kubernetes(config); 8 | Console.WriteLine("Starting Request!"); 9 | 10 | var list = client.CoreV1.ListNamespacedPod("default"); 11 | var pod = list.Items[0]; 12 | await AttachToPod(client, pod).ConfigureAwait(false); 13 | 14 | async Task AttachToPod(IKubernetes client, V1Pod pod) 15 | { 16 | var webSocket = 17 | await client.WebSocketNamespacedPodAttachAsync(pod.Metadata.Name, "default", 18 | pod.Spec.Containers[0].Name).ConfigureAwait(false); 19 | 20 | var demux = new StreamDemuxer(webSocket); 21 | demux.Start(); 22 | 23 | var buff = new byte[4096]; 24 | var stream = demux.GetStream(1, 1); 25 | while (true) 26 | { 27 | var read = stream.Read(buff, 0, 4096); 28 | var str = System.Text.Encoding.Default.GetString(buff); 29 | Console.WriteLine(str); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/KubernetesClient/KubeConfigModels/ExecCredentialResponse.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.KubeConfigModels 2 | { 3 | public class ExecCredentialResponse 4 | { 5 | public class ExecStatus 6 | { 7 | #nullable enable 8 | public DateTime? ExpirationTimestamp { get; set; } 9 | public string? Token { get; set; } 10 | public string? ClientCertificateData { get; set; } 11 | public string? ClientKeyData { get; set; } 12 | #nullable disable 13 | 14 | public bool IsValid() 15 | { 16 | return !string.IsNullOrEmpty(Token) || 17 | (!string.IsNullOrEmpty(ClientCertificateData) && !string.IsNullOrEmpty(ClientKeyData)); 18 | } 19 | } 20 | 21 | [JsonPropertyName("apiVersion")] 22 | public string ApiVersion { get; set; } 23 | [JsonPropertyName("kind")] 24 | public string Kind { get; set; } 25 | [JsonPropertyName("status")] 26 | public ExecStatus Status { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/IntOrStringTests.cs: -------------------------------------------------------------------------------- 1 | using k8s.Models; 2 | using Xunit; 3 | 4 | namespace k8s.Tests 5 | { 6 | public class IntOrStringTests 7 | { 8 | [Fact] 9 | public void Serialize() 10 | { 11 | { 12 | var v = 123; 13 | IntOrString intorstr = v; 14 | 15 | Assert.Equal("123", KubernetesJson.Serialize(intorstr)); 16 | } 17 | 18 | { 19 | IntOrString intorstr = "12%"; 20 | Assert.Equal("\"12%\"", KubernetesJson.Serialize(intorstr)); 21 | } 22 | } 23 | 24 | [Fact] 25 | public void Deserialize() 26 | { 27 | { 28 | var v = KubernetesJson.Deserialize("1234"); 29 | Assert.Equal("1234", v.Value); 30 | } 31 | 32 | { 33 | var v = KubernetesJson.Deserialize("\"12%\""); 34 | Assert.Equal("12%", v.Value); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/NodeMetrics.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | /// 4 | /// Describes the resource usage metrics of a node pull from metrics server API. 5 | /// 6 | public class NodeMetrics : IMetadata 7 | { 8 | /// 9 | /// The kubernetes standard object's metadata. 10 | /// 11 | [JsonPropertyName("metadata")] 12 | public V1ObjectMeta Metadata { get; set; } 13 | 14 | /// 15 | /// The timestamp when metrics were collected. 16 | /// 17 | [JsonPropertyName("timestamp")] 18 | public DateTime? Timestamp { get; set; } 19 | 20 | /// 21 | /// The interval from which metrics were collected. 22 | /// 23 | [JsonPropertyName("window")] 24 | public string Window { get; set; } 25 | 26 | /// 27 | /// The resource usage. 28 | /// 29 | [JsonPropertyName("usage")] 30 | public IDictionary Usage { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/PodMetrics.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | /// 4 | /// Describes the resource usage metrics of a pod pull from metrics server API. 5 | /// 6 | public class PodMetrics : IMetadata 7 | { 8 | /// 9 | /// The kubernetes standard object's metadata. 10 | /// 11 | [JsonPropertyName("metadata")] 12 | public V1ObjectMeta Metadata { get; set; } 13 | 14 | /// 15 | /// The timestamp when metrics were collected. 16 | /// 17 | [JsonPropertyName("timestamp")] 18 | public DateTime? Timestamp { get; set; } 19 | 20 | /// 21 | /// The interval from which metrics were collected. 22 | /// 23 | [JsonPropertyName("window")] 24 | public string Window { get; set; } 25 | 26 | /// 27 | /// The list of containers metrics. 28 | /// 29 | [JsonPropertyName("containers")] 30 | public List Containers { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.doc diff=astextplain 2 | *.DOC diff=astextplain 3 | *.docx diff=astextplain 4 | *.DOCX diff=astextplain 5 | *.dot diff=astextplain 6 | *.DOT diff=astextplain 7 | *.pdf diff=astextplain 8 | *.PDF diff=astextplain 9 | *.rtf diff=astextplain 10 | *.RTF diff=astextplain 11 | 12 | *.jpg binary 13 | *.png binary 14 | *.gif binary 15 | 16 | *.cs text=auto diff=csharp 17 | *.vb text=auto 18 | *.resx text=auto 19 | *.c text=auto 20 | *.cpp text=auto 21 | *.cxx text=auto 22 | *.h text=auto 23 | *.hxx text=auto 24 | *.py text=auto 25 | *.rb text=auto 26 | *.java text=auto 27 | *.html text=auto 28 | *.htm text=auto 29 | *.css text=auto 30 | *.scss text=auto 31 | *.sass text=auto 32 | *.less text=auto 33 | *.js text=auto 34 | *.lisp text=auto 35 | *.clj text=auto 36 | *.sql text=auto 37 | *.php text=auto 38 | *.lua text=auto 39 | *.m text=auto 40 | *.asm text=auto 41 | *.erl text=auto 42 | *.fs text=auto 43 | *.fsx text=auto 44 | *.hs text=auto 45 | 46 | *.csproj text=auto 47 | *.vbproj text=auto 48 | *.fsproj text=auto 49 | *.dbproj text=auto 50 | *.sln text=auto eol=crlf 51 | 52 | src/KubernetesClient/generated/** linguist-generated 53 | -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/KubeConfigModels/ContextDetails.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Represents a tuple of references to a cluster (how do I communicate with a kubernetes cluster), 7 | /// a user (how do I identify myself), and a namespace (what subset of resources do I want to work with) 8 | /// 9 | [YamlSerializable] 10 | public class ContextDetails 11 | { 12 | /// 13 | /// Gets or sets the name of the cluster for this context. 14 | /// 15 | [YamlMember(Alias = "cluster")] 16 | public string Cluster { get; set; } 17 | 18 | /// 19 | /// Gets or sets the name of the user for this context. 20 | /// 21 | [YamlMember(Alias = "user")] 22 | public string User { get; set; } 23 | 24 | /// 25 | /// /Gets or sets the default namespace to use on unspecified requests. 26 | /// 27 | [YamlMember(Alias = "namespace")] 28 | public string Namespace { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/ca2.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC3zCCAcegAwIBAgIQWNOfSGBRn4EUcsj7E1UN8zANBgkqhkiG9w0BAQsFADAZ 3 | MRcwFQYDVQQKEw5EYXZpZCBPcmJlbGlhbjAeFw0xODA2MDgxMjI2MDBaFw0yMTA1 4 | MjMxMjI2MDBaMBkxFzAVBgNVBAoTDkRhdmlkIE9yYmVsaWFuMIIBIjANBgkqhkiG 5 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnXGK1ZHqF4fhO3WOtlo5kqVYHHYTasNmzbQh 6 | MJ0IHiFrCVNi6apohleHi0IlzVFCQY5+yab2Lz7J2qcadRVWLlfhskMx4hbSD+eX 7 | H9MDcnV1k4AyFz+9I+dL4rb5DPcK9vNQF0KXtdpaq4qVs+IoRR4Ck00yvzLmOMTs 8 | YvFVjW6XgKPR+y89y8iykW2puiJ/y6DLKlP+2HDGGEI07C+4Tkxps6uRkPz6ySVb 9 | 6mhJ6P/+8WmuMc0Ur1kNgA0GEUTFYlRNuF0nNjBvncGBUwOWAUNbsYQgElaqXJKe 10 | XZ6M44+oBvRsCsnf7j3hfKti4u/Qy9nDejJ/15R6I6A5JdYOxwIDAQABoyMwITAO 11 | BgNVHQ8BAf8EBAMCAqwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC 12 | AQEAU2Rp4T7iWomEsCC8nrQPXh/6AlVnfb/vhC7aCq+g6CF+LvksfM3Uj+JLQ5rM 13 | QNavSXowqe11vNb1Qu7LcQT5ff76XEoK0dKA8uMs60wUkHttfPzXM522rdv+i8EF 14 | QwVirN85W5i2q669MQ2BeJ37gQ6vQAOLvHXTuspDo1qrfT3zkeGiLEXRM4k4d6OT 15 | BnZNYvfdTTZX7OlvHfw5hdcRtoOTBmTAh+UKJvOUIQ2g/Mp2VBxNNC5zhJHTwEXj 16 | ssHyR24e9+GODLviep2H1uB+mHZQ5Yvzxxlkz8NTDx+mUmBSF1gGuDNdmKrCrP92 17 | bJZY0LcRrXX0aqPymVZrINDvtA== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5zCCAc+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwptaW5p 3 | a3ViZUNBMB4XDTE3MDcyNDA1NDExNloXDTI3MDcyMjA1NDExNlowFTETMBEGA1UE 4 | AxMKbWluaWt1YmVDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMfj 5 | J9bJarUsN5Ynt/sbDFQQLp6BeHPXOcUdbNan1YbXdFGN8qLKkkQz0YY1hcVGrXdj 6 | 3vd2s8x9XlOyQPZ1SX4vJa5x/67BzFdxbCLg6jBYAisGvYu0hV4jvhHYOZH8sWUp 7 | 6n+gPm5c3J8gjqAmM0VwpvtG9HBIr1MWQ4HSTCBVoPvuG9TkOyxrB9RCha16hG7j 8 | B3m9XNEkRVl1xvW6wkeTO4n5cFSoDG0bfCnnjf0oz+pf0yJoSHbl/f2jI/rggMft 9 | 0R0LJfqdGlNCKCuN4g0jMmf26313oe+7i8uU4ut9iM1OBv6vD+xy115DGYG7EQIy 10 | lC1rd+gNlGQSxDafAb8CAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgKkMB0GA1UdJQQW 11 | MBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 12 | DQEBCwUAA4IBAQAnXDZUdfC22zyFpZ+Rez3tyk9SqpOeiN1xGirZ5obDgvOS9vSR 13 | GLrsdN4UtXfGpKeMNQJV4e9YDz1ehLd1MK1BoxDVZHB0Sm2QxuyA4EyPfpHH9zaY 14 | qoRgDeUKBmCteLLcY3ukOzGf915j+lWQHv+tk52gvHfxvRyEuawSxSnowkGGFY9R 15 | 6AQ2cFm7G3SdygRWVXT1hk5hVQXvBY9DNU1YNvN0qWE6ss5RHJ/cxHFWtrdcr86K 16 | DqW9Ylr1l2iwkWpnXR4OMK3ZFjwX/qi11Z8eMDOi+0FxZ/6BkGQxe7X6D2GjCZ3r 17 | Lfbj0HBpynkd6lfLmIWgEzGYxrQjvczbAKBD 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /examples/clientset/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using k8s.Models; 3 | using k8s.ClientSets; 4 | using System.Threading.Tasks; 5 | 6 | namespace clientset 7 | { 8 | internal class Program 9 | { 10 | private static async Task Main(string[] args) 11 | { 12 | var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); 13 | var client = new Kubernetes(config); 14 | 15 | var clientSet = new ClientSet(client); 16 | var list = await clientSet.CoreV1.Pod.ListAsync("default").ConfigureAwait(false); 17 | foreach (var item in list) 18 | { 19 | System.Console.WriteLine(item.Metadata.Name); 20 | } 21 | 22 | var pod = await clientSet.CoreV1.Pod.GetAsync("test", "default").ConfigureAwait(false); 23 | System.Console.WriteLine(pod?.Metadata?.Name); 24 | 25 | var watch = clientSet.CoreV1.Pod.WatchListAsync("default"); 26 | await foreach (var (_, item) in watch.ConfigureAwait(false)) 27 | { 28 | System.Console.WriteLine(item.Metadata.Name); 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/KubernetesClient/Authentication/ServiceClientCredentials.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. See License.txt in the project root for license information. 3 | 4 | using System.Net.Http; 5 | 6 | namespace k8s.Authentication 7 | { 8 | /// 9 | /// ServiceClientCredentials is the abstraction for credentials used by ServiceClients accessing REST services. 10 | /// 11 | public abstract class ServiceClientCredentials 12 | { 13 | /// 14 | /// Apply the credentials to the HTTP request. 15 | /// 16 | /// The HTTP request message. 17 | /// Cancellation token. 18 | /// 19 | /// Task that will complete when processing has finished. 20 | /// 21 | public virtual Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken) 22 | { 23 | // Return an empty task by default 24 | return Task.CompletedTask; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/E2E.Tests/E2E.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | k8s.E2E 5 | net8.0;net9.0;net10.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/Kubectl.Tests/KubectlTests.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace k8s.kubectl.Tests; 4 | 5 | public partial class KubectlTests 6 | { 7 | private string RunKubectl(string args) 8 | { 9 | var p = new Process 10 | { 11 | StartInfo = new ProcessStartInfo 12 | { 13 | FileName = "kubectl", 14 | Arguments = args, 15 | UseShellExecute = false, 16 | RedirectStandardOutput = true, 17 | RedirectStandardError = true, 18 | CreateNoWindow = true, 19 | }, 20 | }; 21 | 22 | p.Start(); 23 | 24 | try 25 | { 26 | if (!p.WaitForExit((int)TimeSpan.FromSeconds(30).TotalMilliseconds)) 27 | { 28 | throw new Exception("kubectl timed out"); 29 | } 30 | 31 | if (p.ExitCode != 0) 32 | { 33 | throw new Exception(p.StandardError.ReadToEnd()); 34 | } 35 | 36 | return p.StandardOutput.ReadToEnd(); 37 | } 38 | finally 39 | { 40 | p.Kill(true); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | 9 | # Maintain dependencies for GitHub Actions 10 | - package-ecosystem: "github-actions" 11 | directory: "/" 12 | schedule: 13 | interval: "daily" 14 | # Allow up to 5 open pull requests for GitHub Actions dependencies 15 | open-pull-requests-limit: 5 16 | labels: 17 | - "dependencies" 18 | # Rebase open pull requests when changes are detected 19 | rebase-strategy: "auto" 20 | 21 | # Maintain dependencies for NuGet packages 22 | - package-ecosystem: "nuget" 23 | directory: "/" 24 | schedule: 25 | interval: "daily" 26 | # Allow up to 10 open pull requests for NuGet dependencies 27 | open-pull-requests-limit: 10 28 | labels: 29 | - "dependencies" 30 | # Rebase open pull requests when changes are detected 31 | rebase-strategy: "auto" 32 | -------------------------------------------------------------------------------- /examples/labels/PodList.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); 6 | IKubernetes client = new Kubernetes(config); 7 | Console.WriteLine("Starting Request!"); 8 | 9 | var list = client.CoreV1.ListNamespacedService("default"); 10 | foreach (var item in list.Items) 11 | { 12 | Console.WriteLine("Pods for service: " + item.Metadata.Name); 13 | Console.WriteLine("=-=-=-=-=-=-=-=-=-=-="); 14 | if (item.Spec == null || item.Spec.Selector == null) 15 | { 16 | continue; 17 | } 18 | 19 | var labels = new List(); 20 | foreach (var key in item.Spec.Selector) 21 | { 22 | labels.Add(key.Key + "=" + key.Value); 23 | } 24 | 25 | var labelStr = string.Join(",", labels.ToArray()); 26 | Console.WriteLine(labelStr); 27 | var podList = client.CoreV1.ListNamespacedPod("default", labelSelector: labelStr); 28 | foreach (var pod in podList.Items) 29 | { 30 | Console.WriteLine(pod.Metadata.Name); 31 | } 32 | 33 | if (podList.Items.Count == 0) 34 | { 35 | Console.WriteLine("Empty!"); 36 | } 37 | 38 | Console.WriteLine(); 39 | } 40 | -------------------------------------------------------------------------------- /src/KubernetesClient/KubeConfigModels/Context.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Relates nicknames to context information. 7 | /// 8 | public class Context 9 | { 10 | /// 11 | /// Gets or sets the context information. 12 | /// 13 | [YamlMember(Alias = "context")] 14 | public ContextDetails ContextDetails { get; set; } 15 | 16 | /// 17 | /// Gets or sets the nickname for this context. 18 | /// 19 | [YamlMember(Alias = "name")] 20 | public string Name { get; set; } 21 | 22 | /// 23 | /// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields. 24 | /// 25 | [YamlMember(Alias = "extensions")] 26 | public IEnumerable Extensions { get; set; } 27 | 28 | 29 | [Obsolete("This property is not set by the YAML config. Use ContextDetails.Namespace instead.")] 30 | [YamlMember(Alias = "namespace")] 31 | public string Namespace { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/ca-bundle-root.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDEDCCAfigAwIBAgIJAJpb9irKg2JjMA0GCSqGSIb3DQEBCwUAMBUxEzARBgNV 3 | BAMMCmt1YmVybmV0ZXMwHhcNMTkwMzAzMDAyMTI3WhcNMzkwMjI2MDAyMTI3WjAV 4 | MRMwEQYDVQQDDAprdWJlcm5ldGVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 5 | CgKCAQEAuoK+Na+LyKIipmftBw4Y+Z19g8yv6Y+dYt6KlBg24XHNA0v1cMwtOCDF 6 | Mlm4rsD7Jd5UO6ugdk3fxEvGGhmzWTXSBRUWcTbScAM49mALBFkCvNTPK2vVhk7P 7 | im2QQl8a5vjYz8HLKJTb/O+0q+Kktpd7XTaU2U7ZebiLVs5bvNbb3ZDtIjAARY9S 8 | alZ4hOzuVNaSX9MBRqTWq3HuKwDiVTT3dan/ABoU8NdedPfIbyY48wiQgjEYb64g 9 | 3geYpArLQeffo8fmhUEPRR/1WrfvYvvm8sV8jT+rqxITKJ5Vo5kpZUpomDOtGVMS 10 | gGAle6mcTrqlrsCFc4gFRRoHiH1ODQIDAQABo2MwYTAdBgNVHQ4EFgQULs/lzct8 11 | CGvVdIiq4t9T4idu5OwwHwYDVR0jBBgwFoAULs/lzct8CGvVdIiq4t9T4idu5Oww 12 | DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD 13 | ggEBAFMq5z4OoaIhqx/i/btpVLRnQDcpDwdUurE0iNPz3bgOI5QiIe95oUwXSFQL 14 | ciECvObfMmiVuz+p7ND5eNdxYR4hlq1W1PYcgRQgusXCC4Xd/XAGaLZXzH3SBrmp 15 | bs5sfokhXKNccsnQu5Ya3JRkALxxUJ+DcOn+vi9gmEAzi+nXbyqUjIhSD5nygClX 16 | 0aSKbvhUmXyaJpUH0i7dSxWP3LqCDjtru/5ejNtB097dNcyF8js3Yuk3hwqyegQx 17 | ELn4c/TKPL9L8vE7tJg/M78DPAvRCiuwl0HQcasBE2AX0wdpY0UeXsNDyzUf/2WF 18 | fHY4DnuBdeVdHtl1yPlXmQkMoQM= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/E2E.Aot.Tests/E2E.Aot.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | k8s.E2E 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /tests/Kubectl.Tests/Kubectl.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0;net9.0;net10.0 5 | enable 6 | enable 7 | false 8 | k8s.kubectl.Tests 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/ca-bundle-intermediate.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDDTCCAfWgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UEAwwKa3Vi 3 | ZXJuZXRlczAeFw0xOTAzMDMxNzA4MDlaFw0yOTAyMjgxNzA4MDlaMBYxFDASBgNV 4 | BAMMC2V0Y2hhbmctdWI1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA 5 | x1Tp7Da3NbjdHmYdYZ/GNpCRGvFFap7EG1pokhfILKSbPusqiO9wnKDE4Afdn/ZE 6 | CQV0Whwtox3jczBOIRy+P6FvlPyhApUpynVTwgCiuhTM+thgODgpe6GXmVlVJGvv 7 | AoLw7CMndB5sMs5HH+qA2U1q4VFI/csr3/yeKzWBik3dZVoh04sI9WTVL+bl/1X5 8 | 0dl5qrqkYiDx8ycAHyOnl8dhJW+RGl67HiliuUeSq6vwsfv9rh3TP9wHVF1PXFJp 9 | WfXy4WbLmuld5wxXnQVO2g51jqfqN9fD8FHIkae1IkO/PUTucloNlLiFsragQOTD 10 | RVSP+TV3gshATBs2MMVXMwIDAQABo2YwZDAdBgNVHQ4EFgQU/3w9AR2cnEepWH4E 11 | 8a1xLZAnjykwHwYDVR0jBBgwFoAULs/lzct8CGvVdIiq4t9T4idu5OwwEgYDVR0T 12 | AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggEB 13 | AKw741V1wszIthHBV8dvCyQoyozBJuAo4IHbiiFmzuiQuyshMcX+Qs9a+g6OG5d1 14 | UbwFfUlqzmZQcbcR/Jc6wMz3wO6Hoy5pS3w/FR2UMGR39o95/7XCkTIOwCqau6Pw 15 | dpgvbnaiqPFPqD3ohdUuVRcXG3va5AmKTsUn7m+lR/93/qptt+SUVp6jwnbGcwoB 16 | s3u2XXx5s1M7tqqj3tAEOPCKlohS6mQ4X3wulgpZ1XpJ0WTvcvoPXEtA56k7vX3a 17 | 4E6x66LZCFA2ZR/5COv5D055AhrihKL8kbAutxhfA27SJ/MGowzmTT7kVQha3Su3 18 | aoOYZgcUww+SkRSGVrtgMgQ= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /examples/webApiDependencyInjection/Controllers/ExampleDependencyInjectionOnMethodController.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace webApiDependencyInjection.Controllers 5 | { 6 | [ApiController] 7 | [Route("[controller]")] 8 | public class ExampleDependencyInjectionOnMethodController : ControllerBase 9 | { 10 | /// 11 | /// Example using the kubernetes client injected directly into the method ([FromServices] IKubernetes kubernetesClient). 12 | /// 13 | /// The Kubernetes client instance injected via dependency injection. 14 | /// A collection of pod names in the default namespace. 15 | [HttpGet] 16 | public IEnumerable GetPods([FromServices] IKubernetes kubernetesClient) 17 | { 18 | ArgumentNullException.ThrowIfNull(kubernetesClient); 19 | 20 | // Read the list of pods contained in default namespace 21 | var podList = kubernetesClient.CoreV1.ListNamespacedPod("default"); 22 | 23 | // Return names of pods 24 | return podList.Items.Select(pod => pod.Metadata.Name); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/KubernetesClient/FloatEmitter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using YamlDotNet.Core; 3 | using YamlDotNet.Core.Events; 4 | using YamlDotNet.Serialization; 5 | using YamlDotNet.Serialization.EventEmitters; 6 | 7 | namespace k8s 8 | { 9 | internal class FloatEmitter : ChainedEventEmitter 10 | { 11 | public FloatEmitter(IEventEmitter nextEmitter) 12 | : base(nextEmitter) 13 | { 14 | } 15 | 16 | public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) 17 | { 18 | switch (eventInfo.Source.Value) 19 | { 20 | // Floating point numbers should always render at least one zero (e.g. 1.0f => '1.0' not '1') 21 | case double d: 22 | emitter.Emit(new Scalar(d.ToString("0.0######################", CultureInfo.InvariantCulture))); 23 | break; 24 | case float f: 25 | emitter.Emit(new Scalar(f.ToString("0.0######################", CultureInfo.InvariantCulture))); 26 | break; 27 | default: 28 | base.Emit(eventInfo, emitter); 29 | break; 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/TokenFileAuthTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using k8s.Authentication; 3 | using System; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | namespace k8s.Tests 9 | { 10 | public class TokenFileAuthTests 11 | { 12 | [Fact] 13 | public async Task TestToken() 14 | { 15 | var auth = new TokenFileAuth("assets/token1"); 16 | var result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(true); 17 | result.Scheme.Should().Be("Bearer"); 18 | result.Parameter.Should().Be("token1"); 19 | 20 | auth.TokenFile = "assets/token2"; 21 | result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(true); 22 | result.Scheme.Should().Be("Bearer"); 23 | result.Parameter.Should().Be("token1"); 24 | 25 | auth.TokenExpiresAt = DateTime.UtcNow.AddSeconds(-1); 26 | result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(true); 27 | result.Scheme.Should().Be("Bearer"); 28 | result.Parameter.Should().Be("token2"); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/aks-kubelogin/README.md: -------------------------------------------------------------------------------- 1 | # AKS C# example using kubelogin + MSI 2 | 3 | This example shows how to use the [kubelogin](https://github.com/Azure/kubelogin) to authenticate using [managed identities](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) with Azure Kubernetes Service (AKS) using the C# SDK. 4 | 5 | 6 | ## Prerequisites 7 | 8 | - turn on AAD support for AKS, see [here](https://docs.microsoft.com/en-us/azure/aks/managed-aad) 9 | - create a managed identity for the AKS cluster 10 | - assign the managed identity the `Azure Kubernetes Service RBAC Cluster Admin` (or other RBAC permission) on the AKS cluster 11 | - assign the managed identity to the VM, see [here](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/qs-configure-portal-windows-vm) 12 | - install the [kubelogin](https://github.com/Azure/kubelogin) to your machine 13 | 14 | ## Running the code 15 | 16 | *You must the the code on VM with MSI* 17 | 18 | - Replace `server` with the address of your AKS cluster 19 | - Replace `clientid` with the client id of the managed identity 20 | - Replace `kubelogin` with the path to the kubelogin executable 21 | 22 | ``` 23 | dotnet run 24 | ``` -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/Beta/AsyncKubectl.Cordon.cs: -------------------------------------------------------------------------------- 1 | using Json.Patch; 2 | using k8s.Models; 3 | using System.Text.Json; 4 | 5 | namespace k8s.kubectl.beta; 6 | 7 | public partial class AsyncKubectl 8 | { 9 | public async Task Cordon(string nodeName, CancellationToken cancellationToken = default) 10 | { 11 | await PatchNodeUnschedulable(nodeName, true, cancellationToken).ConfigureAwait(false); 12 | } 13 | 14 | public async Task Uncordon(string nodeName, CancellationToken cancellationToken = default) 15 | { 16 | await PatchNodeUnschedulable(nodeName, false, cancellationToken).ConfigureAwait(false); 17 | } 18 | 19 | private async Task PatchNodeUnschedulable(string nodeName, bool desired, CancellationToken cancellationToken = default) 20 | { 21 | var node = await client.CoreV1.ReadNodeAsync(nodeName, cancellationToken: cancellationToken).ConfigureAwait(false); 22 | 23 | var old = JsonSerializer.SerializeToDocument(node); 24 | node.Spec.Unschedulable = desired; 25 | 26 | var patch = old.CreatePatch(node); 27 | 28 | await client.CoreV1.PatchNodeAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), nodeName, cancellationToken: cancellationToken).ConfigureAwait(false); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/Beta/AsyncKubectl.Delete.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.kubectl.beta; 2 | 3 | public partial class AsyncKubectl 4 | { 5 | /// 6 | /// Delete a Kubernetes resource by name. 7 | /// 8 | /// The type of Kubernetes resource to delete. 9 | /// The name of the resource. 10 | /// The namespace of the resource (for namespaced resources). Optional. 11 | /// Cancellation token. 12 | /// The deleted resource. 13 | public async Task DeleteAsync(string name, string? @namespace = null, CancellationToken cancellationToken = default) 14 | where T : IKubernetesObject 15 | { 16 | var metadata = typeof(T).GetKubernetesTypeMetadata(); 17 | using var genericClient = new GenericClient(client, metadata.Group, metadata.ApiVersion, metadata.PluralName, disposeClient: false); 18 | 19 | return @namespace != null 20 | ? await genericClient.DeleteNamespacedAsync(@namespace, name, cancellationToken).ConfigureAwait(false) 21 | : await genericClient.DeleteAsync(name, cancellationToken).ConfigureAwait(false); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/IntOrStringJsonConverter.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | public sealed class IntOrStringJsonConverter : JsonConverter 4 | { 5 | public override IntOrString Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 6 | { 7 | switch (reader.TokenType) 8 | { 9 | case JsonTokenType.String: 10 | return reader.GetString(); 11 | case JsonTokenType.Number: 12 | return reader.GetInt64(); 13 | default: 14 | break; 15 | } 16 | 17 | throw new NotSupportedException(); 18 | } 19 | 20 | public override void Write(Utf8JsonWriter writer, IntOrString value, JsonSerializerOptions options) 21 | { 22 | if (writer == null) 23 | { 24 | throw new ArgumentNullException(nameof(writer)); 25 | } 26 | 27 | var s = value.Value; 28 | 29 | if (long.TryParse(s, out var intv)) 30 | { 31 | writer.WriteNumberValue(intv); 32 | return; 33 | } 34 | 35 | writer.WriteStringValue(s); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/KubernetesClient/SourceGenerationContext.cs: -------------------------------------------------------------------------------- 1 | using static k8s.KubernetesJson; 2 | using static k8s.Models.V1Status; 3 | 4 | namespace k8s; 5 | 6 | [JsonSourceGenerationOptions( 7 | DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, 8 | PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, 9 | UseStringEnumConverter = true, 10 | Converters = new[] { typeof(Iso8601TimeSpanConverter), typeof(KubernetesDateTimeConverter), typeof(KubernetesDateTimeOffsetConverter), typeof(V1StatusObjectViewConverter) }) 11 | ] 12 | public partial class SourceGenerationContext : JsonSerializerContext 13 | { 14 | } 15 | 16 | /// 17 | /// Used by V1Status in order to avoid the recursive loop as SourceGenerationContext contains V1StatusObjectViewConverter 18 | /// 19 | [JsonSerializable(typeof(V1Status))] 20 | [JsonSourceGenerationOptions( 21 | DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, 22 | PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, 23 | UseStringEnumConverter = true, 24 | Converters = new[] { typeof(Iso8601TimeSpanConverter), typeof(KubernetesDateTimeConverter), typeof(KubernetesDateTimeOffsetConverter) }) 25 | ] 26 | public partial class StatusSourceGenerationContext : JsonSerializerContext 27 | { 28 | } 29 | -------------------------------------------------------------------------------- /examples/openTelemetryConsole/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using OpenTelemetry; 3 | using OpenTelemetry.Resources; 4 | using OpenTelemetry.Trace; 5 | 6 | var serviceName = "MyCompany.MyProduct.MyService"; 7 | var serviceVersion = "1.0.0"; 8 | 9 | // Create the OpenTelemetry TraceProvide with HttpClient instrumentation enabled 10 | // NOTE: for this example telemetry will be exported to console 11 | using var tracerProvider = Sdk.CreateTracerProviderBuilder() 12 | .AddSource(serviceName) 13 | .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(serviceName: serviceName, serviceVersion: serviceVersion)) 14 | .AddHttpClientInstrumentation() 15 | .AddConsoleExporter() 16 | .Build(); 17 | 18 | // Load kubernetes configuration 19 | var config = KubernetesClientConfiguration.BuildDefaultConfig(); 20 | 21 | // Create an istance of Kubernetes client 22 | IKubernetes client = new Kubernetes(config); 23 | 24 | // Read the list of pods contained in default namespace 25 | var list = client.CoreV1.ListNamespacedPod("default"); 26 | 27 | // Print the name of pods 28 | foreach (var item in list.Items) 29 | { 30 | Console.WriteLine(item.Metadata.Name); 31 | } 32 | 33 | // Or empty if there are no pods 34 | if (list.Items.Count == 0) 35 | { 36 | Console.WriteLine("Empty!"); 37 | } 38 | -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/Beta/Kubectl.Top.cs: -------------------------------------------------------------------------------- 1 | using k8s.Models; 2 | 3 | namespace k8s.kubectl.beta; 4 | 5 | public partial class Kubectl 6 | { 7 | /// 8 | /// Get top nodes sorted by CPU or memory usage. 9 | /// 10 | /// The metric to sort by ("cpu" or "memory"). Defaults to "cpu". 11 | /// A list of nodes with their metrics, sorted by the specified metric in descending order. 12 | public List> TopNodes(string metric = "cpu") 13 | { 14 | return client.TopNodesAsync(metric).GetAwaiter().GetResult(); 15 | } 16 | 17 | /// 18 | /// Get top pods in a namespace sorted by CPU or memory usage. 19 | /// 20 | /// The namespace to get pod metrics from. 21 | /// The metric to sort by ("cpu" or "memory"). Defaults to "cpu". 22 | /// A list of pods with their metrics, sorted by the specified metric in descending order. 23 | public List> TopPods(string @namespace, string metric = "cpu") 24 | { 25 | return client.TopPodsAsync(@namespace, metric).GetAwaiter().GetResult(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/GeneratorExecutionContextExt.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.Text; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Scriban; 5 | using Scriban.Runtime; 6 | using System.Text; 7 | 8 | namespace LibKubernetesGenerator 9 | { 10 | internal static class GeneratorExecutionContextExt 11 | { 12 | public static void RenderToContext(this IncrementalGeneratorPostInitializationContext context, string templatefile, ScriptObject sc, string generatedfile) 13 | { 14 | var tc = new TemplateContext(); 15 | tc.PushGlobal(sc); 16 | context.RenderToContext(templatefile, tc, generatedfile); 17 | } 18 | 19 | public static void RenderToContext(this IncrementalGeneratorPostInitializationContext context, string templatefile, TemplateContext tc, string generatedfile) 20 | { 21 | var template = Template.Parse(EmbedResource.GetResource(templatefile)); 22 | var generated = template.Render(tc); 23 | 24 | var syntaxTree = CSharpSyntaxTree.ParseText(generated); 25 | var normalized = syntaxTree.GetRoot().NormalizeWhitespace().ToFullString(); 26 | context.AddSource(generatedfile, SourceText.From(normalized, Encoding.UTF8)); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/KubernetesClient/Autorest/HttpExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. See License.txt in the project root for license information. 3 | 4 | using System.Net.Http; 5 | using System.Net.Http.Headers; 6 | 7 | namespace k8s.Autorest 8 | { 9 | /// 10 | /// Extensions for manipulating HTTP request and response objects. 11 | /// 12 | internal static class HttpExtensions 13 | { 14 | /// 15 | /// Get the content headers of an HttpRequestMessage. 16 | /// 17 | /// The request message. 18 | /// The content headers. 19 | public static HttpHeaders GetContentHeaders(this HttpRequestMessage request) 20 | { 21 | return request?.Content?.Headers; 22 | } 23 | 24 | /// 25 | /// Get the content headers of an HttpResponseMessage. 26 | /// 27 | /// The response message. 28 | /// The content headers. 29 | public static HttpHeaders GetContentHeaders(this HttpResponseMessage response) 30 | { 31 | return response?.Content?.Headers; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/KubeConfigModels/ExecCredentialResponse.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | [YamlSerializable] 6 | public class ExecCredentialResponse 7 | { 8 | public class ExecStatus 9 | { 10 | #nullable enable 11 | [JsonPropertyName("expirationTimestamp")] 12 | public DateTime? ExpirationTimestamp { get; set; } 13 | [JsonPropertyName("token")] 14 | public string? Token { get; set; } 15 | [JsonPropertyName("clientCertificateData")] 16 | public string? ClientCertificateData { get; set; } 17 | [JsonPropertyName("clientKeyData")] 18 | public string? ClientKeyData { get; set; } 19 | #nullable disable 20 | 21 | public bool IsValid() 22 | { 23 | return !string.IsNullOrEmpty(Token) || 24 | (!string.IsNullOrEmpty(ClientCertificateData) && !string.IsNullOrEmpty(ClientKeyData)); 25 | } 26 | } 27 | 28 | [JsonPropertyName("apiVersion")] 29 | public string ApiVersion { get; set; } 30 | [JsonPropertyName("kind")] 31 | public string Kind { get; set; } 32 | [JsonPropertyName("status")] 33 | public ExecStatus Status { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/LibKubernetesGenerator/templates/Model.cs.template: -------------------------------------------------------------------------------- 1 | // 2 | // Code generated by https://github.com/kubernetes-client/csharp/tree/master/src/LibKubernetesGenerator 3 | // Changes may cause incorrect behavior and will be lost if the code is 4 | // regenerated. 5 | // 6 | 7 | namespace k8s.Models; 8 | 9 | /// 10 | /// {{ToXmlDoc def.description}} 11 | /// 12 | {{ if hasExt }} 13 | [KubernetesEntity(Group=KubeGroup, Kind=KubeKind, ApiVersion=KubeApiVersion, PluralName=KubePluralName)] 14 | {{ end }} 15 | public partial {{typ}} {{clz}} {{ if hasExt }} : {{ GetInterfaceName def }} {{ end }} 16 | { 17 | {{ if hasExt}} 18 | public const string KubeApiVersion = "{{ GetApiVersion def }}"; 19 | public const string KubeKind = "{{ GetKind def }}"; 20 | public const string KubeGroup = "{{ GetGroup def }}"; 21 | public const string KubePluralName = "{{ GetPlural def }}"; 22 | {{ end }} 23 | 24 | {{ for property in properties }} 25 | /// 26 | /// {{ToXmlDoc property.description}} 27 | /// 28 | [JsonPropertyName("{{property.name}}")] 29 | public {{ if property.IsRequired }} required {{ end }} {{GetDotNetType property}} {{GetDotNetName property.name "field"}} { get; set; } 30 | {{ end }} 31 | } 32 | 33 | -------------------------------------------------------------------------------- /tests/Kubectl.Tests/KubectlTests.Version.cs: -------------------------------------------------------------------------------- 1 | using k8s.E2E; 2 | using k8s.kubectl.beta; 3 | using System.Text.Json; 4 | using Xunit; 5 | 6 | namespace k8s.kubectl.Tests; 7 | 8 | public partial class KubectlTests 9 | { 10 | [MinikubeFact] 11 | public void Version() 12 | { 13 | using var kubernetes = MinikubeTests.CreateClient(); 14 | var client = new Kubectl(kubernetes); 15 | var version = client.Version(); 16 | var serverobj = version.ServerVersion; 17 | 18 | var output = RunKubectl("version"); 19 | 20 | var serverstr = output.Split('\n').Skip(1).First().Trim(); 21 | 22 | Assert.Equal(serverstr, $"Server Version: version.Info{{Major:\"{serverobj.Major}\", Minor:\"{serverobj.Minor}\", GitVersion:\"{serverobj.GitVersion}\", GitCommit:\"{serverobj.GitCommit}\", GitTreeState:\"{serverobj.GitTreeState}\", BuildDate:\"{serverobj.BuildDate}\", GoVersion:\"{serverobj.GoVersion}\", Compiler:\"{serverobj.Compiler}\", Platform:\"{serverobj.Platform}\"}}"); 23 | 24 | dynamic? swagger = JsonSerializer.Deserialize(File.OpenRead("swagger.json"), new 25 | { 26 | info = new 27 | { 28 | version = "", 29 | }, 30 | }.GetType()); 31 | 32 | Assert.Equal(swagger?.info.version, version.ClientSwaggerVersion); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/IntOrStringYamlConverter.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Core; 2 | using YamlDotNet.Serialization; 3 | 4 | namespace k8s.Models 5 | { 6 | public class IntOrStringYamlConverter : IYamlTypeConverter 7 | { 8 | public bool Accepts(Type type) 9 | { 10 | return type == typeof(IntOrString); 11 | } 12 | 13 | public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) 14 | { 15 | if (parser?.Current is YamlDotNet.Core.Events.Scalar scalar) 16 | { 17 | try 18 | { 19 | if (string.IsNullOrEmpty(scalar?.Value)) 20 | { 21 | return null; 22 | } 23 | 24 | return scalar?.Value; 25 | } 26 | finally 27 | { 28 | parser?.MoveNext(); 29 | } 30 | } 31 | 32 | throw new InvalidOperationException(parser?.Current?.ToString()); 33 | } 34 | 35 | public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) 36 | { 37 | var obj = (IntOrString)value; 38 | emitter?.Emit(new YamlDotNet.Core.Events.Scalar(obj?.Value)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/client.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDbjCCAlagAwIBAgIJAJD2bN6nz4ieMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV 3 | BAYTAlVTMQswCQYDVQQIDAJXQTENMAsGA1UEBwwEVGVzdDEhMB8GA1UECgwYSW50 4 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE3MDcyNzA0NTEyNloXDTE4MDcyNzA0 5 | NTEyNlowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMQ0wCwYDVQQHDARUZXN0 6 | MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3 7 | DQEBAQUAA4IBDwAwggEKAoIBAQDG8khxm/q6ls7TTKlKtTJgiPh6Gh7w1dCJG04/ 8 | hyKuXMpx1WM0i943/M51k/X9XTuHgCOB/s191yBpNa6pHYgtuQGnzoMdHbRayggH 9 | 3i9x9jwEaf6RXFIuedRANzih+pVlDkXJftebE/YJwoOWes9SBPKqPOaGrC2A0Nqc 10 | s0iiZ/4oil3cXQYyzakwKQ9Mhb6M3Uw5OlfUCJXfAjsg5AIgrtYy//tXu3Cz+zIn 11 | tGvA3iWRIJfpCOziR3mMQc9GnFSeUHZCu/bFPCbc5yQ2Jy5Pm1y0coo/iPTEOw10 12 | RYXocr54lr854rtihHvKat5c/bkJQjpr8Mgy8qeVbAXzVtgRAgMBAAGjUzBRMB0G 13 | A1UdDgQWBBR9trLzkcB5I17ZGBeGhcjX8Ae5GTAfBgNVHSMEGDAWgBR9trLzkcB5 14 | I17ZGBeGhcjX8Ae5GTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IB 15 | AQCXmgQLziUsWh0jDX/LhqwQxIM2YZDm8+K60my9gnWFv9B6OEvj3gilB69B0tuP 16 | YaJcpWhhzO+/pE8vxOBGQz731M7Er3TGpTrmBD/5bj9NJ71u0FxYjVA8lwbaQced 17 | l8bskTBAAiEZTzEEfdBHcHJXvpzLcnRZ1uNin3EYyyfl5dsZyHfyHUtMiMqzuEFP 18 | 8gusgANC3s0to41mZ6S3YJB/TcVKarFAYBg7FYQbIn2+qQg6B6itcZ8FzquffPDO 19 | 7od/iwL7Chh/AkrGQcRlHPZTzsDlpat2+0zHBYAVYVbuQMNaCD3IRh80Ufi+DpxL 20 | osKY7Mkcwj1Nmoz4JPoL0wYI 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/OperatingSystemDependentFactAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Xunit; 3 | 4 | namespace k8s.Tests 5 | { 6 | public class OperatingSystemDependentFactAttribute : FactAttribute 7 | { 8 | public OperatingSystems Include { get; set; } = OperatingSystems.Linux | OperatingSystems.Windows | OperatingSystems.OSX; 9 | public OperatingSystems Exclude { get; set; } 10 | 11 | public override string Skip 12 | { 13 | get => IsOS(Include) && !IsOS(Exclude) ? null : "Not compatible with current OS"; 14 | set { } 15 | } 16 | 17 | private bool IsOS(OperatingSystems operatingSystems) 18 | { 19 | if (operatingSystems.HasFlag(OperatingSystems.Linux) && RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 20 | { 21 | return true; 22 | } 23 | 24 | if (operatingSystems.HasFlag(OperatingSystems.Windows) && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 25 | { 26 | return true; 27 | } 28 | 29 | if (operatingSystems.HasFlag(OperatingSystems.OSX) && RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 30 | { 31 | return true; 32 | } 33 | 34 | return false; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/ResourceQuantityJsonConverter.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | public sealed class ResourceQuantityJsonConverter : JsonConverter 4 | { 5 | // https://github.com/kubernetes/apimachinery/blob/4b14f804a0babdcc58e695d72f77ad29f536511e/pkg/api/resource/quantity.go#L683 6 | public override ResourceQuantity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 7 | { 8 | switch (reader.TokenType) 9 | { 10 | case JsonTokenType.Null: 11 | return null; 12 | case JsonTokenType.Number: 13 | if (reader.TryGetDouble(out var val)) 14 | { 15 | return Convert.ToString(val); 16 | } 17 | 18 | return reader.GetDecimal(); 19 | default: 20 | return reader.GetString(); 21 | } 22 | } 23 | 24 | public override void Write(Utf8JsonWriter writer, ResourceQuantity value, JsonSerializerOptions options) 25 | { 26 | if (writer == null) 27 | { 28 | throw new ArgumentNullException(nameof(writer)); 29 | } 30 | 31 | writer.WriteStringValue(value.ToString()); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/ResourceQuantityYamlConverter.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Core; 2 | using YamlDotNet.Serialization; 3 | 4 | namespace k8s.Models 5 | { 6 | public class ResourceQuantityYamlConverter : IYamlTypeConverter 7 | { 8 | public bool Accepts(Type type) 9 | { 10 | return type == typeof(ResourceQuantity); 11 | } 12 | 13 | public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) 14 | { 15 | if (parser?.Current is YamlDotNet.Core.Events.Scalar scalar) 16 | { 17 | try 18 | { 19 | if (string.IsNullOrEmpty(scalar?.Value)) 20 | { 21 | return null; 22 | } 23 | 24 | return scalar?.Value; 25 | } 26 | finally 27 | { 28 | parser?.MoveNext(); 29 | } 30 | } 31 | 32 | throw new InvalidOperationException(parser?.Current?.ToString()); 33 | } 34 | 35 | public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) 36 | { 37 | var obj = (ResourceQuantity)value; 38 | emitter?.Emit(new YamlDotNet.Core.Events.Scalar(obj?.ToString())); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/KubernetesClient.Kubectl/Beta/Kubectl.Patch.cs: -------------------------------------------------------------------------------- 1 | using k8s.Models; 2 | 3 | namespace k8s.kubectl.beta; 4 | 5 | public partial class Kubectl 6 | { 7 | /// 8 | /// Patch a cluster-scoped Kubernetes resource. 9 | /// 10 | /// The type of Kubernetes resource to patch. 11 | /// The patch to apply. 12 | /// The name of the resource. 13 | /// The patched resource. 14 | public T Patch(V1Patch patch, string name) 15 | where T : IKubernetesObject 16 | { 17 | return client.PatchAsync(patch, name).GetAwaiter().GetResult(); 18 | } 19 | 20 | /// 21 | /// Patch a namespaced Kubernetes resource. 22 | /// 23 | /// The type of Kubernetes resource to patch. 24 | /// The patch to apply. 25 | /// The namespace of the resource. 26 | /// The name of the resource. 27 | /// The patched resource. 28 | public T PatchNamespaced(V1Patch patch, string @namespace, string name) 29 | where T : IKubernetesObject 30 | { 31 | return client.PatchNamespacedAsync(patch, @namespace, name).GetAwaiter().GetResult(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/KubernetesClient/LeaderElection/ResourceLock/MetaObjectAnnotationLock.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.LeaderElection.ResourceLock 2 | { 3 | public abstract class MetaObjectAnnotationLock : MetaObjectLock 4 | where T : class, IMetadata, new() 5 | { 6 | protected MetaObjectAnnotationLock(IKubernetes client, string @namespace, string name, string identity) 7 | : base(client, @namespace, name, identity) 8 | { 9 | } 10 | 11 | private const string LeaderElectionRecordAnnotationKey = "control-plane.alpha.kubernetes.io/leader"; 12 | 13 | protected override LeaderElectionRecord GetLeaderElectionRecord(T obj) 14 | { 15 | var recordRawStringContent = obj.GetAnnotation(LeaderElectionRecordAnnotationKey); 16 | 17 | if (string.IsNullOrEmpty(recordRawStringContent)) 18 | { 19 | return new LeaderElectionRecord(); 20 | } 21 | 22 | var record = KubernetesJson.Deserialize(recordRawStringContent); 23 | return record; 24 | } 25 | 26 | 27 | protected override T SetLeaderElectionRecord(LeaderElectionRecord record, T metaObj) 28 | { 29 | metaObj.SetAnnotation(LeaderElectionRecordAnnotationKey, KubernetesJson.Serialize(record)); 30 | return metaObj; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/aks-kubelogin/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using System; 3 | using System.IO; 4 | using System.Text; 5 | 6 | var server = "https://example.hcp.eastus.azmk8s.io"; // the server url of your aks 7 | var clientid = "00000000-0000-0000-0000-000000000000"; // the client id of the your msi 8 | var kubelogin = @"C:\bin\kubelogin.exe"; // the path to the kubelogin.exe 9 | 10 | using var configstream = new MemoryStream(Encoding.ASCII.GetBytes($""" 11 | apiVersion: v1 12 | clusters: 13 | - cluster: 14 | insecure-skip-tls-verify: true 15 | server: {server} 16 | name: aks 17 | contexts: 18 | - context: 19 | cluster: aks 20 | user: msi 21 | name: aks 22 | current-context: aks 23 | kind: Config 24 | users: 25 | - name: msi 26 | user: 27 | exec: 28 | apiVersion: client.authentication.k8s.io/v1beta1 29 | args: 30 | - get-token 31 | - --login 32 | - msi 33 | - --server-id 34 | - 6dae42f8-4368-4678-94ff-3960e28e3630 35 | - --client-id 36 | - {clientid} 37 | command: {kubelogin} 38 | env: null 39 | """)); 40 | 41 | var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(configstream); 42 | IKubernetes client = new Kubernetes(config); 43 | Console.WriteLine("Starting Request!"); 44 | 45 | var list = client.CoreV1.ListNamespacedPod("default"); 46 | foreach (var item in list.Items) 47 | { 48 | Console.WriteLine(item.Metadata.Name); 49 | } 50 | -------------------------------------------------------------------------------- /src/KubernetesClient/KubeConfigModels/ContextDetails.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Represents a tuple of references to a cluster (how do I communicate with a kubernetes cluster), 7 | /// a user (how do I identify myself), and a namespace (what subset of resources do I want to work with) 8 | /// 9 | public class ContextDetails 10 | { 11 | /// 12 | /// Gets or sets the name of the cluster for this context. 13 | /// 14 | [YamlMember(Alias = "cluster")] 15 | public string Cluster { get; set; } 16 | 17 | /// 18 | /// Gets or sets the name of the user for this context. 19 | /// 20 | [YamlMember(Alias = "user")] 21 | public string User { get; set; } 22 | 23 | /// 24 | /// /Gets or sets the default namespace to use on unspecified requests. 25 | /// 26 | [YamlMember(Alias = "namespace")] 27 | public string Namespace { get; set; } 28 | 29 | /// 30 | /// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields. 31 | /// 32 | [YamlMember(Alias = "extensions")] 33 | public IEnumerable Extensions { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/ExternalExecutionTests.cs: -------------------------------------------------------------------------------- 1 | using k8s.KubeConfigModels; 2 | using System.Collections.Generic; 3 | using System.Text.Json; 4 | using Xunit; 5 | 6 | namespace k8s.Tests 7 | { 8 | public class ExternalExecutionTests 9 | { 10 | [Fact] 11 | public void CreateRunnableExternalProcess() 12 | { 13 | var actual = KubernetesClientConfiguration.CreateRunnableExternalProcess(new ExternalExecution 14 | { 15 | ApiVersion = "testingversion", 16 | Command = "command", 17 | Arguments = new List { "arg1", "arg2" }, 18 | EnvironmentVariables = new List> 19 | { new Dictionary { { "name", "testkey" }, { "value", "testvalue" } } }, 20 | }); 21 | 22 | var actualExecInfo = JsonSerializer.Deserialize>(actual.StartInfo.EnvironmentVariables["KUBERNETES_EXEC_INFO"]); 23 | Assert.Equal("testingversion", actualExecInfo["apiVersion"].ToString()); 24 | Assert.Equal("ExecCredentials", actualExecInfo["kind"].ToString()); 25 | 26 | Assert.Equal("command", actual.StartInfo.FileName); 27 | Assert.Equal("arg1 arg2", actual.StartInfo.Arguments); 28 | Assert.Equal("testvalue", actual.StartInfo.EnvironmentVariables["testkey"]); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/Mock/MockWebSocketBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Net.WebSockets; 5 | using System.Security.Cryptography.X509Certificates; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace k8s.Tests.Mock 10 | { 11 | public class MockWebSocketBuilder : WebSocketBuilder 12 | { 13 | public Dictionary RequestHeaders { get; } 14 | = new Dictionary(); 15 | 16 | public Collection Certificates { get; } 17 | = new Collection(); 18 | 19 | public Uri Uri { get; private set; } 20 | 21 | public WebSocket PublicWebSocket => this.WebSocket; 22 | 23 | public override WebSocketBuilder AddClientCertificate(X509Certificate2 certificate) 24 | { 25 | this.Certificates.Add(certificate); 26 | return this; 27 | } 28 | 29 | public override Task BuildAndConnectAsync(Uri uri, CancellationToken cancellationToken) 30 | { 31 | this.Uri 32 | = uri; 33 | 34 | return Task.FromResult(this.PublicWebSocket); 35 | } 36 | 37 | public override WebSocketBuilder SetRequestHeader(string headerName, string headerValue) 38 | { 39 | this.RequestHeaders.Add(headerName, headerValue); 40 | return this; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/ca-data.txt: -------------------------------------------------------------------------------- 1 | LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURERENDQWZTZ0F3SUJBZ0lSQUo5ZCtLeThkTDJVSzRjdXplMmo2WnN3RFFZSktvWklodmNOQVFFTEJRQXcKTHpFdE1Dc0dBMVVFQXhNa1lXRTBZVFV3T0RZdE0yVm1aaTAwWWpCa0xUbGxORGt0WmpNeVpXWXpabUpqWWpNNApNQjRYRFRFM01ESXlOakExTURRek5Gb1hEVEl5TURJeU5UQTFNRFF6TkZvd0x6RXRNQ3NHQTFVRUF4TWtZV0UwCllUVXdPRFl0TTJWbVppMDBZakJrTFRsbE5Ea3Raak15WldZelptSmpZak00TUlJQklqQU5CZ2txaGtpRzl3MEIKQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBM2dkandhdHNsdCsvQVpqV3hmbkNQeGZqMzNHUUxlOU00VU42VmEwRQpKd0FYL2R3L1ZVa0dvVjlDc3NKRUZMdEdTUnM2K2h0RTEvOUN3ak1USDh2WExKcURHTE9KdFQ5dW9sR2c2Q2k1ClBKNDNKelVLWmJlYVE4Z3hhZndzQjdQU05vTTJOYzROVm9lZzBVTUw0bndGeEhXeTNYWHlFZ0QxTWxTUnVrb3oKTTNoRUVxUjJNVFdrNm9KK3VJNFF4WVZWMnZuWXdXaEJwUDlDR3RWUTlyUW9MVFowcmFpOCtDYURBMVltTWRhbQpRYUVPdURlSFRqU2FYM2dyR0FBVVFWNWl6MC9qVVBuK3lJNm1iV0trbzFzNytPY1dZR2F1aDFaMzFYSjJsc0RTCnU4a3F0d215UEcyUVl2aUQ4YjNOWFAyY0dRK2EwZlpRZnBrbTF0U3IxQnhhaXdJREFRQUJveU13SVRBT0JnTlYKSFE4QkFmOEVCQU1DQWdRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQQpuVzFXVXlLbVJ0TlNzU1VzVFBSUnhFRzhhek9kdjdYeUhRL0R5VWNqWm9rUEJVVHY4VjdvNG96RHgyVHV6UEdYCmZ2YlMvT2g0VDd6ZlYxdjJadmU3dTBxelNiRTl5OGpsaDNxYXJEcEd5ZmlTamwycmhIOFBmay9sZGR0VFpVL04KSkVtYW5ReGl6R20xV2pCSklRSE5LZENneVIwN3A1c0MwNnR3K25YUytla1MxMlBUTG45WjBuRDBKVDdQSzRXQgpQc3ZXeDVXN0w5dnJIdVN5SGRSTkt5eEEvbWI1WHdXMDBkZUpmaHZub0p3ZWRYNDVKZVRiME5MczUzaURqVEU1CnRpdU03Z1RVSjlCcGZTL0gvYSt2SmovVWQ2bHM0QndrWmpUNHNhOTA1bnNzdnRqamlwZ1N5a0QzVkxCQ3VueTkKd1NnbE1vSnZNWmg0bC9FVFJPeFE3Zz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K 2 | -------------------------------------------------------------------------------- /examples/watch/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using System; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); 7 | 8 | IKubernetes client = new Kubernetes(config); 9 | 10 | var podlistResp = client.CoreV1.WatchListNamespacedPodAsync("default"); 11 | 12 | // C# 8 required https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8 13 | await foreach (var (type, item) in podlistResp.ConfigureAwait(false)) 14 | { 15 | Console.WriteLine("==on watch event=="); 16 | Console.WriteLine(type); 17 | Console.WriteLine(item.Metadata.Name); 18 | Console.WriteLine("==on watch event=="); 19 | } 20 | 21 | #pragma warning disable CS8321 // Remove unused private members 22 | void WatchUsingCallback(IKubernetes client) 23 | #pragma warning restore CS8321 // Remove unused private members 24 | { 25 | using (var podlistResp = client.CoreV1.WatchListNamespacedPod("default", onEvent: (type, item) => 26 | { 27 | Console.WriteLine("==on watch event=="); 28 | Console.WriteLine(type); 29 | Console.WriteLine(item.Metadata.Name); 30 | Console.WriteLine("==on watch event=="); 31 | })) 32 | { 33 | Console.WriteLine("press ctrl + c to stop watching"); 34 | 35 | var ctrlc = new ManualResetEventSlim(false); 36 | Console.CancelKeyPress += (sender, eventArgs) => ctrlc.Set(); 37 | ctrlc.Wait(); 38 | } 39 | } -------------------------------------------------------------------------------- /src/KubernetesClient/LeaderElection/ResourceLock/MultiLock.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.LeaderElection.ResourceLock 2 | { 3 | public class MultiLock : ILock 4 | { 5 | private readonly ILock primary; 6 | private readonly ILock secondary; 7 | 8 | public MultiLock(ILock primary, ILock secondary) 9 | { 10 | this.primary = primary; 11 | this.secondary = secondary; 12 | } 13 | 14 | public Task GetAsync(CancellationToken cancellationToken = default) 15 | { 16 | return primary.GetAsync(cancellationToken); 17 | } 18 | 19 | public async Task CreateAsync(LeaderElectionRecord record, CancellationToken cancellationToken = default) 20 | { 21 | return await primary.CreateAsync(record, cancellationToken).ConfigureAwait(false) 22 | && await secondary.CreateAsync(record, cancellationToken).ConfigureAwait(false); 23 | } 24 | 25 | public async Task UpdateAsync(LeaderElectionRecord record, CancellationToken cancellationToken = default) 26 | { 27 | return await primary.UpdateAsync(record, cancellationToken).ConfigureAwait(false) 28 | && await secondary.UpdateAsync(record, cancellationToken).ConfigureAwait(false); 29 | } 30 | 31 | public string Identity => primary.Identity; 32 | 33 | public string Describe() 34 | { 35 | return primary.Describe(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /.github/workflows/docfx.yaml: -------------------------------------------------------------------------------- 1 | name: Docfx 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | # Allows you to run this workflow manually from the Actions tab 8 | workflow_dispatch: 9 | 10 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 11 | permissions: 12 | contents: read 13 | pages: write 14 | id-token: write 15 | 16 | # Allow one concurrent deployment 17 | concurrency: 18 | group: "pages" 19 | cancel-in-progress: true 20 | 21 | jobs: 22 | docfx: 23 | runs-on: ubuntu-latest 24 | environment: 25 | name: github-pages 26 | url: ${{ steps.deployment.outputs.page_url }} 27 | steps: 28 | - uses: actions/checkout@v6 29 | with: 30 | fetch-depth: 0 31 | 32 | - name: Setup dotnet 33 | uses: actions/setup-dotnet@v5 34 | with: 35 | dotnet-version: | 36 | 8.0.x 37 | 9.0.x 38 | 10.0.x 39 | 40 | - name: Build 41 | run: dotnet build -c Release 42 | 43 | - uses: nunit/docfx-action@v4.1.0 44 | name: Build Documentation 45 | with: 46 | args: doc/docfx.json 47 | 48 | - name: Setup Pages 49 | uses: actions/configure-pages@v5 50 | - name: Upload artifact 51 | uses: actions/upload-pages-artifact@v4 52 | with: 53 | # Upload entire repository 54 | path: doc/_site 55 | - name: Deploy to GitHub Pages 56 | id: deployment 57 | uses: actions/deploy-pages@v4 58 | -------------------------------------------------------------------------------- /src/KubernetesClient/Authentication/ExecTokenProvider.cs: -------------------------------------------------------------------------------- 1 | using k8s.KubeConfigModels; 2 | using System.Net.Http.Headers; 3 | 4 | namespace k8s.Authentication 5 | { 6 | public class ExecTokenProvider : ITokenProvider 7 | { 8 | private readonly ExternalExecution exec; 9 | private ExecCredentialResponse response; 10 | 11 | public ExecTokenProvider(ExternalExecution exec) 12 | { 13 | this.exec = exec; 14 | } 15 | 16 | private bool NeedsRefresh() 17 | { 18 | if (response?.Status == null) 19 | { 20 | return true; 21 | } 22 | 23 | if (response.Status.ExpirationTimestamp == null) 24 | { 25 | return false; 26 | } 27 | 28 | return DateTime.UtcNow.AddSeconds(30) > response.Status.ExpirationTimestamp; 29 | } 30 | 31 | public async Task GetAuthenticationHeaderAsync(CancellationToken cancellationToken) 32 | { 33 | if (NeedsRefresh()) 34 | { 35 | await RefreshToken().ConfigureAwait(false); 36 | } 37 | 38 | return new AuthenticationHeaderValue("Bearer", response.Status.Token); 39 | } 40 | 41 | private async Task RefreshToken() 42 | { 43 | response = 44 | await Task.Run(() => KubernetesClientConfiguration.ExecuteExternalCommand(this.exec)).ConfigureAwait(false); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/KubernetesClient/IKubernetes.Exec.cs: -------------------------------------------------------------------------------- 1 | namespace k8s 2 | { 3 | public partial interface IKubernetes 4 | { 5 | /// 6 | /// Executes a command in a container in a pod. 7 | /// 8 | /// 9 | /// The name of the pod which contains the container in which to execute the command. 10 | /// 11 | /// 12 | /// The namespace of the container. 13 | /// 14 | /// 15 | /// The container in which to run the command. 16 | /// 17 | /// 18 | /// The command to execute. 19 | /// 20 | /// 21 | /// if allocate a pseudo-TTY 22 | /// 23 | /// 24 | /// A callback which processes the standard input, standard output and standard error. 25 | /// 26 | /// 27 | /// A which can be used to cancel the asynchronous operation. 28 | /// 29 | /// 30 | /// A which represents the asynchronous operation. 31 | /// 32 | Task NamespacedPodExecAsync(string name, string @namespace, string container, IEnumerable command, 33 | bool tty, ExecAsyncCallback action, CancellationToken cancellationToken); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/TaskAssert.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Xunit; 4 | 5 | namespace k8s.Tests 6 | { 7 | internal static class TaskAssert 8 | { 9 | public static void NotCompleted(Task task, string message = "Task should not be completed") 10 | { 11 | Assert.False(task.IsCompleted, message); 12 | } 13 | 14 | public static async Task Completed(Task task, TimeSpan timeout, string message = "Task timed out") 15 | { 16 | var timeoutTask = Task.Delay( 17 | TimeSpan.FromMilliseconds(1000)); 18 | 19 | var completedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false); 20 | Assert.True(ReferenceEquals(task, completedTask), message); 21 | 22 | await completedTask.ConfigureAwait(false); 23 | } 24 | 25 | public static async Task Completed(Task task, TimeSpan timeout, string message = "Task timed out") 26 | { 27 | var timeoutTask = Task.Delay(TimeSpan.FromMilliseconds(1000)).ContinueWith(completedTimeoutTask => default(T)); 28 | 29 | // Value is never returned, but we need a task of the same result type in order to use Task.WhenAny. 30 | 31 | var completedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false); 32 | Assert.True(ReferenceEquals(task, completedTask), message); 33 | 34 | return await completedTask.ConfigureAwait(false); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/KubernetesClient.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | k8s.Tests 5 | net8.0;net9.0;net10.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | runtime; build; native; contentfiles; analyzers; buildtransitive 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/customResource/Utils.cs: -------------------------------------------------------------------------------- 1 | using k8s.Models; 2 | using System.Collections.Generic; 3 | namespace customResource 4 | { 5 | public class Utils 6 | { 7 | // creats a CRD definition 8 | public static CustomResourceDefinition MakeCRD() 9 | { 10 | var myCRD = new CustomResourceDefinition() 11 | { 12 | Kind = "CResource", 13 | Group = "csharp.com", 14 | Version = "v1alpha1", 15 | PluralName = "customresources", 16 | }; 17 | 18 | return myCRD; 19 | } 20 | 21 | // creats a CR instance 22 | public static CResource MakeCResource() 23 | { 24 | var myCResource = new CResource() 25 | { 26 | Kind = "CResource", 27 | ApiVersion = "csharp.com/v1alpha1", 28 | Metadata = new V1ObjectMeta 29 | { 30 | Name = "cr-instance-london", 31 | NamespaceProperty = "default", 32 | Labels = new Dictionary 33 | { 34 | { 35 | "identifier", "city" 36 | }, 37 | }, 38 | }, 39 | // spec 40 | Spec = new CResourceSpec 41 | { 42 | CityName = "London", 43 | }, 44 | }; 45 | return myCResource; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/KubernetesClient/FileSystem.cs: -------------------------------------------------------------------------------- 1 | namespace k8s 2 | { 3 | internal static class FileSystem 4 | { 5 | public interface IFileSystem 6 | { 7 | Stream OpenRead(string path); 8 | 9 | bool Exists(string path); 10 | 11 | string ReadAllText(string path); 12 | } 13 | 14 | public static IFileSystem Current { get; private set; } = new RealFileSystem(); 15 | 16 | public static IDisposable With(IFileSystem fileSystem) 17 | { 18 | return new InjectedFileSystem(fileSystem); 19 | } 20 | 21 | private class InjectedFileSystem : IDisposable 22 | { 23 | private readonly IFileSystem _original; 24 | 25 | public InjectedFileSystem(IFileSystem fileSystem) 26 | { 27 | _original = Current; 28 | Current = fileSystem; 29 | } 30 | 31 | public void Dispose() 32 | { 33 | Current = _original; 34 | } 35 | } 36 | 37 | private class RealFileSystem : IFileSystem 38 | { 39 | public bool Exists(string path) 40 | { 41 | return File.Exists(path); 42 | } 43 | 44 | public Stream OpenRead(string path) 45 | { 46 | return File.OpenRead(path); 47 | } 48 | 49 | public string ReadAllText(string path) 50 | { 51 | return File.ReadAllText(path); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/KubernetesClient/KubeConfigModels/ExternalExecution.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | public class ExternalExecution 6 | { 7 | [YamlMember(Alias = "apiVersion")] 8 | public string ApiVersion { get; set; } 9 | 10 | /// 11 | /// The command to execute. Required. 12 | /// 13 | [YamlMember(Alias = "command")] 14 | public string Command { get; set; } 15 | 16 | /// 17 | /// Environment variables to set when executing the plugin. Optional. 18 | /// 19 | [YamlMember(Alias = "env")] 20 | public IList> EnvironmentVariables { get; set; } 21 | 22 | /// 23 | /// Arguments to pass when executing the plugin. Optional. 24 | /// 25 | [YamlMember(Alias = "args")] 26 | public IList Arguments { get; set; } 27 | 28 | /// 29 | /// Text shown to the user when the executable doesn't seem to be present. Optional. 30 | /// 31 | [YamlMember(Alias = "installHint")] 32 | public string InstallHint { get; set; } 33 | 34 | /// 35 | /// Whether or not to provide cluster information to this exec plugin as a part of 36 | /// the KUBERNETES_EXEC_INFO environment variable. Optional. 37 | /// 38 | [YamlMember(Alias = "provideClusterInfo")] 39 | public bool ProvideClusterInfo { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/V1Patch.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | [JsonConverter(typeof(V1PatchJsonConverter))] 4 | public record V1Patch 5 | { 6 | public enum PatchType 7 | { 8 | /// 9 | /// not set, this is not allowed 10 | /// 11 | Unknown, 12 | 13 | /// 14 | /// content type application/json-patch+json 15 | /// 16 | JsonPatch, 17 | 18 | /// 19 | /// content type application/merge-patch+json 20 | /// 21 | MergePatch, 22 | 23 | /// 24 | /// content type application/strategic-merge-patch+json 25 | /// 26 | StrategicMergePatch, 27 | 28 | /// 29 | /// content type application/apply-patch+yaml 30 | /// 31 | ApplyPatch, 32 | } 33 | 34 | [JsonPropertyName("content")] 35 | [JsonInclude] 36 | public object Content { get; private set; } 37 | 38 | public PatchType Type { get; private set; } 39 | 40 | public V1Patch(object body, PatchType type) 41 | { 42 | if (type == PatchType.Unknown) 43 | { 44 | throw new ArgumentException("patch type must be set", nameof(type)); 45 | } 46 | 47 | Content = body ?? throw new ArgumentNullException(nameof(body), "object must be set"); 48 | Type = type; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/webApiDependencyInjection/Controllers/ExampleDependencyInjectionOnConstructorController.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace webApiDependencyInjection.Controllers 5 | { 6 | [ApiController] 7 | [Route("[controller]")] 8 | public class ExampleDependencyInjectionOnConstructorController : ControllerBase 9 | { 10 | private readonly IKubernetes kubernetesClient; 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// Injects the Kubernetes client into the controller. 15 | /// 16 | /// The Kubernetes client to interact with the Kubernetes API. 17 | public ExampleDependencyInjectionOnConstructorController(IKubernetes kubernetesClient) 18 | { 19 | this.kubernetesClient = kubernetesClient; 20 | } 21 | 22 | /// 23 | /// Retrieves the names of all pods in the default namespace using the injected Kubernetes client. 24 | /// 25 | /// A collection of pod names in the default namespace. 26 | [HttpGet] 27 | public IEnumerable GetPods() 28 | { 29 | // Read the list of pods contained in the default namespace 30 | var podList = this.kubernetesClient.CoreV1.ListNamespacedPod("default"); 31 | 32 | // Return names of pods 33 | return podList.Items.Select(pod => pod.Metadata.Name); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/KubernetesClient/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace k8s 5 | { 6 | public static class Extensions 7 | { 8 | public static KubernetesEntityAttribute GetKubernetesTypeMetadata(this T obj) 9 | where T : IKubernetesObject 10 | => 11 | obj.GetType().GetKubernetesTypeMetadata(); 12 | public static KubernetesEntityAttribute GetKubernetesTypeMetadata(this Type currentType) 13 | { 14 | var attr = currentType.GetCustomAttribute(); 15 | if (attr == null) 16 | { 17 | throw new InvalidOperationException($"Custom resource must have {nameof(KubernetesEntityAttribute)} applied to it"); 18 | } 19 | 20 | return attr; 21 | } 22 | 23 | public static T Initialize(this T obj) 24 | where T : IKubernetesObject 25 | { 26 | var metadata = obj.GetKubernetesTypeMetadata(); 27 | obj.ApiVersion = !string.IsNullOrEmpty(metadata.Group) ? $"{metadata.Group}/{metadata.ApiVersion}" : metadata.ApiVersion; 28 | obj.Kind = metadata.Kind ?? obj.GetType().Name; 29 | if (obj is IMetadata withMetadata && withMetadata.Metadata == null) 30 | { 31 | withMetadata.Metadata = new V1ObjectMeta(); 32 | } 33 | 34 | return obj; 35 | } 36 | 37 | internal static bool IsValidKubernetesName(this string value) => !Regex.IsMatch(value, "^[a-z0-9-]+$"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/KubeConfigModels/ExternalExecution.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | [YamlSerializable] 6 | public class ExternalExecution 7 | { 8 | [YamlMember(Alias = "apiVersion")] 9 | public string ApiVersion { get; set; } 10 | 11 | /// 12 | /// The command to execute. Required. 13 | /// 14 | [YamlMember(Alias = "command")] 15 | public string Command { get; set; } 16 | 17 | /// 18 | /// Environment variables to set when executing the plugin. Optional. 19 | /// 20 | [YamlMember(Alias = "env")] 21 | public IList> EnvironmentVariables { get; set; } 22 | 23 | /// 24 | /// Arguments to pass when executing the plugin. Optional. 25 | /// 26 | [YamlMember(Alias = "args")] 27 | public IList Arguments { get; set; } 28 | 29 | /// 30 | /// Text shown to the user when the executable doesn't seem to be present. Optional. 31 | /// 32 | [YamlMember(Alias = "installHint")] 33 | public string InstallHint { get; set; } 34 | 35 | /// 36 | /// Whether or not to provide cluster information to this exec plugin as a part of 37 | /// the KUBERNETES_EXEC_INFO environment variable. Optional. 38 | /// 39 | [YamlMember(Alias = "provideClusterInfo")] 40 | public bool ProvideClusterInfo { get; set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/customResource/CustomResourceDefinition.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using k8s.Models; 3 | using System.Collections.Generic; 4 | using System.Text.Json.Serialization; 5 | 6 | [module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "CA1724:TypeNamesShouldNotMatchNamespaces", Justification = "This is just an example.")] 7 | [module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass", Justification = "This is just an example.")] 8 | 9 | namespace customResource 10 | { 11 | public class CustomResourceDefinition 12 | { 13 | public string Version { get; set; } 14 | 15 | public string Group { get; set; } 16 | 17 | public string PluralName { get; set; } 18 | 19 | public string Kind { get; set; } 20 | 21 | public string Namespace { get; set; } 22 | } 23 | 24 | public abstract class CustomResource : KubernetesObject, IMetadata 25 | { 26 | [JsonPropertyName("metadata")] 27 | public V1ObjectMeta Metadata { get; set; } 28 | } 29 | 30 | public abstract class CustomResource : CustomResource 31 | { 32 | [JsonPropertyName("spec")] 33 | public TSpec Spec { get; set; } 34 | 35 | [JsonPropertyName("status")] 36 | public TStatus Status { get; set; } 37 | } 38 | 39 | public class CustomResourceList : KubernetesObject 40 | where T : CustomResource 41 | { 42 | public V1ListMeta Metadata { get; set; } 43 | public List Items { get; set; } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /examples/customResource/README.md: -------------------------------------------------------------------------------- 1 | # Custom Resource Client Example 2 | 3 | This example demonstrates how to use the C# Kubernetes Client library to create, get and list custom resources. 4 | 5 | ## Pre-requisits 6 | 7 | Make sure your have added the library package 8 | 9 | ```shell 10 | dotnet add package KubernetesClient 11 | ``` 12 | 13 | ## Create Custom Resource Definition (CRD) 14 | 15 | Make sure the [CRD](./config/crd.yaml) is created, in order to create an instance of it after. 16 | 17 | ```shell 18 | kubectl create -f ./config/crd.yaml 19 | ``` 20 | 21 | You can test that the CRD is successfully added, by creating an [instance](./config/yaml-cr-instance.yaml) of it using kubectl: 22 | 23 | ```shell 24 | kubectl create -f ./config/yaml-cr-instance.yaml 25 | ``` 26 | 27 | ```shell 28 | kubectl get customresources.csharp.com 29 | ``` 30 | 31 | ## Execute the code 32 | 33 | The client uses the `BuildConfigFromConfigFile()` function. If the KUBECONFIG environment variable is set, then that path to the k8s config file will be used. 34 | 35 | `dotnet run` 36 | 37 | Expected output: 38 | 39 | ``` 40 | strating main()... 41 | working with CRD: customresources.csharp.com 42 | creating CR cr-instance-london 43 | CR list: 44 | - CR Item 0 = cr-instance-london 45 | - CR Item 1 = cr-instance-paris 46 | fetchedCR = cr-instance-london (Labels: {identifier : city, newKey : newValue}), Spec: London 47 | Deleted the CR 48 | ``` 49 | 50 | ## Under the hood 51 | 52 | For more details, you can look at the Generic client [implementation](https://github.com/kubernetes-client/csharp/blob/master/src/KubernetesClient/GenericClient.cs) 53 | 54 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/V1Status.ObjectView.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | public partial record V1Status 4 | { 5 | public sealed class V1StatusObjectViewConverter : JsonConverter 6 | { 7 | public override V1Status Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 8 | { 9 | using var doc = JsonDocument.ParseValue(ref reader); 10 | var ele = doc.RootElement.Clone(); 11 | 12 | try 13 | { 14 | #if NET8_0_OR_GREATER 15 | return JsonSerializer.Deserialize(ele, StatusSourceGenerationContext.Default.V1Status); 16 | #else 17 | return ele.Deserialize(); 18 | #endif 19 | } 20 | catch (JsonException) 21 | { 22 | // should be an object 23 | } 24 | 25 | return new V1Status { _original = ele, HasObject = true }; 26 | } 27 | 28 | public override void Write(Utf8JsonWriter writer, V1Status value, JsonSerializerOptions options) 29 | { 30 | throw new NotImplementedException(); // will not send v1status to server 31 | } 32 | } 33 | 34 | private JsonElement _original; 35 | 36 | public bool HasObject { get; private set; } 37 | 38 | public T ObjectView() 39 | { 40 | #if NET8_0_OR_GREATER 41 | return KubernetesJson.Deserialize(_original); 42 | #else 43 | return _original.Deserialize(); 44 | #endif 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Classic.Tests/KubernetesClient.Classic.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | k8s.Tests 5 | net8.0;net9.0;net10.0 6 | net8.0;net9.0;net10.0;net48 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | runtime; build; native; contentfiles; analyzers; buildtransitive 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for taking the time to join our community and start contributing! 4 | 5 | Please remember to read and observe the [Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). 6 | 7 | This project accepts contribution via github [pull requests](https://help.github.com/articles/about-pull-requests/). This document outlines the process to help get your contribution accepted. Please also read the [Kubernetes contributor guide](https://github.com/kubernetes/community/blob/master/contributors/guide/README.md) which provides detailed instructions on how to get your ideas and bug fixes seen and accepted. 8 | 9 | ## Sign the Contributor License Agreement 10 | We'd love to accept your patches! Before we can accept them you need to sign Cloud Native Computing Foundation (CNCF) [CLA](https://github.com/kubernetes/community/blob/master/CLA.md). 11 | 12 | ## Reporting an issue 13 | If you have any problem with the package or any suggestions, please file an [issue](https://github.com/kubernetes-client/csharp/issues). 14 | 15 | ## Contributing a Patch 16 | 1. Submit an issue describing your proposed change to the repo. 17 | 2. Fork this repo, develop and test your code changes. 18 | 3. Submit a pull request. 19 | 4. The bot will automatically assigns someone to review your PR. Check the full list of bot commands [here](https://prow.k8s.io/command-help). 20 | 21 | ### Contact 22 | You can reach the maintainers of this project at [SIG API Machinery](https://github.com/kubernetes/community/tree/master/sig-api-machinery) or on the [#kubernetes-client](https://kubernetes.slack.com/messages/kubernetes-client) channel on the Kubernetes slack. 23 | -------------------------------------------------------------------------------- /examples/workerServiceDependencyInjection/Worker.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | 3 | namespace workerServiceDependencyInjection 4 | { 5 | public class Worker : BackgroundService 6 | { 7 | private readonly ILogger logger; 8 | private readonly IKubernetes kubernetesClient; 9 | 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// Inject in the constructor the IKubernetes interface. 13 | /// 14 | /// The logger instance used for logging information. 15 | /// The Kubernetes client used to interact with the Kubernetes API. 16 | public Worker(ILogger logger, IKubernetes kubernetesClient) 17 | { 18 | this.logger = logger; 19 | this.kubernetesClient = kubernetesClient; 20 | } 21 | 22 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 23 | { 24 | while (!stoppingToken.IsCancellationRequested) 25 | { 26 | logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); 27 | 28 | // Read the list of pods contained in default namespace 29 | var podList = kubernetesClient.CoreV1.ListNamespacedPod("default"); 30 | 31 | // Print pods names 32 | foreach (var pod in podList.Items) 33 | { 34 | Console.WriteLine(pod.Metadata.Name); 35 | } 36 | 37 | await Task.Delay(1000, stoppingToken).ConfigureAwait(false); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/KubernetesClient/KubernetesObject.cs: -------------------------------------------------------------------------------- 1 | namespace k8s 2 | { 3 | /// 4 | /// Represents a generic Kubernetes object. 5 | /// 6 | /// 7 | /// You can use the if you receive JSON from a Kubernetes API server but 8 | /// are unsure which object the API server is about to return. You can parse the JSON as a 9 | /// and use the and properties to get basic metadata about any Kubernetes object. 10 | /// You can then 11 | /// 12 | public class KubernetesObject : IKubernetesObject 13 | { 14 | /// 15 | /// Gets or sets aPIVersion defines the versioned schema of this 16 | /// representation of an object. Servers should convert recognized 17 | /// schemas to the latest internal value, and may reject unrecognized 18 | /// values. More info: 19 | /// https://git.k8s.io/community/contributors/devel/api-conventions.md#resources 20 | /// 21 | [JsonPropertyName("apiVersion")] 22 | public string ApiVersion { get; set; } 23 | 24 | /// 25 | /// Gets or sets kind is a string value representing the REST resource 26 | /// this object represents. Servers may infer this from the endpoint 27 | /// the client submits requests to. Cannot be updated. In CamelCase. 28 | /// More info: 29 | /// https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds 30 | /// 31 | [JsonPropertyName("kind")] 32 | public string Kind { get; set; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/client-certificate-data.txt: -------------------------------------------------------------------------------- 1 | LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURrVENDQW5tZ0F3SUJBZ0lVTzlVTkdpbHhmSHpMbVJXcWU2dVMyRVZ1NVhVd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1FURUxNQWtHQTFVRUJoTUNWVk14RURBT0JnTlZCQWdUQjFKbFpHMXZibVF4Q3pBSkJnTlZCQWNUQWxkQgpNUk13RVFZRFZRUURFd3ByZFdKbGNtNWxkR1Z6TUNBWERURTRNVEl3T0RBNU5URXdNRm9ZRHpJeE1UZ3hNVEUwCk1EazFNVEF3V2pCQk1Rc3dDUVlEVlFRR0V3SlZVekVRTUE0R0ExVUVDQk1IVW1Wa2JXOXVaREVMTUFrR0ExVUUKQnhNQ1YwRXhFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQgpEd0F3Z2dFS0FvSUJBUUM4WkVRS296SE8zOExmRzRpcHFYWnRLTzNxSENjL1Z1WjUxWnZSeWJuTnpCYU5iMk9oClM0cU1nNDF6cFdzL3dMQnk4ZndPclpoOHpHb28wbHllQXVCSlBPWFc5SmswMmhOc1Y3ZHBqYXBZWFMrSXJvN04KcUxhWDB5amQxWWllSWFlb3NtV2xib2ZpcDVzS3dzVUI3bGREeXJpQklBYTEwNlhhTng5ZG82UEh1TDNibStldwpiaWRoRTlNUFRHY2V5WW9rZ3pNbGppanordk0yUnN5Z05ncmR4VDhROC9GRER2ZndTRmZUaEZlYXIzckQvRkJGCmVYb0Y5MHp6cG1aZlphTDlyZ2NjQ0pzQ2JSZlpiellVVERRVHo2dStaUVhUdGlrbVMvQ3d2d0hXa0w3bGhQNXYKQU0yVFpETEJhQXQwOU14dGlORFNWaFFTWVR2QWpKRmU4SzJoQWdNQkFBR2pmekI5TUE0R0ExVWREd0VCL3dRRQpBd0lGb0RBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUlLd1lCQlFVSEF3SXdEQVlEVlIwVEFRSC9CQUl3CkFEQWRCZ05WSFE0RUZnUVVuQmo0T3Y3MnFlWWJ5YjVYSHJma1pkazd6VUF3SHdZRFZSMGpCQmd3Rm9BVUxwemQKRlplYkR6N0RmZUNkZkJqNmNkUWJmNk13RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQU1CL1RDaElEbTNkeDA4SApJeXlFS2dYUHh1d3A1cTB5QkFoT0pUS1JOVXNpayt6ZVUyUGpibnV0M3B1WnBENkZoTGFKQUZPbTdsMHhkNU1ZCkFZOVloSy9wa1U3Rmw1TFg0MitxQzRqK05JdGhBbFM5clNtNkRvNlN1b3JRcjdNajErY0syTjFkZHBtRWZya3kKZXZnMm02aFB5YTFlV0hNanVCd250bkJmV2EzWHBWMWVGZVBvd21zY3R6UmRJYUh3WDM3Yit3c2JmbkppczRvTgo2bHk0THBQb2xtYld3ZTRnaEtPWXNuL3lMT3FrUGJMZVpLeU5yaWJpSGhSQTM0NUVHUGJleXNmSlNIWWFqMnBaCmE0VmRTRFhnT2JlM3Vtdk9keXVEaGl5RFJ3TFozbVJLWlpIR0lzZC9ORzRncWo3a0gzV2N2Wm5mSkVHMXY2cG0KQTZFYTJiRT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= -------------------------------------------------------------------------------- /.github/workflows/nuget.yaml: -------------------------------------------------------------------------------- 1 | name: Nuget 2 | 3 | on: 4 | release: 5 | types: [ released ] 6 | 7 | jobs: 8 | nuget: 9 | 10 | runs-on: windows-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v6 14 | with: 15 | fetch-depth: 0 16 | 17 | - name: Setup dotnet 18 | uses: actions/setup-dotnet@v5 19 | with: 20 | dotnet-version: | 21 | 8.0.x 22 | 9.0.x 23 | 10.0.x 24 | 25 | - name: dotnet restore 26 | run: dotnet restore --verbosity minimal --configfile nuget.config 27 | 28 | - name: dotnet test 29 | run: dotnet test 30 | 31 | - name: dotnet pack 32 | run: dotnet pack -c Release src/nuget.proj -o pkg --include-symbols 33 | 34 | - name: dotnet nuget push 35 | run: | 36 | dotnet nuget push pkg\*.nupkg -s https://nuget.pkg.github.com/$env:GITHUB_REPOSITORY_OWNER -k ${{ secrets.GITHUB_TOKEN }} --skip-duplicate 37 | dotnet nuget push pkg\*.nupkg -s https://www.nuget.org/ -k ${{ secrets.nuget_api_key }} --skip-duplicate 38 | 39 | 40 | ## Remove old versions of NuGet packages form github NuGet feed 41 | nuget-delete-old-packages: 42 | name: "Delete Old NuGet" 43 | needs: [nuget] 44 | strategy: 45 | matrix: 46 | nuget-package: 47 | - "KubernetesClient" 48 | - "KubernetesClient.Classic" 49 | runs-on: ubuntu-latest 50 | permissions: 51 | packages: write 52 | 53 | steps: 54 | - name: Delete old NuGet packages 55 | uses: actions/delete-package-versions@v5 56 | with: 57 | owner: ${{ env.GITHUB_REPOSITORY_OWNER }} 58 | token: ${{ secrets.GITHUB_TOKEN }} 59 | package-name: ${{ matrix.nuget-package }} 60 | package-type: nuget 61 | min-versions-to-keep: 10 62 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/assets/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDG8khxm/q6ls7T 3 | TKlKtTJgiPh6Gh7w1dCJG04/hyKuXMpx1WM0i943/M51k/X9XTuHgCOB/s191yBp 4 | Na6pHYgtuQGnzoMdHbRayggH3i9x9jwEaf6RXFIuedRANzih+pVlDkXJftebE/YJ 5 | woOWes9SBPKqPOaGrC2A0Nqcs0iiZ/4oil3cXQYyzakwKQ9Mhb6M3Uw5OlfUCJXf 6 | Ajsg5AIgrtYy//tXu3Cz+zIntGvA3iWRIJfpCOziR3mMQc9GnFSeUHZCu/bFPCbc 7 | 5yQ2Jy5Pm1y0coo/iPTEOw10RYXocr54lr854rtihHvKat5c/bkJQjpr8Mgy8qeV 8 | bAXzVtgRAgMBAAECggEASrptPcdyOa42CCaOnJJNVvd8JhkzsBEQYL/R94jiHQ6b 9 | uICH4A/9q5gZUQ7/4min2LDoJYc5VuB8uyg/8CQ4p7wLhCXNGB21RjkHJTVvKuZs 10 | Cthpl95OvEhk0q4rZqSCg1AGJLaxc/3eeDIJTXfZ8hwLrqhriwCXowBQbXXmfaHa 11 | YiOodBFs+B55si2NiO971wiz7jeFYYs/tEiT9wS6nvq0t2omSi7e8ryL103Lb1ge 12 | SAelzS4ZMCf/Xt+kYz+UeC51RlCshHt9sif0Jgst84EVqX5by2PzSUrQu6YPNLrn 13 | 3WulO6a7oqHYfF8wV4ARD89SNRyWcF/Xh+vjPg538QKBgQDx5W/x+F/Nt+f0tlDl 14 | ZeSoB/wWo2yQx0gK98R66M3qUtnoeWC+SSj15z1WPT+MfD+B2haytiFP1+uAveI/ 15 | hup1oJMddciTcLMfc13s7luXe+OLMCxCwJTrgaSZeD79dUKKzHv2yU4v01gJFlMq 16 | GnkAzUxolvb9sVzgFuCy7agHnQKBgQDSi8XxDoNhv9HAKHJDhQ1g3mmGIPPP4M72 17 | v8MxO5AXVCVcL3VFGj+7H6Z3CJuiE7diJVBSPMun/6q1xgMZNUe9EjIjCdmEKMOz 18 | Nm/5P6Dea1Gktd5gb6NB9GTpE3JqwxhxkM0VNv/k8rCp6+4Oz1d8uF+p6jPwNEC5 19 | Z9vlge/aBQKBgQCkv0nl9+5v8rAVF9Ky2hnIY1/Kn1VCqackaSk1OLd9vx3QWlKM 20 | ZtFx4SMCSEauzLSIINvSrX60nW80yJ59+8pVgJ6RsvV/jYNBiVZQFurkmikYVB/g 21 | +r6yQyKyr5XfE+zVEX3gT6xjoEJWNhFAHLWK2UgP97mSgSirKomw83G8dQKBgHWl 22 | fHlx7p/UG1QQRajM0+jo3nYAO7xQldTy2hLMgXtHnYihTBnMzQe2a8HfoXczJSlG 23 | SFdreTDqf20Ks/iF+QwA+trxSgW68X9WT8Mqdq1RslEi/ptMRiE4eppyL2DQmvv6 24 | OV49WUeJBIYuOtszqGMccvfy0grKZ9Ax5IGd1XQxAoGAW7DObS33nO9/arcEg+yK 25 | H0cOSP1h/8v4k4M4gorfuXfi6Xkegt5PaWUf7tJGDon5ArzZsCNRq5rdBMNtA4an 26 | NbMlanRzfBuBqHYo/X8OgqThhn8Uwg/oY778qHEH+WaJdSiNg5TboDPKUyEBNRKA 27 | suoE9MAZsAaIj4YP0RnMLk8= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /src/KubernetesClient/Autorest/HttpRequestMessageWrapper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. See License.txt in the project root for license information. 3 | 4 | using System.Net.Http; 5 | 6 | namespace k8s.Autorest 7 | { 8 | /// 9 | /// Wrapper around HttpRequestMessage type that copies properties of HttpRequestMessage so that 10 | /// they are available after the HttpClient gets disposed. 11 | /// 12 | public class HttpRequestMessageWrapper : HttpMessageWrapper 13 | { 14 | /// 15 | /// Initializes a new instance of the class from HttpRequestMessage. 16 | /// and content. 17 | /// 18 | #pragma warning disable SA1611 // Element parameters should be documented 19 | public HttpRequestMessageWrapper(HttpRequestMessage httpRequest, string content) 20 | #pragma warning restore SA1611 // Element parameters should be documented 21 | { 22 | if (httpRequest == null) 23 | { 24 | throw new ArgumentNullException("httpRequest"); 25 | } 26 | 27 | CopyHeaders(httpRequest.Headers); 28 | CopyHeaders(httpRequest.GetContentHeaders()); 29 | 30 | Content = content; 31 | Method = httpRequest.Method; 32 | RequestUri = httpRequest.RequestUri; 33 | } 34 | 35 | /// 36 | /// Gets or sets the HTTP method used by the HTTP request message. 37 | /// 38 | public HttpMethod Method { get; protected set; } 39 | 40 | /// 41 | /// Gets or sets the Uri used for the HTTP request. 42 | /// 43 | public Uri RequestUri { get; protected set; } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/KubernetesClient.Aot/KubeConfigModels/ClusterEndpoint.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace k8s.KubeConfigModels 4 | { 5 | /// 6 | /// Contains information about how to communicate with a kubernetes cluster 7 | /// 8 | [YamlSerializable] 9 | public class ClusterEndpoint 10 | { 11 | /// 12 | /// Gets or sets the path to a cert file for the certificate authority. 13 | /// 14 | [YamlMember(Alias = "certificate-authority", ApplyNamingConventions = false)] 15 | public string CertificateAuthority { get; set; } 16 | 17 | /// 18 | /// Gets or sets =PEM-encoded certificate authority certificates. Overrides . 19 | /// 20 | [YamlMember(Alias = "certificate-authority-data", ApplyNamingConventions = false)] 21 | public string CertificateAuthorityData { get; set; } 22 | 23 | /// 24 | /// Gets or sets the address of the kubernetes cluster (https://hostname:port). 25 | /// 26 | [YamlMember(Alias = "server")] 27 | public string Server { get; set; } 28 | 29 | /// 30 | /// Gets or sets a value to override the TLS server name. 31 | /// 32 | [YamlMember(Alias = "tls-server-name", ApplyNamingConventions = false)] 33 | public string TlsServerName { get; set; } 34 | 35 | /// 36 | /// Gets or sets a value indicating whether to skip the validity check for the server's certificate. 37 | /// This will make your HTTPS connections insecure. 38 | /// 39 | [YamlMember(Alias = "insecure-skip-tls-verify", ApplyNamingConventions = false)] 40 | public bool SkipTlsVerify { get; set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/KubernetesClient/ChannelIndex.cs: -------------------------------------------------------------------------------- 1 | namespace k8s 2 | { 3 | /// 4 | /// These values identify the various channels which you can use when interacting with a process running in a container in a Kubernetes 5 | /// pod. 6 | /// 7 | /// 8 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1028:Enum Storage should be Int32", Justification = "byte only")] 9 | public enum ChannelIndex : byte 10 | { 11 | /// 12 | /// The standard input channel. Use this channel to send input to a process running in a container inside a Kubernetes pod. 13 | /// 14 | StdIn, 15 | 16 | /// 17 | /// The standard output channel. Use this channel to read standard output generated by a process running in a container in a Kubernetes pod. 18 | /// 19 | StdOut, 20 | 21 | /// 22 | /// The standard error channel. Use this channel to read the error output generated by a process running in a container in a Kubernetes pod. 23 | /// 24 | StdErr, 25 | 26 | /// 27 | /// The error channel. This channel is used by Kubernetes to send you error messages, including the exit code of the process. 28 | /// 29 | Error, 30 | 31 | /// 32 | /// The resize channel. Use this channel to resize the terminal. You need to send a JSON-formatted object over this channel, which 33 | /// has a Width and Height property. 34 | /// 35 | /// 36 | Resize, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/KubernetesClient/Models/KubernetesList.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.Models 2 | { 3 | public class KubernetesList : IMetadata, IItems 4 | where T : IKubernetesObject 5 | { 6 | public KubernetesList(IList items, string apiVersion = default, string kind = default, 7 | V1ListMeta metadata = default) 8 | { 9 | ApiVersion = apiVersion; 10 | Items = items; 11 | Kind = kind; 12 | Metadata = metadata; 13 | } 14 | 15 | /// 16 | /// Gets or sets aPIVersion defines the versioned schema of this 17 | /// representation of an object. Servers should convert recognized 18 | /// schemas to the latest internal value, and may reject unrecognized 19 | /// values. More info: 20 | /// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 21 | /// 22 | [JsonPropertyName("apiVersion")] 23 | public string ApiVersion { get; set; } 24 | 25 | [JsonPropertyName("items")] 26 | public IList Items { get; set; } 27 | 28 | /// 29 | /// Gets or sets kind is a string value representing the REST resource 30 | /// this object represents. Servers may infer this from the endpoint 31 | /// the client submits requests to. Cannot be updated. In CamelCase. 32 | /// More info: 33 | /// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 34 | /// 35 | [JsonPropertyName("kind")] 36 | public string Kind { get; set; } 37 | 38 | /// 39 | /// Gets or sets standard object's metadata. 40 | /// 41 | [JsonPropertyName("metadata")] 42 | public V1ListMeta Metadata { get; set; } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/KubernetesClient/LeaderElection/ResourceLock/EndpointsLock.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.LeaderElection.ResourceLock 2 | { 3 | public class EndpointsLock : MetaObjectAnnotationLock 4 | { 5 | public EndpointsLock(IKubernetes client, string @namespace, string name, string identity) 6 | : base(client, @namespace, name, identity) 7 | { 8 | } 9 | 10 | protected override Task ReadMetaObjectAsync(IKubernetes client, string name, string namespaceParameter, CancellationToken cancellationToken) 11 | { 12 | if (client is null) 13 | { 14 | throw new ArgumentNullException(nameof(client)); 15 | } 16 | 17 | return client.CoreV1.ReadNamespacedEndpointsAsync(name, namespaceParameter, cancellationToken: cancellationToken); 18 | } 19 | 20 | protected override Task CreateMetaObjectAsync(IKubernetes client, V1Endpoints obj, string namespaceParameter, 21 | CancellationToken cancellationToken) 22 | { 23 | if (client is null) 24 | { 25 | throw new ArgumentNullException(nameof(client)); 26 | } 27 | 28 | return client.CoreV1.CreateNamespacedEndpointsAsync(obj, namespaceParameter, cancellationToken: cancellationToken); 29 | } 30 | 31 | protected override Task ReplaceMetaObjectAsync(IKubernetes client, V1Endpoints obj, string name, string namespaceParameter, 32 | CancellationToken cancellationToken) 33 | { 34 | if (client is null) 35 | { 36 | throw new ArgumentNullException(nameof(client)); 37 | } 38 | 39 | return client.CoreV1.ReplaceNamespacedEndpointsAsync(obj, name, namespaceParameter, cancellationToken: cancellationToken); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/resize/Program.cs: -------------------------------------------------------------------------------- 1 | using k8s; 2 | using k8s.Models; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | 7 | var config = KubernetesClientConfiguration.BuildDefaultConfig(); 8 | var client = new Kubernetes(config); 9 | 10 | 11 | var pod = new V1Pod 12 | { 13 | Metadata = new V1ObjectMeta { Name = "nginx-pod" }, 14 | Spec = new V1PodSpec 15 | { 16 | Containers = 17 | [ 18 | new V1Container 19 | { 20 | Name = "nginx", 21 | Image = "nginx", 22 | Resources = new V1ResourceRequirements 23 | { 24 | Requests = new Dictionary() 25 | { 26 | ["cpu"] = "100m", 27 | }, 28 | }, 29 | }, 30 | ], 31 | }, 32 | }; 33 | { 34 | var created = await client.CoreV1.CreateNamespacedPodAsync(pod, "default").ConfigureAwait(false); 35 | Console.WriteLine($"Created pod: {created.Metadata.Name}"); 36 | } 37 | 38 | { 39 | var patchStr = @" 40 | { 41 | ""spec"": { 42 | ""containers"": [ 43 | { 44 | ""name"": ""nginx"", 45 | ""resources"": { 46 | ""requests"": { 47 | ""cpu"": ""200m"" 48 | } 49 | } 50 | } 51 | ] 52 | } 53 | }"; 54 | 55 | var patch = await client.CoreV1.PatchNamespacedPodResizeAsync(new V1Patch(patchStr, V1Patch.PatchType.MergePatch), "nginx-pod", "default").ConfigureAwait(false); 56 | 57 | if (patch?.Spec?.Containers?.Count > 0 && 58 | patch.Spec.Containers[0].Resources?.Requests != null && 59 | patch.Spec.Containers[0].Resources.Requests.TryGetValue("cpu", out var cpuQty)) 60 | { 61 | Console.WriteLine($"CPU request: {cpuQty}"); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/KubernetesClient/Autorest/HttpResponseMessageWrapper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. See License.txt in the project root for license information. 3 | 4 | using System.Net; 5 | using System.Net.Http; 6 | 7 | namespace k8s.Autorest 8 | { 9 | /// 10 | /// Wrapper around HttpResponseMessage type that copies properties of HttpResponseMessage so that 11 | /// they are available after the HttpClient gets disposed. 12 | /// 13 | public class HttpResponseMessageWrapper : HttpMessageWrapper 14 | { 15 | /// 16 | /// Initializes a new instance of the class from HttpResponseMessage. 17 | /// and content. 18 | /// 19 | #pragma warning disable SA1611 // Element parameters should be documented 20 | public HttpResponseMessageWrapper(HttpResponseMessage httpResponse, string content) 21 | #pragma warning restore SA1611 // Element parameters should be documented 22 | { 23 | if (httpResponse == null) 24 | { 25 | throw new ArgumentNullException("httpResponse"); 26 | } 27 | 28 | CopyHeaders(httpResponse.Headers); 29 | CopyHeaders(httpResponse.GetContentHeaders()); 30 | 31 | Content = content; 32 | StatusCode = httpResponse.StatusCode; 33 | ReasonPhrase = httpResponse.ReasonPhrase; 34 | } 35 | 36 | /// 37 | /// Gets or sets the status code of the HTTP response. 38 | /// 39 | public HttpStatusCode StatusCode { get; protected set; } 40 | 41 | /// 42 | /// Exposes the reason phrase, typically sent along with the status code. 43 | /// 44 | public string ReasonPhrase { get; protected set; } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/KubernetesClient.Tests/Mock/Server/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using System; 5 | 6 | namespace k8s.Tests.Mock.Server 7 | { 8 | /// 9 | /// Startup logic for the KubeClient WebSockets test server. 10 | /// 11 | public class Startup 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// Create a new . 16 | /// 17 | public Startup() 18 | { 19 | } 20 | 21 | /// 22 | /// Configure application services. 23 | /// 24 | /// 25 | /// The service collection to configure. 26 | /// 27 | public static void ConfigureServices(IServiceCollection services) 28 | { 29 | if (services == null) 30 | { 31 | throw new ArgumentNullException(nameof(services)); 32 | } 33 | 34 | services.AddLogging(logging => 35 | { 36 | logging.ClearProviders(); // Logger provider will be added by the calling test. 37 | }); 38 | services.AddMvc(opt => opt.EnableEndpointRouting = false); 39 | } 40 | 41 | /// 42 | /// Configure the application pipeline. 43 | /// 44 | /// 45 | /// The application pipeline builder. 46 | /// 47 | public static void Configure(IApplicationBuilder app) 48 | { 49 | app.UseWebSockets(new WebSocketOptions 50 | { 51 | KeepAliveInterval = TimeSpan.FromSeconds(5), 52 | }); 53 | app.UseMvc(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/KubernetesClient/Authentication/StringTokenProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. See License.txt in the project root for license information. 3 | 4 | using System.Net.Http.Headers; 5 | 6 | namespace k8s.Authentication 7 | { 8 | /// 9 | /// A simple token provider that always provides a static access token. 10 | /// 11 | public sealed class StringTokenProvider : ITokenProvider 12 | { 13 | private readonly string _accessToken; 14 | private readonly string _type; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// Create a token provider for the given token type that returns the given 19 | /// access token. 20 | /// 21 | /// The access token to return. 22 | /// The token type of the given access token. 23 | public StringTokenProvider(string accessToken, string tokenType) 24 | { 25 | _accessToken = accessToken; 26 | _type = tokenType; 27 | } 28 | 29 | /// 30 | /// Gets the token type of this access token. 31 | /// 32 | public string TokenType => _type; 33 | 34 | /// 35 | /// Returns the static access token. 36 | /// 37 | /// The cancellation token for this action. 38 | /// This will not be used since the returned token is static. 39 | /// The access token. 40 | public Task GetAuthenticationHeaderAsync(CancellationToken cancellationToken) 41 | { 42 | return Task.FromResult(new AuthenticationHeaderValue(_type, _accessToken)); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/KubernetesClient/LeaderElection/ResourceLock/ConfigMapLock.cs: -------------------------------------------------------------------------------- 1 | namespace k8s.LeaderElection.ResourceLock 2 | { 3 | public class ConfigMapLock : MetaObjectAnnotationLock 4 | { 5 | public ConfigMapLock(IKubernetes client, string @namespace, string name, string identity) 6 | : base(client, @namespace, name, identity) 7 | { 8 | } 9 | 10 | protected override Task ReadMetaObjectAsync(IKubernetes client, string name, 11 | string namespaceParameter, 12 | CancellationToken cancellationToken) 13 | { 14 | if (client is null) 15 | { 16 | throw new ArgumentNullException(nameof(client)); 17 | } 18 | 19 | return client.CoreV1.ReadNamespacedConfigMapAsync(name, namespaceParameter, cancellationToken: cancellationToken); 20 | } 21 | 22 | protected override Task CreateMetaObjectAsync(IKubernetes client, V1ConfigMap obj, 23 | string namespaceParameter, 24 | CancellationToken cancellationToken) 25 | { 26 | if (client is null) 27 | { 28 | throw new ArgumentNullException(nameof(client)); 29 | } 30 | 31 | return client.CoreV1.CreateNamespacedConfigMapAsync(obj, namespaceParameter, cancellationToken: cancellationToken); 32 | } 33 | 34 | protected override Task ReplaceMetaObjectAsync(IKubernetes client, V1ConfigMap obj, string name, 35 | string namespaceParameter, 36 | CancellationToken cancellationToken) 37 | { 38 | if (client is null) 39 | { 40 | throw new ArgumentNullException(nameof(client)); 41 | } 42 | 43 | return client.CoreV1.ReplaceNamespacedConfigMapAsync(obj, name, namespaceParameter, cancellationToken: cancellationToken); 44 | } 45 | } 46 | } 47 | --------------------------------------------------------------------------------