PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/extras-3.10/pp_api/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/extras-3.10/pp_api/__init__.py |
"""The PowerPanel Python API""" import enum from typing import Union import json import platform import requests __all__ = ["PowerPanel", "PowerPanelResponse"] class _PowerPanelAuth(requests.auth.AuthBase): """Attaches an Authorization header to a PowerPanel request""" def __init__(self, key_file_path: str): """Initializes the Auth generator with the key file""" self.key_file_path = key_file_path def _get_api_key(self) -> str: """Reads the pp API key and returns the raw key data. Raises IOError if the key file does not exist or cannot be read. """ with open(self.key_file_path, encoding='ascii') as key_data: return "".join(key_data.read().strip().split()) def __call__(self, r): """Modifies request adding the auth header""" r.headers['Authorization'] = f'{platform.node()}:{self._get_api_key()}' return r class PowerPanelResponse: """The response object from a PowerPanel call Attributes: status (int | Status): The HTTP status code returned by the API, or ``-1`` if no response was acquired. Will be a Status object if PowerPanel was initialized with enum_status=True message (str): The message from the PowerPanel API, or "ERROR: [message]" if status is ``-1``. data (dict): any data from the API raw_response (requests.Response): The requests object returned after querying the API, or ``None`` if status is ``-1`` """ def _generate_error(self, message, request_object=None): """Sets self properties to handle error with [message]""" self.status = -1 self.message = f"ERROR: {message}" self.data = {} self.raw_response = request_object def _status_to_enum(self): try: self.status = Status(self.status) except ValueError: self.status = Status.UNKNOWN_STATUS def __init__( self, request_object: Union[requests.Response, requests.RequestException], enum_status: bool, ): """Parses a requests object containing the power panel API response and populates this object's properties. """ if isinstance(request_object, requests.RequestException): self._generate_error( f"Could not get response from PowerPanel: {request_object}" ) if enum_status: self._status_to_enum() return try: json_response = request_object.json() except ValueError: self._generate_error( "Could not parse response from PowerPanel", request_object ) if enum_status: self._status_to_enum() return try: self.status = json_response['status'] self.message = json_response['message'] self.data = json_response['data'] self.raw_response = request_object except KeyError: self._generate_error( "Could not parse response from PowerPanel", request_object ) if enum_status: self._status_to_enum() class PowerPanel: """A Pythonic interface to the PowerPanel API. Normally, one would use only the "call" method Args: key_file_path (str): path to file containing the PowerPanel API key base_url (str): URL to PowerPanel. Change this only for testing References: https://trac.imhtech.net/Development/wiki/InMotion/Projects/PowerPanelAPI/CommandReference Note: Calling this object directly will redirect to self.call() """ def __init__( self, key_file_path: str = '/etc/pp_api.key', base_url: str = 'https://secure1.inmotionhosting.com/api', enum_status: bool = False, ): self.auth = _PowerPanelAuth(key_file_path) self.pp_api_base_url = base_url self.enum_status = enum_status def call( self, api_name: str, timeout=30, **argument_dict ) -> PowerPanelResponse: """Makes a call to the powerpanel API Args: api_name: dot or slash separated name of the PowerPanel command. The following would be equivalent: - reporting.provisioning - reporting/provisioning argument_dict: any other arguments to pass to the API as data """ api_name = api_name.replace('.', '/') headers = {'Content-Type': 'application/json'} try: obj = requests.post( f"{self.pp_api_base_url}/{api_name}", data=json.dumps(argument_dict), timeout=timeout, headers=headers, auth=self.auth, ) except requests.RequestException as exc: obj = exc return PowerPanelResponse(obj, self.enum_status) def __call__(self, api_name: str, **argument_dict) -> PowerPanelResponse: """Wraps the call function, making an instance of this class directly callable""" return self.call(api_name, **argument_dict) class Status(enum.Enum): """PowerPanel API Status Codes""" # No response from PowerPanel - added by pp_api.PowerPanelResponse() NO_RESPONSE = -1 # PowerPanel gave a status code not listed in their documentation - added # by pp_api.PowerPanelResponse() UNKNOWN_STATUS = -2 # All operations performed without errors STATUS_OK = 0 # The agent that made the request is not authorized for the given request. # Typically, this indicates improper Authorization header content. NOT_AUTHORIZED = 200 # A required named parameter for the requested API function was not provided # in the request MISSING_PARAMETER = 305 # A named parameter value does not have the expected data format INVALID_INPUT = 307 # A client requested an invalid or undefined API command name INVALID_COMMAND = 308 # The request body text is not a proper JSON-encoded parameter set. REQUEST_FORMAT_ERROR = 310 # A generic error indiciating a model created/updated by the command # resulted did not pass validation VALIDATION_FAILURE = 311 # A generic error indicating a specified resource in the power panel system # could not be identified from the given parameters UNKNOWN_RESOURCE = 312 # A generic error indicating a request cannot be processed due to an # inappropriate state in the data objects targetted by the request. DATA_STATE_ERROR = 400 # An administrative request tried to register a client server name that has # already been registered with power panel without specifying an overwrite # flag SERVER_ALREADY_REGISTERED = 410 # An uncaught exception came up during the processing of an API request. INTERNAL_SERVER_ERROR = 500 # Error signifying that a particular command has not been implemented yet. # This is mainly for use in development. NOT_IMPLEMENTED = 501