Fabric: Проблема с переменными окружения и ПУТЬ на удаленном сервере (не источник .bashrc)

Созданный на 9 окт. 2016  ·  22Комментарии  ·  Источник: fabric/fabric

Привет,

Я пытаюсь загрузить файл .bashrc (т.е. источник /home/ubuntu/.bashrc) при запуске команды запуска fab, чтобы добавить некоторые переменные среды и расширить переменную пути:

запустить ('источник /home/ubuntu/.bashrc && echo $ PATH')

Это показывает мне только:

[[email protected]] выход: / usr / local / sbin: / usr / local / bin: / usr / sbin: / usr / bin: / sbin: / bin: / usr / игры: / usr / местные / игры

вместо гораздо более длинного списка путей, который я вижу при входе на удаленный сервер вручную.

Как мне заставить fab правильно импортировать файл .bashrc в мой удаленный домашний каталог?

Спасибо!

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

Это крутая штука, а не фантастика.

Какие файлы bash решает использовать при запуске, может быть сложно http://blog.flowblok.id.au/2013-02/shell-startup-scripts.html, а debian / ubuntu (и большинство дистрибутивов) имеют некоторую настройку в /etc/profile и по умолчанию ~/.bashrc .

По умолчанию fab использует оболочку /bin/bash -l -c , а -l делает ее оболочкой «входа в систему». Без настройки debian / ubuntu оболочка «входа в систему» ​​bash может получить ~/.bash_profile но не ~/.bashrc .

Но в ubuntu 16.04 он, похоже, по умолчанию использует .bashrc даже для оболочки входа. Но строки, добавленные в нижней части значения по умолчанию .bashrc , не обрабатываются, потому что он отключается вверху, если обнаруживает, что он работает не интерактивно.

Здесь я добавил две строки к пользователю ubuntu-16.04 по умолчанию .bashrc

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

export VAR1=val1

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

export VAR2=val2

# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth
...

Вот файл, с которым я тестирую:

from fabric.api import run, env, task

<strong i="23">@task</strong>
def get_myvars():
    run("echo VAR1=$VAR1 VAR2=$VAR2")

Результаты, достижения:

$ fab -H testpy05.ec2.st-av.net get_myvars
[testpy05.ec2.st-av.net] Executing task 'get_myvars'
[testpy05.ec2.st-av.net] run: echo VAR1=$VAR1 VAR2=$VAR2
[testpy05.ec2.st-av.net] out: VAR1=val1 VAR2=
[testpy05.ec2.st-av.net] out: 
...

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

Это крутая штука, а не фантастика.

Какие файлы bash решает использовать при запуске, может быть сложно http://blog.flowblok.id.au/2013-02/shell-startup-scripts.html, а debian / ubuntu (и большинство дистрибутивов) имеют некоторую настройку в /etc/profile и по умолчанию ~/.bashrc .

По умолчанию fab использует оболочку /bin/bash -l -c , а -l делает ее оболочкой «входа в систему». Без настройки debian / ubuntu оболочка «входа в систему» ​​bash может получить ~/.bash_profile но не ~/.bashrc .

Но в ubuntu 16.04 он, похоже, по умолчанию использует .bashrc даже для оболочки входа. Но строки, добавленные в нижней части значения по умолчанию .bashrc , не обрабатываются, потому что он отключается вверху, если обнаруживает, что он работает не интерактивно.

Здесь я добавил две строки к пользователю ubuntu-16.04 по умолчанию .bashrc

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

export VAR1=val1

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

export VAR2=val2

# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth
...

Вот файл, с которым я тестирую:

from fabric.api import run, env, task

<strong i="23">@task</strong>
def get_myvars():
    run("echo VAR1=$VAR1 VAR2=$VAR2")

Результаты, достижения:

$ fab -H testpy05.ec2.st-av.net get_myvars
[testpy05.ec2.st-av.net] Executing task 'get_myvars'
[testpy05.ec2.st-av.net] run: echo VAR1=$VAR1 VAR2=$VAR2
[testpy05.ec2.st-av.net] out: VAR1=val1 VAR2=
[testpy05.ec2.st-av.net] out: 
...

С первого взгляда звучит нормально, спасибо @ploxiln!

Спасибо за развернутый ответ!

Похоже, что это отличается от стандартного поведения ssh, и его было трудно отладить. Когда я вручную ssh'd, все работало нормально, тогда как ткань имела другое значение PATH из-за того, что не запускал .bash_profile в OSX.

@bitprophet это может быть ошибка OSX ??

@ code-tree Вы используете Fabric 1 или 2? 1.x использует явные оболочки оболочки, поэтому он отличается от стандартного клиента OpenSSH; версия 2 не выполняет обертывания и должна вести себя как клиент OpenSSH с точки зрения того, что sshd запускает от вашего имени.

Версия 1 имеет несколько параметров конфигурации env для изменения этой оболочки оболочки, поэтому вы можете попробовать добавить к ней флаги, например -i который IIRC является bash для «запуска интерактивного режима и источника дополнительных файлов».

Это странно, потому что я использую версию 2.2.1 . В настоящее время мне нужно сделать следующее, чтобы мое приложение заработало:
c.run('bash -l -c "python3 ./configure.py"')
Как и когда я установил Python 3, он добавил себя в PATH через мой .bash_profile , который не запускается Fabric. Я также не вносил никаких изменений в стандартную встроенную конфигурацию sshd.

Тогда это странно, мне нужно посмотреть, смогу ли я воспроизвести. Просто провел быструю трассировку вменяемости, чтобы доказать, что я имею в виду, re: Fabric 2 не делает ничего "особенного", управляемого re: sshd:

@ code-tree также, если можете, опубликуйте более подробную информацию о том, что именно вы используете, и другие детали среды (клиентская и серверная ОС / версия и т. д.).

Конечно, я использую старую версию OSX в качестве сервера. Если вы можете подтвердить, что все работает нормально на более новой MacOS, тогда ладно. Но если нет, то может быть проблема с MacOS как сервером в целом?

  • Клиент: Ubuntu 16.04, Python 3.6.6, OpenSSH 7.2p2, Bash 4.3.48, Fabric 2.2.1
  • Сервер: OSX 10.11, Python 3.6.6, OpenSSH 6.9p1, Bash 3.2.57

Боковое примечание, мне интересно, действительно ли это случай неправильного диагноза:

ткань имела другое значение PATH из-за того, что не запущен .bash_profile в OSX

Может ли это быть примером # 1744, где Fabric 2 отличается от ssh с точки зрения шунтирования локальных переменных окружения по трубе? (Зависит от конкретных переменных env, о которых идет речь, и от того, могут ли они быть похожими локально и удаленно; @code-tree может легко опровергнуть эту теорию, дважды проверив точные значения в игре re: их локальный и удаленный bash_profile ... 😁)


Но я все равно собираюсь устранить эту неполадку, просто чтобы я знал, что я не сумасшедший, re: мое понимание того, что делает sshd с точки зрения оболочек и исходных файлов.

Также мне интересно, связано ли это со сценарием / интеллектом из # 1816, который также относится к оболочкам и файлам запуска. Это _ вероятно_ не имеет прямого отношения из-за утверждения здесь о том, что ssh ведет себя одним способом, а Fabric ведет себя иначе (в отличие от того, «как sshd обычно вызывает оболочку»), но в любом случае стоит связать.

Обнаружил, что пытался наткнуться на кучу глубоких погружений в код sshd, которые я помню, как делал в последние несколько месяцев, связанных с чем-то в этом направлении. Я не могу найти его сейчас, что меня раздражает. РЕДАКТИРОВАТЬ: ах, я думаю, что это была не связанная с Paramiko проблема (не связывание, потому что нет смысла сбивать с толку) выполнение команд перед аутентификацией. OK.

Хорошо, так что же на самом деле происходит, когда мы запрашиваем команду exec?

  • SSH-протокол хочет, чтобы вы либо сделали запрос канала shell (который загружает определенную пользователем программу оболочки входа и не принимает никаких command ), либо канал exec запрос (который просто говорит "выполняет заданную командную строку, которая может содержать путь" и не указывает больше)
  • Парамико делает последнее, как мы выяснили выше.
  • Так что же на самом деле делает сам OpenSSH? Я посмотрю на мою локальную проверку openssh-Portable (на 775f8a23f2353f5869003c57a213d14b28e0736e )

Ну, сначала я немного пошутлюсь. Запуск с произвольным контейнером Debian 8.10 (на котором запущен OpenSSH 6.7!) Я вижу это в журналах уровня DEBUG3 после выполнения ssh localhost whoami :

debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
Starting session: command for root from 172.17.0.1 port 42598

Выполнение fab -H localhost -- whoami :

debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
Starting session: command for root from 172.17.0.1 port 42610

Хорошо, они оба делают exec ... этого и следовало ожидать. Что-нибудь изменилось в дереве процессов? не должно быть, и ... нет. оба выглядят так:

sshd,1 -D -e
  └─sshd,1535
      └─pstree,1537 -alpU

Значит, в игре точно нет оболочки? Что он вообще делает? Могу ли я использовать такие вещи, как && ?

Я могу! например, whoami && id отлично работает. Это немного странно, учитывая мое понимание управления процессами Unix; кажется маловероятным, что sshd буквально выполняет exec(string) , но если бы он использовал оболочку для интерпретации, разве мы не увидели бы это в pstree ?

Думаю, пора по-настоящему покопаться в openssh-portable и посмотреть, что к чему.


Кроме того, я _did_ сделал часть этой трассировки (но по другой причине / фокусу) в прошлом, как в декабре 2016 года: https://github.com/paramiko/paramiko/pull/398#issuecomment -264281759. Совершенно забыл ...


Причина, по которой я не вижу оболочку в pstree , связана с использованием execve , который заменяет родительский процесс вместо порождения дочернего. Хорошо знать. (РЕДАКТИРОВАТЬ: неправильно, это просто заменяет дочерний процесс sshd оболочкой; сама оболочка может также выполнять вызов exec в стиле replace-me; см. Комментарии ниже.)


Во всяком случае так! Это по-прежнему должно означать, что клиенты Fabric и OpenSSH делают одно и то же с точки зрения выполнения оболочки; ничто из того, что они делают, не изменило бы эти части кодовой базы OpenSSH. Это всегда должно быть что-то вроде bash -c "python3 ./configure.py" , с фактическим значением bash зависимости от пользователя уровня macOS @code-tree и его настроенной оболочки.

Это заставляет меня задаться вопросом, верна ли моя догадка о передаче env var как дифференциатора, поскольку это единственное, о чем я могу думать о re: как две среды выполнения могут различаться. FWIW в моем тестировании, ориентированном на интерфейс командной строки, env сообщает об одном и том же в обеих системах, и независимо от этих других проблем, связанных с env, поведение _default_ (из-за политики безопасности SSH) всегда должно заключаться в том, что локальный env не "просачивается" в Обратная сторона.

Да, я почти уверен, что sshd всегда запускает командную строку в оболочке пользователя (настроенной в / etc / passwd). Однако он добавляет к командной строке "exec", если он может проанализировать командную строку и определить, что это единственная команда.

$ ssh testdeploy02.ec2.st-av.net pstree -a
...
  |-sshd -D
  |   `-sshd 
  |       `-sshd  
  |           `-pstree -a
$ ssh testdeploy02.ec2.st-av.net 'pstree -a && sleep 1'
...
  |-sshd -D
  |   `-sshd 
  |       `-sshd  
  |           `-bash -c pstree -a && sleep 1
  |               `-pstree -a
$ ssh testdeploy02.ec2.st-av.net 'VAR=-a sh -c "exec pstree \$VAR"'
...
  |-sshd -D
  |   `-sshd 
  |       `-sshd  
  |           `-pstree -a

Что касается переменных среды, они в основном контролируются конфигурациями клиента ssh и сервера sshd:

