Le blog technique

Toutes les astuces #tech des collaborateurs de PI Services.

#openblogPI

Retrouvez les articles à la une

htop : Le tableau de bord ultime pour votre terminal

Si vous avez déjà ouvert le « Gestionnaire des tâches » sur Windows ou le « Moniteur d’activité » sur Mac, vous savez à quel point il est utile de voir ce qui fait ramer votre machine. Sous Linux (et macOS), il existe un outil en ligne de commande qui fait la même chose, mais avec beaucoup plus de style et d’efficacité : htop.

C’est quoi, htop ?

htop est un moniteur système interactif. C’est une version améliorée, plus colorée et plus conviviale de la vénérable commande top. Là où top peut paraître austère et rigide, htop vous permet de naviguer à la souris ou au clavier, de tuer des processus en un clic et de visualiser la charge de vos processeurs en temps réel.


Comment lire l’interface ?

L’écran se divise généralement en trois zones principales :

  1. L’en-tête (en haut à gauche) : Affiche la charge de chaque cœur de votre CPU, l’utilisation de la mémoire vive (RAM) et du SWAP.
    • Astuce : Si les barres sont rouges, votre processeur transpire !
  2. Les statistiques (en haut à droite) : Affiche le « Load Average » (la charge moyenne), le nombre de tâches en cours et l’ « Uptime » (depuis combien de temps votre machine est allumée).
  3. La table des processus (en bas) : C’est la liste de tout ce qui tourne sur votre ordinateur. Vous y voyez qui consomme quoi (CPU%, MEM%).

Les commandes essentielles à connaître

  • F2 (Setup) : Pour personnaliser l’affichage (changer les couleurs, ajouter des graphiques).
  • F3 (Search) : Pour trouver un programme spécifique par son nom.
  • F4 (Filter) : Très pratique pour ne voir que les processus liés à un mot-clé (ex: « python » ou « chrome »).
  • F5 (Tree) : Affiche la hiérarchie des processus (qui a lancé quoi).
  • F9 (Kill) : L’arme ultime pour arrêter un programme qui ne répond plus.

Pourquoi vous devriez l’utiliser ?

Que vous soyez un développeur curieux ou un simple utilisateur de Linux, htop est le meilleur moyen de comprendre comment votre machine respire. C’est léger, ça ne nécessite pas d’interface graphique lourde, et avouons-le : ça donne l’air d’un vrai pro du code quand quelqu’un passe derrière votre épaule.

Installation rapide :

  • Sur Ubuntu/Debian : sudo apt install htop
  • Sur macOS : brew install htop

Simplifier l’injection des paramètres dynamiques dans Azure Machine Configuration avec Terraform

Dans notre précédent article, nous avons vu comment Azure Machine Configuration permettait d’injecter dynamiquement des paramètres dans des configurations DSC génériques.
La mécanique fonctionne, mais personne n’utilise de template ARM pour gérer ses déploiements au quotidien!
Heureusement, la ressource azurerm_policy_virtual_machine_configuration_assignment du provider AzureRM de Terraform supporte également l’injection des paramètres via un ou plusieurs attributs « parameter » dans le bloc « configuration » :

resource "azurerm_policy_virtual_machine_configuration_assignment" "iis_config" {
  name               = "IIS_Standard"
  location           = azurerm_resource_group.rg.location
  virtual_machine_id = azurerm_windows_virtual_machine.web_server.id

  configuration {
    assignment_type = "ApplyAndAutoCorrect"
    version         = "1.0"
    content_uri     = "https://mystorage.blob.core.windows.net/configs/IIS.zip"
    content_hash    = "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1V2W3X4Y5Z6A7B8C9D0E1F2"

    parameter {
      name  = "[WebSite]MyCompanySite;PhysicalPath"
      value = "D:\\ProductionWeb\\MySite"
    }

    parameter {
      name  = "[WebSite]MyCompanySite;State"
      value = "Started"
    }

  parameter {
      name  = "[WindowsFeature]AspNet45;Ensure"
      value = "Present"
    }
  }
}

Le problème? Même si ce code est plus lisible qu’un template ARM en JSON, il souffre du même défaut structurel : la syntaxe name/value pour l’injection des paramètres est strictement la même, toujours aussi verbeuse et répétitive.
Le code n’en est pas moins fonctionnel, mais sa lisibilité devient douteuse lorsqu’il s’agit de configurer des déploiements complexes avec des dizaines de pramètres !

Mais contrairement à ARM, Terraform dispose d’une solution évidente pour améliorer la situation : les modules, qui permettent de simplifier la manipulation de structures complexes et répétitives. Mon objectif devient alors évident : créer un module qui permet la saisie de paramètres en suivant la syntaxe naturelle d’un script DSC, et laisser Terraform faire le travail de formatage complexe en coulisses.

