示例#1
0
        protected override async Task ProcessRecordAsync(CancellationToken cancellationToken)
        {
            await base.ProcessRecordAsync(cancellationToken);

            IEnumerable <PodV1> podList;

            if (String.IsNullOrEmpty(Name) || WildcardPattern.ContainsWildcardCharacters(Name))
            {
                podList = await client.PodsV1().List(
                    kubeNamespace: Namespace,
                    labelSelector: LabelSelector,
                    cancellationToken: cancellationToken
                    );
            }
            else
            {
                PodV1 pod = await client.PodsV1().Get(
                    name: Name,
                    kubeNamespace: Namespace,
                    cancellationToken: cancellationToken
                    );

                podList = new[] { pod };
            }
            if (WildcardPattern.ContainsWildcardCharacters(Name))
            {
                var pattern = new WildcardPattern(Name);
                podList = podList.Where(pod => pattern.IsMatch(pod.Metadata.Name));
            }
            WriteObject(podList, true);
        }
示例#2
0
        public async Task ApplyModel()
        {
            MockMessageHandler handler = new MockMessageHandler(async(HttpRequestMessage request) =>
            {
                Assert.Equal("PATCH", request.Method.Method);

                Assert.NotNull(request.Content);

                string requestBody = await request.Content.ReadAsStringAsync();
                Log.LogInformation("Request body:\n{RequestBody:l}", requestBody);

                Assert.NotNull(request.Content.Headers.ContentType);
                Assert.Equal("application/apply-patch+yaml", request.Content.Headers.ContentType.MediaType);

                Assert.Contains("fieldManager=my-field-manager", request.RequestUri.Query);

                return(request.CreateResponse(HttpStatusCode.OK,
                                              responseBody: JsonConvert.SerializeObject(new PodV1
                {
                    Metadata = new ObjectMetaV1
                    {
                        Name = "my-pod",
                        Namespace = "my-namespace",
                        Finalizers =     // Array test
                        {
                            "foo",
                            "bar"
                        }
                    }
                }),
                                              mediaType: "application/json"
                                              ));
            });

            using (KubeApiClient client = handler.CreateClient(loggerFactory: LoggerFactory))
            {
                PodV1 resource = new PodV1
                {
                    Metadata = new ObjectMetaV1
                    {
                        Name       = "my-pod",
                        Namespace  = "my-namespace",
                        Finalizers = // Array test
                        {
                            "foo",
                            "bar"
                        }
                    }
                };

                await client.Dynamic().Apply(resource,
                                             fieldManager: "my-field-manager"
                                             );
            }
        }
        public void PodV1Result_From_SuccessStatus_ImplicitCast_Resource()
        {
            var result = new KubeResourceResultV1 <PodV1>(new StatusV1
            {
                Status  = "Success",
                Message = "Most definitely a success."
            });

            PodV1 pod = result;

            Assert.Null(pod);
        }
示例#4
0
        private async Task DeletePod(string name, string kubeNamespace, CancellationToken cancellationToken)
        {
            if (!ShouldProcess($"Deleting pod \"{name}\" in namespace \"{kubeNamespace}\"", $"Delete pod \"{name}\" in namespace \"{kubeNamespace}\"?", "Confirm"))
            {
                return;
            }
            try {
                PodV1 pod = await client.PodsV1().Delete(name: name, kubeNamespace: kubeNamespace, cancellationToken: cancellationToken);

                WriteObject(pod);
            } catch (Exception e) {
                WriteError(new ErrorRecord(e, null, ErrorCategory.NotSpecified, null));
            }
        }
        public void PodV1Result_From_FailureStatus_ImplicitCast_Resource()
        {
            PodV1 pod = null;

            KubeApiException exception = Assert.Throws <KubeApiException>(() =>
            {
                pod = new KubeResourceResultV1 <PodV1>(new StatusV1
                {
                    Status  = "Failure",
                    Message = "Most definitely not a success."
                });
            });

            Assert.Null(pod);
            Assert.True(exception.HasStatus);
            Assert.Equal("Failure", exception.Status.Status);
            Assert.Equal("Most definitely not a success.", exception.Status.Message);
        }
        public void PodV1Result_From_PodV1_ImplicitCast_Resource()
        {
            PodV1 expected = new PodV1
            {
                Metadata = new ObjectMetaV1
                {
                    Name      = "my-pod",
                    Namespace = "my-namespace"
                }
            };

            var result = new KubeResourceResultV1 <PodV1>(expected);

            PodV1 actual = result;

            Assert.NotNull(actual);
            Assert.Same(expected, actual);
        }
