Introduction

Cisco Unified Computing System (UCS) combines compute, networking, storage access, and virtualization into a single cohesive platform. Managing UCS at scale — provisioning blade servers, configuring service profiles, setting up VLANs, and enforcing boot policies across multiple UCS domains — is exactly what Ansible excels at. The cisco.ucs collection provides modules for every major UCS Manager operation, turning hours of GUI clicks into repeatable, version-controlled playbooks.

Prerequisites

RequirementDetails
Ansible2.8 or newer
Python SDKucsmsdk
Collectioncisco.ucs
UCS Manager3.2+ recommended
NetworkHTTPS access from Ansible control node to UCS Manager

Installation

# Install the collection
ansible-galaxy collection install cisco.ucs

# Install the UCS Python SDK
pip install ucsmsdk

# Verify SDK connectivity
python3 -c "
from ucsmsdk.ucshandle import UcsHandle
handle = UcsHandle('ucs-manager.example.com', 'admin', 'password')
print('Login:', handle.login())
handle.logout()
"

Module Reference

ModulePurpose
ucs_vlansCreate, modify, delete VLANs
ucs_vlan_findFind VLANs by ID or name
ucs_service_profile_templateManage service profile templates
ucs_service_profile_from_templateInstantiate profiles from templates
ucs_lan_connectivityLAN connectivity policies
ucs_san_connectivitySAN connectivity policies
ucs_mac_poolMAC address pools
ucs_wwn_poolWWN pools for Fibre Channel
ucs_uuid_poolUUID pools for server identity
ucs_ip_poolIP address pools for KVM/management
ucs_ntp_serverNTP server configuration
ucs_dns_serverDNS server configuration
ucs_timezoneTimezone configuration
ucs_disk_group_policyStorage disk group policies
ucs_storage_profileStorage profiles
ucs_managed_objectsGeneric managed object configuration

Inventory and Connection

# inventory/ucs.yml
all:
  children:
    ucs:
      hosts:
        ucs-domain-01:
          ucs_hostname: 10.1.1.100
        ucs-domain-02:
          ucs_hostname: 10.1.1.101
      vars:
        ucs_username: "{{ vault_ucs_username }}"
        ucs_password: "{{ vault_ucs_password }}"

UCS modules use connection: local — Ansible talks to UCS Manager's API from the control node, not via SSH to the servers themselves.

Pattern 1: VLAN Configuration

---
- name: Configure VLANs on UCS domains
  hosts: ucs
  connection: local
  gather_facts: false
  collections:
    - cisco.ucs

  vars:
    vlans:
      - { name: "VLAN-Production", id: "100" }
      - { name: "VLAN-Management", id: "10" }
      - { name: "VLAN-Storage", id: "200" }
      - { name: "VLAN-Backup", id: "201" }
      - { name: "VLAN-DMZ", id: "300" }
      - { name: "VLAN-Dev", id: "400" }
      - { name: "VLAN-Test", id: "401" }
      - { name: "VLAN-vMotion", id: "500" }
      - { name: "VLAN-iSCSI-A", id: "600" }
      - { name: "VLAN-iSCSI-B", id: "601" }

  tasks:
    - name: Configure VLANs
      ucs_vlans:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: "{{ item.name }}"
        id: "{{ item.id }}"
        native: "{{ item.native | default('no') }}"
        state: present
      loop: "{{ vlans }}"

    - name: Verify VLANs exist
      ucs_vlan_find:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        pattern: "VLAN-*"
      register: vlan_list

    - name: Display configured VLANs
      ansible.builtin.debug:
        msg: "Found {{ vlan_list.vlans | length }} VLANs matching pattern"

Pattern 2: Identity Pools (MAC, UUID, WWNN, WWPN)

