Python for DevOps using sys, platform, getpass and paramiko module

Python for DevOps

Platform, getpass, and sys Modules

Beginner-Friendly Notes

In this section, we will look at three small but very useful Python modules for DevOps automation: platform, getpass, and sys. Each module solves a different problem: detecting the operating system, safely accepting sensitive input, and interacting with the Python interpreter and command-line arguments.

1. platform Module

What is this code doing?

This script first detects whether it is running on Linux or macOS. Based on the detected operating system, it runs commands that make sense for that platform. This is a practical DevOps pattern because the same automation script may need to run on different operating systems.

Here is the complete script:

import platform
import subprocess

os_name = platform.system()

print("Detected OS:", os_name)

if os_name == "Linux":
    print("Running Linux commands...")

    subprocess.run(["uname", "-a"])
    subprocess.run(["df", "-h"])

elif os_name == "Darwin":
    print("Running macOS commands...")

    subprocess.run(["sw_vers"])
    subprocess.run(["df", "-h"])

else:
    print("This script is designed for Linux and macOS.")

GitHub example: cross_platform_system_info.py

1.1 Brief explanation of the code

  • import platform - loads the platform module so Python can identify the operating system.
  • import subprocess - lets the script execute external operating-system commands.
  • platform.system() - returns the operating-system name. Common values include Linux, Darwin, and Windows.
  • On Linux, the script runs uname -a to display system information and df -h to display disk usage.
  • On macOS, platform.system() returns Darwin. The script runs sw_vers for macOS version information and df -h for disk usage.
  • The else block handles any operating system that the script was not designed for.

Key idea: platform detects the environment, while subprocess runs the command. Together, they let you write automation that behaves differently on different operating systems.

1.2 What is the platform module?

The platform module is used to get information about the operating system, machine architecture, processor, and Python environment. Instead of running a shell command just to discover basic system information, Python can ask for this information directly.

Some useful examples are:

import platform

print(platform.system())          # Linux, Windows, Darwin
print(platform.release())         # OS or kernel release
print(platform.machine())         # x86_64, arm64, etc.
print(platform.processor())       # Processor information
print(platform.python_version())  # Installed Python version

A simple way to think about it:

  • platform - asks Python for platform and system information.
  • subprocess - executes an external command and can capture its result.
  • os.system() - can also execute a shell command, but gives you less control over the output than subprocess.

1.3 Another cross-platform example: ping

Even when two operating systems provide the same command, the command-line options may be different. A common example is ping. Windows uses -n for the packet count, while Linux and macOS use -c.

import platform
import subprocess

host = "google.com"

if platform.system() == "Windows":
    count_option = "-n"
else:
    count_option = "-c"

subprocess.run(["ping", count_option, "4", host])

The script detects the platform first, chooses the correct ping option, and then builds the command dynamically. This is one of the reasons the platform module is useful when writing cross-platform DevOps scripts.

2. getpass Module

The getpass module is used when a Python script needs to accept sensitive input, such as a password, without displaying the characters on the screen. This is safer than using normal input() for passwords.

2.1 Why not use input() for a password?

With normal input(), whatever the user types is visible on the terminal:

password = input("Enter the password: ")

That may be acceptable for ordinary input, but it is not a good choice for a password because anyone looking at the terminal can see the value being typed.

2.2 Hide the password with getpass.getpass()

import getpass

password = getpass.getpass("Enter your password: ")

print("Password received")

getpass.getpass() asks the user for input without echoing the password to the terminal. The value is still stored in the password variable, so the script can use it later, but it is not displayed while the user types it.

DevOps use case: This can be useful for small interactive scripts that need a password or token temporarily. In production automation, secrets are usually supplied through a secret manager, protected environment variable, or another secure mechanism rather than being hard-coded in the script.

2.3 Find the current user with getpass.getuser()

import getpass

username = getpass.getuser()

print("Current user:", username)

getpass.getuser() returns the name of the user running the program. This can be useful when an automation script needs to know which account is executing it.

3. sys Module

The sys module gives a Python program access to information and functions related to the Python interpreter and the environment in which the script is running. It is especially useful for command-line arguments, Python runtime information, import paths, and exiting a program with a specific status code.

3.1 Useful information available through sys

import sys

print(sys.version)
print(sys.platform)
print(sys.path)
print(sys.modules)
  • sys.version - shows the Python version and build information.
  • sys.platform - gives a short platform identifier for the environment where Python is running.
  • sys.path - shows the locations Python searches when importing modules.
  • sys.modules - shows modules that have already been imported in the current Python process.

