diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-10-15 20:30:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-10-15 20:30:44 +0000 |
commit | 4a398db99d88dd17dabc408fb2b58c610792bc1e (patch) | |
tree | e5404d6d19a4d67a9428b3d10f886717b9756352 /asynceapi | |
parent | Adding upstream version 1.0.0. (diff) | |
download | anta-upstream.tar.xz anta-upstream.zip |
Adding upstream version 1.1.0.upstream/1.1.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'asynceapi')
-rw-r--r-- | asynceapi/aio_portcheck.py | 13 | ||||
-rw-r--r-- | asynceapi/config_session.py | 160 | ||||
-rw-r--r-- | asynceapi/device.py | 118 | ||||
-rw-r--r-- | asynceapi/errors.py | 2 |
4 files changed, 184 insertions, 109 deletions
diff --git a/asynceapi/aio_portcheck.py b/asynceapi/aio_portcheck.py index 79f4562..0cab94c 100644 --- a/asynceapi/aio_portcheck.py +++ b/asynceapi/aio_portcheck.py @@ -37,12 +37,17 @@ async def port_check_url(url: URL, timeout: int = 5) -> bool: """ Open the port designated by the URL given the timeout in seconds. - If the port is available then return True; False otherwise. - Parameters ---------- - url: The URL that provides the target system - timeout: Time to await for the port to open in seconds + url + The URL that provides the target system. + timeout + Time to await for the port to open in seconds. + + Returns + ------- + bool + If the port is available then return True; False otherwise. """ port = url.port or socket.getservbyname(url.scheme) diff --git a/asynceapi/config_session.py b/asynceapi/config_session.py index 4054f14..df26d7d 100644 --- a/asynceapi/config_session.py +++ b/asynceapi/config_session.py @@ -52,8 +52,10 @@ class SessionConfig: Parameters ---------- - device: The associated device instance - name: The name of the config session + device + The associated device instance. + name + The name of the config session. """ self._device = device self._cli = device.cli @@ -87,30 +89,35 @@ class SessionConfig: Returns ------- - Dict object of native EOS eAPI response; see `status` method for + dict[str, Any] + Dictionary of native EOS eAPI response; see `status` method for details. Examples -------- - { - "maxSavedSessions": 1, - "maxOpenSessions": 5, - "sessions": { - "jeremy1": { - "instances": {}, - "state": "pending", - "commitUser": "", - "description": "" - }, - "ansible_167510439362": { - "instances": {}, - "state": "completed", - "commitUser": "joe.bob", - "description": "", - "completedTime": 1675104396.4500246 - } - } + Return example: + + ``` + { + "maxSavedSessions": 1, + "maxOpenSessions": 5, + "sessions": { + "jeremy1": { + "instances": {}, + "state": "pending", + "commitUser": "", + "description": "" + }, + "ansible_167510439362": { + "instances": {}, + "state": "completed", + "commitUser": "joe.bob", + "description": "", + "completedTime": 1675104396.4500246 } + } + } + ``` """ return await self._cli("show configuration sessions detail") # type: ignore[return-value] # json outformat returns dict[str, Any] @@ -126,41 +133,47 @@ class SessionConfig: Returns ------- - Dict instance of the session status. If the session does not exist, + dict[str, Any] | None + Dictionary instance of the session status. If the session does not exist, then this method will return None. - The native eAPI results from JSON output, see example: - Examples -------- - all results: - { - "maxSavedSessions": 1, - "maxOpenSessions": 5, - "sessions": { - "jeremy1": { - "instances": {}, - "state": "pending", - "commitUser": "", - "description": "" - }, - "ansible_167510439362": { - "instances": {}, - "state": "completed", - "commitUser": "joe.bob", - "description": "", - "completedTime": 1675104396.4500246 - } + The return is the native eAPI results from JSON output: + + ``` + all results: + { + "maxSavedSessions": 1, + "maxOpenSessions": 5, + "sessions": { + "jeremy1": { + "instances": {}, + "state": "pending", + "commitUser": "", + "description": "" + }, + "ansible_167510439362": { + "instances": {}, + "state": "completed", + "commitUser": "joe.bob", + "description": "", + "completedTime": 1675104396.4500246 } } - - if the session name was 'jeremy1', then this method would return - { - "instances": {}, - "state": "pending", - "commitUser": "", - "description": "" - } + } + ``` + + If the session name was 'jeremy1', then this method would return: + + ``` + { + "instances": {}, + "state": "pending", + "commitUser": "", + "description": "" + } + ``` """ res = await self.status_all() return res["sessions"].get(self.name) @@ -174,15 +187,15 @@ class SessionConfig: Parameters ---------- - content: - The text configuration CLI commands, as a list of strings, that - will be sent to the device. If the parameter is a string, and not - a list, then split the string across linebreaks. In either case - any empty lines will be discarded before they are send to the - device. - replace: - When True, the content will replace the existing configuration - on the device. + content + The text configuration CLI commands, as a list of strings, that + will be sent to the device. If the parameter is a string, and not + a list, then split the string across linebreaks. In either case + any empty lines will be discarded before they are send to the + device. + replace + When True, the content will replace the existing configuration + on the device. """ # if given s string, we need to break it up into individual command # lines. @@ -212,10 +225,13 @@ class SessionConfig: # configure session <name> # commit - If the timer is specified, format is "hh:mm:ss", then a commit timer is - started. A second commit action must be made to confirm the config - session before the timer expires; otherwise the config-session is - automatically aborted. + Parameters + ---------- + timer + If the timer is specified, format is "hh:mm:ss", then a commit timer is + started. A second commit action must be made to confirm the config + session before the timer expires; otherwise the config-session is + automatically aborted. """ command = f"{self._cli_config_session} commit" @@ -242,6 +258,7 @@ class SessionConfig: Returns ------- + str Return a string in diff-patch format. References @@ -258,17 +275,18 @@ class SessionConfig: Parameters ---------- - filename: - The name of the configuration file. The caller is required to - specify the filesystem, for example, the - filename="flash:thisfile.cfg" + filename + The name of the configuration file. The caller is required to + specify the filesystem, for example, the + filename="flash:thisfile.cfg". - replace: - When True, the contents of the file will completely replace the - session config for a load-replace behavior. + replace + When True, the contents of the file will completely replace the + session config for a load-replace behavior. Raises ------ + RuntimeError If there are any issues with loading the configuration file then a RuntimeError is raised with the error messages content. """ @@ -278,7 +296,7 @@ class SessionConfig: commands.append(f"copy {filename} session-config") res: list[dict[str, Any]] = await self._cli(commands=commands) # type: ignore[assignment] # JSON outformat of multiple commands returns list[dict[str, Any]] - checks_re = re.compile(r"error|abort|invalid", flags=re.I) + checks_re = re.compile(r"error|abort|invalid", flags=re.IGNORECASE) messages = res[-1]["messages"] if any(map(checks_re.search, messages)): diff --git a/asynceapi/device.py b/asynceapi/device.py index 04ec3ab..933ae64 100644 --- a/asynceapi/device.py +++ b/asynceapi/device.py @@ -54,7 +54,7 @@ class Device(httpx.AsyncClient): EAPI_OFMT_OPTIONS = ("json", "text") EAPI_DEFAULT_OFMT = "json" - def __init__( # noqa: PLR0913 # pylint: disable=too-many-arguments + def __init__( self, host: str | None = None, username: str | None = None, @@ -71,23 +71,31 @@ class Device(httpx.AsyncClient): Parameters ---------- - host: The EOS target device, either hostname (DNS) or ipaddress. - username: The login user-name; requires the password parameter. - password: The login password; requires the username parameter. - proto: The protocol, http or https, to communicate eAPI with the device. - port: If not provided, the proto value is used to look up the associated + host + The EOS target device, either hostname (DNS) or ipaddress. + username + The login user-name; requires the password parameter. + password + The login password; requires the username parameter. + proto + The protocol, http or https, to communicate eAPI with the device. + port + If not provided, the proto value is used to look up the associated port (http=80, https=443). If provided, overrides the port used to communite with the device. + kwargs + Other named keyword arguments, some of them are being used in the function + cf Other Parameters section below, others are just passed as is to the httpx.AsyncClient. Other Parameters ---------------- - base_url: str - If provided, the complete URL to the device eAPI endpoint. + base_url : str + If provided, the complete URL to the device eAPI endpoint. - auth: - If provided, used as the httpx authorization initializer value. If - not provided, then username+password is assumed by the Caller and - used to create a BasicAuth instance. + auth : + If provided, used as the httpx authorization initializer value. If + not provided, then username+password is assumed by the Caller and + used to create a BasicAuth instance. """ self.port = port or getservbyname(proto) self.host = host @@ -111,11 +119,12 @@ class Device(httpx.AsyncClient): Returns ------- + bool True when the device eAPI is accessible, False otherwise. """ return await port_check_url(self.base_url) - async def cli( # noqa: PLR0913 # pylint: disable=too-many-arguments + async def cli( # noqa: PLR0913 self, command: str | dict[str, Any] | None = None, commands: Sequence[str | dict[str, Any]] | None = None, @@ -132,18 +141,18 @@ class Device(httpx.AsyncClient): Parameters ---------- - command: - A single command to execute; results in a single output response - commands: - A list of commands to execute; results in a list of output responses - ofmt: + command + A single command to execute; results in a single output response. + commands + A list of commands to execute; results in a list of output responses. + ofmt Either 'json' or 'text'; indicates the output format for the CLI commands. - version: + version By default the eAPI will use "version 1" for all API object models. This driver will, by default, always set version to "latest" so that the behavior matches the CLI of the device. The caller can override the "latest" behavior by explicitly setting the version. - suppress_error: + suppress_error When not False, then if the execution of the command would-have raised an EapiCommandError, rather than raising this exception this routine will return the value None. @@ -152,13 +161,13 @@ class Device(httpx.AsyncClient): EapiCommandError, now response would be set to None instead. response = dev.cli(..., suppress_error=True) - auto_complete: + auto_complete Enabled/disables the command auto-compelete feature of the EAPI. Per the documentation: Allows users to use shorthand commands in eAPI calls. With this parameter included a user can send 'sh ver' via eAPI to get the output of 'show version'. - expand_aliases: + expand_aliases Enables/disables the command use of User defined alias. Per the documentation: Allowed users to provide the expandAliases parameter to eAPI @@ -166,11 +175,12 @@ class Device(httpx.AsyncClient): For example if an alias is configured as 'sv' for 'show version' then an API call with sv and the expandAliases parameter will return the output of show version. - req_id: + req_id A unique identifier that will be echoed back by the switch. May be a string or number. Returns ------- + list[dict[str, Any] | str] | dict[str, Any] | str | None One or List of output responses, per the description above. """ if not any((command, commands)): @@ -189,7 +199,7 @@ class Device(httpx.AsyncClient): return None raise - def _jsonrpc_command( # noqa: PLR0913 # pylint: disable=too-many-arguments + def _jsonrpc_command( # noqa: PLR0913 self, commands: Sequence[str | dict[str, Any]] | None = None, ofmt: str | None = None, @@ -199,7 +209,42 @@ class Device(httpx.AsyncClient): expand_aliases: bool = False, req_id: int | str | None = None, ) -> dict[str, Any]: - """Create the JSON-RPC command dictionary object.""" + """Create the JSON-RPC command dictionary object. + + Parameters + ---------- + commands + A list of commands to execute; results in a list of output responses. + ofmt + Either 'json' or 'text'; indicates the output format for the CLI commands. + version + By default the eAPI will use "version 1" for all API object models. + This driver will, by default, always set version to "latest" so + that the behavior matches the CLI of the device. The caller can + override the "latest" behavior by explicitly setting the version. + auto_complete + Enabled/disables the command auto-compelete feature of the EAPI. Per the + documentation: + Allows users to use shorthand commands in eAPI calls. With this + parameter included a user can send 'sh ver' via eAPI to get the + output of 'show version'. + expand_aliases + Enables/disables the command use of User defined alias. Per the + documentation: + Allowed users to provide the expandAliases parameter to eAPI + calls. This allows users to use aliased commands via the API. + For example if an alias is configured as 'sv' for 'show version' + then an API call with sv and the expandAliases parameter will + return the output of show version. + req_id + A unique identifier that will be echoed back by the switch. May be a string or number. + + Returns + ------- + dict[str, Any]: + dict containing the JSON payload to run the command. + + """ cmd: dict[str, Any] = { "jsonrpc": "2.0", "method": "runCmds", @@ -224,16 +269,17 @@ class Device(httpx.AsyncClient): Parameters ---------- - jsonrpc: - The JSON-RPC as created by the `meth`:_jsonrpc_command(). + jsonrpc + The JSON-RPC as created by the `meth`:_jsonrpc_command(). Raises ------ - EapiCommandError - In the event that a command resulted in an error response. + EapiCommandError + In the event that a command resulted in an error response. Returns ------- + list[dict[str, Any] | str] The list of command results; either dict or text depending on the JSON-RPC format parameter. """ @@ -271,21 +317,27 @@ class Device(httpx.AsyncClient): len_data = len(cmd_data) err_at = len_data - 1 err_msg = err_data["message"] + failed_cmd = commands[err_at] raise EapiCommandError( passed=[get_output(cmd_data[cmd_i]) for cmd_i, cmd in enumerate(commands[:err_at])], - failed=commands[err_at]["cmd"], + failed=failed_cmd["cmd"] if isinstance(failed_cmd, dict) else failed_cmd, errors=cmd_data[err_at]["errors"], errmsg=err_msg, not_exec=commands[err_at + 1 :], ) def config_session(self, name: str) -> SessionConfig: - """ - return a SessionConfig instance bound to this device with the given session name. + """Return a SessionConfig instance bound to this device with the given session name. Parameters ---------- - name: The config-session name + name + The config-session name. + + Returns + ------- + SessionConfig + SessionConfig instance bound to this device with the given session name. """ return SessionConfig(self, name) diff --git a/asynceapi/errors.py b/asynceapi/errors.py index 614427a..e6794b7 100644 --- a/asynceapi/errors.py +++ b/asynceapi/errors.py @@ -24,7 +24,7 @@ class EapiCommandError(RuntimeError): not_exec: a list of commands that were not executed """ - def __init__(self, failed: str, errors: list[str], errmsg: str, passed: list[str | dict[str, Any]], not_exec: list[dict[str, Any]]) -> None: # noqa: PLR0913 # pylint: disable=too-many-arguments + def __init__(self, failed: str, errors: list[str], errmsg: str, passed: list[str | dict[str, Any]], not_exec: list[dict[str, Any]]) -> None: """Initialize for the EapiCommandError exception.""" self.failed = failed self.errmsg = errmsg |