среда, 30 января 2013 г.

Fabric: Модель выполнения

Если Вы читали руководство, то Вы должны быть уже знакомы с тем, как Fabric работает (с одной задачей на одном хосте). Однако, во многих ситуациях Вы можете захотеть выполнить несколько задач и/или на нескольких хостах. Возможно, Вы захотите разделить одну большую задачу на несколько маленьких, или обойти список серверов в поисках тех, на которых надо удалить выбранного пользователя. Все эти сценарии требуют некоторых правил о том, как и когда выполняются задачи.
Этот документ описывает модель выполнения Fabric, включая главный цикл выполнения, определение списка хостов, создание подключений и т.д.

Стратегия выполнения

По умолчанию Fabric работает в одиночном, последовательном режиме выполнения, хотя, начиная с версии 1.3, доступна параллельная модель выполнения (см параллельное выполнение). Поведение по умолчанию заключается в следующем:
  • Создаётся список задач. На данный момент это просто список аргументов, переданных fab'y, сохраняя порядок аргументов
  • Для каждой задачи из разных источников создаётся список хостов (подробнее см "Как создаётся список хостов" ниже)
  • Проходится список задач, каждая задача запускается один раз для каждого хоста в списке
  • Задачи, для которых нет хостов в списке хостов, выполняются только локально и всегда запускаются только один раз
Таким образом, если у нас есть следующий fabfile:
    from fabric.api import run, env

    env.hosts = ['host1', 'host2']

    def taskA():
        run('ls')

    def taskB():
        run('whoami')
и мы выполняем команду:
 $ fab taskA taskB
мы увидим, что Fabric выполнит следующее:
  • taskA выполняется на host1
  • taskA выполняется на host2
  • taskB выполняется на host1
  • taskB выполняется на host2
Хотя это и упрощённый подход, он позволяет очевидно сопоставить задачи и хосты и (в отличие от инструментов, которые запускают задачу сразу на нескольких узлах) позволяют реализовать логику скрипта, где Вы проверяете результат выполнения предыдущей команды и на основании этого решаете что делать дальше.

Определение задач

Подробнее о том, что такое задачи Fabric и с чем их едят, смотрите "Определение задач"

Определение списка хостов

Если только Вы не используете Fabric как просто систему запуска локальных скриптов (что возможно, но не является его основной задачей), наличие задач без возможности определить хосты для их выполнения было бы малополезным. Есть несколько способов сделать это, область воздействия этих методов меняется от глобальной до "только на одну задачу" и их можно смешивать в нужных пропорциях.

Хосты

Хостами, в данном контексте, называется то, что обычно называется "строками хостов": строка, которая определяет имя пользователя, имя хоста и номер порта: `username@hostname:port`. Пользователя и порт (и, соответственно, `@` и `:`) могут быть опущены; в таком случае будет использоваться локальное имя пользователя и порт 22. Таким образом, "admin@foo.com:222", "deploy@website" и "nameserver1" могут быть использованы в качестве строк хостов.
Так же поддерживается нотация IPv6, например, "::1", "[::1]:1222", "user@2001:db8::1" или "user@[2001:db8::1]:1222". Квадратные скобки нужны только для того, чтобы отделить адрес от номера порта. Если номер порта не указан, то скобки тоже можно не использовать. Кроме того, если строка хоста задаётся через командную строку, то в некоторых оболочках может потребоваться экранировать эти скобки.
Примечание: Раздел между именем пользователя и именем хоста происходит по последнему найденному знаку @, так что можно вполне использовать email адрес в качестве имени пользователя.
В процессе выполнения Fabric нормализует полученную строку хоста и затем сохраняет каждую часть (имя пользователя / имя хоста / порт) в словаре окружения и для их использования и для того, чтобы задачи по необходимости могли на них сослаться. Более детально смотри в "Словарь окружения".

Роли

