All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.hyscale.deployer.services.util.K8sPodUtil Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
/**
 * Copyright 2019 Pramati Prism, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.hyscale.deployer.services.util;

import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import io.hyscale.deployer.services.model.PodStatus;
import org.apache.commons.lang3.StringUtils;

import io.hyscale.commons.constants.K8SRuntimeConstants;
import io.hyscale.deployer.services.model.PodCondition;
import io.kubernetes.client.openapi.models.V1ContainerStatus;
import io.kubernetes.client.openapi.models.V1OwnerReference;
import io.kubernetes.client.openapi.models.V1Pod;
import io.kubernetes.client.openapi.models.V1PodCondition;

/**
 * Created by sameerag on 12/9/18.
 * Utility for K8s pod level information
 *
 */
public class K8sPodUtil {

    private K8sPodUtil() {}
    /**
     * Gets aggregate status from Init containers - empty if init containers are ready
     * If init container status not found gets aggregated status from containers
     * If containers status not found get pod level status
     * @param v1Pod
     * @return ServiceStatus from containers in pod
     */
    public static String getAggregatedStatusOfContainersForPod(V1Pod v1Pod) {
        if (v1Pod == null) {
            return null;
        }
        String initContainerAggStatus = validateAndGetInitContainerStatuses(
                v1Pod.getStatus().getInitContainerStatuses());
        if (initContainerAggStatus != null) {
            return initContainerAggStatus;
        }
        if(v1Pod.getMetadata().getDeletionTimestamp() != null){
            return PodStatus.TERMINATING.getStatus();
        }
        String containerAggStatus = validateAndGetContainerStatuses(v1Pod.getStatus().getContainerStatuses());
        return containerAggStatus != null ? containerAggStatus : v1Pod.getStatus().getPhase();
    }

    /**
     * Failure Reason order: Initialized | Pod Scheduled | Containers Ready | Ready
     */
    public static String getFailureMessage(V1Pod v1Pod) {
        if (v1Pod == null || v1Pod.getStatus() == null) {
            return null;
        }
        List podConditions = v1Pod.getStatus().getConditions();
        if (podConditions == null || podConditions.isEmpty()) {
            return null;
        }
        if (checkForPodCondition(v1Pod, PodCondition.READY)) {
            return null;
        }
        Map podConditionsMap = new EnumMap<>(PodCondition.class);
        podConditions.stream().forEach(condition -> {
            PodCondition podCondition = PodCondition.fromString(condition.getType());
            if (podCondition != null) {
                podConditionsMap.put(podCondition, condition);
            }
        });

        String message = getMessageForCondition(podConditionsMap, PodCondition.INITIALIZED);
        if (StringUtils.isNotBlank(message)) {
            return message;
        }
        message = getMessageForCondition(podConditionsMap, PodCondition.POD_SCHEDULED);
        if (StringUtils.isNotBlank(message)) {
            return message;
        }
        message = getMessageForCondition(podConditionsMap, PodCondition.CONTAINERS_READY);
        if (StringUtils.isNotBlank(message)) {
            return message;
        }
        message = getMessageForCondition(podConditionsMap, PodCondition.READY);

        return message;
    }

    private static String getMessageForCondition(Map podConditionsMap,
                                                 PodCondition condition) {
        V1PodCondition podCondition = podConditionsMap.get(condition);
        if (podCondition != null && podCondition.getStatus() != null && !Boolean.valueOf(podCondition.getStatus())) {
            return podCondition.getMessage();
        }

        return null;
    }

    /**
     *
     * @param containerStatuses
     * @return status of container not in running state
     */
    private static String validateAndGetContainerStatuses(List containerStatuses) {
        if (containerStatuses == null || containerStatuses.isEmpty()) {
            return null;
        }
        String aggregateStatus = null;
        for (V1ContainerStatus each : containerStatuses) {
            if (!each.getReady() && each.getLastState() != null) {
                if (each.getLastState().getTerminated() != null) {
                    aggregateStatus = each.getLastState().getTerminated().getReason();
                    break;
                } else if (each.getLastState().getWaiting() != null) {
                    aggregateStatus = each.getLastState().getWaiting().getReason();
                    break;
                }
            }
            if (each.getState().getRunning() == null) {
                if (each.getState().getTerminated() != null) {
                    aggregateStatus = each.getState().getTerminated().getReason();
                    break;
                } else if (each.getState().getWaiting() != null) {
                    aggregateStatus = each.getState().getWaiting().getReason();
                    break;
                }
            }
        }
        return aggregateStatus;
    }

