We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
nodes:scale fails on Vagrant
Looks like a path issue when we shifted around the project in #641. The problem that exists here though is that the `contrib` directory no longer exists in the `deis/controller` image, since it only adds the `controller/` path as per https://github.com/opdemand/deis/blob/master/controller/Dockerfile#L19. Should we move `contrib` to `controller/contrib`, so that the directory is present in the docker image?

```
><> deis nodes:scale dev runtime=1
Scaling nodes... but first, coffee!
400 BAD REQUEST
[Errno 2] No such file or directory: u'/app/deis/contrib/vagrant/util/nodes_vagrantfile_template.rb'
```

Note that the source code now exists at `/app` in the container, so there will have to be another PR to change the path hardcoded at https://github.com/opdemand/deis/blob/master/controller/provider/vagrant.py#L82.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `controller/provider/vagrant.py`
Content:
```
1 """
2 Deis cloud provider implementation for local vagrant setups.
3 """
4 
5 from __future__ import unicode_literals
6 
7 from api.ssh import exec_ssh, connect_ssh
8 
9 import json
10 import logging
11 import string
12 import subprocess
13 import uuid
14 
15 from api.models import Layer
16 from api.models import Node
17 
18 logger = logging.getLogger(__name__)
19 
20 CONTRIB_PATH = '/app/deis/contrib/vagrant'
21 
22 # Collect details for connecting to the host machine
23 try:
24     HOST_NODES_DIR = open('{}/.host_nodes_dir'.format(CONTRIB_PATH)).read().strip()
25     PKEY = open('{}/util/ssh_keys/id_rsa_vagrant-deis-controller'.format(CONTRIB_PATH)).read()
26 except IOError as err:
27     logger.warn(err)
28 
29 
30 def seed_flavors():
31     """Seed the database with default flavors for vagrant.
32 
33     :rtype: list of dicts containing flavor data
34     """
35     flavors = []
36     for m in ['512', '1024', '2048']:
37         flavors.append({
38             'id': "vagrant-{}".format(m),
39             'provider': 'vagrant',
40             'params': json.dumps({
41                 'memory': m
42             })
43         })
44     return flavors
45 
46 
47 def build_layer(layer):
48     """
49     Build a layer.
50 
51     :param layer: a dict containing formation, id, params, and creds info
52     """
53 
54     # This can also be done with `deis layers:update` now.
55     layer_ = Layer.objects.get(id=layer['id'], formation__id=layer['formation'])
56     layer_.ssh_username = 'vagrant'
57     layer_.save()
58 
59 
60 def destroy_layer(layer):
61     """
62     Destroy a layer.
63 
64     :param layer: a dict containing formation, id, params, and creds info
65     """
66     pass
67 
68 
69 def build_node(node):
70     """
71     Build a node.
72 
73     :param node: a dict containing formation, layer, params, and creds info.
74     :rtype: a tuple of (provider_id, fully_qualified_domain_name, metadata)
75     """
76 
77     # Can't use the vagrant UUID because it's not booted yet
78     uid = str(uuid.uuid1())
79 
80     # Create a new Vagrantfile from a template
81     node['params'].setdefault('memory', '512')
82     template = open('/app/deis/contrib/vagrant/util/nodes_vagrantfile_template.rb')
83     raw = string.Template(template.read())
84     ip_addr = '192.168.61.' + str(Node.objects.all().count() + 100)
85     result = raw.substitute({
86         'id': uid,
87         'ipaddress': ip_addr,
88         'memory': node['params']['memory']
89     })
90 
91     # Make a folder for the VM with its own Vagrantfile. Vagrant will then create a .vagrant folder
92     # there too when it first gets booted.
93     node_dir = HOST_NODES_DIR + '/' + uid
94     mkdir = 'mkdir -p "{}"'.format(node_dir)
95     cp_tpl = 'echo "' + result.replace('"', '\\"') + '" > "{}/Vagrantfile"'.format(node_dir)
96     _host_ssh(commands=[mkdir, cp_tpl], creds=node['creds'])
97 
98     # Boot the VM
99     _run_vagrant_command(uid, args=['up'], creds=node['creds'])
100 
101     # Copy the layer's public SSH key to the VM so that the Controller can access it.
102     _run_vagrant_command(
103         uid,
104         args=[
105             'ssh',
106             '-c',
107             '"echo \\"' + node['ssh_public_key'] + '\\" >> /home/vagrant/.ssh/authorized_keys"'
108         ],
109         creds=node['creds'],
110     )
111 
112     provider_id = uid
113     metadata = {
114         'id': uid,
115         'fqdn': ip_addr,
116         'flavor': node['params']['memory']
117     }
118     return provider_id, ip_addr, metadata
119 
120 
121 def destroy_node(node):
122     """
123     Destroy a node.
124 
125     :param node: a dict containing a node's provider_id, params, and creds
126     """
127 
128     # This is useful if node creation failed. So that there's a record in the DB, but it has no
129     # ID associated with it.
130     if node['provider_id'] is None:
131         return
132 
133     # Shut the VM down and destroy it
134     try:
135         _run_vagrant_command(node['provider_id'], args=['destroy', '--force'], creds=node['creds'])
136         node_dir = HOST_NODES_DIR + '/' + node['provider_id']
137 
138         # Sanity check before `rm -rf`
139         if 'contrib/vagrant' not in node_dir:
140             raise RuntimeError(
141                 "Aborted node destruction: attempting to 'rm -rf' unexpected directory")
142 
143         # Completely remove the folder that contained the VM
144         rm_vagrantfile = 'rm "{}/Vagrantfile"'.format(node_dir)
145         rm_node_dir = 'rm -rf "{}"'.format(node_dir)
146         _host_ssh(commands=[rm_vagrantfile, rm_node_dir], creds=node['creds'])
147     except RuntimeError as err:
148         # If we couldn't cd to the node dir, just log that as a warning
149         if 'no such file or directory' in str(err).lower():
150             logger.warn(err)
151         else:
152             raise
153 
154 
155 def _run_vagrant_command(node_id, args=[], creds={}):
156     """
157     args: A tuple of arguments to a vagrant command line.
158     e.g. ['up', 'my_vm_name', '--no-provision']
159     """
160 
161     cd = 'cd "{}/{}"'.format(HOST_NODES_DIR, node_id)
162     command = ['vagrant'] + [arg for arg in args if arg is not None]
163     return _host_ssh(commands=[cd, ' '.join(command)], creds=creds)
164 
165 
166 def _host_ssh(creds={}, commands=[]):
167     """
168     Connect to the host machine. Namely the user's local machine.
169     """
170     if creds == {}:
171         raise RuntimeError("No credentials provided to _host_ssh()")
172     command = ' && '.join(commands)
173 
174     # First check if we can access the host machine. It's likely that their
175     # IP address changes every time they request a DHCP lease.
176     # TODO: Find a way of passing this error onto the CLI client.
177     try:
178         subprocess.check_call([
179             'nc', '-z', '-w2', creds['host'], '22'
180         ], stderr=subprocess.PIPE)
181     except subprocess.CalledProcessError:
182         raise RuntimeError("Couldn't ping port 22 at host with IP " + creds['host'])
183 
184     ssh = connect_ssh(creds['user'], creds['host'], 22, PKEY, timeout=120)
185     result, status = exec_ssh(ssh, command)
186     if status > 0:
187         raise RuntimeError(
188             'SSH to Vagrant host error: ' + result.decode('utf-8') +
189             'Command: ' + command.decode('utf-8'))
190     return result
191
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/controller/provider/vagrant.py b/controller/provider/vagrant.py
--- a/controller/provider/vagrant.py
+++ b/controller/provider/vagrant.py
@@ -17,12 +17,12 @@
 
 logger = logging.getLogger(__name__)
 
-CONTRIB_PATH = '/app/deis/contrib/vagrant'
+VAGRANT_UTIL_PATH = '/app/provider/vagrant-util'
 
 # Collect details for connecting to the host machine
 try:
-    HOST_NODES_DIR = open('{}/.host_nodes_dir'.format(CONTRIB_PATH)).read().strip()
-    PKEY = open('{}/util/ssh_keys/id_rsa_vagrant-deis-controller'.format(CONTRIB_PATH)).read()
+    HOST_NODES_DIR = open('{}/.host_nodes_dir'.format(VAGRANT_UTIL_PATH)).read().strip()
+    PKEY = open('{}/ssh_keys/id_rsa_vagrant-deis-controller'.format(VAGRANT_UTIL_PATH)).read()
 except IOError as err:
     logger.warn(err)
 
@@ -79,7 +79,7 @@
 
     # Create a new Vagrantfile from a template
     node['params'].setdefault('memory', '512')
-    template = open('/app/deis/contrib/vagrant/util/nodes_vagrantfile_template.rb')
+    template = open('{}/nodes_vagrantfile_template.rb'.format(VAGRANT_UTIL_PATH))
     raw = string.Template(template.read())
     ip_addr = '192.168.61.' + str(Node.objects.all().count() + 100)
     result = raw.substitute({

{"golden_diff": "diff --git a/controller/provider/vagrant.py b/controller/provider/vagrant.py\n--- a/controller/provider/vagrant.py\n+++ b/controller/provider/vagrant.py\n@@ -17,12 +17,12 @@\n \n logger = logging.getLogger(__name__)\n \n-CONTRIB_PATH = '/app/deis/contrib/vagrant'\n+VAGRANT_UTIL_PATH = '/app/provider/vagrant-util'\n \n # Collect details for connecting to the host machine\n try:\n-    HOST_NODES_DIR = open('{}/.host_nodes_dir'.format(CONTRIB_PATH)).read().strip()\n-    PKEY = open('{}/util/ssh_keys/id_rsa_vagrant-deis-controller'.format(CONTRIB_PATH)).read()\n+    HOST_NODES_DIR = open('{}/.host_nodes_dir'.format(VAGRANT_UTIL_PATH)).read().strip()\n+    PKEY = open('{}/ssh_keys/id_rsa_vagrant-deis-controller'.format(VAGRANT_UTIL_PATH)).read()\n except IOError as err:\n     logger.warn(err)\n \n@@ -79,7 +79,7 @@\n \n     # Create a new Vagrantfile from a template\n     node['params'].setdefault('memory', '512')\n-    template = open('/app/deis/contrib/vagrant/util/nodes_vagrantfile_template.rb')\n+    template = open('{}/nodes_vagrantfile_template.rb'.format(VAGRANT_UTIL_PATH))\n     raw = string.Template(template.read())\n     ip_addr = '192.168.61.' + str(Node.objects.all().count() + 100)\n     result = raw.substitute({\n", "issue": "nodes:scale fails on Vagrant\nLooks like a path issue when we shifted around the project in #641. The problem that exists here though is that the `contrib` directory no longer exists in the `deis/controller` image, since it only adds the `controller/` path as per https://github.com/opdemand/deis/blob/master/controller/Dockerfile#L19. Should we move `contrib` to `controller/contrib`, so that the directory is present in the docker image?\n\n```\n><> deis nodes:scale dev runtime=1\nScaling nodes... but first, coffee!\n400 BAD REQUEST\n[Errno 2] No such file or directory: u'/app/deis/contrib/vagrant/util/nodes_vagrantfile_template.rb'\n```\n\nNote that the source code now exists at `/app` in the container, so there will have to be another PR to change the path hardcoded at https://github.com/opdemand/deis/blob/master/controller/provider/vagrant.py#L82.\n\n", "before_files": [{"content": "\"\"\"\nDeis cloud provider implementation for local vagrant setups.\n\"\"\"\n\nfrom __future__ import unicode_literals\n\nfrom api.ssh import exec_ssh, connect_ssh\n\nimport json\nimport logging\nimport string\nimport subprocess\nimport uuid\n\nfrom api.models import Layer\nfrom api.models import Node\n\nlogger = logging.getLogger(__name__)\n\nCONTRIB_PATH = '/app/deis/contrib/vagrant'\n\n# Collect details for connecting to the host machine\ntry:\n    HOST_NODES_DIR = open('{}/.host_nodes_dir'.format(CONTRIB_PATH)).read().strip()\n    PKEY = open('{}/util/ssh_keys/id_rsa_vagrant-deis-controller'.format(CONTRIB_PATH)).read()\nexcept IOError as err:\n    logger.warn(err)\n\n\ndef seed_flavors():\n    \"\"\"Seed the database with default flavors for vagrant.\n\n    :rtype: list of dicts containing flavor data\n    \"\"\"\n    flavors = []\n    for m in ['512', '1024', '2048']:\n        flavors.append({\n            'id': \"vagrant-{}\".format(m),\n            'provider': 'vagrant',\n            'params': json.dumps({\n                'memory': m\n            })\n        })\n    return flavors\n\n\ndef build_layer(layer):\n    \"\"\"\n    Build a layer.\n\n    :param layer: a dict containing formation, id, params, and creds info\n    \"\"\"\n\n    # This can also be done with `deis layers:update` now.\n    layer_ = Layer.objects.get(id=layer['id'], formation__id=layer['formation'])\n    layer_.ssh_username = 'vagrant'\n    layer_.save()\n\n\ndef destroy_layer(layer):\n    \"\"\"\n    Destroy a layer.\n\n    :param layer: a dict containing formation, id, params, and creds info\n    \"\"\"\n    pass\n\n\ndef build_node(node):\n    \"\"\"\n    Build a node.\n\n    :param node: a dict containing formation, layer, params, and creds info.\n    :rtype: a tuple of (provider_id, fully_qualified_domain_name, metadata)\n    \"\"\"\n\n    # Can't use the vagrant UUID because it's not booted yet\n    uid = str(uuid.uuid1())\n\n    # Create a new Vagrantfile from a template\n    node['params'].setdefault('memory', '512')\n    template = open('/app/deis/contrib/vagrant/util/nodes_vagrantfile_template.rb')\n    raw = string.Template(template.read())\n    ip_addr = '192.168.61.' + str(Node.objects.all().count() + 100)\n    result = raw.substitute({\n        'id': uid,\n        'ipaddress': ip_addr,\n        'memory': node['params']['memory']\n    })\n\n    # Make a folder for the VM with its own Vagrantfile. Vagrant will then create a .vagrant folder\n    # there too when it first gets booted.\n    node_dir = HOST_NODES_DIR + '/' + uid\n    mkdir = 'mkdir -p \"{}\"'.format(node_dir)\n    cp_tpl = 'echo \"' + result.replace('\"', '\\\\\"') + '\" > \"{}/Vagrantfile\"'.format(node_dir)\n    _host_ssh(commands=[mkdir, cp_tpl], creds=node['creds'])\n\n    # Boot the VM\n    _run_vagrant_command(uid, args=['up'], creds=node['creds'])\n\n    # Copy the layer's public SSH key to the VM so that the Controller can access it.\n    _run_vagrant_command(\n        uid,\n        args=[\n            'ssh',\n            '-c',\n            '\"echo \\\\\"' + node['ssh_public_key'] + '\\\\\" >> /home/vagrant/.ssh/authorized_keys\"'\n        ],\n        creds=node['creds'],\n    )\n\n    provider_id = uid\n    metadata = {\n        'id': uid,\n        'fqdn': ip_addr,\n        'flavor': node['params']['memory']\n    }\n    return provider_id, ip_addr, metadata\n\n\ndef destroy_node(node):\n    \"\"\"\n    Destroy a node.\n\n    :param node: a dict containing a node's provider_id, params, and creds\n    \"\"\"\n\n    # This is useful if node creation failed. So that there's a record in the DB, but it has no\n    # ID associated with it.\n    if node['provider_id'] is None:\n        return\n\n    # Shut the VM down and destroy it\n    try:\n        _run_vagrant_command(node['provider_id'], args=['destroy', '--force'], creds=node['creds'])\n        node_dir = HOST_NODES_DIR + '/' + node['provider_id']\n\n        # Sanity check before `rm -rf`\n        if 'contrib/vagrant' not in node_dir:\n            raise RuntimeError(\n                \"Aborted node destruction: attempting to 'rm -rf' unexpected directory\")\n\n        # Completely remove the folder that contained the VM\n        rm_vagrantfile = 'rm \"{}/Vagrantfile\"'.format(node_dir)\n        rm_node_dir = 'rm -rf \"{}\"'.format(node_dir)\n        _host_ssh(commands=[rm_vagrantfile, rm_node_dir], creds=node['creds'])\n    except RuntimeError as err:\n        # If we couldn't cd to the node dir, just log that as a warning\n        if 'no such file or directory' in str(err).lower():\n            logger.warn(err)\n        else:\n            raise\n\n\ndef _run_vagrant_command(node_id, args=[], creds={}):\n    \"\"\"\n    args: A tuple of arguments to a vagrant command line.\n    e.g. ['up', 'my_vm_name', '--no-provision']\n    \"\"\"\n\n    cd = 'cd \"{}/{}\"'.format(HOST_NODES_DIR, node_id)\n    command = ['vagrant'] + [arg for arg in args if arg is not None]\n    return _host_ssh(commands=[cd, ' '.join(command)], creds=creds)\n\n\ndef _host_ssh(creds={}, commands=[]):\n    \"\"\"\n    Connect to the host machine. Namely the user's local machine.\n    \"\"\"\n    if creds == {}:\n        raise RuntimeError(\"No credentials provided to _host_ssh()\")\n    command = ' && '.join(commands)\n\n    # First check if we can access the host machine. It's likely that their\n    # IP address changes every time they request a DHCP lease.\n    # TODO: Find a way of passing this error onto the CLI client.\n    try:\n        subprocess.check_call([\n            'nc', '-z', '-w2', creds['host'], '22'\n        ], stderr=subprocess.PIPE)\n    except subprocess.CalledProcessError:\n        raise RuntimeError(\"Couldn't ping port 22 at host with IP \" + creds['host'])\n\n    ssh = connect_ssh(creds['user'], creds['host'], 22, PKEY, timeout=120)\n    result, status = exec_ssh(ssh, command)\n    if status > 0:\n        raise RuntimeError(\n            'SSH to Vagrant host error: ' + result.decode('utf-8') +\n            'Command: ' + command.decode('utf-8'))\n    return result\n", "path": "controller/provider/vagrant.py"}], "after_files": [{"content": "\"\"\"\nDeis cloud provider implementation for local vagrant setups.\n\"\"\"\n\nfrom __future__ import unicode_literals\n\nfrom api.ssh import exec_ssh, connect_ssh\n\nimport json\nimport logging\nimport string\nimport subprocess\nimport uuid\n\nfrom api.models import Layer\nfrom api.models import Node\n\nlogger = logging.getLogger(__name__)\n\nVAGRANT_UTIL_PATH = '/app/provider/vagrant-util'\n\n# Collect details for connecting to the host machine\ntry:\n    HOST_NODES_DIR = open('{}/.host_nodes_dir'.format(VAGRANT_UTIL_PATH)).read().strip()\n    PKEY = open('{}/ssh_keys/id_rsa_vagrant-deis-controller'.format(VAGRANT_UTIL_PATH)).read()\nexcept IOError as err:\n    logger.warn(err)\n\n\ndef seed_flavors():\n    \"\"\"Seed the database with default flavors for vagrant.\n\n    :rtype: list of dicts containing flavor data\n    \"\"\"\n    flavors = []\n    for m in ['512', '1024', '2048']:\n        flavors.append({\n            'id': \"vagrant-{}\".format(m),\n            'provider': 'vagrant',\n            'params': json.dumps({\n                'memory': m\n            })\n        })\n    return flavors\n\n\ndef build_layer(layer):\n    \"\"\"\n    Build a layer.\n\n    :param layer: a dict containing formation, id, params, and creds info\n    \"\"\"\n\n    # This can also be done with `deis layers:update` now.\n    layer_ = Layer.objects.get(id=layer['id'], formation__id=layer['formation'])\n    layer_.ssh_username = 'vagrant'\n    layer_.save()\n\n\ndef destroy_layer(layer):\n    \"\"\"\n    Destroy a layer.\n\n    :param layer: a dict containing formation, id, params, and creds info\n    \"\"\"\n    pass\n\n\ndef build_node(node):\n    \"\"\"\n    Build a node.\n\n    :param node: a dict containing formation, layer, params, and creds info.\n    :rtype: a tuple of (provider_id, fully_qualified_domain_name, metadata)\n    \"\"\"\n\n    # Can't use the vagrant UUID because it's not booted yet\n    uid = str(uuid.uuid1())\n\n    # Create a new Vagrantfile from a template\n    node['params'].setdefault('memory', '512')\n    template = open('{}/nodes_vagrantfile_template.rb'.format(VAGRANT_UTIL_PATH))\n    raw = string.Template(template.read())\n    ip_addr = '192.168.61.' + str(Node.objects.all().count() + 100)\n    result = raw.substitute({\n        'id': uid,\n        'ipaddress': ip_addr,\n        'memory': node['params']['memory']\n    })\n\n    # Make a folder for the VM with its own Vagrantfile. Vagrant will then create a .vagrant folder\n    # there too when it first gets booted.\n    node_dir = HOST_NODES_DIR + '/' + uid\n    mkdir = 'mkdir -p \"{}\"'.format(node_dir)\n    cp_tpl = 'echo \"' + result.replace('\"', '\\\\\"') + '\" > \"{}/Vagrantfile\"'.format(node_dir)\n    _host_ssh(commands=[mkdir, cp_tpl], creds=node['creds'])\n\n    # Boot the VM\n    _run_vagrant_command(uid, args=['up'], creds=node['creds'])\n\n    # Copy the layer's public SSH key to the VM so that the Controller can access it.\n    _run_vagrant_command(\n        uid,\n        args=[\n            'ssh',\n            '-c',\n            '\"echo \\\\\"' + node['ssh_public_key'] + '\\\\\" >> /home/vagrant/.ssh/authorized_keys\"'\n        ],\n        creds=node['creds'],\n    )\n\n    provider_id = uid\n    metadata = {\n        'id': uid,\n        'fqdn': ip_addr,\n        'flavor': node['params']['memory']\n    }\n    return provider_id, ip_addr, metadata\n\n\ndef destroy_node(node):\n    \"\"\"\n    Destroy a node.\n\n    :param node: a dict containing a node's provider_id, params, and creds\n    \"\"\"\n\n    # This is useful if node creation failed. So that there's a record in the DB, but it has no\n    # ID associated with it.\n    if node['provider_id'] is None:\n        return\n\n    # Shut the VM down and destroy it\n    try:\n        _run_vagrant_command(node['provider_id'], args=['destroy', '--force'], creds=node['creds'])\n        node_dir = HOST_NODES_DIR + '/' + node['provider_id']\n\n        # Sanity check before `rm -rf`\n        if 'contrib/vagrant' not in node_dir:\n            raise RuntimeError(\n                \"Aborted node destruction: attempting to 'rm -rf' unexpected directory\")\n\n        # Completely remove the folder that contained the VM\n        rm_vagrantfile = 'rm \"{}/Vagrantfile\"'.format(node_dir)\n        rm_node_dir = 'rm -rf \"{}\"'.format(node_dir)\n        _host_ssh(commands=[rm_vagrantfile, rm_node_dir], creds=node['creds'])\n    except RuntimeError as err:\n        # If we couldn't cd to the node dir, just log that as a warning\n        if 'no such file or directory' in str(err).lower():\n            logger.warn(err)\n        else:\n            raise\n\n\ndef _run_vagrant_command(node_id, args=[], creds={}):\n    \"\"\"\n    args: A tuple of arguments to a vagrant command line.\n    e.g. ['up', 'my_vm_name', '--no-provision']\n    \"\"\"\n\n    cd = 'cd \"{}/{}\"'.format(HOST_NODES_DIR, node_id)\n    command = ['vagrant'] + [arg for arg in args if arg is not None]\n    return _host_ssh(commands=[cd, ' '.join(command)], creds=creds)\n\n\ndef _host_ssh(creds={}, commands=[]):\n    \"\"\"\n    Connect to the host machine. Namely the user's local machine.\n    \"\"\"\n    if creds == {}:\n        raise RuntimeError(\"No credentials provided to _host_ssh()\")\n    command = ' && '.join(commands)\n\n    # First check if we can access the host machine. It's likely that their\n    # IP address changes every time they request a DHCP lease.\n    # TODO: Find a way of passing this error onto the CLI client.\n    try:\n        subprocess.check_call([\n            'nc', '-z', '-w2', creds['host'], '22'\n        ], stderr=subprocess.PIPE)\n    except subprocess.CalledProcessError:\n        raise RuntimeError(\"Couldn't ping port 22 at host with IP \" + creds['host'])\n\n    ssh = connect_ssh(creds['user'], creds['host'], 22, PKEY, timeout=120)\n    result, status = exec_ssh(ssh, command)\n    if status > 0:\n        raise RuntimeError(\n            'SSH to Vagrant host error: ' + result.decode('utf-8') +\n            'Command: ' + command.decode('utf-8'))\n    return result\n", "path": "controller/provider/vagrant.py"}]}