---
- name: Configure identity pools
  hosts: ucs
  connection: local
  gather_facts: false
  collections:
    - cisco.ucs

  tasks:
    - name: Create MAC address pool — Fabric A
      ucs_mac_pool:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: MAC-Pool-A
        first_addr: 00:25:B5:A0:00:00
        last_addr: 00:25:B5:A0:00:FF
        order: sequential
        org_dn: org-root
        state: present

    - name: Create MAC address pool — Fabric B
      ucs_mac_pool:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: MAC-Pool-B
        first_addr: 00:25:B5:B0:00:00
        last_addr: 00:25:B5:B0:00:FF
        order: sequential
        org_dn: org-root
        state: present

    - name: Create UUID pool
      ucs_uuid_pool:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: UUID-Pool
        prefix: derived
        first_uuid: "0000-000000000001"
        last_uuid: "0000-0000000000FF"
        order: sequential
        org_dn: org-root
        state: present

    - name: Create WWNN pool
      ucs_wwn_pool:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: WWNN-Pool
        purpose: node
        first_addr: 20:00:00:25:B5:00:00:00
        last_addr: 20:00:00:25:B5:00:00:FF
        order: sequential
        org_dn: org-root
        state: present

    - name: Create WWPN pool — Fabric A
      ucs_wwn_pool:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: WWPN-Pool-A
        purpose: port
        first_addr: 20:00:00:25:B5:A0:00:00
        last_addr: 20:00:00:25:B5:A0:00:FF
        order: sequential
        org_dn: org-root
        state: present

    - name: Create IP pool for KVM access
      ucs_ip_pool:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: KVM-IP-Pool
        first_addr: 10.1.10.100
        last_addr: 10.1.10.200
        subnet_mask: 255.255.255.0
        default_gw: 10.1.10.1
        org_dn: org-root
        state: present

Pattern 3: Service Profile Template

---
- name: Create service profile template
  hosts: ucs
  connection: local
  gather_facts: false
  collections:
    - cisco.ucs

  tasks:
    - name: Configure LAN connectivity policy
      ucs_lan_connectivity:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: ESXi-LAN-Policy
        org_dn: org-root
        vnic_list:
          - name: vNIC-Mgmt
            vnic_template: vNIC-Mgmt-Template
            adapter_policy: VMWare
            order: "1"
          - name: vNIC-vMotion
            vnic_template: vNIC-vMotion-Template
            adapter_policy: VMWare
            order: "2"
          - name: vNIC-Production
            vnic_template: vNIC-Prod-Template
            adapter_policy: VMWare
            order: "3"
        state: present

    - name: Configure SAN connectivity policy
      ucs_san_connectivity:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: ESXi-SAN-Policy
        org_dn: org-root
        wwnn_pool: WWNN-Pool
        vhba_list:
          - name: vHBA-A
            vhba_template: vHBA-Template-A
            adapter_policy: VMWare
            order: "1"
          - name: vHBA-B
            vhba_template: vHBA-Template-B
            adapter_policy: VMWare
            order: "2"
        state: present

    - name: Create service profile template
      ucs_service_profile_template:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: ESXi-Host-Template
        template_type: updating-template
        uuid_pool: UUID-Pool
        lan_connectivity_policy: ESXi-LAN-Policy
        san_connectivity_policy: ESXi-SAN-Policy
        boot_policy: ESXi-SAN-Boot
        bios_policy: ESXi-Performance
        host_firmware_package: default
        ipmi_access_profile: ""
        power_control_policy: No-Power-Cap
        local_disk_policy: No-Local-Storage
        maintenance_policy: User-Ack
        org_dn: org-root
        state: present

Pattern 4: Deploy Servers from Template

---
- name: Deploy ESXi hosts from service profile template
  hosts: ucs
  connection: local
  gather_facts: false
  collections:
    - cisco.ucs

  vars:
    esxi_hosts:
      - { name: "esxi-prod-01", blade: "1/1" }
      - { name: "esxi-prod-02", blade: "1/2" }
      - { name: "esxi-prod-03", blade: "1/3" }
      - { name: "esxi-prod-04", blade: "1/4" }
      - { name: "esxi-prod-05", blade: "2/1" }
      - { name: "esxi-prod-06", blade: "2/2" }
      - { name: "esxi-prod-07", blade: "2/3" }
      - { name: "esxi-prod-08", blade: "2/4" }

  tasks:
    - name: Create service profiles from template
      ucs_service_profile_from_template:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: "{{ item.name }}"
        source_template: ESXi-Host-Template
        org_dn: org-root
        state: present
      loop: "{{ esxi_hosts }}"

    - name: Associate profiles with physical blades
      ucs_managed_objects:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        objects:
          - module: ucsmsdk.mometa.ls.LsBinding
            class: LsBinding
            properties:
              parent_mo_or_dn: "org-root/ls-{{ item.name }}"
              pn_dn: "sys/chassis-{{ item.blade.split('/')[0] }}/blade-{{ item.blade.split('/')[1] }}"
              restrict_migration: "no"
      loop: "{{ esxi_hosts }}"

    - name: Power on servers
      ucs_managed_objects:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        objects:
          - module: ucsmsdk.mometa.ls.LsPower
            class: LsPower
            properties:
              parent_mo_or_dn: "org-root/ls-{{ item.name }}"
              state: admin-up
      loop: "{{ esxi_hosts }}"

