程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python connects to the server remotely. Its enough

編輯:Python

Hello everyone , I'm brother Chen ~

In the use of Python When writing some scripts , In some cases , We need to log in to the remote service frequently to execute a command , And return some results .

stay shell Environment , That's what we do .

$ sshpass -p ${passwd} ssh -p ${port} -l ${user} -o StrictHostKeyChecking=no xx.xx.xx.xx "ls -l"

And then you'll see , There's a lot of your output that you don't need , But some information that can't be lost ( Maybe there's a way , Please leave a message ), Like this

host: xx.xx.xx.xx, port: xx
Warning: Permanently added '[xx.xx.xx.xx]:xx' (RSA) to the list of known hosts.
Login failure: [Errno 1] This server is not registered to rmp platform, please confirm whether cdn server.
total 4
-rw-r--r-- 1 root root 239 Mar 30  2018 admin-openrc

For direct use shell command , To carry out an order , You can use pipes directly , Or redirect the standard output to a file to get the result of executing the command

# 1. Use subprocess

If you use Python To do it , Usually we will be the first to , Think of using os.popen,os.system,commands,subprocess Wait for some command execution libraries to indirectly get .

But as far as I know , These libraries get output Not only standard output , There are also standard errors ( That is, the redundant information above )

So always be right output Data cleaning , Then organize and format , To get the data we want .

use subprocess for instance , Like this

import subprocess
ssh_cmd = "sshpass -p ${passwd} ssh -p 22 -l root -o StrictHostKeyChecking=no xx.xx.xx.xx  'ls -l'"
status, output = subprocess.getstatusoutput(ssh_cmd)
#  Data cleaning , The formatted ones don't show
<code...>

Through the above words + Code display , You can feel it ssh Some of the pain points of landing

  • It hurts a little : Additional installation required sshpass( If you can't help it )

  • Pain point two : Too much interference information , Data cleaning 、 Formatting is quite cumbersome

  • Pain point three : The code implementation is not elegant enough ( It's a bit of dirt ), Poor readability

  • It hurts four :ssh Connections cannot be reused , A connection can only be executed once

  • Pain point five : The code can't be all platform , Only in Linux and OSX Upper use

To solve these problems , I searched the whole web about Python SSH  The article , I really found two libraries

  • sh.ssh

  • Paramiko

# 2. Use sh.ssh

First, let's introduce the first one ,sh.ssh

sh It's a function call that allows you to do Linxu/OSX A library of system commands , Very easy to use , I have the opportunity to write an introduction about it .

$ python3 -m pip install sh

Only one of its functions is introduced today :ssh

Usually two machines visit each other , For convenience , You can set password free login , So you don't have to enter a password .

This code can realize the password free login , And execute our orders ls -l

from sh import ssh
output=ssh("[email protected]", "-p 22", "ls -l")
print(output)

But it's possible , We don't want to set up mutual trust , To make this code more generic , I assume we don't have a secret exemption , You can only log in with a password .

Here's the problem , To enter a password , You have to use interactive methods to input , stay Python How can we achieve this ?

original ssh Method to receive a _out Parameters , This parameter can be a string , Represents the file path , It can also be a file object ( Or class file object ), It can also be a callback function , When there is standard output , Call to pass the output to this function .

This is easy to do .

I just need to recognize that there is password: word , Just write my password into the standard input .

The complete code is as follows :

import sys
from sh import ssh
aggregated = ""
def ssh_interact(char, stdin):
    global aggregated
    sys.stdout.write(char.encode())
    sys.stdout.flush()
    aggregated += char
    if aggregated.endswith("password: "):
        stdin.put("you_password\n")
output=ssh("[email protected]", "-p 22", "ls -l",_tty_in=True, _out_bufsize=0, _out=ssh_interact)
print(output)

This is the official document (http://amoffat.github.io/sh/tutorials/interacting_with_processes.html?highlight=ssh) Some information for , Write a demo.

After trying to run , The discovery program will always be running , Never to return , Will not quit , Callback functions will never enter .

Check the source code through debugging , Still can't find the problem , So I went to Github I've searched it up and down , Originally in 2017 This problem has existed since , Up to now 2020 It hasn't been repaired yet , Seems to use sh.ssh Not many people , So I was “ Questioning ” Now , Expect to get a reply .

The above question , It only appears when a password is required , If the machine mutual trust is set up, there is no problem .

To feel sh.ssh The use effect of , I've set up a machine to trust each other , Then use the following code .

from sh import ssh
my_server=ssh.bake("[email protected]", "-p 22")
#  It's equivalent to logging in and executing commands one at a time , Exit login after execution
print(my_server.ls())
#  Can be found in  sleep  period , Manually log in to the server , Use  top , Check how many terminals are currently connected
time.sleep(5)
#  When the order is executed again , The number of landing terminals will be  +1, After the execution , And will be  -1
print(my_server.ifconfig())

Surprised to find the use of bake This way, ,my_server.ls() and my_server.ifconfig() This seems to be through the same ssh Connect , Execute the order twice , But actually , You can be on a remote machine , perform top Command to see changes in connected terminals , Will first +1 Again -1, Explain that the execution of two commands is realized through two connections .

So it seems , Use sh.ssh It can solve the pain ( If the above problems can be solved )、 Pain point two 、 Pain point three .

But it still can't be reused ssh Connect , It's still inconvenient , It's not the best plan for me .

The most important thing is , sh This module , Support only  Linxu/OSX , stay Windows You have to use its brother Library - pbs , Then I went to  pypi Take a look at pbs, already “ In disrepair ”, No one's defending .

thus , I am from “ pawn ”, It's almost the last straw .

# 3. Use paramiko

With the last glimmer of hope , I tried to use paramiko This library , Finally in the paramiko here , Find back what should have been Python The elegance of .

You can install it with the following command

$ python3 -m pip install paramiko

And then next , Just introduce some common ssh How to log in

  Method 1: User name and password based sshclient How to log in

Then you can refer to the following code , stay Linux/OSX Remote connection under the system

import paramiko
ssh = paramiko.SSHClient()
#  Allow connection not in know_hosts Hosts in files
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#  Establishing a connection
ssh.connect("xx.xx.xx.xx", username="root", port=22, password="you_password")
#  Use this connection to execute commands
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -l")
#  Get output
print(ssh_stdout.read())
#  Close the connection
ssh.close()

  Method 2: User name and password based transport How to log in

Method 1 It's a traditional connection server 、 Carry out orders 、 An operation to close , Multiple operations need to be connected multiple times , Unable to reuse connection [ It hurts four ].

Sometimes you need to log in to the server to perform multiple operations , Such as executing orders 、 Upload / Download the file , Method 1 Can't achieve , Then you can use it transport Methods .

import paramiko
#  Establishing a connection
trans = paramiko.Transport(("xx.xx.xx.xx", 22))
trans.connect(username="root", password="you_passwd")
#  take sshclient Of transport Designated as above trans
ssh = paramiko.SSHClient()
ssh._transport = trans
#  The rest is the same as above
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -l")
print(ssh_stdout.read())
#  Close the connection
trans.close()

  Method 3: Based on public key SSHClient How to log in

import paramiko
#  Designate local RSA Private key file
#  If the password is set when the key pair is established ,password Password set for , If there is no need to specify password Parameters
pkey = paramiko.RSAKey.from_private_key_file('/home/you_username/.ssh/id_rsa', password='12345')
#  Establishing a connection
ssh = paramiko.SSHClient()
ssh.connect(hostname='xx.xx.xx.xx',
            port=22,
            username='you_username',
            pkey=pkey)
#  Carry out orders
stdin, stdout, stderr = ssh.exec_command('ls -l')
#  The result is put in stdout in , If there is a mistake, it will be put in stderr in
print(stdout.read())
#  Close the connection
ssh.close()

  Method 4: Key based Transport How to log in

import paramiko
#  Designate local RSA Private key file
#  If the password is set when the key pair is established ,password Password set for , If there is no need to specify password Parameters
pkey = paramiko.RSAKey.from_private_key_file('/home/you_username/.ssh/id_rsa', password='12345')
#  Establishing a connection
trans = paramiko.Transport(('xx.xx.xx.xx', 22))
trans.connect(username='you_username', pkey=pkey)
#  take sshclient Of transport Designated as above trans
ssh = paramiko.SSHClient()
ssh._transport = trans
#  Carry out orders , Just like the traditional way
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())
#  Close the connection
trans.close()

The above four methods , It can help you to log in to the server remotely to execute commands , If you need to reuse connections : One connection executes multiple commands , have access to Method 2 and Method four

After use , Remember to close the connection .

  Realization sftp File transfer

meanwhile ,paramiko As ssh The perfect solution , It's very professional , It can also be used to achieve sftp File transfer .

import paramiko
#  Instantiate a trans object #  Instantiate a transport object
trans = paramiko.Transport(('xx.xx.xx.xx', 22))
#  Establishing a connection
trans.connect(username='you_username', password='you_passwd')
#  Instantiate a  sftp object , Specify the channel to connect
sftp = paramiko.SFTPClient.from_transport(trans)
#  Send a file
sftp.put(localpath='/tmp/11.txt', remotepath='/tmp/22.txt')
#  Download the file
sftp.get(remotepath='/tmp/22.txt', localpath='/tmp/33.txt')
trans.close()

Come here ,Paramiko It's a complete victory , But there is still a pain point we didn't mention , It's multi platform , It's about Windows, Here's a good thing , A bad thing ,.

Good thing is :paramiko Support windows

The bad thing is : You need to do a lot of complicated preparation , You can google solve , But I suggest you give up , The pit is too deep .

  matters needing attention

Use paramiko When , There is one thing to note , This is also my own " Step on the pit " I found it later , In fact, I think this design is very good , If you don't have to wait for it to return data , The asynchronous effect can be realized directly , It's just for people who don't know the design , It's really an easy spot to fall into a pit

Is to carry out ssh.exec_command(cmd) when , This command is not synchronous blocking .

For example, the following code , Execution time , You'll find that The script ends immediately and exits , Not waiting 5 s after , Again perform ssh.close()

import paramiko
trans = paramiko.Transport(("172.20.42.1", 57891))
trans.connect(username="root", password="youpassword")
ssh = paramiko.SSHClient()
ssh._transport = trans
stdin, stdout, stderr = ssh.exec_command("sleep 5;echo ok")
ssh.close()

But if it's like this , Add a line stdout.read(), paramiko You know , You need the result of this execution , Will be in read() To block .

import paramiko
trans = paramiko.Transport(("172.20.42.1", 57891))
trans.connect(username="root", password="youpassword")
ssh = paramiko.SSHClient()
ssh._transport = trans
stdin, stdout, stderr = ssh.exec_command("sleep 5;echo ok")
#  Add a line  read()
print(stdout.read())
ssh.close()

# 4. At the end

After some comparison , And some examples , It can be seen that Paramiko It's a major 、 It's easy ssh tool , Personally think that Paramiko Module is one of the necessary modules for operation and maintenance personnel , If you happen to need to be in Python In the code ssh Go to the remote server to get some information , Then I put Paramiko Recommended to you .

Last , Hope this article , Can help you .

# 5. Reference link

  • https://github.com/paramiko/paramiko

  • http://docs.paramiko.org

  • https://www.liujiangblog.com/blog/15/

  • http://docs.paramiko.org/en/stable/

Guess you like

No, 50W Betrothal gifts , My girlfriend was forcibly dragged away , What am I gonna do?

20 Zhang let the boss praise the large visual screen , Attached source code template !


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved