Skip to content

Commit 8691ae0

Browse files
authored
Merge pull request #191 from jooola/split_init
chore: rename __init__ to api
2 parents 0f9a0c0 + a73cd71 commit 8691ae0

File tree

4 files changed

+291
-284
lines changed

4 files changed

+291
-284
lines changed

e2e/e2e_test.py renamed to e2e/api_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from pyzabbix import ZabbixAPI
1+
from pyzabbix.api import ZabbixAPI
22

33
from .conftest import ZABBIX_VERSION
44

pyzabbix/__init__.py

Lines changed: 7 additions & 283 deletions
Original file line numberDiff line numberDiff line change
@@ -1,283 +1,7 @@
1-
import logging
2-
from typing import Mapping, Optional, Sequence, Tuple, Union
3-
from warnings import warn
4-
5-
from requests import Session
6-
from requests.exceptions import JSONDecodeError
7-
from semantic_version import Version # type: ignore
8-
9-
logger = logging.getLogger(__name__)
10-
logger.addHandler(logging.NullHandler())
11-
12-
13-
class ZabbixAPIException(Exception):
14-
"""Generic Zabbix API exception
15-
16-
Codes:
17-
-32700: invalid JSON. An error occurred on the server while
18-
parsing the JSON text (typo, wrong quotes, etc.)
19-
-32600: received JSON is not a valid JSON-RPC Request
20-
-32601: requested remote-procedure does not exist
21-
-32602: invalid method parameters
22-
-32603: Internal JSON-RPC error
23-
-32400: System error
24-
-32300: Transport error
25-
-32500: Application error
26-
"""
27-
28-
def __init__(self, *args, **kwargs):
29-
super().__init__(*args)
30-
31-
self.error = kwargs.get("error", None)
32-
33-
34-
# pylint: disable=too-many-instance-attributes
35-
class ZabbixAPI:
36-
# pylint: disable=too-many-arguments
37-
def __init__(
38-
self,
39-
server: str = "http://localhost/zabbix",
40-
session: Optional[Session] = None,
41-
use_authenticate: bool = False,
42-
timeout: Optional[Union[float, int, Tuple[int, int]]] = None,
43-
detect_version: bool = True,
44-
):
45-
"""
46-
:param server: Base URI for zabbix web interface (omitting /api_jsonrpc.php)
47-
:param session: optional pre-configured requests.Session instance
48-
:param use_authenticate: Use old (Zabbix 1.8) style authentication
49-
:param timeout: optional connect and read timeout in seconds, default: None
50-
If you're using Requests >= 2.4 you can set it as
51-
tuple: "(connect, read)" which is used to set individual
52-
connect and read timeouts.
53-
:param detect_version: autodetect Zabbix API version
54-
"""
55-
self.session = session or Session()
56-
57-
# Default headers for all requests
58-
self.session.headers.update(
59-
{
60-
"Content-Type": "application/json-rpc",
61-
"User-Agent": "python/pyzabbix",
62-
"Cache-Control": "no-cache",
63-
}
64-
)
65-
66-
self.use_authenticate = use_authenticate
67-
self.use_api_token = False
68-
self.auth = ""
69-
self.id = 0 # pylint: disable=invalid-name
70-
71-
self.timeout = timeout
72-
73-
if not server.endswith("/api_jsonrpc.php"):
74-
server = server.rstrip("/") + "/api_jsonrpc.php"
75-
self.url = server
76-
logger.info(f"JSON-RPC Server Endpoint: {self.url}")
77-
78-
self.version = ""
79-
self._detect_version = detect_version
80-
81-
def __enter__(self) -> "ZabbixAPI":
82-
return self
83-
84-
# pylint: disable=inconsistent-return-statements
85-
def __exit__(self, exception_type, exception_value, traceback):
86-
if isinstance(exception_value, (ZabbixAPIException, type(None))):
87-
if self.is_authenticated and not self.use_api_token:
88-
# Logout the user if they are authenticated using username + password.
89-
self.user.logout()
90-
return True
91-
return None
92-
93-
def login(
94-
self,
95-
user: str = "",
96-
password: str = "",
97-
api_token: Optional[str] = None,
98-
) -> None:
99-
"""Convenience method for calling user.authenticate
100-
and storing the resulting auth token for further commands.
101-
102-
If use_authenticate is set, it uses the older (Zabbix 1.8)
103-
authentication command
104-
105-
:param password: Password used to login into Zabbix
106-
:param user: Username used to login into Zabbix
107-
:param api_token: API Token to authenticate with
108-
"""
109-
110-
if self._detect_version:
111-
self.version = Version(self.api_version())
112-
logger.info(f"Zabbix API version is: {self.version}")
113-
114-
# If the API token is explicitly provided, use this instead.
115-
if api_token is not None:
116-
self.use_api_token = True
117-
self.auth = api_token
118-
return
119-
120-
# If we have an invalid auth token, we are not allowed to send a login
121-
# request. Clear it before trying.
122-
self.auth = ""
123-
if self.use_authenticate:
124-
self.auth = self.user.authenticate(user=user, password=password)
125-
elif self.version and self.version >= Version("5.4.0"):
126-
self.auth = self.user.login(username=user, password=password)
127-
else:
128-
self.auth = self.user.login(user=user, password=password)
129-
130-
def check_authentication(self):
131-
if self.use_api_token:
132-
# We cannot use this call using an API Token
133-
return True
134-
# Convenience method for calling user.checkAuthentication of the current session
135-
return self.user.checkAuthentication(sessionid=self.auth)
136-
137-
@property
138-
def is_authenticated(self) -> bool:
139-
if self.use_api_token:
140-
# We cannot use this call using an API Token
141-
return True
142-
143-
try:
144-
self.user.checkAuthentication(sessionid=self.auth)
145-
except ZabbixAPIException:
146-
return False
147-
return True
148-
149-
def confimport(
150-
self,
151-
confformat: str = "",
152-
source: str = "",
153-
rules: str = "",
154-
) -> dict:
155-
"""Alias for configuration.import because it clashes with
156-
Python's import reserved keyword
157-
:param rules:
158-
:param source:
159-
:param confformat:
160-
"""
161-
warn(
162-
"ZabbixAPI.confimport() has been deprecated, please use "
163-
"ZabbixAPI.configuration['import']() instead",
164-
DeprecationWarning,
165-
2,
166-
)
167-
168-
return self.configuration["import"](
169-
format=confformat,
170-
source=source,
171-
rules=rules,
172-
)
173-
174-
def api_version(self) -> str:
175-
return self.apiinfo.version()
176-
177-
def do_request(
178-
self,
179-
method: str,
180-
params: Optional[Union[Mapping, Sequence]] = None,
181-
) -> dict:
182-
payload = {
183-
"jsonrpc": "2.0",
184-
"method": method,
185-
"params": params or {},
186-
"id": self.id,
187-
}
188-
189-
# We don't have to pass the auth token if asking for
190-
# the apiinfo.version or user.checkAuthentication
191-
if (
192-
self.auth
193-
and method != "apiinfo.version"
194-
and method != "user.checkAuthentication"
195-
):
196-
payload["auth"] = self.auth
197-
198-
logger.debug(f"Sending: {payload}")
199-
resp = self.session.post(self.url, json=payload, timeout=self.timeout)
200-
logger.debug(f"Response Code: {resp.status_code}")
201-
202-
# NOTE: Getting a 412 response code means the headers are not in the
203-
# list of allowed headers.
204-
resp.raise_for_status()
205-
206-
if not resp.text:
207-
raise ZabbixAPIException("Received empty response")
208-
209-
try:
210-
response = resp.json()
211-
except JSONDecodeError as exception:
212-
raise ZabbixAPIException(
213-
f"Unable to parse json: {resp.text}"
214-
) from exception
215-
216-
logger.debug(f"Response Body: {response}")
217-
218-
self.id += 1
219-
220-
if "error" in response: # some exception
221-
error = response["error"]
222-
223-
# some errors don't contain 'data': workaround for ZBX-9340
224-
if "data" not in error:
225-
error["data"] = "No data"
226-
227-
raise ZabbixAPIException(
228-
f"Error {error['code']}: {error['message']}, {error['data']}",
229-
error["code"],
230-
error=error,
231-
)
232-
233-
return response
234-
235-
def _object(self, attr: str) -> "ZabbixAPIObject":
236-
"""Dynamically create an object class (ie: host)"""
237-
return ZabbixAPIObject(attr, self)
238-
239-
def __getattr__(self, attr: str) -> "ZabbixAPIObject":
240-
return self._object(attr)
241-
242-
def __getitem__(self, attr: str) -> "ZabbixAPIObject":
243-
return self._object(attr)
244-
245-
246-
# pylint: disable=too-few-public-methods
247-
class ZabbixAPIMethod:
248-
def __init__(self, method: str, parent: ZabbixAPI):
249-
self._method = method
250-
self._parent = parent
251-
252-
def __call__(self, *args, **kwargs):
253-
if args and kwargs:
254-
raise TypeError("Found both args and kwargs")
255-
256-
return self._parent.do_request(self._method, args or kwargs)["result"]
257-
258-
259-
# pylint: disable=too-few-public-methods
260-
class ZabbixAPIObject:
261-
def __init__(self, name: str, parent: ZabbixAPI):
262-
self._name = name
263-
self._parent = parent
264-
265-
def _method(self, attr: str) -> ZabbixAPIMethod:
266-
"""Dynamically create a method (ie: get)"""
267-
return ZabbixAPIMethod(f"{self._name}.{attr}", self._parent)
268-
269-
def __getattr__(self, attr: str) -> ZabbixAPIMethod:
270-
return self._method(attr)
271-
272-
def __getitem__(self, attr: str) -> ZabbixAPIMethod:
273-
return self._method(attr)
274-
275-
276-
class ZabbixAPIObjectClass(ZabbixAPIObject):
277-
def __init__(self, *args, **kwargs):
278-
warn(
279-
"ZabbixAPIObjectClass has been renamed to ZabbixAPIObject",
280-
DeprecationWarning,
281-
2,
282-
)
283-
super().__init__(*args, **kwargs)
1+
from .api import (
2+
ZabbixAPI,
3+
ZabbixAPIException,
4+
ZabbixAPIMethod,
5+
ZabbixAPIObject,
6+
ZabbixAPIObjectClass,
7+
)

0 commit comments

Comments
 (0)