Fabric: ProblĂšme avec les variables d'environnement et le PATH sur le serveur distant (pas de sourcing .bashrc)

CrĂ©Ă© le 9 oct. 2016  Â·  22Commentaires  Â·  Source: fabric/fabric

Salut,

J'essaie de charger le fichier .bashrc (c'est-à-dire source /home/ubuntu/.bashrc) lors de l'exécution de la commande run de fab pour ajouter des variables d'environnement et développer la variable de chemin :

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

Cela ne m'affiche que :

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

au lieu d'une liste beaucoup plus longue de chemins que je vois lorsque je me connecte manuellement au serveur distant.

Comment faire en sorte que fab importe correctement le fichier .bashrc dans mon répertoire personnel distant ?

Merci!

Commentaire le plus utile

C'est une chose bash, pas une chose fabuleuse.

Les fichiers que bash dĂ©cide de source au dĂ©marrage peuvent ĂȘtre compliquĂ©s http://blog.flowblok.id.au/2013-02/shell-startup-scripts.html et debian/ubuntu (et la plupart des distributions) ont une certaine personnalisation dans /etc/profile et dans la valeur par dĂ©faut ~/.bashrc .

Le shell par défaut utilisé par fab est /bin/bash -l -c , et le -l fait un shell de "connexion". Sans la personnalisation debian/ubuntu, il est possible pour un shell de "connexion" bash de sourcer ~/.bash_profile mais pas ~/.bashrc .

Mais sur Ubuntu 16.04, il semble que la source .bashrc par dĂ©faut, mĂȘme pour login-shell. Mais les lignes ajoutĂ©es au bas d'un .bashrc par dĂ©faut ne sont pas traitĂ©es, car il se sauve prĂšs du haut s'il dĂ©tecte une exĂ©cution non interactive.

Ici, j'ai ajouté deux lignes à l'utilisateur par défaut d'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
...

Voici un fabfile avec lequel je teste :

from fabric.api import run, env, task

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

Les résultats:

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

Tous les 22 commentaires

C'est une chose bash, pas une chose fabuleuse.

Les fichiers que bash dĂ©cide de source au dĂ©marrage peuvent ĂȘtre compliquĂ©s http://blog.flowblok.id.au/2013-02/shell-startup-scripts.html et debian/ubuntu (et la plupart des distributions) ont une certaine personnalisation dans /etc/profile et dans la valeur par dĂ©faut ~/.bashrc .

Le shell par défaut utilisé par fab est /bin/bash -l -c , et le -l fait un shell de "connexion". Sans la personnalisation debian/ubuntu, il est possible pour un shell de "connexion" bash de sourcer ~/.bash_profile mais pas ~/.bashrc .

Mais sur Ubuntu 16.04, il semble que la source .bashrc par dĂ©faut, mĂȘme pour login-shell. Mais les lignes ajoutĂ©es au bas d'un .bashrc par dĂ©faut ne sont pas traitĂ©es, car il se sauve prĂšs du haut s'il dĂ©tecte une exĂ©cution non interactive.

Ici, j'ai ajouté deux lignes à l'utilisateur par défaut d'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
...

Voici un fabfile avec lequel je teste :

from fabric.api import run, env, task

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

Les résultats:

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

Cela semble lĂ©gitime en un coup d'Ɠil, merci @ploxiln !

Merci pour la réponse détaillée !

Cela semble différer du comportement standard de ssh et était difficile à déboguer. Lorsque j'ai ssh manuellement, tout a bien fonctionné, alors que Fabric avait une valeur PATH différente en raison de la non-exécution de .bash_profile dans OSX.

@bitprophet cela peut ĂȘtre un bogue OSX ??

@code-tree Utilisez-vous Fabric 1 ou 2 ? 1.x utilise des enveloppes de shell explicites, ce qui expliquerait pourquoi il diffÚre du client OpenSSH standard ; la version 2 ne fait aucun wrapping et devrait se comporter beaucoup plus comme un client OpenSSH en termes de ce que le sshd exécute en votre nom.

