Ansible CISCO CIMC : installation d’un firmware

L’installation d’un firmware sur une CIMC via la GUI n’est nativement pas possible (enfin pas totalement, on nuance un peu nos propos car il existe une façon de faire via le dépôt du firmware localement sur le serveur via SFTP (WinSCP est parfait pour ce type d’action) par exemple, puis de faire l’update de firmware via la GUI de la CIMC),  le downgrade est lui bien  possible ;). Si vous souhaitez upgrader le firmware d’un serveur CISCO vous pouvez aussi passer par la Cisco IMC Supervisor (via la GUI ou les APIs),  dans notre cas  nous souhaitions passer directement par la CIMC afin de simplifier (et éviter un spof) notre automatisation d’upgrade de fimware.  Dans le cas présent nous avons automatisé l’upgrade de firmware sur des serveurs CISCO (C220 m4/C240 m5) via un partage NFS (le CIFS est possible). Nous vous partageons le playbook ci-dessous qui permet l’upgrade/downgrade de firmware des serveurs CISCO (testé sur des C220 m4/C240 m5) .

Les pré-requis :

  • Un partage NFS (ou CIFS)
  • Le(s) firmware CISCO
  • Renseignez les variables imc_hostname, bundle_ver_file, nfsserver et nsf_remoteShare

et c’est tout bon 😉 .

---
- hosts: localhost
  gather_facts: false

  vars:
    imc_hostname: "YourServrer.fqdn"
    bundle_ver_file: "YouFirmwareISOFile.iso"
    nfsserver: "Yourserver.fqdn"
    nsf_remoteShare: "/vol_xxxyyyy/pathvol/{{ bundle_ver_file }}"

  tasks:      
    
    
    - name: Upgrade firmware on {{ imc_hostname }} - {{currentSite}}
      community.general.imc_rest:
        hostname: '{{ imc_hostname }}'
        username: '{{ imc_username }}'
        password: '{{ imc_password }}'
        validate_certs: no
        content: |
          <configConfMo>
            <inConfig> 
              <huuFirmwareUpdater dn='sys/huu/firmwareUpdater' adminState='trigger' 
                remoteIp='{{nsf_remoteIp}}' remoteShare='{{nsf_remoteShare}}'
                mapType='nfs' username='' password="" stopOnError='yes' 
                timeOut='200' verifyUpdate='yes' updateComponent='all' >
              </huuFirmwareUpdater>
            </inConfig>
          </configConfMo>
      register: CIMC_upgrade

    - debug:
        msg: "{{CIMC_upgrade}}"

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
    # Check firmware status with block et rescue section
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
    - name: Check status firmware Block
      block:
        # The delay is 300 with retrie 20 for to avoid losing the CIMC during the upgrade
        - name: Check status firmware ( !!!! retry 20 - delay 480 !!!! )
          community.general.imc_rest:
            hostname: '{{ imc_hostname }}'
            username: '{{ imc_username }}'
            password: '{{ imc_password }}'
            validate_certs: no
            content: |
              <configResolveClass inHierarchical="true" classId="huuFirmwareUpdateStatus" dn="sys/huu/firmwareUpdater/updateStatus"/>
          retries: 20
          delay: 480
          register: CIMC_upgrade_status
          until: "CIMC_upgrade_status.configResolveClass.children[0].outConfigs.children[0].huuFirmwareUpdateStatus.attributes.updateEndTime != 'NA'"

        - debug:
            msg: 
              - "{{CIMC_upgrade_status.configResolveClass.children[0].outConfigs.children[0].huuFirmwareUpdateStatus.attributes}}"

      rescue:
        - name: "***** RESCUE BLOCK ******"
          debug:
            msg: "****** RESCUE BLOCK Start **********"

        - name: RESCUE Pause for 10 minutes (wait reboot CIMC)
          ansible.builtin.pause:
            minutes: 10
        
        - name: RESCUE Check status firmware ( !!!! retry 20 - delay 600 !!!! )
          community.general.imc_rest:
            hostname: '{{ imc_hostname }}'
            username: '{{ imc_username }}'
            password: '{{ imc_password }}'
            validate_certs: no
            content: |
              <configResolveClass inHierarchical="true" classId="huuFirmwareUpdateStatus" dn="sys/huu/firmwareUpdater/updateStatus"/>
          retries: 20
          delay: 600
          register: CIMC_upgrade_status
          until: "CIMC_upgrade_status.configResolveClass.children[0].outConfigs.children[0].huuFirmwareUpdateStatus.attributes.updateEndTime != 'NA'"

        - debug:
            msg: 
              - "{{CIMC_upgrade_status.configResolveClass.children[0].outConfigs.children[0].huuFirmwareUpdateStatus.attributes}}"


    - name : Set variable fw_starttime and fw_endtime
      set_fact:
        fw_starttime: "{{CIMC_upgrade_status.configResolveClass.children[0].outConfigs.children[0].huuFirmwareUpdateStatus.attributes.updateStartTime}}"
        fw_endtime: "{{CIMC_upgrade_status.configResolveClass.children[0].outConfigs.children[0].huuFirmwareUpdateStatus.attributes.updateEndTime}}"


    - name: Display Start time and End time upgrade firmware
      debug:
        msg: 
          - "Start time : {{ fw_starttime }}"
          - "End time : {{ fw_endtime }}"
      when: "fw_starttime != 'NA' and fw_endtime != 'NA'"


    - name: Upgrade firmware in minutes
      debug:
        msg: "Number of minutes : {{ (((fw_endtime | to_datetime) - (fw_starttime | to_datetime)).seconds / 60 ) | round | int }}"
      when: "fw_starttime != 'NA' and fw_endtime != 'NA'"


    - name: Check firmware version
      community.general.imc_rest:
        hostname: '{{ imc_hostname }}'
        username: '{{ imc_username }}'
        password: '{{ imc_password }}'
        validate_certs: no
        content: |
          <configResolveClass inHierarchical="true" classId="firmwareRunning" />
      retries: 60
      delay: 120
      register: CIMC_upgrade_version


    - name: Set variable currentfirmware
      set_fact:
        currentfirmware: "{{CIMC_upgrade_version.configResolveClass.children[0].outConfigs.children[1].firmwareRunning.attributes.version}}"


    - name: Display current firmware on {{ imc_hostname }} after upgrade
      debug:
        msg: "Current firmware : {{ currentfirmware }}"