$ grep Env /etc/ssh/*_config
/etc/ssh/ssh_config:    SendEnv LANG LC_*
/etc/ssh/sshd_config:AcceptEnv LANG LC_*

Таким образом, клиент ssh явно отправляет некоторые переменные (вне самой командной строки), и они фильтруются sshd. Но, видимо, есть исключения:

$ ssh testdeploy02.ec2.st-av.net env | grep TERM
$ ssh -t testdeploy02.ec2.st-av.net env | grep TERM
TERM=xterm-256color

На самом деле я думаю, что поведение «автоматический exec для замены оболочки одной командой» - это особенность bash:

$ dash -c "pstree -a"
...
  ├─sshd -D
  │   └─sshd 
  │       └─sshd  
  │           └─bash
  │               └─dash -c pstree -a
  │                   └─pstree -a
$ bash -c "pstree -a"
  ├─sshd -D
  │   └─sshd 
  │       └─sshd  
  │           └─bash
  │               └─pstree -a

РЕДАКТИРОВАТЬ: Для полноты:

$ bash -c "pstree -a && sleep 1"
  ├─sshd -D
  │   └─sshd 
  │       └─sshd  
  │           └─bash
  │               └─bash -c pstree -a && sleep 1
  │                   └─pstree -a

Ах да, я ошибся, execve просто означает, что дочерний процесс -c xxx . Мои тесты были в zsh, fwiw.

Также @ploxiln да, вещь с env vars ссылается на другие билеты, указанные выше, хотя еще неизвестно, действительно ли @code-tree испытывает другой симптом, чем те.

Извините, я думаю, что это ложная тревога. Я не знал, что есть какая-либо разница между выполнением команды через ssh inline и выполнением после входа в систему через ssh. Когда я делаю ssh host 'echo $PATH' он также не обновляет PATH, где echo $PATH после входа в систему работает нормально.

Я до сих пор не понимаю, почему ssh это делает (похоже, мне действительно нужно сделать ssh host 'bash -l -c "python3 ./configure.py"' ). Тем не менее, можно с уверенностью сказать, что это не проблема Fabric. Извините за путаницу.

@code-tree это связано с тем, что было упомянуто ранее - оболочки имеют несколько разных режимов, в которых они работают, часто называемые 'логином' и 'интерактивным' (и обычно они находятся поверх базового режима, который не считается ни тем, ни другим) и какой режим оболочка запускается, изменяет набор загружаемых rc-файлов.

Важным моментом здесь является то, что bash -c xxx не считается "интерактивным" и поэтому пропускает загрузку определенных файлов - например, .bash_profile - а просто запускает bash без -c обычно интерактивен и загружает файлы профиля.

Как вы видели выше, sshd всегда запускает bash -c <command send down the pipe> когда вы просите его запустить одну команду (как это делает Fabric или как ssh host command ), и, таким образом, всегда находится в неинтерактивном режиме. (Если вы не сделаете то, что делает Fabric 1, и не запустите свою собственную вложенную оболочку с -l ... но тогда вы используете bash -c "bash -l -c \"oh god escaping is hard help\"" и я собираюсь попробовать 🥃 сейчас.

В любом случае, не все потеряно, мне нужно обновлять память об этой части вещей каждые несколько лет, очевидно, так что э-э ... теперь я освежился 😆

Это крутая штука, а не фантастика.

Какие файлы bash решает использовать при запуске, может быть сложно http://blog.flowblok.id.au/2013-02/shell-startup-scripts.html, а debian / ubuntu (и большинство дистрибутивов) имеют некоторую настройку в /etc/profile и по умолчанию ~/.bashrc .

По умолчанию fab использует оболочку /bin/bash -l -c , а -l делает ее оболочкой «входа в систему». Без настройки debian / ubuntu оболочка «входа в систему» ​​bash может получить ~/.bash_profile но не ~/.bashrc .

Но в ubuntu 16.04 он, похоже, по умолчанию использует .bashrc даже для оболочки входа. Но строки, добавленные в нижней части значения по умолчанию .bashrc , не обрабатываются, потому что он отключается вверху, если обнаруживает, что он работает не интерактивно.

Здесь я добавил две строки к пользователю ubuntu-16.04 по умолчанию .bashrc

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

export VAR1=val1

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

export VAR2=val2

# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth
...

Вот файл, с которым я тестирую:

from fabric.api import run, env, task

<strong i="24">@task</strong>
def get_myvars():
    run("echo VAR1=$VAR1 VAR2=$VAR2")

Результаты, достижения:

$ fab -H testpy05.ec2.st-av.net get_myvars
[testpy05.ec2.st-av.net] Executing task 'get_myvars'
[testpy05.ec2.st-av.net] run: echo VAR1=$VAR1 VAR2=$VAR2
[testpy05.ec2.st-av.net] out: VAR1=val1 VAR2=
[testpy05.ec2.st-av.net] out: 
...

Вы спасли мою жизнь. Это идеальный ответ, который я нахожу :) Большое спасибо!

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

Смежные вопросы

harobed picture harobed  ·  5Комментарии

Grazfather picture Grazfather  ·  4Комментарии

peteruhnak picture peteruhnak  ·  4Комментарии

TimotheeJeannin picture TimotheeJeannin  ·  3Комментарии

bitprophet picture bitprophet  ·  4Комментарии