示例#1
0
        /// <summary>
        /// <para>
        /// Connects to a Kubernetes cluster if it already exists.  This sets the <see cref="KubeSetupProperty.K8sClient"/>
        /// property in the setup controller state when Kubernetes is running and a connection has not already
        /// been established.
        /// </para>
        /// <note>
        /// The <see cref="KubeSetupProperty.K8sClient"/> will not be set when Kubernetes has not been started, so
        /// <see cref="ObjectDictionary.Get{TValue}(string)"/> calls for this property will fail when the
        /// cluster has not been connected yet, which will be useful for debugging setup steps that require
        /// a connection but this hasn't happened yet.
        /// </note>
        /// </summary>
        /// <param name="controller">The setup controller.</param>
        public static void ConnectCluster(ISetupController controller)
        {
            Covenant.Requires <ArgumentNullException>(controller != null, nameof(controller));

            if (controller.ContainsKey(KubeSetupProperty.K8sClient))
            {
                return;     // Already connected
            }

            var cluster    = controller.Get <ClusterProxy>(KubeSetupProperty.ClusterProxy);
            var configFile = GetCurrentKubeConfigPath();

            if (!string.IsNullOrEmpty(configFile) && File.Exists(configFile))
            {
                // We're using a generated wrapper class to handle transient retries rather than
                // modifying the built-in base retry policy.  We're really just trying to handle
                // the transients that happen during setup when the API server is unavailable for
                // some reaon (like it's being restarted).

                var k8s = new KubernetesWithRetry(KubernetesClientConfiguration.BuildConfigFromConfigFile(configFile, currentContext: cluster.KubeContext.Name));

                k8s.RetryPolicy =
                    new ExponentialRetryPolicy(
                        transientDetector:
                        exception =>
                {
                    var exceptionType = exception.GetType();

                    // Exceptions like this happen when a API server connection can't be established
                    // because the server isn't running or ready.

                    if (exceptionType == typeof(HttpRequestException) && exception.InnerException != null && exception.InnerException.GetType() == typeof(SocketException))
                    {
                        return(true);
                    }

                    var httpOperationException = exception as HttpOperationException;

                    if (httpOperationException != null)
                    {
                        var statusCode = httpOperationException.Response.StatusCode;

                        switch (statusCode)
                        {
                        case HttpStatusCode.GatewayTimeout:
                        case HttpStatusCode.InternalServerError:
                        case HttpStatusCode.RequestTimeout:
                        case HttpStatusCode.ServiceUnavailable:
                        case (HttpStatusCode)423:                   // Locked
                        case (HttpStatusCode)429:                   // Too many requests

                            return(true);
                        }
                    }

                    // This might be another variant of the check just above.  This looks like an SSL negotiation problem.

                    if (exceptionType == typeof(HttpRequestException) && exception.InnerException != null && exception.InnerException.GetType() == typeof(IOException))
                    {
                        return(true);
                    }

                    return(false);
                },
                        maxAttempts:          int.MaxValue,
                        initialRetryInterval: TimeSpan.FromSeconds(1),
                        maxRetryInterval:     TimeSpan.FromSeconds(5),
                        timeout:              TimeSpan.FromMinutes(5));

                controller.Add(KubeSetupProperty.K8sClient, k8s);
            }
        }