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

    VMmark 3.1.1 erreur lors du lancement de notre premier “Tile”

    Dernièrement nous avons testé VMmark 3.1.1 (pour rappel VMmark permet de bencher et mesurer l‘évolution des plates-formes virtuelles) afin de bencher des serveurs DELL (PowerEdge R7515). On vous passe les étapes douloureuses (nous ferons un billet sur l’installation de VMmark 3.1.1 très prochainement) de l’installation et la configuration. Une fois l’installation terminée on lance notre premier Tile et là une belle erreur (ce n’est pas comme si c’était la première en plus…) mais celle-là aurait pu être évitée (genre RTFM) : “Error : machine = client0: Invalid Trust Level (3).

    Ca commence pas bien notre affaire 🙂

    La seule info qui nous intéresse dans le message d’erreur est “Client0”, comme tout bon Sysadmin on fait un ping de notre fameux “Client0”, comme nous n’avons pas de retour, direction le vCenter.

    Sans IP elle ne risque pas de répondre notre CLIENT0 🙂

    En allant plus loin on constate que l’IP du CLIENT0 (192.168.1.2) a été attribué à la VM DeployVM0 (le conflit d’IP explique notre message d’erreur). Direction le fichier VMmark3.properties (situé dans /root/VMmark3 de la VM “PrimeClient”) afin de voir si on n’a pas un problème de configuration sur la VM “Client0” ou  DeployVM0. Après une recherche dans le fichier VMmark3.properties on comprend d’où vient le problème, le deploy/DeployVMinfo est égal à DeployVM0:192.168.2 soit l’IP de de notre VM “CLIENT0”. 

    Il ne reste plus qu’à mettre la bonne IP

    Quand on lit le commentaire “Specifies the name and IP address of the deployed VMs. Ex DeployVM0:192.168.1.245,DeployVM1:192.168.1.246” on se dit qu’on a raté quelques chose 🙂 .

    Une fois l’IP de la VM “DeployVM0” passer sur 192.168.1.245 notre Tile est passé sans encombre

    Post to Twitter

    ESXi : Host TPM attestation alarm

    Sur plusieurs hosts PowerEdge R7515 nous avons constaté après l’installation d’ESXi 7.0.2 (17867351) une erreur TPM sur un de nos vCenter de test (notre fameux POC VCF)  :

    Host TPM attestation alarm

    L’erreur se produisant uniquement sur des PowerEdge R7515 il semblerait que nous ayons oublié de paramétrer correctement la partie TPM dans la config de nos serveurs DELL 🙂 . Direction l’ IDRAC pour vérifier ça.

    • Aller dans le BIOS (F2)
    • BIOS Settings-System Security
    Dans un premier temps on fait un clear avant de paramétrer la suite
    1. Cliquer sur  Clear (confirmer en cliquant sur le bouton Ok  lors de l’affichage du popup).
    2. Cliquer sur TPM Advanced Setting.
    Cliquez sur SHA256 (voilà pourquoi on avait l’erreur)
    Cliquez sur le bouton Yes
    Cliquez sur bouton Ok
    Cliquez sur le bouton Back
    Cliquez sur le bouton Finish
    Cliquer sur le bouton Finish
    Cliquez sur le bouton Yes
    Cliquer sur Reset To Green (et dans notre cas on pourra relancer l’upgrade de ce Workload Domain dans VCF 🙂 )

    Post to Twitter

    VCF : Premier BriengUp

    Dans le cadre d’un POC VCF 4.3.0 (VMware Cloud Foundation) nous avons rencontré une erreur (ou plutôt nous avons retenu celle-là 🙂 ) lors de l’installation du Cloud Builder.  Lors de l’étape “Validate Configuration” tout se passait bien jusqu’à l’apparition d’un Failed associé à l’erreur “Error connecting to ESXi host xxxx. SSL certificate common name doesn’t match  ESXi FQDN” sur les quatre host de notre POC.

    C’est sur que si le Cloud Builder ne peut pas se connecter aux ESXi ça va être dur pour la suite 🙂

    Le message d’erreur “Error connecting to ESXi host xxxx. SSL certificate common name doesn’t match  ESXi FQDN” est explicite, le certificat par défaut des ESXi ne convient pas au Cloud Builder pour se connecter aux ESXi, du coup impossible pour Cloud Builder d’aller plus loin. En relisant les pré-requis on s’aperçoit que depuis la version 4.2 de VCF, il faut que le certificat de l’ESXi soit au format host.FQDN (et corresponde bien sûr à ce qui est rentré dans votre fichier de configuration Cloud Builder).

    RTFM 🙂 c’est ici

    Comme indiqué  par VMware les étapes pour régénérer le certificat sont très simples :

    1. Connectez-vous en SSH sur chaque hôte ESXi.
    2. Lancez la commande “esxcli system hostname get” et vérifiez que Host est bien au format Host.FQDN dans la section “Fully Qualified Domain Name: “, si c’est bien le cas passez directement à l’étape 6.
    3. Lancez la commande “vi etc/hosts” puis ajouter votre Host.FQDN et enregistrer (touche “echap” puis “:wq!”.
    4. Lancez la commande “esxcfg-advcfg -s Host_FQDN /Misc/hostname” (remplacer Host_FQDN par le nom de votre host et son FQDN).
    5. Lancez la commande “reboot” 
    6. Lancez la commande “/sbin/generate-certificates“puis validez
    7. Lancez la commande “/etc/init.d/hostd restart && /etc/init.d/vpxa restart

      Il ne vous reste qu’à faire un “retry” dans le Cloud Builder 😉 .

      Et voilà 🙂 la suite dans un prochain billet (on vous promet c’est fun)

      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

      vRLI : reset du mot de passe utilisateur cassandra

      Récemment sur un vRLI 4.8.0-13036238, nous avons constaté que le compte par défaut de Cassandra (user : cassandra) avait un mot de passe qui ne respectait pas  les critères de sécurité de notre entreprise. Pour faire un  reset du mot de passe du compte user “cassandra” dans Cassandra (vous nous suivez ? 🙂 ) , il faut ouvrir une console SSH sur votre vRLI puis entrer dans Cassandra et lancer deux commandes.

      Une fois connecté en SSH sur votre vRLI, lancer la commande ci-dessous afin de rentrer dans Cassandra.

      /usr/lib/loginsight/application/lib/apache-cassandra-*/bin/cqlsh -u cassandra -p YourPassword
      
      Il ne reste plus qu’à faire un reset du password 😉

      Entrer la commande ci-dessous afin de faire le reset du password du compte cassandra.

      ALTER USER cassandra WITH PASSWORD 'NewPassword';
      
      Taper exit puis valider.

      Quelques liens utiles :

      Post to Twitter

      VM avec deux Datastores appartenant à deux Clusters de Datastores différents

      Lors d’un dernier check de routine avant une decomm de Datastore nous avons eu l’agréable surprise  de tomber sur une VM qui avait deux Datastores qui eux-mêmes appartenaient à deux clusters de Datastore différents (jusqu’a là pourquoi pas… mais vu que la dite VM n’avait rien à faire là, nous avons voulu en savoir plus.)

      Là où c’est rigolo c’est que le premier Datastore est complètement vide et que le deuxième Datastore contient bien tous les fichiers de notre VM 🙂

      On s’aperçoit aussi que toute modification de la VM est impossible (ce qui nous étonne qu’à moitié) et que notre VM a une ISO attachée (ça donne une bonne piste vous l’aurez compris.)

      En googlelant nous sommes tombés sur la KB2105343  qui explique en détail comment procéder pour supprimer le Datastore “intrus”.

      1. Vérifier l’emplacement du fichier vmx de la vm
      2. Faire un “Power Off” de la vm
      3. Faire un “Remove from Inventory” de la vm
      4. Inventorier la vm dans le vCenter
      5. Faire un clique droit sur la vm, Edit Setting, dans “CD/DVD drive 1*” choisir “Client Drive” puis cliquer sur le bouton “OK”
      6. Vous pouvez “Power On” la VM si vous le souhaitez
      Nous avons désormais un seul Datastore et on va pouvoir décommissionner notre Datastore vide 🙂

      Post to Twitter

      Error : A specified parameter was not correct……

      Lors d’un Storage vMotion en masse nous avons rencontré sur certaines VMs l’erreur ci-dessous.

      A specified parameter was not correct: ConfigSpec.files.vmPathName

      En regardant de plus près même la suppression d’une des VMs en question n’était pas possible non plus (au préalable on a bien vérifié qu’on avait un backup récent 🙂 ).

      Afin de pouvoir terminer notre Storage vMotion nous avons dû faire un “Remove from Inventory”sur les VMs qui posaient problème puis les inventorier dans le vCenter (6.7.0.48000)

      Ci-dessous la commande pour afficher les VMs d’un vCenter avec leurs clusters, dossiers et le chemin du vmx.

      Get-VM | Select Name, @{N="Cluster";E={Get-Cluster -VM $_}}, @{N="vmx Path";E={$_.ExtensionData.Config.Files.VmPathName}},@{N="VM Folder";E={$_.folder}}

      Ci-dessous un exemple de commande pour inventorier une VM qui causait problème.

      New-VM -VMFilePath "[datastore0] FolderVm/MyVM1.vmx" -VMHost (Get-Cluster "MyCluster" | Get-VMHost | Get-Random) -Location (Get-Folder MyFolder) -RunAsync

      Comme vous savez faire vos boucles, il vous reste plus qu’à….. 😉

      Post to Twitter

      PuTTY…..à la recherche du port disponible

      Avec un titre comme ça il faut qu’on vous plante le décor au préalable ; nous avons un cluster de deux hosts dont un est en maintenance, les deux serveurs d’admin (RDSH)  qui sont hébergés sur l’autre host commence à être chargés, sur un de nos serveur d’administration nous avions déjà une session en mode déconnecté depuis une vingtaine heures environ. La reconnection à notre session s’est faite sans problème (une chance car l’autre serveur refuse toute connexion) cependant lorsque nous avons essayé de lancer une connection distante (SSH) via PuTTY nous avons rencontré l’erreur ci-dessous  :

      Network error : No buffer space available

      Notre premier bug PuTTY 🙂

      Dans le journal system nous  avons  trouvé l’Event ID 4227 qui visiblement a un lien direct avec notre problème.

      TCP/IP failed to establish an outgoing connection because the selected local endpoint was recently used to connect to the same remote endpoint. This error typically occurs when outgoing connections are opened and closed at a high rate, causing all available local ports to be used and forcing TCP/IP to reuse a local port for an outgoing connection.
      To minimize the risk of data corruption, the TCP/IP standard requires a minimum time period to elapse between successive
      connections from a given local endpoint to a given remote endpoint.

      Outre le problème rencontré avec PuTTY, nous ne pouvons plus “sortir” du serveur, que ce soit via l’accès à un partage distant, un telnet, un rdp, AD etc.. etc….. . Un google plus loin nous comprenons qu’il se pourrait que notre serveur ait un problème de port dynamique (AKA “Ephemeral Port“).  Afin d’afficher la liste et l’état des connexions (ce qui nous intéresses ce sont les connexions en TIME_WAIT) sur notre serveur nous avons utilisé la cmdlet “Get-NetTCPConnection” comme ci-dessous : 

      Get-NetTCPConnection -state timewait
      

      Nous avons constaté un nombre conséquent (environ 200) de connexions en TIME_WAIT (malheureusement nous n’avons pas eu le temps de faire un screenshot, juste le temps de noter les PID coupables, et comme c’est de la prod on ne kill pas les PID sans savoir), on comprend mieux pourquoi PuTTY ne trouve pas un port dynamique de libre. Afin de connaître la plage des ports dynamiques il faut lancer la commande ci-dessous :

      netsh int ipv4 show dynamicport tcp
      
      Notre server a une une plage par défaut pour un Windows 2019

      La solution de facilité serait de rebooter le serveur (mais nous avons toujours des utilisateurs connectés sur le serveur), nous optons pour agrandir la plage des ports dynamiques (sans redémarrer le serveur) . Afin d’agrandir la plage des ports dynamiques et réduire le temps de libération d’un port qui passe en TIME_WAIT de quatre minutes (valeur par défaut) à 30 secondes nous avons passé les clés de registre ci-dessous (qu’on expliquera plus bas) via une console PowerShell.

      Get-Item 'HKLM:\System\CurrentControlSet\Services\Tcpip\Parameters' | New-ItemProperty -Name MaxUserPort -Value 65534 -Force | Out-Null
      
      Get-Item 'HKLM:\System\CurrentControlSet\Services\Tcpip\Parameters' | New-ItemProperty -Name TcpTimedWaitDelay -Value 30 -Force | Out-Null
      
      Get-Item 'HKLM:\System\CurrentControlSet\Services\Tcpip\Parameters' | New-ItemProperty -Name TcpNumConnections -Value 16777214 -Force | Out-Null
      

      Nous relançons un “netsh int ipv4 show dynamicport tcp” afin de vérifier que la plage des ports dynamique a bien été agrandie.

      Notre plage est désormais agrandie

      On teste si PuTTY se lance bien avec la plage des ports dynamiques agrandie.

      Nickel (ça passe sans reboot)

      Quelques explications sur les trois clés passées plus haut.

      1. MaxUserPort : Permet de fixer la plage des ports dynamiques, par défaut la plage sur Windows 2019 commence à 49152 et se termine à 65535
      2. TcpTimedWaitDelay : détermine la durée pendant laquelle une connexion TCP reste dans l’état TIME_WAIT (ou 2MSL) lorsqu’elle est fermée. La valeur par défaut d’un TIME_WAIT est de 240 secondes (4 mn) soit 120 secondes pour MSL qu’on double pour avoir deux MSL (2MSL).
      3. TcpNumConnections : nombre de connexions TCP ouvertes simultanées

        Un peu de littérature  autour des ports dynamiques :

        On s’égare, mais le titre du post était en rapport avec ça 🙂

        Post to Twitter