    public static String getContainerStatus(V1ContainerStatus containerStatus) {
        if (containerStatus.getState().getRunning() == null) {
            if (containerStatus.getState().getTerminated() != null) {
                return containerStatus.getState().getTerminated().getReason();
            } else if (containerStatus.getState().getWaiting() != null) {
                return containerStatus.getState().getWaiting().getReason();
            }
        } else {
            // any other way?
            return "Running";
        }
        return null;
    }

    /**
     *
     * @param initContainerStatuses
     * @return status of init container in waiting state, else null
     */
    private static String validateAndGetInitContainerStatuses(List initContainerStatuses) {
        if (initContainerStatuses == null || initContainerStatuses.isEmpty()) {
            return null;
        }
        String initContainerStatus = null;
        for (V1ContainerStatus each : initContainerStatuses) {
            if (each.getState().getTerminated() != null && each.getReady()) {
                // Do nothing
            } else if (each.getState().getWaiting() != null) {
                initContainerStatus = each.getState().getWaiting().getReason();
                break;
            } else if (each.getState().getRunning() != null) {
                // TODO Handle
            }
        }
        return initContainerStatus;
    }

    // If any container restart > 0 or pod in errorState
    public static boolean checkForPodCreation(V1Pod v1Pod) {
        if (v1Pod == null) {
            return false;
        }
        String status = getAggregatedStatusOfContainersForPod(v1Pod);
        if (K8SRuntimeConstants.POD_RUNING_STATE_CONDITION.equalsIgnoreCase(status)) {
            return true;
        }
        return checkForContainersRestart(v1Pod.getStatus().getContainerStatuses())
                || K8SRuntimeConstants.POD_ERROR_SATES.contains(status);
    }
    
    /**
     * @param v1Pod
     * @return return true if pod is in failed state, else false
     */
	public static boolean checkForPodFailure(V1Pod v1Pod) {
		return K8SRuntimeConstants.POD_ERROR_SATES.contains(getAggregatedStatusOfContainersForPod(v1Pod));
	}


    /**
     * @param pod
     * @param restartPodCount
     * @return If pod restart count is greater than to given restartPodCount then it will return true, else false
     */
	public static boolean checkForPodRestart(V1Pod pod, Long restartPodCount) {
		if(pod==null ||pod.getStatus()==null||pod.getStatus().getContainerStatuses()==null) {
			return false;
		}
		return pod.getStatus().getContainerStatuses().stream().anyMatch(s -> s.getRestartCount() > restartPodCount);

	}
	

