Repository: dask/distributed

Issue:
Problem with dask-ssh in combination with hostnames
When starting a distributed cluster with dask-ssh, the hostnames supplied via commandline or hostfile are passed to the workers with the `--host` parameter. This might be useful for the bokeh interface on the scheduler, but in our case the worker binds to the local interface only (the hostname is listed in the `/etc/hosts` with `127.0.0.1`), so a connection from the scheduler to the worker is not possible (maybe I am wrong and this is somehow not needed, but I receive errors about failed connects).

A possible solution is to provide IP-Adresses, because with that the worker binds to the correct interface. For me this is less optimal, as I cannot easily see where I start my workers.

My quick and dirty fix was to remove the `host` option from the worker start call.

So I would like to suggest adding an option to `dask-ssh` to prevent using the `host` option when spawning a worker (as this works perfectly fine in internal networks where some open ports are not such a big problem).

If you are interested in this `dask-ssh` option, I would implement this in a proper way and create a PR.


Discussion:
Hi @malteger .  Adding such an option makes sense to me.  A PR would be most welcome.

Resolving patch:
diff --git a/distributed/cli/dask_ssh.py b/distributed/cli/dask_ssh.py
--- a/distributed/cli/dask_ssh.py
+++ b/distributed/cli/dask_ssh.py
@@ -29,12 +29,13 @@
               help="Port to use for SSH connections.")
 @click.option('--ssh-private-key', default=None, type=str,
               help="Private key file to use for SSH connections.")
-
+@click.option('--nohost', is_flag=True,
+              help="Do not pass the hostname to the worker.")
 @click.option('--log-directory', default=None, type=click.Path(exists=True),
               help="Directory to use on all cluster nodes for the output of dask-scheduler and dask-worker commands.")
 @click.pass_context
 def main(ctx, scheduler, scheduler_port, hostnames, hostfile, nthreads, nprocs,
-          ssh_username, ssh_port, ssh_private_key, log_directory):
+          ssh_username, ssh_port, ssh_private_key, nohost, log_directory):
     try:
         hostnames = list(hostnames)
         if hostfile:
@@ -50,7 +51,7 @@ def main(ctx, scheduler, scheduler_port, hostnames, hostfile, nthreads, nprocs,
         exit(1)
 
     c = SSHCluster(scheduler, scheduler_port, hostnames, nthreads, nprocs,
-                ssh_username, ssh_port, ssh_private_key, log_directory)
+                ssh_username, ssh_port, ssh_private_key, nohost, log_directory)
 
     import distributed
     print('\n---------------------------------------------------------------')
diff --git a/distributed/deploy/ssh.py b/distributed/deploy/ssh.py
--- a/distributed/deploy/ssh.py
+++ b/distributed/deploy/ssh.py
@@ -184,9 +184,12 @@ def start_scheduler(logdir, addr, port, ssh_username, ssh_port, ssh_private_key)
     return merge(cmd_dict, {'thread': thread})
 
 def start_worker(logdir, scheduler_addr, scheduler_port, worker_addr, nthreads, nprocs,
-                 ssh_username, ssh_port, ssh_private_key):
+                 ssh_username, ssh_port, ssh_private_key, nohost):
 
-    cmd = '{python} -m distributed.cli.dask_worker {scheduler_addr}:{scheduler_port} --host {worker_addr} --nthreads {nthreads} --nprocs {nprocs}'.format(
+    cmd = '{python} -m distributed.cli.dask_worker {scheduler_addr}:{scheduler_port} --nthreads {nthreads} --nprocs {nprocs}'
+    if not nohost:
+        cmd += ' --host {worker_addr}'
+    cmd = cmd.format(
         python = sys.executable,
         scheduler_addr = scheduler_addr, scheduler_port = scheduler_port,
         worker_addr = worker_addr,
@@ -221,7 +224,8 @@ def start_worker(logdir, scheduler_addr, scheduler_port, worker_addr, nthreads,
 
 class SSHCluster(object):
     def __init__(self, scheduler_addr, scheduler_port, worker_addrs, nthreads = 0, nprocs = 1,
-                 ssh_username = None, ssh_port = 22, ssh_private_key = None, logdir = None):
+                 ssh_username = None, ssh_port = 22, ssh_private_key = None,
+                 nohost = False, logdir = None):
 
         self.scheduler_addr = scheduler_addr
         self.scheduler_port = scheduler_port
@@ -232,6 +236,8 @@ def __init__(self, scheduler_addr, scheduler_port, worker_addrs, nthreads = 0, n
         self.ssh_port = ssh_port
         self.ssh_private_key = ssh_private_key
 
+        self.nohost = nohost
+
         # Generate a universal timestamp to use for log files
         import datetime
         if logdir is not None:
@@ -276,7 +282,7 @@ def monitor_remote_processes(self):
 
     def add_worker(self, address):
         self.workers.append(start_worker(self.logdir, self.scheduler_addr, self.scheduler_port, address, self.nthreads,
-                                         self.nprocs, self.ssh_username, self.ssh_port, self.ssh_private_key))
+                                         self.nprocs, self.ssh_username, self.ssh_port, self.ssh_private_key, self.nohost))
 
     def shutdown(self):
         all_processes = [self.scheduler] + self.workers


Test patch: