diff options
| author | Hans-Christoph Steiner <hans@eds.org> | 2018-01-08 22:07:40 +0100 |
|---|---|---|
| committer | git-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com> | 2018-01-09 04:40:24 +0000 |
| commit | ee1bb6d75a8a794e9ce2262c829b850619775e0f (patch) | |
| tree | 8a1d510b84c2b39ea8e731f1c0e87a830784a537 | |
| parent | ede633a87536f66935a364f808eced07d1c3eec7 (diff) | |
0.5.15-1 (patches unapplied)import/0.5.15-1ubuntu/bionic-proposedubuntu/bionic-develubuntu/bionic
Imported using git-ubuntu import.
Notes
Notes:
* New upstream version
| -rw-r--r-- | CHANGELOG.md | 11 | ||||
| -rw-r--r-- | PKG-INFO | 2 | ||||
| -rw-r--r-- | debian/changelog | 6 | ||||
| -rw-r--r-- | debian/control | 2 | ||||
| -rw-r--r-- | debian/copyright | 2 | ||||
| -rw-r--r-- | debian/watch | 2 | ||||
| -rw-r--r-- | python_vagrant.egg-info/PKG-INFO | 2 | ||||
| -rw-r--r-- | tests/test_vagrant.py | 54 | ||||
| -rw-r--r-- | vagrant/__init__.py | 108 |
9 files changed, 159 insertions, 30 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 95ceafb..3633673 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ This document lists the changes (and individuals who contributed to those changes) for each release of python-vagrant. +## 0.5.15 + +- Pull Request #54: Create ssh() method to run shell commands in a VM + Authors: Parker Thompson (https://github.com/mothran) and Todd DeLuca + (https://github.com/todddeluca) +- Pull Request #56: Return generator for `up` and `reload` output lines to + avoid having entire output in memory. + Authors: mmabey (https://github.com/mmabey) and Todd DeLuca + (https://github.com/todddeluca) + + ## 0.5.14 - Pull Request #51: Add support for the vagrant package command. @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: python-vagrant -Version: 0.5.14 +Version: 0.5.15 Summary: Python bindings for interacting with Vagrant virtual machines. Home-page: https://github.com/todddeluca/python-vagrant Author: Todd Francis DeLuca diff --git a/debian/changelog b/debian/changelog index f0b68b5..0ccb967 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +python-vagrant (0.5.15-1) unstable; urgency=medium + + * New upstream version + + -- Hans-Christoph Steiner <hans@eds.org> Mon, 08 Jan 2018 22:07:40 +0100 + python-vagrant (0.5.14-1) unstable; urgency=medium * latest upstream release diff --git a/debian/control b/debian/control index 9ec0cad..33e7709 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Build-Depends: debhelper (>= 9), python-setuptools, python3-all, python3-setuptools, -Standards-Version: 3.9.8 +Standards-Version: 4.1.3 Vcs-Git: https://anonscm.debian.org/git/python-modules/packages/python-vagrant.git Vcs-Browser: https://anonscm.debian.org/cgit/python-modules/packages/python-vagrant.git Homepage: https://github.com/todddeluca/python-vagrant diff --git a/debian/copyright b/debian/copyright index e599005..aaf5f96 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: python-vagrant Upstream-Contact: Todd DeLuca <todddeluca@gmail.com> Source: https://github.com/todddeluca/python-vagrant diff --git a/debian/watch b/debian/watch index 12494e0..4427936 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,3 @@ version=3 opts=uversionmangle=s/\.RC/~RC/ \ -http://pypi.debian.net/python-vagrant/python-vagrant-(.*)\.tar\.gz +https://pypi.debian.net/python-vagrant/python-vagrant-(.*)\.tar\.gz diff --git a/python_vagrant.egg-info/PKG-INFO b/python_vagrant.egg-info/PKG-INFO index 7fadceb..7a2fbcd 100644 --- a/python_vagrant.egg-info/PKG-INFO +++ b/python_vagrant.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: python-vagrant -Version: 0.5.14 +Version: 0.5.15 Summary: Python bindings for interacting with Vagrant virtual machines. Home-page: https://github.com/todddeluca/python-vagrant Author: Todd Francis DeLuca diff --git a/tests/test_vagrant.py b/tests/test_vagrant.py index 21297ed..7b92c1d 100644 --- a/tests/test_vagrant.py +++ b/tests/test_vagrant.py @@ -23,7 +23,7 @@ import subprocess import sys import tempfile import time -from nose.tools import eq_, ok_, with_setup +from nose.tools import eq_, ok_, with_setup, assert_raises import vagrant from vagrant import compat @@ -520,6 +520,58 @@ def test_multivm_config(): eq_(keyfile, parsed_config["IdentityFile"].lstrip('"').rstrip('"')) +@with_setup(make_setup_vm(), teardown_vm) +def test_ssh_command(): + ''' + Test executing a command via ssh on a vm. + ''' + v = vagrant.Vagrant(TD) + v.up() + output = v.ssh(command='echo hello') + assert output.strip() == 'hello' + + +@with_setup(make_setup_vm(MULTIVM_VAGRANTFILE), teardown_vm) +def test_ssh_command_multivm(): + ''' + Test executing a command via ssh on a specific vm + ''' + v = vagrant.Vagrant(TD) + v.up() + output = v.ssh(vm_name=VM_1, command='echo hello') + assert output.strip() == 'hello' + output = v.ssh(vm_name=VM_2, command='echo I like your hat') + assert output.strip() == 'I like your hat' + + +@with_setup(make_setup_vm(), teardown_vm) +def test_streaming_output(): + """ + Test streaming output of up or reload. + """ + test_string = 'Waiting for machine to boot.' + v = vagrant.Vagrant(TD) + + with assert_raises(subprocess.CalledProcessError): + v.up(vm_name='incorrect-name') + + streaming_up = False + for line in v.up(stream_output=True): + print('output line:', line) + if test_string in line: + streaming_up = True + + assert streaming_up + + streaming_reload = False + for line in v.reload(stream_output=True): + print('output line:', line) + if test_string in line: + streaming_reload = True + + assert streaming_reload + + def test_make_file_cm(): filename = os.path.join(TD, 'test.log') if os.path.exists(filename): diff --git a/vagrant/__init__.py b/vagrant/__init__.py index cdd93b8..75d5e7c 100644 --- a/vagrant/__init__.py +++ b/vagrant/__init__.py @@ -26,7 +26,7 @@ from . import compat # python package version # should match r"^__version__ = '(?P<version>[^']+)'$" for setup.py -__version__ = '0.5.14' +__version__ = '0.5.15' log = logging.getLogger(__name__) @@ -227,8 +227,8 @@ class Vagrant(object): env=None, out_cm=None, err_cm=None): ''' root: a directory containing a file named Vagrantfile. Defaults to - os.getcwd(). This is the directory and Vagrantfile that the Vagrant - instance will operate on. + os.getcwd(). This is the directory and Vagrantfile that the Vagrant + instance will operate on. env: a dict of environment variables (string keys and values) passed to the vagrant command subprocess or None. Defaults to None. If env is None, `subprocess.Popen` uses the current process environment. @@ -300,17 +300,24 @@ class Vagrant(object): self._call_vagrant_command(['init', box_name, box_url]) def up(self, no_provision=False, provider=None, vm_name=None, - provision=None, provision_with=None): + provision=None, provision_with=None, stream_output=False): ''' - Launch the Vagrant box. + Invoke `vagrant up` to start a box or boxes, possibly streaming the + command output. vm_name=None: name of VM. provision_with: optional list of provisioners to enable. provider: Back the machine with a specific provider no_provision: if True, disable provisioning. Same as 'provision=False'. provision: optional boolean. Enable or disable provisioning. Default behavior is to use the underlying vagrant default. + stream_output: if True, return a generator that yields each line of the + output of running the command. Consume the generator or the + subprocess might hang. if False, None is returned and the command + is run to completion without streaming the output. Defaults to + False. Note: If provision and no_provision are not None, no_provision will be ignored. + returns: None or a generator yielding lines of output. ''' provider_arg = '--provider=%s' % provider if provider else None prov_with_arg = None if provision_with is None else '--provision-with' @@ -323,15 +330,14 @@ class Vagrant(object): no_provision_arg = '--no-provision' if no_provision else None provision_arg = None if provision is None else '--provision' if provision else '--no-provision' - self._call_vagrant_command(['up', vm_name, no_provision_arg, - provision_arg, provider_arg, - prov_with_arg, providers_arg]) - try: - self.conf(vm_name=vm_name) # cache configuration - except subprocess.CalledProcessError: - # in multi-VM environments, up() can be used to start all VMs, - # however vm_name is required for conf() or ssh_config(). - pass + args = ['up', vm_name, no_provision_arg, provision_arg, provider_arg, prov_with_arg, providers_arg] + if stream_output: + generator = self._stream_vagrant_command(args) + else: + self._call_vagrant_command(args) + + self._cached_conf[vm_name] = None # remove cached configuration + return generator if stream_output else None def provision(self, vm_name=None, provision_with=None): ''' @@ -345,25 +351,40 @@ class Vagrant(object): self._call_vagrant_command(['provision', vm_name, prov_with_arg, providers_arg]) - def reload(self, vm_name=None, provision=None, provision_with=None): + def reload(self, vm_name=None, provision=None, provision_with=None, + stream_output=False): ''' Quoting from Vagrant docs: > The equivalent of running a halt followed by an up. - - > This command is usually required for changes made in the Vagrantfile to take effect. After making any modifications to the Vagrantfile, a reload should be called. - - > The configured provisioners will not run again, by default. You can force the provisioners to re-run by specifying the --provision flag. + > This command is usually required for changes made in the Vagrantfile + to take effect. After making any modifications to the Vagrantfile, a + reload should be called. + > The configured provisioners will not run again, by default. You can + force the provisioners to re-run by specifying the --provision flag. provision: optional boolean. Enable or disable provisioning. Default behavior is to use the underlying vagrant default. provision_with: optional list of provisioners to enable. e.g. ['shell', 'chef_solo'] + stream_output: if True, return a generator that yields each line of the + output of running the command. Consume the generator or the + subprocess might hang. if False, None is returned and the command + is run to completion without streaming the output. Defaults to + False. + returns: None or a generator yielding lines of output. ''' prov_with_arg = None if provision_with is None else '--provision-with' providers_arg = None if provision_with is None else ','.join(provision_with) provision_arg = None if provision is None else '--provision' if provision else '--no-provision' - self._call_vagrant_command(['reload', vm_name, provision_arg, - prov_with_arg, providers_arg]) + + args = ['reload', vm_name, provision_arg, prov_with_arg, providers_arg] + if stream_output: + generator = self._stream_vagrant_command(args) + else: + self._call_vagrant_command(args) + + self._cached_conf[vm_name] = None # remove cached configuration + return generator if stream_output else None def suspend(self, vm_name=None): ''' @@ -728,14 +749,24 @@ class Vagrant(object): ''' self._call_vagrant_command(['snapshot', 'delete', name]) + def ssh(self, vm_name=None, command=None, extra_ssh_args=None): + ''' + Execute a command via ssh on the vm specified. + command: The command to execute via ssh. + extra_ssh_args: Corresponds to '--' option in the vagrant ssh command + Returns the output of running the command. + ''' + cmd = ['ssh', vm_name, '--command', command] + if extra_ssh_args is not None: + cmd += ['--', extra_ssh_args] + + return self._run_vagrant_command(cmd) + def _parse_box_list(self, output): ''' Remove Vagrant usage for unit testing ''' # Parse box list output - # Cue snarky comment about how nice it would be if vagrant used JSON - # or even had a description of the machine readable output for each - # command boxes = [] # initialize box values @@ -944,6 +975,35 @@ class Vagrant(object): return compat.decode(subprocess.check_output(command, cwd=self.root, env=self.env, stderr=err_fh)) + def _stream_vagrant_command(self, args): + """ + Execute a vagrant command, returning a generator of the output lines. + Caller should consume the entire generator to avoid the hanging the + subprocess. + + :param args: Arguments for the Vagrant command. + :return: generator that yields each line of the command stdout. + :rtype: generator iterator + """ + py3 = sys.version_info > (3, 0) + + # Make subprocess command + command = self._make_vagrant_command(args) + with self.err_cm() as err_fh: + sp_args = dict(args=command, cwd=self.root, env=self.env, + stdout=subprocess.PIPE, stderr=err_fh, bufsize=1) + + # Iterate over output lines. + # See http://stackoverflow.com/questions/2715847/python-read-streaming-input-from-subprocess-communicate#17698359 + p = subprocess.Popen(**sp_args) + with p.stdout: + for line in iter(p.stdout.readline, b''): + yield compat.decode(line) # if PY3 decode bytestrings + p.wait() + # Raise CalledProcessError for consistency with _call_vagrant_command + if p.returncode != 0: + raise subprocess.CalledProcessError(p.returncode, command) + class SandboxVagrant(Vagrant): ''' |