示例#7
0
        /// <summary>
        ///     Request creation of a <see cref="Pod"/>.
        /// </summary>
        /// <param name="newPod">
        ///     A <see cref="PodV1"/> representing the Pod to create.
        /// </param>
        /// <param name="cancellationToken">
        ///     An optional <see cref="CancellationToken"/> that can be used to cancel the request.
        /// </param>
        /// <returns>
        ///     A <see cref="PodV1"/> representing the current state for the newly-created Pod.
        /// </returns>
        public async Task <PodV1> Create(PodV1 newPod, CancellationToken cancellationToken = default)
        {
            if (newPod == null)
            {
                throw new ArgumentNullException(nameof(newPod));
            }

            return(await Http
                   .PostAsJsonAsync(
                       Requests.Collection.WithTemplateParameters(new
            {
                Namespace = newPod?.Metadata?.Namespace ?? Client.DefaultNamespace
            }),
                       postBody : newPod,
                       cancellationToken : cancellationToken
                       )
                   .ReadContentAsAsync <PodV1, StatusV1>());
        }
示例#8
0
        /// <summary>
        ///     Request creation of a <see cref="PodV1"/>.
        /// </summary>
        /// <param name="newPod">
        ///     A <see cref="PodV1"/> representing the Pod to create.
        /// </param>
        /// <param name="cancellationToken">
        ///     An optional <see cref="CancellationToken"/> that can be used to cancel the request.
        /// </param>
        /// <returns>
        ///     A <see cref="PodV1"/> representing the current state for the newly-created Pod.
        /// </returns>
        public async Task <PodV1> Create(PodV1 newPod, CancellationToken cancellationToken = default)
        {
            if (newPod == null)
            {
                throw new ArgumentNullException(nameof(newPod));
            }

            return(await Http
                   .PostAsJsonAsync(
                       Requests.Collection.WithTemplateParameters(new
            {
                Namespace = newPod?.Metadata?.Namespace ?? KubeClient.DefaultNamespace
            }),
                       postBody : newPod,
                       cancellationToken : cancellationToken
                       )
                   .ReadContentAsObjectV1Async <PodV1>(
                       operationDescription: $"create v1/Pod resource in namespace {newPod?.Metadata?.Namespace ?? KubeClient.DefaultNamespace}"
                       ));
        }
