杰瑞科技汇

Python fabric如何通过yum管理软件包?

Of course! Using Python with Fabric to manage yum is a very common and powerful task for automating system administration on Red Hat-based Linux distributions (like CentOS, RHEL, Fedora, etc.).

Python fabric如何通过yum管理软件包?-图1
(图片来源网络,侵删)

Fabric is a high-level Python library and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks. It allows you to execute commands or upload files to remote systems in parallel or series.

Here’s a comprehensive guide on how to use Fabric to manage yum.


Prerequisites

First, you need to have Fabric installed. You'll also want the invoke library, which Fabric depends on.

pip install fabric invoke

For this example, you'll also need a remote server (or a local VM) running a Red Hat-based OS with SSH access configured (passwordless SSH keys are highly recommended).

Python fabric如何通过yum管理软件包?-图2
(图片来源网络,侵删)

Basic Fabric Setup

A Fabric project is typically managed by a fabfile.py in your project's root directory. This file contains your tasks.

Let's start with a basic fabfile.py that connects to a single server.

fabfile.py

from invoke import task
from fabric import Connection
# Define your host. You can use a shorthand like 'user@host'
# or define a dictionary for more options.
HOST = "centos_user@your_server_ip"
@task
def c():
    """Establish a connection to the server."""
    # This task doesn't do much by itself, but it's useful for testing
    # the connection. You can run `fab c` to see if you can connect.
    print(f"Connecting to {HOST}...")
    # The actual connection is established when you run other tasks
    # that use the 'Connection' object.

You can test this connection with:

Python fabric如何通过yum管理软件包?-图3
(图片来源网络,侵删)
fab -H centos_user@your_server_ip c

You'll be prompted for your SSH password (or it will use your key).


Task 1: Listing Installed Packages

Let's create a task to list all installed packages. This demonstrates the basic pattern of using Connection.run().

fabfile.py

from invoke import task
from fabric import Connection
HOST = "centos_user@your_server_ip"
@task
def list_installed(conn: Connection):
    """Lists all packages installed via yum."""
    print("Fetching list of installed packages...")
    # The 'run' method executes a command on the remote host.
    # capture=True captures the output of the command.
    # warn=True will not cause the task to fail if the command returns
    # a non-zero exit code (e.g., if a package isn't found).
    result = conn.run("yum list installed", hide=True)
    # The result object contains stdout, stderr, exit_code, etc.
    print(result.stdout)
    print(f"Command exited with code: {result.exit_code}")
# You can run this task with:
# fab -H centos_user@your_server_ip list_installed

Task 2: Installing a Package

This is where Fabric becomes truly useful. We'll create a task to install a package. We'll also add a "clean" task to remove it.

fabfile.py

from invoke import task
from fabric import Connection
HOST = "centos_user@your_server_ip"
# A helper function to create a connection
def get_connection():
    return Connection(HOST)
@task
def install_htop(conn: Connection):
    """Installs the 'htop' package."""
    print("Attempting to install 'htop'...")
    # sudo=True will run the command with 'sudo'.
    # pty=True is often needed for sudo prompts to work correctly.
    conn.run("sudo yum install -y htop", pty=True)
    print("htop installation command sent.")
@task
def remove_htop(conn: Connection):
    """Removes the 'htop' package."""
    print("Attempting to remove 'htop'...")
    conn.run("sudo yum remove -y htop", pty=True)
    print("htop removal command sent.")
# Run with:
# fab -H centos_user@your_server_ip install_htop
# fab -H centos_user@your_server_ip remove_htop

Note: The -y flag in yum is crucial for automation, as it automatically answers "yes" to any prompts, preventing the script from hanging.


Task 3: Checking for & Installing Updates

A common administrative task is to check for and apply all available updates.

fabfile.py

from invoke import task
from fabric import Connection
HOST = "centos_user@your_server_ip"
@task
def update_system(conn: Connection):
    """Checks for and applies all available yum updates."""
    print("Checking for system updates...")
    conn.run("sudo yum check-update", pty=True)
    print("\nApplying all updates...")
    # 'sudo yum update -y' is the command to update all packages.
    conn.run("sudo yum update -y", pty=True)
    print("System update complete.")
# Run with:
# fab -H centos_user@your_server_ip update_system

