Fabric: Problem mit Umgebungsvariablen und PATH auf dem Remote-Server (nicht .bashrc beziehen)

Erstellt am 9. Okt. 2016  Â·  22Kommentare  Â·  Quelle: fabric/fabric

Hi,

Ich versuche, die .bashrc-Datei zu laden (dh source /home/ubuntu/.bashrc), wenn ich den run-Befehl von Fab ausfĂŒhre, um einige Umgebungsvariablen hinzuzufĂŒgen und die Pfadvariable zu erweitern:

run('source /home/ubuntu/.bashrc && echo $PFAD')

Das zeigt mir nur:

[[email protected]] aus: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin: /bin:/usr/games:/usr/local/games

anstelle einer viel lÀngeren Liste von Pfaden, die ich sehe, wenn ich mich manuell beim Remote-Server anmelde.

Wie kann ich die .bashrc-Datei richtig in mein Remote-Home-Verzeichnis importieren?

Dankeschön!

Hilfreichster Kommentar

Das ist eine Bash-Sache, keine tolle Sache.

Welche Dateien die Bash beim Start als Quelle wĂ€hlt, kann kompliziert sein http://blog.flowblok.id.au/2013-02/shell-startup-scripts.html und debian/ubuntu (und die meisten Distributionen) haben einige Anpassungen in /etc/profile und standardmĂ€ĂŸig ~/.bashrc .

Die Standard-Shell-Fab ist /bin/bash -l -c , und -l macht sie zu einer "Login"-Shell. Ohne die debian/ubuntu-Anpassung ist es fĂŒr eine bash-"login"-Shell möglich, ~/.bash_profile aber nicht ~/.bashrc .

Aber unter Ubuntu 16.04 scheint es standardmĂ€ĂŸig .bashrc sogar fĂŒr die Login-Shell. Aber Zeilen, die am unteren Rand eines Standard- .bashrc hinzugefĂŒgt werden, werden nicht verarbeitet, da es am oberen Rand aussteigt, wenn es erkennt, dass es nicht interaktiv ausgefĂŒhrt wird.

Hier habe ich dem Ubuntu-16.04-Standardbenutzer .bashrc zwei Zeilen hinzugefĂŒgt

# ~/.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
...

Hier ist eine Fabfile, mit der ich teste:

from fabric.api import run, env, task

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

Die Ergebnisse:

$ 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: 
...

Alle 22 Kommentare

Das ist eine Bash-Sache, keine tolle Sache.

Welche Dateien die Bash beim Start als Quelle wĂ€hlt, kann kompliziert sein http://blog.flowblok.id.au/2013-02/shell-startup-scripts.html und debian/ubuntu (und die meisten Distributionen) haben einige Anpassungen in /etc/profile und standardmĂ€ĂŸig ~/.bashrc .

Die Standard-Shell-Fab ist /bin/bash -l -c , und -l macht sie zu einer "Login"-Shell. Ohne die debian/ubuntu-Anpassung ist es fĂŒr eine bash-"login"-Shell möglich, ~/.bash_profile aber nicht ~/.bashrc .

Aber unter Ubuntu 16.04 scheint es standardmĂ€ĂŸig .bashrc sogar fĂŒr die Login-Shell. Aber Zeilen, die am unteren Rand eines Standard- .bashrc hinzugefĂŒgt werden, werden nicht verarbeitet, da es am oberen Rand aussteigt, wenn es erkennt, dass es nicht interaktiv ausgefĂŒhrt wird.

Hier habe ich dem Ubuntu-16.04-Standardbenutzer .bashrc zwei Zeilen hinzugefĂŒgt

# ~/.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
...

Hier ist eine Fabfile, mit der ich teste:

from fabric.api import run, env, task

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

Die Ergebnisse:

$ 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: 
...

Klingt auf den ersten Blick echt, danke @ploxiln!

Vielen Dank fĂŒr die ausfĂŒhrliche Antwort!

Dies scheint sich vom Standard-SSH-Verhalten zu unterscheiden und war schwer zu debuggen. Wenn ich manuell ssh'd, funktionierte alles gut, wobei Fabric einen anderen PATH-Wert hatte, weil .bash_profile in OSX nicht ausgefĂŒhrt wurde.

@bitprophet Dies kann ein OSX-Fehler sein??

@code-tree Verwenden Sie Stoff 1 oder 2? 1.x verwendet explizite Shell-Wrapper, weshalb es sich vom Standard-OpenSSH-Client unterscheiden wĂŒrde; Version 2 macht kein Wrapping und sollte sich in Bezug auf das, was der sshd in Ihrem Namen ausfĂŒhrt, eher wie der OpenSSH-Client verhalten.

Version 1 hat einige env config-Wert-Optionen zum Ändern dieses Shell-Wrappers, also sollten Sie versuchen, Flags hinzuzufĂŒgen, wie -i die IIRC ist Bash fĂŒr "Run interaktiven Modus und source einige zusĂ€tzliche Dateien".

Das ist seltsam, weil ich die Version 2.2.1 . Derzeit muss ich Folgendes tun, damit meine App funktioniert:
c.run('bash -l -c "python3 ./configure.py"')
Wie bei der Installation von Python 3 hat es sich ĂŒber mein .bash_profile zu PATH hinzugefĂŒgt, das nicht von Fabric ausgefĂŒhrt wird. Ich habe auch keine Änderungen an der standardmĂ€ĂŸig eingebauten sshd-Konfiguration vorgenommen.

Das ist dann seltsam, ich muss sehen, ob ich replizieren kann. Ich habe nur eine kurze geistige Spur gemacht, um zu beweisen, was ich meine bezĂŒglich: Fabric 2 macht nichts "Besonderes" bezĂŒglich: sshd-gesteuerte AusfĂŒhrung:

@code-tree auch, wenn Sie können, posten Sie bitte einige weitere Details darĂŒber, was Sie genau ausfĂŒhren und andere Umgebungsdetails (Client- und Server-Betriebssystem / -Version usw. usw.).

Klar, ich verwende eine alte OSX-Version als Server. Wenn Sie bestÀtigen können, dass alles auf einem neueren MacOS funktioniert, dann na ja. Aber wenn nicht, dann vielleicht ein Problem mit MacOS als Server im Allgemeinen?

  • Client: Ubuntu 16.04, Python 3.6.6, OpenSSH 7.2p2, Bash 4.3.48, Fabric 2.2.1
  • Server: OSX 10.11, Python 3.6.6, OpenSSH 6.9p1, Bash 3.2.57

Randnotiz, ich frage mich, ob dies tatsÀchlich ein Fall von Fehldiagnose ist:

Fabric hatte einen anderen PATH-Wert, weil .bash_profile in OSX nicht ausgefĂŒhrt wurde

Könnte dies stattdessen ein Beispiel fĂŒr #1744 sein, bei dem sich Fabric 2 von ssh in Bezug auf das Rangieren lokaler Umgebungsvariablen in der Leitung unterscheidet? (HĂ€ngt von den genauen env vars ab und ob sie lokal und remote Ă€hnlich sein könnten; @code-tree könnte diese Theorie leicht widerlegen, indem es die genauen Werte im Spiel ĂŒberprĂŒft: ihr lokales und entferntes bash_profile ... 😁)


Aber ich werde dies trotzdem sofort beheben, nur damit ich weiß, dass ich nicht verrĂŒckt bin in Bezug auf mein VerstĂ€ndnis davon, was die sshd in Bezug auf Shells und Quelldateien tut.

Ich frage mich auch, ob dies mit dem Szenario / der Intelligenz von #1816 zusammenhÀngt, bei dem es auch um Shells und Startdateien geht. Es ist _wahrscheinlich_ nicht direkt relevant, da hier behauptet wird, dass sich ssh eine Richtung und Fabric in eine andere Richtung verhÀlt (im Gegensatz dazu, wie "sshd die Shell normalerweise aufruft"), aber es lohnt sich auf jeden Fall, verlinkt zu werden.

Ich habe festgestellt, dass ich in den letzten Monaten versucht habe, ĂŒber einen Haufen tiefer sshd-Code-TauchgĂ€nge zu stolpern, die mit etwas in dieser Richtung zu tun haben. Ich kann es jetzt aber nicht finden, was nervt. BEARBEITEN: ah, ich denke, es war ein nicht verwandtes Paramiko-Problem (kein Verlinken, da es keinen Sinn macht, Dinge zu verwirren) ĂŒber das AusfĂŒhren von Befehlen vor der Authentifizierung. OK.

