Mini Shell
"""Base class for whmapi/uapi objects"""
from typing import Union
import urllib.parse
import os
import json
from subprocess import run, CalledProcessError, TimeoutExpired
from ._errors import CpAPIExecFail
class CpAPIBase:
"""Base class for whmapi/uapi objects"""
def __init__(self, path: str):
self.path = path
__module__ = 'cpapis'
@staticmethod
def _can_exec(path: str):
"""Tests if the current user can exec a script at ``path``"""
return os.path.isfile(path) and os.access(path, os.X_OK)
def _exec(
self,
*,
module_args: list[str],
user: Union[str, None] = None,
args: Union[dict, None] = None,
timeout: Union[float, None] = None,
) -> dict:
"""uapi/cpapi2/whmapi1 run in similar ways; this executes them
Raises:
CpAPIExecFail: command failed to execute or returned invalid json"""
cmd = [self.path, '--output=json']
if user:
cmd.append(f'--user={user}')
cmd.extend(module_args)
if args:
cmd.extend(self._quote_key_vals(args))
try:
ret = run(
cmd,
capture_output=True,
encoding='utf-8',
timeout=timeout,
check=True,
)
except (TimeoutExpired, CalledProcessError) as exc:
raise CpAPIExecFail(
msg=f"{type(exc).__name__}: {str(exc)}",
cmd=cmd,
stdout=exc.stdout,
stderr=exc.stderr,
returncode=exc.returncode,
) from exc
except OSError as exc:
raise CpAPIExecFail(
msg=f"{type(exc).__name__}: {str(exc)}",
cmd=cmd,
stdout='',
stderr=str(exc),
returncode=127,
) from exc
try:
return json.loads(ret.stdout)
except ValueError as exc:
raise CpAPIExecFail(
msg=f'Invalid JSON returned from {cmd}',
cmd=cmd,
stdout=ret.stdout,
stderr=ret.stderr,
returncode=ret.returncode,
) from exc
@staticmethod
def _quote_key_vals(args: dict):
"""cPanel APIs accessed via CLI send key-values in a special
URI escaped format."""
quoted = []
for key, val in args.items():
val = str(val)
if val.startswith('@'):
# values starting with @ are files and are not uri escaped
quoted.append(f"{urllib.parse.quote(key)}={val}")
else:
quoted.append(
f"{urllib.parse.quote(key)}={urllib.parse.quote(val)}"
)
return quoted
Zerion Mini Shell 1.0