Fabric: При желании избегайте использования ssh при переходе на localhost

Созданный на 19 авг. 2011  ·  59Комментарии  ·  Источник: fabric/fabric

Описание

run () / sudo () разумно увидит, что вы переходите на localhost, и вместо этого просто запустите local (). Вероятно, это необязательная вещь.

Комментарии Джеффа к IRC:

и да, я имею в виду, что всегда будут накладные расходы с ssh и прямыми трубами навскидку, я не думаю, что было бы ужасно сложно обновить run / sudo (особенно в master теперь, когда они были реорганизованы) для вызова / возврата local ( ) разумно, я не уверен, что мне бы хотелось, чтобы это полумагическое поведение в ядре (даже если оно отключено по умолчанию с возможностью его включения, хотя это могло бы помочь), но даже в этом случае это был бы интересный эксперимент. и если это так просто, как я думаю, я, честно говоря, не могу придумать вескую причину не делать этого (опять же, при условии, что это не поведение по умолчанию)

Первоначально представленный Ник Уэлч ( mackstann ) на 2009-11-11 в 01:39 вечера EST

связи

  • Дублировано # 364: разрешить локальную операцию в обход уровня SSH
  • Относится к № 26: Реализовать функцию «пробного запуска»
Feature Network

Самый полезный комментарий

Если кто-то задается вопросом, «зачем кому-то это делать?», Ответ заключается в том, что если у вас есть конвейер развертывания, может быть полезно запустить один и тот же точный сценарий развертывания, независимо от того, в какой среде, вместо того, чтобы иметь специальный сценарий настройки для localhost по сравнению со всем остальным.

Все 59 Комментарий

Джеймс Пирсон (xiong.chiamiov) написал:


Как также упоминалось в irc, я обычно не запускаю ssh-сервер на настольном компьютере, поэтому на самом деле я не могу использовать ssh для localhost.


11 ноября 2009 г., 15:13 EST

Трэвис Свисгуд ( tswicegood ) написал:


Я только что реализовал нечто подобное сегодня вечером в виде новой функции fabric.operations под названием do . Он смотрит на env.run_as чтобы узнать, равно ли оно "local", и при этом переключается на метод local вместо run (или sudo если sudo=True передается как kwarg). Он также обрабатывает префикс локальных команд с помощью sudo в случае, если они выполняются локально.

Это своего рода другой способ решения этой проблемы, который работает без изменения поведения run или sudo . Эти изменения доступны в моем репозитории .


11 января 2010 г., 12:22 EST

Morgan Goose ( goosemo ) опубликовал:


Я действительно не считаю это правдоподобным. Какой смысл бегать как местный. Одним из требований Fabric является запуск sshd на машине, удаленно или с обратной связью. Другая проблема заключается в том, что при изменении только local не учитываются put, get, rsync_project и другие, которые все еще нуждаются в ssh. Попытка реализовать их на самом деле вызовет больше проблем, поскольку теперь это касается преобразования fabfiles в bash.


13 марта 2011 г., 23:14 EDT

