Connecting to a host listed in ~/.ssh/config when using Fabric

Question:

I’m having trouble with Fabric not recognizing hosts that I have in ~/.ssh/config.

My fabfile.py is as follows:

from fabric.api import run, env

env.hosts = ['lulu']

def whoami():
    run('whoami')

Running $ fab whoami gives:

[lulu] run: whoami

Fatal error: Name lookup failed for
lulu

The name lulu is in my ~/.ssh/config, like this:

Host lulu
     hostname 192.168.100.100
     port 2100
     IdentityFile ~/.ssh/lulu-key

My first thought to solving this is adding something like lulu.lulu to /etc/hosts (I’m on a Mac), but then I have to also pass in the identity file to Fabric – and I’d rather keep my authentication (i.e. ~/.ssh/config) separate from my deployment (i.e. fabfile.py).

As well, incidentally, if you try to connect to a host in the hosts file, fabric.contrib.projects.rsync_project doesn’t seem to acknowledge ‘ports’ in the hosts.env (i.e. if you use hosts.env = [lulu:2100] a call to rsync_project seems to try connecting to lulu:21).

Is there a reason Fabric doesn’t recognize this lulu name?

Asked By: Brian M. Hunt

||

Answers:

update: This Answer is now outdated.


Fabric doesn’t have support currently for the .ssh/config file. You can set these up in a function to then call on the cli, eg: fab production task; where production sets the username, hostname, port, and ssh identity.

As for rsync project, that should now have port setting ability, if not, you can always run local(“rsync …”) as that is essentially what that contributed function does.

Answered By: Morgan

Note that this also happens when the name is not in /etc/hosts. I had the same problem and had to add the host name to both that file and ~/.ssh/config.

Answered By: MrD

One can use following code to read the config (original code taken from: http://markpasc.typepad.com/blog/2010/04/loading-ssh-config-settings-for-fabric.html):

from fabric.api import *
env.hosts = ['servername']

def _annotate_hosts_with_ssh_config_info():
    from os.path import expanduser
    from paramiko.config import SSHConfig

    def hostinfo(host, config):
        hive = config.lookup(host)
        if 'hostname' in hive:
            host = hive['hostname']
        if 'user' in hive:
            host = '%s@%s' % (hive['user'], host)
        if 'port' in hive:
            host = '%s:%s' % (host, hive['port'])
        return host

    try:
        config_file = file(expanduser('~/.ssh/config'))
    except IOError:
        pass
    else:
        config = SSHConfig()
        config.parse(config_file)
        keys = [config.lookup(host).get('identityfile', None)
            for host in env.hosts]
        env.key_filename = [expanduser(key) for key in keys if key is not None]
        env.hosts = [hostinfo(host, config) for host in env.hosts]

        for role, rolehosts in env.roledefs.items():
            env.roledefs[role] = [hostinfo(host, config) for host in rolehosts]

_annotate_hosts_with_ssh_config_info()
Answered By: jmu

Since version 1.4.0, Fabric uses your ssh config (partly). However, you need to explicitly enable it, with

env.use_ssh_config = True

somewhere near the top of your fabfile. Once you do this, Fabric should read your ssh config (from ~/.ssh/config by default, or from env.ssh_config_path).

One warning: if you use a version older than 1.5.4, an abort will occur if env.use_ssh_config is set but there is no config file present. In that case, you can use a workaround like:

if env.ssh_config_path and os.path.isfile(os.path.expanduser(env.ssh_config_path)):
    env.use_ssh_config = True
Answered By: rbp
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.