Advanced: Handling Multiple Hosts & Configuration

Real-world automation involves managing multiple servers. Fabric makes this easy.

A. Defining Multiple Hosts

You can define a list of hosts and pass them to your tasks.

fabfile.py

from invoke import task
from fabric import Connection
# Define a list of your servers
HOSTS = [
    "web1_user@web1.example.com",
    "web2_user@web2.example.com",
    "db_user@db.example.com"
]
@task
def update_all_servers(hosts, conn: Connection):
    """Updates the system on a list of servers."""
    # The 'hosts' argument is special; it gets populated by the -H flag.
    print(f"--- Updating {conn.host} ---")
    conn.run("sudo yum update -y", pty=True)
    print(f"--- Finished updating {conn.host} ---")
# To run this on multiple servers, provide them with the -H flag:
# fab -H web1_user@web1.example.com,web2_user@web2.example.com,db_user@db.example.com update_all_servers

B. Using a Configuration File (Recommended)

For complex setups, managing hosts and configuration in a Python file can get messy. Fabric supports loading configurations from a YAML file.

  1. Create fabconfig.yml:

    hosts:
      web_servers:
        - user1@web1.prod
        - user2@web2.prod
      db_servers:
        - user3@db.prod
    # You can also define default settings for connections
    connection:
      connect_timeout: 10
      # ... other fabric.Connection options
  2. Update fabfile.py to use the config:

    from invoke import task
    from fabric import Config
    from fabric.connection import Connection
    import yaml
    # Load the configuration file
    with open("fabconfig.yml", "r") as f:
        config_data = yaml.safe_load(f)
    @task
    def update_webs(hosts, conn: Connection):
        """Updates all web servers defined in the config."""
        print(f"--- Updating web server: {conn.host} ---")
        conn.run("sudo yum update -y", pty=True)
        print(f"--- Finished updating {conn.host} ---")
    # To run this, you specify the group name from the config:
    # fab -l  # (list all tasks)
    # fab -c fabconfig.yml -H web_servers update_webs
    # The -H flag can now take a group name from your YAML file!

Best Practices & Error Handling

  • Idempotency: Write your tasks so they can be run multiple times without causing errors. yum install -y package_name is idempotent. If the package is already installed, it will do nothing.
  • Check Exit Codes: Always check the result.exit_code after a conn.run() call. A non-zero code usually indicates an error.
  • Use hide='warnings' or hide=True: For tasks running in production, you don't want to spam the console with every line of output from yum. Use hide=True to suppress it and only print the final result or errors.
  • Specificity: Instead of yum update, prefer yum install package_name for specific packages. It's more predictable and safer for automation.

Example with robust error handling:

from invoke import task
from fabric import Connection
HOST = "centos_user@your_server_ip"
@task
def safe_install(conn: Connection, package_name: str):
    """
    Safely installs a package if it's not already installed.
    Usage: fab -H user@host safe_install:package_name=vim
    """
    print(f"Checking if '{package_name}' is installed...")
    # Use 'warn=True' so the command doesn't fail if grep finds nothing
    check_result = conn.run(f"yum list installed | grep -q '{package_name}'", warn=True, hide=True)
    if check_result.ok:
        print(f"'{package_name}' is already installed. Nothing to do.")
    else:
        print(f"'{package_name}' is not installed. Installing now...")
        install_result = conn.run(f"sudo yum install -y {package_name}", pty=True, hide='warnings')
        if install_result.ok:
            print(f"Successfully installed '{package_name}'.")
        else:
            print(f"Error installing '{package_name}'. Exit code: {install_result.exit_code}")
            # You could re-raise the exception to fail the task
            # raise Exception("Package installation failed.")

Summary

Goal yum Command Fabric Code
List Installed yum list installed conn.run("yum list installed", hide=True)
Install Package sudo yum install -y <pkg> conn.run("sudo yum install -y htop", pty=True)
Remove Package sudo yum remove -y <pkg> conn.run("sudo yum remove -y htop", pty=True)
Update System sudo yum update -y conn.run("sudo yum update -y", pty=True)
Check Updates sudo yum check-update conn.run("sudo yum check-update", hide=True)
Multiple Hosts (same commands) Use -H host1,host2 or a YAML config file.
分享:
扫描分享到社交APP
上一篇
下一篇