zoukankan      html  css  js  c++  java
  • 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 (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

  • 相关阅读:
    Java中如何利用File类递归的遍历指定目录中的所有文件和文件夹
    SQL的别名和SQL的执行顺序和SQL优化
    Linux中如何配置sudo用户
    Linux的ssh的known_host文件
    Linux的SSH服务
    Linux的图形模式和文本模式以及单用户模式切换
    Linux服务器磁盘空间占满问题
    PLSQL Developer连接本地Oracle 11g数据库
    Linux常用命令学习
    OAuth2 .net MVC实现获取token
  • 原文地址:https://www.cnblogs.com/shengulong/p/7908940.html
Copyright © 2011-2022 走看看