Fabric: مشكلة تتعلق بالمتغيرات البيئية و PATH على الخادم البعيد (عدم تحديد مصادر .bashrc)

تم إنشاؤها على ٩ أكتوبر ٢٠١٦  ·  22تعليقات  ·  مصدر: fabric/fabric

أهلا،

أحاول تحميل ملف .bashrc (مثل source /home/ubuntu/.bashrc) عند تشغيل أمر fab's run لإضافة بعض المتغيرات البيئية وتوسيع متغير المسار:

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

هذا يظهر لي فقط:

[[email protected]] خارج: / usr / local / sbin: / usr / local / bin: / usr / sbin: / usr / bin: / sbin: / bin: / usr / games: / usr / local / games

بدلاً من قائمة المسارات الأطول بكثير التي أراها عند تسجيل الدخول إلى الخادم البعيد يدويًا.

كيف يمكنني الحصول على fab لاستيراد ملف .bashrc بشكل صحيح في دليل منزلي البعيد؟

شكرا لك!

التعليق الأكثر فائدة

هذا شيء باش ، وليس شيئًا رائعًا.

يمكن أن تكون الملفات التي يقرر bash مصدرها عند بدء التشغيل معقدة http://blog.flowblok.id.au/2013-02/shell-startup-scripts.html و debian / ubuntu (ومعظم التوزيعات) لديها بعض التخصيص في /etc/profile وفي الإعداد الافتراضي ~/.bashrc .

يستخدم shell fab الافتراضي هو /bin/bash -l -c ، ويجعله -l غلاف "تسجيل دخول". بدون تخصيص debian / ubuntu ، يمكن لصدفة bash "تسجيل الدخول" إلى مصدر ~/.bash_profile لكن ليس ~/.bashrc .

ولكن في ubuntu 16.04 ، يبدو أنه مصدر .bashrc افتراضيًا حتى بالنسبة لـ login-shell. لكن الأسطر التي تمت إضافتها في الجزء السفلي من .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 .

يستخدم shell fab الافتراضي هو /bin/bash -l -c ، ويجعله -l غلاف "تسجيل دخول". بدون تخصيص debian / ubuntu ، يمكن لصدفة bash "تسجيل الدخول" إلى مصدر ~/.bash_profile لكن ليس ~/.bashrc .

ولكن في ubuntu 16.04 ، يبدو أنه مصدر .bashrc افتراضيًا حتى بالنسبة لـ login-shell. لكن الأسطر التي تمت إضافتها في الجزء السفلي من .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 القياسي وكان من الصعب تصحيحه. عندما عملت بشكل جيد يدويًا ، حيث كان للنسيج قيمة مسار مختلفة بسبب عدم تشغيل .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 المدمج القياسي أيضًا.

هذا غريب إذن ، يجب أن أرى ما إذا كان بإمكاني التكرار. لقد قمت للتو بتتبع عقلاني سريع لإثبات ما أعنيه فيما يتعلق بـ: Fabric 2 لا يقوم بأي شيء 'خاص' فيما يتعلق بتنفيذ 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 من حيث تحويل المتغيرات البيئية المحلية إلى أسفل الأنبوب؟ (يعتمد على المتغيرات البيئية الدقيقة المعنية وما إذا كانت متشابهة محليًا وعن بعد ؛ يمكن لـ @ code-tree دحض هذه النظرية بسهولة عن طريق التحقق المزدوج من القيم الدقيقة في التشغيل: ملف تعريف bash_profile المحلي والبعيد ... 😁)


لكنني سأقوم باستكشاف هذا الخطأ وإصلاحه على أي حال ، فقط حتى أعلم أنني لست مجنونًا: فهمي لما يفعله sshd من حيث الأصداف والملفات التي تم الحصول عليها.

وأتساءل أيضًا عما إذا كان هذا مرتبطًا بالسيناريو / الذكاء من # 1816 ، والذي يتعلق أيضًا بالصدفة وملفات بدء التشغيل. ربما لا يكون ذا صلة مباشرة بسبب التأكيد هنا على أن ssh يتصرف بطريقة ما ويتصرف Fabric بطريقة أخرى (على عكس كونه "فقط كيف يستدعي sshd الصدفة بشكل طبيعي") ، ولكنه يستحق الربط على أي حال.

وجدت أن محاولتي التعثر في مجموعة من الغوص العميق في كود sshd أتذكر أنني قمت به في الأشهر القليلة الماضية ، فيما يتعلق بشيء على غرار هذه الأسطر. لا يمكنني العثور عليه الآن رغم أنه مزعج. تحرير: آه أعتقد أنها كانت مشكلة Paramiko غير ذات صلة (لا ترتبط لأنه لا توجد نقطة تربك الأشياء) حول تنفيذ الأوامر قبل المصادقة. نعم.