3.2 Practical example: pass a server name from the command line

What is this code doing?

This script expects the user to provide a hostname when starting the program. It reads that hostname from the command line using sys.argv and then runs ping against the server. If the hostname is missing, the script prints the correct usage and exits with status code 1.

import sys
import subprocess

if len(sys.argv) < 2:
    print("Usage: python check_server.py <hostname>")
    sys.exit(1)

server = sys.argv[1]

print(f"Checking connectivity to {server}...")

subprocess.run(["ping", "-c", "4", server])

3.3 Brief explanation of the code

  • sys.argv contains the command-line arguments used to start the Python script.
  • sys.argv[0] is normally the script name. sys.argv[1] is the first argument supplied by the user.
  • len(sys.argv) < 2 checks whether the hostname argument is missing.
  • sys.exit(1) stops the program and returns exit status 1, which normally indicates that the script did not complete successfully.
  • server = sys.argv[1] stores the hostname supplied by the user.
  • subprocess.run() executes ping using that hostname.

Run the script like this:

python check_server.py google.com

The command-line arguments would conceptually look like this:

sys.argv[0] -> check_server.py
sys.argv[1] -> google.com

Important: the -c option in this example is appropriate for Linux and macOS. If the same script must support Windows as well, you can combine sys.argv with the platform module and choose -n on Windows, similar to the earlier ping example.

3.4 Using sys.exit() in automation

sys.exit() is useful when a script reaches a condition where it should stop instead of continuing. For example, if a required file does not exist, the script can print an error and return a non-zero exit code.

import sys
import os

if os.path.exists("test.txt"):
    print("File exists")
else:
    print("File does not exist")
    sys.exit(1)

This is especially useful in DevOps automation because another tool, shell script, CI/CD pipeline, or scheduler can inspect the exit code and decide whether the step succeeded or failed.

4. Quick Comparison

platform, getpass, and sys compared
Module Main purpose Typical DevOps use
platform Detect operating-system and runtime information Run different logic on Linux, macOS, or Windows
getpass Accept hidden input and identify the current user Interactive password input or user-aware scripts
sys Work with the Python runtime, arguments, paths, and exit codes CLI scripts, argument handling, and CI/CD-friendly exit status

5. Putting the Modules Together

These modules become more useful when they are combined. A real DevOps script might use sys.argv to accept a server name, platform.system() to detect the operating system, subprocess.run() to execute the correct command, getpass.getpass() if temporary sensitive input is needed, and sys.exit() to return a clear success or failure status.

Simple mental model: platform tells you where the script is running, getpass helps with sensitive interactive input, and sys helps the script interact with the Python runtime and command line.

Python for DevOps: Paramiko

Running Linux Commands on Remote Servers with Python

What is Paramiko?

Paramiko is a pure-Python [1] implementation of the SSHv2 protocol [2], providing both client and server functionality.

In simple words, Paramiko allows a Python program to connect to another machine over SSH. Once connected, we can execute commands, collect their output, transfer files using SFTP, and automate administration tasks without manually opening an SSH terminal.

Official website: https://www.paramiko.org/

For DevOps engineers, this becomes useful when the same operation has to be performed on one or many remote Linux servers. Instead of logging in to every server manually, Python can establish the SSH connection and perform the work for us.

  • Run health-check or troubleshooting commands on remote servers.
  • Collect CPU, memory, disk, process, or service information.
  • Restart or inspect services as part of an automation workflow.
  • Copy configuration files or deployment artifacts using SFTP.
  • Build small administration tools when direct SSH automation is required.

How Paramiko Fits into SSH Automation

Normally, from a terminal, we connect to another server with SSH:

ssh user@server

Paramiko lets Python perform the same type of connection programmatically:

Python script Paramiko / SSHv2 Remote Linux server execute commands read stdout/stderr transfer files with SFTP

The main class we use for client-side automation is paramiko.SSHClient. It represents an SSH session and handles common tasks such as authentication, opening channels, executing commands, and starting SFTP sessions.

Installing Paramiko

Paramiko is not part of the Python standard library, so install it before importing it:

python -m pip install paramiko

Then verify that Python can import it:

import paramiko
print(paramiko.__version__)

Our First Paramiko Script

The following example follows the same flow as the original script, but the real hostname, username, and password have been removed. Placeholders are used so credentials are not exposed in the notes.

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh.connect(
    hostname="<REMOTE_SERVER>",
    username="<SSH_USER>",
    password="<SSH_PASSWORD>"
)

stdin, stdout, stderr = ssh.exec_command("free -m")

print(stdout.read().decode("utf-8"))

ssh.close()

What Is This Code Doing?

  1. Import Paramiko so the script can use its SSH client functionality.
  2. Create an SSHClient object. This object represents the SSH connection from our Python program to the remote server.
  3. Define what should happen when the server host key is not already known.
  4. Connect to the remote machine using SSH authentication.
  5. Run the Linux command free -m on the remote server.
  6. Read the command output returned by the remote server and convert it into normal text.
  7. Close the SSH connection when the work is finished.

Understanding the Script Line by Line

1. Import Paramiko

import paramiko

This loads the Paramiko package and gives the script access to classes such as SSHClient.

2. Create an SSH Client

ssh = paramiko.SSHClient()

SSHClient is the high-level client interface we normally use when connecting to an SSH server. Think of this object as the Python equivalent of preparing an SSH session.

3. Host-Key Policy

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

SSH normally verifies the identity of a remote server using its host key. If Paramiko does not already know that key, a policy decides what to do.

AutoAddPolicy() automatically accepts an unknown host key and adds it to Paramiko's host-key collection. This is convenient for a simple lab, but it removes an important identity check. For production automation, it is safer to load and verify known host keys rather than automatically trusting a new server.

4. Connect to the Remote Server

ssh.connect(
    hostname="<REMOTE_SERVER>",
    username="<SSH_USER>",
    password="<SSH_PASSWORD>"
)

connect() establishes the SSH connection and authenticates to the remote machine. The default SSH port is 22 unless another port is provided.

The important arguments here are:

Arguments to connect
Argument Meaning
hostname DNS name or IP address of the remote SSH server.
username Remote account used for SSH authentication.
password Password used for password authentication. Avoid hardcoding a real password in source code.

5. Execute a Remote Command

stdin, stdout, stderr = ssh.exec_command("free -m")

exec_command() runs a command on the remote server. In this example, free -m shows Linux memory information in megabytes.

Paramiko returns three file-like objects:

Objects returned by exec_command
Object Purpose
stdin Input that can be sent to the remote command.
stdout Normal output produced by the command.
stderr Error output produced by the command.

6. Read the Output

print(stdout.read().decode("utf-8"))

stdout.read() reads the bytes returned by the remote command. .decode("utf-8") converts those bytes into a normal Python string so that the output is easy to print and process.

A slightly cleaner form is:

output = stdout.read().decode("utf-8")
print(output)

7. Close the Connection

ssh.close()

Always close the SSH client when the work is complete. This closes the SSH session and its underlying transport resources.

Do Not Ignore stderr

A remote command can fail even when the SSH connection itself succeeds. For automation, it is useful to read both stdout and stderr.

stdin, stdout, stderr = ssh.exec_command("free -m")

output = stdout.read().decode("utf-8")
error = stderr.read().decode("utf-8")

if error:
    print("Command returned an error:")
    print(error)
else:
    print(output)

This gives the script a simple way to separate successful command output from error messages.

Password Authentication vs SSH Key Authentication

The first example uses a password because it makes the connection flow easy to understand. In real DevOps automation, SSH key authentication is usually a better choice because we do not need to store a server password directly in the script.

A key-based connection can look like this:

import paramiko

ssh = paramiko.SSHClient()
ssh.load_system_host_keys()

ssh.connect(
    hostname="<REMOTE_SERVER>",
    username="<SSH_USER>",
    key_filename="/path/to/private_key"
)

stdin, stdout, stderr = ssh.exec_command("uptime")
print(stdout.read().decode("utf-8"))

ssh.close()

Here, key_filename points to the private key used for authentication. Paramiko can also use keys available through an SSH agent or discoverable local SSH key files, depending on how connect() is configured.

Safer Host-Key Verification

For a quick lab, AutoAddPolicy() is simple. For production, we normally want to verify that we are connecting to the expected server.

ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.connect(
    hostname="<REMOTE_SERVER>",
    username="<SSH_USER>",
    key_filename="/path/to/private_key"
)

load_system_host_keys() loads known host keys, such as the keys maintained by OpenSSH. Paramiko's default missing-host-key behavior is to reject an unknown server, which is safer than automatically trusting it.

Checking the Remote Command Exit Status

In DevOps scripts, stdout alone is not always enough. We often want to know whether the command actually succeeded. The SSH channel can provide the remote command's exit status.

stdin, stdout, stderr = ssh.exec_command("df -h")

exit_code = stdout.channel.recv_exit_status()
output = stdout.read().decode("utf-8")
error = stderr.read().decode("utf-8")

print("Exit code:", exit_code)

if exit_code == 0:
    print(output)
else:
    print(error)

Just like a Linux command executed locally, an exit code of 0 normally means success, while a non-zero value means the command reported a failure.

A Practical DevOps Example

Imagine that we want to connect to a server and collect three basic health checks: uptime, memory usage, and disk usage. Paramiko lets us reuse one SSH connection and execute multiple commands.

import paramiko

commands = [
    "uptime",
    "free -m",
    "df -h"
]

ssh = paramiko.SSHClient()
ssh.load_system_host_keys()

ssh.connect(
    hostname="<REMOTE_SERVER>",
    username="<SSH_USER>",
    key_filename="/path/to/private_key"
)

for command in commands:
    print(f"\nRunning: {command}")

    stdin, stdout, stderr = ssh.exec_command(command)
    exit_code = stdout.channel.recv_exit_status()

    output = stdout.read().decode("utf-8")
    error = stderr.read().decode("utf-8")

    if exit_code == 0:
        print(output)
    else:
        print(error)

ssh.close()

This is a good example of where Paramiko becomes useful in DevOps: one Python program can connect to a remote machine, run a set of troubleshooting commands, collect their results, and then make decisions based on those results.

Handling Connection Errors

Network automation should expect failures such as an unreachable host, a wrong credential, or an SSH problem. Paramiko provides exceptions that we can catch instead of letting the script stop with a long traceback.

import paramiko

ssh = paramiko.SSHClient()
ssh.load_system_host_keys()

try:
    ssh.connect(
        hostname="<REMOTE_SERVER>",
        username="<SSH_USER>",
        key_filename="/path/to/private_key",
        timeout=10
    )

    stdin, stdout, stderr = ssh.exec_command("uptime")
    print(stdout.read().decode("utf-8"))

except paramiko.AuthenticationException:
    print("Authentication failed")

except paramiko.SSHException as error:
    print("SSH error:", error)

except OSError as error:
    print("Connection error:", error)

finally:
    ssh.close()

The finally block runs whether the operation succeeds or fails, which makes it a useful place to close the connection.

Transferring Files with SFTP

Paramiko is not limited to running shell commands. An existing SSHClient can open an SFTP session for remote file operations.

sftp = ssh.open_sftp()

# Upload a file
sftp.put("app.conf", "/tmp/app.conf")

# Download a file
sftp.get("/var/log/app.log", "app.log")

sftp.close()

This can be useful for copying configuration files, collecting logs, or moving deployment artifacts over the same SSH-based transport.

Paramiko vs subprocess

Paramiko compared with subprocess
Task subprocess Paramiko
Run a command on the local machine Yes Not the main purpose
Run a command on a remote SSH server Not directly Yes
Capture command output Yes Yes
Authenticate to an SSH server No Yes
Transfer files over SFTP No Yes

A simple way to remember the difference is: subprocess is mainly for commands executed by the local operating system, while Paramiko is for communicating with remote systems over SSH.

subprocess commands executed by the local operating system
Paramiko communicating with remote systems over SSH

Important Functions to Remember

Paramiko functions and classes
Function / Class Purpose
paramiko.SSHClient() Create a high-level SSH client.
load_system_host_keys() Load trusted host keys.
set_missing_host_key_policy() Choose what to do with an unknown server host key.
connect() Connect and authenticate to an SSH server.
exec_command() Execute a command on the remote server.
stdout.read() / stderr.read() Read normal output and error output.
stdout.channel.recv_exit_status() Read the remote command exit status.
open_sftp() Open an SFTP session for file operations.
close() Close the SSH client and connection.

Final Takeaway

Paramiko gives Python direct access to SSH functionality. For DevOps automation, the basic pattern is straightforward:

Create SSHClient Load / verify host keys Connect and authenticate Execute remote command Read stdout / stderr / exit status Close the connection

Once this pattern is clear, the same idea can be extended to server health checks, deployment automation, log collection, configuration management, and SFTP-based file transfers.

References