paramiko獲取遠程主機的環境變量


本文的情況,不同的linux系統版本,表現可能不同。

 

問題:默認情況下,paramiko在遠程主機上執行命令的時候,命令的搜索路徑為(/usr/local/bin:/bin:/usr/bin),這樣我們安裝的軟件,如果命令不在這些路徑下的話,就會執行錯誤,報找不到命令的錯誤

解決辦法:

  1. 就是在上面的路徑里(/usr/local/bin:/bin:/usr/bin)加我們需要命令的軟鏈接(ln /usr/install/jdk1.8.0_60/bin/java -s java)
  2. 把需要的路徑包含進去 stdin, stdout, stderr = ssh.exec_command('export PATH=$PATH:/usr/local/install/xxx/;echo $PATH')
  3. 先執行一條命令 stdin, stdout, stderr = ssh.exec_command('. ~/.bashrc;echo $PATH');stdin, stdout, stderr = ssh.exec_command('source ~/.bashrc;bash test.sh')
  4. 方法2和3,環境變量可以傳到后續執行的‘.sh’腳本里面去
  5. paramiko的ssh.exec_command()命令會開啟一個單獨的session,而且在exec_command中設定的環境變量不會傳遞給后續的腳本。解決方法是使用bash執行命令:ssh.exec_command("bash -l -c 'some commands and some scripts...'")

  bash -l -c解釋:-l(login)表示bash作為一個login shell;-c(command)表示執行后面字符串內的命令,這樣執行的腳本,可以獲取到/etc/profile里的全局變量,包括我們搜索命令的目錄PATH

  • -l Make bash act as if it had been invoked as a login shell
  • -c If the -c option is present, then commands are read from string.
  • You're running the command passed to the -c argument. -l makes it a login shell so bash first reads /etc/profile,

 

遺留問題:為什么paramiko登錄后,只獲得路徑(/usr/local/bin:/bin:/usr/bin)

解答:密碼存在於被連接機器的/etc/ssh/sshd_config配置文件里;如下所示,sshd服務默認把(/usr/local/bin:/bin:/usr/bin)作為PATH的值

#       $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $

# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/local/bin:/bin:/usr/bin

# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented.  Uncommented options change a
# default value.

對於上面的SSHD默認PATH值,不同的Op'e'nBOpenBSD不一樣

#       $OpenBSD: sshd_config,v 1.101 2017/03/14 07:19:07 djm Exp $
  2
  3 # This is the sshd server system-wide configuration file.  See
  4 # sshd_config(5) for more information.
  5
  6 # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin 7
  8 # The strategy used for options in the default sshd_config shipped with
  9 # OpenSSH is to specify options with their default value where
 10 # possible, but leave them commented.  Uncommented options override the

 

再說一個實際驗證的結論:

ssh -T admin@10.x.x.x 'echo $PATH' 獲得什么環境變量呢?

-T 表示不使用偽終端(man -a ssh---->  -T      Disable pseudo-terminal allocation.)

那么沒有偽終端的話,獲得什么樣的PATH呢(其他環境變量類似)?

首先,通過上面的知識可知,SSHD是有個默認PATH值的,編譯到SSHD(ssh_server)的代碼里的(SSHD可能是C語音寫的吧);

其次,不使用偽終端登錄后,首先執行的用戶目錄下的bashrc腳本(~/.bashrc),一般bashrc腳本里面會執行腳本/etc/profile或者/etc/bashrc之類的;總之只要被bashrc執行產生的全局變量(export)都會傳遞到后續的腳本或者命令行里

上一步需要注意的一點就是,sshd即ssh_server必須使用bash作為登錄shell,而不是zsh等其他的shell(我以為如果登錄shell是zsh,會執行~/.zshrc,結果發現我錯了),如果使用的zsh,發現只讀到寫死到sshd_server里面的PATH值

 

我本機測試的結果是,下面三種情況,都只能讀取sshd_server寫死的環境變量

stdin, stdout, stderr = ssh.exec_command('echo $PATH')和stdin, stdout, stderr = ssh.exec_command('echo $PATH',get_pty=True)和stdin, stdout, stderr = ssh.exec_command('echo $PATH',get_pty=False)

get_pty表示是否分配偽終端

 

paramiko中關於偽終端pty的定義和描述

@open_only
    def get_pty(self, term='vt100', width=80, height=24, width_pixels=0,
                height_pixels=0):
        """
        Request a pseudo-terminal from the server.  This is usually used right
        after creating a client channel, to ask the server to provide some
        basic terminal semantics for a shell invoked with `invoke_shell`.
        It isn't necessary (or desirable) to call this method if you're going
        to execute a single command with `exec_command`.

        :param str term: the terminal type to emulate
            (for example, ``'vt100'``)
        :param int width: width (in characters) of the terminal screen
        :param int height: height (in characters) of the terminal screen
        :param int width_pixels: width (in pixels) of the terminal screen
        :param int height_pixels: height (in pixels) of the terminal screen

        :raises:
            `.SSHException` -- if the request was rejected or the channel was
            closed
        """
        m = Message()
        m.add_byte(cMSG_CHANNEL_REQUEST)
        m.add_int(self.remote_chanid)
        m.add_string('pty-req')
        m.add_boolean(True)
        m.add_string(term)
        m.add_int(width)
        m.add_int(height)
        m.add_int(width_pixels)
        m.add_int(height_pixels)
        m.add_string(bytes())
        self._event_pending()
        self.transport._send_user_message(m)
        self._wait_for_event()

  偽終端不是真實的終端,我們登錄unix界面,然后在里面啟動終端,這屬於真實的終端,假如我們直接通過ssh協議連接sshd(ssh admin@ip),這樣建立的就是偽終端。所以說偽終端不是真實的物理終端,但是卻具有真實終端的函數和功能。偽終端是由類似於xterm的終端模擬器創建的。

  在unix系統中,大量的進程和I/O函數在控制終端中運行。偽終端可以處理控制字符(^C)

 

   為什么使用pseudo-terminal就能終止遠程進程呢?

  當SSH鏈接關閉,遠程服務器會關閉pty,同時發送SIGHUP信號來終止遠程執行的命令。

SIGHUP is sent to the controlling process (session leader) associated with a controlling terminal if a disconnect is detected by the terminal interface.

 

參考:

1、http://feihu.me/blog/2014/env-problem-when-ssh-executing-command-on-remote/

2、https://gist.github.com/yegle/1564928

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM