summaryrefslogtreecommitdiff
path: root/pyvyos/device.py
diff options
context:
space:
mode:
authoreduardormorais <eduardoromorais@gmail.com>2025-08-28 18:01:24 -0300
committereduardormorais <eduardoromorais@gmail.com>2025-08-28 18:01:24 -0300
commit7b147d6964e6390a93b069c6cc2a06bdc2c7651f (patch)
treedf4cf9c9570378635578cd161bfb304e1ad1da89 /pyvyos/device.py
parente770412a93d2bbbc95bbb5a5edcdbb23036fd7dd (diff)
downloadpyvyos-7b147d6964e6390a93b069c6cc2a06bdc2c7651f.tar.gz
pyvyos-7b147d6964e6390a93b069c6cc2a06bdc2c7651f.zip
Feature - Separation of API communication logic into a separate class. Code adjustments and improvements.
Diffstat (limited to 'pyvyos/device.py')
-rw-r--r--pyvyos/device.py241
1 files changed, 65 insertions, 176 deletions
diff --git a/pyvyos/device.py b/pyvyos/device.py
index 6579587..6f177d4 100644
--- a/pyvyos/device.py
+++ b/pyvyos/device.py
@@ -1,26 +1,9 @@
-import urllib3
-import requests
-import json
-import pprint
-from dataclasses import dataclass
-
-@dataclass
-class ApiResponse:
- """
- Represents an API response.
+from typing import List
- Attributes:
- status (int): The HTTP status code of the response.
- request (dict): The request payload sent to the API.
- result (dict): The data result of the API response.
- error (str): Any error message in case of a failed response.
- """
- status: int
- request: dict
- result: dict
- error: str
+from .rest import ApiResponse, RestClient
-class VyDevice:
+
+class VyDevice(RestClient):
"""
Represents a device for interacting with the VyOS API.
@@ -51,8 +34,8 @@ class VyDevice:
image_delete(name, url=None, file=None, path=[]): Delete a specific image.
show(path=[]): Show configuration information.
generate(path=[]): Generate configuration based on specified path.
- configure_set(path=[]): Sets configuration based on the specified path. This method is versatile, accepting
- either a single configuration path or a list of configuration paths. This flexibility
+ configure_set(path=[]): Sets configuration based on the specified path. This method is versatile, accepting
+ either a single configuration path or a list of configuration paths. This flexibility
allows for setting both individual and multiple configurations in a single operation.
configure_delete(path=[]): Delete configuration based on specified path.
config_file_save(file=None): Save the configuration to a file.
@@ -61,136 +44,18 @@ class VyDevice:
poweroff(path=["now"]): Power off the device.
"""
- def __init__(self, hostname, apikey, protocol='https', port=443, verify=True, timeout=10):
- """
- Initializes a VyDevice instance.
-
- Args:
- hostname (str): The hostname or IP address of the VyOS device.
- apikey (str): The API key for authentication.
- protocol (str, optional): The protocol to use (default is 'https').
- port (int, optional): The port to use (default is 443).
- verify (bool, optional): Whether to verify SSL certificates (default is True).
- timeout (int, optional): The request timeout in seconds (default is 10).
- """
- self.hostname = hostname
- self.apikey = apikey
- self.protocol = protocol
- self.port = port
- self.verify = verify
- self.timeout = timeout
-
- def _get_url(self, command):
- """
- Get the full URL for a specific API command.
-
- Args:
- command (str): The API command to construct the URL for.
-
- Returns:
- str: The full URL for the API command.
- """
- return f"{self.protocol}://{self.hostname}:{self.port}/{command}"
-
- def _get_payload(self, op, path=[], file=None, url=None, name=None):
- """
- Generate the payload for an API request.
-
- Args:
- op (str): The operation to perform in the API request.
- path (list, optional): The path elements for the API request. This can be a single list for a single
- configuration path or a list of lists for multiple configuration paths.
- file (str, optional): The file to include in the request (default is None).
- url (str, optional): The URL to include in the request (default is None).
- name (str, optional): The name to include in the request (default is None).
+ def __init__(
+ self,
+ hostname: str,
+ apikey: str,
+ protocol: str = "https",
+ port: int = 443,
+ verify: bool = True,
+ timeout: int = 10,
+ ):
+ super().__init__(hostname, apikey, protocol, port, verify, timeout)
- Returns:
- dict: The payload for the API request.
- """
- # Adding option to pass multiple operation (eg:delete and set) commands
- if op:
- # Adjusting the data structure based on whether path is single or multiple
- if path and isinstance(path, list) and isinstance(path[0], list): # Handling multiple paths
- data = [{'op': op, 'path': p} for p in path]
- else: # Handling a single path
- data = {'op': op, 'path': path}
- else:
- if path and isinstance(path[0], dict):
- data = path
-
- # Including the optional parameters if provided
- if file:
- if isinstance(data, list): # If data is a list of dicts (multiple paths)
- for d in data:
- d['file'] = file
- else: # If data is a single dict (single path)
- data['file'] = file
-
- if url:
- if isinstance(data, list):
- for d in data:
- d['url'] = url
- else:
- data['url'] = url
-
- if name:
- if isinstance(data, list):
- for d in data:
- d['name'] = name
- else:
- data['name'] = name
-
- payload = {
- 'data': json.dumps(data),
- 'key': self.apikey
- }
-
- return payload
-
- def _api_request(self, command, op, path=[], method='POST', file=None, url=None, name=None):
- """
- Make an API request.
-
- Args:
- command (str): The API command to execute.
- op (str): The operation to perform in the API request.
- path (list, optional): The path elements for the API request (default is an empty list).
- method (str, optional): The HTTP method to use for the request (default is 'POST').
- file (str, optional): The file to include in the request (default is None).
- url (str, optional): The URL to include in the request (default is None).
- name (str, optional): The name to include in the request (default is None).
-
- Returns:
- ApiResponse: An ApiResponse object representing the API response.
- """
- url = self._get_url(command)
- payload = self._get_payload(op, path=path, file=file, url=url, name=name)
-
- headers = {}
- error = False
- result = {}
-
- try:
- resp = requests.post(url, verify=self.verify, data=payload, timeout=self.timeout, headers=headers)
- resp_decoded = resp.json()
-
- if resp_decoded['success']:
- result = resp_decoded['data']
- error = False
- else:
- error = resp_decoded['error']
-
- status = resp.status_code
-
- except (requests.exceptions.ConnectionError, json.JSONDecodeError) as e:
- error = 'Error: ' + str(e)
- status = 0
-
- # Removing apikey from payload for security reasons
- del(payload['key'])
- return ApiResponse(status=status, request=payload, result=result, error=error)
-
- def retrieve_show_config(self, path=[]):
+ def retrieve_show_config(self, path: List = None):
"""
Retrieve and show the device configuration.
@@ -200,9 +65,12 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="retrieve", op='showConfig', path=path, method="POST")
- def retrieve_return_values(self, path=[]):
+ return self._api_request(
+ command="retrieve", op="showConfig", path=path, method="POST"
+ )
+
+ def retrieve_return_values(self, path: List = None):
"""
Retrieve and return specific configuration values.
@@ -212,9 +80,11 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="retrieve", op='returnValues', path=path, method="POST")
+ return self._api_request(
+ command="retrieve", op="returnValues", path=path, method="POST"
+ )
- def reset(self, path=[]):
+ def reset(self, path: List = None):
"""
Reset a specific configuration element.
@@ -224,7 +94,7 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="reset", op='reset', path=path, method="POST")
+ return self._api_request(command="reset", op="reset", path=path, method="POST")
def image_add(self, url=None, file=None, path=[]):
"""
@@ -238,7 +108,7 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="image", op='add', url=url, method="POST")
+ return self._api_request(command="image", op="add", url=url, method="POST")
def image_delete(self, name, url=None, file=None, path=[]):
"""
@@ -253,9 +123,9 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="image", op='delete', name=name, method="POST")
+ return self._api_request(command="image", op="delete", name=name, method="POST")
- def show(self, path=[]):
+ def show(self, path: List = None):
"""
Show configuration information.
@@ -265,9 +135,9 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="show", op='show', path=path, method="POST")
+ return self._api_request(command="show", op="show", path=path, method="POST")
- def generate(self, path=[]):
+ def generate(self, path: List = None):
"""
Generate configuration based on the given path.
@@ -277,9 +147,11 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="generate", op='generate', path=path, method="POST")
+ return self._api_request(
+ command="generate", op="generate", path=path, method="POST"
+ )
- def configure_set(self, path=[]):
+ def configure_set(self, path: List = None):
"""
Set configuration based on the given path.
@@ -289,10 +161,11 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="configure", op='set', path=path, method="POST")
+ return self._api_request(
+ command="configure", op="set", path=path, method="POST"
+ )
-
- def configure_delete(self, path=[]):
+ def configure_delete(self, path: List = None):
"""
Delete configuration based on the given path.
@@ -302,9 +175,11 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="configure", op='delete', path=path, method="POST")
+ return self._api_request(
+ command="configure", op="delete", path=path, method="POST"
+ )
- def configure_multiple_op(self, op_path=[]):
+ def configure_multiple_op(self, op_path: List = None):
"""
Set configuration based on the given {operation : path} for multiple operation.
@@ -327,7 +202,9 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="config-file", op='save', file=file, method="POST")
+ return self._api_request(
+ command="config-file", op="save", file=file, method="POST"
+ )
def config_file_load(self, file=None):
"""
@@ -339,9 +216,11 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="config-file", op='load', file=file, method="POST")
+ return self._api_request(
+ command="config-file", op="load", file=file, method="POST"
+ )
- def reboot(self, path=["now"]):
+ def reboot(self, path: List = None):
"""
Reboot the device.
@@ -351,9 +230,14 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="reboot", op='reboot', path=path, method="POST")
-
- def poweroff(self, path=["now"]):
+ if path is None:
+ path = ["now"]
+
+ return self._api_request(
+ command="reboot", op="reboot", path=path, method="POST"
+ )
+
+ def poweroff(self, path: List = None):
"""
Power off the device.
@@ -363,4 +247,9 @@ class VyDevice:
Returns:
ApiResponse: An ApiResponse object representing the API response.
"""
- return self._api_request(command="poweroff", op='poweroff', path=path, method="POST")
+ if path is None:
+ path = ["now"]
+
+ return self._api_request(
+ command="poweroff", op="poweroff", path=path, method="POST"
+ )