La version 1 a quelques options de valeur de configuration env pour changer ce wrapper shell, vous pouvez donc essayer d'y ajouter des indicateurs, comme -i que IIRC est bash pour "exécuter le mode interactif et sourcer des fichiers supplémentaires".

C'est étrange car j'utilise la version 2.2.1 . Je dois actuellement effectuer les opérations suivantes pour que mon application fonctionne :
c.run('bash -l -c "python3 ./configure.py"')
Comme lorsque j'ai installé Python 3, il s'est ajouté à PATH via mon .bash_profile , qui n'est pas exécuté par Fabric. Je n'ai pas non plus apporté de modifications à la configuration standard de sshd intégrée.

C'est étrange alors, je vais devoir voir si je peux reproduire. Je viens de faire un rapide suivi de la raison pour prouver ce que je veux dire concernant : Fabric 2 ne fait rien de « spécial » concernant : exécution pilotée par sshd :

@code-tree également, si vous le pouvez, veuillez publier plus de détails sur ce que vous exécutez exactement et d'autres détails environnementaux (systÚme d'exploitation/version client et serveur, etc.).

Bien sĂ»r, j'utilise une ancienne version d'OSX en tant que serveur. Si vous pouvez confirmer que tout fonctionne bien sur un nouveau MacOS, alors tant pis. Mais sinon, peut-ĂȘtre un problĂšme avec MacOS en tant que serveur en gĂ©nĂ©ral ?

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

Note latérale, je me demande s'il s'agit réellement d'un cas d'erreur de diagnostic :

Fabric avait une valeur PATH différente en raison de l'absence d'exécution de .bash_profile dans OSX

Serait-ce plutĂŽt un exemple de #1744, oĂč Fabric 2 diffĂšre de ssh en termes de shunt des variables d'environnement locales dans le tuyau ? (Cela dĂ©pend des variables d'environnement exactes en question et si elles peuvent ĂȘtre similaires localement et Ă  distance ; @code-tree pourrait facilement rĂ©futer cette thĂ©orie en vĂ©rifiant deux fois les valeurs exactes en jeu concernant : leur bash_profile local et distant... 😁)


Mais je vais quand mĂȘme rĂ©soudre ce problĂšme, juste pour que je sache que je ne suis pas fou de ma comprĂ©hension de ce que fait le sshd en termes de shells et de fichiers sourcĂ©s.

Je me demande Ă©galement si cela est liĂ© au scĂ©nario/intelligence de #1816, qui concerne Ă©galement les shells et les fichiers de dĂ©marrage. Ce n'est _probablement_ pas directement pertinent Ă  cause de l'affirmation ici selon laquelle ssh se comporte d'une maniĂšre et Fabric se comporte d'une autre maniĂšre (par opposition Ă  "juste comment le sshd appelle le shell normalement"), mais cela vaut la peine d'ĂȘtre liĂ© de toute façon.

J'ai trouvé que j'avais essayé de trébucher sur un tas de plongée dans le code sshd en profondeur que je me souviens avoir fait au cours des derniers mois, lié à quelque chose de ce genre. Je ne le trouve pas maintenant, ce qui est irritant. EDIT : ah, je pense que c'était un problÚme de Paramiko sans rapport (pas de lien car cela ne sert à rien de confondre) concernant l'exécution de commandes avant l'authentification. D'ACCORD.

D'accord, que se passe-t-il vraiment lorsque nous demandons l'exécution de la commande ?

  • SSH-the-protocol veut que vous fassiez une demande de canal shell (qui charge le programme shell de connexion dĂ©fini par l'utilisateur et ne prend aucun command ) ou un canal exec request (qui dit simplement "exĂ©cute une chaĂźne de commande donnĂ©e, qui peut contenir un chemin" et n'en spĂ©cifie pas plus)
  • Paramiko fait ce dernier, comme nous l'avons trouvĂ© ci-dessus.
  • Alors, que fait OpenSSH lui-mĂȘme ? Je vais regarder ma caisse locale d'opensh-portable (Ă  775f8a23f2353f5869003c57a213d14b28e0736e )