Une fois lancé,  le playbook va vous donner le retour du code HTTP (logiquement 200 si tout va bien), puis va checker toutes les 480 secondes (X20)  le statut de l’upgrade du firmware (cela permet de gérer l’inaccessibilité de la CIMC lors de son upgrade, si toutefois le check tombe pendant l’inaccessibilité de la CIMC alors ça passe via le block rescue et on recommence via un check toutes les 600 secondes x 20), une fois l’upgrade terminé vous aurez la liste des composants upgraded/skipped, le start time et le end time de l’upgrade (ainsi que la durée de l’upgrade/downgrade) et l’affichage de la version du firmware après upgrade/downgrade.

Enjoy 😉

Post to Twitter

Ansible CISCO CIMC : Reset CIMC

Cela faisait un moment que l’on souhaitait intégrer un reset CIMC dans nos workflows de type souscription/décommissionnement de host CISCO (afin de rendre la CIMC le plus “propre” au début du workflow). C’est désormais chose faite via l’ajout du playbook ci-dessous. 

  - hosts: localhost
  
    vars:
      imc_hostname: "your_IMC"
      imc_username: "IMC_username"
      imc_password: "IMC_password"
      
    tasks:
  
      - name: Reset CIMC
        ignore_errors: yes
        community.general.imc_rest:
          hostname: '{{ imc_hostname }}'
          username: '{{ imc_username }}'
          password: '{{ imc_password }}'
          validate_certs: no
          timeout: 30
          content: |
            <configConfMo>
              <inConfig>
                <computeRackUnit adminPower="bmc-reset-immediate" dn="sys/rack-unit-1">
                </computeRackUnit>
              </inConfig>
            </configConfMo>
        register: result
      
       - debug:
          var: result
        
       - name: Pause for 5 minutes to wait cimc reset
         ansible.builtin.pause:
           minutes: 5
         
       - name: Check uri CIMC
        uri:
          url: "{{ imc_hostname }}"
          validate_certs: no
          status_code: 200
        register: result_cimcuri
        retries: 5
        delay: 10
        until: result_cimcuri is not failed
  
  
      - name: Stop play if result is not 200
        ansible.builtin.fail:
          msg:  "!!! Please check uri {{ imc_hostname }} !!!"
        when: result_cimcuri.status != 200 
  
      - debug:
          msg: "{{ result_cimcuri }}"

Une fois la task lancée, après le time-out (quelle que soit la durée du time-out)  vous obtiendrez l’erreur ci-dessous (c’est pour cela que l’on a ajouté le “ignore_errors: yes” ).

msg”: “Task failed with error -1: Connection failure: The read operation timed out”

L’erreur n’empêche pas le reset CIMC et avec le “ignore_errors: yes” nous pouvons passer à la task suivante (nous avons ajouté une pause de 5 mn afin de laisser le temps à la CIMC de “remonter”), afin de vérifier que la CIMC est bien remontée on check l’uri de la CIMC via la task “Check uri CIMC”, si la CIMC ne répond (code retour http 200) alors la task “Stop play if result is not 200” arrête le play avec le message d’erreur “!!! Please check uri {{ imc_hostname }} !!!”

Généralement nous recherchons les call API de CIMC via l’url “http://CIMC/visore.html“, mais pour le reset de CIMC impossible de trouver le call API en question (au pire on pouvait passer en SSH sur la CIMC, mais ce n’était pas le but). C’est en googlelant que nous sommes tombés sur sur le call API permettant le reset CIMC : reset CIMC with call API

Post to Twitter