Merge pull request #50 from tg123/movector
DelegatingHandler now works with Kubernetes clients
This commit is contained in:
@@ -1,38 +1,36 @@
|
||||
using k8s.Models;
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net.Http;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using k8s.Exceptions;
|
||||
using Microsoft.Rest;
|
||||
|
||||
namespace k8s
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net.Http;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading.Tasks;
|
||||
using k8s.Exceptions;
|
||||
using Microsoft.Rest;
|
||||
|
||||
public partial class Kubernetes : ServiceClient<Kubernetes>, IKubernetes
|
||||
public partial class Kubernetes
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Kubernetes"/> class.
|
||||
/// Initializes a new instance of the <see cref="Kubernetes" /> class.
|
||||
/// </summary>
|
||||
/// <param name='config'>
|
||||
/// Optional. The delegating handlers to add to the http client pipeline.
|
||||
/// Optional. The delegating handlers to add to the http client pipeline.
|
||||
/// </param>
|
||||
public Kubernetes(KubernetesClientConfiguration config)
|
||||
/// <param name="handlers">
|
||||
/// Optional. The delegating handlers to add to the http client pipeline.
|
||||
/// </param>
|
||||
public Kubernetes(KubernetesClientConfiguration config, params DelegatingHandler[] handlers) : this(handlers)
|
||||
{
|
||||
this.Initialize();
|
||||
|
||||
this.CaCert = config.SslCaCert;
|
||||
this.BaseUri = new Uri(config.Host);
|
||||
|
||||
var handler = new HttpClientHandler();
|
||||
CaCert = config.SslCaCert;
|
||||
BaseUri = new Uri(config.Host);
|
||||
|
||||
if (BaseUri.Scheme == "https")
|
||||
{
|
||||
if (config.SkipTlsVerify)
|
||||
{
|
||||
handler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
|
||||
HttpClientHandler.ServerCertificateCustomValidationCallback =
|
||||
(sender, certificate, chain, sslPolicyErrors) => true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -41,21 +39,47 @@ namespace k8s
|
||||
throw new KubeConfigException("a CA must be set when SkipTlsVerify === false");
|
||||
}
|
||||
|
||||
handler.ServerCertificateCustomValidationCallback = CertificateValidationCallBack;
|
||||
HttpClientHandler.ServerCertificateCustomValidationCallback = CertificateValidationCallBack;
|
||||
}
|
||||
}
|
||||
|
||||
// set credentails for the kubernernet client
|
||||
this.SetCredentials(config, handler);
|
||||
this.InitializeHttpClient(handler, new DelegatingHandler[]{new WatcherDelegatingHandler()});
|
||||
|
||||
DeserializationSettings.Converters.Add(new V1Status.V1StatusObjectViewConverter());
|
||||
SetCredentials(config, HttpClientHandler);
|
||||
}
|
||||
|
||||
private X509Certificate2 CaCert { get; set; }
|
||||
private X509Certificate2 CaCert { get; }
|
||||
|
||||
partial void CustomInitialize()
|
||||
{
|
||||
AppendDelegatingHandler<WatcherDelegatingHandler>();
|
||||
DeserializationSettings.Converters.Add(new V1Status.V1StatusObjectViewConverter());
|
||||
}
|
||||
|
||||
private void AppendDelegatingHandler<T>() where T : DelegatingHandler, new()
|
||||
{
|
||||
var cur = FirstMessageHandler as DelegatingHandler;
|
||||
|
||||
while (cur != null)
|
||||
{
|
||||
var next = cur.InnerHandler as DelegatingHandler;
|
||||
|
||||
if (next == null)
|
||||
{
|
||||
// last one
|
||||
// append watcher handler between to last handler
|
||||
cur.InnerHandler = new T
|
||||
{
|
||||
InnerHandler = cur.InnerHandler
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set credentials for the Client
|
||||
/// Set credentials for the Client
|
||||
/// </summary>
|
||||
/// <param name="config">k8s client configuration</param>
|
||||
/// <param name="handler">http client handler for the rest client</param>
|
||||
@@ -88,7 +112,7 @@ namespace k8s
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SSl Cert Validation Callback
|
||||
/// SSl Cert Validation Callback
|
||||
/// </summary>
|
||||
/// <param name="sender">sender</param>
|
||||
/// <param name="certificate">client certificate</param>
|
||||
@@ -97,10 +121,10 @@ namespace k8s
|
||||
/// <returns>true if valid cert</returns>
|
||||
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "Unused by design")]
|
||||
private bool CertificateValidationCallBack(
|
||||
object sender,
|
||||
X509Certificate certificate,
|
||||
X509Chain chain,
|
||||
SslPolicyErrors sslPolicyErrors)
|
||||
object sender,
|
||||
X509Certificate certificate,
|
||||
X509Chain chain,
|
||||
SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
// If the certificate is a valid, signed certificate, return true.
|
||||
if (sslPolicyErrors == SslPolicyErrors.None)
|
||||
@@ -114,16 +138,13 @@ namespace k8s
|
||||
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
||||
|
||||
// add all your extra certificate chain
|
||||
chain.ChainPolicy.ExtraStore.Add(this.CaCert);
|
||||
chain.ChainPolicy.ExtraStore.Add(CaCert);
|
||||
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
|
||||
var isValid = chain.Build((X509Certificate2)certificate);
|
||||
var isValid = chain.Build((X509Certificate2) certificate);
|
||||
return isValid;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In all other cases, return false.
|
||||
return false;
|
||||
}
|
||||
// In all other cases, return false.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,17 +24,6 @@ namespace k8s
|
||||
? Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), @".kube\config")
|
||||
: Path.Combine(Environment.GetEnvironmentVariable("HOME"), ".kube/config");
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KubernetesClientConfiguration"/> class.
|
||||
/// </summary>
|
||||
/// <param name="kubeconfig">kubeconfig file info</param>
|
||||
/// <param name="currentContext">Context to use from kube config</param>
|
||||
public KubernetesClientConfiguration(FileInfo kubeconfig = null, string currentContext = null)
|
||||
{
|
||||
var k8SConfig = LoadKubeConfig(kubeconfig ?? new FileInfo(KubeConfigDefaultLocation));
|
||||
this.Initialize(k8SConfig, currentContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KubernetesClientConfiguration"/> from config file
|
||||
/// </summary>
|
||||
@@ -60,7 +49,7 @@ namespace k8s
|
||||
|
||||
var k8SConfig = LoadKubeConfig(kubeconfig);
|
||||
var k8SConfiguration = new KubernetesClientConfiguration();
|
||||
k8SConfiguration.Initialize(k8SConfig);
|
||||
k8SConfiguration.Initialize(k8SConfig, currentContext);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(masterUrl))
|
||||
{
|
||||
@@ -200,7 +189,7 @@ namespace k8s
|
||||
/// <summary>
|
||||
/// Loads Kube Config
|
||||
/// </summary>
|
||||
/// <param name="config">Kube config file contents</param>
|
||||
/// <param name="kubeconfig">Kube config file contents</param>
|
||||
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
||||
private static K8SConfiguration LoadKubeConfig(FileInfo kubeconfig)
|
||||
{
|
||||
|
||||
@@ -1,78 +1,67 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace k8s
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using k8s.Exceptions;
|
||||
using k8s.KubeConfigModels;
|
||||
using YamlDotNet.Serialization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a set of kubernetes client configuration settings
|
||||
/// Represents a set of kubernetes client configuration settings
|
||||
/// </summary>
|
||||
public partial class KubernetesClientConfiguration
|
||||
{
|
||||
public KubernetesClientConfiguration()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets Host
|
||||
/// Gets Host
|
||||
/// </summary>
|
||||
public string Host { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets SslCaCert
|
||||
/// Gets SslCaCert
|
||||
/// </summary>
|
||||
public X509Certificate2 SslCaCert { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets ClientCertificateData
|
||||
/// Gets ClientCertificateData
|
||||
/// </summary>
|
||||
public string ClientCertificateData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets ClientCertificate Key
|
||||
/// Gets ClientCertificate Key
|
||||
/// </summary>
|
||||
public string ClientCertificateKeyData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets ClientCertificate filename
|
||||
/// Gets ClientCertificate filename
|
||||
/// </summary>
|
||||
public string ClientCertificateFilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets ClientCertificate Key filename
|
||||
/// Gets ClientCertificate Key filename
|
||||
/// </summary>
|
||||
public string ClientKeyFilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to skip ssl server cert validation
|
||||
/// Gets a value indicating whether to skip ssl server cert validation
|
||||
/// </summary>
|
||||
public bool SkipTlsVerify { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HTTP user agent.
|
||||
/// Gets or sets the HTTP user agent.
|
||||
/// </summary>
|
||||
/// <value>Http user agent.</value>
|
||||
public string UserAgent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the username (HTTP basic authentication).
|
||||
/// Gets or sets the username (HTTP basic authentication).
|
||||
/// </summary>
|
||||
/// <value>The username.</value>
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the password (HTTP basic authentication).
|
||||
/// Gets or sets the password (HTTP basic authentication).
|
||||
/// </summary>
|
||||
/// <value>The password.</value>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the access token for OAuth2 authentication.
|
||||
/// Gets or sets the access token for OAuth2 authentication.
|
||||
/// </summary>
|
||||
/// <value>The access token.</value>
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace k8s.Tests
|
||||
public void LoadFromFiles()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigFileName);
|
||||
var cfg = new KubernetesClientConfiguration(fi, "federal-context");
|
||||
var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, "federal-context");
|
||||
|
||||
// Just validate that this doesn't throw and private key is non-null
|
||||
var cert = CertUtils.GeneratePfx(cfg);
|
||||
@@ -33,7 +33,7 @@ namespace k8s.Tests
|
||||
public void LoadFromInlineData()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigFileName);
|
||||
var cfg = new KubernetesClientConfiguration(fi, "victorian-context");
|
||||
var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, "victorian-context");
|
||||
|
||||
// Just validate that this doesn't throw and private key is non-null
|
||||
var cert = CertUtils.GeneratePfx(cfg);
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace k8s.Tests
|
||||
public void ConfigurationFileNotFound()
|
||||
{
|
||||
var fi = new FileInfo("/path/to/nowhere");
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => new KubernetesClientConfiguration(fi));
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -73,7 +73,7 @@ namespace k8s.Tests
|
||||
[Fact]
|
||||
public void DefaultConfigurationLoaded()
|
||||
{
|
||||
var cfg = new KubernetesClientConfiguration(new FileInfo(kubeConfigFileName));
|
||||
var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(new FileInfo(kubeConfigFileName));
|
||||
Assert.NotNull(cfg.Host);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace k8s.Tests
|
||||
public void ContextHost(string context, string host)
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigFileName);
|
||||
var cfg = new KubernetesClientConfiguration(fi, context);
|
||||
var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, context);
|
||||
Assert.Equal(host, cfg.Host);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace k8s.Tests
|
||||
public void ContextUserToken(string context, string token)
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigFileName);
|
||||
var cfg = new KubernetesClientConfiguration(fi, context);
|
||||
var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, context);
|
||||
Assert.Equal(context, cfg.CurrentContext);
|
||||
Assert.Null(cfg.Username);
|
||||
Assert.Equal(token, cfg.AccessToken);
|
||||
@@ -117,7 +117,7 @@ namespace k8s.Tests
|
||||
public void ContextCertificateTest(string context, string clientCert, string clientCertKey)
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigFileName);
|
||||
var cfg = new KubernetesClientConfiguration(fi, context);
|
||||
var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, context);
|
||||
Assert.Equal(context, cfg.CurrentContext);
|
||||
Assert.Equal(cfg.ClientCertificateFilePath, clientCert);
|
||||
Assert.Equal(cfg.ClientKeyFilePath, clientCertKey);
|
||||
@@ -129,10 +129,10 @@ namespace k8s.Tests
|
||||
/// <param name="context">Context to retreive the configuration</param>
|
||||
[Theory]
|
||||
[InlineData("victorian-context")]
|
||||
public void ClientDataTest(string context)
|
||||
public void ClientData(string context)
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigFileName);
|
||||
var cfg = new KubernetesClientConfiguration(fi, context);
|
||||
var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, context);
|
||||
Assert.Equal(context, cfg.CurrentContext);
|
||||
Assert.NotNull(cfg.SslCaCert);
|
||||
Assert.Equal(readLine("assets/client-certificate-data.txt"), cfg.ClientCertificateData);
|
||||
@@ -147,7 +147,7 @@ namespace k8s.Tests
|
||||
public void ContextNotFound()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigFileName);
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => new KubernetesClientConfiguration(fi, "context-not-found"));
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, "context-not-found"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -157,7 +157,7 @@ namespace k8s.Tests
|
||||
public void NoContexts()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigNoContexts);
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => new KubernetesClientConfiguration(fi));
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -167,7 +167,7 @@ namespace k8s.Tests
|
||||
public void NoContextsExplicit()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigNoContexts);
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => new KubernetesClientConfiguration(fi, "context"));
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, "context"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -177,7 +177,7 @@ namespace k8s.Tests
|
||||
public void UserPasswordAuthentication()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigUserPassword);
|
||||
var cfg = new KubernetesClientConfiguration(fi);
|
||||
var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi);
|
||||
Assert.Equal("admin", cfg.Username);
|
||||
Assert.Equal("secret", cfg.Password);
|
||||
}
|
||||
@@ -189,7 +189,7 @@ namespace k8s.Tests
|
||||
public void IncompleteUserCredentials()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigNoCredentials);
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => new KubernetesClientConfiguration(fi));
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -199,7 +199,7 @@ namespace k8s.Tests
|
||||
public void ServerNotFound()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigNoServer);
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => new KubernetesClientConfiguration(fi));
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -209,7 +209,7 @@ namespace k8s.Tests
|
||||
public void ClusterNotFound()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigNoCluster);
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => new KubernetesClientConfiguration(fi));
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -219,7 +219,7 @@ namespace k8s.Tests
|
||||
public void ClusterNameMissmatch()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigClusterMissmatch);
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => new KubernetesClientConfiguration(fi));
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -229,7 +229,7 @@ namespace k8s.Tests
|
||||
public void CheckClusterTlsCorrectness()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigTlsNoSkipError);
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => new KubernetesClientConfiguration(fi));
|
||||
Assert.Throws<k8s.Exceptions.KubeConfigException>(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -239,7 +239,7 @@ namespace k8s.Tests
|
||||
public void CheckClusterTlsSkipCorrectness()
|
||||
{
|
||||
var fi = new FileInfo(kubeConfigTlsSkip);
|
||||
var cfg = new KubernetesClientConfiguration(fi);
|
||||
var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi);
|
||||
Assert.NotNull(cfg.Host);
|
||||
Assert.Null(cfg.SslCaCert);
|
||||
Assert.True(cfg.SkipTlsVerify);
|
||||
@@ -251,7 +251,7 @@ namespace k8s.Tests
|
||||
// [Fact]
|
||||
// public void ListDefaultNamespacedPod()
|
||||
// {
|
||||
// var k8sClientConfig = new KubernetesClientConfiguration();
|
||||
// var k8sClientConfig = KubernetesClientConfiguration.BuildConfigFromConfigFile();
|
||||
// IKubernetes client = new Kubernetes(k8sClientConfig);
|
||||
// var listTask = client.ListNamespacedPodWithHttpMessagesAsync("default").Result;
|
||||
// var list = listTask.Body;
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace k8s.Tests
|
||||
public class V1StatusObjectViewTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestReturnStatus()
|
||||
public void ReturnStatus()
|
||||
{
|
||||
var v1Status = new V1Status
|
||||
{
|
||||
@@ -32,7 +32,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestReturnObject()
|
||||
public void ReturnObject()
|
||||
{
|
||||
var corev1Namespace = new Corev1Namespace()
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using k8s.Exceptions;
|
||||
@@ -270,5 +271,62 @@ namespace k8s.Tests
|
||||
Assert.False(watcher.Watching);
|
||||
Assert.IsType<IOException>(exceptionCatched);
|
||||
}
|
||||
|
||||
private class DummyHandler : DelegatingHandler
|
||||
{
|
||||
internal bool Called { get; private set; }
|
||||
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
Called = true;
|
||||
return base.SendAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestWatchWithHandlers()
|
||||
{
|
||||
using (var server = new MockKubeApiServer(async httpContext =>
|
||||
{
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse);
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(100));
|
||||
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine);
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(100));
|
||||
|
||||
// make server alive, cannot set to int.max as of it would block response
|
||||
await Task.Delay(TimeSpan.FromDays(1));
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
var handler1 = new DummyHandler();
|
||||
var handler2 = new DummyHandler();
|
||||
|
||||
var client = new Kubernetes(new KubernetesClientConfiguration
|
||||
{
|
||||
Host = server.Uri.ToString()
|
||||
}, handler1, handler2);
|
||||
|
||||
Assert.False(handler1.Called);
|
||||
Assert.False(handler2.Called);
|
||||
|
||||
var listTask = client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).Result;
|
||||
|
||||
var events = new HashSet<WatchEventType>();
|
||||
|
||||
var watcher = listTask.Watch<Corev1Pod>(
|
||||
(type, item) => { events.Add(type); }
|
||||
);
|
||||
|
||||
// wait server yields all events
|
||||
Thread.Sleep(TimeSpan.FromMilliseconds(500));
|
||||
|
||||
Assert.Contains(WatchEventType.Added, events);
|
||||
|
||||
Assert.True(handler1.Called);
|
||||
Assert.True(handler2.Called);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user