Solutions

AsterNOS Ansible Collection: Deployment Guide and Practical Case Studies

Preface

This document is a deployment guide and set of practical case studies for the AsterNOS Ansible Collection. It is intended to help network engineers and automation operations personnel quickly deploy the Collection environment on a control node, and use declarative Playbooks to perform operations on AsterNOS data center switches such as batch configuration provisioning, state collection, image upgrades, and patch management.

Intended Audience

This guide is intended for network engineers and operations personnel working with AsterNOS switches. After reading this guide, you will be able to:

• Install Ansible and the asterfusion.asternos Collection on a control node;

• Write Inventory files and variable files, organizing configuration parameters by device role;

• Write Playbooks that manage switches using the three core states: merged / deleted / gathered;

• Perform batch deployment of common data center network configurations such as VLANs, interfaces, and routing protocols.

Before reading this guide, readers are expected to have basic Linux command-line skills and foundational networking knowledge.

Revision History

Date

Version

Revision Notes

2026-09-08

V1.0

Initial release

1 Background

As data center scale continues to grow and network topologies become increasingly complex, configuration management for network devices faces mounting challenges. Manually logging into each device's CLI to perform configuration is not only inefficient, but also prone to human error, which can introduce configuration mistakes and network faults. Ansible, as a mature automation and operations tool, has become the preferred solution in the network automation space thanks to its declarative configuration model and rich module ecosystem.

To enable standardized, large-scale, and automated management of AsterNOS switches, Asterfusion has released the AsterNOS Ansible Collection. Built on the mature network_cli framework, this Collection provides a full-stack set of resource modules covering interfaces, VLANs, routing protocols, system firmware, and patch management. It supports operations such as merged, deleted, and gathered, helping teams build an efficient, reliable automated operations framework.

2 Environment Requirements

2.1 Control Node Requirements

The control node is the server or virtual machine that runs Ansible and this Collection. It must meet the following requirements:
Table 2-1  Control Node Environment Requirements

Component

Minimum Version

Recommended Version

Operating System

Linux

Ubuntu 22.04

Python

3.6

3.9+

Ansible

2.9

2.15+

ansible.netcommon

5.0.0

Latest

SSH Client

OpenSSH 7+

OpenSSH 8+

2.2 Managed Node Requirements

The managed node is an Asterfusion data center switch running AsterNOS. Requirements are as follows:

  • AsterNOS version: R0409 series or later

  • SSH access enabled, with the management-port IP reachable from the control node

  • A local user account with administrator privileges (used for SSH login and configuration provisioning)

  • The switch CLI must support the Klish framework (Cisco-like IOS syntax)

2.3 Network Requirements

  • SSH connectivity between the control node and the switches (TCP port 22)

  • SNMP (optional): used only for facts collection.

3 Installation Guide

This chapter provides two installation methods. Method 2 (Docker image installation) is recommended, as it enables faster deployment and reduces dependency configuration.

3.1 Method 1: Installing from a Locally Built tar Package

After preparing a Linux server or virtual machine, use this method if you prefer to install the Ansible environment and its dependencies yourself. Complete the following steps in order:

3.1.1 Install Python and pip

If Python and pip are already installed and meet the version requirements, you may skip this step.

sonic@asterfusion:~$ sudo apt update
sonic@asterfusion:~$ sudo apt install -y python3 python3-pip

# Verify
sonic@asterfusion:~$ python3 --version
Python 3.10.12
sonic@asterfusion:~$ pip3 --version
pip 24.0 from /usr/local/lib/python3.10/site-packages/pip (python 3.10)

3.1.2 Install Ansible

Install Ansible using pip.

sonic@asterfusion:~$ pip3 install ansible

# Verify the installation; it should show Ansible 2.15+ version information
sonic@asterfusion:~$ ansible --version
ansible [core 2.17.14]
  config file = None
  configured module search path = ['/root/.ansible/plugins/modules',
'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.10/dist-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.10.12 (main, Jun 22 2026, 18:55:27) [GCC 11.4.0] (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True

3.1.3 Install the ansible.netcommon Dependency

Install the common ansible.netcommon collection. ansible.netcommon provides the network_cli connection plugin, which is a prerequisite for this Collection to run. Version >= 5.0.0 is required.

sonic@asterfusion:~$ ansible-galaxy collection install ansible.netcommon

3.1.4 Install the AsterNOS Collection

Obtain the prebuilt tar package file asterfusion-asternos-1.1.1.tar.gz from the relevant personnel, and install the Collection from this tar package. After downloading and uploading the tar package, run the following command to install it:

sonic@asterfusion:~$ ansible-galaxy collection install asterfusion-asternos-1.1.1.tar.gz --force

The --force flag overwrites any already-installed version with the same name; using this flag ensures the latest version is installed.

3.1.5 Verify the Installation

Check whether Ansible and the Collection were installed successfully. Expected output: asterfusion.asternos 1.1.1.

root@asterfusion:~# ansible-galaxy collection list | grep asterfusion
asterfusion.asternos                  1.1.1

3.2 Method 2: Docker Image Installation

Asterfusion provides a Docker image with Ansible, the ansible.netcommon dependency, and the asterfusion.asternos Collection preinstalled. After loading the image with docker load, it can be used directly — there's no need to install Ansible or its dependencies yourself.

3.2.1 Obtain the Image File

Obtain the Docker image file asternos-ansible-v1.0.tar from the relevant personnel.

3.2.2 Load the Docker Image

After transferring the image file to the control node server, run the following command to load the image.

sonic@asterfusion:~/ycw$ sudo docker load -i asternos-ansible-v1.0.tar

# View the loaded images
sonic@asterfusion:~$ docker images

3.2.3 Create the Container

sonic@asterfusion:~$ docker run -d \
  --name asternos-ansible \
  -w /var/test/ansible \
  --network host \
  --privileged \
  asternos-ansible:v1.0

3.2.4 Enter the Container and Verify

After the container is created, enter it.

sonic@asterfusion:~$ docker exec -it asternos-ansible bash

Verify the Ansible version inside the container

root@asterfusion:/var/test/ansible# ansible --version
ansible [core 2.16.3]
  config file = None
  configured module search path = ['/root/.ansible/plugins/modules',
'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.12.3 (main, Mar 23 2026, 19:04:32) [GCC 13.3.0] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True

Verify whether the Collection is installed.

root@asterfusion:/var/test/ansible# ansible-galaxy collection list | grep asterfusion
asterfusion.asternos                  1.1.1

Once verification passes, you can write and run Playbooks inside the container. For detailed usage instructions, refer to Chapters 4 and 5.

4 Prerequisite Configuration

Before writing and running Playbooks, you need to prepare and configure the ansible.cfg and inventory files. If Ansible was installed via the Docker image, the ansible.cfg and inventory files are already created for you under /var/test/ansible/asternos-playbooks inside the container. If the Collection was installed from a locally built tar package, you will need to create these two files yourself.

4.1 Create the Ansible Configuration File

ansible.cfg is Ansible's project-level configuration file. When a Playbook script is run to deploy switch configuration, Ansible reads this file first, taking priority over the global default settings. It can specify the inventory file path, plugin search directories, SSH connection timeout, and more. Create the ansible.cfg file under the asternos-playbooks working directory:

root@asterfusion:/var/test/ansible/asternos-playbooks# cat ansible.cfg
[defaults]
inventory = ./inventory
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml
interpreter_python = auto_silent
timeout = 120

[collections]
collections_paths = ~/.ansible/collections:/usr/share/ansible/collections

[persistent_connection]
connect_timeout = 120
command_timeout = 120

4.2 Create the Inventory File

inventory is Ansible's host inventory file, used to define the IP list of managed devices and the username/password used to log into them uniformly. When Ansible executes a Playbook, it uses this file to determine which devices to act on and how to connect to them. Configuration variables can also be defined here and referenced directly during configuration provisioning. Create the inventory file under the asternos-playbooks working directory:

root@asterfusion:/var/test/ansible/asternos-playbooks# cat inventory
# AsterNOS switch inventory - the entries below are examples; replace with your actual IPs
[asternos_switches]
spine01 ansible_host=10.250.0.171
leaf161 ansible_host=10.250.0.161
leaf128 ansible_host=10.250.0.128

[asternos_switches:vars]
ansible_network_os=asterfusion.asternos.asternos
ansible_user=admin
ansible_password=asteros
ansible_connection=ansible.netcommon.network_cli
ansible_become=no
ansible_host_key_checking=False
ansible_ssh_host_key_checking=False

Key parameters in the inventory file are explained below:

Table 4-1 Inventory File Parameter Descriptions

Parameter

Description

ansible_network_os

Specifies the network device type; must be asterfusion.asternos.asternos

ansible_connection

Connection method; ansible.netcommon.network_cli provisions configuration via CLI commands

ansible_user

SSH login username

ansible_password

SSH login password

ansible_become

Whether to escalate privileges; usually set to no

4.3 Test Connectivity

Once the prerequisite configuration is complete, use the following command to test connectivity with the switches — for example, using the facts module to collect switch platform information:

root@asterfusion:/var/test/ansible/asternos-playbooks# ansible leaf161 -m
asterfusion.asternos.asternos_facts -a 'gather_subset=platform'
leaf161 | SUCCESS => {
  "ansible_facts": {
    "ansible_net_gather_network_resources": [],
    "ansible_net_gather_subset": [],
    "ansible_net_platform_fan": [
      {
        "direction": "1",
        "name": "FAN",
        "presence": "green",
        "speed": "DRAWER",
        "status": "FAN",
        "timestamp": "1F 10680RPM intake Present OK 20260730 11:06:43"
      },
      {
        "direction": "1",
        "name": "FAN",
        "presence": "green",
        "speed": "DRAWER",
        "status": "FAN",
        "timestamp": "1R 9480RPM intake Present OK 20260730 11:06:43"
      },
      {
        "direction": "2",
        "name": "FAN",
        "presence": "green",
        "speed": "DRAWER",
        "status": "FAN",
        "timestamp": "2F 11040RPM intake Present OK 20260730 11:06:45"
      },
      {
        "direction": "2",
        "name": "FAN",
        "presence": "green",
        "speed": "DRAWER",
        "status": "FAN",
……

5 Writing and Running Playbooks

5.1 Writing a Playbook

A Playbook is Ansible's configuration file, using YAML format to describe the tasks to be executed on a device. Once the prerequisite configuration is complete, you can start writing Playbooks under the asternos-playbooks directory to perform specific tasks. Below is a complete Playbook example demonstrating how to configure a hostname:

- name: config switches hostname
  hosts: asternos_switches
  gather_facts: no
  tasks:
    - name: config hostname
      asterfusion.asternos.asternos_hostname:
        config:
          hostname: "sonic-leaf"
        state: merged

Explanation of key elements:

  • hosts: The host(s) on which the configuration is executed. This can be a specific device or category of devices defined under asternos_switches in the inventory file, or it can be asternos_switches itself, meaning all hosts participate in the task.

  • gather_facts: By default, Ansible implicitly collects target-host facts (CPU, memory, OS, etc.) at the start of every Playbook and stores them in the ansible_facts variable. Adding this parameter causes Ansible to skip this step and execute only the tasks explicitly defined in the Playbook, improving execution efficiency.

  • asterfusion.asternos.asternos_<module_name>: The name of the module invoked during task execution

  • config: The module's configuration parameters

  • state: Typically merged, deleted, or gathered — used to add or remove configuration

5.2 Running a Playbook

Once a Playbook is written, it can be executed. As an example, here we write a Playbook inside the container to configure an interface IP address on a switch. The specific Playbook content is as follows:

root@asterfusion:/var/test/ansible/asternos-playbooks# cat config_interface.yml
- name: Configure Layer 3 Interfaces
  hosts: leaf161
  gather_facts: no
  tasks:
    - name: Configure Interface IP
      asterfusion.asternos.asternos_l3_interfaces:
        config:
          - name: "0/1"
            ipv4:
              - address: "10.1.1.1/24"
        state: merged

Run the specified Playbook.

root@asterfusion:/var/test/ansible/asternos-playbooks# ansible-playbook config_interface.yml

PLAY [Configure Layer 3 Interfaces] 
********************************************************************************************************************************************************

TASK [Configure Interface IP] 
********************************************************************************************************************************************************
changed: [leaf161]

PLAY RECAP 
********************************************************************************************************************************************************
leaf161                    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Log into the switch and check the configuration under interface 0/1 — the IP address has been configured successfully.

sonic# configure
sonic(config)# interface ethernet 0/1
sonic(config-if-0/1)# show this
!
interface ethernet 0/1
 fec rs
 mtu 9216
 speed 25000
 ip address 10.1.1.1/24

5.3 Execution Parameters

When running a Playbook, you can also specify several optional parameters to make troubleshooting and issue diagnosis easier.

Table 5-1 Common Playbook Execution Parameters

Flag

Full Name

Description

Use Case

-v / -vvv

--verbose

Outputs detailed logs. -v shows the CLI commands issued; -vvv shows the complete connection and debug log.

Debugging and troubleshooting

-l

--limit

Restricts the execution target. Supports a single device name, wildcards (e.g., leaf*), or a comma-separated device list.

Canary rollouts, single-device testing

-C

--check

Check mode. Computes and simulates the configuration that would be pushed, without actually writing it to the device.

Pre-change safety dry runs

-D

--diff

Diff comparison. Shows the details of the configuration difference before and after the change; typically used together with -C or -v.

Auditing configuration changes

The -v flag runs with verbose output, showing the log printed during execution — such as the actual configuration commands executed — which is very helpful for troubleshooting. The -vvv flag shows even more detailed log output.

root@asterfusion:/var/test/ansible/asternos-playbooks# ansible-playbook config_interface.yml -v
Using /var/test/ansible/asternos-playbooks/ansible.cfg as config file

PLAY [Configure Layer 3 Interfaces] 
********************************************************************************************************************************************************

TASK [Configure Interface IP] 
********************************************************************************************************************************************************
changed: [leaf161] => changed=true
  commands:
  - interface ethernet 0/1
  - no switchport
  - ip address 10.1.1.1/24
  - exit

PLAY RECAP 
********************************************************************************************************************************************************
leaf161                    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

The -l flag can restrict the execution scope. If the inventory file defines a large number of switches but a Playbook task should only run against one device or a subset of devices, you can use the -l flag.

root@asterfusion:/var/test/ansible/asternos-playbooks# ansible-playbook config_interface.yml -l leaf161

PLAY [Configure Layer 3 Interfaces] 
********************************************************************************************************************************************************

TASK [Configure Interface IP] 
********************************************************************************************************************************************************
changed: [leaf161]

PLAY RECAP 
********************************************************************************************************************************************************
leaf161                    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
root@asterfusion:/var/test/ansible/asternos-playbooks#

To run a Playbook task against all leaf switches:

root@asterfusion:/var/test/ansible/asternos-playbooks# ansible-playbook config_interface.yml -l leaf*

To run a Playbook task against a specific subset of switches:

root@asterfusion:/var/test/ansible/asternos-playbooks# ansible-playbook config_interface.yml -l "leaf161,leaf128"

In check mode, the module computes and prints the commands that would be issued, but does not actually modify the device configuration. Combined with the --diff and -v flags, you can also view the detailed diff of the configuration change. This can be used to preview configuration changes before they are actually applied; exact support depends on the module being used.

root@asterfusion:/var/test/ansible/asternos-playbooks# ansible-playbook config_interface.yml --check --diff -v
Using /var/test/ansible/asternos-playbooks/ansible.cfg as config file

PLAY [Configure Layer 3 Interfaces] 
********************************************************************************************************************************************************

TASK [Configure Interface IP] 
********************************************************************************************************************************************************
changed: [leaf161] => changed=true
  commands:
  - interface ethernet 0/1
  - no switchport
  - ip address 10.1.1.1/24
  - exit

PLAY RECAP 
********************************************************************************************************************************************************
leaf161                    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

6 Usage Examples

6.1 Retrieving Basic Switch Information

By writing and running a Playbook task, you can collect switch information in bulk. Example:

root@asterfusion:/var/test/ansible/asternos-playbooks# cat get_info.yml
- name: Collect AsterNOS switches info
  hosts: asternos_switches
  gather_facts: no
  tasks:
    - name: Gather device information
      asterfusion.asternos.asternos_facts:
        gather_subset:
          - default
          - platform
      register: result

After execution, platform-related information can be collected from switches in bulk.

6.2 Batch Configuration Provisioning

Configuration can be provisioned to switches in bulk, covering hostname, VLANs, physical interfaces, Layer 3 interfaces, BGP, and more. This example shows how to chain multiple resource modules together in a single Playbook to complete an entire configuration set in one execution run. The specific workflow is:

  1. Configure the device hostname

  2. Create VLANs and configure their descriptions

  3. Configure descriptions for physical interfaces

  4. Add interfaces to VLANs

  5. Configure the uplink interface IP address

  6. Configure BGP settings such as AS number, router ID, and neighbor information

⚠️ The configuration parameters below are for illustration only. In an actual deployment, these should be defined separately via the Inventory or variable files, based on device role, management address, and network topology.

- name: Batch configuration distribution
  hosts: asternos_switches
  gather_facts: no
  tasks:
    - name: Configure hostname
      asterfusion.asternos.asternos_hostname:
        config:
          hostname: "{{ inventory_hostname }}"
          router_type: "{{ 'spine' if 'spine' in inventory_hostname else 'leaf' }}"
        state: merged

    - name: Create VLAN
      asterfusion.asternos.asternos_vlans:
        config:
          - vlan_id: 10
            description: "Management"
            mac_learning: true
          - vlan_id: 20
            description: "Server"
            mac_learning: true
          - vlan_id: 30
            description: "Storage"
            mac_learning: true
        state: merged

    - name: Configure ethernet interface
      asterfusion.asternos.asternos_interfaces:
        config:
          - name: "0/1"
            description: "Uplink to Spine"
            enabled: true
            speed: "25000"
            mtu: 9216
          - name: "0/2"
            description: "Downlink to Server"
            enabled: true
            mtu: 9216
        state: merged

    - name: Configure L2interface
      asterfusion.asternos.asternos_l2_interfaces:
        config:
          - name: "0/2"
            mode: trunk
            trunk:
              allowed_vlans: [10, 20, 30]
          - name: "0/3"
            mode: access
            access:
              vlan: 20
        state: merged

    - name: Configure L3 interface IP address
      asterfusion.asternos.asternos_l3_interfaces:
        config:
          - name: "vlan10"
            ipv4:
              - address: "10.1.10.1/24"
        state: merged

    - name: Configure BGP
      asterfusion.asternos.asternos_bgp_global:
        config:
          as_number: 65141
          router_id: "10.1.1.1"
          neighbors:
            - neighbor_address: "10.1.1.2"
              remote_as: 65002
              bfd: true
        state: merged

    - name: Save configuration
      asterfusion.asternos.asternos_config:
        save_when: always

6.3 Deleting Switch Configuration

In a Playbook, the state: deleted parameter defines a delete operation, which can remove specific configuration items. As an example, we delete a VLAN that has already been configured on a switch; after execution, you can log into the switch to confirm the VLAN was successfully deleted.

root@asterfusion:/var/test/ansible/asternos-playbooks# cat delete_vlan.yml
- name: delete VLANs
  hosts: leaf161
  gather_facts: no
  tasks:
    - name: delete VLAN
      asterfusion.asternos.asternos_vlans:
        config:
          - vlan_id: 10
        state: deleted
root@asterfusion:/var/test/ansible/asternos-playbooks# ansible-playbook delete_vlan.yml -v
Using /var/test/ansible/asternos-playbooks/ansible.cfg as config file

PLAY [delete VLANs] 
********************************************************************************************************************************************************

TASK [delete VLAN] 
********************************************************************************************************************************************************
changed: [leaf161] => changed=true
  commands:
  - no interface vlan 10
  - no vlan 10

PLAY RECAP 
********************************************************************************************************************************************************
leaf161                    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

6.4 Saving Configuration

When configuration changes need to be saved, use the asternos_config module to save them:

root@asterfusion:/var/test/ansible/asternos-playbooks# cat save_config.yml
- name: Save configuration
  hosts: asternos_switches
  gather_facts: no
  tasks:
    - name: Save switches running-configuration
      asterfusion.asternos.asternos_config:
        save_when: always

save_when options: always — always save; never — never save (default); changed — save only when there is a change; modified — save when the configuration has been modified. changed is recommended.

6.5 Issuing CLI Commands Directly

When the existing functional modules don't yet fully cover a specific configuration requirement, you can execute CLI commands directly using the config module. For example, to configure uCentral-related settings, you can run the Playbook below.

root@asterfusion:/var/test/ansible/asternos-playbooks# cat config_ucentral.yml
- name: Configure Ucentral
  hosts: leaf161
  gather_facts: no
  tasks:
    - name: Config ucentral
      asterfusion.asternos.asternos_config:
        lines:
          - feature ucentral state enable
          - feature ucentral autorestart enable
          - ucentral-client server 10.126.1.100 vrf mgmt
        save_when: always

Configuring the device time zone:

root@asterfusion:/var/test/ansible/asternos-playbooks# cat config_clock.yml
- name: Configure timezone
  hosts: asternos_switches
  gather_facts: no
  tasks:
    - name: Config timezone
      asterfusion.asternos.asternos_config:
        lines:
          - clock timezone Asia/Shanghai

When executing a command that includes an interactive confirmation prompt (such as a [y/N] prompt), you can use prompt to match the echoed output after the command executes, and use answer to supply the y/N response. Below is a Playbook that executes the reload command and answers y to confirm the action. A reload operation may cause a service interruption, so execute it with caution.

- name: reload switch
  hosts: leaf161
  gather_facts: no
  tasks:
    - name: Reload switch
      ansible.netcommon.cli_command:
        command: reload
        prompt: "Clear running config and reload saved config"
        answer: "y"

6.6 Batch Version Upgrades

When managing a network in practice, it is often necessary to perform system image upgrades across multiple switches. Using the batch version-upgrade Playbook below as an example, the specific workflow is:

  1. Retrieve the device type

  2. Based on the device type, transfer the corresponding image file to the switch

  3. Verify that the image's MD5 checksum matches the expected value

  4. Save the device configuration

  5. Perform the image installation, upgrading 10 switches at a time

  6. Wait for the image installation to complete, then reboot the device

  7. Once the device has recovered, log in and check the version information

⚠️ By default, 5 devices are upgraded concurrently. Setting the serial parameter to 1 in the Playbook executes devices one at a time; setting serial to 10 allows 10 switches to be upgraded concurrently.

Before running the upgrade Playbook, copy the switch image file to the ansible working directory in advance.

- name: Upgrade switch
  hosts: asternos_switches
  gather_facts: no
  serial: 10

  tasks:
    # 1. Get platform info
    - name: Get ASIC_TYPE
      ansible.netcommon.cli_command:
        command: "system cat /etc/sonic/sonic-environment"
      register: sonic_env

    # 2. Get ASIC_TYPE
    - name: Parse ASIC_TYPE
      set_fact:
        asic_type: "{{ sonic_env.stdout | regex_findall('ASIC_TYPE=(\\S+)') | first }}"

    - name: Validate supported ASIC_TYPE
      assert:
        that:
          - asic_type | length > 0
          - asic_type in ['marvell', 'innovium']
        fail_msg: |
          ERR--not supported ASIC_TYPE: '{{ asic_type }}'
          Only support marvell / innovium, abort task!
        success_msg: "ASIC_TYPE: {{ asic_type }}"

    # 3. Choose bin
    - name: choose image
      set_fact:
        image_bin: "{{ 'AsterNOS_V3.1_R0409P01-FL.bin' if asic_type == 'marvell' else 'AsterNOS_V3.1_R0409P01.bin' }}"

    # 4 upload images
    - name: Upload image to switch via SCP
      command: |
        sshpass -p '{{ ansible_password }}' scp
        -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null
        "{{ playbook_dir }}/{{ image_bin }}"
        "{{ ansible_user }}@{{ ansible_host }}:/home/admin/{{ image_bin }}"
      delegate_to: localhost
      register: upload_result

    - name: Calculate MD5 of uploaded image on switch
      command: |
        sshpass -p '{{ ansible_password }}' ssh
        -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null
        {{ ansible_user }}@{{ ansible_host }}
        "md5sum /home/admin/{{ image_bin }} | awk '{print $1}'"
      delegate_to: localhost
      register: md5_result

    # 4.2 Set the expected MD5 value, example data, please replace it with actual data
    - name: Set expected MD5 based on ASIC type
      set_fact:
        expected_md5: "{{ 'f115b5ded0deefb6ede65602bd27e11b' if asic_type != 'marvell' else '69dd9d4b7dd1e34783a776eec5bd2682' }}"

    # 4.3 Verify the MD5, abort and report an error if it does not match
    - name: Verify MD5 checksum
      fail:
        msg: |
          MD5 checksum mismatch!
          Expected : {{ expected_md5 }}
          Got      : {{ md5_result.stdout }}
          File     : /home/admin/{{ image_bin }}
          Upgrade aborted to prevent corruption.
      when: (md5_result.stdout | trim) != expected_md5

    # 5. Save configuration
    - name: Save switches running-configuration
      asterfusion.asternos.asternos_config:
        save_when: always

    # 6. Upgrade images
    - name: Switch System update Image
      asterfusion.asternos.asternos_image:
        config:
          bin_file: "{{ image_bin }}"
        state: merged

    # 7. reboot
    - name: Safe Reboot Switch
      asterfusion.asternos.asternos_reboot:
        confirm: true

    # 8. wait 600s
    - name: Wait 600 seconds after reboot
      wait_for:
        timeout: 600
      delegate_to: localhost

    # 9.Check version
    - name: Check SONiC version
      ansible.netcommon.cli_command:
        command: show version
      register: ver

    - name: Assert expected version
      ansible.builtin.assert:
        that:
          - "'Software, Version 3.1, R0409P01' in ver.stdout"
        fail_msg: "Version mismatch! Got: {{ ver.stdout_lines[0] }}"
        success_msg: "Version check passed"

6.7 Installing a Patch

When a switch needs a patch installed, you can similarly write a Playbook script to perform the patch installation in bulk. Refer to the content below; the specific workflow is:

  1. Copy the patch file to the /home/admin directory on the switch

  2. Perform the patch installation

- name: Install System Patch
  hosts: asternos_switches
  gather_facts: no
  tasks:
    - name: Copy patch file to device
      ansible.netcommon.net_put:
        src: ./files/patch.bin
        dest: /home/admin/patch.bin

    - name: Install patch
      asterfusion.asternos.asternos_patch:
        file_name: patch.bin
        remote_dir: /home/admin
        install_args: "-i"

Related solutions