Merge "[ops-sunbeam] Allow post-init to throw status exceptions" into main

This commit is contained in:
Zuul 2025-02-25 00:50:04 +00:00 committed by Gerrit Code Review
commit d8e75e5cbc
2 changed files with 36 additions and 10 deletions

View File

@ -25,6 +25,9 @@ from typing import (
)
import ops_sunbeam.tracing as sunbeam_tracing
from ops_sunbeam.guard import (
BaseStatusExceptionError,
)
if TYPE_CHECKING:
from ops_sunbeam.charm import (
@ -101,5 +104,20 @@ class PostInitMeta(type):
def __call__(cls, *args, **kw):
"""Call __post_init__ after __init__."""
instance = super().__call__(*args, **kw)
instance.__post_init__()
try:
instance.__post_init__()
except BaseStatusExceptionError as e:
# Allow post init to raise an ops_sunbeam status
# exception without causing the charm to error.
# This status will be collected and set on the
# unit.
# import here to avoid circular import
from ops_sunbeam.charm import (
OSBaseOperatorCharm,
)
if isinstance(instance, OSBaseOperatorCharm):
instance.status.set(e.to_status())
else:
raise e
return instance

View File

@ -20,9 +20,11 @@ from contextlib import (
contextmanager,
)
from ops.model import (
from ops import (
ActiveStatus,
BlockedStatus,
MaintenanceStatus,
StatusBase,
WaitingStatus,
)
@ -43,27 +45,33 @@ class GuardExceptionError(Exception):
class BaseStatusExceptionError(Exception):
"""Charm is blocked."""
def __init__(self, msg):
status_type: type[StatusBase] = ActiveStatus
def __init__(self, msg: str):
super().__init__(msg)
self.msg = msg
super().__init__(self.msg)
def to_status(self):
"""Convert the exception to an ops status."""
return self.status_type(self.msg)
class BlockedExceptionError(BaseStatusExceptionError):
"""Charm is blocked."""
pass
status_type = BlockedStatus
class MaintenanceExceptionError(BaseStatusExceptionError):
"""Charm is performing maintenance."""
pass
status_type = MaintenanceStatus
class WaitingExceptionError(BaseStatusExceptionError):
"""Charm is waiting."""
pass
status_type = WaitingStatus
@contextmanager
@ -103,19 +111,19 @@ def guard(
logger.warning(
"Charm is blocked in section '%s' due to '%s'", section, str(e)
)
charm.status.set(BlockedStatus(e.msg))
charm.status.set(e.to_status())
except WaitingExceptionError as e:
logger.warning(
"Charm is waiting in section '%s' due to '%s'", section, str(e)
)
charm.status.set(WaitingStatus(e.msg))
charm.status.set(e.to_status())
except MaintenanceExceptionError as e:
logger.warning(
"Charm performing maintenance in section '%s' due to '%s'",
section,
str(e),
)
charm.status.set(MaintenanceStatus(e.msg))
charm.status.set(e.to_status())
except Exception as e:
# something else went wrong
if handle_exception: