Exemple #1
0
        public IRunspaceInfo StartCreate()
        {
            _logger.LogInformation("Create Runspace");
            K8sRunspaceInfo result = null;

            try {
                _logger.LogDebug("GenerateRunspaceId");
                var runspaceId = GenerateRunspaceId();
                _logger.LogDebug($"RunspaceId: {runspaceId}");
                var runspacePod = CreateK8sPod(runspaceId);

                result = new K8sRunspaceInfo {
                    Id            = runspaceId,
                    CreationState = RunspaceCreationState.Creating
                };
                _logger.LogDebug($"RunspaceInfo.Id: {result.Id}");
            } catch (Exception exc) {
                _logger.LogError(exc.ToString());

                var error = new RunspaceProviderException(
                    Resources.K8sRunspaceProvider_Create_K8sRunspaceCreateFail,
                    exc);

                result = new K8sRunspaceInfo {
                    Id            = result?.Id,
                    CreationState = RunspaceCreationState.Error,
                    CreationError = error
                };
            }

            return(result);
        }
Exemple #2
0
        public IRunspaceInfo[] List()
        {
            _logger.LogInformation("List Runspaces");
            List <IRunspaceInfo> result = new List <IRunspaceInfo>();

            try {
                var runspacePods = _client.ListNamespacedPod(
                    _namespace,
                    labelSelector: $"{LABEL_KEY}={RUNSPACE_TYPE}");

                foreach (var runspacePod in runspacePods.Items)
                {
                    if (runspacePod?.Status?.Phase != "Running" &&
                        runspacePod?.Status?.Phase != "Pending")
                    {
                        continue;
                    }

                    var runspaceInfo = new K8sRunspaceInfo {
                        Id = runspacePod.Metadata.Name
                    };

                    if (runspacePod?.Status?.Phase == "Pending")
                    {
                        runspaceInfo.CreationState = RunspaceCreationState.Creating;
                    }
                    else
                    {
                        runspaceInfo.Endpoint = new IPEndPoint(
                            IPAddress.Parse(runspacePod.Status.PodIP),
                            _runspaceApiPort);
                        runspaceInfo.CreationState = RunspaceCreationState.Ready;
                    }

                    result.Add(runspaceInfo);
                }
            } catch (Exception exc) {
                _logger.LogError(exc.ToString());
                throw new RunspaceProviderException(
                          Resources.K8sRunspaceProvider_List_K8sRunspaceListFail,
                          exc);
            }

            return(result.ToArray());
        }
Exemple #3
0
        public IRunspaceInfo WaitCreateCompletion(IRunspaceInfo runspaceInfo)
        {
            var result = runspaceInfo;

            if (result != null && result.CreationState == RunspaceCreationState.Creating)
            {
                V1Pod pod = null;
                try {
                    _logger.LogDebug($"Waiting k8s Pod '{runspaceInfo.Id}' to become ready");
                    _logger.LogDebug($"K8s API Call ReadNamespacedPod: {runspaceInfo.Id}");
                    pod = _client.ReadNamespacedPod(runspaceInfo.Id, _namespace);
                } catch (Exception exc) {
                    result = new K8sRunspaceInfo {
                        Id            = result.Id,
                        CreationState = RunspaceCreationState.Error,
                        CreationError = new RunspaceProviderException(
                            string.Format(
                                Resources.K8sRunspaceProvider_WaitCreateComplation_PodNotFound, result.Id),
                            exc)
                    };
                }

                if (pod != null)
                {
                    // Set 10 minutes timeout for container creation.
                    // Worst case would be image pulling from server.
                    int maxRetryCount   = 6000;
                    int retryIntervalMs = 100;
                    int retryCount      = 1;

                    // Wait Pod to become running and obtain IP Address
                    _logger.LogDebug($"Start wating K8s Pod to become running: {pod.Metadata.Name}");
                    // There are three possible phases of a POD
                    // Pending - awaiting containers to start
                    // Running - Pod is initialized and all containers in the Pod are running or completed successfully
                    // Terminating - Pod is terminating

                    // The Pending phase could last forever when container image pull error occurred or some other error
                    // in the container initialization happens. In order to stop waiting below we first monitor for Pod status to
                    // phase to switch from pending to running. While Pod is pending phase we monitor the container
                    // creation for errors and if such occur we break the waiting with error.
                    //
                    // The Container creation errors that are related to image pulling failura are stored in the
                    // pod.Status.ContainerStatuses[0].State.Waiting propery is not null which is instance of V1ContainerStateWaiting
                    // The errors are returned as strings in Reason property of the V1ContainerStateWaiting
                    // The strings that represent errors are:
                    //
                    // ImagePullBackOff - Container image pull failed, kubelet is backing off image pull
                    // ImageInspectError - Unable to inspect image
                    // ErrImagePull - General image pull error
                    // ErrImageNeverPull - Required Image is absent on host and PullPolicy is NeverPullImage
                    // RegistryUnavailable - Get http error when pulling image from registry
                    // InvalidImageName - Unable to parse the image name.

                    while (
                        pod != null &&
                        string.IsNullOrEmpty(pod.Status?.PodIP) &&
                        (pod.Status?.Phase != "Running" ||
                         (pod.Status?.Phase == "Pending" &&
                          !HasErrrorInContainerStatus(pod.Status, out var _))) &&
                        retryCount < maxRetryCount)
                    {
                        Thread.Sleep(retryIntervalMs);
                        _logger.LogDebug($"K8s API Call ReadNamespacedPod: {pod.Metadata.Name}");
                        pod = _client.ReadNamespacedPod(pod.Metadata.Name, _namespace);
                        retryCount++;
                    }

                    if (retryCount >= maxRetryCount)
                    {
                        // Timeout
                        result = new K8sRunspaceInfo {
                            Id            = result.Id,
                            CreationState = RunspaceCreationState.Error,
                            CreationError = new RunspaceProviderException(Resources.K8sRunspaceProvider_WaitCreateComplition_TimeOut)
                        };
                    }
                    else
                    if (HasErrrorInContainerStatus(pod.Status, out var errorMessage))
                    {
                        // Container Creation Error
                        result = new K8sRunspaceInfo {
                            Id            = result.Id,
                            CreationState = RunspaceCreationState.Error,
                            CreationError = new RunspaceProviderException(errorMessage)
                        };
                    }
                    else
                    {
                        // Success, everything should be in place
                        result = new K8sRunspaceInfo {
                            Id       = result.Id,
                            Endpoint =
                                new IPEndPoint(
                                    IPAddress.Parse(pod.Status.PodIP),
                                    _runspaceApiPort),
                            CreationState = RunspaceCreationState.Ready
                        };
                    }

                    if (result.CreationState == RunspaceCreationState.Ready && _verifyRunspaceApiIsAccessibleOnCreate)
                    {
                        try {
                            _logger.LogDebug($"EnsureRunspaceEndpointIsAccessible: Start");
                            // Ensure Container is accessible over the network after creation
                            EnsureRunspaceEndpointIsAccessible(result);
                            _logger.LogDebug($"EnsureRunspaceEndpointIsAccessible: Success");
                        } catch (RunspaceProviderException exc) {
                            _logger.LogError(exc.ToString());
                            // Kill the container that is not accessible, otherwise it will leak
                            try {
                                Kill(result.Id);
                            } catch (RunspaceProviderException rexc) {
                                _logger.LogError(rexc.ToString());
                            }

                            result = new K8sRunspaceInfo {
                                Id            = result.Id,
                                CreationState = RunspaceCreationState.Error,
                                CreationError = exc
                            };
                        }
                    }
                }
            }
            return(result);
        }