public void Cert() { var serverCertificateData = File.ReadAllText("assets/apiserver-pfx-data.txt"); var clientCertificateKeyData = File.ReadAllText("assets/client-key-data.txt"); var clientCertificateData = File.ReadAllText("assets/client-certificate-data.txt"); X509Certificate2 serverCertificate = null; if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { using (var serverCertificateStream = new MemoryStream(Convert.FromBase64String(serverCertificateData))) { serverCertificate = OpenCertificateStore(serverCertificateStream); } } else { serverCertificate = new X509Certificate2(Convert.FromBase64String(serverCertificateData), ""); } var clientCertificate = new X509Certificate2(Convert.FromBase64String(clientCertificateData), ""); var clientCertificateValidationCalled = false; using (var server = new MockKubeApiServer(testOutput, listenConfigure: options => { options.UseHttps(new HttpsConnectionAdapterOptions { ServerCertificate = serverCertificate, ClientCertificateMode = ClientCertificateMode.RequireCertificate, ClientCertificateValidation = (certificate, chain, valid) => { clientCertificateValidationCalled = true; return(clientCertificate.Equals(certificate)); }, }); })) { { clientCertificateValidationCalled = false; var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), ClientCertificateData = clientCertificateData, ClientCertificateKeyData = clientCertificateKeyData, SslCaCerts = new X509Certificate2Collection(serverCertificate), SkipTlsVerify = false, }); var listTask = ExecuteListPods(client); Assert.True(clientCertificateValidationCalled); Assert.True(listTask.Response.IsSuccessStatusCode); Assert.Equal(1, listTask.Body.Items.Count); } { clientCertificateValidationCalled = false; var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), ClientCertificateData = clientCertificateData, ClientCertificateKeyData = clientCertificateKeyData, SkipTlsVerify = true, }); var listTask = ExecuteListPods(client); Assert.True(clientCertificateValidationCalled); Assert.True(listTask.Response.IsSuccessStatusCode); Assert.Equal(1, listTask.Body.Items.Count); } { clientCertificateValidationCalled = false; var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), ClientCertificateFilePath = "assets/client.crt", // TODO amazoning why client.crt != client-data.txt ClientKeyFilePath = "assets/client.key", SkipTlsVerify = true, }); Assert.ThrowsAny <Exception>(() => ExecuteListPods(client)); Assert.True(clientCertificateValidationCalled); } { clientCertificateValidationCalled = false; var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), SkipTlsVerify = true, }); Assert.ThrowsAny <Exception>(() => ExecuteListPods(client)); Assert.False(clientCertificateValidationCalled); } } }
public void Token() { const string token = "testingtoken"; using (var server = new MockKubeApiServer(testOutput, cxt => { var header = cxt.Request.Headers["Authorization"].FirstOrDefault(); var expect = new AuthenticationHeaderValue("Bearer", token).ToString(); if (header != expect) { cxt.Response.StatusCode = (int)HttpStatusCode.Unauthorized; return(Task.FromResult(false)); } return(Task.FromResult(true)); })) { { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), AccessToken = token, }); var listTask = ExecuteListPods(client); Assert.True(listTask.Response.IsSuccessStatusCode); Assert.Equal(1, listTask.Body.Items.Count); } { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), AccessToken = "wrong token", }); var listTask = ExecuteListPods(client); Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), Username = "******", Password = "******", }); var listTask = ExecuteListPods(client); Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = ExecuteListPods(client); Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } } }
public void BasicAuth() { const string testName = "test_name"; const string testPassword = "******"; using (var server = new MockKubeApiServer(testOutput, cxt => { var header = cxt.Request.Headers["Authorization"].FirstOrDefault(); var expect = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{testName}:{testPassword}"))) .ToString(); if (header != expect) { cxt.Response.StatusCode = (int)HttpStatusCode.Unauthorized; return(Task.FromResult(false)); } return(Task.FromResult(true)); })) { { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), Username = testName, Password = testPassword, }); var listTask = ExecuteListPods(client); Assert.True(listTask.Response.IsSuccessStatusCode); Assert.Equal(1, listTask.Body.Items.Count); } { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), Username = "******", Password = testPassword, }); var listTask = ExecuteListPods(client); Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), Username = testName, Password = "******", }); var listTask = ExecuteListPods(client); Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), Username = "******", Password = "******", }); var listTask = ExecuteListPods(client); Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = ExecuteListPods(client); Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), Username = "******", }); var listTask = ExecuteListPods(client); Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } } }
public void ExternalCertificate() { const string name = "testing_irrelevant"; var serverCertificateData = Convert.FromBase64String(File.ReadAllText("assets/apiserver-pfx-data.txt")); var clientCertificateKeyData = Convert.FromBase64String(File.ReadAllText("assets/client-key-data.txt")); var clientCertificateData = Convert.FromBase64String(File.ReadAllText("assets/client-certificate-data.txt")); X509Certificate2 serverCertificate = null; if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { using (MemoryStream serverCertificateStream = new MemoryStream(serverCertificateData)) { serverCertificate = OpenCertificateStore(serverCertificateStream); } } else { serverCertificate = new X509Certificate2(serverCertificateData, ""); } var clientCertificate = new X509Certificate2(clientCertificateData, ""); var clientCertificateValidationCalled = false; using (var server = new MockKubeApiServer(testOutput, listenConfigure: options => { options.UseHttps(new HttpsConnectionAdapterOptions { ServerCertificate = serverCertificate, ClientCertificateMode = ClientCertificateMode.RequireCertificate, ClientCertificateValidation = (certificate, chain, valid) => { clientCertificateValidationCalled = true; return(clientCertificate.Equals(certificate)); }, }); })) { { var clientCertificateText = Encoding.ASCII.GetString(clientCertificateData).Replace("\n", "\\n"); var clientCertificateKeyText = Encoding.ASCII.GetString(clientCertificateKeyData).Replace("\n", "\\n"); var responseJson = $"{{\"apiVersion\":\"testingversion\",\"status\":{{\"clientCertificateData\":\"{clientCertificateText}\",\"clientKeyData\":\"{clientCertificateKeyText}\"}}}}"; var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), responseJson, name); var clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name); var client = new Kubernetes(clientConfig); var listTask = ExecuteListPods(client); Assert.True(listTask.Response.IsSuccessStatusCode); Assert.Equal(1, listTask.Body.Items.Count); } { var clientCertificateText = File.ReadAllText("assets/client.crt").Replace("\n", "\\n"); var clientCertificateKeyText = File.ReadAllText("assets/client.key").Replace("\n", "\\n"); var responseJson = $"{{\"apiVersion\":\"testingversion\",\"status\":{{\"clientCertificateData\":\"{clientCertificateText}\",\"clientKeyData\":\"{clientCertificateKeyText}\"}}}}"; var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), responseJson, name); var clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name); var client = new Kubernetes(clientConfig); Assert.ThrowsAny <Exception>(() => ExecuteListPods(client)); Assert.True(clientCertificateValidationCalled); } } }
public async Task SuriveBadLine() { AsyncCountdownEvent eventsReceived = new AsyncCountdownEvent(5); AsyncManualResetEvent serverShutdown = new AsyncManualResetEvent(); AsyncManualResetEvent connectionClosed = new AsyncManualResetEvent(); using (var server = new MockKubeApiServer( testOutput, async httpContext => { httpContext.Response.StatusCode = (int)HttpStatusCode.OK; httpContext.Response.ContentLength = null; await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse); await WriteStreamLine(httpContext, MockBadStreamLine); await WriteStreamLine(httpContext, MockAddedEventStreamLine); await WriteStreamLine(httpContext, MockBadStreamLine); await WriteStreamLine(httpContext, MockModifiedStreamLine); // make server alive, cannot set to int.max as of it would block response await serverShutdown.WaitAsync(); return(false); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch : true); var events = new HashSet <WatchEventType>(); var errors = 0; var watcher = listTask.Watch <V1Pod>( (type, item) => { testOutput.WriteLine($"Watcher received '{type}' event."); events.Add(type); eventsReceived.Signal(); }, error => { testOutput.WriteLine($"Watcher received '{error.GetType().FullName}' error."); errors += 1; eventsReceived.Signal(); }, onClosed: connectionClosed.Set ); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, "Timed out waiting for all events / errors to be received." ); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Modified, events); Assert.Equal(3, errors); Assert.True(watcher.Watching); // Let the server know it can initiate a shut down. serverShutdown.Set(); await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)); Assert.True(connectionClosed.IsSet); } }
public async Task DirectWatchEventsWithTimeout() { AsyncCountdownEvent eventsReceived = new AsyncCountdownEvent(4); AsyncManualResetEvent serverShutdown = new AsyncManualResetEvent(); using (var server = new MockKubeApiServer(testOutput, async httpContext => { await Task.Delay(TimeSpan.FromSeconds(120)); // The default timeout is 100 seconds await WriteStreamLine(httpContext, MockAddedEventStreamLine); await WriteStreamLine(httpContext, MockDeletedStreamLine); await WriteStreamLine(httpContext, MockModifiedStreamLine); await WriteStreamLine(httpContext, MockErrorStreamLine); // make server alive, cannot set to int.max as of it would block response await serverShutdown.WaitAsync(); return(false); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var events = new HashSet <WatchEventType>(); var errors = 0; var watcher = await client.WatchNamespacedPodAsync( name : "myPod", @namespace : "default", onEvent : (type, item) => { testOutput.WriteLine($"Watcher received '{type}' event."); events.Add(type); eventsReceived.Signal(); }, onError : error => { testOutput.WriteLine($"Watcher received '{error.GetType().FullName}' error."); errors += 1; eventsReceived.Signal(); } ); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, "Timed out waiting for all events / errors to be received." ); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Deleted, events); Assert.Contains(WatchEventType.Modified, events); Assert.Contains(WatchEventType.Error, events); Assert.Equal(0, errors); Assert.True(watcher.Watching); serverShutdown.Set(); } }
public async Task WatchAllEvents() { AsyncCountdownEvent eventsReceived = new AsyncCountdownEvent(4 /* first line of response is eaten by WatcherDelegatingHandler */); AsyncManualResetEvent serverShutdown = new AsyncManualResetEvent(); var waitForClosed = new AsyncManualResetEvent(false); using (var server = new MockKubeApiServer(testOutput, async httpContext => { await WriteStreamLine(httpContext, MockAddedEventStreamLine); await WriteStreamLine(httpContext, MockDeletedStreamLine); await WriteStreamLine(httpContext, MockModifiedStreamLine); await WriteStreamLine(httpContext, MockErrorStreamLine); // make server alive, cannot set to int.max as of it would block response await serverShutdown.WaitAsync(); return(false); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch : true); var events = new HashSet <WatchEventType>(); var errors = 0; var watcher = listTask.Watch <V1Pod>( (type, item) => { testOutput.WriteLine($"Watcher received '{type}' event."); events.Add(type); eventsReceived.Signal(); }, error => { testOutput.WriteLine($"Watcher received '{error.GetType().FullName}' error."); errors += 1; eventsReceived.Signal(); }, onClosed: waitForClosed.Set ); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, "Timed out waiting for all events / errors to be received." ); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Deleted, events); Assert.Contains(WatchEventType.Modified, events); Assert.Contains(WatchEventType.Error, events); Assert.Equal(0, errors); Assert.True(watcher.Watching); serverShutdown.Set(); await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout)); Assert.True(waitForClosed.IsSet); Assert.False(watcher.Watching); } }
public async Task DisposeWatch() { var connectionClosed = new AsyncManualResetEvent(); var eventsReceived = new AsyncCountdownEvent(1); bool serverRunning = true; using (var server = new MockKubeApiServer(testOutput, async httpContext => { await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse); while (serverRunning) { await WriteStreamLine(httpContext, MockAddedEventStreamLine); } return(true); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch : true); var events = new HashSet <WatchEventType>(); var watcher = listTask.Watch <V1Pod>( (type, item) => { events.Add(type); eventsReceived.Signal(); }, onClosed: connectionClosed.Set ); // wait at least an event await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, "Timed out waiting for events." ); Assert.NotEmpty(events); Assert.True(watcher.Watching); watcher.Dispose(); events.Clear(); // Let the server disconnect serverRunning = false; var timeout = Task.Delay(TestTimeout); while (!timeout.IsCompleted && watcher.Watching) { await Task.Yield(); } Assert.Empty(events); Assert.False(watcher.Watching); Assert.True(connectionClosed.IsSet); } }