Playbook Ansible : renouveler le certificat aut0-signé d’une Cisco IMC

Depuis un certain temps, nous rencontrons des “problèmes” d’expiration de certificat (auto-signé) de CIMC sur des C220 M4.  Renouveler le certificat auto-signé d’une CIMC est très simple, vous pouvez le faire via la GUI de la CIMC, en CLI ou via le Playbook que nous venons de mettre en place. L’avantage du Playbook est qu’il va récupérer les informations de l’ancien certificat afin de les reporter sur le nouveau certificat, puis il va afficher les informations du nouveau certificat afin de s’assurer que le nouveau certificat a bien une nouvelle date d’expiration, et bien sûr c’est plus rapide et on peut se faire une petite boucle histoire de le faire sur plusieurs CIMC 😉 .

Juste avant Noël, donc on peut légitiment espérer un vrai certificat sous le sapin pour le 25 au matin 🙂
- hosts: localhost
  
  tasks:      
    
    # Read current certificate
    - name: Read Current Certificate
      community.general.imc_rest:
        hostname: '{{ imc_hostname }}'
        username: '{{ imc_username }}'
        password: '{{ imc_password }}'
        validate_certs: no
        content: |
          <configResolveDn  inHierarchical="false" dn="sys/cert-mgmt/curr-cert">
          </configResolveDn>
      retries: 10
      delay: 5
      register: current_certif
      until: current_certif is not failed

    - debug:
        msg: "{{ current_certif }}"

    - name: create variables from current_certif
      set_fact:
        var_commonName: "{{ current_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.commonName }}"
        var_countryCode: "{{ current_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.countryCode }}"
        var_organization: "{{ current_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.organization }}"
        var_organizationalUnit: "{{ current_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.organizationalUnit }}"
        var_locality: "{{ current_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.locality }}"
        var_state: "{{ current_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.state }}"
        var_validFrom: "{{ current_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.validFrom }}"
        var_validTo: "{{ current_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.validTo }}"
        var_signatureAlgorithm: "SHA384"
        var_selfSigned: "yes"

    - debug:
        msg: 
          - "{{ var_commonName }}"
          - "{{ var_countryCode }}"
          - "{{ var_organization }}"
          - "{{ var_organizationalUnit }}"
          - "{{ var_locality }}"
          - "{{ var_state }}"
          - "{{ var_validFrom }}"
          - "{{ var_validTo }}"


     # Generate selfSigned Certificate
    - name: Generate selfSigned Certificate
      community.general.imc_rest:
        hostname: '{{ imc_hostname }}'
        username: '{{ imc_username }}'
        password: '{{ imc_password }}'
        validate_certs: no
        timeout: 180
        content: |
            <configConfMo dn="sys/cert-mgmt/gen-csr-req" inHierarchical="false">
            <inConfig>
            <generateCertificateSigningRequest commonName="{{ var_commonName }}" 
              organization="{{ var_organization }}" 
              organizationalUnit="{{ var_organizationalUnit }}" locality="{{ var_locality }}" 
              state="{{ var_state }}" countryCode="United States" 
              dn="sys/cert-mgmt/gen-csr-req" selfSigned="yes"/>
            </inConfig>
            </configConfMo>
      retries: 10
      delay: 5
      register: generate_certif
      until: generate_certif is not failed


    # Read the new certificate
    - name: Read the new certificate
      community.general.imc_rest:
        hostname: '{{ imc_hostname }}'
        username: '{{ imc_username }}'
        password: '{{ imc_password }}'
        validate_certs: no
        content: |
          <configResolveDn  inHierarchical="false" dn="sys/cert-mgmt/curr-cert">
          </configResolveDn>
      retries: 30
      delay: 5
      register: new_certif
      until: (new_certif is not failed) and (new_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.commonName == var_commonName)

    - debug:
        msg: "{{ new_certif }}"

    - name: create variables for new_certif
      set_fact:
        var_commonName: "{{ new_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.commonName }}"
        var_countryCode: "{{ new_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.countryCode }}"
        var_organization: "{{ new_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.organization }}"
        var_organizationalUnit: "{{ new_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.organizationalUnit }}"
        var_locality: "{{ new_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.locality }}"
        var_state: "{{ new_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.state }}"
        var_validFrom: "{{ new_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.validFrom }}"
        var_validTo: "{{ new_certif.configResolveDn.children[0].outConfig.children[0].currentCertificate.attributes.validTo }}"

    - debug:
        msg: 
          - "{{ var_commonName }}"
          - "{{ var_countryCode }}"
          - "{{ var_organization }}"
          - "{{ var_organizationalUnit }}"
          - "{{ var_locality }}"
          - "{{ var_state }}"
          - "{{ var_validFrom }}"
          - "{{ var_validTo }}"