Alles klar, was passiert also wirklich, wenn wir Command Exec anfordern?

  • SSH-the-protocol möchte, dass Sie entweder eine shell Kanalanfrage (die das definierte Login-Shell-Programm des Benutzers lĂ€dt und keine command ) oder einen exec Kanal machen request (die nur sagt "fĂŒhrt eine gegebene Befehlszeichenfolge aus, die einen Pfad enthalten kann" und gibt nicht mehr an)
  • Paramiko macht letzteres, wie wir oben festgestellt haben.
  • Was macht OpenSSH selbst eigentlich? Ich werde mir meine lokale Kasse von openssh-portable ansehen (bei 775f8a23f2353f5869003c57a213d14b28e0736e )

Nun, zuerst werde ich ein bisschen herumalbern. LĂ€uft gegen einen beliebigen Debian 8.10-Container (der OpenSSH 6.7 ausfĂŒhrt!) Ich sehe dies in den Protokollen der DEBUG3-Ebene, wenn ich ssh localhost whoami mache:

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 tun:

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

OK, sie machen beide exec ...das ist zu erwarten. Etwas anders im Prozessbaum? sollte nicht sein, und ... gibt es nicht. beide sehen so aus:

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

Also definitiv keine Muschel im Spiel? Was macht es ĂŒberhaupt? Kann ich Shelly-Dinge wie && ?

Ich kann! zB whoami && id funktioniert gut. Angesichts meines VerstĂ€ndnisses von Unix-Prozesskontrolle ist das etwas seltsam; es scheint unwahrscheinlich, dass sshd nur buchstĂ€blich exec(string) ausfĂŒhrt, aber wenn es eine Shell zum Interpretieren verwenden wĂŒrde, wĂŒrden wir das nicht in pstree ?

Ich denke, es ist an der Zeit, sich mit openssh-portable auseinanderzusetzen und zu sehen, was was ist.


Auch, huh, ich habe einen Teil dieser Nachverfolgung (aber aus einem anderen Grund/Schwerpunkt) in der Vergangenheit gemacht, wie im Dezember 2016: https://github.com/paramiko/paramiko/pull/398#issuecomment -264281759. Hatte total vergessen...


Der Grund, warum ich die Shell in pstree nicht sehe, liegt an der Verwendung von execve , die einen Elternprozess ersetzt, anstatt ein Kind zu erzeugen. Gut zu wissen. (EDIT: falsch, das ersetzt nur den sshd-Kind-Proc durch die Shell; die Shell selbst fĂŒhrt dann möglicherweise auch einen Exec-Aufruf im Stil von replace-me durch; siehe Kommentare unten.)


Wie auch immer, so! Dies sollte immer noch bedeuten, dass die Clients von Fabric und OpenSSH in Bezug auf die Shell-AusfĂŒhrung genau dasselbe tun; nichts von ihnen wĂŒrde diese Teile der OpenSSH-Codebasis modifizieren. Es sollte immer so etwas wie bash -c "python3 ./configure.py" , mit dem tatsĂ€chlichen Wert von bash abhĂ€ngig vom macOS-Level-Benutzer von @code-tree und seiner konfigurierten Shell.

Ich frage mich, ob meine Vermutung, dass die env var-Übertragung das Unterscheidungsmerkmal ist, richtig ist, da dies das einzige andere ist, was mir einfĂ€llt: wie sich die beiden AusfĂŒhrungsumgebungen unterscheiden könnten. FWIW in meinen CLI-fokussierten Tests meldet env auf beiden Systemen dasselbe, und unabhĂ€ngig von diesen anderen umgebungsbezogenen Problemen sollte das _default_-Verhalten (aufgrund der SSH-Sicherheitsrichtlinie) immer so sein, dass keine lokale Umgebung "durchsickert". Die andere Seite.

Ja, ich bin mir ziemlich sicher, dass sshd die Befehlszeichenfolge immer in der Shell des Benutzers ausfĂŒhrt (konfiguriert in /etc/passwd). Es stellt jedoch der Befehlszeichenfolge "exec" voran, wenn es die Befehlszeichenfolge analysieren und feststellen kann, dass es sich um einen einzelnen Befehl handelt.

$ 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

Die Umgebungsvariablen werden hauptsÀchlich von den ssh-Client- und sshd-Server-Konfigurationen gesteuert:

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

Der ssh-Client sendet also explizit einige Variablen (außerhalb des Befehlsstrings selbst) und sie werden von sshd gefiltert. Aber es gibt anscheinend einige Ausnahmen:

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

TatsĂ€chlich denke ich, dass das Verhalten "automatische AusfĂŒhrung zum Ersetzen der Shell durch einen einzelnen Befehl" eine Funktion von bash ist:

$ 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