حسنًا ، ما الذي يحدث حقًا عندما نطلب الأمر exec؟

  • يريدك SSH-the-protocol إما تقديم طلب قناة shell (والذي يقوم بتحميل برنامج shell المحدد لتسجيل الدخول للمستخدم ولا يأخذ أي قناة command ) أو قناة exec الطلب (الذي يقول فقط "ينفذ سلسلة أوامر معينة ، والتي قد تحتوي على مسار" ولا تحدد المزيد)
  • يقوم Paramiko بالأخير ، كما وجدنا أعلاه.
  • إذن ما الذي تفعله OpenSSH نفسها بالفعل؟ سأقوم بإلقاء نظرة على عملية الدفع المحلية الخاصة بي من opensh-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) حرفيًا ، ولكن إذا كان يستخدم shell للتفسير ، ألا نرى ذلك في pstree ؟

أعتقد أن الوقت قد حان للتنقيب حقًا في الفتحات المحمولة ومعرفة ما هو.


أيضًا ، هاه ، لقد قمت بجزء من هذا التتبع (ولكن لسبب / تركيز مختلف) في الماضي ، كما في ديسمبر 2016: https://github.com/paramiko/paramiko/pull/398#issuecomment -264281759. نسيت تماما ...


السبب في أنني لا أرى الصدفة في pstree بسبب استخدام execve ، والذي يقوم باستبدال العملية الأبوية بدلاً من إنجاب طفل. جيد ان تعلم. (EDIT: خطأ ، هذا فقط يستبدل proc sshd child بالصدفة ؛ قد تقوم الصدفة نفسها أيضًا بإجراء مكالمة exec على غرار الاستبدال ؛ انظر التعليقات أدناه.)


على أي حال ، هكذا! لا يزال هذا يعني أن عملاء Fabric و OpenSSH يفعلون نفس الشيء بالضبط فيما يتعلق بتنفيذ الصدفة ؛ لا شيء يفعله أي منهما هو تعديل هذه الأجزاء من قاعدة كود OpenSSH. يجب أن يكون دائمًا شيئًا مثل bash -c "python3 ./configure.py" ، مع القيمة الفعلية bash اعتمادًا على مستخدم مستوى macOS الخاص بـ @ code-tree والهيكل الذي تم تكوينه.

يجعلني أتساءل عما إذا كان حدسي حول انتقال env var هو أداة التفاضل دقيقًا ، لأن هذا هو الشيء الآخر الوحيد الذي يمكنني التفكير فيه: كيف يمكن أن تختلف بيئتا التنفيذ. FWIW في الاختبار الذي يركز على CLI ، تقارير env على كلا النظامين ، وبغض النظر عن تلك المشكلات الأخرى المتعلقة بالبيئة ، يجب أن يكون السلوك الافتراضي (بسبب سياسة أمان SSH) دائمًا هو عدم وجود بيئة محلية "تسرب" إلى الجانب الآخر.

نعم ، أنا متأكد من أن 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 التلقائي لاستبدال shell بأمر واحد" هو سمة من سمات 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 يعني فقط أن عملية sshd child هي ما يتم استبداله ، لذا فإن ما يحدث بعد ذلك يعود إلى الغلاف نفسه وما يفعله مقابل -c xxx . كانت اختباراتي في zsh ، fwiw.

أيضًا ploxiln نعم الشيء الذي يحتوي على env vars يشير إلى تذاكر أخرى مرتبطة أعلاه ، على الرغم من أنه يبقى أن نرى ما إذا كانت @ code-tree تعاني حقًا من أعراض مختلفة عن تلك.

آسف ، أعتقد أن هذا إنذار كاذب. لم أكن على علم بوجود أي اختلاف بين تنفيذ أمر عبر ssh المضمنة والتنفيذ بعد تسجيل الدخول عبر ssh. عندما أقوم بعمل ssh host 'echo $PATH' ، لم يتم أيضًا تحديث PATH حيث يعمل echo $PATH بعد تسجيل الدخول بشكل جيد.

ما زلت لا أفهم حقًا سبب قيام ssh بهذا (يبدو أنني يجب أن أفعل بالفعل ssh host 'bash -l -c "python3 ./configure.py"' ). بغض النظر ، من الآمن القول أن هذه ليست مشكلة قماش بعد كل شيء. اسف لخلط الامور.

@ code-tree إنه مرتبط بما تم ذكره سابقًا - تحتوي الأصداف على عدد قليل من الأوضاع المختلفة التي تعمل بها ، والتي يطلق عليها غالبًا "تسجيل الدخول" و "التفاعلية" (وعادة ما تكون تلك الأوضاع أعلى الوضع الأساسي الذي لا يعتبر أيًا منهما) وأي وضع يتم تشغيل shell فيه ، وتغيير مجموعة ملفات 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 .

يستخدم shell fab الافتراضي هو /bin/bash -l -c ، ويجعله -l غلاف "تسجيل دخول". بدون تخصيص debian / ubuntu ، يمكن لصدفة bash "تسجيل الدخول" إلى مصدر ~/.bash_profile لكن ليس ~/.bashrc .

ولكن في ubuntu 16.04 ، يبدو أنه مصدر .bashrc افتراضيًا حتى بالنسبة لـ login-shell. لكن الأسطر التي تمت إضافتها في الجزء السفلي من .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 التقييمات