Une fois le Playbook passé la CIMC a un nouveau certificat auto-signé avec les anciennes valeurs.

On est reparti pour 5 ans 🙂

Post to Twitter

Playbook Ansible : paramétrer l’état des disques dans une CIMC

Dans ce Playbook nous allons configurer l’état des disques d’un serveur CISCO M5 en “Unconfigured-good”  (via une CIMC), afin de les préparer pour la création d’un Virtual Drive  (voir notre précedent billet “Playbook Ansible : créer un Virtual Drive dans une CIMC“).

Les tasks du Playbook :

  • Check Power Status : récupère l’état du serveur (on/off ) envoie le résultat dans la variable  “SrvPwStatus“, si le serveur est “power off” alors le playbook s’arrête.
  • Check IMC uri : vérifie que l’url de la CIMC du serveur répond bien via un retour HTTP 200, si ce n’est pas le cas le Playblook s’arrête.
  • Search Status and ID storageLocalDisk 0 and 1 : récupère  le status des disques (JBOD/unconfigured-good) ainsi que l’ID de chaque disques. Le status des disques est envoyé dans les variables SearchStatusDisk0/SearchStatusDisk1, l’ID des disques  est envoyé dans les variables SearchIdDisk0/SearchIdDisk0
  • Search dn Storage Controller: permet de récupérer le dn du Storage Controller . Cette task est exécuté si un des disques à sa variable SearchStatusDisk0/SearchStatusDisk1 égal la variable StatusDiskJbod (“JBOD”)
  • Configure Disk 0 : Configure le disk0 en “make-unconfigured-good
    uniquement si la variable SearchStatusDisk0 est égale à StatusDiskJbod (“JBOD”)
  • Configure Disk 1 : Configure le disk1 en “make-unconfigured-good
    uniquement si la variable SearchStatusDisk1 est égale à StatusDiskJbod (“JBOD”)
    hosts: localhost
    
      vars:
        imc_hostname: 100.83.36.141
        imc_password: 
        imc_username: admin
        StatusDiskJbod: JBOD
        StatusDiskUnconfGood: unconfigured-good
        
    
      tasks:
    
        - name: Check Power Status
          community.general.imc_rest:
            hostname: '{{ imc_hostname }}'
            username: '{{ imc_username }}'
            password: '{{ imc_password }}'
            validate_certs: no
            content: |
              <configResolveClass inHierarchical="false" classId="computeRackUnit"/>      
          register: CIMCPower
        - set_fact:
            SrvPwStatus: "{{ CIMCPower.configResolveClass.children[0].outConfigs.children[0].computeRackUnit.attributes.operPower }} "
        - debug:
            msg: "{{ SrvPwStatus }}"
          failed_when: '"on" not in SrvPwStatus'
    
    
        - name: Check IMC uri
          uri:
            url: https://{{ imc_hostname }}
            validate_certs: no
            status_code: 200
          register: result
        - debug:
            msg: "{{result}}"
          failed_when: result.status != 200
            
    
        - name: Search Status and ID storageLocalDisk 0 and 1
          community.general.imc_rest:
            hostname: '{{ imc_hostname }}'
            username: '{{ imc_username }}'
            password: '{{ imc_password }}'
            validate_certs: no
            content: |
              <configResolveClass inHierarchical="true" classId="storageLocalDisk"/>
          register: storageLocalDisk
        - set_fact:
            SearchStatusDisk0: "{{ storageLocalDisk.configResolveClass.children[0].outConfigs.children[0].storageLocalDisk.attributes.pdState }}"
            SearchStatusDisk1: "{{ storageLocalDisk.configResolveClass.children[0].outConfigs.children[1].storageLocalDisk.attributes.pdState }}"
            SearchIdDisk0: "{{ 'pd-' + storageLocalDisk.configResolveClass.children[0].outConfigs.children[0].storageLocalDisk.attributes.id }}"
            SearchIdDisk1: "{{ 'pd-' + storageLocalDisk.configResolveClass.children[0].outConfigs.children[1].storageLocalDisk.attributes.id }}"
        - debug:
            msg: 
              - "{{ SearchStatusDisk0 }}"
              - "{{ SearchStatusDisk1 }}"
              - "{{ SearchIdDisk0 }}"
              - "{{ SearchIdDisk1 }}"
    
    
        - name: Search dn Storage Controller
          community.general.imc_rest:
            hostname: '{{ imc_hostname }}'
            username: '{{ imc_username }}'
            password: '{{ imc_password }}'
            validate_certs: no
            content: |
              <configResolveClass inHierarchical="true" classId="storageController"/>
          register: StorageController
          when: SearchStatusDisk0 == StatusDiskJbod  or SearchStatusDisk1 == StatusDiskJbod
        - set_fact:
            SearchDnRaid: "{{ StorageController.configResolveClass.children[0].outConfigs.children[0].storageController.attributes.dn }}"
          when: SearchStatusDisk0 == StatusDiskJbod or SearchStatusDisk1 == StatusDiskJbod
        - debug:
            msg: "{{ SearchDnRaid }}"
          when: SearchStatusDisk0 == StatusDiskJbod or SearchStatusDisk1 == StatusDiskJbod
    
    
        - name: Configure Disk 0
          community.general.imc_rest:
            hostname: '{{ imc_hostname }}'
            username: '{{ imc_username }}'
            password: '{{ imc_password }}'
            validate_certs: no
            content: |
              <configConfMo dn='{{SearchDnRaid}}/{{ SearchIdDisk0 }}'>
              <inConfig>
              <storageLocalDisk adminAction='make-{{StatusDiskUnconfGood}}'></storageLocalDisk>
              </inConfig>
              </configConfMo>
          retries: 3
          delay: 1
          when: SearchStatusDisk0 == StatusDiskJbod
    
        - name: Configure Disk 1
          community.general.imc_rest:
            hostname: '{{ imc_hostname }}'
            username: '{{ imc_username }}'
            password: '{{ imc_password }}'
            validate_certs: no
            content: |
              <configConfMo dn='{{SearchDnRaid}}/{{ SearchIdDisk1 }}'>
              <inConfig>
              <storageLocalDisk adminAction='make-{{StatusDiskUnconfGood}}'></storageLocalDisk>
              </inConfig>
              </configConfMo>
          retries: 3
          when: SearchStatusDisk1 == StatusDiskJbod
    
    Dans la CIMC nous avons quatre disques configurés en JBOD

    Il ne reste plus qu’à lancer le Playbook pour configurer les deux premiers disques en “unconfigured-good”.

    La task Check Power Status a bien vu le server “on”, le Playbook passe donc à la task suivante (dans le cas contraire le Playbook s’arrête)
    La task Check IMC uri récupère un “status 200”, le Playbook passe donc aux tasks qui configurent les disques (dans le cas contraire le Playbook s’arrête)
    Nos deux disques sont désormais configurés en “Unconfigured-good”
    C’est tout bon côté CIMC

    Post to Twitter

    Playbook Ansible : créer un Virtual Drive dans une CIMC

    Suite à un projet d’automatisation de déploiement de serveurs CISCO nous allons essayer de vous faire partager au fil du temps des Playbooks Ansible (essentiellement sur la partie CIMC dans un premier temps). Le playbook du jour permet la création d’un virtual drive dans une CIMC d’un serveur CISCO C220 M5 .

    - hosts: localhost
    
    
      vars:
        imc_hostname: ""
        imc_password: ""
        imc_username: "admin"
    
      tasks:
    
        - name: Search Disk Size
          community.general.imc_rest:
            hostname: '{{ imc_hostname }}'
            username: '{{ imc_username }}'
            password: '{{ imc_password }}'
            validate_certs: no
            content: |
              <configResolveClass inHierarchical="true" classId="storageLocalDisk"/>
          register: CIMC
        - set_fact:
            ddsize: "{{ CIMC.configResolveClass.children[0].outConfigs.children[0].storageLocalDisk.attributes.coercedSize }}"
        - debug:
            msg: "{{ ddsize }}"
    
        
        - name: Search dn Storage Controller
          community.general.imc_rest:
            hostname: '{{ imc_hostname }}'
            username: '{{ imc_username }}'
            password: '{{ imc_password }}'
            validate_certs: no
            content: |
              <configResolveClass inHierarchical="true" classId="storageController"/>
          register: StorageController
        - set_fact:
            SearchDnRaid: "{{ StorageController.configResolveClass.children[0].outConfigs.children[0].storageController.attributes.dn }}"
        - debug:
            msg: "{{ SearchDnRaid }}"
    
        
        - name: Create Virtual Drive
          community.general.imc_rest:
            hostname: '{{ imc_hostname }}'
            username: '{{ imc_username }}'
            password: '{{ imc_password }}'
            validate_certs: no
            content: |
              <configConfMo dn='{{SearchDnRaid}}/virtual-drive-create'> 
              <inConfig> 
              <storageVirtualDriveCreatorUsingUnusedPhysicalDrive virtualDriveName='vdTest' raidLevel='1' size="{{ddsize}}" driveGroup='[1,2]' writePolicy='Write Through' adminState='trigger'/>
              </inConfig>
              </configConfMo>
    

    Dans la task “Search Disk Size” on récupère la taille du premier disque qui nous servira à la création du RAID dans la task “Create Virtual Drive”. La task “Search dn Storage Controller” permet de récupérer le dn du Controller afin de pouvoir la récupérer dans la task “Create Virtual Drive” (si vous avez des Controller différents notamment)

    Notre CIMC sans Virtual Drive
    dans le Playbook on voit bien la taille des disques remontés et le dn qui seront utiles pour la création du Virtual Drive
    Le Virtual Drive est bien créé une fois le Playbook terminé

    Quelques lien sur les APi (REST/XML) CISCO IMC  :

    Post to Twitter

    IMC Supervisor : déploiement firmware impossible

    Déployer un firmware via IMC Surpervisor est très simple encore faut-il que cela fonctionne, et c’est toujours quand on n’a pas le temps que cela se complique 🙂 . Sur Une IMC Supervisor (ver : 2.2.0.0) nous devions déployer un firmware sur un Serveur Cisco M5, mais le menu “Firmware Upgrade” en avait décidé autrement. En effet lorsque l’onglet “Firmware Upgrade” s’affichait, la liste des serveurs (tout du moins le bouton +)  ne s’affichait pas, seule une barre de progression qui tournait sans fin nous tenait compagnie.

    Sur la page Rack Groups, onglet “Rack Servers” on remarque une ligne avec des éléments manquants (seule le Last Inventory Update) apparaît. 

    Avec l’information “Last Inventory Update” nous allons regarder dans la page Physical Account (onglet “Racks Accounts”) si nous trouvons quelque chose.

    Bingo on retrouve notre serveur, cette fois avec toutes ses informations

    Nous avons supprimé ce serveur afin de vérifier que c’était bien la cause de notre problème (dans le menu “Firmware Upgrade”), puis nous sommes allés tester le menu “Firmware Upgrade”.

    Nickel ça passe (il ne reste plus qu’à rajouter notre serveur supprimé)

    Post to Twitter

    Host hardware system board status

    Sur plusieurs Vcenter 6.5/6.7 nous avons rencontré l’erreur “Host hardware system board status” sur des ESXi 6.5/6.7 (UCS-240-M4). En regardant côté CIMC (Cisco Integrated Management Controller) on n’a rien constaté au premier abord (pas d’alerte hardware ou autre). En navigant dans la CIMC dans l’onglet SEL (System Event Log) nous avons constaté que ce dernier était full, en faisant un clear log cela nous a permis de corriger l’alarme “Host hardware system board status”.


    Il est aussi possible de faire un clear du SEL via SSH et REST API

    En SSH :
    Se connecter en SSH sur le serveur puis entrer les commandes ci-dessous :

    • show sel (si vous souhaitez au préalable visualiser le pourcentage d’occupation des log)L’attribut alt de cette image est vide, son nom de fichier est SEL01.png.
    • scope sel
    • clear (le screeenshoot ci-dessous montre le résultat de la commande show après un clear

    En Rest API :

    • https://10.10.10.10/redfish/v1/Chassis/1/LogServices/SEL/Actions/LogService.ClearLog


    Si vous souhaitez plus d’infos sur les CLI CISCO UCS c’est juste en dessous.

    Post to Twitter

    vSAN : Rechercher un disque

    La lecture du titre de ce post vous laisse dubitatif avouez le 🙂 .

    Dernièrement nous avons dù identifier physiquemebt un disque (au sein d’un disque group) qui rencontrait de grosses latences (entre 15000 ms et 45000 ms), un remplacement rapide s’imposait donc.

    Le problème est que nous avons pu identifier le disque au sein du disque groupe via son naa, mais comment l’identifier physiquement sur l’ESXi (serveur CISCO UCS-C240-M4SX) ? Dans UCS Central aucune alarme ne remontait côté disque (normal il n’y a pas de problème hardware vous nous direz) et en ESXCLI on ne remonte pas d’informations de type PID permettant de faire le lien entre le naa. et le disque dans UCS. Dans le Vcenter, sur l’ESXi dans l’onglet “Configure” –  “Storage-Storage Device” vous avez un bouton qui permet (logiquement) d’allumer la led d’un disque  selectionné (le fameux “turn on ou turn off disk locator”), mais dans notre cas cela ne fonctionnait pas. 

    On a beau cliquez ça reste vert 🙁 .

    En googlelant nous sommes tombés sur la commande ci-dessous qui permet d’allumer (ou clignoter) la led d’un disque.

    esxcli storage core device set -d naa.50000397885347bd -l=locator -L=600
    

    Après avoir trouver une âme charitable dans le Datacenter, le collègue a pu nous donner la position du disque dans le serveur en vue de son prochain remplacement.

    Post to Twitter