EDIT: Der VollstÀndigkeit halber:

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

Ah ja, ich habe mich geirrt, execve bedeutet nur, dass der sshd-Kind-Proc ersetzt wird, also was danach passiert, liegt an der Shell selbst und was sie fĂŒr -c xxx tut. Meine Tests waren in zsh, fwiw.

Auch @ploxiln ja, die Sache mit env vars verweist auf andere oben verlinkte Tickets, obwohl es abzuwarten bleibt, ob @code-tree wirklich ein anderes Symptom als diese aufweist.

Tut mir leid, ich denke, das ist ein Fehlalarm. Mir war nicht bewusst, dass es einen Unterschied zwischen der AusfĂŒhrung eines Befehls ĂŒber ssh inline und der AusfĂŒhrung nach der Anmeldung ĂŒber ssh gibt. Wenn ich ssh host 'echo $PATH' mache, hat es auch PATH nicht aktualisiert, wĂ€hrend echo $PATH nach dem Anmelden gut funktioniert.

Ich verstehe immer noch nicht wirklich, warum ssh dies tut (scheint, als mĂŒsste ich tatsĂ€chlich ssh host 'bash -l -c "python3 ./configure.py"' tun). UnabhĂ€ngig davon kann man mit Sicherheit sagen, dass dies kein Fabric-Problem ist. Entschuldigung fĂŒr die Verwirrung.

@code-tree es hĂ€ngt mit dem zusammen, was zuvor erwĂ€hnt wurde - Shells haben ein paar verschiedene Modi, in denen sie arbeiten, hĂ€ufig als "Anmeldung" und "interaktiv" bezeichnet (und normalerweise liegen diese ĂŒber einem Basismodus, der als keiner angesehen wird) und welcher Modus die Shell ausgefĂŒhrt wird, Ă€ndert den Satz von rc-Dateien, die sie lĂ€dt.

Der hervorstechende Punkt hier ist, dass bash -c xxx nicht als "interaktiv" angesehen wird und daher das Laden bestimmter Dateien ĂŒberspringt - wie .bash_profile - sondern nur bash ohne -c ist normalerweise interaktiv und lĂ€dt Profildateien.

Wie Sie oben gesehen haben, fĂŒhrt sshd immer bash -c <command send down the pipe> wenn Sie es auffordern, einen einzelnen Befehl auszufĂŒhren (wie es Fabric oder ssh host command tut) und befindet sich daher immer im nicht interaktiven Modus. (Es sei denn , Sie tun , was Stoff 1 tut , und fĂŒhren Sie Ihre eigene, verschachtelt, Shell mit -l ... aber dann Sie laufen bash -c "bash -l -c \"oh god escaping is hard help\"" und ich werde einige đŸ„ƒ jetzt gehen.

Wie auch immer, nicht alles ist verloren, ich muss meine Erinnerung an diesen Teil der Dinge anscheinend alle paar Jahre auffrischen, also Ă€h...jetzt bin ich erfrischt 😆

Das ist eine Bash-Sache, keine tolle Sache.

Welche Dateien die Bash beim Start als Quelle wĂ€hlt, kann kompliziert sein http://blog.flowblok.id.au/2013-02/shell-startup-scripts.html und debian/ubuntu (und die meisten Distributionen) haben einige Anpassungen in /etc/profile und standardmĂ€ĂŸig ~/.bashrc .

Die Standard-Shell-Fab ist /bin/bash -l -c , und -l macht sie zu einer "Login"-Shell. Ohne die debian/ubuntu-Anpassung ist es fĂŒr eine bash-"login"-Shell möglich, ~/.bash_profile aber nicht ~/.bashrc .

Aber unter Ubuntu 16.04 scheint es standardmĂ€ĂŸig .bashrc sogar fĂŒr die Login-Shell. Aber Zeilen, die am unteren Rand eines Standard- .bashrc hinzugefĂŒgt werden, werden nicht verarbeitet, da es am oberen Rand aussteigt, wenn es erkennt, dass es nicht interaktiv ausgefĂŒhrt wird.

Hier habe ich dem Ubuntu-16.04-Standardbenutzer .bashrc zwei Zeilen hinzugefĂŒgt

# ~/.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
...

Hier ist eine Fabfile, mit der ich teste:

from fabric.api import run, env, task

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

Die Ergebnisse:

$ 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: 
...

Du hast mein Leben gerettet. Dies ist die perfekte Antwort, die ich finde :) Vielen Dank!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen