Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

raise if __exit__ fail #2294

Merged
merged 4 commits into from
Jan 27, 2025
Merged
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
8 changes: 8 additions & 0 deletions ocp_resources/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,11 @@ def __str__(self):

class NNCPConfigurationFailed(Exception):
pass


class ResourceTeardownError(Exception):
def __init__(self, resource: Any):
self.resource = resource

def __str__(self):
return f"Failed to excute teardown for resource {self.resource}"
43 changes: 22 additions & 21 deletions ocp_resources/resource.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,55 @@
from __future__ import annotations

from collections.abc import Callable, Generator
import contextlib

import copy
import json
from warnings import warn

import os
import re
import sys
from collections.abc import Callable, Generator
from io import StringIO
from signal import SIGINT, signal
from types import TracebackType
from typing import Any
from warnings import warn

import kubernetes
from kubernetes.dynamic import DynamicClient, ResourceInstance
import yaml
from benedict import benedict
from kubernetes.dynamic import DynamicClient, ResourceInstance
from kubernetes.dynamic.exceptions import (
ConflictError,
ForbiddenError,
MethodNotAllowedError,
NotFoundError,
ForbiddenError,
ResourceNotFoundError,
)
from kubernetes.dynamic.resource import ResourceField
from packaging.version import Version
from simple_logger.logger import get_logger, logging
from timeout_sampler import (
TimeoutExpiredError,
TimeoutSampler,
TimeoutWatch,
)
from urllib3.exceptions import MaxRetryError

from ocp_resources.event import Event
from ocp_resources.exceptions import MissingRequiredArgumentError, MissingResourceResError, ResourceTeardownError
from ocp_resources.utils.constants import (
DEFAULT_CLUSTER_RETRY_EXCEPTIONS,
NOT_FOUND_ERROR_EXCEPTION_DICT,
PROTOCOL_ERROR_EXCEPTION_DICT,
TIMEOUT_1MINUTE,
TIMEOUT_1SEC,
TIMEOUT_4MINUTES,
TIMEOUT_5SEC,
TIMEOUT_10SEC,
TIMEOUT_30SEC,
TIMEOUT_5SEC,
TIMEOUT_1SEC,
)
from ocp_resources.event import Event
from timeout_sampler import (
TimeoutExpiredError,
TimeoutSampler,
TimeoutWatch,
)
from ocp_resources.exceptions import MissingRequiredArgumentError, MissingResourceResError
from ocp_resources.utils.resource_constants import ResourceConstants
from ocp_resources.utils.utils import skip_existing_resource_creation_teardown


LOGGER = get_logger(name=__name__)
MAX_SUPPORTED_API_VERSION = "v2"

Expand Down Expand Up @@ -571,7 +568,8 @@ def __exit__(
exc_tb: TracebackType | None = None,
) -> None:
if self.teardown:
self.clean_up()
if not self.clean_up():
raise ResourceTeardownError(resource=self)

def _sigint_handler(self, signal_received: int, frame: Any) -> None:
self.__exit__()
Expand Down Expand Up @@ -745,10 +743,13 @@ def wait_deleted(self, timeout: int = TIMEOUT_4MINUTES) -> bool:
TimeoutExpiredError: If resource still exists.
"""
self.logger.info(f"Wait until {self.kind} {self.name} is deleted")
samples = TimeoutSampler(wait_timeout=timeout, sleep=1, func=lambda: self.exists)
for sample in samples:
if not sample:
return True
try:
for sample in TimeoutSampler(wait_timeout=timeout, sleep=1, func=lambda: self.exists):
if not sample:
return True
except TimeoutExpiredError:
self.logger.warning(f"Timeout expired while waiting for {self.kind} {self.name} to be deleted")
return False

return False

Expand Down
25 changes: 23 additions & 2 deletions tests/test_resources.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import pytest
import yaml
from testcontainers.k3s import K3SContainer

from ocp_resources.exceptions import ResourceTeardownError
from ocp_resources.namespace import Namespace
from ocp_resources.pod import Pod
from ocp_resources.resource import Resource, get_client
import yaml
from testcontainers.k3s import K3SContainer
from ocp_resources.secret import Secret


class TestSecretExit(Secret):
def deploy(self, wait: bool = False):
return self

def clean_up(self, wait: bool = True, timeout: int | None = None) -> bool:
return False


@pytest.fixture(scope="session")
Expand Down Expand Up @@ -82,3 +92,14 @@ def test_update_replace(self, namespace):

def test_cleanup(self, namespace):
namespace.clean_up(wait=False)

def test_resource_context_manager(self, client):
with Secret(name="test-context-manager", namespace="default", client=client) as sec:
pass

assert not sec.exists

def test_resource_context_manager_exit(self, client):
with pytest.raises(ResourceTeardownError):
with TestSecretExit(name="test-context-manager-exit", namespace="default", client=client):
pass