    public static boolean checkForContainersRestart(List containerStatuses) {
        if (containerStatuses == null) {
            return false;
        }

        for (V1ContainerStatus status : containerStatuses) {
            Integer contRestartCount = status.getRestartCount();
            if (contRestartCount != null && contRestartCount > 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks if provided pod condition status is true in the pod
     * @param pod
     * @param podCondition
     * @return true is condition is set in Pod, else false
     */
    public static boolean checkForPodCondition(V1Pod pod, PodCondition podCondition) {
        List conditions = pod.getStatus().getConditions();
        if (conditions == null || conditions.isEmpty() || podCondition == null) {
            return false;
        }
        for (V1PodCondition v1PodCondition : conditions) {
            if (v1PodCondition.getType().equalsIgnoreCase(podCondition.getPodCondition())
                    && Boolean.valueOf(v1PodCondition.getStatus())) {
                return true;
            }
        }
        return false;
    }

    public static String getPodMessage(V1Pod v1Pod) {
        if (v1Pod == null) {
            return null;
        }
        String initContainerAggStatusMsg = validateAndGetInitContainerMessage(
                v1Pod.getStatus().getInitContainerStatuses());
        if (initContainerAggStatusMsg != null) {
            return initContainerAggStatusMsg;
        }
        String containerAggStatusMsg = validateAndGetContainerStatusMessage(v1Pod.getStatus().getContainerStatuses());
        return containerAggStatusMsg != null ? containerAggStatusMsg : v1Pod.getStatus().getMessage();
    }

    private static String validateAndGetContainerStatusMessage(List containerStatuses) {
        if (containerStatuses == null || containerStatuses.isEmpty()) {
            return null;
        }
        String aggregateStatus = null;
        for (V1ContainerStatus each : containerStatuses) {
            if (each.getLastState() != null) {
                if (each.getLastState().getTerminated() != null) {
                    aggregateStatus = each.getLastState().getTerminated().getMessage();
                    break;
                } else if (each.getLastState().getWaiting() != null) {
                    aggregateStatus = each.getLastState().getWaiting().getMessage();
                    break;
                }
            }
            if (each.getState().getRunning() == null) {
                if (each.getState().getTerminated() != null) {
                    aggregateStatus = each.getState().getTerminated().getMessage();
                    break;
                } else if (each.getState().getWaiting() != null) {
                    aggregateStatus = each.getState().getWaiting().getMessage();
                    break;
                }
            }
        }
        return aggregateStatus;
    }

    private static String validateAndGetInitContainerMessage(List initContainerStatuses) {
        if (initContainerStatuses == null || initContainerStatuses.isEmpty()) {
            return null;
        }
        String initContainerStatus = null;
        for (V1ContainerStatus each : initContainerStatuses) {
            if (each.getState().getTerminated() != null && each.getReady()) {
                // Do nothing
            } else if (each.getState().getWaiting() != null) {
                initContainerStatus = each.getState().getWaiting().getMessage();
                break;
            } else if (each.getState().getRunning() != null) {
                // TODO
            }
        }
        return initContainerStatus;
    }

    /**
     *
     * @param podList
     * @return pod owner kind if all pods have same owner, else null
     */

    public static String getPodsUniqueOwner(List podList) {
        if (podList == null || podList.isEmpty()) {
            return null;
        }

        String podOwner = getPodOwner(podList.get(0));
        if (StringUtils.isBlank(podOwner)) {
            return null;
        }

        for (V1Pod pod : podList) {
            if (!podOwner.equals(getPodOwner(pod))) {
                return null;
            }
        }

        return podOwner;
    }

    /**
     *
     * @param pod
     * @return pod owner kind
     */
    public static String getPodOwner(V1Pod pod) {
        if (pod == null) {
            return null;
        }
        V1OwnerReference podOwner = getOwnerReference(pod);

        return podOwner != null ? podOwner.getKind() : null;
    }
  
    /**
     *
     * @param podList
     * @param filter predicate used for filtering
     * @return filtered pods
     */
    public static List filterPods(List podList, Predicate filter) {
        if (podList == null || podList.isEmpty() || filter == null) {
            return podList;
        }
        return podList.stream().filter(filter::test).collect(Collectors.toList());
    }

    /**
     *
     * @param podList
     * @param filter condition and value
     * @param filterValue - value used for filtering
     * @return
     */
    public static List filterPods(List podList, BiPredicate filter, Object filterValue) {
        if (podList == null || podList.isEmpty() || filter == null || filterValue == null) {
            return podList;
        }

        return podList.stream().filter(pod -> filter.test(pod, filterValue))
                .collect(Collectors.toList());
    }

    /**
     * Check if pods contains passed labels(key as well as value)
     * @param pod
     * @param labels
     * @return true if pod contains passed labels, else false
     */
    public static boolean checkPodLabels(V1Pod pod, Map labels) {
        if (pod == null) {
            return false;
        }
        if (labels == null || labels.isEmpty()) {
            return true;
        }
        Map podLabels = pod.getMetadata().getLabels();

        if (podLabels == null) {
            return false;
        }

        return podLabels.entrySet().containsAll(labels.entrySet());
    }

    /**
     * Pods are ambiguous if pods have different owner kinds, or same owner with different uid
     * @param podList
     * @return whether all pods belong to same owner
     */
    public static boolean checkForPodAmbiguity(List podList) {
        if (podList == null || podList.size() < 2) {
            return false;
        }
        V1OwnerReference ownerReference = getOwnerReference(podList.get(0));
        if (ownerReference == null) {
            return true;
        }
        String podOwner = ownerReference.getKind();
        String ownerUID = ownerReference.getUid();

        if (StringUtils.isBlank(podOwner) || StringUtils.isBlank(ownerUID)) {
            return true;
        }

        for (V1Pod pod : podList) {
            ownerReference = getOwnerReference(pod);
            if (ownerReference == null) {
                return true;
            }
            if (!podOwner.equals(ownerReference.getKind()) || !ownerUID.equals(ownerReference.getUid())) {
                return true;
            }
        }
        return false;
    }

    private static V1OwnerReference getOwnerReference(V1Pod pod) {
        if (pod == null) {
            return null;
        }
        List ownerReferences = pod.getMetadata().getOwnerReferences();
        if (ownerReferences == null || ownerReferences.isEmpty()) {
            return null;
        }
        return ownerReferences.get(0);
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy