├── Kubernetes.Configuration.Extensions.TestApplication
└── Kubernetes.Configuration.Extensions.TestApplication.csproj
├── .github
└── workflows
│ ├── dotnetcore.yml
│ ├── nuget_push.yml
│ └── integration.yml
├── Kubernetes.Config
├── Configmap
│ ├── ConfigmapConfigurationSource.cs
│ ├── ConfigmapConfigurationExtensions.cs
│ └── ConfigmapConfigurationProvider.cs
├── Secret
│ ├── SecretConfigurationSource.cs
│ ├── SecretConfigurationExtensions.cs
│ └── SecretConfigurationProvider.cs
└── Kubernetes.Configuration.Extensions.csproj
├── README.md
├── Configmap.Extensions.Test
├── IntegrationTests.cs
├── Kubernetes.Configuration.Extensions.Test.csproj
├── ConfigmapExtensionTest.cs
└── SecretExtensionTest.cs
├── KubernetesConfig.sln
├── .gitattributes
├── .editorconfig
├── .gitignore
└── LICENSE
/Kubernetes.Configuration.Extensions.TestApplication/Kubernetes.Configuration.Extensions.TestApplication.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 | enable
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.github/workflows/dotnetcore.yml:
--------------------------------------------------------------------------------
1 | name: .NET Core
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: Setup .NET Core
13 | uses: actions/setup-dotnet@v1
14 | with:
15 | dotnet-version: '3.1.x'
16 | - name: Build with dotnet
17 | run: dotnet build --configuration Release
18 | - name: Test with dotnet
19 | run: dotnet test --filter Type!=IntegrationTest
20 |
--------------------------------------------------------------------------------
/.github/workflows/nuget_push.yml:
--------------------------------------------------------------------------------
1 | name: Publish to Nuget
2 | on:
3 | push:
4 | branches:
5 | - master
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 | steps:
10 | # Checkout
11 | - uses: actions/checkout@v2
12 | - uses: actions/setup-dotnet@v1
13 | with:
14 | dotnet-version: '3.1.x'
15 | - name: Build
16 | run: dotnet build --configuration Release
17 | - name: Push
18 | run: dotnet nuget push --skip-duplicate **/*.nupkg
19 | --api-key ${{ secrets.NUGET_API_KEY }}
20 | --source https://api.nuget.org/v3/index.json
21 | --no-symbols true
22 |
--------------------------------------------------------------------------------
/Kubernetes.Config/Configmap/ConfigmapConfigurationSource.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 |
3 | namespace Kubernetes.Configuration.Extensions.Configmap
4 | {
5 | public class ConfigmapConfigurationSource : IConfigurationSource
6 | {
7 | public string? Namespace { get; set; }
8 | public string? LabelSelector { get; set; }
9 | public string? Separator { get; set; }
10 | public bool ReloadOnChange { get; set; }
11 | public IConfigurationProvider Build(IConfigurationBuilder builder)
12 | {
13 | return new ConfigmapConfigurationProvider(Namespace, LabelSelector, Separator, ReloadOnChange);
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/.github/workflows/integration.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: KinD (Kubernetes in Docker) Action
13 | uses: engineerd/setup-kind@v0.5.0
14 | - name: Install configmap and secret
15 | run: |
16 | kubectl create configmap test-config --from-literal=Test__Config=testvalue
17 | kubectl create secret generic test-secret --from-literal=Test__Secret=testsecretvalue
18 | kubectl label configmap test-config app=testapp
19 | kubectl label secret test-secret app=testapp
20 | - name: Run integrationtest
21 | run: dotnet test --filter Type=IntegrationTest
--------------------------------------------------------------------------------
/Kubernetes.Config/Secret/SecretConfigurationSource.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 |
3 | namespace Kubernetes.Configuration.Extensions.Secret
4 | {
5 | public class SecretConfigurationSource : IConfigurationSource
6 | {
7 | public string? Namespace { get; set; }
8 | public string? LabelSelector { get; set; }
9 | public string? Separator { get; set; }
10 | public bool ReloadOnChange { get; set; }
11 | public bool DecodeData { get; set; } = true;
12 | public IConfigurationProvider Build(IConfigurationBuilder builder)
13 | {
14 | return new SecretConfigurationProvider(Namespace, LabelSelector, Separator, ReloadOnChange, DecodeData);
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | 
3 |
4 | # Kubernetes.Configuration.Extensions
5 |
6 | Adds extension methods for reading Kubernetes Configmaps and Secrets
7 |
8 | ### Installing
9 |
10 | Available on nuget. Run command
11 | ``` Install-Package Kubernetes.Configuration.Extensions ```
12 |
13 | ### Usage
14 | To use with DI just add the following.
15 | ```
16 | .ConfigureAppConfiguration((hostingContext, config) =>
17 | {
18 | config.AddKubernetesConfigmap("app=testapp", reloadOnChange:true);
19 | config.AddKubernetesSecret("app=testapp", reloadOnChange:true);
20 |
21 | })
22 | ```
23 | A label is required on the configmap since otherwise every configmap on the system will be fetched.
24 |
--------------------------------------------------------------------------------
/Configmap.Extensions.Test/IntegrationTests.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Kubernetes.Configuration.Extensions.Configmap;
3 | using Kubernetes.Configuration.Extensions.Secret;
4 | using Microsoft.Extensions.Configuration;
5 | using Xunit;
6 |
7 | namespace Kubernetes.Configuration.Extensions.Test
8 | {
9 | public class IntegrationTests
10 | {
11 | [Trait("Type", "IntegrationTest")]
12 | [Fact]
13 | public void Test_Add_ConfigMap_And_Secret_From_Kubernetes()
14 | {
15 | var builder = new ConfigurationBuilder();
16 | builder.AddKubernetesConfigmap("app=testapp");
17 | builder.AddKubernetesSecret("app=testapp");
18 |
19 | var config = builder.Build();
20 | Assert.NotEmpty(config.Providers);
21 | Assert.Equal("testvalue", config.AsEnumerable().Single(x => x.Key == "Test:Config").Value);
22 | Assert.Equal("testsecretvalue", config.AsEnumerable().Single(x => x.Key == "Test:Secret").Value);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Kubernetes.Config/Kubernetes.Configuration.Extensions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | true
6 | enable
7 | 1.2.0
8 | 1.2.0.0
9 | 1.2.0.0
10 | Adds extension methods for reading Kubernetes Configmaps and Secrets
11 | Tommy Kindmark
12 | Kubernetes
13 | https://github.com/Towmeykaw/Kubernetes.Configuration.Extensions
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Configmap.Extensions.Test/Kubernetes.Configuration.Extensions.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 | all
14 | runtime; build; native; contentfiles; analyzers
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | ..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.configuration\2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Configmap.Extensions.Test/ConfigmapExtensionTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Kubernetes.Configuration.Extensions.Configmap;
3 | using Microsoft.Extensions.Configuration;
4 | using Xunit;
5 |
6 | namespace Kubernetes.Configuration.Extensions.Test
7 | {
8 | public class ConfigmapExtensionTest
9 | {
10 | [Theory]
11 | [InlineData(null)]
12 | [InlineData("")]
13 | public void AddConfigmap_ThrowsIfLabelIsNullOrEmpty(string label)
14 | {
15 | var configurationBuilder = new ConfigurationBuilder();
16 | var ex = Assert.Throws(() => configurationBuilder.AddKubernetesConfigmap(label));
17 | Assert.Equal("labelSelector", ex.ParamName);
18 | Assert.StartsWith("Invalid label selector", ex.Message);
19 | }
20 | [Fact]
21 | public void AddConfigmap_HasDefaultNamespace()
22 | {
23 | var configurationBuilder = new ConfigurationBuilder();
24 | var source = configurationBuilder.AddKubernetesConfigmap("label").Sources[0] as ConfigmapConfigurationSource;
25 | Assert.Equal("default", source?.Namespace);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/Kubernetes.Config/Configmap/ConfigmapConfigurationExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.Configuration;
3 |
4 | namespace Kubernetes.Configuration.Extensions.Configmap
5 | {
6 | public static class ConfigmapConfigurationExtensions
7 | {
8 | public static IConfigurationBuilder AddKubernetesConfigmap(this IConfigurationBuilder builder, string labelSelector, string namespaceSelector = "default", bool reloadOnChange = false, string separator = "__")
9 | {
10 | if (builder == null)
11 | {
12 | throw new ArgumentNullException(nameof(builder));
13 | }
14 | if (string.IsNullOrEmpty(labelSelector))
15 | {
16 | throw new ArgumentException("Invalid label selector", nameof(labelSelector));
17 | }
18 | builder.Add(new ConfigmapConfigurationSource { Namespace = namespaceSelector, LabelSelector = labelSelector, ReloadOnChange = reloadOnChange});
19 | return builder;
20 | }
21 |
22 | ///
23 | /// Adds a JSON configuration source to .
24 | ///
25 | /// The to add to.
26 | /// Configures the source.
27 | /// The .
28 | public static IConfigurationBuilder AddKubernetesConfigmap(this IConfigurationBuilder builder, Action configureSource)
29 | => builder.Add(configureSource);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Kubernetes.Config/Secret/SecretConfigurationExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.Configuration;
3 |
4 | namespace Kubernetes.Configuration.Extensions.Secret
5 | {
6 | public static class SecretConfigurationExtensions
7 | {
8 | public static IConfigurationBuilder AddKubernetesSecret(this IConfigurationBuilder builder, string labelSelector, string namespaceSelector = "default", string separator = "__", bool reloadOnChange = false, bool decodeData = true)
9 | {
10 | if (builder == null)
11 | {
12 | throw new ArgumentNullException(nameof(builder));
13 | }
14 | if (string.IsNullOrEmpty(labelSelector))
15 | {
16 | throw new ArgumentException("Invalid label selector", nameof(labelSelector));
17 | }
18 | builder.Add(new SecretConfigurationSource { Namespace = namespaceSelector, LabelSelector = labelSelector, Separator = separator, ReloadOnChange = reloadOnChange, DecodeData = decodeData});
19 | return builder;
20 | }
21 |
22 | ///
23 | /// Adds a JSON configuration source to .
24 | ///
25 | /// The to add to.
26 | /// Configures the source.
27 | /// The .
28 | public static IConfigurationBuilder AddKubernetesSecret(this IConfigurationBuilder builder, Action configureSource)
29 | => builder.Add(configureSource);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Configmap.Extensions.Test/SecretExtensionTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using Kubernetes.Configuration.Extensions.Secret;
5 | using Microsoft.Extensions.Configuration;
6 | using Xunit;
7 |
8 | namespace Kubernetes.Configuration.Extensions.Test
9 | {
10 | public class SecretExtensionTest
11 | {
12 | [Theory]
13 | [InlineData(null)]
14 | [InlineData("")]
15 | public void AddSecret_ThrowsIfLabelIsNullOrEmpty(string label)
16 | {
17 | var configurationBuilder = new ConfigurationBuilder();
18 | var ex = Assert.Throws(() => configurationBuilder.AddKubernetesSecret(label));
19 | Assert.Equal("labelSelector", ex.ParamName);
20 | Assert.StartsWith("Invalid label selector", ex.Message);
21 | }
22 | [Fact]
23 | public void AddSecret_HasDefaultNamespace()
24 | {
25 | var configurationBuilder = new ConfigurationBuilder();
26 | var source = configurationBuilder.AddKubernetesSecret("label").Sources[0] as SecretConfigurationSource;
27 | Assert.Equal("default", source?.Namespace);
28 | }
29 |
30 | [Theory]
31 | [MemberData(nameof(GetData))]
32 | public void DecodeSecret_HandlesNormalCases(byte[] value)
33 | {
34 | var result = SecretConfigurationProvider.DecodeSecret(value);
35 | Assert.Equal(Encoding.UTF8.GetBytes("testdata"), Encoding.UTF8.GetBytes(result));
36 | }
37 |
38 | public static IEnumerable