diff options
author | Roberto Berto <roberto.berto@gmail.com> | 2023-12-13 12:50:45 -0300 |
---|---|---|
committer | Roberto Berto <roberto.berto@gmail.com> | 2023-12-13 12:50:45 -0300 |
commit | 4148924483f14e5ecde296df09e0c2a2fef20787 (patch) | |
tree | f88b368e9d9a40f9daa34b88a7df204d27cde4a4 | |
parent | 1cd622e219ceed9ba669bb373a4e4407a9542215 (diff) | |
download | pyvyos-4148924483f14e5ecde296df09e0c2a2fef20787.tar.gz pyvyos-4148924483f14e5ecde296df09e0c2a2fef20787.zip |
version 0.2.0 with all api and tests
-rw-r--r-- | CONTRIB.md | 10 | ||||
-rw-r--r-- | README.md | 153 | ||||
-rw-r--r-- | example.py | 62 | ||||
-rw-r--r-- | pyproject.toml | 12 | ||||
-rw-r--r-- | pyvyos/__init__.py (renamed from vyapi/__init__.py) | 0 | ||||
-rw-r--r-- | pyvyos/device.py (renamed from vyapi/device.py) | 70 | ||||
-rw-r--r-- | tests/test_vy_device.py | 42 | ||||
-rw-r--r-- | vyapi/utils.py | 0 |
8 files changed, 281 insertions, 68 deletions
@@ -1,6 +1,6 @@ -# Contributing to VyAPI +# Contributing to PyVyOS -We welcome contributions to the VyAPI project! If you're looking to contribute, please take a moment to read this guide to understand how you can be a part of our community and help make VyAPI better. +We welcome contributions to the PyVyOS project! If you're looking to contribute, please take a moment to read this guide to understand how you can be a part of our community and help make PyVyOS better. ## Code of Conduct @@ -8,7 +8,7 @@ We expect all contributors to adhere to our Code of Conduct. Respectful, collabo ## How to Contribute -There are many ways to contribute to VyAPI: +There are many ways to contribute to PyVyOS: - **Submitting bug reports and feature requests:** Use our issue tracker to report bugs or suggest features. - **Writing code:** Feel free to take on open issues or propose new changes. Please follow the guidelines outlined below. @@ -61,7 +61,7 @@ There are many ways to contribute to VyAPI: ## License -By contributing to VyAPI, you agree that your contributions will be licensed under the same license that covers the project. +By contributing to PyVyOS, you agree that your contributions will be licensed under the same license that covers the project. -Thank you for considering contributing to VyAPI. Your efforts are what make this project great! +Thank you for considering contributing to PyVyOS. Your efforts are what make this project great! @@ -1,15 +1,150 @@ -# vyapi -Python SDK for interacting with VyOS API +# PyVyOS Documentation +PyVyOS is a Python library for interacting with VyOS devices via their API. This documentation provides a guide on how to use PyVyOS to manage your VyOS devices programmatically. -## .env for example.py -run example.py after you create and .env +## Installation + +You can install PyVyOS using pip: + +``` +bash +pip install pyvyos +``` + +## Getting Started + +### Importing and Disabling Warnings for verify=False +Before using PyVyOS, it's a good practice to disable urllib3 warnings and import the required modules, IF you use verify=False: ``` -VYDEVICE_HOSTNAME= -VYDEVICE_KEY= -VYDEVICE_PORT=443 -VYDEVICE_PROTOCOL=https -VYDEVICE_VERIFY_SSL=False +import urllib3 +urllib3.disable_warnings() ``` +### Using API Response Class +PyVyOS uses a custom ApiResponse data class to handle API responses: + +``` +@dataclass +class ApiResponse: + status: int + request: dict + result: dict + error: str +``` + +### Initializing a VyDevice Object +To interact with your VyOS device, you'll need to create an instance of the VyDevice class. You can set up your device using the following code, +assuming you've stored your credentials as environment variables: + +``` +from dotenv import load_dotenv + +# Load environment variables from a .env file +load_dotenv() + +# Retrieve VyOS device connection details from environment variables +hostname = os.getenv('VYDEVICE_HOSTNAME') +apikey = os.getenv('VYDEVICE_APIKEY') +port = os.getenv('VYDEVICE_PORT') +protocol = os.getenv('VYDEVICE_PROTOCOL') +verify_ssl = os.getenv('VYDEVICE_VERIFY_SSL') + +# Convert the verify_ssl value to a boolean +verify = verify_ssl.lower() == "true" if verify_ssl else True + +# Create an instance of the VyOS device +device = VyDevice(hostname=hostname, apikey=apikey, port=port, protocol=protocol, verify=verify) +``` + +## Using PyVyOS +Once you have created a VyDevice object, you can use it to interact with your VyOS device using various methods provided by the library. + + +### Reset +The reset method allows you to run a reset command: + +``` +# Execute the reset command +response = device.reset(path=["conntrack-sync", "internal-cache"]) + +# Check for errors and print the result +if not response.error: + print(response.result) +``` + +### Retrieve Show Configuration +The retrieve_show_config method retrieves the VyOS configuration: + +``` +# Retrieve the VyOS configuration +response = device.retrieve_show_config(path=[]) + +# Check for errors and print the result +if not response.error: + print(response.result) +``` + +### Retrieve Return Values +``` +# Retrieve VyOS return values for a specific interface +response = device.retrieve_return_values(path=["interfaces", "dummy", "dum1", "address"]) +print(response.result) +``` + +### Configure Delete +``` +# Delete a VyOS interface configuration +response = device.configure_delete(path=["interfaces", "dummy", "dum1"]) +``` + +### Generate +``` +# Generate an SSH key with a random string in the name +randstring = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(20)) +keyrand = f'/tmp/key_{randstring}' +response = device.generate(path=["ssh", "client-key", keyrand]) +``` + +### Show +``` +# Show VyOS system image information +response = device.show(path=["system", "image"]) +print(response.result) +``` + +### Reset +``` +# Reset VyOS with specific parameters +response = device.reset(path=["conntrack-sync", "internal-cache"]) +``` + +### Configure Set +The configure_set method sets a VyOS configuration: + +``` +# Set a VyOS configuration +response = device.configure_set(path=["interfaces ethernet eth0 address '192.168.1.1/24'"]) + +# Check for errors and print the result +if not response.error: + print(response.result) +``` + +### Config File Save +``` +# Save VyOS configuration without specifying a file (default location) +response = device.config_file_save() +``` + +### Config File Save with custom filename +``` +# Save VyOS configuration to a specific file +response = device.config_file_save(file="/config/test300.config") +``` + +### Config File Load +``` +# Load VyOS configuration from a specific file +response = device.config_file_load(file="/config/test300.config") +```
\ No newline at end of file @@ -1,34 +1,66 @@ -#import warnings -#warnings.filterwarnings("ignore", category=RuntimeWarning) - +# importing modules +import warnings +warnings.filterwarnings("ignore", category=RuntimeWarning) import sys import os - -# Adicione o diretório raiz do projeto ao sys.path para que possa importar vyapi -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__)))) - +# adding pyvyos to sys.path +#sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__)))) import unittest -from vyapi.device import VyDevice -from vyapi.device import ApiResponse from dotenv import load_dotenv import pprint +import random +import string + +# importing pyvyos modules +from pyvyos.device import VyDevice +from pyvyos.device import ApiResponse -load_dotenv() +# getting env variables +load_dotenv() hostname = os.getenv('VYDEVICE_HOSTNAME') -key = os.getenv('VYDEVICE_KEY') +apikey = os.getenv('VYDEVICE_APIKEY') port = os.getenv('VYDEVICE_PORT') protocol = os.getenv('VYDEVICE_PROTOCOL') verify = os.getenv('VYDEVICE_VERIFY_SSL') if verify == "False": verify = False - else: verify = True +# running example if __name__ == '__main__': - device = VyDevice(hostname=hostname, key=key, port=port, protocol=protocol, verify=verify) - response = device.retrieve_show_config(['system']) - pprint.pprint(response) + # preparing connection to vyos device + device = VyDevice(hostname=hostname, apikey=apikey, port=port, protocol=protocol, verify=verify) + + + + #response = device.retrieve_show_config(['system']) + #pprint.pprint(response) + + #print("### Generating ssh key ###") + #randstring = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(20)) + #keyrand = f'/tmp/key_{randstring}' + #response = device.generate(path=["ssh", "client-key", keyrand]) + #pprint.pprint(response) + + + + #response = device.retrieve_return_values(path=["interfaces", "ethernet", "eth0", "address"]) + #pprint.pprint(response) + + #response = device.reset(path=["conntrack-sync", "internal-cache"]) + #pprint.pprint(response) + + #response = device.reboot(path=["now"]) + #pprint.pprint(response) + + #response = device.shutdown(path=["now"]) + #pprint.pprint(response) + + #response = device.image_add(url="https://github.com/vyos/vyos-rolling-nightly-builds/releases/download/1.5-rolling-202312130023/vyos-1.5-rolling-202312130023-amd64.iso") + #pprint.pprint(response) + response = device.image_delete(name="foo") + pprint.pprint(response) diff --git a/pyproject.toml b/pyproject.toml index ef4c9c8..82ac6cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,8 +3,8 @@ requires = ["hatchling"] build-backend = "hatchling.build" [project] -name = "vyapi" -version = "0.1.1" +name = "pyvyos" +version = "0.2.0" authors = [ { name="Roberto Berto", email="roberto.berto@gmail.com" }, ] @@ -18,8 +18,8 @@ classifiers = [ ] [project.urls] -Homepage = "https://github.com/gravscale/vyapi" -Issues = "https://github.com/gravscale/vyapi/issues" +Homepage = "https://github.com/gravscale/pyvyos" +Issues = "https://github.com/gravscale/pyvyos/issues" [tool.hatch.metadata] dependencies = [ @@ -31,10 +31,10 @@ dev-dependencies = [ ] [tool.poetry] -name = "vyapi" +name = "pyvyos" description = "Python SDK for interacting with VyOS API" authors = ["Roberto Berto <roberto.berto@gmail.com>"] -version = "0.1.1" +version = "0.2.0" [tool.poetry.dependencies] python = ">=3.8" diff --git a/vyapi/__init__.py b/pyvyos/__init__.py index 7c327e5..7c327e5 100644 --- a/vyapi/__init__.py +++ b/pyvyos/__init__.py diff --git a/vyapi/device.py b/pyvyos/device.py index f601f36..1d0933b 100644 --- a/vyapi/device.py +++ b/pyvyos/device.py @@ -26,25 +26,34 @@ class VyDevice: def _get_url(self, command): return f"{self.protocol}://{self.hostname}:{self.port}/{command}" - def _get_payload(self, op, path, file=None): + + def _get_payload(self, op, path=[], file=None, url=None, name=None): + data = { + 'op': op, + 'path': path + } + if file is not None: - return { - 'data': json.dumps({ - 'op': op, - 'file': file, - }), - 'key': self.apikey - } - else: - return { - 'data': json.dumps({'op': op, 'path': path}), - 'key': self.apikey - } - - def _api_request(self, command, op, path=[], method='POST', file=None): + data['file'] = file + + if url is not None: + data['url'] = url + + if name is not None: + data['name'] = name + + payload = { + 'data': json.dumps(data), + 'key': self.apikey + } + + #print(payload) + return payload + + def _api_request(self, command, op, path=[], method='POST', file=None, url=None, name=None): url = self._get_url(command) - payload = self._get_payload(op, path, file) - pprint.pprint(payload) + payload = self._get_payload(op, path=path, file=file, url=url, name=name) + #pprint.pprint(payload) headers = {} error = False @@ -53,6 +62,7 @@ class VyDevice: try: resp = requests.post(url, verify=self.verify, data=payload, timeout=self.timeout, headers=headers) pprint.pprint(resp.text) + if resp.status_code == 200: try: resp_decoded = resp.json() @@ -74,6 +84,8 @@ class VyDevice: error = 'connection 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) @@ -81,22 +93,22 @@ class VyDevice: return self._api_request(command="retrieve", op='showConfig', path=path, method="POST") def retrieve_return_values(self, path=[]): - pass + return self._api_request(command="retrieve", op='returnValues', path=path, method="POST") def reset(self, path=[]): - pass + return self._api_request(command="reset", op='reset', path=path, method="POST") - def image_add(self): - pass + def image_add(self, url=None, file=None, path=[]): + return self._api_request(command="image", op='add', url=url, method="POST") - def image_delete(self): - pass + def image_delete(self, name, url=None, file=None, path=[]): + return self._api_request(command="image", op='delete', name=name, method="POST") def show(self, path=[]): - pass + return self._api_request(command="show", op='show', path=path, method="POST") def generate(self, path=[]): - pass + return self._api_request(command="generate", op='generate', path=path, method="POST") def configure_set(self, path=[]): return self._api_request(command="configure", op='set', path=path, method="POST") @@ -110,5 +122,9 @@ class VyDevice: def config_file_load(self, file=None): return self._api_request(command="config-file", op='load', file=file, method="POST") - -
\ No newline at end of file + def reboot(self, path=["now"]): + return self._api_request(command="reboot", op='reboot', path=path, method="POST") + + def poweroff(self, path=["now"]): + return self._api_request(command="poweroff", op='poweroff', path=path, method="POST") +
\ No newline at end of file diff --git a/tests/test_vy_device.py b/tests/test_vy_device.py index b101c1d..84ff0ed 100644 --- a/tests/test_vy_device.py +++ b/tests/test_vy_device.py @@ -1,11 +1,12 @@ import sys import os import unittest -from vyapi.device import VyDevice -from vyapi.device import ApiResponse +from pyvyos.device import VyDevice +from pyvyos.device import ApiResponse from dotenv import load_dotenv import os import pprint +import random, string load_dotenv() @@ -25,7 +26,7 @@ class TestVyDevice(unittest.TestCase): self.device = VyDevice(hostname=hostname, apikey=apikey, port=port, protocol=protocol, verify=verify) def test_001_retrieve_show_config(self): - response = self.device.retrieve_show_config(['system']) + response = self.device.retrieve_show_config([]) pprint.pprint(response) self.assertEqual(response.status, 200) @@ -40,8 +41,14 @@ class TestVyDevice(unittest.TestCase): self.assertIsNone(response.result) self.assertFalse(response.error) + def test_011_retrieve_return_values(self): + response = self.device.retrieve_return_values(path=["interfaces", "dummy", "dum1", "address"]) + self.assertEqual(response.status, 200) + self.assertIsNotNone(response.result) + self.assertFalse(response.error) + self.assertEqual(response.result, ['192.168.140.1/24']) - def test_011_configure_delete_interface(self): + def test_020_configure_delete_interface(self): response = self.device.configure_delete(path=["interfaces", "dummy", "dum1"]) pprint.pprint(response) @@ -49,6 +56,31 @@ class TestVyDevice(unittest.TestCase): self.assertIsNone(response.result) self.assertFalse(response.error) + def test_050_generate(self): + randstring = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(20)) + keyrand = f'/tmp/key_{randstring}' + response = self.device.generate(path=["ssh", "client-key", keyrand]) + pprint.pprint(response) + + self.assertEqual(response.status, 200) + self.assertIsNotNone(response.result) + self.assertFalse(response.error) + + def test_100_show(self): + response = self.device.show(path=["system", "image"]) + pprint.pprint(response) + + self.assertEqual(response.status, 200) + self.assertIsNotNone(response.result) + self.assertFalse(response.error) + + def test_200_reset(self): + response = self.device.reset(path=["conntrack-sync", "internal-cache"]) + pprint.pprint(response) + + self.assertEqual(response.status, 200) + self.assertIsNotNone(response.result) + self.assertFalse(response.error) def test_300_config_file_save(self): response = self.device.config_file_save(file="/config/test300.config") @@ -76,8 +108,6 @@ class TestVyDevice(unittest.TestCase): self.assertFalse(response.error) - - def tearDown(self): pass diff --git a/vyapi/utils.py b/vyapi/utils.py deleted file mode 100644 index e69de29..0000000 --- a/vyapi/utils.py +++ /dev/null |