Pattern 5: System Configuration

---
- name: Configure UCS system settings
  hosts: ucs
  connection: local
  gather_facts: false
  collections:
    - cisco.ucs

  tasks:
    - name: Configure NTP servers
      ucs_ntp_server:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        ntp_server: "{{ item }}"
        state: present
      loop:
        - 10.1.1.10
        - 10.1.1.11
        - pool.ntp.org

    - name: Configure DNS servers
      ucs_dns_server:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        dns_server: "{{ item }}"
        state: present
      loop:
        - 10.1.1.10
        - 10.1.1.11

    - name: Set timezone
      ucs_timezone:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        timezone: America/New_York
        state: present

Pattern 6: Storage Configuration

---
- name: Configure storage policies
  hosts: ucs
  connection: local
  gather_facts: false
  collections:
    - cisco.ucs

  tasks:
    - name: Create disk group policy — RAID 1 for boot
      ucs_disk_group_policy:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: Boot-RAID1
        raid_level: mirror
        num_drives: 2
        drive_type: SSD
        org_dn: org-root
        state: present

    - name: Create disk group policy — RAID 5 for data
      ucs_disk_group_policy:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: Data-RAID5
        raid_level: stripe-parity
        num_drives: 4
        drive_type: SSD
        org_dn: org-root
        state: present

    - name: Create storage profile
      ucs_storage_profile:
        hostname: "{{ ucs_hostname }}"
        username: "{{ ucs_username }}"
        password: "{{ ucs_password }}"
        name: ESXi-Storage-Profile
        local_luns:
          - name: Boot-LUN
            disk_policy_name: Boot-RAID1
            size: "100"
            expand_to_avail: "no"
          - name: Datastore-LUN
            disk_policy_name: Data-RAID5
            size: "0"
            expand_to_avail: "yes"
        org_dn: org-root
        state: present

Multi-Domain Management

---
- name: Apply standard configuration to all UCS domains
  hosts: ucs
  connection: local
  gather_facts: false
  serial: 1  # One domain at a time for safety

  tasks:
    - name: Apply VLANs
      ansible.builtin.include_tasks: tasks/vlans.yml

    - name: Apply identity pools
      ansible.builtin.include_tasks: tasks/identity-pools.yml

    - name: Apply service profile templates
      ansible.builtin.include_tasks: tasks/service-profile-templates.yml

    - name: Apply system configuration
      ansible.builtin.include_tasks: tasks/system-config.yml

    - name: Validate configuration
      ansible.builtin.include_tasks: tasks/validate.yml

Troubleshooting

SDK Connection Test

# test_ucs_connection.py
from ucsmsdk.ucshandle import UcsHandle

handle = UcsHandle("10.1.1.100", "admin", "password")
try:
    handle.login()
    print("✅ Connected successfully")
    print(f"UCS Version: {handle.version}")
    # List all blades
    blades = handle.query_classid("ComputeBlade")
    for blade in blades:
        print(f"  Blade {blade.dn}: {blade.num_of_cpus} CPUs, {blade.total_memory}MB RAM")
finally:
    handle.logout()

Module Timeout Issues

# Increase timeout for long-running operations
- name: Deploy service profile (may take several minutes)
  ucs_service_profile_from_template:
    hostname: "{{ ucs_hostname }}"
    username: "{{ ucs_username }}"
    password: "{{ ucs_password }}"
    name: "{{ item.name }}"
    source_template: ESXi-Host-Template
  environment:
    UCS_TIMEOUT: 300

Permission Errors

UCS Manager requires an account with at least admin or server-profile privileges for service profile operations. Read-only operations work with read-only access.

Conclusion

The cisco.ucs collection automates the full UCS lifecycle: VLANs, identity pools (MAC/UUID/WWN/IP), service profile templates, server deployment, storage policies, and system configuration. Use connection: local since Ansible talks to UCS Manager's REST API, not SSH. For enterprise environments with multiple UCS domains, define all domains in inventory and use serial: 1 for safe sequential configuration. The biggest win is service profile templates — define your server configuration once, deploy identical servers in minutes, and ensure every blade in the data center matches the same standard.