Uncover the infinite in IT

Table of Contents
< All Topics

Automated Script Deployment and Execution with SSH

Purpose of the Script

The provided script automates the process of uploading and remotely executing various Bash and Python scripts on multiple servers. It utilizes SSH for secure communication and supports custom SSH ports.

Create the Deployment Script

1. Open a text editor of your choice:

nano deployment_script.py

2. Copy and paste the deployment script below into the editor.

import os
import subprocess

# Get the current username
username = os.getenv("USER")

# Check if SSH agent is running
agent_running = subprocess.run(["ssh-add", "-L"], stdout=subprocess.PIPE, stderr=subprocess.PIPE).returncode == 0

if not agent_running:
    print("SSH agent is not running. Please start the SSH agent and add your keys.")
    exit(1)

# Get the path to the servers list file in the same directory as the script
script_directory = os.path.dirname(os.path.abspath(__file__))
servers_list_default = "servers.list"

# Ask the user for the script name to upload
script_name = input("Enter the name of the script to upload: ")
script_path = os.path.join(script_directory, script_name)

# Ask the user if they want to deploy to a single host or a host list
deployment_choice = input("Deploy to a single host or a host list?\n1) single host\n2) host list\nEnter the number of your choice: ").lower()

# Ask the user if the SSH port is default or custom
ssh_port_choice = input("Is the SSH port default or custom?\n1) default\n2) custom\nEnter the number of your choice: ").lower()

if ssh_port_choice == "default":
    ssh_port = 22
else:
    # Ask the user for the custom SSH port
    ssh_port = input("Enter the custom SSH port: ")

# Determine the execution command based on the file extension
file_extension = os.path.splitext(script_name)[1]
if file_extension == ".sh":
    execution_command = f"./{script_name}"
elif file_extension == ".py":
    execution_command = f"python3 {script_name}"
else:
    print("Unsupported file extension. Please provide a script with either .sh or .py extension.")
    exit(1)

if deployment_choice == "1":
    # Ask the user for the IP of the single host
    target_host = input("Enter the IP of the host to deploy to: ")
    target_hosts = [target_host]
elif deployment_choice == "2":
    # Ask the user for the name of the servers' list file
    servers_list_custom = input(f"Enter the name of the servers' list file (default: {servers_list_default}): ")
    servers_list = servers_list_custom if servers_list_custom else servers_list_default

    # Use the specified servers' list file to get the list of hosts
    servers_list_path = os.path.join(script_directory, servers_list)
    if not os.path.exists(servers_list_path):
        print(f"Error: The specified servers' list file '{servers_list}' does not exist.")
        exit(1)

    with open(servers_list_path, 'r') as file:
        target_hosts = file.read().splitlines()
else:
    print("Invalid choice. Please enter either '1' for a single host or '2' for a host list.")
    exit(1)

for server in target_hosts:
    try:
        # Get the remote server's hostname
        remote_hostname_result = subprocess.run(
            ["ssh", f"-p{ssh_port}", "-o", "StrictHostKeyChecking=no", f"{username}@{server}", "hostname"],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        )
        remote_hostname = remote_hostname_result.stdout.decode().strip()

        # Check if the file already exists on the destination server
        check_file_exists_cmd = f"[ -e {script_name} ] && echo 'File exists' || echo 'File not found'"
        file_exists_result = subprocess.run(
            ["ssh", f"-p{ssh_port}", "-o", "StrictHostKeyChecking=no", f"{username}@{server}", check_file_exists_cmd],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        )

        if "File exists" in file_exists_result.stdout.decode():
            print(f"{script_name} already exists on {remote_hostname}. Skipping upload.")
        else:
            # Try copying the script using scp with agent forwarding and the selected SSH port
            subprocess.run(
                ["scp", f"-P{ssh_port}", "-o", "StrictHostKeyChecking=no", script_path, f"{username}@{server}:"],
                cwd=script_directory,  # Set the current working directory for scp
                check=True
            )
            print(f"Successfully copied {script_name} to {remote_hostname}.")

        print(f"Connecting to {remote_hostname} on port {ssh_port}...")
        # Try connecting on the selected SSH port with agent forwarding, switch to superuser, and execute script with sudo
        subprocess.run(
            ["ssh", "-A", f"-p{ssh_port}", "-o", "StrictHostKeyChecking=no", f"{username}@{server}", f"sudo su && chmod +x {script_name} && {execution_command}"],
            check=True
        )
        print(f"Successfully executed {script_name} on {remote_hostname}.")

        # Disconnect from SSH
        subprocess.run(["ssh", "-A", f"-p{ssh_port}", "-o", "StrictHostKeyChecking=no", f"{username}@{server}", "exit"])
        print(f"Disconnected from {remote_hostname}.")
    except subprocess.CalledProcessError as e:
        print(f"Failed to execute {script_name} on {remote_hostname}: {e}")
    except Exception as e:
        print(f"Failed to execute {script_name} on {remote_hostname}: {e}")
    else:
        print(f"Successfully executed {script_name} on {remote_hostname}")

3. Save the script with an appropriate name (e.g., deployment_script.py) in the desired folder:

Ctrl + X, Y, Enter

Now you have successfully created the deployment script that will automate the process of uploading and remotely executing scripts on multiple servers.

Step 1: Create the Script

Create the script that you want to upload and execute remotely. Ensure the script has either a ‘.sh’ or ‘.py’ extension.

Step 2: Configure the Script

  • Place both the script to be uploaded and executed (e.g., script.sh or myscript.py) and the servers’ list file in the same folder as the deployment script.

Step 3: Prerequisites

  • Ensure that the SSH agent is running, and your keys are added to the agent.

Step 4: Run the Deployment Script

Open a terminal and navigate to the folder containing the deployment script.

python3 deployment_script.py

Step 5: Script Information

  • Enter the name of the script you want to upload when prompted.
  • Choose the deployment mode: single host or host list.
  • If deploying to a single host, enter the IP of the target host.
  • If deploying to a host list, enter the name of the servers’ list file (default: servers.list).

Step 6: Specify SSH Port

  • Select the SSH port:
    • Enter ‘1’ for the default port (22).
    • Enter ‘2’ for a custom port and provide the custom port number.

Step 7: Observe Script Execution

The script will:

  • Check if the script to be uploaded already exists on the target server.
  • If not, copy the script to the target server.
  • Disconnect from scp.
  • Connect to the same target server via SSH.
  • Switch to superuser and execute the script with the appropriate command based on the script’s file extension.
  • Disconnect from SSH.

Step 8: Review Output

Review the script output for each step, including success messages or any errors encountered during execution.

Note:

  • Both the script to be uploaded and the servers’ list file should be in the same folder as the deployment script.
  • The servers’ list file should contain the IP addresses of the target servers, one per line.

Script Output Examples

Below are examples of the script output for each interaction:

Example 1: Entering Script Information

Enter the name of the script to upload: script.sh
Deploy to a single host or a host list?
1) single host
2) host list
Enter the number of your choice: 2

Example 2: Specifying SSH Port

Is the SSH port default or custom?
1) default
2) custom
Enter the number of your choice: 2
Enter the custom SSH port: 2222

Example 3: Observe Script Execution

script.sh already exists on server1.example.com. Skipping upload.
Connecting to server1.example.com on port 2222...
Successfully executed iptables.sh on server1.example.com.
Disconnected from server1.example.com.

Example 4: Review Output

Successfully executed iptables.sh on server1.example.com
Successfully executed iptables.sh on server2.example.com

This tutorial provides a detailed walkthrough of using the script, covering each step and providing examples of the script’s output during execution.