Ansible playbook to collect vSphere performance metrics

vSphere exposes CPU, memory, storage and network counters that help teams explain saturation, validate capacity and investigate incidents. Ansible can collect those values through a repeatable workflow instead of intermittent screenshots or manual checks in the vSphere Client.

This example uses VMware PowerCLI through the community.general.powershell module, producing timestamped JSON that can feed AWX, a SIEM or a time-series platform. It captures a current snapshot; historical analysis requires a performance-history pipeline or access to the vCenter Performance API.

Why automate vSphere performance data

Regular collection gives operations teams a common baseline. Host CPU and memory indicate whether the physical layer is under pressure, while VM counters reveal which workloads are responsible. The evidence supports capacity reviews, incident timelines and post-maintenance comparisons.

Australian enterprises and managed service providers often span Sydney, Melbourne, Brisbane and Perth, with vCenter endpoints hosted in major regional facilities. Australian admins commonly call a saturated VM hot, so alerts can preserve that familiar language while exposing the underlying counter. The VMware automation guides place this collection job within a broader VMware workflow.

Prepare the collection environment

Run the controller from a trusted Linux host, such as Ubuntu 24.04 LTS, with Ansible Core, the community.general collection, PowerShell 7 and VMware.PowerCLI. The controller needs outbound TCP 443 access to vCenter; virtual machines do not need an Ansible agent for this method.

Install the collection with ansible-galaxy collection install community.general and PowerCLI with Install-Module VMware.PowerCLI -Scope CurrentUser. Create a dedicated vCenter service account with read access to inventory and current performance counters. Store its credentials with Ansible Vault, then pass them to the short-lived PowerCLI session as environment values.

Record timestamps in UTC and translate them for display. New South Wales moves between AEST and AEDT, while Victoria and Queensland keep standard time; offset-aware alerts prevent an hour of misleading data each autumn. Central scheduling should also account for links to regional sites rather than assuming constant low latency.

Build the collection playbook

The inventory defines one local controller, while variables hold the vCenter address and artifact path. VMware.PowerCLI supplies current counters through Get-VMHostSummary and Get-VM, so no guest agent is required. Each record keeps the source unit explicit.

---
- name: Collect vSphere performance metrics
  hosts: localhost
  connection: local
  gather_facts: false
  vars:
    vsphere_server: vcenter.au.example.com
    metric_directory: /var/tmp/vsphere-metrics
  tasks:
    - name: Set the UTC collection timestamp
      ansible.builtin.set_fact:
        metric_run: "{{ now(utc=true) | strftime('%Y%m%dT%H%M%SZ') }}"

    - name: Ensure the artifact directory exists
      ansible.builtin.file:
        path: "{{ metric_directory }}"
        state: directory
        mode: "0750"

    - name: Collect host and virtual machine counters
      community.general.powershell:
        script: |
          $ErrorActionPreference = 'Stop'
          $password = ConvertTo-SecureString $env:VSPHERE_PASSWORD -AsPlainText -Force
          $credential = [pscredential]::new($env:VSPHERE_USER, $password)
          $session = Connect-VIServer -Server $env:VSPHERE_SERVER -Credential $credential

          try {
            $summaries = Get-VMHostSummary -VMHost (Get-VMHost)

            $hosts = @(Get-VMHost | ForEach-Object {
              $esxiHost = $_
              $summary = $summaries | Where-Object { $_.Name -eq $esxiHost.Name }
              [ordered]@{
                name = $esxiHost.Name
                cpu_percent = $summary.CpuUsage
                memory_mb = $summary.MemUsage
                power_state = [string]$esxiHost.PowerState
              }
            })

            $vms = @(Get-VM | ForEach-Object {
              $vm = $_
              [ordered]@{
                name = $vm.Name
                host = $vm.Host.Name
                cpu_mhz = $vm.CPUUsage
                memory_mb = $vm.MemoryUsage
                power_state = [string]$vm.PowerState
              }
            })

            $payload = [ordered]@{
              collected_at = [DateTime]::UtcNow.ToString('o')
              hosts = $hosts
              vms = $vms
            }

            $payload | ConvertTo-Json -Depth 5 |
              Set-Content -Path $env:VSPHERE_ARTIFACT -Encoding utf8
          }
          finally {
            Disconnect-VIServer -Server $session -ErrorAction SilentlyContinue
          }
        environment:
          VSPHERE_SERVER: "{{ vsphere_server }}"
          VSPHERE_USER: "{{ vault_vsphere_user }}"
          VSPHERE_PASSWORD: "{{ vault_vsphere_password }}"
          VSPHERE_ARTIFACT: "{{ metric_directory }}/vsphere-{{ metric_run }}.json"
      no_log: true
      changed_when: false

    - name: Restrict artifact permissions
      ansible.builtin.file:
        path: "{{ metric_directory }}/vsphere-{{ metric_run }}.json"
        mode: "0640"

The host payload includes processor percentage and memory usage. The VM payload adds its ESXi host, power state, CPU load in MHz and memory use in MB. The controller creates a UTC-stamped JSON file with restrictive permissions; no values are normalised without knowing the configured capacity.

Compare the viable collection methods

The right collection route depends on whether the requirement is a repeatable snapshot, historical series or continuous monitoring:

Approach Useful output Operating model Main trade-off
Ansible with PowerCLI Current host and VM CPU and memory counters Scheduled controller or AWX job Simple to operate, but limited history
Ansible with pyVmomi Current or historical counters from the vSphere Performance API Custom Python module or script Flexible, but more development
vCenter exporter with Prometheus Continuous time-series metrics for hosts and VMs Scrape and retention stack Better trend analysis, extra infrastructure

PowerCLI is the simplest route for a small estate or a scheduled evidence bundle. For detailed history, pyVmomi exposes the Performance API but requires custom code. A Prometheus exporter supports continuous fleet-wide metrics, adding a scrape and retention stack to operate.

Validate and operationalise the output

Start with a syntax check, then run the playbook against a non-production vCenter and inspect the JSON. Confirm object counts, null values and units before scheduling. A powered-off VM can legitimately report zero or missing counters, which should not be treated as a failed collection.

Use jq '{collected_at, host_count: (.hosts | length), vm_count: (.vms | length)}' metrics.json to validate the shape quickly, then compare trends rather than isolated readings. CPU values in MHz are not CPU percentages, and memory figures need configured capacity before a utilisation ratio is calculated. Treat authentication failures, stale timestamps or unexpected gaps as collection failures and alert operations instead of publishing empty results.

Build a repeatable monitoring workflow

Once the snapshot is reliable, AWX can run it on a short interval and forward the JSON to InfluxDB, a SIEM or an API. Keep raw counters and the collection timestamp so teams can reconcile them with Australian daylight-saving changes and regional maintenance windows.

The pattern can be extended through the VirtXpert resources and tools, including related PowerCLI utilities. Keep credential handling in Vault and avoid placing vCenter addresses or performance data in public build logs.

Copy the playbook into your repository, test it with a read-only account, verify one complete artifact, and schedule the first run from AWX. Retain that baseline for capacity reviews and make it the starting point for continuous virtualisation observability.