Строка хоста определяют один хост, но иногда бывает полезно объединить хосты в группы. Возможно, у Вас есть несколько Web серверов за балансировщиком нагрузки, и Вы хотите обновить их все; или Вы хотите запустить задачу на "всех клиентских серверах". Роли позволяют Вам определить строки, которые будут соответствовать списку строк хостов, и их потом можно использовать вместо перечисления всех этих узлов.
Такое отображение определяется как словарь, env.roledefs, который должен быть изменён fabfile перед использованием. Вот простой пример:
    from fabric.api import env

    env.roledefs['webservers'] = ['www1', 'www2', 'www3']
Так как env.roledefs по умолчанию пуст, Вы можете спокойно изменить его, не боясь потерять информацию (понятно, если Вы не используете другие fabfile, которые тоже изменяют этот словарь):
    from fabric.api import env

    env.roledefs = {
        'web': ['www1', 'www2', 'www3'],
        'dns': ['ns1', 'ns2']
    }
Значениями в env.roledefs могут быть не только итерируемыми объектами, но и вызываемыми, и потому могут быть вызваны при выполнении задачи, а не при загрузке модуля. (Например, Вы можете подключиться к удалённому серверу для того, чтобы получить определения ролей и не беспокоиться о задержке при загрузке файла при выполнении, например, fab --list.)
Использование ролей вовсе не обязательно, это лишь более удобный способ работы в ситуации, когда у Вас есть группы серверов.
Изменение в версии 0.9.2 Добавлена возможность использовать вызываемые объекты в качестве значений roledefs

Как создаётся список хостов

Есть несколько способов создать список хостов, глобальный или локальный, для задачи, и обычно каждый из этих методов перезаписывает другой, вместо того, чтобы объединять полученные списки (но это может быть изменено в будущих релизах). Каждый такой метод обычно состоит из двух частей - одна для узлов, другая - для ролей.
Глобально, при помощи env
Наиболее используемый метод создания списка хостов или ролей - изменение двух значений в словаре окружения env: hosts и roles. Значения этих переменных проверяется в процессе выполнения, когда и создаётся список хостов для каждой задачи.
Таким образом, это можно сделать на уровне модуля, что возымеет эффект при импорте fabfile:
    from fabric.api import env, run

    env.hosts = ['host1', 'host2']

    def mytask():
        run('ls /var/www')
Такой fabfile, запущенный как fab mytask, запустит mytask на host1, а, затем, на host2.
Так как переменная env проверяется для каждой задачи, это означает, что Вы можете изменить env в одной задаче и это будет влиять на все следующие задачи:
    from fabric.api import env, run

    def set_hosts():
        env.hosts = ['host1', 'host2']

    def mytask():
        run('ls /var/www')
Когда Вы запустите fab set_hosts mytask, set_hosts является локальной задачей, так как его список хостов пуст, но mytask будет запущен уже для двух указанных узлов.
Примечание: Этот метод раньше использовался для создания фиктивных ролей, но при возможности создать обычные роли такая потребность отпала. Но его всё ещё можно использовать в некоторых случаях.
Рядом с env.hosts расположен env.roles (не путать с env.roledefs), который, если задан, используется как список имён ролей для обращения к env.roledefs.
Глобально, через командную строку
Кроме изменения env.hosts, env.roles и env.exclude_hosts на уровне модуля, Вы можете задать их при помощи аргументов командной строки в виде строки с разделителем - запятой: -H/--hosts и -R/--roles:
$ fab -H host1,host2 mytask
Такой вызов эквивалентен env.hosts = ['host1','host2'].
Примечание: Эти опции можно использовать (и часто так и делают) для указания только одного узла или роли. Fabirc просто вызывает string.split(',') над полученной строкой, так что строка без запятых превращается в список с одним элементом.
Важно знать, что эти опции обрабатываются до того, как загружается ваш fabfile, так что все присвоения значений env.hosts или env.roles в вашем файле будут переопределять полученные аргументы.
Если Вы хотите слить списки из командной строки и определённые в fabfile, убедитесь, что Вы используете env.hosts.extend():
    from fabric.api import env, run

    env.hosts.extend(['host3', 'host4'])

    def mytask():
        run('ls /var/www')
Когда Вы запустите этот fabfile c опциями командной строки: fab -H host1,host2 mytask, env.hosts будет содержать `['host1','host2','host3','host4']` к моменту выполнения mytask.
Примечание: env.hosts - простой список Python, так что Вы можете использовать и env.hosts.append() или любой другой метод списков.
Определение хостов для конкретной задачи в командной строке
Глобальные списки хостов полезны только если Вы хотите, чтобы все ваши задачи выполнялись на одном и том же списке узлов. Но, поскольку, это не всегда так, Fabric предоставляет несколько методов более точно указания узлов для выполнения конкретной задачи. Первый - использование аргументов задачи.
Как указано в "Опции и аргументы fab", возможно задать аргументы для конкретной задачи при помощи специального синтаксиса командной строки. Кроме того, чтобы передавать аргументы вашим задачам, это можно использовать и для задания "аргументов" host, hosts, role или roles, которые интерпретируются Fabric при создании списка хостов (и они удаляются из аргументов, передаваемых самой задаче.)
Примечание: Так как запятые уже используются для разделения аргументов, в качестве разделителей строк хостов в аргументах hosts или roles должны использоваться точки с запятой. Более того, аргумент должен быть заключён в кавычки, чтобы ваши точки с запятой не были интерпретированы оболочкой.
Возьмём такой fabfile, который похож на используемый ранее, но в котором не определены хосты:
    from fabric.api import run

    def mytask():
        run('ls /var/www')
Для того, чтобы определить узел для задачи mytask используйте такую команду:
    $ fab mytask:hosts="host1;host2"
Это переопределит все другие списки хостов и mytask всегда будет запускаться только на этих двух узлах.
Определение хостов для конкретной задачи при помощи декораторов
Если данная задача всегда должна выполняться на определённом списке узлов, Вы можете захотеть определить их в самом fabfile. Это можно сделать декорируя задачу при помощи декораторов hosts или roles. Эти декораторы принимают список аргументов:
    from fabric.api import hosts, run

    @hosts('host1', 'host2')
    def mytask():
        run('ls /var/www')
Или один итерируемый аргумент:
    my_hosts = ('host1', 'host2')
    @hosts(my_hosts)
    def mytask():
        # ...
Когда используются декораторы, они переопределяют все проверки env для списка хостов этой задачи (хотя сам env не изменяется - просто игнорируется). Таким образом, даже если выше в fabfile Вы определили env.hosts или вызвали fab c опцией -H/--hosts,  mytask будет всё равно запущен на узлах host1 и host2.
Тем не менее, декоратор не переопределяет аргумент командной строки для этой задачи, о чём говорилось в предыдущем разделе.
Старшинство
Мы показали несколько методов указания хостов и сказали, какой из них какой переопределяет. Но, для пущей ясности, подведём тут краткий итог:
  • Для конкретной задачи, список хостов, передаваемый через аргументы командной строки (fab mytask:host=host1), переопределяет вообще всё.
  • Для конкретной задачи, список хостов, определяемый в декораторе (@hosts('host1')), переопределяет переменную env.
  • Глобально определённый список узлов, заданный в fabfile (env.hosts = ['host1']) может переопределить список хостов из командной строки, но только если Вы специально так сделали (или же допустили ошибку)
  • Глобально определённый список узлов из командной строки (--hosts=host1) лишь инициализирует переменную env.
В будущем такой подход может измениться, чтобы быть более логичным (например, чтобы опция --hosts имела преимущество над env.hosts, так же как аргументы командной строки для конкретной задачи имеют преимущество над значениями, определёнными в коде), но только в релизах, без обратной совместимости.

Комбинация списков хостов

Списки узлов из разных источников не объединяются. Если значением env.hosts является ['host1','host2','host3'], а список хостов, определённый для задачи, например, через декоратор - ['host2','host3'], то эта задача не будет выполнена на host1, так как узлы, определённые в декораторе переопределяют значение из переменной окружения.
Однако, для каждого источника, если определены и hosts и roles, то их значения сливаются в один список узлов. Возьмём для примера fabfile, который мы использовали для декораторов:
    from fabric.api import env, hosts, roles, run

    env.roledefs = {'role1': ['b', 'c']}

    @hosts('a', 'b')
    @roles('role1')
    def mytask():
        run('ls /var/www')