Un exemple valant mieux qu’un long discours, voici la syntaxe souhaitée :

parameters = {
  "[WebSite]MyCompanySite" = {
     PhysicalPath = "D:\\ProductionWeb\\MySite"
     State        = "Started"
  }
}

Voilà qui est bien plus simple, lisible et proche de la syntaxe DSC d’origine!

Pour que les informations contenues dans cette structure (techniquement un dictionnaire de dictionnaires, ou map(map(string)) soit compréhensible par la ressource azurerm_policy_virtual_machine_configuration_assignment, notre module doit la transformer. Terraform propose pour cela des outils de manipulation de données très puissants : les boucles for imbriquées et la fonction flatten.

Voici le cœur du moteur de notre module (dans le fichier main.tf) :

resource "azurerm_policy_virtual_machine_configuration_assignment" "this" {
  for_each = local.guest_configurations_map

  name               = each.key
  location           = var.location
  virtual_machine_id = var.virtual_machine_id

  configuration {
    assignment_type = var.assignment_type
    version         = var.configuration_version
    content_uri     = each.value.content_uri
    content_hash    = each.value.content_hash

    dynamic "parameter" {
      for_each = flatten([
        for param_name, param_values in each.value.parameters : [
          for key, value in param_values : {
            name  = "${param_name};${key}"
            value = value
          }
        ]
      ])
      content {
        name  = parameter.value.name
        value = parameter.value.value
      }
    }
  }
}

Que se passe-t-il exactement ?

Terraform parcourt notre dictionnaire principal parameters (for param_name, param_values…).

Pour chaque ressource DSC trouvée (ex: [WebSite]MyCompanySite), il parcourt ses propriétés (for key, value…).

Il concatène dynamiquement la clé principale, un point-virgule et la sous-clé : name = « ${param_name};${key} ».

La fonction flatten « écrase » ces listes imbriquées pour en faire une liste simple à un seul niveau, qui va ensuite être parcourue de facon classique par le for_each du bloc dynamic et transformé en autant de blocs « parameter » que nécessaire.

Maintenant que notre module est prêt, son appel depuis notre code principal devient un jeu d’enfant. Non seulement nous pouvons gérer facilement les paramètres complexes, mais nous pouvons également assigner plusieurs packages DSC à la même machine virtuelle en une seule fois :

module "machine_configuration" {
  source  = "github.com/Cyr-Az/terraform-azurerm-cyraz-machine-configuration"
  # version = "x.x.x"

  virtual_machine_id = azurerm_windows_virtual_machine.example.id
  location           = azurerm_resource_group.example.location

  guest_configurations =[
    {
      name         = "IIS_Standard"
      content_uri  = "https://mystorage.blob.core.windows.net/configs/IIS_Standard.zip"
      content_hash = "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1V2W3X4Y5Z6A7B8C9D0E1F2"
      
      parameters = {
        "[WebSite]MyCompanySite" = {
          PhysicalPath = "D:\\ProductionWeb\\MySite"
          State        = "Started"
        }
        "[WindowsFeature]AspNet45" = {
          Ensure = "Present"
        }
      }
    },
    {
      name         = "Other_Config"
      content_uri  ="https://mystorage.blob.core.windows.net/configs/Other_Config.zip"
      content_hash = "B2C3D4E5..."

      parameters = {
        "[SomeResource]Name" = {
          Parameter = "Value"
        }
      }
    }
  ]
}

Vous pouvez retrouver ce module complet avec un example plus détaillé sur mon Github : Cyr-Az/terraform-azurerm-cyraz-machine-configuration: Terraform module to simplify Machine Configuration assignments with custom parameters

Azure – Utiliser des packages DSC génériques dans Machine Configuration

Le service Azure Machine Configuration (anciennement connu sous le nom de Guest Configuration) est une fonctionnalité qui parait encore méconnue ou boudée au profit d’autres mécanismes comme Ansible. Elle est pourtant la digne descendante du vénérable  PowerShell DSC (Desired State Configuration). et de ses implémentations Azure (extension DSC et Azure Automation DSC, dont la dépréciation a été annoncée pour 2027) : elle permet d’auditer et de configurer l’intérieur de vos machines virtuelles (paramètres de l’OS, registres, applications) à l’aide de packages constitués de modules et de configurations DSC classiques accessibles en HTTPS (souvent via un storage account).

A la différence des méthodes précédentes, Machine Configuration n’utilise pas le Local Configuration Manager (LCM) natif de Windows mais plutôt une extension Azure dédiée qui se charge de la récupération des packages, de l’application des configurations qu’ils contiennent et de la remontée des informations d’audit. Machine Configuration permet également d’appliquer plusieurs configurations (assignments) à une machine, alors que les méthodes traditionnelles ne pouvaient prendre en compte qu’une seule.

Un défaut historique de DSC réside dans ses configurations qui sont des fichiers .mof statiques, obtenus après « compilation » d’un script Powershell DSC. Il était donc nécessaire de créer un fichier .mof pour chaque serveur, au lieu de pouvoir simplement utiliser une configuration générique et lui passer les paramètres propres à chaque serveur.

Mais réjouissez-vous : c’est de l’histoire ancienne! Même si Machine Configuration repose toujours sur des packages contenant des .mof compilés et donc des valeurs statiques, il introduit la possibilité de les modifier directement via la propriété configurationParameter de la ressource guestConfigurationAssignments. Autrement dit, il est possible de créer des .mof contenant les ressources nécessaires à la configuration d’un role sur vos serveurs (par exemple IIS) avec une série de paramètres standardisés, mais avec des valeurs fictives; puis de modifier ces valeurs à la volée dans vos templates ARM en fonction du serveur auxquels vous appliquez les guestConfigurationAssignments!

Concrètement, comment cela fonctionne-t-il ? Lors de l’assignation de la configuration via l’API Azure (par exemple lors du déploiement de votre template ARM), le service transmet vos paramètres à l’agent local (l’extension Azure présente sur la VM). Ce dernier va alors lire le fichier MOF téléchargé et écraser littéralement les valeurs textuelles statiques avec celles que vous avez fournies, juste avant l’application de l’état désiré. Vous n’avez plus besoin d’exécuter la moindre commande à l’intérieur de la machine ou de regénérer un package par environnement. Un seul package IIS.zip compilé une bonne fois pour toutes suffit désormais pour tous vos serveurs !

Pour bien visualiser, voici à quoi ressemblerait le code source de cette configuration DSC générique (avant sa compilation en fichier .mof). On y installe le rôle IIS natif, et on y configure un site web basique à l’aide du module WebAdministrationDsc. Remarquez comment les valeurs utilisées sont fictives (placeholders) et n’ont pas vocation à rester telles quelles en production :

Configuration IIS {
    # Import des ressources natives et du module IIS
    Import-DscResource -ModuleName 'PSDesiredStateConfiguration'
    Import-DscResource -ModuleName 'WebAdministrationDsc'

    Node localhost {
        # 1. Installation du rôle IIS
        WindowsFeature InstallIIS {
            Ensure = "Present"
            Name   = "Web-Server"
        }

        # 2. Création et paramétrage du site web (avec des valeurs fictives)
        WebSite MyCompanySite {
            Ensure       = "Present"
            Name         = "MySite"
            State        = "Started"
            PhysicalPath = "C:\inetpub\wwwroot\dummy" # Valeur statique destinée à être écrasée
            DependsOn    = "[WindowsFeature]InstallIIS"
        }
    }
}

Pour modifier une de ces valeurs (par exemple PhysicalPath) ou même le statut du site (State) à la volée dans vos templates ARM, il faut utiliser le paramètre configurationParameter de votre ressource  Microsoft.Compute/virtualMachines/providers/guestConfigurationAssignments. Attention, la syntaxe n’est pas très intuitive : la clé name du paramètre doit cibler précisément la ressource DSC et sa propriété selon le modèle suivant : [ClasseDeLaRessource]NomDeLaRessource;NomDeLaPropriete.

En reprenant le code DSC ci-dessus (la ressource nommée MyCompanySite de classe WebSite), pour définir le véritable chemin d’accès aux fichiers du site pour un serveur spécifique de production, la définition dans le template ARM inclura ce bloc JSON :

"properties": {
  "guestConfiguration": {
    "name": "IIS",
    "assignmentType": "ApplyAndMonitor",
    "configurationParameter":[
      {
        "name": "[WebSite]MyCompanySite;PhysicalPath",
        "value": "D:\ProductionWeb\MySite"
      }
    ]
  }
}

Attention cependant : tous les paramètres passés à Machine Configuration doivent être de type string. L’API Azure ne supporte pas le passage de tableaux (arrays) via la propriété configurationParameter et ce, même si la ressource DSC sous-jacente est techniquement capable de les interpréter (comme c’est le cas avec la propriété BindingInfo du module WebAdministrationDsc par exemple).

Si ce mécanisme vous semble familier, c’est normal : c’est en effet exactement le même qui se cache derrière les « Azure Security Baselines » déployées via Azure Policy. Lorsque vous configurez une policy Azure pour imposer des paramètres d’OS à votre parc, le service se contente d’orchestrer la création de ces assignations en injectant dynamiquement vos valeurs dans les fichiers MOF pré-packagés par Microsoft.

Le même résultat est bien sûr atteignable à l’aide de Terraform, mais cela sera l’objet du prochain article!