From 065ec5963189da3a7cf5e7c93f154033a1ba9fff Mon Sep 17 00:00:00 2001 From: mihail Date: Tue, 19 Jun 2018 14:18:32 +0300 Subject: [PATCH 01/16] error message is in resp.reason which was not part of the exception message (try to delete a missing pool, the message is not in the body) --- proxmoxer/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxmoxer/core.py b/proxmoxer/core.py index 43c3a06..710dffa 100644 --- a/proxmoxer/core.py +++ b/proxmoxer/core.py @@ -75,8 +75,8 @@ def _request(self, method, data=None, params=None): logger.debug('Status code: %s, output: %s', resp.status_code, resp.content) if resp.status_code >= 400: - raise ResourceException("{0} {1}: {2}".format(resp.status_code, httplib.responses[resp.status_code], - resp.content)) + raise ResourceException("{0} {1}: {2}, Content:{3}".format(resp.status_code, httplib.responses[resp.status_code], + resp.reason, resp.content)) elif 200 <= resp.status_code <= 299: return self._store["serializer"].loads(resp) From fb4809171e9826a0edf9bd101ea2700b98e5210a Mon Sep 17 00:00:00 2001 From: mihail Date: Tue, 19 Jun 2018 15:00:40 +0300 Subject: [PATCH 02/16] no resp.reason when using ssh, reason = stderr --- proxmoxer/backends/base_ssh.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/proxmoxer/backends/base_ssh.py b/proxmoxer/backends/base_ssh.py index ee8fc72..4cae9e9 100644 --- a/proxmoxer/backends/base_ssh.py +++ b/proxmoxer/backends/base_ssh.py @@ -9,10 +9,11 @@ class Response(object): - def __init__(self, content, status_code): + def __init__(self, content, status_code, reason): self.status_code = status_code self.content = content self.headers = {"content-type": "application/json"} + self.reason = reason class ProxmoxBaseSSHSession(object): @@ -49,7 +50,7 @@ def request(self, method, url, data=None, params=None, headers=None): status_code = next( (int(s.split()[0]) for s in stderr.splitlines() if match(s)), 500) - return Response(stdout, status_code) + return Response(stdout, status_code, stderr) def upload_file_obj(self, file_obj, remote_path): raise NotImplementedError() From 8a6c698cdf3c9fd11fd258709f23ab8fd05a33ea Mon Sep 17 00:00:00 2001 From: mihail Date: Tue, 19 Jun 2018 15:01:55 +0300 Subject: [PATCH 03/16] bugfix --- proxmoxer/backends/ssh_paramiko.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxmoxer/backends/ssh_paramiko.py b/proxmoxer/backends/ssh_paramiko.py index c24c384..f9cbe11 100644 --- a/proxmoxer/backends/ssh_paramiko.py +++ b/proxmoxer/backends/ssh_paramiko.py @@ -56,8 +56,8 @@ def _exec(self, cmd): cmd = 'sudo ' + cmd session = self.ssh_client.get_transport().open_session() session.exec_command(cmd) - stdout = ''.join(session.makefile('rb', -1)) - stderr = ''.join(session.makefile_stderr('rb', -1)) + stdout = ''.join(session.makefile('r', -1)) + stderr = ''.join(session.makefile_stderr('r', -1)) return stdout, stderr def upload_file_obj(self, file_obj, remote_path): From 8876676d1976fc32cdb04281aaf35c38915e48ef Mon Sep 17 00:00:00 2001 From: mihail Date: Tue, 19 Jun 2018 15:08:40 +0300 Subject: [PATCH 04/16] if argument has space, will surround with double quotes --- proxmoxer/backends/base_ssh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmoxer/backends/base_ssh.py b/proxmoxer/backends/base_ssh.py index 4cae9e9..9c63d37 100644 --- a/proxmoxer/backends/base_ssh.py +++ b/proxmoxer/backends/base_ssh.py @@ -41,7 +41,7 @@ def request(self, method, url, data=None, params=None, headers=None): data['filename'] = data['filename'].name data['tmpfilename'] = tmp_filename - translated_data = ' '.join(["-{0} {1}".format(k, v) for k, v in chain(data.items(), params.items())]) + translated_data = ' '.join(["-{0} {1}".format(k, v if not isinstance(v, str) or " " not in v else '"{}"'.format(v)) for k, v in chain(data.items(), params.items())]) full_cmd = 'pvesh {0}'.format(' '.join(filter(None, (cmd, url, translated_data)))) stdout, stderr = self._exec(full_cmd) From e71cb23af8f239b9c56d5d2d61814de02e2d4f77 Mon Sep 17 00:00:00 2001 From: mihail Date: Tue, 19 Jun 2018 23:49:20 +0300 Subject: [PATCH 05/16] ResourceException has fields now so that we can use them one by one --- proxmoxer/core.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/proxmoxer/core.py b/proxmoxer/core.py index 710dffa..fd7fcb0 100644 --- a/proxmoxer/core.py +++ b/proxmoxer/core.py @@ -42,7 +42,16 @@ def url_join(self, base, *args): class ResourceException(Exception): - pass + def __init__(self, status_code, status_message, content, reason): + self.status_code = status_code + self.status_message = status_message + self.content = content + self.reason = reason + super(ResourceException, self).__init__(self.__repr__()) + + def __repr__(self): + return "{0} {1}: {2}, Content:{3}".format( + self.status_code, self.status_message, self.reason, self.content) class ProxmoxResource(ProxmoxResourceBase): @@ -75,8 +84,7 @@ def _request(self, method, data=None, params=None): logger.debug('Status code: %s, output: %s', resp.status_code, resp.content) if resp.status_code >= 400: - raise ResourceException("{0} {1}: {2}, Content:{3}".format(resp.status_code, httplib.responses[resp.status_code], - resp.reason, resp.content)) + raise ResourceException(resp.status_code, httplib.responses[resp.status_code], resp.reason, resp.content) elif 200 <= resp.status_code <= 299: return self._store["serializer"].loads(resp) From 30960156e798bf479aebd874b6397b7bd5867159 Mon Sep 17 00:00:00 2001 From: mihail Date: Wed, 20 Jun 2018 00:01:40 +0300 Subject: [PATCH 06/16] bugfix --- proxmoxer/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxmoxer/core.py b/proxmoxer/core.py index fd7fcb0..b2c9b49 100644 --- a/proxmoxer/core.py +++ b/proxmoxer/core.py @@ -46,7 +46,7 @@ def __init__(self, status_code, status_message, content, reason): self.status_code = status_code self.status_message = status_message self.content = content - self.reason = reason + self.reason = reason.strip() super(ResourceException, self).__init__(self.__repr__()) def __repr__(self): @@ -84,7 +84,7 @@ def _request(self, method, data=None, params=None): logger.debug('Status code: %s, output: %s', resp.status_code, resp.content) if resp.status_code >= 400: - raise ResourceException(resp.status_code, httplib.responses[resp.status_code], resp.reason, resp.content) + raise ResourceException(resp.status_code, httplib.responses[resp.status_code], resp.content, resp.reason) elif 200 <= resp.status_code <= 299: return self._store["serializer"].loads(resp) From 3b6877d4a983ee33100becae291bac02c18a85bc Mon Sep 17 00:00:00 2001 From: Oleg Butovich Date: Thu, 6 Sep 2018 13:58:00 +0200 Subject: [PATCH 07/16] fix from https://github.com/swayf/proxmoxer/pull/40 --- proxmoxer/backends/https.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proxmoxer/backends/https.py b/proxmoxer/backends/https.py index b870195..d9cf802 100644 --- a/proxmoxer/backends/https.py +++ b/proxmoxer/backends/https.py @@ -90,6 +90,10 @@ def request(self, method, url, params=None, data=None, headers=None, cookies=Non timeout=None, allow_redirects=True, proxies=None, hooks=None, stream=None, verify=None, cert=None, serializer=None): + # take set verify flag from session request does not have this parameter explicitly + if verify is None: + verify = self.verify + #filter out streams files = files or {} data = data or {} From d6437e57feaf8f0bde15706b65a29cc2b5cc086c Mon Sep 17 00:00:00 2001 From: Geert Stappers Date: Sun, 4 Feb 2018 15:19:51 +0100 Subject: [PATCH 08/16] README.rst: create container with parameters in dictonary Avoids syntax error on adding ssh-public-keys Signed-off-by: Geert Stappers --- README.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.rst b/README.rst index bd639c7..450410b 100644 --- a/README.rst +++ b/README.rst @@ -132,6 +132,23 @@ Example of creation of lxc container: password='secret', net0='name=eth0,bridge=vmbr0,ip=192.168.22.1/20,gw=192.168.16.1') +Example of creating the same lxc container with parameters in a dictonary. +This approach allows to add ``ssh-public-keys`` without getting syntax errors. + +.. code-block:: python + + newcontainer = { 'vmid': 202, + 'ostemplate': 'local:vztmpl/debian-9.0-standard_20170530_amd64.tar.gz', + 'hostname': 'debian-stretch', + 'storage': 'local', + 'memory': 512, + 'swap': 512, + 'cores': 1, + 'password': 'secret', + 'net0': 'name=eth0,bridge=vmbr0,ip=192.168.22.1/20,gw=192.168.16.1' } + node = proxmox.nodes('proxmox_node') + node.lxc.create(**newcontainer) + Example of template upload: .. code-block:: python From bd743f9fd6870903ec466acf63078c07758be1b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Schneider?= Date: Tue, 6 Feb 2018 10:41:03 +0100 Subject: [PATCH 09/16] paramiko python3: stdout and stderr must be a str not bytes Fixes paramiko tests: return io.BytesIO instead of a list for stdout and stderr to look like paramiko.channel.channelfile object --- proxmoxer/backends/ssh_paramiko.py | 4 ++-- tests/base/base_ssh_suite.py | 6 ++++++ tests/paramiko_tests.py | 9 +++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/proxmoxer/backends/ssh_paramiko.py b/proxmoxer/backends/ssh_paramiko.py index f9cbe11..482da55 100644 --- a/proxmoxer/backends/ssh_paramiko.py +++ b/proxmoxer/backends/ssh_paramiko.py @@ -56,8 +56,8 @@ def _exec(self, cmd): cmd = 'sudo ' + cmd session = self.ssh_client.get_transport().open_session() session.exec_command(cmd) - stdout = ''.join(session.makefile('r', -1)) - stderr = ''.join(session.makefile_stderr('r', -1)) + stdout = session.makefile('rb', -1).read().decode() + stderr = session.makefile_stderr('rb', -1).read().decode() return stdout, stderr def upload_file_obj(self, file_obj, remote_path): diff --git a/tests/base/base_ssh_suite.py b/tests/base/base_ssh_suite.py index cbe6d07..943b72f 100644 --- a/tests/base/base_ssh_suite.py +++ b/tests/base/base_ssh_suite.py @@ -72,12 +72,15 @@ def test_get(self): def test_delete(self): self.proxmox.nodes('proxmox').openvz(100).delete() eq_(self._get_called_cmd(), self._called_cmd('pvesh delete /nodes/proxmox/openvz/100')) + self._set_stderr("200 OK") self.proxmox.nodes('proxmox').openvz('101').delete() eq_(self._get_called_cmd(), self._called_cmd('pvesh delete /nodes/proxmox/openvz/101')) + self._set_stderr("200 OK") self.proxmox.nodes('proxmox').openvz.delete('102') eq_(self._get_called_cmd(), self._called_cmd('pvesh delete /nodes/proxmox/openvz/102')) def test_post(self): + self._set_stderr("200 OK") node = self.proxmox.nodes('proxmox') node.openvz.create(vmid=800, ostemplate='local:vztmpl/debian-6-turnkey-core_12.0-1_i386.tar.gz', @@ -102,6 +105,7 @@ def test_post(self): ok_('-swap 512' in options) ok_('-vmid 800' in options) + self._set_stderr("200 OK") node = self.proxmox.nodes('proxmox1') node.openvz.post(vmid=900, ostemplate='local:vztmpl/debian-7-turnkey-core_12.0-1_i386.tar.gz', @@ -127,6 +131,7 @@ def test_post(self): ok_('-vmid 900' in options) def test_put(self): + self._set_stderr("200 OK") node = self.proxmox.nodes('proxmox') node.openvz(101).config.set(cpus=4, memory=1024, ip_address='10.0.100.100', onboot=True) cmd, options = self._split_cmd(self._get_called_cmd()) @@ -136,6 +141,7 @@ def test_put(self): ok_('-onboot True' in options) ok_('-cpus 4' in options) + self._set_stderr("200 OK") node = self.proxmox.nodes('proxmox1') node.openvz('102').config.put(cpus=2, memory=512, ip_address='10.0.100.200', onboot=False) cmd, options = self._split_cmd(self._get_called_cmd()) diff --git a/tests/paramiko_tests.py b/tests/paramiko_tests.py index 923c386..e69ee79 100644 --- a/tests/paramiko_tests.py +++ b/tests/paramiko_tests.py @@ -2,6 +2,7 @@ __copyright__ = '(c) Oleg Butovich 2013-2017' __licence__ = 'MIT' +import io from mock import patch from nose.tools import eq_ from proxmoxer import ProxmoxAPI @@ -37,10 +38,10 @@ def _get_called_cmd(self): return self.session.exec_command.call_args[0][0] def _set_stdout(self, stdout): - self.session.makefile.return_value = [stdout] + self.session.makefile.return_value = io.BytesIO(stdout.encode('utf-8')) def _set_stderr(self, stderr): - self.session.makefile_stderr.return_value = [stderr] + self.session.makefile_stderr.return_value = io.BytesIO(stderr.encode('utf-8')) class TestParamikoSuiteWithSudo(BaseSSHSuite): @@ -59,7 +60,7 @@ def _get_called_cmd(self): return self.session.exec_command.call_args[0][0] def _set_stdout(self, stdout): - self.session.makefile.return_value = [stdout] + self.session.makefile.return_value = io.BytesIO(stdout.encode('utf-8')) def _set_stderr(self, stderr): - self.session.makefile_stderr.return_value = [stderr] + self.session.makefile_stderr.return_value = io.BytesIO(stderr.encode('utf-8')) From 1dbcc6e81afe959d6171b9ae991f965aaf685f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Schneider?= Date: Tue, 6 Feb 2018 12:16:57 +0100 Subject: [PATCH 10/16] proxmoxer/backends/base_ssh.py: add stderr on the Response content It's great to show response content when we have a 500 but it's better to show error when we have one --- proxmoxer/backends/base_ssh.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/proxmoxer/backends/base_ssh.py b/proxmoxer/backends/base_ssh.py index 9c63d37..683c846 100644 --- a/proxmoxer/backends/base_ssh.py +++ b/proxmoxer/backends/base_ssh.py @@ -9,11 +9,10 @@ class Response(object): - def __init__(self, content, status_code, reason): + def __init__(self, content, status_code): self.status_code = status_code self.content = content self.headers = {"content-type": "application/json"} - self.reason = reason class ProxmoxBaseSSHSession(object): @@ -50,7 +49,10 @@ def request(self, method, url, data=None, params=None, headers=None): status_code = next( (int(s.split()[0]) for s in stderr.splitlines() if match(s)), 500) - return Response(stdout, status_code, stderr) + if stdout: + return Response(stdout, status_code) + else: + return Response(stderr, status_code) def upload_file_obj(self, file_obj, remote_path): raise NotImplementedError() From d7da31a925bb681cee29f05657b966d882b714b2 Mon Sep 17 00:00:00 2001 From: Piet van Agtmaal Date: Thu, 14 Jun 2018 12:27:36 +0200 Subject: [PATCH 11/16] Add option to specify port in host --- proxmoxer/backends/https.py | 5 +++++ tests/https_tests.py | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/proxmoxer/backends/https.py b/proxmoxer/backends/https.py index d9cf802..ad76a47 100644 --- a/proxmoxer/backends/https.py +++ b/proxmoxer/backends/https.py @@ -113,7 +113,12 @@ def request(self, method, url, params=None, data=None, headers=None, cookies=Non class Backend(object): def __init__(self, host, user, password, port=8006, verify_ssl=True, mode='json', timeout=5, auth_token=None, csrf_token=None): + if ':' in host: + host, host_port = host.split(':') + port = host_port if host_port.isdigit() else port + self.base_url = "https://{0}:{1}/api2/{2}".format(host, port, mode) + if auth_token is not None: self.auth = ProxmoxHTTPTokenAuth(auth_token, csrf_token) else: diff --git a/tests/https_tests.py b/tests/https_tests.py index 3efc1fc..1c1b454 100644 --- a/tests/https_tests.py +++ b/tests/https_tests.py @@ -20,6 +20,32 @@ def test_https_connection(req_session): eq_(call['verify'], False) +@patch('requests.sessions.Session') +def test_https_connection_wth_port_in_host(req_session): + response = {'ticket': 'ticket', + 'CSRFPreventionToken': 'CSRFPreventionToken'} + req_session.request.return_value = response + ProxmoxAPI('proxmox:123', user='root@pam', password='secret', port=124, verify_ssl=False) + call = req_session.return_value.request.call_args[1] + eq_(call['url'], 'https://proxmox:123/api2/json/access/ticket') + eq_(call['data'], {'username': 'root@pam', 'password': 'secret'}) + eq_(call['method'], 'post') + eq_(call['verify'], False) + + +@patch('requests.sessions.Session') +def test_https_connection_wth_bad_port_in_host(req_session): + response = {'ticket': 'ticket', + 'CSRFPreventionToken': 'CSRFPreventionToken'} + req_session.request.return_value = response + ProxmoxAPI('proxmox:notaport', user='root@pam', password='secret', port=124, verify_ssl=False) + call = req_session.return_value.request.call_args[1] + eq_(call['url'], 'https://proxmox:124/api2/json/access/ticket') + eq_(call['data'], {'username': 'root@pam', 'password': 'secret'}) + eq_(call['method'], 'post') + eq_(call['verify'], False) + + class TestSuite(): proxmox = None serializer = None From 031f359f99fd9a489182822902f18e0c271a5310 Mon Sep 17 00:00:00 2001 From: Oleg Butovich Date: Thu, 6 Sep 2018 23:22:01 +0200 Subject: [PATCH 12/16] fix from mihailstoynov --- proxmoxer/backends/ssh_paramiko.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxmoxer/backends/ssh_paramiko.py b/proxmoxer/backends/ssh_paramiko.py index 482da55..7ff14e4 100644 --- a/proxmoxer/backends/ssh_paramiko.py +++ b/proxmoxer/backends/ssh_paramiko.py @@ -56,8 +56,8 @@ def _exec(self, cmd): cmd = 'sudo ' + cmd session = self.ssh_client.get_transport().open_session() session.exec_command(cmd) - stdout = session.makefile('rb', -1).read().decode() - stderr = session.makefile_stderr('rb', -1).read().decode() + stdout = session.makefile('r', -1).read().decode() + stderr = session.makefile_stderr('r', -1).read().decode() return stdout, stderr def upload_file_obj(self, file_obj, remote_path): From c49386bbb8a77e428f9b323958fe29b765f0d1a2 Mon Sep 17 00:00:00 2001 From: Oleg Butovich Date: Thu, 6 Sep 2018 23:37:01 +0200 Subject: [PATCH 13/16] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 450410b..91b24e9 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,7 @@ develop branch: |develop_build_status| |develop_coverage_status| What does it do and what's different? ------------------------------------- -Proxmoxer is a wrapper around the `Proxmox REST API v2 `_. +Proxmoxer is a wrapper around the `Proxmox REST API v2 `_. It was inspired by slumber, but it dedicated only to Proxmox. It allows to use not only REST API over HTTPS, but the same api over ssh and pvesh utility. From 6ca20f04dc2921cb38e9673adffb3c8771fa59e4 Mon Sep 17 00:00:00 2001 From: Oleg Butovich Date: Mon, 10 Sep 2018 21:52:25 +0200 Subject: [PATCH 14/16] Revert "fix from mihailstoynov" This reverts commit 061edfbb8615e38a54f867ea424a19eb76eff976. --- proxmoxer/backends/ssh_paramiko.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxmoxer/backends/ssh_paramiko.py b/proxmoxer/backends/ssh_paramiko.py index 7ff14e4..482da55 100644 --- a/proxmoxer/backends/ssh_paramiko.py +++ b/proxmoxer/backends/ssh_paramiko.py @@ -56,8 +56,8 @@ def _exec(self, cmd): cmd = 'sudo ' + cmd session = self.ssh_client.get_transport().open_session() session.exec_command(cmd) - stdout = session.makefile('r', -1).read().decode() - stderr = session.makefile_stderr('r', -1).read().decode() + stdout = session.makefile('rb', -1).read().decode() + stderr = session.makefile_stderr('rb', -1).read().decode() return stdout, stderr def upload_file_obj(self, file_obj, remote_path): From cf4c3f64de4fb71fa92b3f9bc23228fb9ecffda9 Mon Sep 17 00:00:00 2001 From: Oleg Butovich Date: Mon, 10 Sep 2018 21:55:56 +0200 Subject: [PATCH 15/16] bump version --- README.rst | 7 +++++++ proxmoxer/__init__.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 91b24e9..eb7dab2 100644 --- a/README.rst +++ b/README.rst @@ -185,6 +185,13 @@ Roadmap History ------- +1.0.3 (1018-09-10) +.................. +* Improvement: Added option to specify port in hostname parameter (`pvanagtmaal `_) +* Improvement: Added stderr to the Response content (`Jérôme Schneider `_) +* Bugfix: Paramiko python3: stdout and stderr must be a str not bytes (`Jérôme Schneider `_) +* New lxc example in docu (`Geert Stappers `_) + 1.0.2 (2017-12-02) .................. * Tarball repackaged with tests diff --git a/proxmoxer/__init__.py b/proxmoxer/__init__.py index a7cd49c..736104b 100644 --- a/proxmoxer/__init__.py +++ b/proxmoxer/__init__.py @@ -1,6 +1,6 @@ __author__ = 'Oleg Butovich' __copyright__ = '(c) Oleg Butovich 2013-2017' -__version__ = '1.0.2' +__version__ = '1.0.3' __licence__ = 'MIT' from .core import * From c661dd7942e581c076e286d623435e25ad25cc9d Mon Sep 17 00:00:00 2001 From: Oleg Butovich Date: Mon, 13 Apr 2020 13:36:00 +0200 Subject: [PATCH 16/16] Update README.rst --- README.rst | 278 +---------------------------------------------------- 1 file changed, 1 insertion(+), 277 deletions(-) diff --git a/README.rst b/README.rst index eb7dab2..ea25cf3 100644 --- a/README.rst +++ b/README.rst @@ -2,280 +2,4 @@ Proxmoxer: A wrapper for Proxmox REST API ========================================= -master branch: |master_build_status| |master_coverage_status| |pypi_version| |pypi_downloads| - -develop branch: |develop_build_status| |develop_coverage_status| - - -What does it do and what's different? -------------------------------------- - -Proxmoxer is a wrapper around the `Proxmox REST API v2 `_. - -It was inspired by slumber, but it dedicated only to Proxmox. It allows to use not only REST API over HTTPS, but -the same api over ssh and pvesh utility. - -Like `Proxmoxia `_ it dynamically creates attributes which responds to the -attributes you've attempted to reach. - -Installation ------------- - -.. code-block:: bash - - pip install proxmoxer - -For 'https' backend install requests - -.. code-block:: bash - - pip install requests - -For 'ssh_paramiko' backend install paramiko - -.. code-block:: bash - - pip install paramiko - - -Short usage information ------------------------ - -The first thing to do is import the proxmoxer library and create ProxmoxAPI instance. - -.. code-block:: python - - from proxmoxer import ProxmoxAPI - proxmox = ProxmoxAPI('proxmox_host', user='admin@pam', - password='secret_word', verify_ssl=False) - -This will connect by default through the 'https' backend. - -It is possible to use already prepared public/private key authentication. It is possible to use ssh-agent also. - -.. code-block:: python - - from proxmoxer import ProxmoxAPI - proxmox = ProxmoxAPI('proxmox_host', user='proxmox_admin', backend='ssh_paramiko') - -**Please note, https-backend needs 'requests' library, ssh_paramiko-backend needs 'paramiko' library, -openssh-backend needs 'openssh_wrapper' library installed.** - -Queries are exposed via the access methods **get**, **post**, **put** and **delete**. For convenience added two -synonyms: **create** for **post**, and **set** for **put**. - -.. code-block:: python - - for node in proxmox.nodes.get(): - for vm in proxmox.nodes(node['node']).openvz.get(): - print "{0}. {1} => {2}" .format(vm['vmid'], vm['name'], vm['status']) - - >>> 141. puppet-2.london.baseblack.com => running - 101. munki.london.baseblack.com => running - 102. redmine.london.baseblack.com => running - 140. dns-1.london.baseblack.com => running - 126. ns-3.london.baseblack.com => running - 113. rabbitmq.london.baseblack.com => running - -same code can be rewritten in the next way: - -.. code-block:: python - - for node in proxmox.get('nodes'): - for vm in proxmox.get('nodes/%s/openvz' % node['node']): - print "%s. %s => %s" % (vm['vmid'], vm['name'], vm['status']) - - -for example next lines do the same job: - -.. code-block:: python - - proxmox.nodes(node['node']).openvz.get() - proxmox.nodes(node['node']).get('openvz') - proxmox.get('nodes/%s/openvz' % node['node']) - proxmox.get('nodes', node['node'], 'openvz') - - -Some more examples: - -.. code-block:: python - - for vm in proxmox.cluster.resources.get(type='vm'): - print("{0}. {1} => {2}" .format(vm['vmid'], vm['name'], vm['status'])) - - -.. code-block:: python - - node = proxmox.nodes('proxmox_node') - pprint(node.storage('local').content.get()) - -or the with same results - -.. code-block:: python - - node = proxmox.nodes.proxmox_node() - pprint(node.storage.local.content.get()) - - -Example of creation of lxc container: - -.. code-block:: python - - node = proxmox.nodes('proxmox_node') - node.lxc.create(vmid=202, - ostemplate='local:vztmpl/debian-9.0-standard_20170530_amd64.tar.gz', - hostname='debian-stretch', - storage='local', - memory=512, - swap=512, - cores=1, - password='secret', - net0='name=eth0,bridge=vmbr0,ip=192.168.22.1/20,gw=192.168.16.1') - -Example of creating the same lxc container with parameters in a dictonary. -This approach allows to add ``ssh-public-keys`` without getting syntax errors. - -.. code-block:: python - - newcontainer = { 'vmid': 202, - 'ostemplate': 'local:vztmpl/debian-9.0-standard_20170530_amd64.tar.gz', - 'hostname': 'debian-stretch', - 'storage': 'local', - 'memory': 512, - 'swap': 512, - 'cores': 1, - 'password': 'secret', - 'net0': 'name=eth0,bridge=vmbr0,ip=192.168.22.1/20,gw=192.168.16.1' } - node = proxmox.nodes('proxmox_node') - node.lxc.create(**newcontainer) - -Example of template upload: - -.. code-block:: python - - local_storage = proxmox.nodes('proxmox_node').storage('local') - local_storage.upload.create(content='vztmpl', - filename=open(os.path.expanduser('~/templates/debian-6-my-core_1.0-1_i386.tar.gz')))) - - -Example of rrd download: - -.. code-block:: python - - response = proxmox.nodes('proxmox').rrd.get(ds='cpu', timeframe='hour') - with open('cpu.png', 'wb') as f: - f.write(response['image'].encode('raw_unicode_escape')) - -Example of usage of logging: - -.. code-block:: python - - # now logging debug info will be written to stdout - logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s:%(name)s: %(message)s') - - -Roadmap -------- - -* write tests -* support other actual python versions -* add optional validation of requests -* add some shortcuts for convenience - -History -------- - -1.0.3 (1018-09-10) -.................. -* Improvement: Added option to specify port in hostname parameter (`pvanagtmaal `_) -* Improvement: Added stderr to the Response content (`Jérôme Schneider `_) -* Bugfix: Paramiko python3: stdout and stderr must be a str not bytes (`Jérôme Schneider `_) -* New lxc example in docu (`Geert Stappers `_) - -1.0.2 (2017-12-02) -.................. -* Tarball repackaged with tests - -1.0.1 (2017-12-02) -.................. -* LICENSE file now included in tarball -* Added verify_ssl parameter to ProxmoxHTTPAuth (`Walter Doekes `_) - -1.0.0 (2017-11-12) -.................. -* Update Proxmoxer readme (`Emmanuel Kasper `_) -* Display the reason of API calls errors (`Emmanuel Kasper `_, `kantsdog `_) -* Filter for ssh response code (`Chris Plock `_) - -0.2.5 (2017-02-12) -.................. -* Adding sudo to execute CLI with paramiko ssh backend (`Jason Meridth `_) -* Proxmoxer/backends/ssh_paramiko: improve file upload (`Jérôme Schneider `_) - -0.2.4 (2016-05-02) -.................. -* Removed newline in tmp_filename string (`Jérôme Schneider `_) -* Fix to avoid module reloading (`jklang `_) - -0.2.3 (2016-01-20) -.................. -* Minor typo fix (`Srinivas Sakhamuri `_) - -0.2.2 (2016-01-19) -.................. -* Adding sudo to execute pvesh CLI in openssh backend (`Wei Tie `_, `Srinivas Sakhamuri `_) -* Add support to specify an identity file for ssh connections (`Srinivas Sakhamuri `_) - -0.2.1 (2015-05-02) -.................. -* fix for python 3.4 (`kokuev `_) - -0.2.0 (2015-03-21) -.................. -* Https will now raise AuthenticationError when appropriate. (`scap1784 `_) -* Preliminary python 3 compatibility. (`wdoekes `_) -* Additional example. (`wdoekes `_) - -0.1.7 (2014-11-16) -.................. -* Added ignore of "InsecureRequestWarning: Unverified HTTPS request is being made..." warning while using https (requests) backend. - -0.1.4 (2013-06-01) -.................. -* Added logging -* Added openssh backend -* Tests are reorganized - -0.1.3 (2013-05-30) -.................. -* Added next tests -* Bugfixes - -0.1.2 (2013-05-27) -.................. -* Added first tests -* Added support for travis and coveralls -* Bugfixes - -0.1.1 (2013-05-13) -.................. -* Initial try. - -.. |master_build_status| image:: https://travis-ci.org/swayf/proxmoxer.png?branch=master - :target: https://travis-ci.org/swayf/proxmoxer - -.. |master_coverage_status| image:: https://coveralls.io/repos/swayf/proxmoxer/badge.png?branch=master - :target: https://coveralls.io/r/swayf/proxmoxer - -.. |develop_build_status| image:: https://travis-ci.org/swayf/proxmoxer.png?branch=develop - :target: https://travis-ci.org/swayf/proxmoxer - -.. |develop_coverage_status| image:: https://coveralls.io/repos/swayf/proxmoxer/badge.png?branch=develop - :target: https://coveralls.io/r/swayf/proxmoxer - -.. |pypi_version| image:: https://img.shields.io/pypi/v/proxmoxer.svg - :target: https://pypi.python.org/pypi/proxmoxer - -.. |pypi_downloads| image:: https://img.shields.io/pypi/dm/proxmoxer.svg - :target: https://pypi.python.org/pypi/proxmoxer - +repository is moved to https://github.com/proxmoxer/proxmoxer