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

PythonSshFabric

Python Problem Overview


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?

Python Solutions


Solution 1 - Python

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

Solution 2 - Python

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.

Solution 3 - Python

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.

Solution 4 - Python

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()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBrian M. HuntView Question on Stackoverflow
Solution 1 - PythonrbpView Answer on Stackoverflow
Solution 2 - PythonMrDView Answer on Stackoverflow
Solution 3 - PythonMorganView Answer on Stackoverflow
Solution 4 - PythonjmuView Answer on Stackoverflow