Джефф Форсьер (


Хотя я также не уверен на 100%, что это отличная идея, очевидно, что это то, в чем многие пользователи чувствуют потребность - еще один запрос был подан под номером 364 с другим объяснением варианта использования.

Я также добавил билет на пробный запуск, связанный с этим, потому что (я полагаю - если кто-либо из запрашивающих пользователей может проверить это, это было бы здорово) основным вариантом использования этой функции является тестирование / проверка Бег.


23.06.2011, 11:26 EDT

Как отмечалось в # 538, если мы когда-либо сможем полностью нормализовать три бегуна, чтобы их можно было использовать взаимозаменяемо, нам нужно убедиться, что экранирование оболочки работает последовательно для них. Прямо сейчас мы не используем экранирование оболочки local , хотя это, по крайней мере, частично, потому что он не использует оболочку оболочки.

Если кто-то задается вопросом, «зачем кому-то это делать?», Ответ заключается в том, что если у вас есть конвейер развертывания, может быть полезно запустить один и тот же точный сценарий развертывания, независимо от того, в какой среде, вместо того, чтобы иметь специальный сценарий настройки для localhost по сравнению со всем остальным.

+1 за функцию

+1

+10

+1

+1

Чтобы задержать вас, вы можете просто убедиться, что у вас запущен сервер OpenSSH. Сначала выполните sudo apt-get install ssh чтобы убедиться, что он установлен (даже если вы думаете, что это так). Затем выполните sudo service ssh start | stop | restart мере необходимости. Узнал из этой ветки .

+1

Мой вариант использования прост: я хочу использовать один и тот же сценарий django-deploy для настройки экземпляров ec2 как с помощью cloud-init через CloudWatch (случай для запуска локальных команд), так и с использованием обычного fab deploy_django -H foo@bar .

+1

Это было бы действительно полезно. Один из вариантов использования, который у меня есть, - это использование vagrant shell provisioner для настройки конкретной vm с использованием фабрики и без необходимости ssh localhost.

+1

Я был удивлен, что не увидел этого в Fabric.

К вашему сведению: реализация этой функции становится более сложной, если вы думаете о функциях структуры, таких как reboot() .

+1

Уже должен быть частью ядра!

+1

Это было бы совершенно логично: с абстрактной точки зрения, local - это просто частный случай run , в котором не задействован механизм SSH.

Еще одна вещь, на которую стоит обратить внимание (возможно, очевидная): Fabric должна быть достаточно умной, чтобы решить, следует ли преобразовывать run в local ПОСЛЕ чтения / etc / hosts.

Я имею в виду: если у нас есть

env.host = [ 'mywebserver' ]

и в / etc / hosts у нас есть:

127.0.0.1 mywebserver

тогда любые вызовы run должны быть вызовами local .

Продвигая эту концепцию дальше, мы также должны рассматривать run как локальный вызов, когда удаленный хост разрешает IP-адрес, назначенный сетевому интерфейсу локальной машины.
Например:
fabfile:

env.host = [ 'mywebserver' ]

/ etc / hosts:

192.168.1.1 mywebserver

ip addr :

[...]
eth0:
  inet 192.168.1.1
[...]

+1

+1: +1:

: +1:

+1

+1

Fabric 2 будет использовать pyinvoke / invoke, так что это должно быть довольно легко сделать там. Я бы дождался Fabric 2, чтобы не взломать способ сделать это.

: +1:

+1

: +1:

: +1: Пожалуйста, реализуйте это, тем более что компьютеры Mac не настроены автоматически для настройки туннелей SSH для удаленного доступа к серверу localhost.

+1

+1 :)

+1 пожалуйста

: +1:

: +1:

: +1:

Мы используем Fab для сборки пакетов debian, и это добавляет дополнительную сложность

ребята привет всем
я пытаюсь создать клон ткани с разницей:

  • Функция run () работает таким же образом с subprocess.popen на локальном хосте, как и на ssh для подключения к удаленному хосту
  • Factory использует openssh или любой другой клиент ssh (для этого вам следует изменить конфигурацию), поэтому вы можете использовать всю мощь сокетов ssh
  • Factory использует библиотеку gevent для асинхронного выполнения

Вы можете посмотреть, нужна ли вам эта функция
https://github.com/Friz-zy/factory

Возможно, мне что-то не хватает в этом обсуждении, но вот что я сделал, чтобы использовать тот же код с командой fab run как на локальном, так и на удаленных машинах.

  1. Я установил env.use_ssh_config = True в свой файл fabfile.py
  2. ssh-copy-id localhost

Это не решит вашу проблему, если вы не используете ssh-сервер на своем локальном компьютере.

: +1:

+1

+1 Пожалуйста, внедрите эту функцию :)

+1

Может быть очень полезно для начальной загрузки образов Docker с использованием существующих скриптов Fabric. Эта функция позволит избежать установки SSH-сервера в контейнер, что противоречит лучшим практикам Docker.

+1

+1

+1

В дополнение к ответу, предоставленному @AntoniosHadji , вот полные инструкции по выполнению этой работы;

# Generate new SSH key for local usage
ssh-keygen -f ~/.ssh/id_rsa -N ''

# Add server keys to users known hosts (eliminates 'are you sure' messages);
ssh-keyscan -H localhost > ~/.ssh/known_hosts

# Allow user to ssh to itself
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

Собственно, это можно сделать с помощью кухни . Вам нужно изменить все run выполнения, чтобы они ссылались на cuisine.run функцию, что можно легко сделать с помощью импорта, и изменить режим на локальный:

from cuisine import run, mode_local

mode_local()
print run("echo Hello")

Отлично @cgarciaarano

Для простых случаев использования это работает для меня:

from fabric.api import run, local
# ...
# in task:
  if env.host is None or env.host == 'localhost':
    run = local

: +1:

