Executing commands on remote machines
This post comes from a request from one of my friends on discord. We will go over how to setup a python script that can connect to a remote machine, execute commands, and reutrn the output back to you. And then a little bit on how to parse that output. I will also show how to use the remote server how run commands on another machine that is behind the remote server.
For the purpose of this diminstartion, we will use "Local" to refer to our pc. "Server_IP" will refer to the remote server's IP address. Finally, "Remote_Device_IP" will refer to the remote machine that is on a network behine the remote server. Also, I will be using Notepad++ for writing this code as well.
For the frirst part we need to import three key libraries. Getpass, paramiko, and time. Please not you may need to run pip to install paramiko.
From here you can structure your code however you like. For the purpose of this example, I will keep it simple. I am just going to build this as a one time pass through with no function calls.
Next we will setup our client, set a host key policy, and get the username and password form the user that is needed to connect to the server.
Optional step is to get the remote server IP and port if you don't want to hard code them in. For the rest of this example we will work with this optional input.
Next we need to establish the connection to the remote server.
Now for a couple of examples. First we will grab the hostname of the server.
First we tell it we want to execute the command hostname using the "client.exec_command()" command. I have it hear for stdin, stdout, and stderr to all send/recieve from this. This is just something I do everytime regardless of what I am doing. I find it works best to have this as a common practice. Then we read from stdout and decode it. It gets passed back as a byte string. By decoding, it gets turned into a normal string. Then we strip the newline at the end of the output. Then we simple print it out using an f-string.
The next example will be to pull the current CPU temps. This is stored in a temporary file in the /sys/class/thermal folder. This is where most if not all sensors will store info on linux systems. Note that the number of the folder name "thermal_zone1" may need to be changed for your machine. Each zone has a temp and a type file. You can check the type file for CPU to know oyu have the right one.
We are going to use the "client.exec_command" toll again. This time we want it to cat the temp file and the we will use some sed magic to make it an actual temp out put. The normal output isn't formated and has zeros after it. So if the temp is 79C, in the file that would look like 79000. Then, like, before, we read the output, decode it, and strip the trailing newline. Finally print it out with the server name.
Lastly, we will have the code connect to a remote device thorugh the remote server and retrive the root partition usage size. There are several parts to this. First we will gatehr the information from the user that we need to make the connection. I have the user supplying the remote port, but you can leave this out and not have the port option in the next section. It will use the default 22 port in that case.
Next we will invoke a shell on the remote server to that we can runs commands as if they where ran on the server. I find it easier to handle this type of work using the "client.invoke_shell()" as to the method we used for the last two examples. Then we send our command for the server to ssh into the remote device and run the df command. We parse the output fo the df command with to grep statments. The first one uses the switch "-v" to remove lines with the loop keyword. The second one will look for only lines that have the dev keyword.
Please note the \' in the df command. We need these here so python will not read these parts as strings, but knows to actually send a single quote. If we didn't, the first single quote before the loop keyword. would close out string we are sending and raise an error when we ran out code. Lastly, we sleep for two seconds to give the time needed to setup the connection and recieve our first bit of output. Also, the command is passed as a r-string. This is a 'raw string'. This tells python to ignore the slashes basically.
Next we recieve from the connection with a 9999 character buffer. It is overkill, but I like to have more then I expect I will need. We check the output for the yes/no you would see if it was your first time connecting to a device through ssh. If it is found we will send yes reply with a newline to act as us using the enter key. Then we wait five seconds to allow it time to add the device fingerprint to our known_hosts file.
Next, we need to send the remote device password we got from out input. Then wait two seconds for it to log us in.
For the last bit we will recieve the output of the command we passed back on line 37. there is a split('\r') after decodeing the recved output. This was from trial and error. The nice thing is you can skip the decode part and print the byte string. This will show any escape characters like the \r and \n. Then we have a for loop that splits each line of the output on the space character and make it a list. We check the last item in the list using the [-1] for just the / character. This indicates the root drive we are looking for. You could add an or statment here if you wanted to look for a /boot drive or any other custome partions you have in your setup.
Once we find the root drive, we will split that enter on the space charater as well to make a new list. Then grab the second to last item in the new list. This will normally be your disk usage in the output. You can always check this by running the command on the remote device and comparing it to the byte string information that we get. Finally we print out the usage with the server name via an f-string.
I hope you enjoyed this walkthrough and where able to learn from it. Below you can find a link to the code used in this post on my github. I encourage you to experament with your on machines to see what all you can do with this script. Good luck and thank you for taking the time to read.
Code Link