Skip to content

Commit

Permalink
refact package
Browse files Browse the repository at this point in the history
  • Loading branch information
witskeeper committed Jan 28, 2024
1 parent 3678cf3 commit 531cbde
Show file tree
Hide file tree
Showing 44 changed files with 566 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ jobs:
- name: Pack NuGet
run: dotnet pack -c Release --version-suffix preview.1.`date +%y%m%d%H%M` -o ./
- name: Push NuGet
run: dotnet nuget push '*.nupkg' -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_API_KEY }} -n true --skip-duplicate
run: dotnet nuget push '*.nupkg' -s https://www.myget.org/F/netcorepal/api/v3/index.json -k ${{ secrets.MYGET_API_KEY }} -n true --skip-duplicate

29 changes: 29 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: .NET

on:
push:
tags:
- 'v*'

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.0.104
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
- name: Pack NuGet
run: dotnet pack -c Release --version-suffix preview.1.`date +%y%m%d%H%M` -o ./
- name: Push NuGet
run: dotnet nuget push '*.nupkg' -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_API_KEY }} -n true --skip-duplicate

39 changes: 39 additions & 0 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<Project>
<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0'">
<FrameworkVersion>6.0.0</FrameworkVersion>
<ExtensionsVersion>6.0.0</ExtensionsVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net7.0'">
<FrameworkVersion>7.0.0</FrameworkVersion>
<ExtensionsVersion>7.0.0</ExtensionsVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0'">
<FrameworkVersion>8.0.0</FrameworkVersion>
<ExtensionsVersion>8.0.0</ExtensionsVersion>
</PropertyGroup>
<ItemGroup>
<!--microsoft extensions -->
<PackageReference Update="Microsoft.Extensions.Configuration.Abstractions" Version="$(ExtensionsVersion)"/>
<PackageReference Update="Microsoft.Extensions.Configuration" Version="$(ExtensionsVersion)"/>
<PackageReference Update="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(ExtensionsVersion)"/>
<PackageReference Update="Microsoft.Extensions.DependencyInjection" Version="$(ExtensionsVersion)"/>
<PackageReference Update="Microsoft.Extensions.Logging.Abstractions" Version="$(ExtensionsVersion)"/>
<PackageReference Update="Microsoft.Extensions.Options" Version="$(ExtensionsVersion)"/>
<PackageReference Update="Microsoft.Extensions.Logging" Version="$(ExtensionsVersion)"/>
<PackageReference Update="Microsoft.Extensions.Logging.Console" Version="$(ExtensionsVersion)"/>
<PackageReference Update="Microsoft.Extensions.FileProviders.Embedded" Version="$(ExtensionsVersion)"/>

<PackageReference Update="Microsoft.AspNetCore.Mvc.Testing" Version="$(FrameworkVersion)" />
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.6.2" />
<PackageReference Update="Moq" Version="4.18.4" />
<PackageReference Update="xunit" Version="2.4.2" />
<PackageReference Update="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Update="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
3 changes: 3 additions & 0 deletions NuGet.config
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key=".NET Libraries Daily" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries/nuget/v3/index.json" />
<!-- The .NET Libraries Transport Daily feed is only needed for the Yarp.Kubernetes.Controller package -->
<add key=".NET Libraries Transport Daily" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries-transport/nuget/v3/index.json" />
<add key="myget" value="https://www.myget.org/F/netcorepal/api/v3/index.json" />
<add key="nuget_v3" value="https://api.nuget.org/v3/index.json" />
</packageSources>
Expand Down
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
# netcorepal-extensions-yarp

NetCorePal Extensions for YAEP
[![Release Build](https://img.shields.io/github/actions/workflow/status/netcorepal/netcorepal-extensions-yarp/release.yml?label=release%20build)](https://github.com/netcorepal/netcorepal-extensions-yarp/actions/workflows/release.yml)
[![Preview Build](https://img.shields.io/github/actions/workflow/status/netcorepal/netcorepal-extensions-yarp/dotnet.yml?label=preview%20build)](https://github.com/netcorepal/netcorepal-extensions-yarp/actions/workflows/dotnet.yml)
[![NuGet](https://img.shields.io/nuget/v/NetCorePal.Yarp.ReverseProxy.Dashboard.svg)](https://www.nuget.org/packages/NetCorePal.Yarp.ReverseProxy.Dashboard)
[![MyGet Preview](https://img.shields.io/myget/netcorepal/vpre/NetCorePal.Yarp.ReverseProxy.Dashboard?label=preview)](https://www.myget.org/feed/netcorepal/package/nuget/NetCorePal.Yarp.ReverseProxy.Dashboard)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/netcorepal/netcorepal-extensions-yarp/blob/main/LICENSE)

The Extensions for [YAEP](https://github.com/microsoft/reverse-proxy)

## Package List

|Package|Release|Preview|
|---|---|---|
|NetCorePal.Yarp.ReverseProxy.Dashboard|[![NuGet](https://img.shields.io/nuget/v/NetCorePal.Yarp.ReverseProxy.Dashboard.svg)](https://www.nuget.org/packages/NetCorePal.Yarp.ReverseProxy.Dashboard)|[![MyGet Preview](https://img.shields.io/myget/netcorepal/vpre/NetCorePal.Yarp.ReverseProxy.Dashboard?label=preview)](https://www.myget.org/feed/netcorepal/package/nuget/NetCorePal.Yarp.ReverseProxy.Dashboard)|
|NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates|[![NuGet](https://img.shields.io/nuget/v/NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates.svg)](https://www.nuget.org/packages/NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates)|[![MyGet Preview](https://img.shields.io/myget/netcorepal/vpre/NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates?label=preview)](https://www.myget.org/feed/netcorepal/package/nuget/NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates)|

## Preview Build

Preview NuGet Feed:

```text
https://www.myget.org/F/netcorepal/api/v3/index.json
```

NuGet.config:

```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="netcorepal" value="https://www.myget.org/F/netcorepal/api/v3/index.json" />
</packageSources>
</configuration>
```
2 changes: 1 addition & 1 deletion eng/versions.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<VersionPrefix>0.1.0</VersionPrefix>
<VersionPrefix>0.2.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
27 changes: 25 additions & 2 deletions netcorepal-extensions-yarp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决
eng\versions.props = eng\versions.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCorePal.Extensions.Yarp.ServiceDiscovery", "src\NetCorePal.Extensions.Yarp.ServiceDiscovery\NetCorePal.Extensions.Yarp.ServiceDiscovery.csproj", "{B9913396-5C97-4296-97A4-9F0D7716A1E6}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCorePal.Yarp.ServiceDiscovery", "src\NetCorePal.Yarp.ServiceDiscovery\NetCorePal.Yarp.ServiceDiscovery.csproj", "{B9913396-5C97-4296-97A4-9F0D7716A1E6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCorePal.Extensions.YarpProxyStateUI", "src\NetCorePal.Extensions.YarpProxyStateUI\NetCorePal.Extensions.YarpProxyStateUI.csproj", "{10DFF0FD-CF81-4C18-AFA5-2EEACEAC0845}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCorePal.Yarp.ReverseProxy.Dashboard", "src\NetCorePal.Yarp.ReverseProxy.Dashboard\NetCorePal.Yarp.ReverseProxy.Dashboard.csproj", "{10DFF0FD-CF81-4C18-AFA5-2EEACEAC0845}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates", "src\NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates\NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates.csproj", "{EF55F855-1B26-47A0-A0F4-61C0B482BADF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{BEE4A397-41B9-4EFC-A37C-C74F1A97ACBE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates.Tests", "test\NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates.Tests\NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates.Tests.csproj", "{85BA9DE7-5526-4937-8C40-4EC3D2DD4455}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IngressControllerTestWebHost", "test\IngressControllerTestWebHost\IngressControllerTestWebHost.csproj", "{4AB4F9D3-6C63-44E3-8484-2CC0DD460E33}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -31,13 +39,28 @@ Global
{10DFF0FD-CF81-4C18-AFA5-2EEACEAC0845}.Debug|Any CPU.Build.0 = Debug|Any CPU
{10DFF0FD-CF81-4C18-AFA5-2EEACEAC0845}.Release|Any CPU.ActiveCfg = Release|Any CPU
{10DFF0FD-CF81-4C18-AFA5-2EEACEAC0845}.Release|Any CPU.Build.0 = Release|Any CPU
{EF55F855-1B26-47A0-A0F4-61C0B482BADF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF55F855-1B26-47A0-A0F4-61C0B482BADF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF55F855-1B26-47A0-A0F4-61C0B482BADF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF55F855-1B26-47A0-A0F4-61C0B482BADF}.Release|Any CPU.Build.0 = Release|Any CPU
{85BA9DE7-5526-4937-8C40-4EC3D2DD4455}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85BA9DE7-5526-4937-8C40-4EC3D2DD4455}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85BA9DE7-5526-4937-8C40-4EC3D2DD4455}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85BA9DE7-5526-4937-8C40-4EC3D2DD4455}.Release|Any CPU.Build.0 = Release|Any CPU
{4AB4F9D3-6C63-44E3-8484-2CC0DD460E33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4AB4F9D3-6C63-44E3-8484-2CC0DD460E33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4AB4F9D3-6C63-44E3-8484-2CC0DD460E33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4AB4F9D3-6C63-44E3-8484-2CC0DD460E33}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{B9913396-5C97-4296-97A4-9F0D7716A1E6} = {07187FF1-BBBA-4EC6-A16B-A88BFB309065}
{10DFF0FD-CF81-4C18-AFA5-2EEACEAC0845} = {07187FF1-BBBA-4EC6-A16B-A88BFB309065}
{EF55F855-1B26-47A0-A0F4-61C0B482BADF} = {07187FF1-BBBA-4EC6-A16B-A88BFB309065}
{85BA9DE7-5526-4937-8C40-4EC3D2DD4455} = {BEE4A397-41B9-4EFC-A37C-C74F1A97ACBE}
{4AB4F9D3-6C63-44E3-8484-2CC0DD460E33} = {BEE4A397-41B9-4EFC-A37C-C74F1A97ACBE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {82B031CC-A5AC-4C7B-BC85-EFBC09207DBB}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
using System.Collections.Concurrent;
using System.Security.Cryptography.X509Certificates;
using k8s;
using k8s.Models;
using Microsoft.AspNetCore.Connections;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Yarp.Kubernetes.Controller;
using Yarp.Kubernetes.Controller.Caching;
using Yarp.Kubernetes.Controller.Certificates;
using Yarp.Kubernetes.Controller.Client;

namespace NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates;

public class IngressServerCertificateManager : IHostedService
{
private readonly IngressServerCertificateSelector _certificateSelector;

private readonly object _lock = new object();

private readonly ICache _cache;

private readonly ILogger _logger;

private readonly ConcurrentDictionary<NamespacedName, X509Certificate2> _secrets = new();

private readonly ICertificateHelper _certificateHelper;

public IngressServerCertificateManager(
IngressServerCertificateSelector certificateSelector,
ICache cache,
ICertificateHelper certificateHelper,
IResourceInformer<V1Secret> secretInformer,
IResourceInformer<V1Ingress> ingressInformer,
ILogger<IngressServerCertificateManager> logger)
{
_certificateSelector = certificateSelector;
_cache = cache;
_certificateHelper = certificateHelper;
secretInformer.Register(Update);
ingressInformer.Register(Update);
_logger = logger;
}

private void Update(WatchEventType eventType, V1Ingress ingress)
{
try
{
ResetCertificates();
}
catch (Exception e)
{
_logger.LogError(e, "Update ingress certificate error when update ingress");
}
}

private void Update(WatchEventType eventType, V1Secret resource)
{
try
{
NamespacedName n = new NamespacedName(resource.Namespace(), resource.Name());
switch (eventType)
{
case WatchEventType.Added:
case WatchEventType.Modified:
_secrets.TryAdd(n, _certificateHelper.ConvertCertificate(n, resource));
break;
case WatchEventType.Deleted:
_secrets.TryRemove(n, out _);
break;
}

ResetCertificates();
}
catch (Exception e)
{
_logger.LogError(e, "Update ingress certificate error when update secret");
}
}


private void ResetCertificates()
{
lock (_lock)
{
var certs = new Dictionary<string, X509Certificate2>();
var wildcardCerts = new Dictionary<string, X509Certificate2>();
foreach (var ingress in _cache.GetIngresses())
{
if (ingress.Spec?.Tls == null) continue;

foreach (var tls in ingress.Spec.Tls)
{
if (!string.IsNullOrEmpty(tls.SecretName))
{
var secretName = new NamespacedName(ingress.Metadata.Namespace(), tls.SecretName);
if (_secrets.TryGetValue(secretName, out var certificate))
{
foreach (var host in tls.Hosts)
{
if (IsWildcardDomain(host))
{
wildcardCerts[host] = certificate;
}
else
{
certs[host] = certificate;
}
}
}
}
}
}

Interlocked.Exchange(ref _certificateSelector._domainCertificates, certs);
Interlocked.Exchange(ref _certificateSelector._wildcardDomainCertificates, wildcardCerts);
}
}


bool IsWildcardDomain(string domainName)
{
return domainName.StartsWith("*", StringComparison.Ordinal);
}

bool TryToWildcardDomain(string domainName, out string wildcardDomainName)
{
wildcardDomainName = string.Empty;
var index = domainName.IndexOf(".", StringComparison.Ordinal);
if (index == -1)
{
return false;
}

wildcardDomainName = string.Concat("*", domainName.AsSpan(index));
return true;
}

public Task StartAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Connections;
using Yarp.Kubernetes.Controller;
using Yarp.Kubernetes.Controller.Certificates;

namespace NetCorePal.Yarp.Kubernetes.Controller.IngressCertificates;

public class IngressServerCertificateSelector : IServerCertificateSelector
{
private X509Certificate2? _defaultCertificate = null;

internal volatile Dictionary<string, X509Certificate2> _domainCertificates = new();

internal volatile Dictionary<string, X509Certificate2> _wildcardDomainCertificates = new();


public X509Certificate2? GetCertificate(ConnectionContext connectionContext, string domainName)
{
if (_domainCertificates.TryGetValue(domainName, out var certificate))
{
return certificate;
}

if (TryToWildcardDomain(domainName, out var wildcardDomainName)
&& _wildcardDomainCertificates.TryGetValue(wildcardDomainName, out var certificate1))
{
return certificate1;
}

return _defaultCertificate;
}

public void AddCertificate(NamespacedName certificateName, X509Certificate2 certificate)
{
_defaultCertificate = certificate;
}

public void RemoveCertificate(NamespacedName certificateName)
{
_defaultCertificate = null;
}

bool TryToWildcardDomain(string domainName, out string wildcardDomainName)
{
wildcardDomainName = string.Empty;
var index = domainName.IndexOf(".", StringComparison.Ordinal);
if (index == -1)
{
return false;
}

wildcardDomainName = string.Concat("*", domainName.AsSpan(index));
return true;
}
}
Loading

0 comments on commit 531cbde

Please sign in to comment.