DevOps Automation with Python and Infrastructure Scripting

Chapter 11
Configuration Management and Fleet Automation

Post Graduate Program in Dev Ops
DevOps Automation with Python and Infrastructure Scripting   •   Post Graduate

11. Configuration Management and Fleet Automation

Introduction and Context

Configuration management is the disciplined practice of defining, applying, verifying, and maintaining the desired state of computing infrastructure. In a small environment, an administrator may configure a few servers manually. In a modern organization, however, infrastructure may include cloud instances, virtual machines, containers, network devices, databases, operating-system variants, and geographically distributed edge systems. Manual administration at this scale is slow, inconsistent, difficult to audit, and highly vulnerable to human error.

Fleet automation addresses this problem by treating infrastructure as a managed population rather than as a collection of individually administered machines. Automation tools such as Ansible enable teams to describe desired configurations in declarative files, organize machines into inventories, apply reusable roles, and coordinate changes across heterogeneous environments. Python complements these tools by supporting custom modules, inventory generation, validation scripts, API integrations, and operational analytics.

Configuration management is closely related to infrastructure as code, continuous delivery, site reliability engineering, security operations, and platform engineering. Its purpose is not merely to install packages. It establishes a repeatable operating model in which infrastructure changes are designed, reviewed, tested, executed, and measured in a controlled manner.

Learning Objectives

After completing this chapter, students should be able to:

1. Explain the purpose, scope, and operating principles of configuration management.

2. Design static and dynamic inventories for heterogeneous infrastructure fleets.

3. Construct maintainable Ansible playbooks, roles, variables, handlers, and templates.

4. Apply idempotent provisioning, configuration, patching, and compliance practices.

5. Select suitable orchestration strategies for rolling, staged, and coordinated deployments.

6. Integrate Python with Ansible and infrastructure APIs for discovery, validation, and automation.

7. Evaluate security, governance, reliability, and operational risks in fleet automation.

8. Analyze an applied fleet-management scenario and justify an appropriate automation design.

From Individual Servers to Desired State

A configuration-management system distinguishes between the current state of a resource and its desired state. The current state might include an outdated operating system, a missing package, an incorrect file permission, or a stopped service. The desired state describes what should be true: a package must be installed at an approved version, a configuration file must match a controlled template, and a service must be enabled and running.

The automation engine compares these states and performs only the actions required to close the difference. This approach is more reliable than a procedural script that blindly executes commands every time. A well-designed configuration task is idempotent: applying it once or repeatedly produces the same intended result without unnecessary side effects.

Idempotence does not mean that every operation is intrinsically safe to repeat. Database migrations, user creation through poorly designed shell commands, or service restarts can have side effects. The engineer must therefore select state-aware modules, use conditions, record change status, and isolate operations that genuinely need one-time execution.

A useful conceptual model is:

Desired state + inventory + execution policy + automation code = managed fleet behavior.

The inventory identifies targets, the automation code defines the desired state, and the execution policy determines when, where, and in what order changes occur.

Ansible’s Operating Model

Ansible generally uses an agentless architecture. A control node connects to managed hosts using protocols such as SSH for Linux systems or WinRM and related mechanisms for Windows systems. The control node transfers or invokes the required operations and receives results. This reduces the need to install and maintain a persistent management agent, although it places importance on credentials, network reachability, interpreter availability, and control-node capacity.

Ansible automation is commonly organized around several elements:

  • Inventory: A description of managed hosts and their group membership.
  • Playbook: A YAML document describing plays and tasks.
  • Play: A mapping of selected hosts to variables, roles, and tasks.
  • Task: A single desired-state operation using a module.
  • Module: A unit of automation for managing packages, files, services, users, cloud resources, and other objects.
  • Handler: A task triggered by a notification, commonly used for controlled service restarts.
  • Role: A reusable directory structure containing tasks, variables, templates, files, handlers, and metadata.
  • Facts: Information gathered from managed hosts, such as operating-system family, memory, interfaces, and processor architecture.
  • Variable: A value used to adapt automation to hosts, environments, or operational conditions.

A simple playbook illustrates the relationship between these elements:

```yaml

  • name: Configure web servers

hosts: web

become: true

vars:

web_package: nginx

tasks:

  • name: Install web server

ansible.builtin.package:

name: "{{ web_package }}"

state: present

notify: Restart web service

  • name: Deploy application configuration

ansible.builtin.template:

src: app.conf.j2

dest: /etc/myapp/app.conf

owner: root

group: root

mode: '0644'

notify: Restart web service

handlers:

  • name: Restart web service

ansible.builtin.service:

name: "{{ web_package }}"

state: restarted

```

The package module abstracts operating-system differences more safely than a raw shell command. The template task changes the configuration only when rendered content differs. The handler prevents an unnecessary restart when no relevant change has occurred.

Inventory Design for Heterogeneous Fleets

Inventory design is an architectural decision rather than a clerical task. A useful inventory expresses operational relationships: application tier, environment, location, operating system, ownership, compliance classification, and maintenance policy. Poor grouping leads to accidental broad execution and makes it difficult to express deployment strategy.

A static inventory may be written in INI or YAML format:

```yaml

all:

children:

production:

children:

web:

hosts:

web-01.example.net:

web-02.example.net:

database:

hosts:

db-01.example.net:

vars:

environment: production

staging:

hosts:

stage-web-01.example.net:

```

Variables should be assigned at the narrowest sensible scope. Organization-wide defaults belong in group variables, while host-specific exceptions belong in host variables. Excessive host-specific configuration can indicate that the fleet has not been modeled consistently. Conversely, forcing every host into an identical profile can conceal legitimate differences.

Heterogeneous fleets require explicit handling of platform differences. A role may use `ansible_facts.os_family` to choose package names or service behavior, but platform branching should remain limited and visible. If a role contains extensive conditional logic for unrelated systems, separate roles or a clearer abstraction may be more maintainable.

Dynamic Inventory and Discovery

Static files become unsuitable when cloud resources are created and destroyed frequently. Dynamic inventory obtains host information from a cloud provider, virtualization platform, configuration database, container orchestrator, or service registry. Hosts can then be grouped by tags such as `environment=production`, `team=payments`, or `patch_window=sunday-night`.

Dynamic discovery introduces important governance questions. Which resources are eligible for management? What happens when tags are missing or inaccurate? How are terminated instances removed? How are credentials protected? A dynamic inventory should apply validation rules and fail safely when discovery data is incomplete. It should not silently interpret an empty API response as permission to target no hosts or, worse, an uncontrolled default group.

Python is useful for custom discovery when an existing inventory plugin is insufficient. A Python discovery program can query an API, normalize resource metadata, validate required tags, and emit inventory in a supported format. It should use timeouts, retry limits, structured logging, and least-privilege credentials.

Playbook Engineering and Reusable Roles

A playbook is maintainable when it communicates intent, limits scope, separates configuration from logic, and can be tested without requiring production access. Tasks should have descriptive names, use fully qualified module names where appropriate, avoid unnecessary shell commands, and define explicit permissions for sensitive files.

Roles provide a convention for packaging automation. A typical role may contain:

```text

roles/web_server/

├── defaults/main.yml

├── handlers/main.yml

├── tasks/main.yml

├── templates/app.conf.j2

├── files/

├── vars/main.yml

└── meta/main.yml

```

Defaults are intended to be overridden; role variables are generally more strongly controlled. Templates use variables to generate environment-specific configuration while preserving a common structure. Metadata can express dependencies and supported platforms.

A role should have a narrow responsibility. A role named `web_server` should not silently create databases, modify unrelated firewall policies, and deploy application code unless those responsibilities are deliberately part of its contract. Smaller roles improve reuse and testing, but excessive fragmentation can make execution difficult to understand. The correct boundary usually follows a stable operational capability.

Variables should be validated before destructive or production-sensitive tasks begin. For example, an application role may require a non-empty database endpoint and a valid deployment environment. Assertions can stop an unsafe run early rather than allowing a partially completed deployment.

Provisioning, Configuration, and Patching as a Lifecycle

Fleet automation commonly supports three related but distinct activities.

Provisioning creates a usable host or resource. It may include initial access, operating-system configuration, disk layout, baseline users, time synchronization, and registration with monitoring or inventory systems.

Configuration establishes the software and policy state of an existing host. Examples include package installation, service configuration, certificate deployment, logging, firewall rules, and application settings.

Patching updates operating-system or application components to address defects, vulnerabilities, or support requirements. Patching is operationally sensitive because it can introduce incompatibilities, require reboots, or disrupt service availability.

A mature process separates these concerns while connecting them through a controlled pipeline. A baseline role may establish common security and observability settings. Application roles then configure workload-specific services. A patching playbook can use maintenance groups, package exclusions, reboot detection, health checks, and staged rollout policies.

Patch automation should not be reduced to “install the latest package.” Organizations may require approved repositories, vulnerability severity thresholds, compatibility testing, change tickets, maintenance windows, and rollback plans. The desired state may therefore be a tested version range rather than the newest available version.

Orchestration and Deployment Strategies

Orchestration concerns the order and coordination of changes across hosts and services. Ansible can limit concurrency through `serial`, prevent a play from continuing after excessive failures through `max_fail_percentage`, and coordinate service actions with delegated tasks and handlers.

A rolling strategy updates a subset of hosts at a time. It is appropriate for horizontally scaled web services where capacity remains sufficient during maintenance. A canary strategy begins with a small representative group and expands only after health checks and operational review. A blue-green approach maintains two environments and shifts traffic after the new environment is validated. These strategies are not merely syntax choices; they express risk tolerance and service architecture.

For stateful systems, ordering is more complex. Database nodes may require leader election, replication checks, quorum preservation, or application compatibility validation. Automation should not assume that parallel execution is safe. The playbook must reflect the system’s failure model.

A robust orchestration workflow commonly includes:

1. Preflight validation of inventory, credentials, versions, capacity, and maintenance approval.

2. A controlled change on a limited target set.

3. Verification of service health and key business indicators.

4. Expansion to additional targets only when verification succeeds.

5. Post-change reporting and reconciliation.

Check mode and diff mode can help reviewers understand intended changes before execution, although not every module fully supports prediction. Testing in an environment representative of production remains necessary.

Python as an Extension to Configuration Management

Ansible provides a broad module library, but infrastructure environments often contain proprietary APIs, specialized validation requirements, or data transformations. Python can extend the automation system in several ways.

A custom module can expose a domain-specific resource through a declarative interface. For example, a module might ensure that a service account exists in an internal identity platform. The module should report whether it changed state, return structured results, and fail with an actionable message. Direct shell invocation should be a last resort because it weakens idempotence and error handling.

Python can also support preflight and postflight validation. A validation script may check that all production hosts have approved tags, that TLS certificates are not near expiration, or that a cluster retains sufficient capacity before patching. Such scripts should produce machine-readable output so that a CI pipeline can interpret success and failure consistently.

Another useful pattern is event-driven automation. A monitoring event, cloud event, or service-desk approval can invoke a controlled workflow. Automation should still enforce authorization, scope, rate limits, and approval policies; event-driven execution must not become an uncontrolled command channel.

Security, Governance, and Auditability

Configuration management has privileged access to systems and can therefore amplify both operational capability and security risk. Credentials should be stored in an approved secret-management system or encrypted mechanism, not committed to source control. Access should be limited by role, environment, and action. Production execution should use separate identities and, where appropriate, multi-party approval.

Sensitive values must not appear in logs. Tasks that handle credentials should suppress accidental output, and templates should set restrictive file permissions. SSH host-key verification and certificate validation should not be disabled merely to simplify connectivity.

The automation repository should be treated as production code. Changes require version control, peer review, automated linting, testing, traceable approvals, and documented ownership. Commit history, execution logs, inventory snapshots, and change records support auditability. However, logs must be designed with privacy and data-minimization principles in mind.

Governance also includes drift management. Drift occurs when a host deviates from the declared configuration because of manual changes, emergency actions, software updates, or incomplete automation. Periodic reconciliation can restore the desired state, but organizations must distinguish unauthorized drift from legitimate emergency modifications. A rigid “always overwrite” policy may destroy evidence or interfere with incident response.

Applied Case: Automating a Mixed-Platform Retail Fleet

Background

This illustrative case concerns a retailer operating an online ordering platform across two data centers and a public cloud. The fleet contains Linux web servers, Windows-based warehouse service hosts, database servers, and monitoring nodes. The organization has experienced inconsistent patch levels, undocumented manual changes, and prolonged maintenance windows.

Situation and Problem

The operations team maintains separate scripts for each platform. Some scripts use fixed host lists, while others discover cloud instances by name. A patch applied to all web servers simultaneously caused a capacity reduction and an outage when one release introduced a service incompatibility. Management requires a repeatable process with evidence of what changed and which systems remain non-compliant.

Analysis

The problem is not simply the absence of a better script. It includes weak inventory modeling, insufficient separation between staging and production, lack of idempotent configuration, and an orchestration policy that ignores service capacity. The team also lacks a common definition of compliance. A successful design must therefore combine technical automation with governance and operational controls.

Approach and Solution

The team creates an inventory generated from the cloud API and an internal asset database. Hosts are grouped by environment, platform, application tier, location, and patch window. Discovery rejects resources that lack mandatory ownership and environment tags.

Common configuration is placed in baseline roles. Separate Linux and Windows roles manage platform-specific packages and services, while application roles configure the ordering platform. Variables define approved repository URLs, package versions, maintenance windows, and notification endpoints. Secrets are retrieved at execution time from a dedicated secret store.

The patching workflow first runs Python-based preflight checks. These verify inventory freshness, available capacity, repository reachability, backup status, and the presence of a change approval. The playbook then updates one canary web host, runs synthetic ordering tests, and checks application latency and error rates. If the checks pass, the play proceeds in batches of 20 percent of the web tier. A handler restarts services only when configuration or package changes require it.

Windows warehouse hosts are patched in a separate play with platform-specific modules and a reboot policy. Database nodes are excluded from parallel patching and follow a documented replication-aware sequence. Every run records the target set, changed resources, failed tasks, package versions, and post-change validation results.

Outcome

The organization gains a single model for discovering and classifying hosts, although platform-specific implementation remains explicit. Maintenance becomes predictable because changes are staged and capacity is preserved. Failed canary validation stops the rollout before the entire fleet is affected. Compliance reports identify hosts that are unreachable, incorrectly tagged, or outside the approved patch baseline.

Learning Points

The case demonstrates that fleet automation is an organizational control system as much as a collection of playbooks. Inventory quality determines targeting accuracy; idempotence reduces repeated risk; staged orchestration protects availability; and evidence enables accountability. Automation does not remove the need for engineering judgment. It makes that judgment repeatable and enforceable.

Challenges and Common Failure Modes

One common mistake is using a large collection of shell commands because they appear quick to write. Such commands often lack idempotence, obscure change reporting, and behave differently across platforms. Another is placing all logic in one enormous playbook, making review and reuse difficult.

Unbounded concurrency can overload networks, repositories, APIs, or dependent services. Incorrect variable precedence can produce surprising configurations, especially when defaults, group variables, host variables, and runtime values overlap. Dynamic inventory can create dangerous targeting errors when tags are stale or ambiguous.

Teams sometimes treat successful task execution as proof of successful service operation. A package installation may succeed while the application remains unhealthy. Post-change tests must therefore examine meaningful outcomes: process status, endpoint behavior, replication health, queue depth, latency, or business transactions.

Other risks include untested reboots, missing rollback procedures, secrets in source control, excessive privilege, unreviewed emergency changes, and failure to test the automation itself. A playbook that works on one distribution or one cloud account should not be assumed to work across the entire fleet.

Emerging Directions and Best Practices

Configuration management increasingly operates alongside policy-as-code, immutable images, container orchestration, and continuous compliance platforms. In some environments, hosts are replaced rather than extensively modified; in others, long-lived systems still require reconciliation and patching. The appropriate model depends on workload characteristics, regulatory requirements, cost, and recovery objectives.

Machine learning may assist with anomaly detection, drift prioritization, patch-risk estimation, and log analysis. It should support—not replace—authorization, testing, and accountable decision-making. Automated recommendations require explainability and careful treatment of false positives and false negatives.

Effective practice includes the following principles:

  • Model inventory according to operational relationships and ownership.
  • Prefer declarative, idempotent modules over unstructured commands.
  • Keep roles focused, documented, and testable.
  • Separate development, staging, and production execution paths.
  • Use canaries, batches, health checks, and explicit abort criteria.
  • Validate inputs and fail safely when discovery data is incomplete.
  • Protect credentials and minimize execution privileges.
  • Treat automation code as software subject to review and testing.
  • Measure compliance, failure rate, duration, drift, and recovery performance.
  • Document exceptions rather than allowing permanent undocumented deviations.

Chapter Summary

Configuration management converts infrastructure administration from an individual, procedural activity into a repeatable system of desired-state management. Ansible provides inventories, playbooks, modules, roles, variables, facts, handlers, and orchestration controls for managing diverse fleets. Good inventory design enables accurate targeting, while dynamic discovery supports cloud-scale environments but requires validation and governance.

Idempotent tasks, reusable roles, templates, and platform-aware abstractions improve maintainability. Provisioning, configuration, and patching should be treated as related stages in a controlled lifecycle. Rolling and canary strategies reduce operational risk, particularly when supported by preflight checks, health validation, and explicit failure thresholds. Python extends fleet automation through custom modules, discovery, validation, API integration, and analytics.

Because automation operates with substantial privilege, security, auditability, secret management, testing, and change governance are essential. The applied case demonstrates that reliable fleet automation combines technical design with organizational controls and service-level thinking.

Key Terms

Configuration management: The practice of defining, applying, and maintaining the desired state of IT resources.

Desired state: The configuration and behavior that a managed resource is intended to have.

Idempotence: The property that repeated application of an operation produces the same intended result without unnecessary side effects.

Fleet: A population of managed servers, devices, services, or infrastructure resources.

Inventory: A structured description of managed hosts, groups, variables, and metadata.

Dynamic inventory: Inventory generated from an external API, database, cloud platform, or service registry.

Playbook: A YAML-based Ansible document that defines plays and automation tasks.

Play: An Ansible mapping of a set of hosts to variables, roles, and tasks.

Task: A declared unit of work executed through an Ansible module.

Module: A reusable automation component that manages a particular resource or operation.

Role: A standardized, reusable package of Ansible tasks, templates, variables, files, and handlers.

Handler: A conditionally triggered task, commonly used for service restarts after configuration changes.

Fact: Information gathered about a managed host, such as its operating system or network interfaces.

Drift: Deviation between a resource’s actual state and its declared desired state.

Orchestration: Coordination of changes across multiple systems according to dependency and sequencing rules.

Canary deployment: A rollout that first changes a small representative group before wider execution.

Rolling deployment: A staged update that processes a fleet in successive batches.

Preflight check: A validation performed before an automated change begins.

Infrastructure as code: The practice of defining infrastructure through version-controlled, machine-readable code.

Configuration baseline: An approved reference set of settings, packages, and controls used to assess compliance.

Review Questions

Short Answer Questions

1. What is the difference between current state and desired state in configuration management?

2. Why is idempotence important in an Ansible task?

3. What information can be represented in an inventory besides hostnames?

4. What is the purpose of an Ansible handler?

5. Why should dynamic inventory validate resource metadata?

Long Answer Questions

1. Explain how inventories, playbooks, roles, modules, variables, and handlers work together in an Ansible automation design.

2. Discuss the principles of designing a maintainable role for a heterogeneous infrastructure fleet.

3. Compare rolling, canary, and blue-green deployment strategies in terms of risk, capacity, and operational use.

4. Explain how provisioning, configuration, and patching should be integrated into an infrastructure lifecycle.

5. Discuss the security and governance controls required when automation has privileged access to production systems.

Analytical / Application Questions

1. A cloud inventory suddenly returns no production hosts because a tagging API is unavailable. What safeguards should the automation platform apply before executing a patching workflow?

2. A web service has ten identical servers, but patching all of them together would remove too much capacity. Design an orchestration approach using canaries, batches, health checks, and abort criteria.

3. An organization uses a shell script that always rewrites configuration files and restarts services. Analyze the operational weaknesses and propose an idempotent Ansible-based design.

22. Multiple Choice Questions with Answers

Question 1

A configuration task installs a package only when it is absent and reports no change on later executions. Which property does this best demonstrate?

A. Idempotence

B. Dynamic discovery

C. Blue-green deployment

D. Secret rotation

Correct Answer: A. Idempotence

Question 2

Which inventory design is most appropriate for selecting cloud hosts that are tagged environment=production and patch_window=weekend?

A. A manually maintained list with no groups

B. A dynamic inventory that maps validated tags to groups

C. A playbook containing hard-coded IP addresses

D. A handler that discovers hosts after execution

Correct Answer: B. A dynamic inventory that maps validated tags to groups

Question 3

In the example playbook, why is the web service restart implemented as a handler?

A. To ensure the service restarts after every task

B. To restart the service only when a notifying change occurs

C. To permit execution without privileges

D. To replace inventory grouping

Correct Answer: B. To restart the service only when a notifying change occurs

Question 4

Which approach best reduces the risk of a faulty patch affecting an entire horizontally scaled web tier?

A. Run the patch simultaneously on every host

B. Use a canary followed by controlled batches and health checks

C. Disable service monitoring during the patch

D. Use only shell commands instead of modules

Correct Answer: B. Use a canary followed by controlled batches and health checks

Question 5

A dynamic inventory receives an API response with missing ownership and environment tags. What should a well-governed discovery process do?

A. Assign the hosts automatically to production

B. Ignore the missing data and continue silently

C. Reject or quarantine the incomplete records and report the problem

D. Delete all existing inventory data

Correct Answer: C. Reject or quarantine the incomplete records and report the problem

Question 6

Which activity is most clearly a preflight check before fleet patching?

A. Verifying repository reachability and available service capacity

B. Restarting every service after the patch

C. Removing failed hosts from the inventory permanently

D. Disabling host-key verification

Correct Answer: A. Verifying repository reachability and available service capacity

Question 7

Why is a focused role generally preferable to an enormous role containing unrelated infrastructure responsibilities?

A. Focused roles make variable use impossible

B. Focused roles improve reuse, testing, review, and ownership clarity

C. Large roles cannot contain handlers

D. Focused roles eliminate the need for inventories

Correct Answer: B. Focused roles improve reuse, testing, review, and ownership clarity

Question 8

Which is an appropriate use of Python alongside Ansible?

A. Embedding credentials directly in source code

B. Creating a validated custom discovery program or domain-specific module

C. Bypassing all authorization checks for faster execution

D. Replacing all declarative state with random commands

Correct Answer: B. Creating a validated custom discovery program or domain-specific module

Question 9

A task successfully installs a package, but the application endpoint returns errors. What does this demonstrate about automation validation?

A. Task success always proves service success

B. Package installation is unrelated to configuration management

C. Post-change checks must verify meaningful service and business health

D. Health checks should be removed from production

Correct Answer: C. Post-change checks must verify meaningful service and business health

Question 10

Which control most directly supports auditability of privileged configuration changes?

A. Unreviewed manual edits on the control node

B. Version control, peer review, execution records, and documented approvals

C. Suppressing all automation output

D. Using a shared administrator password

Correct Answer: B. Version control, peer review, execution records, and documented approvals

DevOps Automation with Python and Infrastructure Scripting
Chapter 11 of 15