Skip to content

Commit cbe83c2

Browse files
authored
Refactor ZabbixAPI exception handling (#267)
1 parent e1ae03c commit cbe83c2

File tree

3 files changed

+53
-21
lines changed

3 files changed

+53
-21
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
- `create_notification_user`: Now adds users to the default user group in addition to the notification user group to match behavior in V2.
1515
- `show_media_types`: Now shows the formatted string representation of the media type `type` field instead of an integer.
16+
- Auth tokens and passwords from API request errors are now masked by default in output.
1617

1718
### Deprecated
1819

zabbix_cli/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ class ZabbixAPIResponseParsingError(ZabbixAPIRequestError):
144144
"""Zabbix API request error."""
145145

146146

147+
class ZabbixAPISessionExpired(ZabbixAPIRequestError):
148+
"""Zabbix API session expired."""
149+
150+
147151
class ZabbixAPICallError(ZabbixAPIException):
148152
"""Zabbix API request error."""
149153

zabbix_cli/pyzabbix/client.py

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from zabbix_cli.exceptions import ZabbixAPINotAuthorizedError
4343
from zabbix_cli.exceptions import ZabbixAPIRequestError
4444
from zabbix_cli.exceptions import ZabbixAPIResponseParsingError
45+
from zabbix_cli.exceptions import ZabbixAPISessionExpired
4546
from zabbix_cli.exceptions import ZabbixAPITokenExpiredError
4647
from zabbix_cli.exceptions import ZabbixNotFoundError
4748
from zabbix_cli.pyzabbix import compat
@@ -455,29 +456,55 @@ def do_request(
455456
"Zabbix API returned invalid JSON", response=response
456457
) from e
457458

458-
if resp.error is not None:
459-
# some errors don't contain 'data': workaround for ZBX-9340
460-
if not resp.error.data:
461-
resp.error.data = "No data"
462-
463-
# TODO: refactor this exc type narrowing to some sort of predicate/dict lookup
464-
if "API token expired" in resp.error.data:
465-
cls = ZabbixAPITokenExpiredError
466-
logger.debug(
467-
"API token '%s' has expired.",
468-
f"{self.auth[:8]}...", # Redact most of the token
469-
)
470-
elif "Not authorized" in resp.error.data:
471-
cls = ZabbixAPINotAuthorizedError
472-
else:
473-
cls = ZabbixAPIRequestError
474-
raise cls(
475-
f"Error: {resp.error.message}: {resp.error.data}",
476-
api_response=resp,
477-
response=response,
478-
)
459+
self._check_response_errors(resp, response, params)
460+
479461
return resp
480462

463+
def _check_response_errors(
464+
self,
465+
resp: ZabbixAPIResponse,
466+
response: httpx.Response,
467+
params: ParamsType,
468+
) -> None:
469+
# Nothing to handlde
470+
if not resp.error:
471+
return
472+
473+
# some errors don't contain 'data': workaround for ZBX-9340
474+
if not resp.error.data:
475+
resp.error.data = "No data"
476+
477+
msg = f"Error: {resp.error.message} {resp.error.data}"
478+
479+
to_replace = [
480+
(self.auth, "<token>"),
481+
(params.get("token", ""), "<token>"),
482+
(params.get("password", ""), "<password>"),
483+
]
484+
for replace in to_replace:
485+
if replace[0]:
486+
msg = msg.replace(str(replace), replace[1])
487+
488+
# TODO: refactor this exc type narrowing to some sort of predicate/dict lookup
489+
msgc = msg.casefold()
490+
if "api token expired" in msgc:
491+
cls = ZabbixAPITokenExpiredError
492+
logger.debug(
493+
"API token '%s' has expired.",
494+
f"{self.auth[:8]}...", # Redact most of the token
495+
)
496+
elif "re-login" in msgc:
497+
cls = ZabbixAPISessionExpired
498+
elif "not authorized" in msgc:
499+
cls = ZabbixAPINotAuthorizedError
500+
else:
501+
cls = ZabbixAPIRequestError
502+
raise cls(
503+
msg,
504+
api_response=resp,
505+
response=response,
506+
)
507+
481508
def populate_cache(self) -> None:
482509
"""Populates the various caches with data from the Zabbix API."""
483510
# NOTE: Must be manually invoked. Can we do this in a thread?

0 commit comments

Comments
 (0)