diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 000000000..1326700af
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,3 @@
+{
+ "image": "mcr.microsoft.com/dotnet/sdk:8.0"
+}
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 000000000..841fcae61
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,37 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**Kubernetes C# SDK Client Version**
+e.g. `9.0.1`
+
+**Server Kubernetes Version**
+e.g. `1.22.3`
+
+**Dotnet Runtime Version**
+e.g. net6
+
+**To Reproduce**
+Steps to reproduce the behavior:
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**KubeConfig**
+If applicable, add a KubeConfig file with secrets redacted.
+
+**Where do you run your app with Kubernetes SDK (please complete the following information):**
+ - OS: [e.g. Linux]
+ - Environment [e.g. container]
+ - Cloud [e.g. Azure]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/workflows/buildtest.yaml b/.github/workflows/buildtest.yaml
index c0a114796..26d585ec7 100644
--- a/.github/workflows/buildtest.yaml
+++ b/.github/workflows/buildtest.yaml
@@ -8,63 +8,82 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest]
name: Dotnet build
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v5
with:
fetch-depth: 0
- - name: Setup dotnet SDK 3.1
- uses: actions/setup-dotnet@v2
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v5
with:
- dotnet-version: '3.1.x'
- - name: Setup dotnet SDK 5
- uses: actions/setup-dotnet@v2
- with:
- dotnet-version: '5.0.x'
- - name: Setup dotnet SDK 6
- uses: actions/setup-dotnet@v2
- with:
- dotnet-version: '6.0.x'
- # - name: Check Format
- # # don't check formatting on Windows b/c of CRLF issues.
- # if: matrix.os == 'ubuntu-latest'
- # run: dotnet format --severity error --verify-no-changes --exclude ./src/KubernetesClient/generated/
+ dotnet-version: |
+ 8.0.x
+ 9.0.x
- name: Build
- run: dotnet build --configuration Release -v detailed
+ run: dotnet build --configuration Release
- name: Test
- run: dotnet test /p:CollectCoverage=true /p:ExcludeByFile=\"**/KubernetesClient/generated/**/*.cs\" /p:CoverletOutputFormat="cobertura"
- # - uses: 5monkeys/cobertura-action@master
- # with:
- # path: tests/KubernetesClient.Tests/coverage.netcoreapp2.1.cobertura.xml
- # repo_token: ${{ secrets.GITHUB_TOKEN }}
- # minimum_coverage: 0
- e2e:
- runs-on: ubuntu-latest
+ run: dotnet test --configuration Release --collect:"Code Coverage;Format=Cobertura" --logger trx --results-directory TestResults --settings CodeCoverage.runsettings --no-build
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v5
+ with:
+ directory: ./TestResults
+ files: '*.cobertura.xml'
+ - name: Upload test results
+ uses: actions/upload-artifact@v5
+ with:
+ name: test-results-${{ matrix.os }}
+ path: ./TestResults
+ if: ${{ always() }} # Always run this step even on failure
+
+ # Test code gen for visual studio compatibility >> https://github.com/kubernetes-client/csharp/pull/1008
+ codgen:
+ runs-on: windows-latest
+ name: MSBuild build
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v5
with:
fetch-depth: 0
- - name: Setup dotnet SDK 3.1
- uses: actions/setup-dotnet@v2
+ - name: Add msbuild to PATH
+ uses: microsoft/setup-msbuild@v2
+ - name: Setup dotnet SDK
+ uses: actions/setup-dotnet@v5
with:
- dotnet-version: '3.1.x'
- - name: Setup dotnet SDK 5
- uses: actions/setup-dotnet@v2
+ dotnet-version: '9.0.x'
+ - name: Restore nugets (msbuild)
+ run: msbuild .\src\KubernetesClient\ -t:restore -p:RestorePackagesConfig=true
+ - name: Build (msbuild)
+ run: msbuild .\src\KubernetesClient\
+
+ e2e:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v5
with:
- dotnet-version: '5.0.x'
- - name: Setup dotnet SDK 6
- uses: actions/setup-dotnet@v2
+ fetch-depth: 0
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v5
with:
- dotnet-version: '6.0.x'
+ dotnet-version: |
+ 8.0.x
+ 9.0.x
- name: Minikube
run: minikube start
- name: Test
run: |
true > skip.log
- env K8S_E2E_MINIKUBE=1 dotnet test tests/E2E.Tests --logger "SkipTestLogger;file=$PWD/skip.log"
+ env K8S_E2E_MINIKUBE=1 dotnet test tests/E2E.Tests --logger "SkipTestLogger;file=$PWD/skip.log" -p:BuildInParallel=false
+ if [ -s skip.log ]; then
+ cat skip.log
+ echo "CASES MUST NOT BE SKIPPED"
+ exit 1
+ fi
+ - name: AOT Test
+ run: |
+ true > skip.log
+ env K8S_E2E_MINIKUBE=1 dotnet test tests/E2E.Aot.Tests --logger "SkipTestLogger;file=$PWD/skip.log" -p:BuildInParallel=false
if [ -s skip.log ]; then
cat skip.log
echo "CASES MUST NOT BE SKIPPED"
exit 1
- fi
+ fi
on:
pull_request:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 94566421d..6355396eb 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -1,5 +1,10 @@
name: "CodeQL"
+permissions:
+ actions: read
+ contents: read
+ security-events: write
+
on:
push:
branches: [ master ]
@@ -12,7 +17,7 @@ on:
jobs:
analyze:
name: Analyze
- runs-on: windows-2019
+ runs-on: windows-2022
strategy:
fail-fast: false
@@ -21,26 +26,20 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v5
with:
fetch-depth: 0
- - name: Setup dotnet SDK 3.1
- uses: actions/setup-dotnet@v2
- with:
- dotnet-version: '3.1.x'
- - name: Setup dotnet SDK 5
- uses: actions/setup-dotnet@v2
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v5
with:
- dotnet-version: '5.0.x'
- - name: Setup dotnet SDK 6
- uses: actions/setup-dotnet@v2
- with:
- dotnet-version: '6.0.x'
+ dotnet-version: |
+ 8.0.x
+ 9.0.x
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -48,8 +47,16 @@ jobs:
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- - name: Autobuild
- uses: github/codeql-action/autobuild@v2
+ # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ # Currently .NET8.0 isn't supported
+ # - name: Autobuild
+ # uses: github/codeql-action/autobuild@v2
+
+ - name: Restore dependencies
+ run: dotnet restore
+ - name: Build
+ run: dotnet build --configuration Debug --no-restore
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v4
diff --git a/.github/workflows/docfx.yaml b/.github/workflows/docfx.yaml
new file mode 100644
index 000000000..3eec06ec3
--- /dev/null
+++ b/.github/workflows/docfx.yaml
@@ -0,0 +1,56 @@
+name: Docfx
+
+on:
+ push:
+ branches: [ master ]
+
+ # Allows you to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+# Allow one concurrent deployment
+concurrency:
+ group: "pages"
+ cancel-in-progress: true
+
+jobs:
+ docfx:
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - uses: actions/checkout@v5
+ with:
+ fetch-depth: 0
+
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v5
+ with:
+ dotnet-version: |
+ 8.0.x
+ 9.0.x
+
+ - name: Build
+ run: dotnet build -c Release
+
+ - uses: nunit/docfx-action@v4.1.0
+ name: Build Documentation
+ with:
+ args: doc/docfx.json
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v5
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v4
+ with:
+ # Upload entire repository
+ path: doc/_site
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/draft.yaml b/.github/workflows/draft.yaml
index 1a143fe0f..01b098518 100644
--- a/.github/workflows/draft.yaml
+++ b/.github/workflows/draft.yaml
@@ -1,5 +1,8 @@
name: Draft Release
+permissions:
+ contents: write
+
on:
push:
branches: [ master ]
@@ -10,24 +13,16 @@ jobs:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v5
with:
fetch-depth: 0
- - name: .NET Core 3.1.x SDK
- uses: actions/setup-dotnet@v2
- with:
- dotnet-version: 3.1.x
-
- - name: .NET 5.x SDK
- uses: actions/setup-dotnet@v2
- with:
- dotnet-version: 5.0.x
-
- - name: .NET 6.x SDK
- uses: actions/setup-dotnet@v2
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v5
with:
- dotnet-version: 6.0.x
+ dotnet-version: |
+ 8.0.x
+ 9.0.x
- name: dotnet restore
run: dotnet restore --verbosity minimal --configfile nuget.config
@@ -44,4 +39,4 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- gh release create -d --generate-notes v$env:NBGV_NuGetPackageVersion
\ No newline at end of file
+ gh release create -d --generate-notes v$env:NBGV_NuGetPackageVersion
diff --git a/.github/workflows/nuget.yaml b/.github/workflows/nuget.yaml
index a39cd63e4..fa654822f 100644
--- a/.github/workflows/nuget.yaml
+++ b/.github/workflows/nuget.yaml
@@ -10,24 +10,16 @@ jobs:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v5
with:
fetch-depth: 0
- - name: .NET Core 3.1.x SDK
- uses: actions/setup-dotnet@v2
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v5
with:
- dotnet-version: 3.1.x
-
- - name: .NET 5.x SDK
- uses: actions/setup-dotnet@v2
- with:
- dotnet-version: 5.0.x
-
- - name: .NET 6.x SDK
- uses: actions/setup-dotnet@v2
- with:
- dotnet-version: 6.0.x
+ dotnet-version: |
+ 8.0.x
+ 9.0.x
- name: dotnet restore
run: dotnet restore --verbosity minimal --configfile nuget.config
@@ -52,17 +44,17 @@ jobs:
matrix:
nuget-package:
- "KubernetesClient"
- - "KubernetesClient.Models"
- - "KubernetesClient.Basic"
- "KubernetesClient.Classic"
runs-on: ubuntu-latest
+ permissions:
+ packages: write
steps:
- name: Delete old NuGet packages
- uses: actions/delete-package-versions@v3
+ uses: actions/delete-package-versions@v5
with:
owner: ${{ env.GITHUB_REPOSITORY_OWNER }}
- repo: ${{ github.event.repository.name }}
token: ${{ secrets.GITHUB_TOKEN }}
package-name: ${{ matrix.nuget-package }}
+ package-type: nuget
min-versions-to-keep: 10
diff --git a/.gitignore b/.gitignore
index d24a2eae2..46bc886d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,4 +15,6 @@ bin/
*.sln.iml
launchSettings.json
-*.DotSettings
\ No newline at end of file
+*.DotSettings
+
+*.sln
\ No newline at end of file
diff --git a/CodeCoverage.runsettings b/CodeCoverage.runsettings
new file mode 100644
index 000000000..acc025c10
--- /dev/null
+++ b/CodeCoverage.runsettings
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+ .*KubernetesClient\..*\.dll$
+
+
+ .*tests\.dll$
+ .*xunit.*dll$
+ .*moq\.dll$
+ .*System\.Reactive\.dll$
+ .*BouncyCastle\.Crypto\.dll$
+ .*IdentityModel\.OidcClient\.dll$
+
+
+
+ True
+
+ True
+
+ True
+
+
+ ^System.ObsoleteAttribute$
+ ^System.CodeDom.Compiler.GeneratedCodeAttribute$
+ ^System.Diagnostics.DebuggerHiddenAttribute$
+ ^System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute$
+
+
+
+
+
+
+
+
diff --git a/Directory.Build.props b/Directory.Build.props
index 6af780d70..3d3e1cfce 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,4 +1,4 @@
-
+
$(MSBuildThisFileDirectory)\kubernetes-client.ruleset
@@ -26,7 +26,7 @@
snupkg
true
$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
- 10.0
+ 13.0
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 001ec93f7..517121e49 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -1,12 +1,5 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 000000000..27783a77c
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,54 @@
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 3a060c888..c8eb91626 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,23 @@
# Kubernetes C# Client
-[](https://travis-ci.org/kubernetes-client/csharp)
+
+[](https://github.com/kubernetes-client/csharp/actions/workflows/buildtest.yaml)
[](http://bit.ly/kubernetes-client-capabilities-badge)
[](http://bit.ly/kubernetes-client-support-badge)
# Usage
-[Nuget Package](https://www.nuget.org/packages/KubernetesClient/)
+
+[](https://www.nuget.org/packages/KubernetesClient/)
```sh
dotnet add package KubernetesClient
```
+## Generate with Visual Studio
+
+```
+dotnet msbuild /Restore /t:SlnGen kubernetes-client.proj
+```
+
## Authentication/Configuration
You should be able to use a standard KubeConfig file with this library,
see the `BuildConfigFromConfigFile` function below. Most authentication
@@ -20,14 +28,11 @@ You should also be able to authenticate with the in-cluster service
account using the `InClusterConfig` function shown below.
## Monitoring
-There is optional built-in metric generation for prometheus client metrics.
-The exported metrics are:
-
-* `k8s_dotnet_request_total` - Counter of request, broken down by HTTP Method
-* `k8s_dotnet_response_code_total` - Counter of responses, broken down by HTTP Method and response code
-* `k8s_request_latency_seconds` - Latency histograms broken down by method, api group, api version and resource kind
+Metrics are built in to HttpClient using System.Diagnostics.DiagnosticsSource.
+https://learn.microsoft.com/en-us/dotnet/core/diagnostics/built-in-metrics-system-net
-There is an example integrating these monitors in the examples/prometheus directory.
+There are many ways these metrics can be consumed/exposed but that decision is up to the application, not KubernetesClient itself.
+https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-collection
## Sample Code
@@ -96,7 +101,7 @@ var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
var client = new Kubernetes(config);
```
-Not all auth providers are supported at moment [#91](https://github.com/kubernetes-client/csharp/issues/91#issuecomment-362920478). You can still connect to a cluster by starting the proxy command:
+Not all auth providers are supported at the moment [#91](https://github.com/kubernetes-client/csharp/issues/91#issuecomment-362920478). You can still connect to a cluster by starting the proxy command:
```bash
$ kubectl proxy
@@ -147,24 +152,42 @@ ${GEN_DIR}/openapi/csharp.sh ${REPO_DIR}/src/KubernetesClient ${REPO_DIR}/csharp
# Version Compatibility
-| SDK Version | Kubernetes Version | .NET Targeting |
-|-------------|--------------------|------------------------------------------------------|
-| 9.0 | 1.25 | netstandard2.1;net5.0;net6.0;net48*;netstandard2.0* |
-| 8.0 | 1.24 | netstandard2.1;net5.0;net6.0;net48*;netstandard2.0* |
-| 7.2 | 1.23 | netstandard2.1;net5.0;net6.0;net48*;netstandard2.0* |
-| 7.0 | 1.23 | netstandard2.1;net5.0;net6.0 |
-| 6.0 | 1.22 | netstandard2.1;net5.0 |
-| 5.0 | 1.21 | netstandard2.1;net5 |
-| 4.0 | 1.20 | netstandard2.0;netstandard2.1 |
-| 3.0 | 1.19 | netstandard2.0;net452 |
-| 2.0 | 1.18 | netstandard2.0;net452 |
-| 1.6 | 1.16 | netstandard1.4;netstandard2.0;net452; |
-| 1.4 | 1.13 | netstandard1.4;net451 |
-| 1.3 | 1.12 | netstandard1.4;net452 |
+| SDK Version | Kubernetes Version | .NET Targeting |
+|-------------|--------------------|-----------------------------------------------------|
+| 18.0 | 1.34 | net8.0;net9.0;net48*;netstandard2.0* |
+| 17.0 | 1.33 | net8.0;net9.0;net48*;netstandard2.0* |
+| 16.0 | 1.32 | net8.0;net9.0;net48*;netstandard2.0* |
+| 15.0 | 1.31 | net6.0;net8.0;net48*;netstandard2.0* |
+| 14.0 | 1.30 | net6.0;net8.0;net48*;netstandard2.0* |
+| 13.0 | 1.29 | net6.0;net7.0;net8.0;net48*;netstandard2.0* |
+| 12.0 | 1.28 | net6.0;net7.0;net48*;netstandard2.0* |
+| 11.0 | 1.27 | net6.0;net7.0;net48*;netstandard2.0* |
+| 10.0 | 1.26 | net6.0;net7.0;net48*;netstandard2.0* |
+| 9.1 | 1.25 | netstandard2.1;net6.0;net7.0;net48*;netstandard2.0* |
+| 9.0 | 1.25 | netstandard2.1;net5.0;net6.0;net48*;netstandard2.0* |
+| 8.0 | 1.24 | netstandard2.1;net5.0;net6.0;net48*;netstandard2.0* |
+| 7.2 | 1.23 | netstandard2.1;net5.0;net6.0;net48*;netstandard2.0* |
+| 7.0 | 1.23 | netstandard2.1;net5.0;net6.0 |
+| 6.0 | 1.22 | netstandard2.1;net5.0 |
+| 5.0 | 1.21 | netstandard2.1;net5 |
+| 4.0 | 1.20 | netstandard2.0;netstandard2.1 |
+| 3.0 | 1.19 | netstandard2.0;net452 |
+| 2.0 | 1.18 | netstandard2.0;net452 |
+| 1.6 | 1.16 | netstandard1.4;netstandard2.0;net452; |
+| 1.4 | 1.13 | netstandard1.4;net451 |
+| 1.3 | 1.12 | netstandard1.4;net452 |
* Starting from `2.0`, [dotnet sdk versioning](https://github.com/kubernetes-client/csharp/issues/400) adopted
* `Kubernetes Version` here means the version sdk models and apis were generated from
- * Kubernetes api server guarantees the compatibility with `n-2` version. for exmaple, 1.19 based sdk should work with 1.21 cluster, but no guarantee works with 1.22 cluster. see also
+ * Kubernetes api server guarantees the compatibility with `n-2` (`n-3` after 1.28) version. for example:
+ - 1.19 based sdk should work with 1.21 cluster, but not guaranteed to work with 1.22 cluster.
+
+ and vice versa:
+ - 1.21 based sdk should work with 1.19 cluster, but not guaranteed to work with 1.18 cluster.
+Note: in practice, the sdk might work with much older clusters, at least for the more stable functionality. However, it is not guaranteed past the `n-2` (or `n-3` after 1.28 ) version. See [#1511](https://github.com/kubernetes-client/csharp/issues/1511) for additional details.
+
+ see also
+ * Fixes (including security fixes) are not back-ported automatically to older sdk versions. However, contributions from the community are welcomed 😊; See [Contributing](#contributing) for instructions on how to contribute.
* `*` `KubernetesClient.Classic`: netstandard2.0 and net48 are supported with limited features
diff --git a/SECURITY_CONTACTS b/SECURITY_CONTACTS
index d22538052..df0df1c5f 100644
--- a/SECURITY_CONTACTS
+++ b/SECURITY_CONTACTS
@@ -11,3 +11,4 @@
# INSTRUCTIONS AT https://kubernetes.io/security/
brendandburns
+tg123
diff --git a/csharp.settings b/csharp.settings
index 6d67b355a..0110958c8 100644
--- a/csharp.settings
+++ b/csharp.settings
@@ -1,3 +1,3 @@
-export KUBERNETES_BRANCH=v1.25.0
+export KUBERNETES_BRANCH=v1.34.0
export CLIENT_VERSION=0.0.1
export PACKAGE_NAME=k8s
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 000000000..2f16432e9
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,11 @@
+###############
+# folder #
+###############
+/**/DROP/
+/**/TEMP/
+/**/packages/
+/**/bin/
+/**/obj/
+_site
+
+api
\ No newline at end of file
diff --git a/doc/CONTRIBUTING.md b/doc/CONTRIBUTING.md
new file mode 120000
index 000000000..44fcc6343
--- /dev/null
+++ b/doc/CONTRIBUTING.md
@@ -0,0 +1 @@
+../CONTRIBUTING.md
\ No newline at end of file
diff --git a/doc/docfx.json b/doc/docfx.json
new file mode 100644
index 000000000..2917802e6
--- /dev/null
+++ b/doc/docfx.json
@@ -0,0 +1,41 @@
+{
+ "metadata": [
+ {
+ "src": [
+ {
+ "files": [
+ "KubernetesClient/bin/Release/net8.0/KubernetesClient.dll"
+ ],
+ "src": "../src"
+ }
+ ],
+ "dest": "api",
+ "disableGitFeatures": false,
+ "disableDefaultFilter": false
+ }
+ ],
+ "build": {
+ "content": [
+ {
+ "files": [
+ "api/**.yml",
+ "index.md",
+ "CONTRIBUTING.md",
+ "toc.yml"
+ ]
+ }
+ ],
+ "dest": "_site",
+ "globalMetadataFiles": [],
+ "fileMetadataFiles": [],
+ "template": [
+ "default"
+ ],
+ "postProcessors": [],
+ "markdownEngineName": "markdig",
+ "noLangKeyword": false,
+ "keepFileLink": false,
+ "cleanupCacheHistory": false,
+ "disableGitFeatures": false
+ }
+}
\ No newline at end of file
diff --git a/doc/index.md b/doc/index.md
new file mode 120000
index 000000000..32d46ee88
--- /dev/null
+++ b/doc/index.md
@@ -0,0 +1 @@
+../README.md
\ No newline at end of file
diff --git a/doc/toc.yml b/doc/toc.yml
new file mode 100644
index 000000000..8bf2c8ed1
--- /dev/null
+++ b/doc/toc.yml
@@ -0,0 +1,2 @@
+- name: API Documentation
+ href: api/k8s.yml
diff --git a/examples/Directory.Build.props b/examples/Directory.Build.props
index ab4d8e735..b87fe6aaa 100644
--- a/examples/Directory.Build.props
+++ b/examples/Directory.Build.props
@@ -1,6 +1,7 @@
+
- net6.0
+ net9.0
diff --git a/examples/Directory.Build.targets b/examples/Directory.Build.targets
index 3b7810177..bf5f5ee49 100644
--- a/examples/Directory.Build.targets
+++ b/examples/Directory.Build.targets
@@ -1,5 +1,6 @@
+
-
+
diff --git a/examples/GenericKubernetesApi/Program.cs b/examples/GenericKubernetesApi/Program.cs
deleted file mode 100644
index 5a093fad1..000000000
--- a/examples/GenericKubernetesApi/Program.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using k8s;
-using k8s.Models;
-using k8s.Util.Common;
-using k8s.Util.Common.Generic;
-
-namespace GenericKubernetesApiExample
-{
- public class Program
- {
- private static GenericKubernetesApi _genericKubernetesApi;
-
- public static void Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildDefaultConfig();
- IKubernetes client = new Kubernetes(config);
- var cts = new CancellationTokenSource();
-
- _genericKubernetesApi = new GenericKubernetesApi(
- apiGroup: "pod",
- apiVersion: "v1",
- resourcePlural: "pods",
- apiClient: client);
-
- var aPod = GetNamespacedPod(Namespaces.NamespaceDefault, "my-pod-name", cts.Token);
- var aListOfPods = ListPodsInNamespace(Namespaces.NamespaceDefault, cts.Token);
-
- // Watch for pod actions in a namespsace
- using var watch = _genericKubernetesApi.Watch(
- Namespaces.NamespaceDefault,
- (eventType, pod) => { Console.WriteLine("The event {0} happened on pod named {1}", eventType, pod.Metadata.Name); },
- exception => { Console.WriteLine("Oh no! An exception happened while watching pods. The message was '{0}'.", exception.Message); },
- () => { Console.WriteLine("The server closed the connection."); });
-
- Console.WriteLine("press ctrl + c to stop watching");
-
- var ctrlc = new ManualResetEventSlim(false);
- Console.CancelKeyPress += (sender, eventArgs) => ctrlc.Set();
- ctrlc.Wait();
- cts.Cancel();
- }
-
- private static V1Pod GetNamespacedPod(string @namespace, string podName, CancellationToken cancellationToken)
- {
- var resp = Task.Run(
- async () => await _genericKubernetesApi.GetAsync(@namespace, podName, cancellationToken).ConfigureAwait(false), cancellationToken);
-
- return resp.Result;
- }
-
- private static V1PodList ListPodsInNamespace(string @namespace, CancellationToken cancellationToken)
- {
- var resp = Task.Run(
- async () => await _genericKubernetesApi.ListAsync(@namespace, cancellationToken).ConfigureAwait(false), cancellationToken);
-
- return resp.Result;
- }
- }
-}
diff --git a/examples/aks-kubelogin/Program.cs b/examples/aks-kubelogin/Program.cs
new file mode 100644
index 000000000..cdee0cf10
--- /dev/null
+++ b/examples/aks-kubelogin/Program.cs
@@ -0,0 +1,49 @@
+using k8s;
+using System;
+using System.IO;
+using System.Text;
+
+var server = "https://example.hcp.eastus.azmk8s.io/"; // the server url of your aks
+var clientid = "00000000-0000-0000-0000-000000000000"; // the client id of the your msi
+var kubelogin = @"C:\bin\kubelogin.exe"; // the path to the kubelogin.exe
+
+using var configstream = new MemoryStream(Encoding.ASCII.GetBytes($"""
+apiVersion: v1
+clusters:
+- cluster:
+ insecure-skip-tls-verify: true
+ server: {server}
+ name: aks
+contexts:
+- context:
+ cluster: aks
+ user: msi
+ name: aks
+current-context: aks
+kind: Config
+users:
+- name: msi
+ user:
+ exec:
+ apiVersion: client.authentication.k8s.io/v1beta1
+ args:
+ - get-token
+ - --login
+ - msi
+ - --server-id
+ - 6dae42f8-4368-4678-94ff-3960e28e3630
+ - --client-id
+ - {clientid}
+ command: {kubelogin}
+ env: null
+"""));
+
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(configstream);
+IKubernetes client = new Kubernetes(config);
+Console.WriteLine("Starting Request!");
+
+var list = client.CoreV1.ListNamespacedPod("default");
+foreach (var item in list.Items)
+{
+ Console.WriteLine(item.Metadata.Name);
+}
diff --git a/examples/aks-kubelogin/README.md b/examples/aks-kubelogin/README.md
new file mode 100644
index 000000000..ab71071b0
--- /dev/null
+++ b/examples/aks-kubelogin/README.md
@@ -0,0 +1,24 @@
+# AKS C# example using kubelogin + MSI
+
+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.
+
+
+## Prerequisites
+
+ - turn on AAD support for AKS, see [here](https://docs.microsoft.com/en-us/azure/aks/managed-aad)
+ - create a managed identity for the AKS cluster
+ - assign the managed identity the `Azure Kubernetes Service RBAC Cluster Admin` (or other RBAC permission) on the AKS cluster
+ - 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)
+ - install the [kubelogin](https://github.com/Azure/kubelogin) to your machine
+
+## Running the code
+
+ *You must the the code on VM with MSI*
+
+ - Replace `server` with the address of your AKS cluster
+ - Replace `clientid` with the client id of the managed identity
+ - Replace `kubelogin` with the path to the kubelogin executable
+
+```
+dotnet run
+```
\ No newline at end of file
diff --git a/examples/GenericKubernetesApi/GenericKubernetesApi.csproj b/examples/aks-kubelogin/aks-kubelogin.csproj
similarity index 89%
rename from examples/GenericKubernetesApi/GenericKubernetesApi.csproj
rename to examples/aks-kubelogin/aks-kubelogin.csproj
index 139aaf588..11afe8d56 100644
--- a/examples/GenericKubernetesApi/GenericKubernetesApi.csproj
+++ b/examples/aks-kubelogin/aks-kubelogin.csproj
@@ -1,7 +1,5 @@
-
Exe
-
-
+
\ No newline at end of file
diff --git a/examples/aot/Program.cs b/examples/aot/Program.cs
new file mode 100644
index 000000000..d5125c0ff
--- /dev/null
+++ b/examples/aot/Program.cs
@@ -0,0 +1,16 @@
+using k8s;
+
+var config = KubernetesClientConfiguration.BuildDefaultConfig();
+IKubernetes client = new Kubernetes(config);
+Console.WriteLine("Starting Request!");
+
+var list = client.CoreV1.ListNamespacedPod("default");
+foreach (var item in list.Items)
+{
+ Console.WriteLine(item.Metadata.Name);
+}
+
+if (list.Items.Count == 0)
+{
+ Console.WriteLine("Empty!");
+}
\ No newline at end of file
diff --git a/examples/aot/aot.csproj b/examples/aot/aot.csproj
new file mode 100644
index 000000000..28741906d
--- /dev/null
+++ b/examples/aot/aot.csproj
@@ -0,0 +1,11 @@
+
+
+ Exe
+ enable
+ enable
+ true
+
+
+
+
+
diff --git a/examples/attach/Attach.cs b/examples/attach/Attach.cs
index a53b5da56..cfdce7d8e 100755
--- a/examples/attach/Attach.cs
+++ b/examples/attach/Attach.cs
@@ -3,38 +3,29 @@
using System;
using System.Threading.Tasks;
-namespace attach
-{
- internal class Attach
- {
- private static async Task Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- IKubernetes client = new Kubernetes(config);
- Console.WriteLine("Starting Request!");
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+IKubernetes client = new Kubernetes(config);
+Console.WriteLine("Starting Request!");
- var list = client.CoreV1.ListNamespacedPod("default");
- var pod = list.Items[0];
- await AttachToPod(client, pod).ConfigureAwait(false);
- }
+var list = client.CoreV1.ListNamespacedPod("default");
+var pod = list.Items[0];
+await AttachToPod(client, pod).ConfigureAwait(false);
- private static async Task AttachToPod(IKubernetes client, V1Pod pod)
- {
- var webSocket =
- await client.WebSocketNamespacedPodAttachAsync(pod.Metadata.Name, "default",
- pod.Spec.Containers[0].Name).ConfigureAwait(false);
+async Task AttachToPod(IKubernetes client, V1Pod pod)
+{
+ var webSocket =
+ await client.WebSocketNamespacedPodAttachAsync(pod.Metadata.Name, "default",
+ pod.Spec.Containers[0].Name).ConfigureAwait(false);
- var demux = new StreamDemuxer(webSocket);
- demux.Start();
+ var demux = new StreamDemuxer(webSocket);
+ demux.Start();
- var buff = new byte[4096];
- var stream = demux.GetStream(1, 1);
- while (true)
- {
- var read = stream.Read(buff, 0, 4096);
- var str = System.Text.Encoding.Default.GetString(buff);
- Console.WriteLine(str);
- }
- }
+ var buff = new byte[4096];
+ var stream = demux.GetStream(1, 1);
+ while (true)
+ {
+ var read = stream.Read(buff, 0, 4096);
+ var str = System.Text.Encoding.Default.GetString(buff);
+ Console.WriteLine(str);
}
}
diff --git a/examples/clientset/Program.cs b/examples/clientset/Program.cs
new file mode 100644
index 000000000..a1b74e0f8
--- /dev/null
+++ b/examples/clientset/Program.cs
@@ -0,0 +1,32 @@
+using k8s;
+using k8s.Models;
+using k8s.ClientSets;
+using System.Threading.Tasks;
+
+namespace clientset
+{
+ internal class Program
+ {
+ private static async Task Main(string[] args)
+ {
+ var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+ var client = new Kubernetes(config);
+
+ var clientSet = new ClientSet(client);
+ var list = await clientSet.CoreV1.Pod.ListAsync("default").ConfigureAwait(false);
+ foreach (var item in list)
+ {
+ System.Console.WriteLine(item.Metadata.Name);
+ }
+
+ var pod = await clientSet.CoreV1.Pod.GetAsync("test", "default").ConfigureAwait(false);
+ System.Console.WriteLine(pod?.Metadata?.Name);
+
+ var watch = clientSet.CoreV1.Pod.WatchListAsync("default");
+ await foreach (var (_, item) in watch.ConfigureAwait(false))
+ {
+ System.Console.WriteLine(item.Metadata.Name);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/clientset/clientset.csproj b/examples/clientset/clientset.csproj
new file mode 100644
index 000000000..4274ceb02
--- /dev/null
+++ b/examples/clientset/clientset.csproj
@@ -0,0 +1,6 @@
+
+
+ Exe
+
+
+
diff --git a/examples/cp/Cp.cs b/examples/cp/Cp.cs
index b7dd5b207..43e769490 100644
--- a/examples/cp/Cp.cs
+++ b/examples/cp/Cp.cs
@@ -1,4 +1,4 @@
-using ICSharpCode.SharpZipLib.Tar;
+using ICSharpCode.SharpZipLib.Tar;
using k8s;
using System;
using System.IO;
@@ -7,110 +7,104 @@
using System.Threading;
using System.Threading.Tasks;
-namespace cp
-{
- internal class Cp
- {
- private static IKubernetes client;
+namespace cp;
- private static async Task Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- client = new Kubernetes(config);
+internal class Cp
+{
+ private static IKubernetes client;
+ private static async Task Main(string[] args)
+ {
+ var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+ client = new Kubernetes(config);
- var pods = client.CoreV1.ListNamespacedPod("default", null, null, null, $"job-name=upload-demo");
- var pod = pods.Items.First();
- await CopyFileToPodAsync(pod.Metadata.Name, "default", "upload-demo", args[0], $"home/{args[1]}");
+ var pods = client.CoreV1.ListNamespacedPod("default", null, null, null, $"job-name=upload-demo");
+ var pod = pods.Items.First();
- }
+ await CopyFileToPodAsync(pod.Metadata.Name, "default", "upload-demo", args[0], $"home/{args[1]}").ConfigureAwait(false);
+ }
- private static void ValidatePathParameters(string sourcePath, string destinationPath)
+ private static void ValidatePathParameters(string sourcePath, string destinationPath)
+ {
+ if (string.IsNullOrWhiteSpace(sourcePath))
{
- if (string.IsNullOrWhiteSpace(sourcePath))
- {
- throw new ArgumentException($"{nameof(sourcePath)} cannot be null or whitespace");
- }
-
- if (string.IsNullOrWhiteSpace(destinationPath))
- {
- throw new ArgumentException($"{nameof(destinationPath)} cannot be null or whitespace");
- }
-
+ throw new ArgumentException($"{nameof(sourcePath)} cannot be null or whitespace");
}
- public static async Task CopyFileToPodAsync(string name, string @namespace, string container, string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken = default(CancellationToken))
+ if (string.IsNullOrWhiteSpace(destinationPath))
{
- // All other parameters are being validated by MuxedStreamNamespacedPodExecAsync called by NamespacedPodExecAsync
- ValidatePathParameters(sourceFilePath, destinationFilePath);
+ throw new ArgumentException($"{nameof(destinationPath)} cannot be null or whitespace");
+ }
+ }
+
+ public static async Task CopyFileToPodAsync(string name, string @namespace, string container, string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ // All other parameters are being validated by MuxedStreamNamespacedPodExecAsync called by NamespacedPodExecAsync
+ ValidatePathParameters(sourceFilePath, destinationFilePath);
- // The callback which processes the standard input, standard output and standard error of exec method
- var handler = new ExecAsyncCallback(async (stdIn, stdOut, stdError) =>
+ // The callback which processes the standard input, standard output and standard error of exec method
+ var handler = new ExecAsyncCallback(async (stdIn, stdOut, stdError) =>
+ {
+ var fileInfo = new FileInfo(destinationFilePath);
+ try
{
- var fileInfo = new FileInfo(destinationFilePath);
- try
+ using (var memoryStream = new MemoryStream())
{
- using (var memoryStream = new MemoryStream())
+ using (var inputFileStream = File.OpenRead(sourceFilePath))
+ using (var tarOutputStream = new TarOutputStream(memoryStream, Encoding.Default))
{
- using (var inputFileStream = File.OpenRead(sourceFilePath))
- using (var tarOutputStream = new TarOutputStream(memoryStream, Encoding.Default))
- {
- tarOutputStream.IsStreamOwner = false;
-
- var fileSize = inputFileStream.Length;
- var entry = TarEntry.CreateTarEntry(fileInfo.Name);
-
- entry.Size = fileSize;
+ tarOutputStream.IsStreamOwner = false;
- tarOutputStream.PutNextEntry(entry);
- await inputFileStream.CopyToAsync(tarOutputStream);
- tarOutputStream.CloseEntry();
- }
+ var fileSize = inputFileStream.Length;
+ var entry = TarEntry.CreateTarEntry(fileInfo.Name);
- memoryStream.Position = 0;
+ entry.Size = fileSize;
- await memoryStream.CopyToAsync(stdIn);
- await stdIn.FlushAsync();
+ tarOutputStream.PutNextEntry(entry);
+ await inputFileStream.CopyToAsync(tarOutputStream).ConfigureAwait(false);
+ tarOutputStream.CloseEntry();
}
- }
- catch (Exception ex)
- {
- throw new IOException($"Copy command failed: {ex.Message}");
- }
+ memoryStream.Position = 0;
- using StreamReader streamReader = new StreamReader(stdError);
- while (streamReader.EndOfStream == false)
- {
- string error = await streamReader.ReadToEndAsync();
- throw new IOException($"Copy command failed: {error}");
+ await memoryStream.CopyToAsync(stdIn).ConfigureAwait(false);
+ await stdIn.FlushAsync().ConfigureAwait(false);
}
- });
-
- string destinationFolder = GetFolderName(destinationFilePath);
-
- return await client.NamespacedPodExecAsync(
- name,
- @namespace,
- container,
- new string[] { "sh", "-c", $"tar xmf - -C {destinationFolder}" },
- false,
- handler,
- cancellationToken);
- }
-
+ }
+ catch (Exception ex)
+ {
+ throw new IOException($"Copy command failed: {ex.Message}");
+ }
- private static string GetFolderName(string filePath)
- {
- var folderName = Path.GetDirectoryName(filePath);
+ using StreamReader streamReader = new StreamReader(stdError);
+ while (streamReader.EndOfStream == false)
+ {
+ string error = await streamReader.ReadToEndAsync().ConfigureAwait(false);
+ throw new IOException($"Copy command failed: {error}");
+ }
+ });
+
+ string destinationFolder = GetFolderName(destinationFilePath);
+
+ return await client.NamespacedPodExecAsync(
+ name,
+ @namespace,
+ container,
+ new string[] { "sh", "-c", $"tar xmf - -C {destinationFolder}" },
+ false,
+ handler,
+ cancellationToken).ConfigureAwait(false);
+ }
- return string.IsNullOrEmpty(folderName) ? "." : folderName;
- }
+ private static string GetFolderName(string filePath)
+ {
+ var folderName = Path.GetDirectoryName(filePath);
+ return string.IsNullOrEmpty(folderName) ? "." : folderName;
}
}
diff --git a/examples/cp/cp.csproj b/examples/cp/cp.csproj
index 27cff0379..cde0f0fca 100644
--- a/examples/cp/cp.csproj
+++ b/examples/cp/cp.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/examples/csrApproval/Program.cs b/examples/csrApproval/Program.cs
index b4f154864..6c374105b 100644
--- a/examples/csrApproval/Program.cs
+++ b/examples/csrApproval/Program.cs
@@ -1,4 +1,4 @@
-using Json.Patch;
+using Json.Patch;
using k8s;
using k8s.Models;
using System.Net;
@@ -21,7 +21,7 @@ string GenerateCertificate(string name)
var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false));
- request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new("1.3.6.1.5.5.7.3.1") }, false));
+ request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension([new ("1.3.6.1.5.5.7.3.1")], false));
request.CertificateExtensions.Add(sanBuilder.Build());
var csr = request.CreateSigningRequest();
var pemKey = "-----BEGIN CERTIFICATE REQUEST-----\r\n" +
@@ -44,34 +44,42 @@ string GenerateCertificate(string name)
Kind = "CertificateSigningRequest",
Metadata = new V1ObjectMeta
{
- Name = name
+ Name = name,
},
Spec = new V1CertificateSigningRequestSpec
{
Request = encodedCsr,
SignerName = "kubernetes.io/kube-apiserver-client",
Usages = new List { "client auth" },
- ExpirationSeconds = 600 // minimum should be 10 minutes
- }
+ ExpirationSeconds = 600, // minimum should be 10 minutes
+ },
};
-await client.CertificatesV1.CreateCertificateSigningRequestAsync(request);
+await client.CertificatesV1.CreateCertificateSigningRequestAsync(request).ConfigureAwait(false);
var serializeOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
- WriteIndented = true
+ WriteIndented = true,
};
-var readCert = await client.CertificatesV1.ReadCertificateSigningRequestAsync(name);
+var readCert = await client.CertificatesV1.ReadCertificateSigningRequestAsync(name).ConfigureAwait(false);
var old = JsonSerializer.SerializeToDocument(readCert, serializeOptions);
var replace = new List
{
- new("True", "Approved", DateTime.UtcNow, DateTime.UtcNow, "This certificate was approved by k8s client", "Approve")
+ new V1CertificateSigningRequestCondition
+ {
+ Type = "Approved",
+ Status = "True",
+ Reason = "Approve",
+ Message = "This certificate was approved by k8s client",
+ LastUpdateTime = DateTime.UtcNow,
+ LastTransitionTime = DateTime.UtcNow,
+ },
};
readCert.Status.Conditions = replace;
var expected = JsonSerializer.SerializeToDocument(readCert, serializeOptions);
var patch = old.CreatePatch(expected);
-await client.CertificatesV1.PatchCertificateSigningRequestApprovalAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name);
+await client.CertificatesV1.PatchCertificateSigningRequestApprovalAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name).ConfigureAwait(false);
diff --git a/examples/csrApproval/csrApproval.csproj b/examples/csrApproval/csrApproval.csproj
index 51531b474..f67de4fbc 100644
--- a/examples/csrApproval/csrApproval.csproj
+++ b/examples/csrApproval/csrApproval.csproj
@@ -7,6 +7,6 @@
-
+
diff --git a/examples/customResource/CustomResourceDefinition.cs b/examples/customResource/CustomResourceDefinition.cs
index b0deb2913..ad1b7f9c4 100644
--- a/examples/customResource/CustomResourceDefinition.cs
+++ b/examples/customResource/CustomResourceDefinition.cs
@@ -32,8 +32,8 @@ public abstract class CustomResource : CustomResource
[JsonPropertyName("spec")]
public TSpec Spec { get; set; }
- [JsonPropertyName("CStatus")]
- public TStatus CStatus { get; set; }
+ [JsonPropertyName("status")]
+ public TStatus Status { get; set; }
}
public class CustomResourceList : KubernetesObject
diff --git a/examples/customResource/Program.cs b/examples/customResource/Program.cs
index 3898f3134..726852a7f 100644
--- a/examples/customResource/Program.cs
+++ b/examples/customResource/Program.cs
@@ -92,11 +92,11 @@ private static async Task Main(string[] args)
// deleting the custom resource
try
{
- myCr = await generic.DeleteNamespacedAsync(
+ var status = await generic.DeleteNamespacedAsync(
myCr.Metadata.NamespaceProperty ?? "default",
myCr.Metadata.Name).ConfigureAwait(false);
- Console.WriteLine("Deleted the CR");
+ Console.WriteLine($"Deleted the CR status: {status}");
}
catch (Exception exception)
{
diff --git a/examples/customResource/cResource.cs b/examples/customResource/cResource.cs
index f9df60b22..67440aee9 100644
--- a/examples/customResource/cResource.cs
+++ b/examples/customResource/cResource.cs
@@ -19,13 +19,13 @@ public override string ToString()
}
}
- public class CResourceSpec
+ public record CResourceSpec
{
[JsonPropertyName("cityName")]
public string CityName { get; set; }
}
- public class CResourceStatus : V1Status
+ public record CResourceStatus : V1Status
{
[JsonPropertyName("temperature")]
public string Temperature { get; set; }
diff --git a/examples/customResource/customResource.csproj b/examples/customResource/customResource.csproj
index c20c0a210..ad2bdd739 100644
--- a/examples/customResource/customResource.csproj
+++ b/examples/customResource/customResource.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/examples/exec/Exec.cs b/examples/exec/Exec.cs
index 9fdfc73b0..20bbd2125 100755
--- a/examples/exec/Exec.cs
+++ b/examples/exec/Exec.cs
@@ -3,35 +3,26 @@
using System;
using System.Threading.Tasks;
-namespace exec
-{
- internal class Exec
- {
- private static async Task Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- IKubernetes client = new Kubernetes(config);
- Console.WriteLine("Starting Request!");
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+IKubernetes client = new Kubernetes(config);
+Console.WriteLine("Starting Request!");
- var list = client.CoreV1.ListNamespacedPod("default");
- var pod = list.Items[0];
- await ExecInPod(client, pod).ConfigureAwait(false);
- }
+var list = client.CoreV1.ListNamespacedPod("default");
+var pod = list.Items[0];
+await ExecInPod(client, pod).ConfigureAwait(false);
- private static async Task ExecInPod(IKubernetes client, V1Pod pod)
- {
- var webSocket =
- await client.WebSocketNamespacedPodExecAsync(pod.Metadata.Name, "default", "ls",
- pod.Spec.Containers[0].Name).ConfigureAwait(false);
+async Task ExecInPod(IKubernetes client, V1Pod pod)
+{
+ var webSocket =
+ await client.WebSocketNamespacedPodExecAsync(pod.Metadata.Name, "default", "ls",
+ pod.Spec.Containers[0].Name).ConfigureAwait(false);
- var demux = new StreamDemuxer(webSocket);
- demux.Start();
+ var demux = new StreamDemuxer(webSocket);
+ demux.Start();
- var buff = new byte[4096];
- var stream = demux.GetStream(1, 1);
- var read = stream.Read(buff, 0, 4096);
- var str = System.Text.Encoding.Default.GetString(buff);
- Console.WriteLine(str);
- }
- }
+ var buff = new byte[4096];
+ var stream = demux.GetStream(1, 1);
+ var read = stream.Read(buff, 0, 4096);
+ var str = System.Text.Encoding.Default.GetString(buff);
+ Console.WriteLine(str);
}
diff --git a/examples/generic/Generic.cs b/examples/generic/Generic.cs
index 41f91b39f..f65fb944d 100644
--- a/examples/generic/Generic.cs
+++ b/examples/generic/Generic.cs
@@ -1,26 +1,16 @@
using k8s;
using k8s.Models;
using System;
-using System.Threading.Tasks;
-namespace exec
-{
- internal class Generic
- {
- private static async Task Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- IKubernetes client = new Kubernetes(config);
- var generic = new GenericClient(client, "", "v1", "nodes");
- var node = await generic.ReadAsync("kube0").ConfigureAwait(false);
- Console.WriteLine(node.Metadata.Name);
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+IKubernetes client = new Kubernetes(config);
+var generic = new GenericClient(client, "", "v1", "nodes");
+var node = await generic.ReadAsync("kube0").ConfigureAwait(false);
+Console.WriteLine(node.Metadata.Name);
- var genericPods = new GenericClient(client, "", "v1", "pods");
- var pods = await genericPods.ListNamespacedAsync("default").ConfigureAwait(false);
- foreach (var pod in pods.Items)
- {
- Console.WriteLine(pod.Metadata.Name);
- }
- }
- }
+var genericPods = new GenericClient(client, "", "v1", "pods");
+var pods = await genericPods.ListNamespacedAsync("default").ConfigureAwait(false);
+foreach (var pod in pods.Items)
+{
+ Console.WriteLine(pod.Metadata.Name);
}
diff --git a/examples/labels/PodList.cs b/examples/labels/PodList.cs
index 2d59e9026..0c5df001d 100755
--- a/examples/labels/PodList.cs
+++ b/examples/labels/PodList.cs
@@ -2,47 +2,38 @@
using System;
using System.Collections.Generic;
-namespace simple
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+IKubernetes client = new Kubernetes(config);
+Console.WriteLine("Starting Request!");
+
+var list = client.CoreV1.ListNamespacedService("default");
+foreach (var item in list.Items)
{
- internal class PodList
+ Console.WriteLine("Pods for service: " + item.Metadata.Name);
+ Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=");
+ if (item.Spec == null || item.Spec.Selector == null)
{
- private static void Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- IKubernetes client = new Kubernetes(config);
- Console.WriteLine("Starting Request!");
-
- var list = client.CoreV1.ListNamespacedService("default");
- foreach (var item in list.Items)
- {
- Console.WriteLine("Pods for service: " + item.Metadata.Name);
- Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=");
- if (item.Spec == null || item.Spec.Selector == null)
- {
- continue;
- }
-
- var labels = new List();
- foreach (var key in item.Spec.Selector)
- {
- labels.Add(key.Key + "=" + key.Value);
- }
+ continue;
+ }
- var labelStr = string.Join(",", labels.ToArray());
- Console.WriteLine(labelStr);
- var podList = client.CoreV1.ListNamespacedPod("default", labelSelector: labelStr);
- foreach (var pod in podList.Items)
- {
- Console.WriteLine(pod.Metadata.Name);
- }
+ var labels = new List();
+ foreach (var key in item.Spec.Selector)
+ {
+ labels.Add(key.Key + "=" + key.Value);
+ }
- if (podList.Items.Count == 0)
- {
- Console.WriteLine("Empty!");
- }
+ var labelStr = string.Join(",", labels.ToArray());
+ Console.WriteLine(labelStr);
+ var podList = client.CoreV1.ListNamespacedPod("default", labelSelector: labelStr);
+ foreach (var pod in podList.Items)
+ {
+ Console.WriteLine(pod.Metadata.Name);
+ }
- Console.WriteLine();
- }
- }
+ if (podList.Items.Count == 0)
+ {
+ Console.WriteLine("Empty!");
}
+
+ Console.WriteLine();
}
diff --git a/examples/logs/Logs.cs b/examples/logs/Logs.cs
index ea23fa05f..5293de579 100755
--- a/examples/logs/Logs.cs
+++ b/examples/logs/Logs.cs
@@ -1,31 +1,21 @@
using k8s;
using System;
-using System.Threading.Tasks;
-namespace logs
-{
- internal class Logs
- {
- private static async Task Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- IKubernetes client = new Kubernetes(config);
- Console.WriteLine("Starting Request!");
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+IKubernetes client = new Kubernetes(config);
+Console.WriteLine("Starting Request!");
- var list = client.CoreV1.ListNamespacedPod("default");
- if (list.Items.Count == 0)
- {
- Console.WriteLine("No pods!");
- return;
- }
+var list = client.CoreV1.ListNamespacedPod("default");
+if (list.Items.Count == 0)
+{
+ Console.WriteLine("No pods!");
+ return;
+}
- var pod = list.Items[0];
+var pod = list.Items[0];
- var response = await client.CoreV1.ReadNamespacedPodLogWithHttpMessagesAsync(
- pod.Metadata.Name,
- pod.Metadata.NamespaceProperty, container: pod.Spec.Containers[0].Name, follow: true).ConfigureAwait(false);
- var stream = response.Body;
- stream.CopyTo(Console.OpenStandardOutput());
- }
- }
-}
+var response = await client.CoreV1.ReadNamespacedPodLogWithHttpMessagesAsync(
+ pod.Metadata.Name,
+ pod.Metadata.NamespaceProperty, container: pod.Spec.Containers[0].Name, follow: true).ConfigureAwait(false);
+var stream = response.Body;
+stream.CopyTo(Console.OpenStandardOutput());
diff --git a/examples/metrics/Program.cs b/examples/metrics/Program.cs
index 33a779f09..f823bf54d 100644
--- a/examples/metrics/Program.cs
+++ b/examples/metrics/Program.cs
@@ -3,58 +3,49 @@
using System.Linq;
using System.Threading.Tasks;
-namespace metrics
+async Task NodesMetrics(IKubernetes client)
{
- internal class Program
+ var nodesMetrics = await client.GetKubernetesNodesMetricsAsync().ConfigureAwait(false);
+
+ foreach (var item in nodesMetrics.Items)
{
- private static async Task NodesMetrics(IKubernetes client)
+ Console.WriteLine(item.Metadata.Name);
+
+ foreach (var metric in item.Usage)
{
- var nodesMetrics = await client.GetKubernetesNodesMetricsAsync().ConfigureAwait(false);
+ Console.WriteLine($"{metric.Key}: {metric.Value}");
+ }
+ }
+}
- foreach (var item in nodesMetrics.Items)
- {
- Console.WriteLine(item.Metadata.Name);
+async Task PodsMetrics(IKubernetes client)
+{
+ var podsMetrics = await client.GetKubernetesPodsMetricsAsync().ConfigureAwait(false);
- foreach (var metric in item.Usage)
- {
- Console.WriteLine($"{metric.Key}: {metric.Value}");
- }
- }
- }
+ if (!podsMetrics.Items.Any())
+ {
+ Console.WriteLine("Empty");
+ }
- private static async Task PodsMetrics(IKubernetes client)
+ foreach (var item in podsMetrics.Items)
+ {
+ foreach (var container in item.Containers)
{
- var podsMetrics = await client.GetKubernetesPodsMetricsAsync().ConfigureAwait(false);
-
- if (!podsMetrics.Items.Any())
- {
- Console.WriteLine("Empty");
- }
+ Console.WriteLine(container.Name);
- foreach (var item in podsMetrics.Items)
+ foreach (var metric in container.Usage)
{
- foreach (var container in item.Containers)
- {
- Console.WriteLine(container.Name);
-
- foreach (var metric in container.Usage)
- {
- Console.WriteLine($"{metric.Key}: {metric.Value}");
- }
- }
-
- Console.Write(Environment.NewLine);
+ Console.WriteLine($"{metric.Key}: {metric.Value}");
}
}
- private static async Task Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- var client = new Kubernetes(config);
-
- await NodesMetrics(client).ConfigureAwait(false);
- Console.WriteLine(Environment.NewLine);
- await PodsMetrics(client).ConfigureAwait(false);
- }
+ Console.Write(Environment.NewLine);
}
}
+
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+var client = new Kubernetes(config);
+
+await NodesMetrics(client).ConfigureAwait(false);
+Console.WriteLine(Environment.NewLine);
+await PodsMetrics(client).ConfigureAwait(false);
diff --git a/examples/namespace/NamespaceExample.cs b/examples/namespace/NamespaceExample.cs
index 351453a4d..06e8757a4 100644
--- a/examples/namespace/NamespaceExample.cs
+++ b/examples/namespace/NamespaceExample.cs
@@ -4,52 +4,37 @@
using System.Net;
using System.Threading.Tasks;
-namespace @namespace
+void ListNamespaces(IKubernetes client)
{
- internal class NamespaceExample
+ var list = client.CoreV1.ListNamespace();
+ foreach (var item in list.Items)
{
- private static void ListNamespaces(IKubernetes client)
- {
- var list = client.CoreV1.ListNamespace();
- foreach (var item in list.Items)
- {
- Console.WriteLine(item.Metadata.Name);
- }
+ Console.WriteLine(item.Metadata.Name);
+ }
- if (list.Items.Count == 0)
- {
- Console.WriteLine("Empty!");
- }
- }
+ if (list.Items.Count == 0)
+ {
+ Console.WriteLine("Empty!");
+ }
+}
- private static async Task DeleteAsync(IKubernetes client, string name, int delayMillis)
+async Task DeleteAsync(IKubernetes client, string name, int delayMillis)
+{
+ while (true)
+ {
+ await Task.Delay(delayMillis).ConfigureAwait(false);
+ try
{
- while (true)
+ await client.CoreV1.ReadNamespaceAsync(name).ConfigureAwait(false);
+ }
+ catch (AggregateException ex)
+ {
+ foreach (var innerEx in ex.InnerExceptions)
{
- await Task.Delay(delayMillis).ConfigureAwait(false);
- try
- {
- await client.CoreV1.ReadNamespaceAsync(name).ConfigureAwait(false);
- }
- catch (AggregateException ex)
- {
- foreach (var innerEx in ex.InnerExceptions)
- {
- if (innerEx is k8s.Autorest.HttpOperationException)
- {
- var code = ((k8s.Autorest.HttpOperationException)innerEx).Response.StatusCode;
- if (code == HttpStatusCode.NotFound)
- {
- return;
- }
-
- throw;
- }
- }
- }
- catch (k8s.Autorest.HttpOperationException ex)
+ if (innerEx is k8s.Autorest.HttpOperationException exception)
{
- if (ex.Response.StatusCode == HttpStatusCode.NotFound)
+ var code = exception.Response.StatusCode;
+ if (code == HttpStatusCode.NotFound)
{
return;
}
@@ -58,41 +43,47 @@ private static async Task DeleteAsync(IKubernetes client, string name, int delay
}
}
}
-
- private static void Delete(IKubernetes client, string name, int delayMillis)
+ catch (k8s.Autorest.HttpOperationException ex)
{
- DeleteAsync(client, name, delayMillis).Wait();
+ if (ex.Response.StatusCode == HttpStatusCode.NotFound)
+ {
+ return;
+ }
+
+ throw;
}
+ }
+}
- private static void Main(string[] args)
- {
- var k8SClientConfig = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- IKubernetes client = new Kubernetes(k8SClientConfig);
+void Delete(IKubernetes client, string name, int delayMillis)
+{
+ DeleteAsync(client, name, delayMillis).Wait();
+}
- ListNamespaces(client);
+var k8SClientConfig = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+IKubernetes client = new Kubernetes(k8SClientConfig);
- var ns = new V1Namespace { Metadata = new V1ObjectMeta { Name = "test" } };
+ListNamespaces(client);
- var result = client.CoreV1.CreateNamespace(ns);
- Console.WriteLine(result);
+var ns = new V1Namespace { Metadata = new V1ObjectMeta { Name = "test" } };
- ListNamespaces(client);
+var result = client.CoreV1.CreateNamespace(ns);
+Console.WriteLine(result);
- var status = client.CoreV1.DeleteNamespace(ns.Metadata.Name, new V1DeleteOptions());
+ListNamespaces(client);
- if (status.HasObject)
- {
- var obj = status.ObjectView();
- Console.WriteLine(obj.Status.Phase);
+var status = client.CoreV1.DeleteNamespace(ns.Metadata.Name, new V1DeleteOptions());
- Delete(client, ns.Metadata.Name, 3 * 1000);
- }
- else
- {
- Console.WriteLine(status.Message);
- }
+if (status.HasObject)
+{
+ var obj = status.ObjectView();
+ Console.WriteLine(obj.Status.Phase);
- ListNamespaces(client);
- }
- }
+ Delete(client, ns.Metadata.Name, 3 * 1000);
}
+else
+{
+ Console.WriteLine(status.Message);
+}
+
+ListNamespaces(client);
diff --git a/examples/openTelemetryConsole/Program.cs b/examples/openTelemetryConsole/Program.cs
index 9a5460dcb..4b7406be3 100644
--- a/examples/openTelemetryConsole/Program.cs
+++ b/examples/openTelemetryConsole/Program.cs
@@ -24,11 +24,12 @@
// Read the list of pods contained in default namespace
var list = client.CoreV1.ListNamespacedPod("default");
-// Print the name of pods
+// Print the name of pods
foreach (var item in list.Items)
{
Console.WriteLine(item.Metadata.Name);
}
+
// Or empty if there are no pods
if (list.Items.Count == 0)
{
diff --git a/examples/openTelemetryConsole/openTelemetryConsole.csproj b/examples/openTelemetryConsole/openTelemetryConsole.csproj
index 374da9c72..ff48d4450 100644
--- a/examples/openTelemetryConsole/openTelemetryConsole.csproj
+++ b/examples/openTelemetryConsole/openTelemetryConsole.csproj
@@ -7,9 +7,8 @@
-
-
-
+
+
diff --git a/examples/patch-aot/Program.cs b/examples/patch-aot/Program.cs
new file mode 100644
index 000000000..e72f6a4d2
--- /dev/null
+++ b/examples/patch-aot/Program.cs
@@ -0,0 +1,33 @@
+using k8s;
+using k8s.Models;
+
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+IKubernetes client = new Kubernetes(config);
+Console.WriteLine("Starting Request!");
+
+var pod = client.CoreV1.ListNamespacedPod("default").Items.First();
+var name = pod.Metadata.Name;
+PrintLabels(pod);
+
+var patchStr = @"
+{
+ ""metadata"": {
+ ""labels"": {
+ ""test"": ""test""
+ }
+ }
+}";
+
+client.CoreV1.PatchNamespacedPod(new V1Patch(patchStr, V1Patch.PatchType.MergePatch), name, "default");
+PrintLabels(client.CoreV1.ReadNamespacedPod(name, "default"));
+
+static void PrintLabels(V1Pod pod)
+{
+ Console.WriteLine($"Labels: for {pod.Metadata.Name}");
+ foreach (var (k, v) in pod.Metadata.Labels)
+ {
+ Console.WriteLine($"{k} : {v}");
+ }
+
+ Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=");
+}
diff --git a/examples/patch-aot/patch-aot.csproj b/examples/patch-aot/patch-aot.csproj
new file mode 100644
index 000000000..c2c806215
--- /dev/null
+++ b/examples/patch-aot/patch-aot.csproj
@@ -0,0 +1,11 @@
+
+
+ Exe
+ enable
+ enable
+ true
+
+
+
+
+
diff --git a/examples/patch/Program.cs b/examples/patch/Program.cs
index 7958fcc35..f8cefa67c 100644
--- a/examples/patch/Program.cs
+++ b/examples/patch/Program.cs
@@ -3,21 +3,15 @@
using System;
using System.Linq;
-namespace patch
-{
- internal class Program
- {
- private static void Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- IKubernetes client = new Kubernetes(config);
- Console.WriteLine("Starting Request!");
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+IKubernetes client = new Kubernetes(config);
+Console.WriteLine("Starting Request!");
- var pod = client.CoreV1.ListNamespacedPod("default").Items.First();
- var name = pod.Metadata.Name;
- PrintLabels(pod);
+var pod = client.CoreV1.ListNamespacedPod("default").Items.First();
+var name = pod.Metadata.Name;
+PrintLabels(pod);
- var patchStr = @"
+var patchStr = @"
{
""metadata"": {
""labels"": {
@@ -26,19 +20,16 @@ private static void Main(string[] args)
}
}";
- client.CoreV1.PatchNamespacedPod(new V1Patch(patchStr, V1Patch.PatchType.MergePatch), name, "default");
- PrintLabels(client.CoreV1.ReadNamespacedPod(name, "default"));
- }
-
- private static void PrintLabels(V1Pod pod)
- {
- Console.WriteLine($"Labels: for {pod.Metadata.Name}");
- foreach (var (k, v) in pod.Metadata.Labels)
- {
- Console.WriteLine($"{k} : {v}");
- }
+client.CoreV1.PatchNamespacedPod(new V1Patch(patchStr, V1Patch.PatchType.MergePatch), name, "default");
+PrintLabels(client.CoreV1.ReadNamespacedPod(name, "default"));
- Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=");
- }
+void PrintLabels(V1Pod pod)
+{
+ Console.WriteLine($"Labels: for {pod.Metadata.Name}");
+ foreach (var (k, v) in pod.Metadata.Labels)
+ {
+ Console.WriteLine($"{k} : {v}");
}
+
+ Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=");
}
diff --git a/examples/portforward/PortForward.cs b/examples/portforward/PortForward.cs
index fe9485d86..ee095e073 100644
--- a/examples/portforward/PortForward.cs
+++ b/examples/portforward/PortForward.cs
@@ -6,74 +6,66 @@
using System.Text;
using System.Threading.Tasks;
-namespace portforward
-{
- internal class Portforward
- {
- private static async Task Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- IKubernetes client = new Kubernetes(config);
- Console.WriteLine("Starting port forward!");
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+IKubernetes client = new Kubernetes(config);
+Console.WriteLine("Starting port forward!");
- var list = client.CoreV1.ListNamespacedPod("default");
- var pod = list.Items[0];
- await Forward(client, pod);
- }
-
- private static async Task Forward(IKubernetes client, V1Pod pod)
- {
- // Note this is single-threaded, it won't handle concurrent requests well...
- var webSocket = await client.WebSocketNamespacedPodPortForwardAsync(pod.Metadata.Name, "default", new int[] { 80 }, "v4.channel.k8s.io");
- var demux = new StreamDemuxer(webSocket, StreamType.PortForward);
- demux.Start();
+var list = client.CoreV1.ListNamespacedPod("default");
+var pod = list.Items[0];
+await Forward(client, pod).ConfigureAwait(false);
- var stream = demux.GetStream((byte?)0, (byte?)0);
+async Task Forward(IKubernetes client, V1Pod pod)
+{
+ // Note this is single-threaded, it won't handle concurrent requests well...
+ var webSocket = await client.WebSocketNamespacedPodPortForwardAsync(pod.Metadata.Name, "default", new int[] { 80 }, "v4.channel.k8s.io").ConfigureAwait(false);
+ var demux = new StreamDemuxer(webSocket, StreamType.PortForward);
+ demux.Start();
- IPAddress ipAddress = IPAddress.Loopback;
- IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 8080);
- Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
- listener.Bind(localEndPoint);
- listener.Listen(100);
+ var stream = demux.GetStream((byte?)0, (byte?)0);
- Socket handler = null;
+ IPAddress ipAddress = IPAddress.Loopback;
+ IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 8080);
+ Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+ listener.Bind(localEndPoint);
+ listener.Listen(100);
- // Note this will only accept a single connection
- var accept = Task.Run(() =>
- {
- while (true)
- {
- handler = listener.Accept();
- var bytes = new byte[4096];
- while (true)
- {
- int bytesRec = handler.Receive(bytes);
- stream.Write(bytes, 0, bytesRec);
- if (bytesRec == 0 || Encoding.ASCII.GetString(bytes, 0, bytesRec).IndexOf("") > -1)
- {
- break;
- }
- }
- }
- });
+ Socket handler = null;
- var copy = Task.Run(() =>
+ // Note this will only accept a single connection
+ var accept = Task.Run(() =>
+ {
+ while (true)
+ {
+ handler = listener.Accept();
+ var bytes = new byte[4096];
+ while (true)
{
- var buff = new byte[4096];
- while (true)
+ int bytesRec = handler.Receive(bytes);
+ stream.Write(bytes, 0, bytesRec);
+ if (bytesRec == 0 || Encoding.ASCII.GetString(bytes, 0, bytesRec).IndexOf("") > -1)
{
- var read = stream.Read(buff, 0, 4096);
- handler.Send(buff, read, 0);
+ break;
}
- });
-
- await accept;
- await copy;
- if (handler != null)
- {
- handler.Close();
}
- listener.Close();
}
+ });
+
+ var copy = Task.Run(() =>
+ {
+ var buff = new byte[4096];
+ while (true)
+ {
+ var read = stream.Read(buff, 0, 4096);
+ handler.Send(buff, read, 0);
+ }
+ });
+
+ await accept.ConfigureAwait(false);
+ await copy.ConfigureAwait(false);
+ if (handler != null)
+ {
+ handler.Close();
}
+
+ listener.Close();
}
diff --git a/examples/prometheus/Prometheus.cs b/examples/prometheus/Prometheus.cs
deleted file mode 100755
index 0a3111ef7..000000000
--- a/examples/prometheus/Prometheus.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using k8s;
-using k8s.Monitoring;
-using Prometheus;
-using System;
-using System.Net.Http;
-using System.Threading;
-
-namespace prom
-{
- internal class Prometheus
- {
- private static void Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildDefaultConfig();
- var handler = new PrometheusHandler();
- IKubernetes client = new Kubernetes(config, new DelegatingHandler[] { handler });
-
- var server = new MetricServer(hostname: "localhost", port: 1234);
- server.Start();
-
- Console.WriteLine("Making requests!");
- while (true)
- {
- client.CoreV1.ListNamespacedPod("default");
- client.CoreV1.ListNode();
- client.AppsV1.ListNamespacedDeployment("default");
- Thread.Sleep(1000);
- }
- }
- }
-}
diff --git a/examples/resize/Program.cs b/examples/resize/Program.cs
new file mode 100644
index 000000000..85fbeb9b2
--- /dev/null
+++ b/examples/resize/Program.cs
@@ -0,0 +1,63 @@
+using k8s;
+using k8s.Models;
+using System;
+using System.Collections.Generic;
+
+
+var config = KubernetesClientConfiguration.BuildDefaultConfig();
+var client = new Kubernetes(config);
+
+
+var pod = new V1Pod
+{
+ Metadata = new V1ObjectMeta { Name = "nginx-pod" },
+ Spec = new V1PodSpec
+ {
+ Containers =
+ [
+ new V1Container
+ {
+ Name = "nginx",
+ Image = "nginx",
+ Resources = new V1ResourceRequirements
+ {
+ Requests = new Dictionary()
+ {
+ ["cpu"] = "100m",
+ },
+ },
+ },
+ ],
+ },
+};
+{
+ var created = await client.CoreV1.CreateNamespacedPodAsync(pod, "default").ConfigureAwait(false);
+ Console.WriteLine($"Created pod: {created.Metadata.Name}");
+}
+
+{
+ var patchStr = @"
+ {
+ ""spec"": {
+ ""containers"": [
+ {
+ ""name"": ""nginx"",
+ ""resources"": {
+ ""requests"": {
+ ""cpu"": ""200m""
+ }
+ }
+ }
+ ]
+ }
+ }";
+
+ var patch = await client.CoreV1.PatchNamespacedPodResizeAsync(new V1Patch(patchStr, V1Patch.PatchType.MergePatch), "nginx-pod", "default").ConfigureAwait(false);
+
+ if (patch?.Spec?.Containers?.Count > 0 &&
+ patch.Spec.Containers[0].Resources?.Requests != null &&
+ patch.Spec.Containers[0].Resources.Requests.TryGetValue("cpu", out var cpuQty))
+ {
+ Console.WriteLine($"CPU request: {cpuQty}");
+ }
+}
diff --git a/examples/prometheus/prometheus.csproj b/examples/resize/resize.csproj
old mode 100755
new mode 100644
similarity index 88%
rename from examples/prometheus/prometheus.csproj
rename to examples/resize/resize.csproj
index 52e6553de..d1e5b4724
--- a/examples/prometheus/prometheus.csproj
+++ b/examples/resize/resize.csproj
@@ -1,7 +1,5 @@
-
Exe
-
-
+
\ No newline at end of file
diff --git a/examples/restart/Program.cs b/examples/restart/Program.cs
index b6e7a6f22..894e305a6 100644
--- a/examples/restart/Program.cs
+++ b/examples/restart/Program.cs
@@ -1,17 +1,17 @@
-using Json.Patch;
+using Json.Patch;
using k8s;
using k8s.Models;
using System.Text.Json;
async Task RestartDaemonSetAsync(string name, string @namespace, IKubernetes client)
{
- var daemonSet = await client.AppsV1.ReadNamespacedDaemonSetAsync(name, @namespace);
+ var daemonSet = await client.AppsV1.ReadNamespacedDaemonSetAsync(name, @namespace).ConfigureAwait(false);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true };
var old = JsonSerializer.SerializeToDocument(daemonSet, options);
var now = DateTimeOffset.Now.ToUnixTimeSeconds();
var restart = new Dictionary
{
- ["date"] = now.ToString()
+ ["date"] = now.ToString(),
};
daemonSet.Spec.Template.Metadata.Annotations = restart;
@@ -19,18 +19,18 @@ async Task RestartDaemonSetAsync(string name, string @namespace, IKubernetes cli
var expected = JsonSerializer.SerializeToDocument(daemonSet);
var patch = old.CreatePatch(expected);
- await client.AppsV1.PatchNamespacedDaemonSetAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace);
+ await client.AppsV1.PatchNamespacedDaemonSetAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace).ConfigureAwait(false);
}
async Task RestartDeploymentAsync(string name, string @namespace, IKubernetes client)
{
- var deployment = await client.AppsV1.ReadNamespacedDeploymentAsync(name, @namespace);
+ var deployment = await client.AppsV1.ReadNamespacedDeploymentAsync(name, @namespace).ConfigureAwait(false);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true };
var old = JsonSerializer.SerializeToDocument(deployment, options);
var now = DateTimeOffset.Now.ToUnixTimeSeconds();
var restart = new Dictionary
{
- ["date"] = now.ToString()
+ ["date"] = now.ToString(),
};
deployment.Spec.Template.Metadata.Annotations = restart;
@@ -38,18 +38,18 @@ async Task RestartDeploymentAsync(string name, string @namespace, IKubernetes cl
var expected = JsonSerializer.SerializeToDocument(deployment);
var patch = old.CreatePatch(expected);
- await client.AppsV1.PatchNamespacedDeploymentAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace);
+ await client.AppsV1.PatchNamespacedDeploymentAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace).ConfigureAwait(false);
}
async Task RestartStatefulSetAsync(string name, string @namespace, IKubernetes client)
{
- var deployment = await client.AppsV1.ReadNamespacedStatefulSetAsync(name, @namespace);
+ var deployment = await client.AppsV1.ReadNamespacedStatefulSetAsync(name, @namespace).ConfigureAwait(false);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true };
var old = JsonSerializer.SerializeToDocument(deployment, options);
var now = DateTimeOffset.Now.ToUnixTimeSeconds();
var restart = new Dictionary
{
- ["date"] = now.ToString()
+ ["date"] = now.ToString(),
};
deployment.Spec.Template.Metadata.Annotations = restart;
@@ -57,12 +57,12 @@ async Task RestartStatefulSetAsync(string name, string @namespace, IKubernetes c
var expected = JsonSerializer.SerializeToDocument(deployment);
var patch = old.CreatePatch(expected);
- await client.AppsV1.PatchNamespacedStatefulSetAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace);
+ await client.AppsV1.PatchNamespacedStatefulSetAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace).ConfigureAwait(false);
}
var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
IKubernetes client = new Kubernetes(config);
-await RestartDeploymentAsync("event-exporter", "monitoring", client);
-await RestartDaemonSetAsync("prometheus-exporter", "monitoring", client);
-await RestartStatefulSetAsync("argocd-application-controlle", "argocd", client);
+await RestartDeploymentAsync("event-exporter", "monitoring", client).ConfigureAwait(false);
+await RestartDaemonSetAsync("prometheus-exporter", "monitoring", client).ConfigureAwait(false);
+await RestartStatefulSetAsync("argocd-application-controlle", "argocd", client).ConfigureAwait(false);
diff --git a/examples/restart/restart.csproj b/examples/restart/restart.csproj
index 9adb54279..0d5a49c4c 100644
--- a/examples/restart/restart.csproj
+++ b/examples/restart/restart.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/examples/simple/PodList.cs b/examples/simple/PodList.cs
index b9eb3cdcf..751622c16 100755
--- a/examples/simple/PodList.cs
+++ b/examples/simple/PodList.cs
@@ -1,26 +1,17 @@
using k8s;
using System;
-namespace simple
-{
- internal class PodList
- {
- private static void Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildDefaultConfig();
- IKubernetes client = new Kubernetes(config);
- Console.WriteLine("Starting Request!");
+var config = KubernetesClientConfiguration.BuildDefaultConfig();
+IKubernetes client = new Kubernetes(config);
+Console.WriteLine("Starting Request!");
- var list = client.CoreV1.ListNamespacedPod("default");
- foreach (var item in list.Items)
- {
- Console.WriteLine(item.Metadata.Name);
- }
+var list = client.CoreV1.ListNamespacedPod("default");
+foreach (var item in list.Items)
+{
+ Console.WriteLine(item.Metadata.Name);
+}
- if (list.Items.Count == 0)
- {
- Console.WriteLine("Empty!");
- }
- }
- }
+if (list.Items.Count == 0)
+{
+ Console.WriteLine("Empty!");
}
diff --git a/examples/watch/Program.cs b/examples/watch/Program.cs
index 525cbec5c..1aff65883 100644
--- a/examples/watch/Program.cs
+++ b/examples/watch/Program.cs
@@ -1,50 +1,39 @@
using k8s;
-using k8s.Models;
using System;
using System.Threading;
using System.Threading.Tasks;
-namespace watch
-{
- internal class Program
- {
- private static async Task Main(string[] args)
- {
- var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
+var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
- IKubernetes client = new Kubernetes(config);
+IKubernetes client = new Kubernetes(config);
- var podlistResp = client.CoreV1.ListNamespacedPodWithHttpMessagesAsync("default", watch: true);
- // C# 8 required https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8
- await foreach (var (type, item) in podlistResp.WatchAsync())
- {
- Console.WriteLine("==on watch event==");
- Console.WriteLine(type);
- Console.WriteLine(item.Metadata.Name);
- Console.WriteLine("==on watch event==");
- }
+var podlistResp = client.CoreV1.WatchListNamespacedPodAsync("default");
- // uncomment if you prefer callback api
- // WatchUsingCallback(client);
- }
+// C# 8 required https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8
+await foreach (var (type, item) in podlistResp.ConfigureAwait(false))
+{
+ Console.WriteLine("==on watch event==");
+ Console.WriteLine(type);
+ Console.WriteLine(item.Metadata.Name);
+ Console.WriteLine("==on watch event==");
+}
- private static void WatchUsingCallback(IKubernetes client)
- {
- var podlistResp = client.CoreV1.ListNamespacedPodWithHttpMessagesAsync("default", watch: true);
- using (podlistResp.Watch((type, item) =>
- {
- Console.WriteLine("==on watch event==");
- Console.WriteLine(type);
- Console.WriteLine(item.Metadata.Name);
- Console.WriteLine("==on watch event==");
- }))
- {
- Console.WriteLine("press ctrl + c to stop watching");
+#pragma warning disable CS8321 // Remove unused private members
+void WatchUsingCallback(IKubernetes client)
+#pragma warning restore CS8321 // Remove unused private members
+{
+ using (var podlistResp = client.CoreV1.WatchListNamespacedPod("default", onEvent: (type, item) =>
+ {
+ Console.WriteLine("==on watch event==");
+ Console.WriteLine(type);
+ Console.WriteLine(item.Metadata.Name);
+ Console.WriteLine("==on watch event==");
+ }))
+ {
+ Console.WriteLine("press ctrl + c to stop watching");
- var ctrlc = new ManualResetEventSlim(false);
- Console.CancelKeyPress += (sender, eventArgs) => ctrlc.Set();
- ctrlc.Wait();
- }
- }
+ var ctrlc = new ManualResetEventSlim(false);
+ Console.CancelKeyPress += (sender, eventArgs) => ctrlc.Set();
+ ctrlc.Wait();
}
-}
+}
\ No newline at end of file
diff --git a/examples/webApiDependencyInjection/Controllers/ExampleDependencyInjectionOnConstructorController.cs b/examples/webApiDependencyInjection/Controllers/ExampleDependencyInjectionOnConstructorController.cs
index 30fd2656c..6bff6df0d 100644
--- a/examples/webApiDependencyInjection/Controllers/ExampleDependencyInjectionOnConstructorController.cs
+++ b/examples/webApiDependencyInjection/Controllers/ExampleDependencyInjectionOnConstructorController.cs
@@ -10,22 +10,23 @@ public class ExampleDependencyInjectionOnConstructorController : ControllerBase
private readonly IKubernetes kubernetesClient;
///
- /// Inject the kubernets class in the constructor.
+ /// Initializes a new instance of the class.
+ /// Injects the Kubernetes client into the controller.
///
- ///
+ /// The Kubernetes client to interact with the Kubernetes API.
public ExampleDependencyInjectionOnConstructorController(IKubernetes kubernetesClient)
{
this.kubernetesClient = kubernetesClient;
}
///
- /// Example using the kubernetes client obtained from the constructor (this.kubernetesClient).
+ /// Retrieves the names of all pods in the default namespace using the injected Kubernetes client.
///
- ///
- [HttpGet()]
+ /// A collection of pod names in the default namespace.
+ [HttpGet]
public IEnumerable GetPods()
{
- // Read the list of pods contained in default namespace
+ // Read the list of pods contained in the default namespace
var podList = this.kubernetesClient.CoreV1.ListNamespacedPod("default");
// Return names of pods
diff --git a/examples/webApiDependencyInjection/Controllers/ExampleDependencyInjectionOnMethodController.cs b/examples/webApiDependencyInjection/Controllers/ExampleDependencyInjectionOnMethodController.cs
index 0a831befb..84427f5e2 100644
--- a/examples/webApiDependencyInjection/Controllers/ExampleDependencyInjectionOnMethodController.cs
+++ b/examples/webApiDependencyInjection/Controllers/ExampleDependencyInjectionOnMethodController.cs
@@ -10,11 +10,13 @@ public class ExampleDependencyInjectionOnMethodController : ControllerBase
///
/// Example using the kubernetes client injected directly into the method ([FromServices] IKubernetes kubernetesClient).
///
- ///
- ///
- [HttpGet()]
+ /// The Kubernetes client instance injected via dependency injection.
+ /// A collection of pod names in the default namespace.
+ [HttpGet]
public IEnumerable GetPods([FromServices] IKubernetes kubernetesClient)
{
+ ArgumentNullException.ThrowIfNull(kubernetesClient);
+
// Read the list of pods contained in default namespace
var podList = kubernetesClient.CoreV1.ListNamespacedPod("default");
diff --git a/examples/webApiDependencyInjection/webApiDependencyInjection.csproj b/examples/webApiDependencyInjection/webApiDependencyInjection.csproj
index 43064ecb1..23e466d7e 100644
--- a/examples/webApiDependencyInjection/webApiDependencyInjection.csproj
+++ b/examples/webApiDependencyInjection/webApiDependencyInjection.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/examples/workerServiceDependencyInjection/Program.cs b/examples/workerServiceDependencyInjection/Program.cs
index 59bf3cf25..a894a33fe 100644
--- a/examples/workerServiceDependencyInjection/Program.cs
+++ b/examples/workerServiceDependencyInjection/Program.cs
@@ -14,4 +14,4 @@
})
.Build();
-await host.RunAsync();
+await host.RunAsync().ConfigureAwait(false);
diff --git a/examples/workerServiceDependencyInjection/Worker.cs b/examples/workerServiceDependencyInjection/Worker.cs
index 87d2ecfe2..cb2f82386 100644
--- a/examples/workerServiceDependencyInjection/Worker.cs
+++ b/examples/workerServiceDependencyInjection/Worker.cs
@@ -8,10 +8,11 @@ public class Worker : BackgroundService
private readonly IKubernetes kubernetesClient;
///
+ /// Initializes a new instance of the class.
/// Inject in the constructor the IKubernetes interface.
///
- ///
- ///
+ /// The logger instance used for logging information.
+ /// The Kubernetes client used to interact with the Kubernetes API.
public Worker(ILogger logger, IKubernetes kubernetesClient)
{
this.logger = logger;
@@ -33,7 +34,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
Console.WriteLine(pod.Metadata.Name);
}
- await Task.Delay(1000, stoppingToken);
+ await Task.Delay(1000, stoppingToken).ConfigureAwait(false);
}
}
}
diff --git a/examples/workerServiceDependencyInjection/workerServiceDependencyInjection.csproj b/examples/workerServiceDependencyInjection/workerServiceDependencyInjection.csproj
index accf7dd56..84522ab7c 100644
--- a/examples/workerServiceDependencyInjection/workerServiceDependencyInjection.csproj
+++ b/examples/workerServiceDependencyInjection/workerServiceDependencyInjection.csproj
@@ -6,6 +6,6 @@
-
+
diff --git a/examples/yaml/Program.cs b/examples/yaml/Program.cs
index a724f3083..47b70bdfe 100644
--- a/examples/yaml/Program.cs
+++ b/examples/yaml/Program.cs
@@ -2,25 +2,17 @@
using k8s.Models;
using System;
using System.Collections.Generic;
-using System.Threading.Tasks;
-namespace yaml
+var typeMap = new Dictionary
{
- internal class Program
- {
- private static async Task Main(string[] args)
- {
- var typeMap = new Dictionary();
- typeMap.Add("v1/Pod", typeof(V1Pod));
- typeMap.Add("v1/Service", typeof(V1Service));
- typeMap.Add("apps/v1/Deployment", typeof(V1Deployment));
+ { "v1/Pod", typeof(V1Pod) },
+ { "v1/Service", typeof(V1Service) },
+ { "apps/v1/Deployment", typeof(V1Deployment) },
+};
- var objects = await KubernetesYaml.LoadAllFromFileAsync(args[0], typeMap);
+var objects = await KubernetesYaml.LoadAllFromFileAsync(args[0], typeMap).ConfigureAwait(false);
- foreach (var obj in objects)
- {
- Console.WriteLine(obj);
- }
- }
- }
+foreach (var obj in objects)
+{
+ Console.WriteLine(obj);
}
diff --git a/global.json b/global.json
index ed66463ef..101665708 100644
--- a/global.json
+++ b/global.json
@@ -1,10 +1,9 @@
-
{
- "sdk": {
- "version": "6.0.400",
- "rollForward": "latestMajor"
- },
- "msbuild-sdks": {
- "Microsoft.Build.Traversal" : "3.1.6"
- }
+ "sdk": {
+ "version": "8.0.100",
+ "rollForward": "latestMajor"
+ },
+ "msbuild-sdks": {
+ "Microsoft.Build.Traversal": "4.1.0"
+ }
}
diff --git a/kubernetes-client.proj b/kubernetes-client.proj
new file mode 100644
index 000000000..9f634d328
--- /dev/null
+++ b/kubernetes-client.proj
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kubernetes-client.ruleset b/kubernetes-client.ruleset
index f1221e98d..8baea16b9 100644
--- a/kubernetes-client.ruleset
+++ b/kubernetes-client.ruleset
@@ -51,9 +51,6 @@
-
-
-
diff --git a/kubernetes-client.sln b/kubernetes-client.sln
deleted file mode 100644
index 698be9190..000000000
--- a/kubernetes-client.sln
+++ /dev/null
@@ -1,496 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31903.59
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{B70AFB57-57C9-46DC-84BE-11B7DDD34B40}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "attach", "examples\attach\attach.csproj", "{87CD4259-88DC-4748-AC61-CDDFB6E02891}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "exec", "examples\exec\exec.csproj", "{0044011C-25A6-4303-AA3F-877244B51ABB}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "labels", "examples\labels\labels.csproj", "{D5471F2E-F522-47E7-B3D2-F98A4452E214}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "logs", "examples\logs\logs.csproj", "{4BD050E8-B0E4-40B4-AC72-5130D81095C7}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "namespace", "examples\namespace\namespace.csproj", "{1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "simple", "examples\simple\simple.csproj", "{DDB14203-DD5B-452A-A1E0-9FD98629101F}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "watch", "examples\watch\watch.csproj", "{1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3D1864AA-1FFC-4512-BB13-46055E410F73}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient", "src\KubernetesClient\KubernetesClient.csproj", "{35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Tests", "tests\KubernetesClient.Tests\KubernetesClient.Tests.csproj", "{806AD0E5-833F-42FB-A870-4BCEE7F4B17F}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "patch", "examples\patch\patch.csproj", "{04DE2C84-117D-4E21-8B45-B7AE627697BD}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "metrics", "examples\metrics\metrics.csproj", "{B9647AD4-F6B0-406F-8B79-6781E31600EC}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "E2E.Tests", "tests\E2E.Tests\E2E.Tests.csproj", "{5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkipTestLogger", "tests\SkipTestLogger\SkipTestLogger.csproj", "{4D2AE427-F856-49E5-B61D-EA6B17D89051}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "customResource", "examples\customResource\customResource.csproj", "{95672061-5799-4454-ACDB-D6D330DB1EC4}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "generic", "examples\generic\generic.csproj", "{F06D4C3A-7825-43A8-832B-6BDE3D355486}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibKubernetesGenerator", "src\LibKubernetesGenerator\LibKubernetesGenerator.csproj", "{64C71596-B916-46EF-8115-B53E238F79D4}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "portforward", "examples\portforward\portforward.csproj", "{DFBB1025-BD22-459D-A04D-E2AB31E129E2}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "prometheus", "examples\prometheus\prometheus.csproj", "{682B94E4-1761-48FF-B5D0-87B45DC0C735}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "yaml", "examples\yaml\yaml.csproj", "{17AB0AD8-6C90-42DD-880C-16B5AC4A373F}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Models", "src\KubernetesClient.Models\KubernetesClient.Models.csproj", "{F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Basic", "src\KubernetesClient.Basic\KubernetesClient.Basic.csproj", "{927995F5-05CC-4078-8805-8E6CC06914D8}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Classic", "src\KubernetesClient.Classic\KubernetesClient.Classic.csproj", "{80F19E8A-F097-4AA4-A68C-D417B96BBC68}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Classic.Tests", "tests\KubernetesClient.Classic.Tests\KubernetesClient.Classic.Tests.csproj", "{FD90C861-56C6-4536-B7F5-AC7779296384}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "csrApproval", "examples\csrApproval\csrApproval.csproj", "{F626860C-F141-45B3-9DDD-88AD3932ACAF}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "restart", "examples\restart\restart.csproj", "{973CCB4A-F344-4C4F-81A5-0F40F7F43C07}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Kubectl", "src\KubernetesClient.Kubectl\KubernetesClient.Kubectl.csproj", "{21201F30-5463-4FC6-93C3-FBF157F0D46C}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kubectl.Tests", "tests\Kubectl.Tests\Kubectl.Tests.csproj", "{9128F6DC-6B7A-417F-937A-90461D6989A8}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "openTelemetryConsole", "examples\openTelemetryConsole\openTelemetryConsole.csproj", "{8E266190-AE6E-44A8-948D-BD974AA82428}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "webApiDependencyInjection", "examples\webApiDependencyInjection\webApiDependencyInjection.csproj", "{C0759F88-A010-4DEF-BD3B-E183D3328FFC}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "workerServiceDependencyInjection", "examples\workerServiceDependencyInjection\workerServiceDependencyInjection.csproj", "{05DC8884-AC54-4603-AC25-AE9D9F24E7AE}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cp", "examples\cp\cp.csproj", "{CC41E248-2139-427E-8DD4-B047A8924FD2}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Debug|x64.ActiveCfg = Debug|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Debug|x64.Build.0 = Debug|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Debug|x86.ActiveCfg = Debug|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Debug|x86.Build.0 = Debug|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Release|Any CPU.Build.0 = Release|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Release|x64.ActiveCfg = Release|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Release|x64.Build.0 = Release|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Release|x86.ActiveCfg = Release|Any CPU
- {87CD4259-88DC-4748-AC61-CDDFB6E02891}.Release|x86.Build.0 = Release|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Debug|x64.ActiveCfg = Debug|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Debug|x64.Build.0 = Debug|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Debug|x86.ActiveCfg = Debug|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Debug|x86.Build.0 = Debug|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Release|Any CPU.Build.0 = Release|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Release|x64.ActiveCfg = Release|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Release|x64.Build.0 = Release|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Release|x86.ActiveCfg = Release|Any CPU
- {0044011C-25A6-4303-AA3F-877244B51ABB}.Release|x86.Build.0 = Release|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Debug|x64.ActiveCfg = Debug|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Debug|x64.Build.0 = Debug|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Debug|x86.ActiveCfg = Debug|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Debug|x86.Build.0 = Debug|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Release|Any CPU.Build.0 = Release|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Release|x64.ActiveCfg = Release|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Release|x64.Build.0 = Release|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Release|x86.ActiveCfg = Release|Any CPU
- {D5471F2E-F522-47E7-B3D2-F98A4452E214}.Release|x86.Build.0 = Release|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Debug|x64.ActiveCfg = Debug|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Debug|x64.Build.0 = Debug|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Debug|x86.ActiveCfg = Debug|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Debug|x86.Build.0 = Debug|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Release|Any CPU.Build.0 = Release|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Release|x64.ActiveCfg = Release|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Release|x64.Build.0 = Release|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Release|x86.ActiveCfg = Release|Any CPU
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7}.Release|x86.Build.0 = Release|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Debug|x64.Build.0 = Debug|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Debug|x86.Build.0 = Debug|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Release|Any CPU.Build.0 = Release|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Release|x64.ActiveCfg = Release|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Release|x64.Build.0 = Release|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Release|x86.ActiveCfg = Release|Any CPU
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68}.Release|x86.Build.0 = Release|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Debug|x64.ActiveCfg = Debug|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Debug|x64.Build.0 = Debug|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Debug|x86.ActiveCfg = Debug|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Debug|x86.Build.0 = Debug|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Release|Any CPU.Build.0 = Release|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Release|x64.ActiveCfg = Release|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Release|x64.Build.0 = Release|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Release|x86.ActiveCfg = Release|Any CPU
- {DDB14203-DD5B-452A-A1E0-9FD98629101F}.Release|x86.Build.0 = Release|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Debug|x64.Build.0 = Debug|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Debug|x86.Build.0 = Debug|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Release|Any CPU.Build.0 = Release|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Release|x64.ActiveCfg = Release|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Release|x64.Build.0 = Release|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Release|x86.ActiveCfg = Release|Any CPU
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5}.Release|x86.Build.0 = Release|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Debug|x64.ActiveCfg = Debug|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Debug|x64.Build.0 = Debug|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Debug|x86.ActiveCfg = Debug|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Debug|x86.Build.0 = Debug|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Release|Any CPU.Build.0 = Release|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Release|x64.ActiveCfg = Release|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Release|x64.Build.0 = Release|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Release|x86.ActiveCfg = Release|Any CPU
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7}.Release|x86.Build.0 = Release|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Debug|x64.ActiveCfg = Debug|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Debug|x64.Build.0 = Debug|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Debug|x86.ActiveCfg = Debug|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Debug|x86.Build.0 = Debug|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Release|Any CPU.Build.0 = Release|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Release|x64.ActiveCfg = Release|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Release|x64.Build.0 = Release|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Release|x86.ActiveCfg = Release|Any CPU
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F}.Release|x86.Build.0 = Release|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Debug|x64.ActiveCfg = Debug|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Debug|x64.Build.0 = Debug|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Debug|x86.ActiveCfg = Debug|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Debug|x86.Build.0 = Debug|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|Any CPU.Build.0 = Release|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|x64.ActiveCfg = Release|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|x64.Build.0 = Release|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|x86.ActiveCfg = Release|Any CPU
- {04DE2C84-117D-4E21-8B45-B7AE627697BD}.Release|x86.Build.0 = Release|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Debug|x64.ActiveCfg = Debug|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Debug|x64.Build.0 = Debug|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Debug|x86.ActiveCfg = Debug|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Debug|x86.Build.0 = Debug|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Release|Any CPU.Build.0 = Release|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Release|x64.ActiveCfg = Release|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Release|x64.Build.0 = Release|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Release|x86.ActiveCfg = Release|Any CPU
- {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Release|x86.Build.0 = Release|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|x64.ActiveCfg = Debug|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|x64.Build.0 = Debug|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|x86.ActiveCfg = Debug|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|x86.Build.0 = Debug|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|Any CPU.Build.0 = Release|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|x64.ActiveCfg = Release|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|x64.Build.0 = Release|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|x86.ActiveCfg = Release|Any CPU
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|x86.Build.0 = Release|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|x64.ActiveCfg = Debug|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|x64.Build.0 = Debug|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|x86.ActiveCfg = Debug|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|x86.Build.0 = Debug|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|Any CPU.Build.0 = Release|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|x64.ActiveCfg = Release|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|x64.Build.0 = Release|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|x86.ActiveCfg = Release|Any CPU
- {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|x86.Build.0 = Release|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Debug|x64.ActiveCfg = Debug|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Debug|x64.Build.0 = Debug|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Debug|x86.ActiveCfg = Debug|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Debug|x86.Build.0 = Debug|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Release|Any CPU.Build.0 = Release|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Release|x64.ActiveCfg = Release|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Release|x64.Build.0 = Release|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Release|x86.ActiveCfg = Release|Any CPU
- {95672061-5799-4454-ACDB-D6D330DB1EC4}.Release|x86.Build.0 = Release|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Debug|x64.Build.0 = Debug|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Debug|x86.Build.0 = Debug|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Release|Any CPU.Build.0 = Release|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Release|x64.ActiveCfg = Release|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Release|x64.Build.0 = Release|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Release|x86.ActiveCfg = Release|Any CPU
- {F06D4C3A-7825-43A8-832B-6BDE3D355486}.Release|x86.Build.0 = Release|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Debug|x64.ActiveCfg = Debug|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Debug|x64.Build.0 = Debug|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Debug|x86.ActiveCfg = Debug|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Debug|x86.Build.0 = Debug|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Release|Any CPU.Build.0 = Release|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Release|x64.ActiveCfg = Release|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Release|x64.Build.0 = Release|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Release|x86.ActiveCfg = Release|Any CPU
- {64C71596-B916-46EF-8115-B53E238F79D4}.Release|x86.Build.0 = Release|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Debug|x64.ActiveCfg = Debug|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Debug|x64.Build.0 = Debug|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Debug|x86.ActiveCfg = Debug|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Debug|x86.Build.0 = Debug|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Release|Any CPU.Build.0 = Release|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Release|x64.ActiveCfg = Release|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Release|x64.Build.0 = Release|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Release|x86.ActiveCfg = Release|Any CPU
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2}.Release|x86.Build.0 = Release|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Debug|x64.ActiveCfg = Debug|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Debug|x64.Build.0 = Debug|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Debug|x86.ActiveCfg = Debug|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Debug|x86.Build.0 = Debug|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Release|Any CPU.Build.0 = Release|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Release|x64.ActiveCfg = Release|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Release|x64.Build.0 = Release|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Release|x86.ActiveCfg = Release|Any CPU
- {682B94E4-1761-48FF-B5D0-87B45DC0C735}.Release|x86.Build.0 = Release|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Debug|x64.ActiveCfg = Debug|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Debug|x64.Build.0 = Debug|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Debug|x86.ActiveCfg = Debug|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Debug|x86.Build.0 = Debug|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Release|Any CPU.Build.0 = Release|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Release|x64.ActiveCfg = Release|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Release|x64.Build.0 = Release|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Release|x86.ActiveCfg = Release|Any CPU
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F}.Release|x86.Build.0 = Release|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Debug|x64.Build.0 = Debug|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Debug|x86.Build.0 = Debug|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Release|Any CPU.Build.0 = Release|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Release|x64.ActiveCfg = Release|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Release|x64.Build.0 = Release|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Release|x86.ActiveCfg = Release|Any CPU
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}.Release|x86.Build.0 = Release|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Debug|x64.ActiveCfg = Debug|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Debug|x64.Build.0 = Debug|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Debug|x86.ActiveCfg = Debug|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Debug|x86.Build.0 = Debug|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Release|Any CPU.Build.0 = Release|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Release|x64.ActiveCfg = Release|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Release|x64.Build.0 = Release|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Release|x86.ActiveCfg = Release|Any CPU
- {927995F5-05CC-4078-8805-8E6CC06914D8}.Release|x86.Build.0 = Release|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x64.ActiveCfg = Debug|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x64.Build.0 = Debug|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x86.ActiveCfg = Debug|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x86.Build.0 = Debug|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|Any CPU.Build.0 = Release|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x64.ActiveCfg = Release|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x64.Build.0 = Release|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x86.ActiveCfg = Release|Any CPU
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x86.Build.0 = Release|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x64.ActiveCfg = Debug|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x64.Build.0 = Debug|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x86.ActiveCfg = Debug|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x86.Build.0 = Debug|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Release|Any CPU.Build.0 = Release|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x64.ActiveCfg = Release|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x64.Build.0 = Release|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x86.ActiveCfg = Release|Any CPU
- {FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x86.Build.0 = Release|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|x64.Build.0 = Debug|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|x86.Build.0 = Debug|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Release|Any CPU.Build.0 = Release|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Release|x64.ActiveCfg = Release|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Release|x64.Build.0 = Release|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Release|x86.ActiveCfg = Release|Any CPU
- {F626860C-F141-45B3-9DDD-88AD3932ACAF}.Release|x86.Build.0 = Release|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Debug|x64.ActiveCfg = Debug|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Debug|x64.Build.0 = Debug|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Debug|x86.ActiveCfg = Debug|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Debug|x86.Build.0 = Debug|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Release|Any CPU.Build.0 = Release|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Release|x64.ActiveCfg = Release|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Release|x64.Build.0 = Release|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Release|x86.ActiveCfg = Release|Any CPU
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07}.Release|x86.Build.0 = Release|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Debug|x64.ActiveCfg = Debug|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Debug|x64.Build.0 = Debug|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Debug|x86.ActiveCfg = Debug|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Debug|x86.Build.0 = Debug|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Release|Any CPU.Build.0 = Release|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Release|x64.ActiveCfg = Release|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Release|x64.Build.0 = Release|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Release|x86.ActiveCfg = Release|Any CPU
- {21201F30-5463-4FC6-93C3-FBF157F0D46C}.Release|x86.Build.0 = Release|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Debug|x64.ActiveCfg = Debug|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Debug|x64.Build.0 = Debug|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Debug|x86.ActiveCfg = Debug|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Debug|x86.Build.0 = Debug|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Release|Any CPU.Build.0 = Release|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Release|x64.ActiveCfg = Release|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Release|x64.Build.0 = Release|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Release|x86.ActiveCfg = Release|Any CPU
- {9128F6DC-6B7A-417F-937A-90461D6989A8}.Release|x86.Build.0 = Release|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Debug|x64.ActiveCfg = Debug|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Debug|x64.Build.0 = Debug|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Debug|x86.ActiveCfg = Debug|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Debug|x86.Build.0 = Debug|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Release|Any CPU.Build.0 = Release|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Release|x64.ActiveCfg = Release|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Release|x64.Build.0 = Release|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Release|x86.ActiveCfg = Release|Any CPU
- {8E266190-AE6E-44A8-948D-BD974AA82428}.Release|x86.Build.0 = Release|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Debug|x64.ActiveCfg = Debug|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Debug|x64.Build.0 = Debug|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Debug|x86.ActiveCfg = Debug|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Debug|x86.Build.0 = Debug|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Release|Any CPU.Build.0 = Release|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Release|x64.ActiveCfg = Release|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Release|x64.Build.0 = Release|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Release|x86.ActiveCfg = Release|Any CPU
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC}.Release|x86.Build.0 = Release|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Debug|x64.ActiveCfg = Debug|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Debug|x64.Build.0 = Debug|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Debug|x86.ActiveCfg = Debug|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Debug|x86.Build.0 = Debug|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Release|Any CPU.Build.0 = Release|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Release|x64.ActiveCfg = Release|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Release|x64.Build.0 = Release|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Release|x86.ActiveCfg = Release|Any CPU
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE}.Release|x86.Build.0 = Release|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Debug|x64.ActiveCfg = Debug|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Debug|x64.Build.0 = Debug|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Debug|x86.ActiveCfg = Debug|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Debug|x86.Build.0 = Debug|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Release|Any CPU.Build.0 = Release|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Release|x64.ActiveCfg = Release|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Release|x64.Build.0 = Release|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Release|x86.ActiveCfg = Release|Any CPU
- {CC41E248-2139-427E-8DD4-B047A8924FD2}.Release|x86.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {87CD4259-88DC-4748-AC61-CDDFB6E02891} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {0044011C-25A6-4303-AA3F-877244B51ABB} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {D5471F2E-F522-47E7-B3D2-F98A4452E214} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {4BD050E8-B0E4-40B4-AC72-5130D81095C7} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {1AA79D75-E7C4-4C0C-928B-FB12EC3CBF68} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {DDB14203-DD5B-452A-A1E0-9FD98629101F} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {1DDB0CCF-7CCE-4A60-BAC6-9AE1779DEDB5} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {35DD7248-F9EC-4272-A32C-B0C59E5A6FA7} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
- {806AD0E5-833F-42FB-A870-4BCEE7F4B17F} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}
- {04DE2C84-117D-4E21-8B45-B7AE627697BD} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {B9647AD4-F6B0-406F-8B79-6781E31600EC} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}
- {4D2AE427-F856-49E5-B61D-EA6B17D89051} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}
- {95672061-5799-4454-ACDB-D6D330DB1EC4} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {F06D4C3A-7825-43A8-832B-6BDE3D355486} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {64C71596-B916-46EF-8115-B53E238F79D4} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
- {DFBB1025-BD22-459D-A04D-E2AB31E129E2} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {682B94E4-1761-48FF-B5D0-87B45DC0C735} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {17AB0AD8-6C90-42DD-880C-16B5AC4A373F} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
- {927995F5-05CC-4078-8805-8E6CC06914D8} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
- {80F19E8A-F097-4AA4-A68C-D417B96BBC68} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
- {FD90C861-56C6-4536-B7F5-AC7779296384} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}
- {F626860C-F141-45B3-9DDD-88AD3932ACAF} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {973CCB4A-F344-4C4F-81A5-0F40F7F43C07} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {21201F30-5463-4FC6-93C3-FBF157F0D46C} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
- {9128F6DC-6B7A-417F-937A-90461D6989A8} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}
- {8E266190-AE6E-44A8-948D-BD974AA82428} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {C0759F88-A010-4DEF-BD3B-E183D3328FFC} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {05DC8884-AC54-4603-AC25-AE9D9F24E7AE} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- {CC41E248-2139-427E-8DD4-B047A8924FD2} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {049A763A-C891-4E8D-80CF-89DD3E22ADC7}
- EndGlobalSection
-EndGlobal
diff --git a/src/KubernetesClient.Basic/Global.cs b/src/KubernetesClient.Aot/Global.cs
similarity index 75%
rename from src/KubernetesClient.Basic/Global.cs
rename to src/KubernetesClient.Aot/Global.cs
index d91efcf78..2b5a4ae8e 100644
--- a/src/KubernetesClient.Basic/Global.cs
+++ b/src/KubernetesClient.Aot/Global.cs
@@ -1,8 +1,10 @@
-global using System;
-global using System.Collections.Generic;
-global using System.Linq;
global using k8s.Autorest;
global using k8s.Models;
+global using System;
+global using System.Collections.Generic;
global using System.IO;
+global using System.Linq;
+global using System.Text.Json;
+global using System.Text.Json.Serialization;
global using System.Threading;
global using System.Threading.Tasks;
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/AuthProvider.cs b/src/KubernetesClient.Aot/KubeConfigModels/AuthProvider.cs
new file mode 100644
index 000000000..5bec9095e
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/AuthProvider.cs
@@ -0,0 +1,23 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels
+{
+ ///
+ /// Contains information that describes identity information. This is use to tell the kubernetes cluster who you are.
+ ///
+ [YamlSerializable]
+ public class AuthProvider
+ {
+ ///
+ /// Gets or sets the nickname for this auth provider.
+ ///
+ [YamlMember(Alias = "name")]
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the configuration for this auth provider
+ ///
+ [YamlMember(Alias = "config")]
+ public Dictionary Config { get; set; }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/Cluster.cs b/src/KubernetesClient.Aot/KubeConfigModels/Cluster.cs
new file mode 100644
index 000000000..80faf96a5
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/Cluster.cs
@@ -0,0 +1,23 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels
+{
+ ///
+ /// Relates nicknames to cluster information.
+ ///
+ [YamlSerializable]
+ public class Cluster
+ {
+ ///
+ /// Gets or sets the cluster information.
+ ///
+ [YamlMember(Alias = "cluster")]
+ public ClusterEndpoint ClusterEndpoint { get; set; }
+
+ ///
+ /// Gets or sets the nickname for this Cluster.
+ ///
+ [YamlMember(Alias = "name")]
+ public string Name { get; set; }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/ClusterEndpoint.cs b/src/KubernetesClient.Aot/KubeConfigModels/ClusterEndpoint.cs
new file mode 100644
index 000000000..c40827651
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/ClusterEndpoint.cs
@@ -0,0 +1,42 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels
+{
+ ///
+ /// Contains information about how to communicate with a kubernetes cluster
+ ///
+ [YamlSerializable]
+ public class ClusterEndpoint
+ {
+ ///
+ /// Gets or sets the path to a cert file for the certificate authority.
+ ///
+ [YamlMember(Alias = "certificate-authority", ApplyNamingConventions = false)]
+ public string CertificateAuthority { get; set; }
+
+ ///
+ /// Gets or sets =PEM-encoded certificate authority certificates. Overrides .
+ ///
+ [YamlMember(Alias = "certificate-authority-data", ApplyNamingConventions = false)]
+ public string CertificateAuthorityData { get; set; }
+
+ ///
+ /// Gets or sets the address of the kubernetes cluster (https://hostname:port).
+ ///
+ [YamlMember(Alias = "server")]
+ public string Server { get; set; }
+
+ ///
+ /// Gets or sets a value to override the TLS server name.
+ ///
+ [YamlMember(Alias = "tls-server-name", ApplyNamingConventions = false)]
+ public string TlsServerName { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to skip the validity check for the server's certificate.
+ /// This will make your HTTPS connections insecure.
+ ///
+ [YamlMember(Alias = "insecure-skip-tls-verify", ApplyNamingConventions = false)]
+ public bool SkipTlsVerify { get; set; }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/Context.cs b/src/KubernetesClient.Aot/KubeConfigModels/Context.cs
new file mode 100644
index 000000000..65241315f
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/Context.cs
@@ -0,0 +1,23 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels
+{
+ ///
+ /// Relates nicknames to context information.
+ ///
+ [YamlSerializable]
+ public class Context
+ {
+ ///
+ /// Gets or sets the context information.
+ ///
+ [YamlMember(Alias = "context")]
+ public ContextDetails ContextDetails { get; set; }
+
+ ///
+ /// Gets or sets the nickname for this context.
+ ///
+ [YamlMember(Alias = "name")]
+ public string Name { get; set; }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/ContextDetails.cs b/src/KubernetesClient.Aot/KubeConfigModels/ContextDetails.cs
new file mode 100644
index 000000000..ca2bf1e07
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/ContextDetails.cs
@@ -0,0 +1,30 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels
+{
+ ///
+ /// Represents a tuple of references to a cluster (how do I communicate with a kubernetes cluster),
+ /// a user (how do I identify myself), and a namespace (what subset of resources do I want to work with)
+ ///
+ [YamlSerializable]
+ public class ContextDetails
+ {
+ ///
+ /// Gets or sets the name of the cluster for this context.
+ ///
+ [YamlMember(Alias = "cluster")]
+ public string Cluster { get; set; }
+
+ ///
+ /// Gets or sets the name of the user for this context.
+ ///
+ [YamlMember(Alias = "user")]
+ public string User { get; set; }
+
+ ///
+ /// /Gets or sets the default namespace to use on unspecified requests.
+ ///
+ [YamlMember(Alias = "namespace")]
+ public string Namespace { get; set; }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/ExecCredentialResponse.cs b/src/KubernetesClient.Aot/KubeConfigModels/ExecCredentialResponse.cs
new file mode 100644
index 000000000..d593ff4f6
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/ExecCredentialResponse.cs
@@ -0,0 +1,35 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels
+{
+ [YamlSerializable]
+ public class ExecCredentialResponse
+ {
+ public class ExecStatus
+ {
+#nullable enable
+ [JsonPropertyName("expirationTimestamp")]
+ public DateTime? ExpirationTimestamp { get; set; }
+ [JsonPropertyName("token")]
+ public string? Token { get; set; }
+ [JsonPropertyName("clientCertificateData")]
+ public string? ClientCertificateData { get; set; }
+ [JsonPropertyName("clientKeyData")]
+ public string? ClientKeyData { get; set; }
+#nullable disable
+
+ public bool IsValid()
+ {
+ return !string.IsNullOrEmpty(Token) ||
+ (!string.IsNullOrEmpty(ClientCertificateData) && !string.IsNullOrEmpty(ClientKeyData));
+ }
+ }
+
+ [JsonPropertyName("apiVersion")]
+ public string ApiVersion { get; set; }
+ [JsonPropertyName("kind")]
+ public string Kind { get; set; }
+ [JsonPropertyName("status")]
+ public ExecStatus Status { get; set; }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/ExecCredentialResponseContext.cs b/src/KubernetesClient.Aot/KubeConfigModels/ExecCredentialResponseContext.cs
new file mode 100644
index 000000000..c7ffd8294
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/ExecCredentialResponseContext.cs
@@ -0,0 +1,7 @@
+namespace k8s.KubeConfigModels
+{
+ [JsonSerializable(typeof(ExecCredentialResponse))]
+ internal partial class ExecCredentialResponseContext : JsonSerializerContext
+ {
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/ExternalExecution.cs b/src/KubernetesClient.Aot/KubeConfigModels/ExternalExecution.cs
new file mode 100644
index 000000000..7e18f449e
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/ExternalExecution.cs
@@ -0,0 +1,42 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels
+{
+ [YamlSerializable]
+ public class ExternalExecution
+ {
+ [YamlMember(Alias = "apiVersion")]
+ public string ApiVersion { get; set; }
+
+ ///
+ /// The command to execute. Required.
+ ///
+ [YamlMember(Alias = "command")]
+ public string Command { get; set; }
+
+ ///
+ /// Environment variables to set when executing the plugin. Optional.
+ ///
+ [YamlMember(Alias = "env")]
+ public IList> EnvironmentVariables { get; set; }
+
+ ///
+ /// Arguments to pass when executing the plugin. Optional.
+ ///
+ [YamlMember(Alias = "args")]
+ public IList Arguments { get; set; }
+
+ ///
+ /// Text shown to the user when the executable doesn't seem to be present. Optional.
+ ///
+ [YamlMember(Alias = "installHint")]
+ public string InstallHint { get; set; }
+
+ ///
+ /// Whether or not to provide cluster information to this exec plugin as a part of
+ /// the KUBERNETES_EXEC_INFO environment variable. Optional.
+ ///
+ [YamlMember(Alias = "provideClusterInfo")]
+ public bool ProvideClusterInfo { get; set; }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/K8SConfiguration.cs b/src/KubernetesClient.Aot/KubeConfigModels/K8SConfiguration.cs
new file mode 100644
index 000000000..a0c3a4fef
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/K8SConfiguration.cs
@@ -0,0 +1,65 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels
+{
+ ///
+ /// kubeconfig configuration model. Holds the information needed to build connect to remote
+ /// Kubernetes clusters as a given user.
+ ///
+ ///
+ /// Should be kept in sync with https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/tools/clientcmd/api/v1/types.go
+ /// Should update MergeKubeConfig in KubernetesClientConfiguration.ConfigFile.cs if updated.
+ ///
+ [YamlSerializable]
+ public class K8SConfiguration
+ {
+ // ///
+ // /// Gets or sets general information to be use for CLI interactions
+ // ///
+ // [YamlMember(Alias = "preferences")]
+ // public IDictionary Preferences { get; set; }
+
+ [YamlMember(Alias = "apiVersion")]
+ public string ApiVersion { get; set; }
+
+ [YamlMember(Alias = "kind")]
+ public string Kind { get; set; }
+
+ ///
+ /// Gets or sets the name of the context that you would like to use by default.
+ ///
+ [YamlMember(Alias = "current-context", ApplyNamingConventions = false)]
+ public string CurrentContext { get; set; }
+
+ ///
+ /// Gets or sets a map of referencable names to context configs.
+ ///
+ [YamlMember(Alias = "contexts")]
+ public List Contexts { get; set; } = new List();
+
+ ///
+ /// Gets or sets a map of referencable names to cluster configs.
+ ///
+ [YamlMember(Alias = "clusters")]
+ public List Clusters { get; set; } = new List();
+
+ ///
+ /// Gets or sets a map of referencable names to user configs
+ ///
+ [YamlMember(Alias = "users")]
+ public List Users { get; set; } = new List();
+
+ // ///
+ // /// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields.
+ // ///
+ // [YamlMember(Alias = "extensions")]
+ // public List Extensions { get; set; }
+
+ ///
+ /// Gets or sets the name of the Kubernetes configuration file. This property is set only when the configuration
+ /// was loaded from disk, and can be used to resolve relative paths.
+ ///
+ [YamlIgnore]
+ public string FileName { get; set; }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/StaticContext.cs b/src/KubernetesClient.Aot/KubeConfigModels/StaticContext.cs
new file mode 100644
index 000000000..ae9be922e
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/StaticContext.cs
@@ -0,0 +1,8 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels;
+
+[YamlStaticContext]
+public partial class StaticContext : YamlDotNet.Serialization.StaticContext
+{
+}
\ No newline at end of file
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/User.cs b/src/KubernetesClient.Aot/KubeConfigModels/User.cs
new file mode 100644
index 000000000..557f02256
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/User.cs
@@ -0,0 +1,23 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels
+{
+ ///
+ /// Relates nicknames to auth information.
+ ///
+ [YamlSerializable]
+ public class User
+ {
+ ///
+ /// Gets or sets the auth information.
+ ///
+ [YamlMember(Alias = "user")]
+ public UserCredentials UserCredentials { get; set; }
+
+ ///
+ /// Gets or sets the nickname for this auth information.
+ ///
+ [YamlMember(Alias = "name")]
+ public string Name { get; set; }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubeConfigModels/UserCredentials.cs b/src/KubernetesClient.Aot/KubeConfigModels/UserCredentials.cs
new file mode 100644
index 000000000..bd8a5063e
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubeConfigModels/UserCredentials.cs
@@ -0,0 +1,83 @@
+using YamlDotNet.Serialization;
+
+namespace k8s.KubeConfigModels
+{
+ ///
+ /// Contains information that describes identity information. This is use to tell the kubernetes cluster who you are.
+ ///
+ [YamlSerializable]
+ public class UserCredentials
+ {
+ ///
+ /// Gets or sets PEM-encoded data from a client cert file for TLS. Overrides .
+ ///
+ [YamlMember(Alias = "client-certificate-data", ApplyNamingConventions = false)]
+ public string ClientCertificateData { get; set; }
+
+ ///
+ /// Gets or sets the path to a client cert file for TLS.
+ ///
+ [YamlMember(Alias = "client-certificate", ApplyNamingConventions = false)]
+ public string ClientCertificate { get; set; }
+
+ ///
+ /// Gets or sets PEM-encoded data from a client key file for TLS. Overrides .
+ ///
+ [YamlMember(Alias = "client-key-data", ApplyNamingConventions = false)]
+ public string ClientKeyData { get; set; }
+
+ ///
+ /// Gets or sets the path to a client key file for TLS.
+ ///
+ [YamlMember(Alias = "client-key", ApplyNamingConventions = false)]
+ public string ClientKey { get; set; }
+
+ ///
+ /// Gets or sets the bearer token for authentication to the kubernetes cluster.
+ ///
+ [YamlMember(Alias = "token")]
+ public string Token { get; set; }
+
+ ///
+ /// Gets or sets the username to impersonate. The name matches the flag.
+ ///
+ [YamlMember(Alias = "as")]
+ public string Impersonate { get; set; }
+
+ ///
+ /// Gets or sets the groups to impersonate.
+ ///
+ [YamlMember(Alias = "as-groups", ApplyNamingConventions = false)]
+ public IEnumerable ImpersonateGroups { get; set; } = new string[0];
+
+ ///
+ /// Gets or sets additional information for impersonated user.
+ ///
+ [YamlMember(Alias = "as-user-extra", ApplyNamingConventions = false)]
+ public Dictionary ImpersonateUserExtra { get; set; } = new Dictionary();
+
+ ///
+ /// Gets or sets the username for basic authentication to the kubernetes cluster.
+ ///
+ [YamlMember(Alias = "username")]
+ public string UserName { get; set; }
+
+ ///
+ /// Gets or sets the password for basic authentication to the kubernetes cluster.
+ ///
+ [YamlMember(Alias = "password")]
+ public string Password { get; set; }
+
+ ///
+ /// Gets or sets custom authentication plugin for the kubernetes cluster.
+ ///
+ [YamlMember(Alias = "auth-provider", ApplyNamingConventions = false)]
+ public AuthProvider AuthProvider { get; set; }
+
+ ///
+ /// Gets or sets external command and its arguments to receive user credentials
+ ///
+ [YamlMember(Alias = "exec")]
+ public ExternalExecution ExternalExecution { get; set; }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubernetesClient.Aot.csproj b/src/KubernetesClient.Aot/KubernetesClient.Aot.csproj
new file mode 100644
index 000000000..5c7cf8fed
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubernetesClient.Aot.csproj
@@ -0,0 +1,113 @@
+
+
+
+ net8.0;net9.0
+ k8s
+ true
+ true
+ true
+ $(DefineConstants);K8S_AOT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/KubernetesClient.Aot/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClient.Aot/KubernetesClientConfiguration.ConfigFile.cs
new file mode 100644
index 000000000..a2301b464
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubernetesClientConfiguration.ConfigFile.cs
@@ -0,0 +1,774 @@
+using k8s.Authentication;
+using k8s.Exceptions;
+using k8s.KubeConfigModels;
+using System.Diagnostics;
+using System.Net;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.X509Certificates;
+
+namespace k8s
+{
+ public partial class KubernetesClientConfiguration
+ {
+ ///
+ /// kubeconfig Default Location
+ ///
+ public static readonly string KubeConfigDefaultLocation =
+ RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+ ? Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE") ?? @"\", @".kube\config")
+ : Path.Combine(Environment.GetEnvironmentVariable("HOME") ?? "/", ".kube/config");
+
+ ///
+ /// Gets CurrentContext
+ ///
+ public string CurrentContext { get; private set; }
+
+ // For testing
+ internal static string KubeConfigEnvironmentVariable { get; set; } = "KUBECONFIG";
+
+ ///
+ /// Exec process timeout
+ ///
+ public static TimeSpan ExecTimeout { get; set; } = TimeSpan.FromMinutes(2);
+
+ ///
+ /// Exec process Standard Errors
+ ///
+ public static event EventHandler ExecStdError;
+
+ ///
+ /// Initializes a new instance of the from default locations
+ /// If the KUBECONFIG environment variable is set, then that will be used.
+ /// Next, it looks for a config file at .
+ /// Then, it checks whether it is executing inside a cluster and will use .
+ /// Finally, if nothing else exists, it creates a default config with localhost:8080 as host.
+ ///
+ ///
+ /// If multiple kubeconfig files are specified in the KUBECONFIG environment variable,
+ /// merges the files, where first occurrence wins. See https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#merging-kubeconfig-files.
+ ///
+ /// Instance of the class
+ public static KubernetesClientConfiguration BuildDefaultConfig()
+ {
+ var kubeconfig = Environment.GetEnvironmentVariable(KubeConfigEnvironmentVariable);
+ if (kubeconfig != null)
+ {
+ var configList = kubeconfig.Split(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ';' : ':')
+ .Select((s) => new FileInfo(s.Trim('"')));
+ var k8sConfig = LoadKubeConfig(configList.ToArray());
+ return BuildConfigFromConfigObject(k8sConfig);
+ }
+
+ if (File.Exists(KubeConfigDefaultLocation))
+ {
+ return BuildConfigFromConfigFile(KubeConfigDefaultLocation);
+ }
+
+ if (IsInCluster())
+ {
+ return InClusterConfig();
+ }
+
+ var config = new KubernetesClientConfiguration
+ {
+ Host = "http://localhost:8080/",
+ };
+
+ return config;
+ }
+
+ ///
+ /// Initializes a new instance of the from config file
+ ///
+ /// Explicit file path to kubeconfig. Set to null to use the default file path
+ /// override the context in config file, set null if do not want to override
+ /// kube api server endpoint
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// file is located. When , the paths will be considered to be relative to the current working directory.
+ /// Instance of the class
+ public static KubernetesClientConfiguration BuildConfigFromConfigFile(
+ string kubeconfigPath = null,
+ string currentContext = null, string masterUrl = null, bool useRelativePaths = true)
+ {
+ return BuildConfigFromConfigFile(new FileInfo(kubeconfigPath ?? KubeConfigDefaultLocation), currentContext,
+ masterUrl, useRelativePaths);
+ }
+
+ ///
+ /// Initializes a new instance of the from config file
+ ///
+ /// Fileinfo of the kubeconfig, cannot be null
+ /// override the context in config file, set null if do not want to override
+ /// override the kube api server endpoint, set null if do not want to override
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// file is located. When , the paths will be considered to be relative to the current working directory.
+ /// Instance of the class
+ public static KubernetesClientConfiguration BuildConfigFromConfigFile(
+ FileInfo kubeconfig,
+ string currentContext = null, string masterUrl = null, bool useRelativePaths = true)
+ {
+ return BuildConfigFromConfigFileAsync(kubeconfig, currentContext, masterUrl, useRelativePaths).GetAwaiter()
+ .GetResult();
+ }
+
+ ///
+ /// Initializes a new instance of the from config file
+ ///
+ /// Fileinfo of the kubeconfig, cannot be null
+ /// override the context in config file, set null if do not want to override
+ /// override the kube api server endpoint, set null if do not want to override
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// file is located. When , the paths will be considered to be relative to the current working directory.
+ /// Instance of the class
+ public static async Task BuildConfigFromConfigFileAsync(
+ FileInfo kubeconfig,
+ string currentContext = null, string masterUrl = null, bool useRelativePaths = true)
+ {
+ if (kubeconfig == null)
+ {
+ throw new NullReferenceException(nameof(kubeconfig));
+ }
+
+ var k8SConfig = await LoadKubeConfigAsync(kubeconfig, useRelativePaths).ConfigureAwait(false);
+ var k8SConfiguration = GetKubernetesClientConfiguration(currentContext, masterUrl, k8SConfig);
+
+ return k8SConfiguration;
+ }
+
+ ///
+ /// Initializes a new instance of the from config file
+ ///
+ /// Stream of the kubeconfig, cannot be null
+ /// Override the current context in config, set null if do not want to override
+ /// Override the Kubernetes API server endpoint, set null if do not want to override
+ /// Instance of the class
+ public static KubernetesClientConfiguration BuildConfigFromConfigFile(
+ Stream kubeconfig,
+ string currentContext = null, string masterUrl = null)
+ {
+ return BuildConfigFromConfigFileAsync(kubeconfig, currentContext, masterUrl).GetAwaiter().GetResult();
+ }
+
+ ///
+ /// Initializes a new instance of the from config file
+ ///
+ /// Stream of the kubeconfig, cannot be null
+ /// Override the current context in config, set null if do not want to override
+ /// Override the Kubernetes API server endpoint, set null if do not want to override
+ /// Instance of the class
+ public static async Task BuildConfigFromConfigFileAsync(
+ Stream kubeconfig,
+ string currentContext = null, string masterUrl = null)
+ {
+ if (kubeconfig == null)
+ {
+ throw new NullReferenceException(nameof(kubeconfig));
+ }
+
+ if (!kubeconfig.CanSeek)
+ {
+ throw new Exception("Stream don't support seeking!");
+ }
+
+ kubeconfig.Position = 0;
+
+ var k8SConfig = await KubernetesYaml.LoadFromStreamAsync(kubeconfig).ConfigureAwait(false);
+ var k8SConfiguration = GetKubernetesClientConfiguration(currentContext, masterUrl, k8SConfig);
+
+ return k8SConfiguration;
+ }
+
+ ///
+ /// Initializes a new instance of from pre-loaded config object.
+ ///
+ /// A , for example loaded from
+ /// Override the current context in config, set null if do not want to override
+ /// Override the Kubernetes API server endpoint, set null if do not want to override
+ /// Instance of the class
+ public static KubernetesClientConfiguration BuildConfigFromConfigObject(
+ K8SConfiguration k8SConfig,
+ string currentContext = null, string masterUrl = null)
+ => GetKubernetesClientConfiguration(currentContext, masterUrl, k8SConfig);
+
+ private static KubernetesClientConfiguration GetKubernetesClientConfiguration(
+ string currentContext,
+ string masterUrl, K8SConfiguration k8SConfig)
+ {
+ if (k8SConfig == null)
+ {
+ throw new ArgumentNullException(nameof(k8SConfig));
+ }
+
+ var k8SConfiguration = new KubernetesClientConfiguration();
+
+ currentContext = currentContext ?? k8SConfig.CurrentContext;
+ // only init context if context is set
+ if (currentContext != null)
+ {
+ k8SConfiguration.InitializeContext(k8SConfig, currentContext);
+ }
+
+ if (!string.IsNullOrWhiteSpace(masterUrl))
+ {
+ k8SConfiguration.Host = masterUrl;
+ }
+
+ if (string.IsNullOrWhiteSpace(k8SConfiguration.Host))
+ {
+ throw new KubeConfigException("Cannot infer server host url either from context or masterUrl");
+ }
+
+ return k8SConfiguration;
+ }
+
+ ///
+ /// Validates and Initializes Client Configuration
+ ///
+ /// Kubernetes Configuration
+ /// Current Context
+ private void InitializeContext(K8SConfiguration k8SConfig, string currentContext)
+ {
+ // current context
+ var activeContext =
+ k8SConfig.Contexts.FirstOrDefault(
+ c => c.Name.Equals(currentContext, StringComparison.OrdinalIgnoreCase));
+ if (activeContext == null)
+ {
+ throw new KubeConfigException($"CurrentContext: {currentContext} not found in contexts in kubeconfig");
+ }
+
+ if (string.IsNullOrEmpty(activeContext.ContextDetails?.Cluster))
+ {
+ // This serves as validation for any of the properties of ContextDetails being set.
+ // Other locations in code assume that ContextDetails is non-null.
+ throw new KubeConfigException($"Cluster not set for context `{currentContext}` in kubeconfig");
+ }
+
+ CurrentContext = activeContext.Name;
+
+ // cluster
+ SetClusterDetails(k8SConfig, activeContext);
+
+ // user
+ SetUserDetails(k8SConfig, activeContext);
+
+ // namespace
+ Namespace = activeContext.ContextDetails?.Namespace;
+ }
+
+ private void SetClusterDetails(K8SConfiguration k8SConfig, Context activeContext)
+ {
+ var clusterDetails =
+ k8SConfig.Clusters.FirstOrDefault(c => c.Name.Equals(
+ activeContext.ContextDetails.Cluster,
+ StringComparison.OrdinalIgnoreCase));
+
+ if (clusterDetails?.ClusterEndpoint == null)
+ {
+ throw new KubeConfigException($"Cluster not found for context `{activeContext}` in kubeconfig");
+ }
+
+ if (string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.Server))
+ {
+ throw new KubeConfigException($"Server not found for current-context `{activeContext}` in kubeconfig");
+ }
+
+ Host = clusterDetails.ClusterEndpoint.Server;
+ SkipTlsVerify = clusterDetails.ClusterEndpoint.SkipTlsVerify;
+ TlsServerName = clusterDetails.ClusterEndpoint.TlsServerName;
+
+ if (!Uri.TryCreate(Host, UriKind.Absolute, out var uri))
+ {
+ throw new KubeConfigException($"Bad server host URL `{Host}` (cannot be parsed)");
+ }
+
+ if (IPAddress.TryParse(uri.Host, out var ipAddress))
+ {
+ if (IPAddress.Equals(IPAddress.Any, ipAddress))
+ {
+ var builder = new UriBuilder(Host)
+ {
+ Host = $"{IPAddress.Loopback}",
+ };
+ Host = builder.ToString();
+ }
+ else if (IPAddress.Equals(IPAddress.IPv6Any, ipAddress))
+ {
+ var builder = new UriBuilder(Host)
+ {
+ Host = $"{IPAddress.IPv6Loopback}",
+ };
+ Host = builder.ToString();
+ }
+ }
+
+ if (uri.Scheme == "https")
+ {
+ if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthorityData))
+ {
+ var data = clusterDetails.ClusterEndpoint.CertificateAuthorityData;
+#if NET9_0_OR_GREATER
+ SslCaCerts = new X509Certificate2Collection(X509CertificateLoader.LoadCertificate(Convert.FromBase64String(data)));
+#else
+ string nullPassword = null;
+ // This null password is to change the constructor to fix this KB:
+ // https://support.microsoft.com/en-us/topic/kb5025823-change-in-how-net-applications-import-x-509-certificates-bf81c936-af2b-446e-9f7a-016f4713b46b
+ SslCaCerts = new X509Certificate2Collection(new X509Certificate2(Convert.FromBase64String(data), nullPassword));
+#endif
+ }
+ else if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthority))
+ {
+#if NET9_0_OR_GREATER
+ SslCaCerts = new X509Certificate2Collection(X509CertificateLoader.LoadCertificateFromFile(GetFullPath(
+ k8SConfig,
+ clusterDetails.ClusterEndpoint.CertificateAuthority)));
+#else
+ SslCaCerts = new X509Certificate2Collection(new X509Certificate2(GetFullPath(
+ k8SConfig,
+ clusterDetails.ClusterEndpoint.CertificateAuthority)));
+#endif
+ }
+ }
+ }
+
+
+ private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext)
+ {
+ if (string.IsNullOrWhiteSpace(activeContext.ContextDetails.User))
+ {
+ return;
+ }
+
+ var userDetails = k8SConfig.Users.FirstOrDefault(c => c.Name.Equals(
+ activeContext.ContextDetails.User,
+ StringComparison.OrdinalIgnoreCase));
+
+ if (userDetails == null)
+ {
+ throw new KubeConfigException($"User not found for context {activeContext.Name} in kubeconfig");
+ }
+
+ if (userDetails.UserCredentials == null)
+ {
+ throw new KubeConfigException($"User credentials not found for user: {userDetails.Name} in kubeconfig");
+ }
+
+ var userCredentialsFound = false;
+
+ // Basic and bearer tokens are mutually exclusive
+ if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.Token))
+ {
+ AccessToken = userDetails.UserCredentials.Token;
+ userCredentialsFound = true;
+ }
+ else if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.UserName) &&
+ !string.IsNullOrWhiteSpace(userDetails.UserCredentials.Password))
+ {
+ Username = userDetails.UserCredentials.UserName;
+ Password = userDetails.UserCredentials.Password;
+ userCredentialsFound = true;
+ }
+
+ // Token and cert based auth can co-exist
+ if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientCertificateData) &&
+ !string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientKeyData))
+ {
+ ClientCertificateData = userDetails.UserCredentials.ClientCertificateData;
+ ClientCertificateKeyData = userDetails.UserCredentials.ClientKeyData;
+ userCredentialsFound = true;
+ }
+
+ if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientCertificate) &&
+ !string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientKey))
+ {
+ ClientCertificateFilePath = GetFullPath(k8SConfig, userDetails.UserCredentials.ClientCertificate);
+ ClientKeyFilePath = GetFullPath(k8SConfig, userDetails.UserCredentials.ClientKey);
+ userCredentialsFound = true;
+ }
+
+ if (userDetails.UserCredentials.AuthProvider != null)
+ {
+ if (userDetails.UserCredentials.AuthProvider.Config != null
+ && (userDetails.UserCredentials.AuthProvider.Config.ContainsKey("access-token")
+ || userDetails.UserCredentials.AuthProvider.Config.ContainsKey("id-token")))
+ {
+ switch (userDetails.UserCredentials.AuthProvider.Name)
+ {
+ case "azure":
+ throw new Exception("Please use the https://github.com/Azure/kubelogin credential plugin instead. See https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins for further details`");
+
+ case "gcp":
+ throw new Exception("Please use the \"gke-gcloud-auth-plugin\" credential plugin instead. See https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke for further details");
+ }
+ }
+ }
+
+ if (userDetails.UserCredentials.ExternalExecution != null)
+ {
+ if (string.IsNullOrWhiteSpace(userDetails.UserCredentials.ExternalExecution.Command))
+ {
+ throw new KubeConfigException(
+ "External command execution to receive user credentials must include a command to execute");
+ }
+
+ if (string.IsNullOrWhiteSpace(userDetails.UserCredentials.ExternalExecution.ApiVersion))
+ {
+ throw new KubeConfigException("External command execution missing ApiVersion key");
+ }
+
+ var response = ExecuteExternalCommand(userDetails.UserCredentials.ExternalExecution);
+ AccessToken = response.Status.Token;
+ // When reading ClientCertificateData from a config file it will be base64 encoded, and code later in the system (see CertUtils.GeneratePfx)
+ // expects ClientCertificateData and ClientCertificateKeyData to be base64 encoded because of this. However the string returned by external
+ // auth providers is the raw certificate and key PEM text, so we need to take that and base64 encoded it here so it can be decoded later.
+ ClientCertificateData = response.Status.ClientCertificateData == null ? null : Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(response.Status.ClientCertificateData));
+ ClientCertificateKeyData = response.Status.ClientKeyData == null ? null : Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(response.Status.ClientKeyData));
+
+ userCredentialsFound = true;
+
+ // TODO: support client certificates here too.
+ if (AccessToken != null)
+ {
+ TokenProvider = new ExecTokenProvider(userDetails.UserCredentials.ExternalExecution);
+ }
+ }
+
+ if (!userCredentialsFound)
+ {
+ throw new KubeConfigException(
+ $"User: {userDetails.Name} does not have appropriate auth credentials in kubeconfig");
+ }
+ }
+
+ public static Process CreateRunnableExternalProcess(ExternalExecution config, EventHandler captureStdError = null)
+ {
+ if (config == null)
+ {
+ throw new ArgumentNullException(nameof(config));
+ }
+
+ var process = new Process();
+
+ process.StartInfo.EnvironmentVariables.Add("KUBERNETES_EXEC_INFO", $"{{ \"apiVersion\":\"{config.ApiVersion}\",\"kind\":\"ExecCredentials\",\"spec\":{{ \"interactive\":{Environment.UserInteractive.ToString().ToLower()} }} }}");
+ if (config.EnvironmentVariables != null)
+ {
+ foreach (var configEnvironmentVariable in config.EnvironmentVariables)
+ {
+ if (configEnvironmentVariable.ContainsKey("name") && configEnvironmentVariable.ContainsKey("value"))
+ {
+ var name = configEnvironmentVariable["name"];
+ process.StartInfo.EnvironmentVariables[name] = configEnvironmentVariable["value"];
+ }
+ else
+ {
+ var badVariable = string.Join(",", configEnvironmentVariable.Select(x => $"{x.Key}={x.Value}"));
+ throw new KubeConfigException($"Invalid environment variable defined: {badVariable}");
+ }
+ }
+ }
+
+ process.StartInfo.FileName = config.Command;
+ if (config.Arguments != null)
+ {
+ process.StartInfo.Arguments = string.Join(" ", config.Arguments);
+ }
+
+ process.StartInfo.RedirectStandardOutput = true;
+ process.StartInfo.RedirectStandardError = captureStdError != null;
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.CreateNoWindow = true;
+
+ return process;
+ }
+
+ ///
+ /// Implementation of the proposal for out-of-tree client
+ /// authentication providers as described here --
+ /// https://github.com/kubernetes/community/blob/master/contributors/design-proposals/auth/kubectl-exec-plugins.md
+ /// Took inspiration from python exec_provider.py --
+ /// https://github.com/kubernetes-client/python-base/blob/master/config/exec_provider.py
+ ///
+ /// The external command execution configuration
+ ///
+ /// The token, client certificate data, and the client key data received from the external command execution
+ ///
+ public static ExecCredentialResponse ExecuteExternalCommand(ExternalExecution config)
+ {
+ if (config == null)
+ {
+ throw new ArgumentNullException(nameof(config));
+ }
+
+ var captureStdError = ExecStdError;
+ var process = CreateRunnableExternalProcess(config, captureStdError);
+
+ try
+ {
+ process.Start();
+ if (captureStdError != null)
+ {
+ process.ErrorDataReceived += captureStdError.Invoke;
+ process.BeginErrorReadLine();
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new KubeConfigException($"external exec failed due to: {ex.Message}");
+ }
+
+ try
+ {
+ if (!process.WaitForExit((int)(ExecTimeout.TotalMilliseconds)))
+ {
+ throw new KubeConfigException("external exec failed due to timeout");
+ }
+
+ var responseObject = JsonSerializer.Deserialize(
+ process.StandardOutput.ReadToEnd(),
+ ExecCredentialResponseContext.Default.ExecCredentialResponse);
+
+ if (responseObject == null || responseObject.ApiVersion != config.ApiVersion)
+ {
+ throw new KubeConfigException(
+ $"external exec failed because api version {responseObject.ApiVersion} does not match {config.ApiVersion}");
+ }
+
+ if (responseObject.Status.IsValid())
+ {
+ return responseObject;
+ }
+ else
+ {
+ throw new KubeConfigException($"external exec failed missing token or clientCertificateData field in plugin output");
+ }
+ }
+ catch (JsonException ex)
+ {
+ throw new KubeConfigException($"external exec failed due to failed deserialization process: {ex}");
+ }
+ catch (Exception ex)
+ {
+ throw new KubeConfigException($"external exec failed due to uncaught exception: {ex}");
+ }
+ }
+
+ ///
+ /// Loads entire Kube Config from default or explicit file path
+ ///
+ /// Explicit file path to kubeconfig. Set to null to use the default file path
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// file is located. When , the paths will be considered to be relative to the current working directory.
+ /// Instance of the class
+ public static async Task LoadKubeConfigAsync(
+ string kubeconfigPath = null,
+ bool useRelativePaths = true)
+ {
+ var fileInfo = new FileInfo(kubeconfigPath ?? KubeConfigDefaultLocation);
+
+ return await LoadKubeConfigAsync(fileInfo, useRelativePaths).ConfigureAwait(false);
+ }
+
+ ///
+ /// Loads entire Kube Config from default or explicit file path
+ ///
+ /// Explicit file path to kubeconfig. Set to null to use the default file path
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// file is located. When , the paths will be considered to be relative to the current working directory.
+ /// Instance of the class
+ public static K8SConfiguration LoadKubeConfig(string kubeconfigPath = null, bool useRelativePaths = true)
+ {
+ return LoadKubeConfigAsync(kubeconfigPath, useRelativePaths).GetAwaiter().GetResult();
+ }
+
+ ///
+ /// Loads Kube Config
+ ///
+ /// Kube config file contents
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// file is located. When , the paths will be considered to be relative to the current working directory.
+ /// Instance of the class
+ public static async Task LoadKubeConfigAsync(
+ FileInfo kubeconfig,
+ bool useRelativePaths = true)
+ {
+ if (kubeconfig == null)
+ {
+ throw new ArgumentNullException(nameof(kubeconfig));
+ }
+
+
+ if (!kubeconfig.Exists)
+ {
+ throw new KubeConfigException($"kubeconfig file not found at {kubeconfig.FullName}");
+ }
+
+ using (var stream = kubeconfig.OpenRead())
+ {
+ var config = await KubernetesYaml.LoadFromStreamAsync(stream).ConfigureAwait(false);
+
+ if (useRelativePaths)
+ {
+ config.FileName = kubeconfig.FullName;
+ }
+
+ return config;
+ }
+ }
+
+ ///
+ /// Loads Kube Config
+ ///
+ /// Kube config file contents
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// file is located. When , the paths will be considered to be relative to the current working directory.
+ /// Instance of the class
+ public static K8SConfiguration LoadKubeConfig(FileInfo kubeconfig, bool useRelativePaths = true)
+ {
+ return LoadKubeConfigAsync(kubeconfig, useRelativePaths).GetAwaiter().GetResult();
+ }
+
+ ///
+ /// Loads Kube Config
+ ///
+ /// Kube config file contents stream
+ /// Instance of the class
+ public static async Task LoadKubeConfigAsync(Stream kubeconfigStream)
+ {
+ return await KubernetesYaml.LoadFromStreamAsync(kubeconfigStream).ConfigureAwait(false);
+ }
+
+ ///
+ /// Loads Kube Config
+ ///
+ /// Kube config file contents stream
+ /// Instance of the class
+ public static K8SConfiguration LoadKubeConfig(Stream kubeconfigStream)
+ {
+ return LoadKubeConfigAsync(kubeconfigStream).GetAwaiter().GetResult();
+ }
+
+ ///
+ /// Loads Kube Config
+ ///
+ /// List of kube config file contents
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// file is located. When , the paths will be considered to be relative to the current working directory.
+ /// Instance of the class
+ ///
+ /// The kube config files will be merges into a single , where first occurrence wins.
+ /// See https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#merging-kubeconfig-files.
+ ///
+ internal static K8SConfiguration LoadKubeConfig(FileInfo[] kubeConfigs, bool useRelativePaths = true)
+ {
+ return LoadKubeConfigAsync(kubeConfigs, useRelativePaths).GetAwaiter().GetResult();
+ }
+
+ ///
+ /// Loads Kube Config
+ ///
+ /// List of kube config file contents
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// file is located. When , the paths will be considered to be relative to the current working directory.
+ /// Instance of the class
+ ///
+ /// The kube config files will be merges into a single , where first occurrence wins.
+ /// See https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#merging-kubeconfig-files.
+ ///
+ internal static async Task LoadKubeConfigAsync(
+ FileInfo[] kubeConfigs,
+ bool useRelativePaths = true)
+ {
+ var basek8SConfig = await LoadKubeConfigAsync(kubeConfigs[0], useRelativePaths).ConfigureAwait(false);
+
+ for (var i = 1; i < kubeConfigs.Length; i++)
+ {
+ var mergek8SConfig = await LoadKubeConfigAsync(kubeConfigs[i], useRelativePaths).ConfigureAwait(false);
+ MergeKubeConfig(basek8SConfig, mergek8SConfig);
+ }
+
+ return basek8SConfig;
+ }
+
+ ///
+ /// Tries to get the full path to a file referenced from the Kubernetes configuration.
+ ///
+ ///
+ /// The Kubernetes configuration.
+ ///
+ ///
+ /// The path to resolve.
+ ///
+ ///
+ /// When possible a fully qualified path to the file.
+ ///
+ ///
+ /// For example, if the configuration file is at "C:\Users\me\kube.config" and path is "ca.crt",
+ /// this will return "C:\Users\me\ca.crt". Similarly, if path is "D:\ca.cart", this will return
+ /// "D:\ca.crt".
+ ///
+ private static string GetFullPath(K8SConfiguration configuration, string path)
+ {
+ // If we don't have a file name,
+ if (string.IsNullOrWhiteSpace(configuration.FileName) || Path.IsPathRooted(path))
+ {
+ return path;
+ }
+ else
+ {
+ return Path.Combine(Path.GetDirectoryName(configuration.FileName), path);
+ }
+ }
+
+ ///
+ /// Merges kube config files together, preferring configuration present in the base config over the merge config.
+ ///
+ /// The to merge into
+ /// The to merge from
+ private static void MergeKubeConfig(K8SConfiguration basek8SConfig, K8SConfiguration mergek8SConfig)
+ {
+ // For scalar values, prefer local values
+ basek8SConfig.CurrentContext = basek8SConfig.CurrentContext ?? mergek8SConfig.CurrentContext;
+ basek8SConfig.FileName = basek8SConfig.FileName ?? mergek8SConfig.FileName;
+
+ // Kinds must match in kube config, otherwise throw.
+ if (basek8SConfig.Kind != mergek8SConfig.Kind)
+ {
+ throw new KubeConfigException(
+ $"kubeconfig \"kind\" are different between {basek8SConfig.FileName} and {mergek8SConfig.FileName}");
+ }
+
+ // Note, Clusters, Contexts, and Extensions are map-like in config despite being represented as a list here:
+ // https://github.com/kubernetes/client-go/blob/ede92e0fe62deed512d9ceb8bf4186db9f3776ff/tools/clientcmd/api/types.go#L238
+ // basek8SConfig.Extensions = MergeLists(basek8SConfig.Extensions, mergek8SConfig.Extensions, (s) => s.Name).ToList();
+ basek8SConfig.Clusters = MergeLists(basek8SConfig.Clusters, mergek8SConfig.Clusters, (s) => s.Name).ToList();
+ basek8SConfig.Users = MergeLists(basek8SConfig.Users, mergek8SConfig.Users, (s) => s.Name).ToList();
+ basek8SConfig.Contexts = MergeLists(basek8SConfig.Contexts, mergek8SConfig.Contexts, (s) => s.Name).ToList();
+ }
+
+ private static IEnumerable MergeLists(IEnumerable baseList, IEnumerable mergeList,
+ Func getNameFunc)
+ {
+ if (mergeList != null && mergeList.Any())
+ {
+ var mapping = new Dictionary();
+ foreach (var item in baseList)
+ {
+ mapping[getNameFunc(item)] = item;
+ }
+
+ foreach (var item in mergeList)
+ {
+ var name = getNameFunc(item);
+ if (!mapping.ContainsKey(name))
+ {
+ mapping[name] = item;
+ }
+ }
+
+ return mapping.Values;
+ }
+
+ return baseList;
+ }
+ }
+}
diff --git a/src/KubernetesClient.Aot/KubernetesYaml.cs b/src/KubernetesClient.Aot/KubernetesYaml.cs
new file mode 100644
index 000000000..5530a2e02
--- /dev/null
+++ b/src/KubernetesClient.Aot/KubernetesYaml.cs
@@ -0,0 +1,171 @@
+using System.Text;
+using YamlDotNet.Core;
+using YamlDotNet.Core.Events;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+
+namespace k8s
+{
+ ///
+ /// This is a utility class that helps you load objects from YAML files.
+ ///
+ internal static class KubernetesYaml
+ {
+ private static StaticDeserializerBuilder CommonDeserializerBuilder =>
+ new StaticDeserializerBuilder(new k8s.KubeConfigModels.StaticContext())
+ .WithNamingConvention(CamelCaseNamingConvention.Instance)
+ .WithTypeConverter(new IntOrStringYamlConverter())
+ .WithTypeConverter(new ByteArrayStringYamlConverter())
+ .WithTypeConverter(new ResourceQuantityYamlConverter())
+ .WithTypeConverter(new KubernetesDateTimeYamlConverter())
+ .WithTypeConverter(new KubernetesDateTimeOffsetYamlConverter())
+ .WithAttemptingUnquotedStringTypeDeserialization()
+ ;
+
+ private static readonly IDeserializer Deserializer =
+ CommonDeserializerBuilder
+ .IgnoreUnmatchedProperties()
+ .Build();
+ private static IDeserializer GetDeserializer(bool strict) => Deserializer;
+
+ private static readonly IValueSerializer Serializer =
+ new StaticSerializerBuilder(new k8s.KubeConfigModels.StaticContext())
+ .DisableAliases()
+ .WithNamingConvention(CamelCaseNamingConvention.Instance)
+ .WithTypeConverter(new IntOrStringYamlConverter())
+ .WithTypeConverter(new ByteArrayStringYamlConverter())
+ .WithTypeConverter(new ResourceQuantityYamlConverter())
+ .WithTypeConverter(new KubernetesDateTimeYamlConverter())
+ .WithTypeConverter(new KubernetesDateTimeOffsetYamlConverter())
+ .WithEventEmitter(e => new StringQuotingEmitter(e))
+ .WithEventEmitter(e => new FloatEmitter(e))
+ .ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull)
+ .BuildValueSerializer();
+
+ private class ByteArrayStringYamlConverter : IYamlTypeConverter
+ {
+ public bool Accepts(Type type)
+ {
+ return type == typeof(byte[]);
+ }
+
+ public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
+ {
+ if (parser?.Current is Scalar scalar)
+ {
+ try
+ {
+ if (string.IsNullOrEmpty(scalar.Value))
+ {
+ return null;
+ }
+
+ return Convert.FromBase64String(scalar.Value);
+ }
+ finally
+ {
+ parser.MoveNext();
+ }
+ }
+
+ throw new InvalidOperationException(parser.Current?.ToString());
+ }
+
+ public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer)
+ {
+ if (value == null)
+ {
+ emitter.Emit(new Scalar(string.Empty));
+ return;
+ }
+
+ var obj = (byte[])value;
+ var encoded = Convert.ToBase64String(obj);
+ emitter.Emit(new Scalar(encoded));
+ }
+ }
+
+ public static async Task LoadFromStreamAsync(Stream stream, bool strict = false)
+ {
+ var reader = new StreamReader(stream);
+ var content = await reader.ReadToEndAsync().ConfigureAwait(false);
+ return Deserialize(content, strict);
+ }
+
+ public static async Task LoadFromFileAsync(string file, bool strict = false)
+ {
+ using (var fs = File.OpenRead(file))
+ {
+ return await LoadFromStreamAsync(fs, strict).ConfigureAwait(false);
+ }
+ }
+
+ [Obsolete("use Deserialize")]
+ public static T LoadFromString(string content, bool strict = false)
+ {
+ return Deserialize(content, strict);
+ }
+
+ [Obsolete("use Serialize")]
+ public static string SaveToString(T value)
+ {
+ return Serialize(value);
+ }
+
+ public static TValue Deserialize(string yaml, bool strict = false)
+ {
+ using var reader = new StringReader(yaml);
+ return GetDeserializer(strict).Deserialize(new MergingParser(new Parser(reader)));
+ }
+
+ public static TValue Deserialize(Stream yaml, bool strict = false)
+ {
+ using var reader = new StreamReader(yaml);
+ return GetDeserializer(strict).Deserialize(new MergingParser(new Parser(reader)));
+ }
+
+ public static string SerializeAll(IEnumerable