Предположим, что для исполнения mytask в командной строке не указаны ни hosts ни roles. В таком случае этот fabfile выполнится на узлах ['a','b','c'] - объединении role1 и содержимого декоратора hosts.

Дедупликация

По умолчанию, для поддержки объединения списков хостов, Fabric производит дедупликацию итогового списка, так что каждая строка хоста будет присутствовать в итоговом списке только раз. Это не допускает умышленного выполнения той же самой задачи несколько раз на одном и том же хосте, что иногда может быть полезно.
Для того, чтобы отключить дедупликацию установите env.dedupe_hosts в False

Удаление определённых узлов

Иногда бывает полезно исключить один или более хостов, т.е. убрать несколько плохих или по другим причинам негодных узлов, которые упоминаются в ролях или сгенерированном листе узлов.
Примечание: В Fabric 1.4 Вы можете использовать вместо этого skip-bad-hosts, в этом случае недоступные хосты будут игнорированы
Исключение узлов может быть достигнуто глобально опцией --exclude-hosts/-x
    $ fab -R myrole -x host2,host5 mytask
Если myrole определена как ['host1','host2',...,'host15'], то вызов выше выполнит задачу на списке узлов ['host1','host3','host4','host6',...,'host15'].
Примечание: использование этой опции не модифицирует env.hosts - эти узлы лишь исключаются в процессе выполнения задачи
Исключить узлы можно и для отдельной задачи при помощи именованного аргумента exclude_hosts, который используется аналогично аргументам hosts и roles. Этот пример будет иметь тот же результат, что и пример выше:
    $ fab mytask:roles=myrole,exclude_hosts="host2;host5"
Обратите внимание, что в списке в качестве разделителя опять используются точка с запятой.

Комбинация исключений

Список хостов для исключения, так же как и список хостов, не взаимодействует со списками, полученными с других уровней. Например, опция -x не будет влиять на список хостов, указанных в декораторе или в именованном аргументе, а именованный аргумент exlude_hosts не будет влиять на список, полученный через -H.
Есть только одно маленькое исключение из этого правила, а именно, именованные аргументы уровня CLI (mytask:exclude_hosts=x,y) будет учтён в списках хостов, заданных через @hosts или @roles. Таким образом, задача, декорированная при помощи @hosts('host1','host2'), выполненное через fab taskname:exclude_hosts=host2, будет запущен только на host1.
Как и в случае с объединением списков, эта функциональность на данный момент ограничена (в частности, для облегчения реализации) и может быть изменена в будущих релизах.

Интеллектуальное выполнение задач при помощи execute

Добавлено в версии 1.3
Большая часть информации, приведённой здесь, касается задач "верхнего уровня", выполняемых через fab, таких как наш первый пример, где мы вызывали fab taskA taskB. Однако, часто удобно обернуть вызов нескольких задач, как в нашем примере, в свою собственную задачу meta.
До Fabric 1.3 это надо было делать вручную, как об этом говорится в Library Use. Дизайн Fabric воздерживается от магического поведения, так что простой вызов задачи не принимает во внимание декораторы, такие как roles.
Начиная с Fabric 1.3 вспомогательная функция execute, принимающая в качестве аргумента имя или объект задачи. Её используют так же, как и вызывают задачу из командной строки: к ним применяются все те же правила, которые мы приводили выше в разделе "как создаются списки хостов". (Именованные аргументы hosts и roles для execute аналогичны аргументам CLI для задачи, включая то, как они переопределяют все остальные настройки host/role.)
В качестве примера возьмём fabfile, который определяет две отдельные задачи для развёртывания Web приложения:
    from fabric.api import run, roles

    env.roledefs = {
        'db': ['db1', 'db2'],
        'web': ['web1', 'web2', 'web3'],
    }

    @roles('db')
    def migrate():
        # Database stuff here.
        pass

    @roles('web')
    def update():
        # Code updates here.
        pass
