/// <summary> /// We've received a command. Instead of running it, we instead /// relay the command to each worker pod. /// </summary> /// <param name="command">Command to be run.</param> /// <param name="connection">Connection on which we received the command.</param> protected override void RunCommand(ICommand command, IConnectionManager connection) { // Relay the command to all workers. if (command is ReadCommand readCommand) { DoReadCommand(readCommand, connection); return; } foreach (string podName in workers) { V1Pod pod = GetWorkerPod(podName); if (string.IsNullOrEmpty(pod.Status.PodIP)) { throw new NotImplementedException("Pod IP not set."); } // Create a new socket connection to the pod. string ip = pod.Status.PodIP; WriteToLog($"Attempting connection to pod {podName} on {ip}:{portNo}"); using (NetworkSocketClient conn = new NetworkSocketClient(relayOptions.Verbose, ip, portNo, Protocol.Managed)) { WriteToLog($"Connection to {podName} established. Sending command..."); // Relay the command to the pod. conn.SendCommand(command); WriteToLog($"Closing connection to {podName}..."); } } connection.OnCommandFinished(command); }
public static string TestInstance(this V1Pod pod) { var instance = ""; pod.Metadata.Labels.TryGetValue("testInstance", out instance); return(instance); }
private static Pod GetPod(V1Pod data) { var podNamespace = string.IsNullOrWhiteSpace(data.Metadata.NamespaceProperty) ? "default" : data.Metadata.NamespaceProperty; var ready = data.Status.Conditions?.Any(x => string.Equals(x.Type, "Ready", StringComparison.OrdinalIgnoreCase) && x.Status.Equals(true.ToString(), StringComparison.OrdinalIgnoreCase) ) ?? false; var podPorts = data.Spec.Containers .SelectMany(x => x.Ports.Select(c => new { Container = x, Port = c })) .Select(x => new PodPort(x.Container.Name, x.Port.Name, x.Port.ContainerPort)) .ToList(); var pod = new Pod( data.Metadata.Uid, podNamespace, data.Metadata.Name, data.Spec.NodeName, data.Status.PodIP, ready, podPorts, new Dictionary <string, string>(data.Metadata.Labels ?? new Dictionary <string, string>()), new Dictionary <string, string>(data.Metadata.Annotations ?? new Dictionary <string, string>()) ); return(pod); }
public async Task KubernetesAdbSocketLocator_WorksWithDependencyInjection_Async() { var pod = new V1Pod(); var kubernetes = new Mock <KubernetesClient>(); var context = new KubernetesAdbContext() { Pod = pod }; var stream = Mock.Of <Stream>(); kubernetes .Setup(p => p.ConnectToPodPortAsync(pod, 5037, default)) .ReturnsAsync(stream); var services = new ServiceCollection() .AddScoped <AdbClient>() .AddScoped <AdbSocketLocator, KubernetesAdbSocketLocator>() .AddScoped((p) => context) .AddSingleton(kubernetes.Object) .AddLogging() .BuildServiceProvider(); var client = services.GetRequiredService <AdbClient>(); await using (var protocol = await client.TryConnectToAdbAsync(default))
public async Task ReconcileAsync_FeedbackLoopReturnsNull_DoesNothing_Async() { var kubernetes = new Mock <KubernetesClient>(); var sessions = kubernetes.WithClient <WebDriverSession>(); var pods = kubernetes.WithClient <V1Pod>(); Feedback <WebDriverSession, V1Pod> feedback = null; var parent = new WebDriverSession(); var child = new V1Pod(); var feedbackLoops = new Collection <FeedbackLoop <WebDriverSession, V1Pod> >() { new FeedbackLoop <WebDriverSession, V1Pod>((context, cancellationToken) => { return(Task.FromResult(feedback)); }), }; using (var @operator = new ChildOperator <WebDriverSession, V1Pod>( kubernetes.Object, this.configuration, this.filter, (session, pod) => { }, feedbackLoops, this.logger, this.services)) { await @operator.ReconcileAsync(parent, child, default).ConfigureAwait(false); } sessions.Verify(); }
private IReadOnlyDictionary <string, bool> ReadPodContainerState(V1Pod existingPod) { var dict = new Dictionary <string, bool>(); if (existingPod == null) { return(dict); } if (existingPod.Status.ContainerStatuses != null) { foreach (var item in existingPod.Status.ContainerStatuses) { dict[item.Name] = item.Ready; } } if (existingPod.Status.EphemeralContainerStatuses != null) { foreach (var item in existingPod.Status.EphemeralContainerStatuses) { dict[item.Name] = item.Ready; } } return(dict); }
public static void CopyFileToPod(this Kubernetes client, V1Pod pod, string container, string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken = default(CancellationToken)) { if (!IsKubectlInstalled()) { throw new Exception($"kubectl is either not installed or is not on path\n{kubectlInstallLink}"); } if (!(File.Exists(sourceFilePath) || Directory.Exists(sourceFilePath))) { throw new FileNotFoundException($"File {sourceFilePath} does not exist"); } Process proc = new Process(); proc.StartInfo.FileName = "kubectl"; proc.StartInfo.Arguments = $"cp {sourceFilePath} {pod.Namespace()}/{pod.Name()}:{destinationFilePath} -c {container}"; proc.StartInfo.RedirectStandardOutput = true; proc.StartInfo.RedirectStandardError = true; proc.Start(); proc.WaitForExit(); if (proc.ExitCode != 0) { string stdout = proc.StandardOutput.ReadToEnd(); string stderr = proc.StandardError.ReadToEnd(); throw new Exception($"Failed to copy {sourceFilePath} to pod {pod.Name()};\nstdout:\n{stdout}\nstderr:\n{stderr}"); } }
public async Task ConnectToPodPortAsync_UsesPortForwarding_Async() { var pod = new V1Pod() { Metadata = new V1ObjectMeta() { NamespaceProperty = "my-namespace", Name = "usbmuxd-abcd", }, }; var websocket = Mock.Of <WebSocket>(); var protocol = new Mock <IKubernetesProtocol>(MockBehavior.Strict); protocol .Setup(k => k.WebSocketNamespacedPodPortForwardAsync("usbmuxd-abcd", "my-namespace", new int[] { 27015 }, null, null, default)) .ReturnsAsync(websocket) .Verifiable(); protocol.Setup(p => p.Dispose()).Verifiable(); using (var client = new KubernetesClient(protocol.Object, KubernetesOptions.Default, NullLogger <KubernetesClient> .Instance, NullLoggerFactory.Instance)) using (var stream = await client.ConnectToPodPortAsync(pod, 27015, default)) { var portForwardStream = Assert.IsType <PortForwardStream>(stream); Assert.Same(websocket, portForwardStream.WebSocket); } protocol.Verify(); }
public void Kill(string id) { _logger.LogInformation($"Kill Runspace: {id}"); try { _client.DeleteNamespacedPod(id, _namespace); // Wait pod to be deleted int maxRetry = 20; int retryCount = 1; V1Pod pod = null; do { pod = null; try { pod = _client.ReadNamespacedPod(id, _namespace); Thread.Sleep(100); } catch (Exception) { } retryCount++; } while (pod != null && pod.Status?.Phase == "Running" && retryCount < maxRetry); } catch (Exception exc) { _logger.LogError(exc.ToString()); throw new RunspaceProviderException( Resources.K8sRunspaceProvider_Create_K8sRunspaceCreateFail, exc); } }
public async Task CreatePodHttpClient_IsConfiguredCorrectly_Async() { var pod = new V1Pod() { Metadata = new V1ObjectMeta() { NamespaceProperty = "default", Name = "my-pod" } }; var mock = new Mock <KubernetesClient>(MockBehavior.Strict); mock.Setup(c => c.CreatePodHttpClient(pod, 8080)).CallBase(); mock.Setup(c => c.ConnectToPodPortAsync(pod, 8080, It.IsAny <CancellationToken>())).ReturnsAsync(Stream.Null).Verifiable(); mock.Setup(c => c.Dispose()); using (var client = mock.Object) using (var httpClient = client.CreatePodHttpClient(pod, 8080)) { Assert.NotNull(httpClient); Assert.Equal(new Uri("http://my-pod:8080"), httpClient.BaseAddress); // Executing the request will result in an attempt to read a HTTP response off Stream.Null, which // will throw an IOException wrapped in a HttpRequestException. // Verify the exception and make sure ConnectToPodPortAsync was called as basic verification. var exception = await Assert.ThrowsAsync <HttpRequestException>(() => httpClient.GetStreamAsync("/")).ConfigureAwait(false); Assert.IsType <IOException>(exception.InnerException); mock.Verify(); } }
public bool PodComplete(string _PodName, Action <string> _ErrorMessageAction = null) { try { RemoveFromPodList(_PodName); V1Pod CurrentState = PodManager.GetPodByNameAndNamespace(_PodName, BATCH_NAMESPACE); if (CurrentState != null) { UpdatePodStatus(CurrentState, EPodType.None, null, null, null, COMPLETED_STATE); V1Pod Result = PodManager.DeletePod(_PodName, BATCH_NAMESPACE); if (Result != null) { return(true); } else { _ErrorMessageAction?.Invoke("The pod you are trying to delete no longer exists"); return(false); } } else { _ErrorMessageAction?.Invoke("The pod you are trying to delete no longer exists"); return(false); } } catch (Exception ex) { _ErrorMessageAction?.Invoke($"Failed to Delete pod - {ex.Message}\n{ex.StackTrace}"); return(false); } }
public async Task ReturnsModuleRuntimeInfoWhenPodsAreUpdated() { V1Pod edgeagent1 = BuildPodList()["edgeagent"]; edgeagent1.Metadata.Name = "edgeagent_123"; edgeagent1.Status.ContainerStatuses .First(c => c.Name == "edgeagent").State.Running.StartedAt = new DateTime(2019, 10, 28); V1Pod edgeagent2 = BuildPodList()["edgeagent"]; edgeagent2.Metadata.Name = "edgeAgent_456"; edgeagent2.Status.ContainerStatuses .First(c => c.Name == "edgeagent").State.Running.StartedAt = new DateTime(2019, 10, 29); var client = new Mock <IKubernetes>(MockBehavior.Strict); var moduleManager = new Mock <IModuleManager>(MockBehavior.Strict); var runtimeInfo = new KubernetesRuntimeInfoProvider(Namespace, client.Object, moduleManager.Object); runtimeInfo.CreateOrUpdateAddPodInfo(edgeagent1); runtimeInfo.CreateOrUpdateAddPodInfo(edgeagent2); runtimeInfo.RemovePodInfo(edgeagent1); var modules = await runtimeInfo.GetModules(CancellationToken.None); var info = modules.Single(); Assert.NotNull(info); Assert.Equal(info.StartTime, Option.Some(new DateTime(2019, 10, 29))); }
public async Task ReturnModuleStatusWithPodConditionsWhenThereAreNoContainers() { var client = new Mock <IKubernetes>(MockBehavior.Strict); var moduleManager = new Mock <IModuleManager>(MockBehavior.Strict); var runtimeInfo = new KubernetesRuntimeInfoProvider(Namespace, client.Object, moduleManager.Object); V1Pod pod = CreatePodWithPodParametersOnly("Pending", string.Empty, string.Empty); pod.Status.Conditions = new List <V1PodCondition>() { new V1PodCondition { LastTransitionTime = new DateTime(2020, 02, 05, 10, 10, 10), Message = "Ready", Reason = "Scheduling", }, new V1PodCondition { LastTransitionTime = new DateTime(2020, 02, 05, 10, 10, 15), Message = "persistentvolumeclaim module-a-pvc not found", Reason = "Unschedulable", } }; runtimeInfo.CreateOrUpdateAddPodInfo(pod); string expectedDescription = "Module Failed with container status Unknown More Info: persistentvolumeclaim module-a-pvc not found K8s reason: Unschedulable"; ModuleRuntimeInfo info = (await runtimeInfo.GetModules(CancellationToken.None)).Single(); Assert.Equal(ModuleStatus.Failed, info.ModuleStatus); Assert.Equal(expectedDescription, info.Description); }
public async Task DeleteResources(V1Pod pod) { if (!ShouldDeleteResources(pod)) { Logger.Debug($"Skipping resource deletion."); return; } var rgName = GetResourceGroupName(pod); if (string.IsNullOrEmpty(rgName)) { return; } Subscription subscription = ARMClient.DefaultSubscription; ResourceGroup resourceGroup; try { resourceGroup = await subscription.GetResourceGroups().GetAsync(rgName); } catch (Exception e) { Logger.Error($"Failed to get resource group '{rgName}' using subsription id '{subscription.Id}'"); throw e; } await resourceGroup.DeleteAsync(); Logger.Information($"Deleted resources {rgName}"); }
private Task <DataTable> RelayReadCommand(string podName, ReadCommand command, IConnectionManager connection) { return(Task.Run <DataTable>(() => { V1Pod pod = GetWorkerPod(podName); if (string.IsNullOrEmpty(pod.Status.PodIP)) { throw new NotImplementedException("Pod IP not set."); } // Create a new socket connection to the pod. string ip = pod.Status.PodIP; ushort port = GetPortNo(pod); WriteToLog($"Attempting connection to pod {podName} on {ip}:{port}"); using (NetworkSocketClient conn = new NetworkSocketClient(relayOptions.Verbose, ip, port, Protocol.Managed)) { WriteToLog($"Connection to {podName} established. Sending command..."); // Relay the command to the pod. try { return conn.ReadOutput(command); } catch (Exception err) { throw new Exception($"Unable to read output from pod {podName}", err); } } })); }
public void AsOwner_ReturnsValidReference() { var parent = new V1Pod() { ApiVersion = V1Pod.KubeApiVersion, Kind = V1Pod.KubeKind, Metadata = new V1ObjectMeta() { Name = "test", NamespaceProperty = "default", Uid = "my-uid", }, }; var reference = parent.AsOwnerReference(); reference.Validate(); Assert.Equal(V1Pod.KubeApiVersion, reference.ApiVersion); Assert.Null(reference.BlockOwnerDeletion); Assert.Null(reference.Controller); Assert.Equal(V1Pod.KubeKind, reference.Kind); Assert.Equal("test", reference.Name); Assert.Equal("my-uid", reference.Uid); }
public IActionResult Post([FromQuery] string name, string namespaceName) { var pod = new V1Pod { ApiVersion = "v1", Kind = "Pod", Metadata = new V1ObjectMeta { Name = name }, Spec = new V1PodSpec { Containers = new List <V1Container>() { new V1Container() { Name = "container-test", Image = "hello-world" } } } }; var result = kubeClient.CreateNamespacedPod(pod, namespaceName); return(Ok()); }
public async Task CreatePodHttpClient_OtherHost_Throws_Async(string url) { var pod = new V1Pod() { Metadata = new V1ObjectMeta() { NamespaceProperty = "default", Name = "my-pod" } }; var mock = new Mock <KubernetesClient>(MockBehavior.Strict); mock.Setup(c => c.CreatePodHttpClient(pod, 8080)).CallBase(); mock.Setup(c => c.Dispose()); using (var client = mock.Object) using (var httpClient = client.CreatePodHttpClient(pod, 8080)) { Assert.NotNull(httpClient); Assert.Equal(new Uri("http://my-pod:8080"), httpClient.BaseAddress); // Executing the request will result in the connect callback failing validation, // which will throw an InvalidOperationException wrapped in a HttpRequestException. // Verify the exception and make sure ConnectToPodPortAsync was called as basic verification. var exception = await Assert.ThrowsAsync <HttpRequestException>(() => httpClient.GetStreamAsync(url)).ConfigureAwait(false); Assert.IsType <InvalidOperationException>(exception.InnerException); mock.Verify(); } }
public async Task StartChaosResources(V1Pod pod) { var chaos = await ChaosClient.ListNamespacedAsync(pod.Namespace()); var tasks = chaos.Items .Where(cr => ShouldStartChaos(cr, pod)) .Select(async cr => { string plural = ""; foreach (string pluralName in Enum.GetNames(typeof(GenericChaosClient.ChaosResourcePlurals))) { if (pluralName.Contains(cr.Kind.ToLower())) { plural = pluralName; break; } } await Client.PatchNamespacedCustomObjectWithHttpMessagesAsync( PodChaosResumePatchBody, ChaosClient.Group, ChaosClient.Version, pod.Namespace(), plural, cr.Metadata.Name); using (LogContext.PushProperty("chaosResource", $"{cr.Kind}/{cr.Metadata.Name}")) { Logger.Information($"Started chaos for pod."); } }); await Task.WhenAll(tasks); }
[InlineData(@"{""kind"":""Status"", ""apiVersion"":""v1beta1"", ""message"":""""}")] // Empty message public async Task CreatePodAsync_InvalidKubernetesError_Async(string statusJson) { var pod = new V1Pod() { Metadata = new V1ObjectMeta() { NamespaceProperty = "default" } }; var protocol = new Mock <IKubernetesProtocol>(MockBehavior.Strict); protocol .Setup(p => p.CreateNamespacedPodWithHttpMessagesAsync(pod, pod.Metadata.NamespaceProperty, null, null, null, null, default)) .ThrowsAsync( new HttpOperationException() { Response = new HttpResponseMessageWrapper( new HttpResponseMessage(HttpStatusCode.UnprocessableEntity), statusJson), }); protocol.Setup(p => p.Dispose()).Verifiable(); using (var client = new KubernetesClient(protocol.Object, KubernetesOptions.Default, NullLogger <KubernetesClient> .Instance, NullLoggerFactory.Instance)) { await Assert.ThrowsAsync <HttpOperationException>(() => client.CreatePodAsync(pod, default)).ConfigureAwait(false); } }
public async Task CreatePodAsync_CapturesKubernetesError_Async(HttpStatusCode statusCode) { const string status = @"{""kind"":""Status"",""apiVersion"":""v1"",""metadata"":{},""status"":""Failure"",""message"":""pods 'waitforpodrunning-integrationtest-async' already exists"",""reason"":""AlreadyExists"",""details"":{ ""name"":""waitforpodrunning-integrationtest-async"",""kind"":""pods""},""code"":409}"; var pod = new V1Pod() { Metadata = new V1ObjectMeta() { NamespaceProperty = "default" } }; var protocol = new Mock <IKubernetesProtocol>(MockBehavior.Strict); protocol .Setup(p => p.CreateNamespacedPodWithHttpMessagesAsync(pod, pod.Metadata.NamespaceProperty, null, null, null, null, default)) .ThrowsAsync( new HttpOperationException() { Response = new HttpResponseMessageWrapper( new HttpResponseMessage(statusCode), status), }); protocol.Setup(p => p.Dispose()).Verifiable(); using (var client = new KubernetesClient(protocol.Object, KubernetesOptions.Default, NullLogger <KubernetesClient> .Instance, NullLoggerFactory.Instance)) { var ex = await Assert.ThrowsAsync <KubernetesException>(() => client.CreatePodAsync(pod, default)).ConfigureAwait(false); Assert.Equal("pods 'waitforpodrunning-integrationtest-async' already exists", ex.Message); Assert.NotNull(ex.Status); } }
public string GetResourceGroupName(V1Pod pod) { var deployContainers = pod.Spec.InitContainers?.Where(c => c.Name == "init-azure-deployer"); var envVars = deployContainers?.First().Env; if (envVars == null) { return(""); } var rgName = envVars.Where(e => e.Name == "RESOURCE_GROUP_NAME").Select(e => e.Value); if (rgName.Count() == 0) { Logger.Error("Cannot find the env variable 'RESOURCE_GROUP_NAME' on the init container 'init-azure-deployer' spec."); return(""); } if (rgName.First() == null) { Logger.Error("Env variable RESOURCE_GROUP_NAME does not have a value."); return(""); } return(rgName.First().ToString()); }
public static ModuleRuntimeInfo ConvertToRuntime(this V1Pod pod, string name) { Option <V1ContainerStatus> containerStatus = GetContainerByName(name, pod); ReportedModuleStatus moduleStatus = ConvertPodStatusToModuleStatus(containerStatus); RuntimeData runtimeData = GetRuntimeData(containerStatus.OrDefault()); string moduleName = string.Empty; if (!(pod.Metadata?.Annotations?.TryGetValue(KubernetesConstants.K8sEdgeOriginalModuleId, out moduleName) ?? false)) { moduleName = name; } var reportedConfig = new AgentDocker.DockerReportedConfig(runtimeData.ImageName, string.Empty, string.Empty); return(new ModuleRuntimeInfo <AgentDocker.DockerReportedConfig>( moduleName, "docker", moduleStatus.Status, moduleStatus.Description, runtimeData.ExitStatus, runtimeData.StartTime, runtimeData.EndTime, reportedConfig)); }
private Task RelayCommand(string podName, ICommand command, IConnectionManager connection) { return(Task.Run(() => { V1Pod pod = GetWorkerPod(podName); if (string.IsNullOrEmpty(pod.Status.PodIP)) { throw new NotImplementedException("Pod IP not set."); } // Create a new socket connection to the pod. string ip = pod.Status.PodIP; ushort port = GetPortNo(pod); WriteToLog($"Attempting connection to pod {podName} on {ip}:{port}"); using (NetworkSocketClient conn = new NetworkSocketClient(relayOptions.Verbose, ip, port, Protocol.Managed)) { WriteToLog($"Connection to {podName} established. Sending command..."); // Relay the command to the pod. conn.SendCommand(command); WriteToLog($"Closing connection to {podName}..."); } })); }
void HandlePodChangedAsync(WatchEventType type, V1Pod pod) { // if the pod doesn't have the module label set then we are not interested in it if (!pod.Metadata.Labels.ContainsKey(Constants.K8sEdgeModuleLabel)) { return; } Events.PodStatus(type, pod); switch (type) { case WatchEventType.Added: case WatchEventType.Modified: case WatchEventType.Error: this.moduleStatusSource.CreateOrUpdateAddPodInfo(pod); break; case WatchEventType.Deleted: if (!this.moduleStatusSource.RemovePodInfo(pod)) { Events.PodStatusRemoveError(pod); } break; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } }
public static void CopyDirectoryToPod(this Kubernetes client, V1Pod pod, string container, string sourceDirectoryPath, string destinationDirectoyPath, CancellationToken cancellationToken = default(CancellationToken)) { if (!Directory.Exists(sourceDirectoryPath)) { throw new DirectoryNotFoundException($"Directory {sourceDirectoryPath} does not exist"); } client.CopyFileToPod(pod, container, sourceDirectoryPath, destinationDirectoyPath, cancellationToken); }
static Option <V1ContainerStatus> GetContainerByName(string name, V1Pod pod) { string containerName = KubeUtils.SanitizeDNSValue(name); V1ContainerStatus status = pod.Status?.ContainerStatuses? .FirstOrDefault(container => string.Equals(container.Name, containerName, StringComparison.OrdinalIgnoreCase)); return(Option.Maybe(status)); }
public bool ShouldStartChaos(GenericChaosResource chaos, V1Pod pod) { if (chaos.Spec.GetTestInstance() != pod.TestInstance()) { return(false); } return(chaos.IsPaused()); }
/// <summary> /// Asynchronously deletes a pod. /// </summary> /// <param name="value"> /// The pod to delete. /// </param> /// <param name="timeout"> /// The amount of time in which the pod should be deleted. /// </param> /// <param name="cancellationToken"> /// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation. /// </param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public virtual Task DeletePodAsync(V1Pod value, TimeSpan timeout, CancellationToken cancellationToken) { return(this.DeleteNamespacedObjectAsync <V1Pod>( value, this.protocol.DeleteNamespacedPodAsync, this.WatchPodAsync, timeout, cancellationToken)); }
private static Option <V1ContainerStatus> GetContainerByName(string name, V1Pod pod) { string containerName = KubeUtils.SanitizeDNSValue(name); return(pod.Status?.ContainerStatuses .Where(status => string.Equals(status.Name, containerName, StringComparison.OrdinalIgnoreCase)) .Select(status => Option.Some(status)) .FirstOrDefault() ?? Option.None <V1ContainerStatus>()); }