Я хочу, чтобы мой fabfile запускался удаленно или локально, когда ssh не подходит. Это включает в себя локальные оболочки для get / put / exists и т. Д.

: +1: У меня есть fabfiles, которые запускаются как локально, так и удаленно, и в итоге я взломал свои собственные функции оболочки для run / local / get, чтобы справиться со всеми тонкими различиями, такими как захват вывода и обработка ошибок.

Что делать, если у вас есть ssh-соединение, выполняющее динамическую переадресацию портов и привязку к 127.0.0.2 (все еще технически localhost) на порту 2223. Я вижу, как это может вызвать проблемы, для этого сопоставление на localhost и разрешение на 127.0.0.1, а не также поддержка всего класса 127.0.0.0/8 может быть хорошей идеей для обработки.

@ blade2005 Да, весь диапазон 127 ._._. * указывает на ваш локальный хост (кроме 127.0.0.0 и 127.255.255.255), но когда вы фактически указываете на свой локальный хост, вы не будете использовать порт, верно?
Поэтому я считаю, что мы можем с уверенностью предположить, что 127.*.*.* == localhost и ssh можно избежать, но 127.*.*.*:* указывает на перенаправленный порт, и требуется ssh.

Честно говоря, эта функция, вероятно, имела бы больше смысла в качестве стороннего плагина, созданного на основе ткани, похожего на библиотеку кухни. Затем мы просто импортируем обернутые функции для run / get / put / etc, которые будут знать, нужно ли запускать локально или удаленно на основе переменной env. По крайней мере, таким образом, кто-нибудь мог бы запустить это, чтобы все могли использовать.

Я реализовал что-то локально, и это намного больше, чем просто переключение между локальным / запуском. Вы должны учитывать префиксы, измененные каталоги, пользователей sudo и т. Д.

Вкратце подумал об этом в контексте другого тикета, связанного с 2.0, и понял, что есть еще кое-что, кроме простого « run становится перепривязкой local »:

  • Любая задача действительно смешанного режима с использованием local и run или любого из put / get своей сути становится проблематичной: операции с четко определенными «local» и «remote» теперь «концы» указывают локально.

    • Я бы предположил, что это вариант использования меньшинства (если он вообще есть), но его все еще нужно выяснить, даже если он «вызывает любую операцию, но run или sudo поднимает DoesntMakeAnySenseError "или что-то в этом роде.

    • put / get предположительно может просто превратиться в shutil.copy или аналогичный

    • local , по-видимому, не изменится (хотя при печати того, что происходит, вероятно, все же нужно, чтобы оно отличалось от того, что run-except-locally имеет префикс ...?)

    • Как отмечалось выше, различные методы / менеджеры контекста, такие как prefix , cd т. Д., Требуют ответов на аналогичные вопросы.

  • Кроме того, локальный запуск команд sudo вообще потенциально огромен и, вероятно, требует дополнительных проверок безопасности.

    • Если это тоже не станет еще одной привязкой к local , что является еще одной возможностью. Хотя и небольшая, любые команды sudo которые даже работают локально (т.е. одна из них развертывается в Linux и развертывается из нее), по-видимому, должны оставаться локальными привилегиями (например, apt / yum и друзья, возня с файрволлом и т. д.).

  • sudo также (как отмечалось выше Джоном) необходимо расширить возможность настройки отдельных векторов конфигурации local-vs-remote, поскольку пользователь sudo, пароль и т. Д., Вероятно, будут различаться между двумя сторонами.

    • Хотя, поскольку я думаю обо всем этом в контексте Fab 2, ожидаемые переопределения конфигурации для каждого хоста, вероятно, решат, по крайней мере, эту часть вещей - контексту localhost просто будут переданы соответствующие значения. (Кроме того, в качестве специального подкласса Context "для локального запуска удаленных вещей" он может делать и другие вещи, если это необходимо).

@ max-arnold пробовал это в альфа-версии v2 и столкнулся с запутанными проблемами, чего и следовало ожидать на данный момент, поскольку - я еще не дошел до варианта использования этого конкретного билета, кроме обеспечения run и local имеют максимально похожие API.

На данный момент большая проблема заключается просто в природе и API объекта, привязанного к контексту задачи ( c или ctx или как там это называется) posarg. В настоящее время, и это опять же, не предполагается, что это будет окончательным, просто так все закончилось до сих пор:

  • по умолчанию, когда выполняется Invoke - х Executor , или Fab 2 - х FabExecutor , когда нет хозяев нет, это invoke.Context , который имеет run , что выполняется локально и отсутствует local ;
  • когда Fab 2 имеет хост (ы) для работы, он создает fabric.Connection , run запускается удаленно, а local является перепривязкой run Invoke.

