public async Task Usbmuxd_CanListDevices_Async() { var config = KubernetesClientConfiguration.BuildDefaultConfig(); if (config.Namespace == null) { config.Namespace = "default"; } using (var kubernetes = new KubernetesProtocol( config, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory)) using (var client = new KubernetesClient( kubernetes, KubernetesOptions.Default, this.output.BuildLoggerFor <KubernetesClient>(), this.loggerFactory)) { // There's at least one usbmuxd pod var pods = await kubernetes.ListNamespacedPodAsync(config.Namespace, labelSelector : "app.kubernetes.io/component=usbmuxd"); Assert.NotEmpty(pods.Items); var pod = pods.Items[0]; // The pod is in the running state pod = await client.WaitForPodRunningAsync(pod, TimeSpan.FromMinutes(2), default).ConfigureAwait(false); Assert.Equal("Running", pod.Status.Phase); // We can connect to port 27015 and retrieve an empty device list var locator = new KubernetesMuxerSocketLocator(kubernetes, pod, this.loggerFactory.CreateLogger <KubernetesMuxerSocketLocator>(), this.loggerFactory); var muxerClient = new MuxerClient(locator, this.loggerFactory.CreateLogger <MuxerClient>(), this.loggerFactory); var devices = await muxerClient.ListDevicesAsync(default).ConfigureAwait(false);
public void KubernetesClient_IsConfigured() { using (var protocol = new KubernetesProtocol( KubernetesClientConfiguration.BuildConfigFromConfigFile("Polyfill/kubeconfig.yml"), NullLogger <KubernetesProtocol> .Instance, NullLoggerFactory.Instance)) { Assert.Collection( protocol.HttpMessageHandlers, (h) => { var apiHandler = Assert.IsType <CoreApiHandler>(h); Assert.NotNull(apiHandler.InnerHandler); }, (h) => { var watchHandler = Assert.IsType <WatchHandler>(h); Assert.NotNull(watchHandler.InnerHandler); }, (h) => { var handler = Assert.IsType <HttpClientHandler>(h); Assert.Collection( handler.ClientCertificates.OfType <X509Certificate2>(), c => { Assert.Equal("C2E33CEADA8CA7416367A0CA639EA155CC920319", c.Thumbprint); }); }); Assert.Equal(new Uri("https://127.0.0.1:443"), protocol.BaseUri); } }
public async Task WatchNamespacedObjectAsync_CancelsIfNeeded_Async() { var readTaskCompletion = new TaskCompletionSource <int>(); var stream = new Mock <Stream>(MockBehavior.Strict); stream.Setup(s => s.CanSeek).Returns(false); stream.Setup(s => s.CanRead).Returns(true); stream .Setup(s => s.ReadAsync(It.IsAny <Memory <byte> >(), It.IsAny <CancellationToken>())) .Returns <Memory <byte>, CancellationToken>(async(memory, cancellationToken) => await readTaskCompletion.Task); stream .Setup(s => s.Close()) .Callback(() => readTaskCompletion.TrySetException(new ObjectDisposedException("Stream", "Stream is being disposed, and all pending I/O cancelled"))) .Verifiable(); var handler = new DummyHandler(); handler.Responses.Enqueue( new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new WatchHttpContent( new StreamContent(stream.Object)), }); Collection <(WatchEventType, V1Pod)> events = new Collection <(WatchEventType, V1Pod)>(); var protocol = new KubernetesProtocol(handler, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); var cts = new CancellationTokenSource(); var watchTask = protocol.WatchNamespacedObjectAsync( new V1Pod() { Metadata = new V1ObjectMeta(name: "pod", namespaceProperty: "default", resourceVersion: "1"), }, protocol.ListNamespacedPodWithHttpMessagesAsync, (eventType, result) => { events.Add((eventType, result)); return(Task.FromResult(WatchResult.Continue)); }, cts.Token); Assert.False(watchTask.IsCompleted); cts.Cancel(); await Task.WhenAny( watchTask, Task.Delay(TimeSpan.FromSeconds(5))).ConfigureAwait(false); Assert.True(watchTask.IsCompletedSuccessfully); stream.Verify(); }
public async Task ApiServer_Is_Running_Async() { var config = KubernetesClientConfiguration.BuildDefaultConfig(); if (config.Namespace == null) { config.Namespace = "default"; } using (var kubernetes = new KubernetesProtocol( config, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory)) using (var client = new KubernetesClient( kubernetes, KubernetesOptions.Default, this.output.BuildLoggerFor <KubernetesClient>(), this.loggerFactory)) { // There's at least one operator pod var pods = await kubernetes.ListNamespacedPodAsync(config.Namespace, labelSelector : "app.kubernetes.io/component=operator"); Assert.NotEmpty(pods.Items); var pod = pods.Items[0]; // The pod is in the running state pod = await client.WaitForPodRunningAsync(pod, TimeSpan.FromMinutes(5), default).ConfigureAwait(false); Assert.Equal("Running", pod.Status.Phase); // We can connect to port 80 and fetch the status using (var httpClient = new HttpClient( new SocketsHttpHandler() { ConnectCallback = (context, cancellationToken) => client.ConnectToPodPortAsync(pod, 80, cancellationToken), })) { httpClient.BaseAddress = new Uri("http://localhost:80/"); var urls = new string[] { "/", "/health/ready", "/health/alive" }; foreach (var url in urls) { var response = await httpClient.GetAsync(url).ConfigureAwait(false); Assert.True(response.IsSuccessStatusCode); Assert.True(response.Headers.TryGetValues("X-Kaponata-Version", out var values)); Assert.Equal(ThisAssembly.AssemblyInformationalVersion, Assert.Single(values)); } } } }
public async Task WatchNamespacedObjectAsync_ValidatesArguments_Async() { var pod = new V1Pod() { Metadata = new V1ObjectMeta() { Name = "name", NamespaceProperty = "namespace" } }; var protocol = new KubernetesProtocol(new DummyHandler(), this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); await Assert.ThrowsAsync <ArgumentNullException>("value", () => protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>(null, protocol.ListNamespacedPodWithHttpMessagesAsync, (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ValidationException>(() => protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>(new V1Pod() { }, null, (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ValidationException>(() => protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>(new V1Pod() { Metadata = new V1ObjectMeta() }, null, (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ValidationException>(() => protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>(new V1Pod() { Metadata = new V1ObjectMeta() { Name = "test" } }, null, (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ValidationException>(() => protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>(new V1Pod() { Metadata = new V1ObjectMeta() { NamespaceProperty = "test" } }, null, (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ArgumentNullException>("listOperation", () => protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>(pod, null, (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ArgumentNullException>("eventHandler", () => protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>(pod, protocol.ListNamespacedPodWithHttpMessagesAsync, null, default)).ConfigureAwait(false); await Assert.ThrowsAsync <ArgumentNullException>("namespace", () => protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>(null, string.Empty, string.Empty, string.Empty, null, protocol.ListNamespacedPodWithHttpMessagesAsync, (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ArgumentNullException>("listOperation", () => protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>("default", null, null, null, null, null, (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ArgumentNullException>("eventHandler", () => protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>("default", null, null, null, null, protocol.ListNamespacedPodWithHttpMessagesAsync, null, default)).ConfigureAwait(false); }
public async Task WatchNamespacedObjectAsync_ThrowsExceptionIfNeeded_Async() { var handler = new DummyHandler(); handler.Responses.Enqueue( new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new WatchHttpContent( new StringContent( JsonConvert.SerializeObject( new V1WatchEvent() { Type = nameof(WatchEventType.Error), ObjectProperty = new V1Status() { Kind = "Status", Message = "ErrorMessage", }, }))), }); Collection <(WatchEventType, V1Pod)> events = new Collection <(WatchEventType, V1Pod)>(); var protocol = new KubernetesProtocol(handler, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); var cts = new CancellationTokenSource(); var ex = await Assert.ThrowsAsync <KubernetesException>( () => protocol.WatchNamespacedObjectAsync( new V1Pod() { Metadata = new V1ObjectMeta(name: "pod", namespaceProperty: "default", resourceVersion: "1"), }, protocol.ListNamespacedPodWithHttpMessagesAsync, (eventType, result) => { events.Add((eventType, result)); return(Task.FromResult(WatchResult.Continue)); }, cts.Token)).ConfigureAwait(false); Assert.Equal("ErrorMessage", ex.Message); }
public async Task WatchCustomResourceDefinitionAsync_ValidatesArguments_Async() { var protocol = new KubernetesProtocol(new DummyHandler(), this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); await Assert.ThrowsAsync <ArgumentNullException>("value", () => protocol.WatchCustomResourceDefinitionAsync(null, (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ValidationException>(() => protocol.WatchCustomResourceDefinitionAsync(new V1CustomResourceDefinition(), (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ValidationException>(() => protocol.WatchCustomResourceDefinitionAsync(new V1CustomResourceDefinition() { Metadata = new V1ObjectMeta() }, (eventType, result) => Task.FromResult(WatchResult.Continue), default)).ConfigureAwait(false); await Assert.ThrowsAsync <ArgumentNullException>("eventHandler", () => protocol.WatchCustomResourceDefinitionAsync(new V1CustomResourceDefinition() { Metadata = new V1ObjectMeta() { Name = "test" } }, null, default)).ConfigureAwait(false); }
public async Task Registry_Running_Async() { var config = KubernetesClientConfiguration.BuildDefaultConfig(); if (config.Namespace == null) { config.Namespace = "default"; } using (var kubernetes = new KubernetesProtocol( config, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory)) using (var client = new KubernetesClient( kubernetes, KubernetesOptions.Default, this.output.BuildLoggerFor <KubernetesClient>(), this.loggerFactory)) { // There's at least one usbmuxd pod var pods = await kubernetes.ListNamespacedPodAsync(config.Namespace, labelSelector : "app.kubernetes.io/component=registry"); Assert.NotEmpty(pods.Items); var pod = pods.Items[0]; // The pod is in the running state pod = await client.WaitForPodRunningAsync(pod, TimeSpan.FromMinutes(2), default).ConfigureAwait(false); Assert.Equal("Running", pod.Status.Phase); // Try to perform a handshake var httpClient = client.CreatePodHttpClient(pod, 5000); httpClient.BaseAddress = new Uri($"http://{pod.Metadata.Name}:5000/v2/"); var response = await httpClient.GetAsync(string.Empty).ConfigureAwait(false); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var apiVersion = Assert.Single(response.Headers.GetValues("Docker-Distribution-Api-Version")); Assert.Equal("registry/2.0", apiVersion); } }
public async Task Guacd_PerformsHandshake_Async() { var config = KubernetesClientConfiguration.BuildDefaultConfig(); if (config.Namespace == null) { config.Namespace = "default"; } using (var kubernetes = new KubernetesProtocol( config, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory)) using (var client = new KubernetesClient( kubernetes, KubernetesOptions.Default, this.output.BuildLoggerFor <KubernetesClient>(), this.loggerFactory)) { // There's at least one guacd pod var pods = await kubernetes.ListNamespacedPodAsync(config.Namespace, labelSelector : "app.kubernetes.io/name=guacamole,app.kubernetes.io/component=guacd"); Assert.NotEmpty(pods.Items); var pod = pods.Items[0]; // The pod is in the running state pod = await client.WaitForPodRunningAsync(pod, Timeout, default).ConfigureAwait(false); Assert.Equal("Running", pod.Status.Phase); // Try to perform a handshake using (var connection = await client.ConnectToPodPortAsync(pod, 4822, default).ConfigureAwait(false)) { GuacdProtocol protocol = new GuacdProtocol(connection); // Handshake phase await protocol.SendInstructionAsync("select", new string[] { "vnc" }, default).ConfigureAwait(false); var response = await protocol.ReadInstructionAsync(default);
public async Task WatchNamespacedObjectAsync_EmptyContent_Completes_Async() { var handler = new DummyHandler(); handler.Responses.Enqueue( new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new WatchHttpContent( new StringContent(string.Empty)), }); Collection <(WatchEventType, V1Pod)> events = new Collection <(WatchEventType, V1Pod)>(); var protocol = new KubernetesProtocol(handler, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); var result = await protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>( new V1Pod() { Metadata = new V1ObjectMeta(name: "pod", namespaceProperty: "default", resourceVersion: "1"), }, protocol.ListNamespacedPodWithHttpMessagesAsync, (eventType, result) => { events.Add((eventType, result)); return(Task.FromResult(WatchResult.Continue)); }, default).ConfigureAwait(false); Assert.Equal(WatchExitReason.ServerDisconnected, result); Assert.Empty(events); Assert.Collection( handler.Requests, r => { Assert.Equal(new Uri("http://localhost/api/v1/namespaces/default/pods?allowWatchBookmarks=true&fieldSelector=metadata.name%3Dpod&resourceVersion=1&watch=true"), r.RequestUri); }); }
public async Task WatchCustomResourceDefinitionAsync_EmptyContent_Completes_Async() { var handler = new DummyHandler(); handler.Responses.Enqueue( new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new WatchHttpContent( new StringContent(string.Empty)), }); Collection <(WatchEventType, V1CustomResourceDefinition)> events = new Collection <(WatchEventType, V1CustomResourceDefinition)>(); var protocol = new KubernetesProtocol(handler, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); var result = await protocol.WatchCustomResourceDefinitionAsync( new V1CustomResourceDefinition() { Metadata = new V1ObjectMeta(name: "crd", namespaceProperty: "default", resourceVersion: "1"), }, (eventType, result) => { events.Add((eventType, result)); return(Task.FromResult(WatchResult.Continue)); }, default).ConfigureAwait(false); Assert.Equal(WatchExitReason.ServerDisconnected, result); Assert.Empty(events); Assert.Collection( handler.Requests, r => { Assert.Equal(new Uri("http://localhost/apis/apiextensions.k8s.io/v1/customresourcedefinitions?fieldSelector=metadata.name%3Dcrd&resourceVersion=1&watch=true"), r.RequestUri); }); }
public async Task WatchNamespacedObjectAsync_ClientCanStopLoop_Async() { using (var stream = new SimplexStream()) using (var writer = new StreamWriter(stream)) { var handler = new DummyHandler(); handler.Responses.Enqueue( new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new WatchHttpContent( new StreamContent(stream)), }); Collection <(WatchEventType, V1Pod)> events = new Collection <(WatchEventType, V1Pod)>(); var protocol = new KubernetesProtocol(handler, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); var cts = new CancellationTokenSource(); var watchTask = protocol.WatchNamespacedObjectAsync( new V1Pod() { Metadata = new V1ObjectMeta(name: "pod", namespaceProperty: "default", resourceVersion: "1"), }, protocol.ListNamespacedPodWithHttpMessagesAsync, (eventType, result) => { events.Add((eventType, result)); return(Task.FromResult(events.Count == 1 ? WatchResult.Continue : WatchResult.Stop)); }, cts.Token); Assert.True(!watchTask.IsCompleted); await writer.WriteAsync( JsonConvert.SerializeObject( new V1WatchEvent() { Type = nameof(WatchEventType.Deleted), ObjectProperty = new V1Pod() { Metadata = new V1ObjectMeta() { NamespaceProperty = "some-namespace", Name = "some-name", }, }, })); await writer.WriteAsync('\n').ConfigureAwait(false); await writer.FlushAsync().ConfigureAwait(false); Assert.True(!watchTask.IsCompleted); await writer.WriteAsync( JsonConvert.SerializeObject( new V1WatchEvent() { Type = nameof(WatchEventType.Deleted), ObjectProperty = new V1Pod() { Metadata = new V1ObjectMeta() { NamespaceProperty = "some-namespace2", Name = "some-name2", }, }, })); await writer.WriteAsync('\n').ConfigureAwait(false); await writer.FlushAsync().ConfigureAwait(false); var result = await watchTask; Assert.Equal(WatchExitReason.ClientDisconnected, result); Assert.Collection( events, e => { Assert.Equal(WatchEventType.Deleted, e.Item1); Assert.Equal("some-namespace", e.Item2.Metadata.NamespaceProperty); Assert.Equal("some-name", e.Item2.Metadata.Name); }, e => { Assert.Equal(WatchEventType.Deleted, e.Item1); Assert.Equal("some-namespace2", e.Item2.Metadata.NamespaceProperty); Assert.Equal("some-name2", e.Item2.Metadata.Name); }); } }