Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/robusta/core/discovery/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -897,12 +897,13 @@ def extract_containers_k8(resource) -> List[Container]:


def is_pod_ready(pod) -> bool:
# Unset until kubelet reports on the pod.
conditions = []
if isinstance(pod, V1Pod):
conditions = pod.status.conditions
conditions = getattr(pod.status, "conditions", None) or []

if isinstance(pod, Pod):
conditions = pod.status.conditions
conditions = getattr(pod.status, "conditions", None) or []

for condition in conditions:
if condition.type == "Ready":
Expand Down
35 changes: 34 additions & 1 deletion tests/discovery/test_discovery.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
import signal
from concurrent.futures import ProcessPoolExecutor
from contextlib import contextmanager
Expand All @@ -7,9 +8,10 @@

import kubernetes
import pytest
from kubernetes.client import V1ObjectMeta, V1Pod, V1PodCondition, V1PodStatus
from kubernetes.client.exceptions import ApiException

from robusta.core.discovery.discovery import Discovery
from robusta.core.discovery.discovery import Discovery, extract_ready_pods, is_pod_ready


# pytest-timeout requires pytest>=7, https://github.com/pytest-dev/pytest-timeout/blob/main/setup.cfg
Expand Down Expand Up @@ -42,3 +44,34 @@ def test_discovery_recovery_on_failure():

assert patched_pool._shutdown_thread
assert not Discovery.executor._shutdown_thread


# ---- is_pod_ready with an unpopulated status ----


def _pod(status: Any) -> V1Pod:
return V1Pod(metadata=V1ObjectMeta(name="p", namespace="kube-system"), status=status)


@pytest.mark.parametrize("status", [None, V1PodStatus(conditions=None), V1PodStatus(conditions=[])])
def test_is_pod_ready_handles_unpopulated_status(status: Any):
"""Regression: a pod kubelet has not reported on yet raised TypeError, which
extract_ready_pods logged as an ERROR with the whole pod dumped into it."""
assert is_pod_ready(_pod(status)) is False


@pytest.mark.parametrize("condition_status,expected", [("True", True), ("False", False)])
def test_is_pod_ready_reads_ready_condition(condition_status: str, expected: bool):
pod = _pod(V1PodStatus(conditions=[V1PodCondition(type="Ready", status=condition_status)]))
assert is_pod_ready(pod) is expected


def test_is_pod_ready_ignores_other_conditions():
pod = _pod(V1PodStatus(conditions=[V1PodCondition(type="PodScheduled", status="True")]))
assert is_pod_ready(pod) is False


def test_extract_ready_pods_does_not_log_for_unpopulated_status(caplog):
with caplog.at_level(logging.ERROR):
assert extract_ready_pods(_pod(None)) == 0
assert not caplog.records
Loading