В Fabric версии 1.2 и раньше, единственный способ убедиться, что migrate запускается на серверах БД, а update - на Web серверах - было вызвать обе задачи как задачи "верхнего уровня":
    $ fab migrate update
В версиях начиная от 1.3 Вы можете использовать execute для создания мета-задачи. Обновим инструкцию import:
    from fabric.api import run, roles, execute
и добавим это в конец файла:
    def deploy():
        execute(migrate)
        execute(update)
Вот и всё. Декораторы будут работать, как и ожидается, в результате чего будут выполнены:
  • migrate на db1
  • migrate на db2
  • update на web1
  • update на web2
  • update на web3
Предупреждение: эта техника работает так как задачи, у которых нет списка узлов (даже глобального списка) выполняются только один раз. Если это используется в "обычной" задаче, которая запускается на нескольких хостах, вызов execute также будет вызван несколько раз, в результате чего будет вызваны несколько раз подзадачи - будьте осторожны. Если Вы хотите, чтобы ваш вызов execute происходил только один раз, Вам нужно использовать декоратор runs_once.
См также: executeruns_once

Использование execute c динамически создаваемым списком хостов

Ещё одно частое применение Fabric продвинутыми пользователями - параметризация поиска списка узлов в процессе выполнения (когда использование ролей недостаточно). execute может сильно облегчить это:
    from fabric.api import run, execute, task

    # Например, код, работающий с HTTP API, или БД, или ...
    from mylib import external_datastore

    # Это сам алгоритм, который вообще не думает о списке узлов
    def do_work():
        run("something interesting on a host")

    # Задача, вызываемая из командной строки
    @task
    def deploy(lookup_param):
        # Вот то, чего Вы не добьётесь при помощи @hosts или @roles.
        # Даже "ленивые" роли требуют сперва объявления доступных ролей
        # Тут же нет никаких ограничений
        host_list = external_datastore.query(lookup_param)
        # Используем динамический список вместе с задачей
        execute(do_work, hosts=host_list)
Например, если "external_datastore" просто получает список узлов по некоторому тегу и Вы хотите выполнить задачу на всех серверах, относящихся к вашему приложения, Вы можете просто сделать так:
    $ fab deploy:app
Но постойте! Что-то не так пошло на серверах БД. Давайте обновим код миграции и запустим обновление только на нужных серверах:
    $ fab deploy:db
Такое использование похоже на роли Fabric, но имеет гораздо больше возможностей и при этом не ограничен только одним аргументом. Определите задачу так, как Вам нужно, получите из вашей БД то, что Вам нужно - это лишь Python.

Альтернативный подход

Похожим на то, о чём мы только что говорили, но с использованием способности fab вызывать поочерёдно несколько задач без явного вызова - заменить env.hosts на задачу поиска списка узлов и затем вызвать do_work в той же самой сессии:
    from fabric.api import run, task

    from mylib import external_datastore

    # Отмечена как публично видимая задача, но о списке хостов
    # пусть подумает кто-то другой
    @task
    def do_work():
        run("something interesting on a host")

    @task
    def set_hosts(lookup_param):
        # Обновляем env.hosts вместо вызова execute()
        env.hosts = external_datastore.query(lookup_param)
Теперь мы можем сделать так:
    $ fab set_hosts:app do_work
Преимуществом этого подхода по отношению к предыдущему варианту является то, что Вы можете спокойно do_work на любую другую задачу:
    $ fab set_hosts:db snapshot
    $ fab set_hosts:cassandra,cluster2 repair_ring
    $ fab set_hosts:redis,environ=prod status

Обработка ошибок

После того, как список задач составлен, Fabric начнёт выполнять его, как это описано в "Стратегии выполнения", пока все задачи не будут выполнены на всех узлах из списка для каждой задачи. По умолчанию Fabric работает по принципу "быстрой ошибки" - как только удалённая программа возвращает ненулевое значение или ваш код Python в fabfile возбуждает исключение выполнение задач тут же прекращается.
Обычно это ровно то, что нужно, но, как и в каждом правиле, тут есть свои исключения, так что Fabric даёт Вам настройку env.warn_only. Значение по умолчанию False означает, что при ошибке выполнение скрипта будет тут же прервано. Если же значением является True - то при возникновении ошибки Fabric выдаст предупреждение, но выполнение скрипта будет продолжено.

Подключения

Сам по себе fab не делает никаких подключений к удалённым узлам. Вместо этого он лишь проверяет для каждого запуска задачи на каждом узле, что переменная env.host_string имеет корректное значение. Пользователи, желающие использовать Fabric как библиотеку могут вручную добиться того же эффекта (хотя в Fabric 1.3 использовать execute предпочтительнее и даёт больше возможностей.)
env.host_string, как и следует из названия, текущая строка узла и её и использует Fabric для определения того, как подключиться к узлу при использовании сетевых функций. Операции вроде run или put используют env.host_string в качестве ключа поиска в общем словаре, которые отражает строки узлов на объекты подключений SSH.
Примечание: Словарь подключений (на данный момент он расположен в fabric.state.connections) работает как кэш, возвращая уже созданные подключения, если можно, для экономии времени, или создавая новые.

"Ленивые" подключения

Так как подключения определяются конкретными операциями, Fabric не будет создавать подключения, пока они не понадобятся. Возьмём для примера задачу, которая делает что-то локально до того, как она начинает взаимодействовать с удалённым сервером:
    from fabric.api import *

    @hosts('host1')
    def clean_and_upload():
        local('find assets/ -name "*.DS_Store" -exec rm '{}' \;')
        local('tar czf /tmp/assets.tgz assets/')
        put('/tmp/assets.tgz', '/tmp/assets.tgz')
        with cd('/var/www/myapp/'):
            run('tar xzf /tmp/assets.tgz')
Вот как это происходит:
  • Два вызова local будут произведены без создания подключений
  • put запросит кэш подключений в поисках подключения к host1
  • Кэш подключений не найдёт существующего подключения для этой строки хоста, так что будет создано новое SSH подключение, которое и будет возвращено операции put
  • put передаст файл через это подключение
  • Наконец, run запрашивает кэш в поисках подключения для той же самой строки, откуда его и получает
Таким образом, задача, которая не использует сетевых задач, вообще не будет создавать подключений (но она будет всё равно выполнена для каждого узла в списке)

Закрытие соединения

Кэш соединений Fabric сам никогда не закрывает соединения - они остаются открытыми для возможного дальнейшего использования. fab делает это для Вас сам: перед завершением скрипта он обходит все открытые подключения и закрывает их (вне зависимости от результата завершения задач).
Пользующиеся Fabric как библиотекой должны сами убедиться, что перед завершением скрипта все подключения будут закрыты. Сделать это можно при помощи вызова disconnect_all в конце скрипта.
Примечание: disconnect_all может быть перемещён в более доступное место в будущем. Мы всё ещё работаем над библиотечным использованием Fabric c точки зрения его организации.

Множественные попытки подключений и игнорирование плохих узлов

Начиная с Fabric 1.4 перед тем, как завершиться с ошибкой, скрипт будет предпринимать env.connection_attempts попыток подключения c таймаутом env.timeout секунд. (На данный момент по умолчанию это 1 попытка и 10 секунд, для соответствия предыдущему поведению, но эти значения можно спокойно поменять)
Более того, даже полная невозможность подключиться к серверу уже не является абсолютным препятствием. Задайте env.skip_bad_hosts в True и в большинстве случаев (обычно в начале подключений) Fabric будет лишь предупреждать об ошибке, а не завершать выполнение задач.
Добавлено в версии 1.4

Управление паролями

Fabric работает с двухъярусным кэшем паролей, чтобы запоминать ваши логин и пароли sudo в некоторых случаях; это помогает избежать нудного повторного ввода паролей, если несколько систем используют одни и те же пароли [мы крайне рекомендуем использовать SSH доступ по ключу, а не полагаться на настройки пароля, что менее безопасно], или же конфигурация sudo на удалённой системе не имеет своего кэша.
Первый слой - это либо значения по умолчанию, либо fallback кэш паролей, env.password (который можно задать либо через командную строку опцией --password или --initial-password-prompt). Эта переменная хранит только один пароль который (если он не пуст) будет использован в случае, когда кэш для узла не имеет значения для текущей строки узла.
env.passwords (множественное число!) служит как кэш на пользователя / узел, храня недавно введённый пароль для каждой уникальной комбинации пользователь/узел/порт. Таким образом, в той же сессии подключения под разными пользователями и / или к разным узлам будут требовать только один пароль для каждого случая. (В прежних версиях Fabric использовал только один кэш пароля по умолчанию и потому требовалось каждый раз вводить пароль заново, как только хранившийся в кэше не подходил.)
В зависимости от вашей конфигурации и числа узлов в сессии, к которым Вы будете подключаться, Вы можете использовать одну или обе этих переменных. В любом случае, Fabric автоматически заполняет их по необходимости без дополнительных настроек.
Конкретнее, каждый раз, когда у пользователя запрашивается пароль, введённое значение используется и для обновления кэша пароля по умолчанию, и значения кэша для текущего значения строки хоста.

Использование "родных" файлов конфигурации SSH

SSH клиенты командной строки (как те, которые предоставляет OpenSSH) используют специальный формат конфигурации, известный как ssh_config и считывается из файла, чьё расположение зависит от платформы - $HOME/.ssh/config (или в пути, указанном в опции --ssh-config-path/env.ssh_config_path). Этот файл позволяет определить различные SSH опции, такие как имя пользователя по умолчанию или для конкретного хоста, псевдонимы узлов и другие опции переключения (например, использовать ли agent forwarding)
Реализация SSH Fabric позволяет загрузить набор этих опций из указанного файла конфигурации SSH, который должен существовать. По умолчанию этого не делается (для сохранения обратной совместимости), но его можно активировать при помощи настройки env.use_ssh_config, установив его в True в начале вашего fabfile.
Если эта настройка активирована, то следующие настройки SSH будут загружены и использованы Fabric:
  • User и Port будут использованы для соответствующих параметров подключения, если другие не указаны в таком порядке:
    • Глобально определённые User / Port будут использованы вместо текущих значений по умолчанию (локальное имя пользователя и 22 соответственно), если соответствующие переменные окружения не заданы
    • Однако, если env.user / env.port заданы, они переопределяют глобальные значения User / Port.
    • Значения user/port в строке хоста (т.е. hostname:222) будут переопределять всё, включая значения из ssh_config
  • HostName может быть использован для замещения переданного имени узла, так же как и в обычном ssh. Таким образом запись `Host foo` определяющая `HostName example.com` позволит использовать в Fabric имя узла foo, которое на момент подключения будет заменено на example.com
  • IdentityFile будет применено (но не заменит) к env.key_filename
  • ForwardAgent будет аргументом env.forward_agent по принципу OR: если либо значение из файла, либо значение переменной будет положительным, то тогда перенаправление агента будет активировано
  • ProxyCommand вызовет использование команды proxy для подключения к узлу, как и в обычном ssh
Примечание: Если Вы хотите всего лишь "отфутболить" SSH трафик от шлюза, Вы можете решить, что env.gateway более удобный способ подключения (и это уже настройка уровня Fabric), чем просто метод `ssh gatewayhost nc %h %p` использования ProxyCommand в качестве шлюза.
Примечание: Если Ваш файл настроек SSH содержит директиву ProxyCommand и Вы установили значение env.gateway, отличное от None, env.gateway будет иметь приоритет и ProxyCommand будет проигнорирована.
Примечание: Если Вы создали SSH файл настройки, Вам будет проще изменить env.gateway (через settings), чем разбираться с настройками из файла настроек.

Комментариев нет:

Отправить комментарий