Łączenie się z hostem wymienionym w ~ / .ssh / config podczas korzystania z Fabric

83

Mam problem z Fabricnierozpoznaniem hostów, na których się znajduję ~/.ssh/config.

Mój fabfile.pyjest następujący:

from fabric.api import run, env

env.hosts = ['lulu']

def whoami():
    run('whoami')

Bieganie $ fab whoamidaje:

[lulu] run: whoami

Błąd krytyczny: wyszukiwanie nazwy dla lulu nie powiodło się

Imię lulujest w moim ~/.ssh/config, na przykład:

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

Moja pierwsza myśl, aby rozwiązać ten jest dodanie czegoś podobnego lulu.luludo /etc/hosts(jestem na komputerze Mac), ale potem muszę też przejść w pliku tożsamości na tkaninę - i wolałbym, aby moje uwierzytelniania (tj ~/.ssh/config) oddzielić od mojego rozmieszczenia ( ie fabfile.py).

Poza tym, nawiasem mówiąc, jeśli próbujesz połączyć się z hostem w pliku hosts, fabric.contrib.projects.rsync_projectnie wydaje się potwierdzać „portów” w hosts.env(tj. Jeśli używasz hosts.env = [lulu:2100]wywołania do rsync_projectwydaje się próbować się połączyć lulu:21).

Czy jest jakiś powód, dla którego Fabric nie rozpoznaje tej lulunazwy?

Brian M. Hunt
źródło

Odpowiedzi:

145

Od wersji 1.4.0 Fabric używa (częściowo) twojej konfiguracji ssh . Musisz jednak jawnie włączyć to za pomocą

env.use_ssh_config = True

gdzieś blisko początku twojego pliku fabfile. Gdy to zrobisz, Fabric powinien odczytać konfigurację ssh ( ~/.ssh/configdomyślnie lub z env.ssh_config_path).

Jedno ostrzeżenie: jeśli używasz wersji starszej niż 1.5.4, nastąpi przerwanie, jeśli env.use_ssh_configjest ustawione, ale nie ma pliku konfiguracyjnego. W takim przypadku możesz zastosować obejście, takie jak:

if env.ssh_config_path and os.path.isfile(os.path.expanduser(env.ssh_config_path)):
    env.use_ssh_config = True
rbp
źródło
Odpowiedź pierwotnie zaczynała się od „Zaakceptowana odpowiedź jest nieaktualna” [ponieważ dokumentuje zachowanie sprzed wersji 1.4.0]. Usunąłem tę przedmowę, ponieważ zamiast tego moja odpowiedź została zaakceptowana;) Dzięki!
rbp
9

Zwróć uwagę, że dzieje się tak również wtedy, gdy nazwy nie ma /etc/hosts. Miałem ten sam problem i musiałem dodać nazwę hosta zarówno do tego pliku, jak i ~/.ssh/config.

MrD
źródło
5

aktualizacja : ta odpowiedź jest już nieaktualna .


Fabric nie obsługuje obecnie pliku .ssh / config. Możesz ustawić je w funkcji, aby następnie wywoływały cli, np .: zadanie produkcyjne fab; gdzie produkcja ustawia nazwę użytkownika, nazwę hosta, port i tożsamość ssh.

Jeśli chodzi o projekt rsync, powinien on teraz mieć możliwość ustawiania portu, jeśli nie, zawsze możesz uruchomić lokalny ("rsync ..."), ponieważ jest to zasadniczo to, co robi ta funkcja dodana.

Morgan
źródło
1
Ustaw env.key_filename na pełną ścieżkę klucza prywatnego. Jeśli napotkasz problemy, zobacz code.fabfile.org/issues/show/265, aby zapoznać się z kilkoma problemami.
tobych
1
Tak, teraz ma wsparcie. (chociaż było to przed 1.0, kiedy komentowałem) Uwaga dla późniejszych czytelników.
Morgan
4

Do odczytania konfiguracji można użyć następującego kodu (oryginalny kod pobrany z: 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()
jmu
źródło
1
Tkanina 1.2+ korzysta z sshbiblioteki ( paramikowidelca):try: \n from ssh.config import SSHConfig \n except ImportError: \n from paramiko.config import SSHConfig
jfs
Biblioteka SSH została ponownie włączona do Paramiko, np.from paramiko.config import SSHConfig
n8henrie,