Требуется более конкретное мышление, в том числе рассмотрение вариантов использования здесь и в связанных тикетах. Беглый мозговой штурм:

  • Полезное решение (или по крайней мере в документации) для этого почти наверняка должно существовать в ядре (согласно предыдущему чату о том, что он живет за пределами ядра), потому что:

    • это достаточно распространенный вариант использования

    • легко испортить

    • это необходимо для полезной реализации v2-совместимых версий patchwork (урожденная contrib ) и / или invocations (аналогичная версия Invoke), особенно потому, что она сообщает, сколько совместного использования кода они могут делать. Многие задачи и / или подпрограммы в этих типах кодовых баз могут захотеть запускаться локально или удаленно.

  • По сути, речь идет о том, какого API ожидать от объектов контекста, когда задача может не знать наверняка, «как» она вызывается.
  • Может зависеть от того, как создается задача, т.е. разные версии @task и / или kwargs на одну и ту же, где пользователь может заявить о своих ожиданиях (т.е. «Я действительно хочу получить контекст с возможностью удаленного доступа», «пожалуйста, никогда не давайте мне удаленный контекст» и т. д.)

    • Мы можем захотеть _require_ это, чтобы избежать двусмысленности ( ZoP # 12 )

    • Чем больше я думаю об этом, тем яснее становится, что мы действительно хотим, чтобы Fabric вырастила свою собственную легкую оболочку вокруг @task / Task ; Кодовые базы pure-Invoke будут просто использовать его @task который всегда будет запускать получение ванильного значения Context , в то время как задачи, созданные с помощью версии Fabric, по крайней мере, будут иметь возможность получить Connection , если не требуется.

    • Обратной стороной является упомянутая выше задача типа «Я могу быть полезной локально удаленно с помощью XOR»; задача, которая хочет только один вариант «запускать команды, пожалуйста» и не смешивает оба режима одновременно. Это _не_ работает хорошо с решениями типа "декоратор объявляет тип контекста", потому что _необходимо_ переключать тип контекста в зависимости от того, кто его вызывает и как.

    • Хотя на самом деле это одна из составляющих текущего API; эти задачи _не заботятся_ о подклассе контекста, _ пока существует ctx.run() .

    • Таким образом, те, кто предположительно хотят быть украшены версией @task «Мне нужна только базовая, ванильный контекст», при том понимании, что кто-то с точки зрения вызова Fabric (или Fabric-подобной) имеет возможность предоставить эти задает Connection вместо Context .



      • Это возвращает нас к размышлениям о том, как именно выполнять задачи, иначе pyinvoke / invoke # 170



  • Независимо от реализации, мы должны гарантировать, что минимизируем потенциальный риск использования ножного оружия re: пользователи, выполняющие такие действия, как:

    • Ожидание local когда он не существует (код ожидания Fabric / Connection запускается через Invoke)

    • Ожидание локального запуска run когда вместо этого был предоставлен контекст с удаленным run (код вызова / ожидания контекста запускается через Fabric)

    • Что-нибудь еще из дополнительного комментария Макса здесь

  • Как видно из гораздо более старых комментариев, второстепенный вариант использования здесь - это пользователи, ожидающие, что v2-эквивалент Connection('localhost').run('foo') _не будет использовать SSH_, а будет действовать точно так же, как Connection('localhost').local('foo') .

    • Я _угадываюсь_, что мы на самом деле не хотим этого делать, потому что это похоже на неприятное оружие для всех, кто пытается выполнить проверку работоспособности локального хоста. Мне это кажется слишком волшебным. Но я открыт для аргументов, возможно, на основе согласия (например, установить параметр конфигурации, например ssh.localhost_becomes_subprocess = True или что-то еще.)

На данный момент я могу использовать только upload_template() для локального рендеринга шаблона.

Конечно, это можно было сделать так:

#http://matthiaseisen.com/pp/patterns/p0198/
import os
import jinja2


def render(tpl_path, context):
    path, filename = os.path.split(tpl_path)
    return jinja2.Environment(
        loader=jinja2.FileSystemLoader(path or './')
    ).get_template(filename).render(context)

Но почему бы не иметь возможность рендерить локально?

Основное использование этой функции в моем случае - развертывание конфигурации приложения на моем локальном компьютере для локального тестирования.

Предположим, у вас есть settings.py.j2 который отображается на целевом сервере при развертывании, и там он называется settings.py и содержит только код Python, без jinja.
Теперь вы хотите протестировать локально, но локально еще нет settings.py , потому что его нужно отрендерить из settings.py.j2 .
Таким образом, ваше приложение не может запуститься, и вам придется вручную создать отдельный settings.py для локального тестирования.

Это очень утомительно, и должно быть легче.

Например, в Ansible я бы просто сказал задаче, что она будет использовать «локальное соединение», и она будет отображаться на локальном хосте, не пытаясь подключиться к нему по ssh.

Пока эта функция не будет доступна в Fabric, я, конечно, буду использовать вставленное выше решение, так как это всего лишь несколько строк кода. Хотя имхо должно быть проще. Я чувствую, что такая ткань должна облегчить мне задачу.

@fninja Я еще не портировал сам upload_template , но я определенно согласен с тем, что он подпадает под это проблемное пространство. Вероятно, можно было бы справиться с этим, просто разделив этап рендеринга Jinja-wrapping и этап загрузки-выгрузки строки, особенно, поскольку последний уже существует в форме «передать FLO в put ». Например:

from StringIO import StringIO # too lazy to remember the newer path offhand
from somewhere.jinja_wrapper import render
from invoke import task

<strong i="9">@task</strong>
def render_settings(c):
    rendered = render('settings.py.j2', {'template': 'params'})
    c.put(StringIO(rendered), 'remote/path/to/settings.py')

Но, вероятно, все еще есть место для еще более короткого аналога с одной остановкой для upload_template который был бы либо методом Connection или подпрограммой, принимающей аргумент Connection .

В любом случае, это вызывает больше вопросов относительно того, как именно относиться к такого рода вещам - например, объекты Context вызова не имеют put / get . Стоит ли их добавлять? Это имеет смысл для пользователей Fabric в контексте этого тикета (тогда upload_template или w / e могут просто вызвать put в любом случае), но для пользователей, использующих только Invoke, это странно. и бесполезная часть API.

+1, чтобы сделать это основной функцией

Крестовина от №1637. Просто идея:

from fabric import task, local

<strong i="6">@task</strong>
<strong i="7">@local</strong>
def build(ctx):
    with ctx.cd('/project/dir'):
        ctx.run('build > artifact.zip')

<strong i="8">@task</strong>
def deploy(conn):
    build(local(conn))

    with conn.cd('/remote/path'), local(conn).cd('/project/dir'):
        conn.put(remote_path='build.zip', local_path='artifact.zip')

В основном local() может действовать как декоратор / контекстный менеджер / функция и преобразовывать Connection в Context .

Еще один вариант использования, о котором я не думаю, что упоминал: создание библиотеки многоразовых функций. В моем случае это в основном команды git . Я написал чрезмерно упрощенный dorun который скрывает различия между параметрами функции run и local (в версии 1); какая функция выбрана, передается как параметр. Вот, например, git checkout :

def git_checkout(branch, remote='origin', run=run):
    """Checkout a branch if necessary."""

    if branch == git_current_branch(run=run):
        return
    elif branch in git_local_branches(run=run):
        dorun('git checkout ' + branch, run=run)
    else:
        dorun('git checkout -t -b {0} {1}/{0}'.format(branch, remote), run=run)


def git_current_branch(run=run):
    """Get the current branch (aka HEAD)"""

    output = dorun('git name-rev --name-only HEAD', run=run)
    return output.strip()


def git_local_branches(run=run):
    """Get a list of local branches; assumes in repo directory."""

    output = dorun('git branch --no-color', run=run)
    branches = {l.strip().split(' ')[-1]
                for l in output.strip().split('\n')}
    return branches

Это выглядит так:

from fabric.api import run as run_remote, local as run_local

def dorun(*args, **kwargs):
    """Work around the fact that "local" and "run" are very different."""
    kwargs.setdefault('run', run_remote)
    run = kwargs.pop('run')

    if run == run_local:
        kwargs.setdefault('capture', True)
    elif 'capture' in kwargs:
        del kwargs['capture']

    return run(*args, **kwargs)

Я понятия не имею, что происходит с sudo и есть проблемы, с которыми я не могу легко справиться, например, расширение ~remoteuser для создания пути.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги