Overview on automated package management #
Automated Package Management is essential for maintaining multiple servers efficiently. This guide demonstrates how to create and execute a Python script that automates package updates, installations, removals, and purges on remote hosts using SSH. This method saves time and ensures consistent package management across multiple systems.
- Official Python Documentation
- Learn more on Automation with scripting
1) How to Create and Run the Python Script: #
Step 1: Create the Python Script #
Create a new file with a .py
extension, e.g., apt.py
. Copy and paste the following script into this file.
import os
import subprocess
# Get the current username
username = os.getenv("USER")
# 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 host list file
deployment_choice = input("Deploy to a single host or a host list?n1) single hostn2) host listnEnter the number of your choice: ").lower()
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)
# Ask the user for the action to perform (only once for the entire host list)
action_choice = input(
"What action do you want performed?n1) update & upgraden2) installn3) removen4) purgenEnter the number of your choice: ").lower()
if action_choice not in ["1", "2", "3", "4"]:
print("Invalid choice. Please enter a number between 1 and 4.")
exit(1)
# Loop through each target host
for server in target_hosts:
try:
# Get the remote server's hostname using port 22
remote_hostname_result = subprocess.run(
["ssh", "-p", "22", "-o", "StrictHostKeyChecking=no", f"{username}@{server}", "hostname"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
remote_hostname = remote_hostname_result.stdout.decode().strip()
print(f"Connecting to {remote_hostname} on port 22...")
# Apply the action based on the user's choice
if action_choice == "1":
subprocess.run(
["ssh", "-A", "-p", "22", "-o", "StrictHostKeyChecking=no", f"{username}@{server}",
"sudo apt update && sudo apt upgrade -y"],
check=True
)
print(f"Successfully performed 'apt update && apt upgrade' on {remote_hostname}.")
elif action_choice == "2":
package_to_install = input("Enter the package name to install: ")
subprocess.run(
["ssh", "-A", "-p", "22", "-o", "StrictHostKeyChecking=no", f"{username}@{server}",
f"sudo apt install {package_to_install} -y"],
check=True
)
print(f"Successfully installed '{package_to_install}' on {remote_hostname}.")
elif action_choice == "3":
package_to_remove = input("Enter the package name to remove: ")
subprocess.run(
["ssh", "-A", "-p", "22", "-o", "StrictHostKeyChecking=no", f"{username}@{server}",
f"sudo apt remove {package_to_remove} -y"],
check=True
)
print(f"Successfully removed '{package_to_remove}' from {remote_hostname}.")
elif action_choice == "4":
package_to_purge = input("Enter the package name to purge: ")
subprocess.run(
["ssh", "-A", "-p", "22", "-o", "StrictHostKeyChecking=no", f"{username}@{server}",
f"sudo apt purge {package_to_purge} -y"],
check=True
)
print(f"Successfully purged '{package_to_purge}' from {remote_hostname}.")
# Disconnect from SSH using port 22
subprocess.run(["ssh", "-A", "-p", "22", "-o", "StrictHostKeyChecking=no", f"{username}@{server}", "exit"])
print(f"Disconnected from {remote_hostname}.")
except subprocess.CalledProcessError as e:
print(f"Failed to connect to {server} on port 22. Trying port 2022...")
try:
# Get the remote server's hostname using port 2022
remote_hostname_result = subprocess.run(
["ssh", "-p", "2022", "-o", "StrictHostKeyChecking=no", f"{username}@{server}", "hostname"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
remote_hostname = remote_hostname_result.stdout.decode().strip()
print(f"Connecting to {remote_hostname} on port 2022...")
# Apply the action based on the user's choice
if action_choice == "1":
subprocess.run(
["ssh", "-A", "-p", "2022", "-o", "StrictHostKeyChecking=no", f"{username}@{server}",
"sudo apt update && sudo apt upgrade -y"],
check=True
)
print(f"Successfully performed 'apt update && apt upgrade' on {remote_hostname}.")
elif action_choice == "2":
package_to_install = input("Enter the package name to install: ")
subprocess.run(
["ssh", "-A", "-p", "2022", "-o", "StrictHostKeyChecking=no", f"{username}@{server}",
f"sudo apt install {package_to_install} -y"],
check=True
)
print(f"Successfully installed '{package_to_install}' on {remote_hostname}.")
elif action_choice == "3":
package_to_remove = input("Enter the package name to remove: ")
subprocess.run(
["ssh", "-A", "-p", "2022", "-o", "StrictHostKeyChecking=no", f"{username}@{server}",
f"sudo apt remove {package_to_remove} -y"],
check=True
)
print(f"Successfully removed '{package_to_remove}' from {remote_hostname}.")
elif action_choice == "4":
package_to_purge = input("Enter the package name to purge: ")
subprocess.run(
["ssh", "-A", "-p", "2022", "-o", "StrictHostKeyChecking=no", f"{username}@{server}",
f"sudo apt purge {package_to_purge} -y"],
check=True
)
print(f"Successfully purged '{package_to_purge}' from {remote_hostname}.")
# Disconnect from SSH using port 2022
subprocess.run(["ssh", "-A", "-p", "2022", "-o", "StrictHostKeyChecking=no", f"{username}@{server}", "exit"])
print(f"Disconnected from {remote_hostname} on port 2022.")
except subprocess.CalledProcessError as e:
print(f"Failed to connect to {server} on port 2022. Error: {e}")
except Exception as e:
print(f"Failed to execute the chosen action on {remote_hostname}: {e}")
except Exception as e:
print(f"Failed to execute the chosen action on {remote_hostname}: {e}")
Step 2: Save the File #
Save the file after pasting the script.
Step 3: Open a Terminal #
Open a terminal on your computer.
Step 4: Navigate to the Script’s Directory #
Use the cd
command to navigate to the directory where your Python script is saved.
Step 5: Run the Script #
Run the script using the command:
python3 apt.py
or
python apt.py
2) What It Does: #
The script automates package management tasks on remote servers using SSH. It supports the following actions:
- Update and upgrade packages (
apt update && apt upgrade -y
) - Install a specified package
- Remove a specified package
- Purge a specified package
3) Example Output for Every Interactive Step Taken: #
Choosing Deployment Type: #
Deploy to a single host or a host list?
1) single host
2) host list
Enter the number of your choice: 1
Entering Single Host IP: #
Enter the IP of the host to deploy to: 10.0.1.234
Choosing Action: #
What action do you want performed?
1) update & upgrade
2) install
3) remove
4) purge
Enter the number of your choice: 1
Performing Action on Single Host: #
Connecting to [hostname] on port 22...
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Hit:1 http://security.debian.org bullseye-security InRelease
Hit:2 http://deb.debian.org/debian bullseye InRelease
Hit:3 http://deb.debian.org/debian bullseye-updates InRelease
Hit:4 https://repo.zabbix.com/zabbix/6.4/debian bullseye InRelease
Reading package lists...
Building dependency tree...
Reading state information...
All packages are up to date.
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Successfully performed 'apt update && apt upgrade' on [hostname].
Disconnected from [hostname].
Choosing Action for Multiple Hosts: #
Do you want to perform the action on a single host or multiple hosts?
1) single host
2) multiple hosts
Enter the number of your choice: 2
Example Output – Entering Host List File: #
Enter the name of the servers' list file (default: servers.list): targets.list
Connecting to [hostname1] on port 22...
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Hit:1 http://deb.debian.org/debian bullseye InRelease
Hit:2 http://security.debian.org bullseye-security InRelease
Hit:3 https://downloads.plex.tv/repo/deb public InRelease
Hit:4 http://deb.debian.org/debian bullseye-updates InRelease
Hit:5 https://repo.zabbix.com/zabbix/6.4/debian bullseye InRelease
Reading package lists...
Building dependency tree...
Reading state information...
All packages are up to date.
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
0 upgraded, 0 newly installed, 0 to remove, and 0 not upgraded.
Successfully performed 'apt update && apt upgrade' on [hostname1].
Disconnected from [hostname1] on port 22.
Connecting to on port 22...
ssh: connect to host [hostname2] port 22: Connection refused
Failed to connect to [hostname2] on port 22. Trying port 2022...
Connecting to [hostname2] on port 2022...
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Hit:1 http://deb.debian.org/debian bullseye InRelease
Hit:2 http://security.debian.org bullseye-security InRelease
Hit:3 https://downloads.plex.tv/repo/deb public InRelease
Hit:4 http://deb.debian.org/debian bullseye-updates InRelease
Hit:5 https://repo.zabbix.com/zabbix/6.4/debian bullseye InRelease
Reading package lists...
Building dependency tree...
Reading state information...
All packages are up to date.
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
0 upgraded, 0 newly installed, 0 to remove, and 0 not upgraded.
Successfully performed 'apt update && apt upgrade' on [hostname2].
Disconnected from [hostname2] on port 2022.
Conclusion regarding automated package management #
Automating package management with Python scripts enhances efficiency and consistency in maintaining remote servers. By following this guide, you can automate updates, installations, removals, and purges effortlessly. Additionally, implementing best practices and security measures ensures reliable and secure automation.
This method not only saves time but also minimizes errors, making it an essential tool for system administrators.