summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIB.md10
-rw-r--r--docs/source/conf.py6
-rw-r--r--poetry.lock32
-rw-r--r--pyproject.toml12
-rw-r--r--pyvyos/device.py94
-rw-r--r--requirements.txt3
-rw-r--r--vagrant/.env.example13
-rw-r--r--vagrant/VAGRANT.md35
-rw-r--r--vagrant/Vagrantfile50
9 files changed, 161 insertions, 94 deletions
diff --git a/CONTRIB.md b/CONTRIB.md
index 28e3685..fda65c5 100644
--- a/CONTRIB.md
+++ b/CONTRIB.md
@@ -1,6 +1,6 @@
-# Contributing to PyVyOS
+# Contributing to pyvyos
-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.
+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 PyVyOS:
+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 PyVyOS:
## License
-By contributing to PyVyOS, 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 PyVyOS. Your efforts are what make this project great!
+Thank you for considering contributing to pyvyos. Your efforts are what make this project great!
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 8e9f3c2..4b3b786 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -6,10 +6,10 @@
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
-project = 'PyVyOS'
-copyright = '2023, Roberto Berto'
+project = 'pyvyos'
+copyright = '2024, Roberto Berto'
author = 'Roberto Berto'
-release = '0.2.0'
+release = '0.2.1'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
diff --git a/poetry.lock b/poetry.lock
index 7f20ce3..ab3c950 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,14 +1,14 @@
-# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
[[package]]
name = "certifi"
-version = "2023.11.17"
+version = "2024.2.2"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
files = [
- {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"},
- {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"},
+ {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"},
+ {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"},
]
[[package]]
@@ -112,24 +112,24 @@ files = [
[[package]]
name = "idna"
-version = "3.4"
+version = "3.6"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.5"
files = [
- {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
- {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
+ {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"},
+ {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
]
[[package]]
name = "python-dotenv"
-version = "1.0.0"
+version = "1.0.1"
description = "Read key-value pairs from a .env file and set them as environment variables"
optional = false
python-versions = ">=3.8"
files = [
- {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"},
- {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"},
+ {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
+ {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
]
[package.extras]
@@ -158,22 +158,22 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "urllib3"
-version = "2.0.7"
+version = "2.2.1"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"},
- {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"},
+ {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"},
+ {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"},
]
[package.extras]
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
-secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"]
+h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.8"
-content-hash = "ef09cfdf5c9430601a5f2044d458baa6184b53a705a76f9ef1c4bd7c00a598bb"
+content-hash = "f223c5fdd1d6f40fab9f9dc2320a2ee4aab1f2a82eea8a9b020e63621a887845"
diff --git a/pyproject.toml b/pyproject.toml
index 11613a0..e90621b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "pyvyos"
-version = "0.2.0"
+version = "0.2.1"
authors = [
{ name="Roberto Berto", email="463349+robertoberto@users.noreply.github.com" },
]
@@ -18,13 +18,13 @@ classifiers = [
]
[project.urls]
-Homepage = "https://github.com/gravscale/pyvyos"
-Issues = "https://github.com/gravscale/pyvyos/issues"
+Homepage = "https://github.com/robertoberto/pyvyos"
+Issues = "https://github.com/robertoberto/pyvyos/issues"
[tool.hatch.metadata]
dependencies = [
"requests>=2.31.0,<3.0",
- "python-dotenv>=1.0.0,<2.0"
+ "python-dotenv>=1.0.1,<2.0"
]
dev-dependencies = [
"pytest>=6.2.2,<7.0"
@@ -34,10 +34,10 @@ dev-dependencies = [
name = "pyvyos"
description = "Python SDK for interacting with VyOS API"
authors = ["Roberto Berto <463349+robertoberto@users.noreply.github.com>"]
-version = "0.2.0"
+version = "0.2.1"
[tool.poetry.dependencies]
python = ">=3.8"
requests = "^2.31.0"
-python-dotenv = "^1.0.0"
+python-dotenv = "^1.0.1"
diff --git a/pyvyos/device.py b/pyvyos/device.py
index 6d8a1dc..d168b65 100644
--- a/pyvyos/device.py
+++ b/pyvyos/device.py
@@ -52,8 +52,8 @@ class VyDevice:
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
- allows for setting both individual and multiple configurations in a single operation.
+ 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.
config_file_load(file=None): Load the configuration from a file.
@@ -98,7 +98,8 @@ class VyDevice:
Args:
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).
+ 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).
@@ -106,64 +107,42 @@ class VyDevice:
Returns:
dict: The payload for the API request.
"""
- if not path:
- data = {
- 'op': op,
- 'path': path
- }
-
- if file is not None:
+ # Adjusting the data structure based on whether path is single or multiple
+ if 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}
+
+ # 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 is not None:
+ if url:
+ if isinstance(data, list):
+ for d in data:
+ d['url'] = url
+ else:
data['url'] = url
- if name is not None:
+ 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
-
- elif isinstance(path, list) and len(path) == 1:
- # If path is a list and contains only one element, use it directly
- data = {'op': op, 'path': path[0]}
- else:
- data = []
- current_command = {'op': op, 'path': []}
- for p in path:
- if isinstance(p, list):
- # If the current item is a list, merge it into the current command
- if current_command['path']:
- data.append(current_command)
- current_command = {'op': op, 'path': p}
- else:
- # Otherwise, add the item to the current command's path
- current_command['path'].append(p)
-
- # Add the last command to data
- if current_command['path']:
- data.append(current_command)
-
payload = {
'data': json.dumps(data),
'key': self.apikey
}
- if file is not None:
- data['file'] = file
-
- if url is not None:
- payload['url'] = url
-
- if name is not None:
- data['name'] = name
-
return payload
+
def _api_request(self, command, op, path=[], method='POST', file=None, url=None, name=None):
"""
Make an API request.
@@ -308,24 +287,13 @@ class VyDevice:
"""
Set configuration based on the given path.
- This method accepts both a single configuration path as a list and a list of configuration paths for setting multiple configurations in one go.
-
Args:
- path (list): The path elements for configuration setting. This can be a list for a single configuration,
- or a list of lists for multiple configurations.
+ path (list, optional): The path elements for configuration setting (default is an empty list).
Returns:
- ApiResponse or list of ApiResponse: Returns a single ApiResponse object for a single configuration, or a list of ApiResponse objects for multiple configurations.
- """
- # Check if the first element of the path is a list, indicating multiple configurations
- if path and isinstance(path[0], list):
- # Process each configuration path separately
- responses = [self._api_request("configure", "set", [p], "POST") for p in path]
- # Return a list of ApiResponse objects for multiple configurations
- return responses
- else:
- # Handle a single configuration path
- return self._api_request("configure", "set", path, "POST")
+ ApiResponse: An ApiResponse object representing the API response.
+ """
+ return self._api_request(command="configure", op='set', path=path, method="POST")
def configure_delete(self, path=[]):
diff --git a/requirements.txt b/requirements.txt
index 523e2c2..56dc8de 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
requests>=2.25.1,<3.0
-python-dotenv>=1.0.0,<2.0
+python-dotenv>=1.0.1,<2.0
+poetry>=1.1.0,<2.0 \ No newline at end of file
diff --git a/vagrant/.env.example b/vagrant/.env.example
new file mode 100644
index 0000000..36bebf8
--- /dev/null
+++ b/vagrant/.env.example
@@ -0,0 +1,13 @@
+
+# vyos https api key
+VYDEVICE_APIKEY=your_api_key
+
+# vyos network interface
+VYDEVICE_IP=192.168.56.10
+VYDEVICE_NETMASK=255.255.255.0
+
+# HOST_IP is the ip address of the host machine of the virtualbox
+# use your windows network interface for virtualbox running on windows host and using wsl2 for vagrant
+HOST_IP=192.168.0.114
+# or use 127.0.0.1, virtualbox running on linux host or windows host
+# HOST_IP=127.0.0.1 \ No newline at end of file
diff --git a/vagrant/VAGRANT.md b/vagrant/VAGRANT.md
new file mode 100644
index 0000000..fab5e59
--- /dev/null
+++ b/vagrant/VAGRANT.md
@@ -0,0 +1,35 @@
+# Vagrant only for development and tests
+
+Vagrant is a tool for building and managing virtual machine environments
+in pyvyos we use vagrant to deploy vyos virtual machines
+for development and automated tests
+
+If you want to only use pyvyos you dont need to install vagrant
+
+# Vagrant install instructions
+
+1. Install Vagrant
+2. Install VirtualBox
+3. Install Vagrant plugin for vyos
+```
+vagrant plugin install vagrant-vyos
+```
+4. Install mkisofs
+```
+sudo apt install genisoimage
+```
+
+5. Run vagrant up
+```
+vagrant up
+```
+6. Run vagrant ssh
+```
+vagrant ssh
+```
+
+# For Windows with wsl2:
+```
+export VAGRANT_WSL_ENABLE_WINDOWS_ACCESS="1"
+export PATH="$PATH:/mnt/c/Program Files/Oracle/VirtualBox"
+``` \ No newline at end of file
diff --git a/vagrant/Vagrantfile b/vagrant/Vagrantfile
new file mode 100644
index 0000000..89edbf3
--- /dev/null
+++ b/vagrant/Vagrantfile
@@ -0,0 +1,50 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# Documentation:
+# - read VAGRANT.md
+# - need vagrant plugin install vagrant-vyos
+
+Vagrant.configure("2") do |config|
+ # enable the environment variables
+ # need vagrant plugin install vagrant-dotenv
+ config.env.enable
+
+ # vm to deploy tests
+ config.vm.define "pyvyos" do |pyvyos|
+ pyvyos.vm.box = "vyos/current"
+ pyvyos.vm.hostname = "pyvyos"
+
+ # network configuration of eth1
+ pyvyos.vm.network "private_network", ip: ENV['VYDEVICE_IP'], netmask: ENV['VYDEVICE_NETMASK']
+ pyvyos.ssh.host = ENV['HOST_IP']
+
+ # nat port forwarding
+ pyvyos.vm.network "forwarded_port", guest: 443, host: 8433, id: "https", auto_correct: true, protocol: "tcp", host_ip: ENV['HOST_IP']
+ pyvyos.vm.network "forwarded_port", guest: 22, host: 2022, id: "ssh", auto_correct: true, protocol: "tcp", host_ip: ENV['HOST_IP']
+
+ # ssh configuration default username and password of vyos/current is vyos / vyos
+ # if you want to change the default password, you can change in provision script
+ # also, you can disable ssh password in provision script and use only ssh key
+ pyvyos.ssh.username = "vyos"
+ pyvyos.ssh.password = "vyos"
+
+ # vagrant will insert the ssh key in the vm automatically, so password authentication after
+ # first boot is not necessary
+ pyvyos.ssh.insert_key = true
+
+ # shell script to provision the vyos vm
+ pyvyos.vm.provision "shell", inline: <<-SHELL
+ #!/bin/vbash
+ source /opt/vyatta/etc/functions/script-template
+ configure
+ set service https listen-address '#{ENV['VYDEVICE_IP']}'
+ set service https api keys id 'apikey' key '#{ENV['VYDEVICE_APIKEY']}'
+ set service https api debug
+ set service https api strict
+ commit
+ save
+ exit
+ SHELL
+ end
+ end