示例#9
0
        /// <summary>
        ///     The main program entry-point.
        /// </summary>
        /// <param name="commandLineArguments">
        ///     The program's command-line arguments.
        /// </param>
        /// <returns>
        ///     The program exit-code.
        /// </returns>
        static async Task <int> Main(string[] commandLineArguments)
        {
            // Show help if no arguments are specified.
            bool showHelp = commandLineArguments.Length == 0;

            if (showHelp)
            {
                commandLineArguments = new[] { "--help" }
            }
            ;

            try
            {
                SynchronizationContext.SetSynchronizationContext(
                    new SynchronizationContext()
                    );

                ProgramOptions options = ProgramOptions.Parse(commandLineArguments);
                if (options == null)
                {
                    return(showHelp ? ExitCodes.Success : ExitCodes.InvalidArguments);
                }

                ConfigureLogging(options);

                using (ServiceProvider serviceProvider = BuildServiceProvider(options))
                    using (AutoResetEvent done = new AutoResetEvent(initialState: false))
                    {
                        KubeApiClient client        = serviceProvider.GetRequiredService <KubeApiClient>();
                        KubeResources kubeResources = serviceProvider.GetRequiredService <KubeResources>();

                        string jobName = kubeResources.Names.DeployGliderGunRemoteJob(options);

                        JobV1 existingJob = await client.JobsV1().Get(jobName);

                        if (existingJob != null)
                        {
                            Log.Information("Found existing job {JobName} in namespace {KubeNamespace}; deleting...",
                                            existingJob.Metadata.Name,
                                            existingJob.Metadata.Namespace
                                            );

                            await client.JobsV1().Delete(jobName,
                                                         propagationPolicy: DeletePropagationPolicy.Foreground
                                                         );

                            Log.Information("Deleted existing job {JobName}.",
                                            existingJob.Metadata.Name,
                                            existingJob.Metadata.Namespace
                                            );
                        }

                        string secretName = kubeResources.Names.DeployGliderGunRemoteSecret(options);

                        SecretV1 existingSecret = await client.SecretsV1().Get(secretName);

                        if (existingSecret != null)
                        {
                            Log.Information("Found existing secret {SecretName} in namespace {KubeNamespace}; deleting...",
                                            existingSecret.Metadata.Name,
                                            existingSecret.Metadata.Namespace
                                            );

                            await client.SecretsV1().Delete(secretName);

                            Log.Information("Deleted existing secret {SecretName}.",
                                            existingSecret.Metadata.Name,
                                            existingSecret.Metadata.Namespace
                                            );
                        }

                        Log.Information("Creating deployment secret {SecretName}...", secretName);

                        SecretV1 deploymentSecret = kubeResources.DeployGliderGunRemoteSecret(options);
                        try
                        {
                            deploymentSecret = await client.SecretsV1().Create(deploymentSecret);
                        }
                        catch (HttpRequestException <StatusV1> createSecretFailed)
                        {
                            Log.Error(createSecretFailed, "Failed to create Kubernetes Secret {SecretName} for deployment ({Reason}): {ErrorMessage}",
                                      secretName,
                                      createSecretFailed.Response.Reason,
                                      createSecretFailed.Response.Message
                                      );

                            return(ExitCodes.JobFailed);
                        }

                        Log.Information("Created deployment secret {SecretName}.", deploymentSecret.Metadata.Name);

                        // Watch for job's associated pod to start, then monitor the pod's log until it completes.
                        IDisposable jobLogWatch = null;
                        IDisposable jobPodWatch = client.PodsV1().WatchAll(
                            labelSelector: $"job-name={jobName}",
                            kubeNamespace: options.KubeNamespace
                            ).Subscribe(
                            podEvent =>
                        {
                            if (jobLogWatch != null)
                            {
                                return;
                            }

                            PodV1 jobPod = podEvent.Resource;
                            if (jobPod.Status.Phase != "Pending")
                            {
                                Log.Information("Job {JobName} has started.", jobName);

                                Log.Verbose("Hook up log monitor for Pod {PodName} of Job {JobName}...",
                                            jobPod.Metadata.Name,
                                            jobName
                                            );

                                jobLogWatch = client.PodsV1().StreamLogs(
                                    name: jobPod.Metadata.Name,
                                    kubeNamespace: jobPod.Metadata.Namespace
                                    ).Subscribe(
                                    logEntry =>
                                {
                                    Log.Information("[{PodName}] {LogEntry}", jobPod.Metadata.Name, logEntry);
                                },
                                    error =>
                                {
                                    if (error is HttpRequestException <StatusV1> requestError)
                                    {
                                        Log.Error(requestError, "Kubernetes API request error ({Reason}): {ErrorMessage:l}",
                                                  requestError.Response.Reason,
                                                  requestError.Response.Message
                                                  );
                                    }
                                    else
                                    {
                                        Log.Error(error, "JobLog Error");
                                    }
                                },
                                    () =>
                                {
                                    Log.Information("[{PodName}] <end of log>", jobPod.Metadata.Name);

                                    done.Set();
                                }
                                    );

                                Log.Information("Monitoring log for Pod {PodName} of Job {JobName}.",
                                                jobPod.Metadata.Name,
                                                jobName
                                                );
                            }
                        },
                            error =>
                        {
                            Log.Error(error, "PodWatch Error");
                        },
                            () =>
                        {
                            Log.Information("PodWatch End");
                        }
                            );

                        Log.Information("Creating deployment job {JobName}...", jobName);

                        JobV1 deploymentJob = kubeResources.DeployGliderGunRemoteJob(options);
                        try
                        {
                            deploymentJob = await client.JobsV1().Create(deploymentJob);
                        }
                        catch (HttpRequestException <StatusV1> createJobFailed)
                        {
                            Log.Error(createJobFailed, "Failed to create Kubernetes Job {JobName} for deployment ({Reason}): {ErrorMessage}",
                                      jobName,
                                      createJobFailed.Response.Reason,
                                      createJobFailed.Response.Message
                                      );

                            return(ExitCodes.JobFailed);
                        }

                        Log.Information("Created deployment job {JobName}.", deploymentJob.Metadata.Name);

                        TimeSpan timeout = TimeSpan.FromSeconds(options.Timeout);
                        Log.Information("Waiting up to {TimeoutSeconds} seconds for deployment job {JobName} to complete.",
                                        timeout.TotalSeconds,
                                        jobName
                                        );
                        if (!done.WaitOne(timeout))
                        {
                            using (jobPodWatch)
                                using (jobLogWatch)
                                {
                                    Log.Error("Timed out after waiting {TimeoutSeconds} seconds for deployment job {JobName} to complete.",
                                              timeout.TotalSeconds,
                                              jobName
                                              );

                                    return(ExitCodes.JobTimeout);
                                }
                        }

                        jobPodWatch?.Dispose();
                        jobLogWatch?.Dispose();

                        deploymentJob = await client.JobsV1().Get(jobName);

                        if (deploymentJob == null)
                        {
                            Log.Error("Cannot find deployment job {JobName} in namespace {KubeNamespace}.",
                                      deploymentJob.Metadata.Name,
                                      deploymentJob.Metadata.Namespace
                                      );

                            return(ExitCodes.UnexpectedError);
                        }

                        if (deploymentJob.Status.Failed > 0)
                        {
                            Log.Error("Deployment job {JobName} failed.",
                                      deploymentJob.Metadata.Name
                                      );
                            foreach (JobConditionV1 jobCondition in deploymentJob.Status.Conditions)
                            {
                                Log.Error("Deployment job {JobName} failed ({Reason}): {ErrorMessage}.",
                                          deploymentJob.Metadata.Name,
                                          jobCondition.Reason,
                                          jobCondition.Message
                                          );
                            }

                            return(ExitCodes.JobFailed);
                        }

                        if (deploymentJob.Status.Succeeded > 0)
                        {
                            Log.Information("Deployment job {JobName} completed successfully.",
                                            deploymentJob.Metadata.Name
                                            );
                        }
                    }

                Log.Information("Done.");

                return(ExitCodes.Success);
            }
            catch (HttpRequestException <StatusV1> kubeRequestError)
            {
                Log.Error(kubeRequestError, "A Kubernetes API request failed while deploying the remote node ({Reason}): {ErrorMessage}",
                          kubeRequestError.Response.Reason,
                          kubeRequestError.Response.Message
                          );

                return(ExitCodes.JobFailed);
            }
            catch (Exception unexpectedError)
            {
                Log.Error(unexpectedError, "An unexpected error occurred while deploying the remote node.");

                return(ExitCodes.UnexpectedError);
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }
        public async Task PodsV1_GetByName_NotFound()
        {
            var logEntries = new List <LogEntry>();

            TestLogger logger = new TestLogger(LogLevel.Information);

            logger.LogEntries.Subscribe(
                logEntry => logEntries.Add(logEntry)
                );

            ClientBuilder clientBuilder = new ClientBuilder()
                                          .WithLogging(logger);

            HttpClient httpClient = clientBuilder.CreateClient("http://localhost:1234", TestHandlers.RespondWith(request =>
            {
                return(request.CreateResponse(HttpStatusCode.NotFound,
                                              responseBody: JsonConvert.SerializeObject(new StatusV1
                {
                    Reason = "NotFound"
                }),
                                              WellKnownMediaTypes.Json
                                              ));
            }));

            KubeClientOptions clientOptions = new KubeClientOptions("http://localhost:1234");

            using (KubeApiClient kubeClient = KubeApiClient.Create(httpClient, clientOptions))
            {
                PodV1 pod = await kubeClient.PodsV1().Get(name: "foo");

                Assert.Null(pod);
            }

            Assert.Equal(2, logEntries.Count);

            LogEntry logEntry1 = logEntries[0];

            Assert.Equal(LogEventIds.BeginRequest, logEntry1.EventId);
            Assert.Equal("Performing GET request to 'http://localhost:1234/api/v1/namespaces/default/pods/foo'.",
                         logEntry1.Message
                         );
            Assert.Equal("GET",
                         logEntry1.Properties["Method"]
                         );
            Assert.Equal(new Uri("http://localhost:1234/api/v1/namespaces/default/pods/foo"),
                         logEntry1.Properties["RequestUri"]
                         );

            LogEntry logEntry2 = logEntries[1];

            Assert.Equal(LogEventIds.EndRequest, logEntry2.EventId);
            Assert.Equal("Completed GET request to 'http://localhost:1234/api/v1/namespaces/default/pods/foo' (NotFound).",
                         logEntry2.Message
                         );
            Assert.Equal("GET",
                         logEntry2.Properties["Method"]
                         );
            Assert.Equal(new Uri("http://localhost:1234/api/v1/namespaces/default/pods/foo"),
                         logEntry2.Properties["RequestUri"]
                         );
            Assert.Equal(HttpStatusCode.NotFound,
                         logEntry2.Properties["StatusCode"]
                         );
        }
示例#11
0
        public async Task Delete(PodV1 entity)
        {
            var result = await _client.PodsV1().Delete(entity.Metadata.Name, entity.Metadata.Namespace, DeletePropagationPolicy.Background);

            return;
        }
示例#12
0
        /// <summary>
        ///     The main program entry-point.
        /// </summary>
        /// <param name="commandLineArguments">
        ///     The program's command-line arguments.
        /// </param>
        /// <returns>
        ///     The program exit-code.
        /// </returns>
        static async Task <int> Main(string[] commandLineArguments)
        {
            // Show help if no arguments are specified.
            bool showHelp = commandLineArguments.Length == 0;

            if (showHelp)
            {
                commandLineArguments = new[] { "--help" }
            }
            ;

            ProgramOptions options = ProgramOptions.Parse(commandLineArguments);

            if (options == null)
            {
                return(showHelp ? ExitCodes.Success : ExitCodes.InvalidArguments);
            }

            ILoggerFactory loggers = ConfigureLogging(options);

            try
            {
                KubeClientOptions clientOptions = K8sConfig.Load().ToKubeClientOptions(
                    kubeContextName: options.KubeContext,
                    defaultKubeNamespace: options.KubeNamespace
                    );

                using (KubeApiClient client = KubeApiClient.Create(clientOptions, loggers))
                {
                    Log.LogInformation("Finding target pod...");

                    PodV1 targetPod = await client.PodsV1().Get(options.PodName,
                                                                kubeNamespace: options.KubeNamespace
                                                                );

                    if (targetPod == null)
                    {
                        Log.LogError("Pod '{PodName}' not found in namespace '{KubeNamespace}' on cluster ({KubeContextName}).",
                                     options.PodName,
                                     options.KubeNamespace,
                                     options.KubeContext
                                     );

                        return(ExitCodes.NotFound);
                    }

                    if (!String.IsNullOrWhiteSpace(options.ContainerName))
                    {
                        ContainerStatusV1 targetContainer = targetPod.Status.ContainerStatuses.Find(
                            container => container.Name == options.ContainerName
                            );
                        if (targetContainer == null)
                        {
                            Log.LogError("Container '{ContainerName}' not found in Pod '{PodName}' in namespace '{KubeNamespace}' on cluster ({KubeContextName}).",
                                         options.ContainerName,
                                         options.PodName,
                                         options.KubeNamespace,
                                         options.KubeContext
                                         );

                            return(ExitCodes.NotFound);
                        }
                    }
                    else if (targetPod.Status.ContainerStatuses.Count > 1)
                    {
                        Log.LogError("Pod '{PodName}' in namespace '{KubeNamespace}' on cluster ({KubeContextName}) has more than one container. Please specify the name of the target container",
                                     options.PodName,
                                     options.KubeNamespace,
                                     options.KubeContext
                                     );

                        return(ExitCodes.InvalidArguments);
                    }

                    Log.LogDebug("Connecting...");

                    K8sMultiplexer multiplexer = await client.PodsV1().ExecAndConnect(
                        podName: options.PodName,
                        container: options.ContainerName,
                        command: options.Command,
                        kubeNamespace: options.KubeContext,
                        stdin: true,
                        stdout: true,
                        stderr: true,
                        tty: true // Required for interactivity
                        );

                    Log.LogInformation("Connected.");

                    Task stdInPump, stdOutPump, stdErrPump;

                    using (multiplexer)
                        using (CancellationTokenSource pumpCancellation = new CancellationTokenSource())
                            using (Stream localStdIn = Console.OpenStandardInput())
                                using (Stream remoteStdIn = multiplexer.GetStdIn())
                                    using (Stream localStdOut = Console.OpenStandardOutput())
                                        using (Stream remoteStdOut = multiplexer.GetStdOut())
                                            using (Stream localStdErr = Console.OpenStandardError())
                                                using (Stream remoteStdErr = multiplexer.GetStdErr())
                                                {
                                                    stdInPump  = localStdIn.CopyToAsync(remoteStdIn, pumpCancellation.Token);
                                                    stdOutPump = remoteStdOut.CopyToAsync(localStdOut, pumpCancellation.Token);
                                                    stdErrPump = remoteStdErr.CopyToAsync(localStdErr, pumpCancellation.Token);

                                                    await multiplexer.WhenConnectionClosed;

                                                    // Terminate stream pumps.
                                                    pumpCancellation.Cancel();
                                                }

                    Log.LogInformation("Connection closed.");
                    Log.LogInformation("Done.");
                }

                return(ExitCodes.Success);
            }
            catch (Exception unexpectedError)
            {
                Log.LogError(unexpectedError.ToString());
                Log.LogError(unexpectedError, "Unexpected error.");

                return(ExitCodes.UnexpectedError);
            }
        }