Eh bien, d'abord, je vais m'amuser un peu. Exécution sur un conteneur Debian 8.10 arbitraire (qui exécute OpenSSH 6.7 !) Je vois ceci dans les journaux de niveau DEBUG3 en faisant 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

Faire 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

OK, ils font tous les deux exec ... c'est normal. Quelque chose de diffĂ©rent dans l'arborescence des processus ? ne devrait pas ĂȘtre, et... il n'y en a pas. les deux ressemblent Ă  ça :

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

Alors, dĂ©finitivement pas de coquille en jeu ? Qu'est-ce qu'il fait mĂȘme? Puis-je utiliser des choses shelly comme && ?

Je peux! par exemple whoami && id fonctionne trÚs bien. C'est donc un peu bizarre étant donné ma compréhension du contrÎle de processus Unix ; il semble peu probable que sshd fasse littéralement exec(string) , mais s'il utilisait un shell pour interpréter, ne verrions-nous pas cela dans pstree ?

Je pense qu'il est temps de vraiment creuser dans openssh-portable et de voir ce qu'il en est.


De plus, hein, j'ai fait une partie de ce traçage (mais pour une raison/un focus différent) dans le passé, comme en décembre 2016 : https://github.com/paramiko/paramiko/pull/398#issuecomment -264281759. Avait totalement oublié...


La raison pour laquelle je ne vois pas le shell dans pstree est l'utilisation de execve , qui remplace le processus parent au lieu de gĂ©nĂ©rer un enfant. Bon Ă  savoir. (EDIT: faux, cela remplace simplement le proc enfant sshd par le shell; le shell lui-mĂȘme peut alors Ă©galement effectuer un appel exec de style replace-me; voir les commentaires ci-dessous.)


En tout cas, alors ! Cela devrait toujours signifier que les clients de Fabric et OpenSSH font exactement la mĂȘme chose en termes d'exĂ©cution du shell ; rien de ce qu'ils font ne modifierait ces parties de la base de code d'OpenSSH. Cela devrait toujours ĂȘtre quelque chose comme bash -c "python3 ./configure.py" , avec la valeur rĂ©elle de bash fonction de l'utilisateur de niveau macOS de @code-tree et de son shell configurĂ©.

Je me demande si mon intuition que la transmission env var est le diffĂ©renciateur est exacte, car c'est la seule autre chose Ă  laquelle je peux penser: comment les deux environnements d'exĂ©cution pourraient diffĂ©rer. FWIW dans mes tests axĂ©s sur la CLI, env rapporte la mĂȘme chose sur les deux systĂšmes, et indĂ©pendamment de ces autres problĂšmes liĂ©s Ă  l'environnement, le comportement _default_ (en raison de la politique de sĂ©curitĂ© SSH) devrait toujours ĂȘtre qu'aucun environnement local ne "fuit" vers l'autre cĂŽtĂ©.

Oui, je suis presque sûr que sshd exécute toujours la chaßne de commande dans le shell de l'utilisateur (configuré dans /etc/passwd). Cependant, il ajoute "exec" à la chaßne de commande s'il peut analyser la chaßne de commande et déterminer qu'il s'agit d'une seule commande.

$ 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

Quant aux variables d'environnement, elles sont principalement contrÎlées par les configurations du client ssh et du serveur sshd :

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

Ainsi, le client ssh envoie explicitement certaines variables (en dehors de la chaĂźne de commande elle-mĂȘme) et elles sont filtrĂ©es par sshd. Mais il y a apparemment quelques exceptions :

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

En fait, je pense que le comportement "exécution automatique pour remplacer le shell par une seule commande" est une fonctionnalité de 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

EDIT : Pour ĂȘtre complet :

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

Ah oui, je me suis trompĂ©, execve signifie simplement que le proc enfant sshd est ce qui est remplacĂ©, donc ce qui se passe aprĂšs cela dĂ©pend du shell lui-mĂȘme et de ce qu'il fait pour -c xxx . Mes tests Ă©taient en zsh, fwiw.

Aussi @ploxiln oui, le truc avec env vars fait référence à d'autres tickets liés ci-dessus, bien qu'il reste à voir si @code-tree éprouve vraiment un symptÎme différent de ceux-ci.

DĂ©solĂ©, je pense que c'est une fausse alerte. Je ne savais pas qu'il y avait une diffĂ©rence entre l'exĂ©cution d'une commande via ssh en ligne et l'exĂ©cution aprĂšs la connexion via ssh. Quand je fais ssh host 'echo $PATH' il n'a pas non plus mis Ă  jour PATH oĂč echo $PATH aprĂšs la connexion fonctionne bien.

Je ne comprends toujours pas pourquoi ssh fait cela (il me semble que je dois effectivement faire ssh host 'bash -l -c "python3 ./configure.py"' ). Quoi qu'il en soit, il est sûr de dire que ce n'est pas un problÚme de Fabric aprÚs tout. Désolé pour la confusion.

@code-tree c'est lié à ce qui a été mentionné précédemment - les shells ont quelques modes différents dans lesquels ils fonctionnent, fréquemment appelés "connexion" et "interactif" (et généralement ceux-ci sont au-dessus d'un mode de base qui n'est considéré ni) et quel mode le shell est en cours d'exécution, change l'ensemble de fichiers rc qu'il charge.

Le point saillant ici est que bash -c xxx n'est pas considéré comme "interactif" et saute donc le chargement de certains fichiers - comme .bash_profile - mais exécute simplement bash sans -c est généralement interactif et charge les fichiers de profil.

Comme vous l'avez vu ci-dessus, sshd exĂ©cute toujours bash -c <command send down the pipe> lorsque vous lui demandez d'exĂ©cuter une seule commande (comme le fait Fabric ou ssh host command ), et est donc toujours en mode non interactif. (À moins que vous ne fassiez ce que Fabric 1 fait et exĂ©cutez votre propre shell imbriquĂ© avec -l ... mais alors vous exĂ©cutez bash -c "bash -l -c \"oh god escaping is hard help\"" et je vais en avoir đŸ„ƒ maintenant.

Quoi qu'il en soit, tout n'est pas perdu, j'ai besoin de me rafraĂźchir la mĂ©moire de cette partie des choses toutes les quelques annĂ©es apparemment donc euh... maintenant je suis rafraĂźchi 😆

C'est une chose bash, pas une chose fabuleuse.

Les fichiers que bash dĂ©cide de source au dĂ©marrage peuvent ĂȘtre compliquĂ©s http://blog.flowblok.id.au/2013-02/shell-startup-scripts.html et debian/ubuntu (et la plupart des distributions) ont une certaine personnalisation dans /etc/profile et dans la valeur par dĂ©faut ~/.bashrc .

Le shell par défaut utilisé par fab est /bin/bash -l -c , et le -l fait un shell de "connexion". Sans la personnalisation debian/ubuntu, il est possible pour un shell de "connexion" bash de sourcer ~/.bash_profile mais pas ~/.bashrc .

Mais sur Ubuntu 16.04, il semble que la source .bashrc par dĂ©faut, mĂȘme pour login-shell. Mais les lignes ajoutĂ©es au bas d'un .bashrc par dĂ©faut ne sont pas traitĂ©es, car il se sauve prĂšs du haut s'il dĂ©tecte une exĂ©cution non interactive.

Ici, j'ai ajouté deux lignes à l'utilisateur par défaut d'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
...

Voici un fabfile avec lequel je teste :

from fabric.api import run, env, task

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

Les résultats:

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

Tu m'as sauvé la vie. C'est la réponse parfaite que je trouve :) Merci beaucoup !

Cette page vous a été utile?
0 / 5 - 0 notes