Accueil / HPE Morpheus / HPE Morpheus Enterprise : automatiser l’exploitation Linux avec les Operational Workflows

HPE Morpheus Enterprise : automatiser l’exploitation Linux avec les Operational Workflows

Après avoir automatisé le provisioning d’une VM Ubuntu 24.04 sur HVM, l’étape suivante consiste à automatiser les opérations courantes après le déploiement. HPE Morpheus Enterprise permet de le faire proprement avec les Operational Workflows, les Tasks, les Script Templates et les Inputs.

Dans cet article, je mets en place trois cas d’usage très concrets sur une instance Linux déjà provisionnée :

  • créer un compte administrateur local ;
  • réinitialiser le mot de passe d’un compte existant ;
  • lancer un diagnostic Linux synthétique directement depuis Morpheus.

L’objectif n’est pas seulement d’exécuter quelques commandes Bash. L’intérêt est de transformer des opérations d’administration en actions réutilisables, paramétrables et accessibles depuis l’interface Morpheus sans ouvrir une session SSH manuelle sur la machine.

Architecture de l’automatisation

Pour ces trois cas d’usage, j’utilise toujours la même chaîne :

Inputs
   ↓
Operational Workflow
   ↓
Library Script Task
   ↓
Script Template Bash
   ↓
Instance Linux cible

Les menus utilisés sont les suivants :

  • Library → Options → Inputs : création des paramètres saisis par l’opérateur ;
  • Library → Templates → Script Templates : stockage des scripts Bash réutilisables ;
  • Library → Automation → Tasks : création d’une Task de type Library Script ;
  • Library → Automation → Workflows : assemblage de la Task et des Inputs dans un Operational Workflow ;
  • Instance → Actions → Run Workflow : exécution sur une VM déjà déployée.

HPE documente bien ce modèle : un Script Template peut être utilisé dans une Library Script Task, et un Operational Workflow peut être exécuté sur une instance existante.

Point important : les Inputs sont sensibles à la casse

C’est le détail qui m’a fait perdre le plus de temps pendant les tests.

Dans Morpheus, la valeur utilisée dans le script doit correspondre exactement au Field Name de l’Input. La casse compte.

Par exemple, si l’Input possède :

Field Name : LocalUsername

le Script Template doit utiliser :

USERNAME="<%= customOptions.LocalUsername %>"

et non :

USERNAME="<%= customOptions.localUsername %>"

Avec une casse incorrecte, la variable est résolue à null. Dans mon premier test, le workflow a donc réellement créé un utilisateur nommé null. Depuis, tous mes scripts commencent par vérifier explicitement que les variables reçues ne sont ni vides ni égales à null.

Cas d’usage 1 — Créer un administrateur Linux local

Créer les Inputs

Dans Library → Options → Inputs, je crée deux Inputs :

Name       : Local Username
Field Name : LocalUsername
Type       : Text
Required   : Yes

Name       : Local Password
Field Name : LocalPassword
Type       : Password
Required   : Yes

Le type Password permet de masquer la saisie dans le formulaire Morpheus. Le script ne doit évidemment jamais afficher cette valeur dans les logs.

Créer le Script Template

Dans Library → Templates → Script Templates → + Add :

Name        : Create Linux Local Admin
Script Type : Bash
Phase       : Reconfigure
Sudo        : Yes

Le script est volontairement idempotent sur la création de l’utilisateur : si le compte existe déjà, il n’est pas recréé. Le mot de passe est en revanche réappliqué.

#!/bin/bash

set -euo pipefail

USERNAME="<%= customOptions.LocalUsername %>"
PASSWORD="<%= customOptions.LocalPassword %>"

echo "=== Configuration du compte local ==="

if [[ -z "${USERNAME}" || "${USERNAME}" == "null" ]]; then
    echo "ERROR: LocalUsername absent ou non transmis par Morpheus."
    exit 1
fi

if [[ -z "${PASSWORD}" || "${PASSWORD}" == "null" ]]; then
    echo "ERROR: LocalPassword absent ou non transmis par Morpheus."
    exit 1
fi

echo "Utilisateur demandé : ${USERNAME}"

if id "${USERNAME}" >/dev/null 2>&1; then
    echo "L'utilisateur ${USERNAME} existe déjà."
else
    useradd \
        --create-home \
        --shell /bin/bash \
        "${USERNAME}"

    echo "Utilisateur ${USERNAME} créé."
fi

echo "${USERNAME}:${PASSWORD}" | chpasswd
usermod -aG sudo "${USERNAME}"

echo "Mot de passe configuré."
echo "Droits sudo configurés."

echo
echo "=== Vérification ==="
id "${USERNAME}"

echo
echo "Compte ${USERNAME} configuré avec succès."

Créer la Task

Dans Library → Automation → Tasks → + Add, je crée une Task de type Library Script et je sélectionne le Script Template précédent.

Name           : Create Linux Local Admin
Type           : Library Script
Library Script : Create Linux Local Admin
Execute Target : Resource

Créer l’Operational Workflow

Dans Library → Automation → Workflows → + Add → Operational Workflow, j’ajoute :

Workflow : Create Linux Local Admin

Inputs :
- LocalUsername
- LocalPassword

Task :
- Create Linux Local Admin

Depuis une instance existante, Actions → Run Workflow affiche alors un petit formulaire demandant le nom du compte et son mot de passe.

Le résultat attendu ressemble à ceci :

=== Configuration du compte local ===
Utilisateur demandé : ops-admin
Utilisateur ops-admin créé.
Mot de passe configuré.
Droits sudo configurés.

=== Vérification ===
uid=1002(ops-admin) gid=1002(ops-admin) groups=1002(ops-admin),27(sudo)

Compte ops-admin configuré avec succès.

Cas d’usage 2 — Réinitialiser un mot de passe local

Le second workflow reprend exactement la même mécanique. L’Input LocalUsername existe déjà : il est donc réutilisé. Il suffit d’ajouter un nouvel Input de type Password.

Name       : New Password
Field Name : NewPassword
Type       : Password
Required   : Yes

Le Script Template peut rester très court :

#!/bin/bash

set -euo pipefail

USERNAME="<%= customOptions.LocalUsername %>"
PASSWORD="<%= customOptions.NewPassword %>"

echo "=== Reset du mot de passe local ==="

if [[ -z "${USERNAME}" || "${USERNAME}" == "null" ]]; then
    echo "ERROR: LocalUsername absent ou non transmis par Morpheus."
    exit 1
fi

if [[ -z "${PASSWORD}" || "${PASSWORD}" == "null" ]]; then
    echo "ERROR: NewPassword absent ou non transmis par Morpheus."
    exit 1
fi

if ! id "${USERNAME}" >/dev/null 2>&1; then
    echo "ERROR: L'utilisateur ${USERNAME} n'existe pas."
    exit 1
fi

echo "${USERNAME}:${PASSWORD}" | chpasswd

echo "Mot de passe du compte ${USERNAME} modifié avec succès."

Je crée ensuite comme précédemment :

Script Template : Reset Linux Local Password
Task            : Reset Linux Local Password
Workflow        : Reset Linux Local Password

Inputs :
- LocalUsername
- NewPassword

Ce cas d’usage est intéressant pour le support : l’opérateur peut réinitialiser un mot de passe sans ouvrir directement une session root sur la VM.

Cas d’usage 3 — Diagnostic Linux depuis Morpheus

Le troisième workflow ne modifie rien sur la machine. Il collecte quelques indicateurs utiles et affiche une synthèse directement dans l’historique d’exécution Morpheus.

Une première version très détaillée fonctionnait correctement, mais l’interface Morpheus tronquait l’aperçu avec .... Le résultat complet restait accessible via la fonction de copie du process output, mais pour un opérateur il est beaucoup plus pratique d’avoir immédiatement les informations essentielles.

J’ai donc retenu une version volontairement compacte.

#!/bin/bash

set -u

HOSTNAME_VALUE=$(hostname)
OS_NAME=$(awk -F= '/^PRETTY_NAME=/{gsub(/"/,"",$2); print $2}' /etc/os-release 2>/dev/null)
KERNEL=$(uname -r)
UPTIME_VALUE=$(uptime -p)
VCPU=$(nproc)

MEM_AVAILABLE_KB=$(awk '/MemAvailable:/ {print $2}' /proc/meminfo)
MEM_TOTAL_KB=$(awk '/MemTotal:/ {print $2}' /proc/meminfo)

MEM_AVAILABLE_GB=$(awk -v kb="${MEM_AVAILABLE_KB:-0}" \
    'BEGIN {printf "%.1f", kb/1024/1024}')

MEM_PERCENT=$(awk \
    -v available="${MEM_AVAILABLE_KB:-0}" \
    -v total="${MEM_TOTAL_KB:-1}" \
    'BEGIN {printf "%.0f", ((total-available)/total)*100}')

ROOT_USAGE=$(df -P / | awk 'NR==2 {gsub("%","",$5); print $5}')
ROOT_SIZE=$(df -hP / | awk 'NR==2 {print $2}')
ROOT_FREE=$(df -hP / | awk 'NR==2 {print $4}')

PRIMARY_IF=$(ip route | awk '/^default/ {print $5; exit}')
PRIMARY_IP=$(ip -4 -o addr show "${PRIMARY_IF}" 2>/dev/null \
    | awk '{print $4}' | cut -d/ -f1 | head -1)

DEFAULT_GW=$(ip route | awk '/^default/ {print $3; exit}')

DNS_SERVERS=$(resolvectl dns "${PRIMARY_IF}" 2>/dev/null \
    | sed 's/.*: //' || true)

FAILED_SERVICES=$(systemctl --failed --no-legend 2>/dev/null \
    | grep -c . || true)

QEMU_STATUS=$(systemctl is-active qemu-guest-agent 2>/dev/null || true)

if command -v cloud-init >/dev/null 2>&1; then
    CLOUD_STATUS=$(cloud-init status 2>/dev/null \
        | awk -F': ' '/status:/ {print $2}' || true)
else
    CLOUD_STATUS="not-installed"
fi

LOAD_AVG=$(awk '{print $1" / "$2" / "$3}' /proc/loadavg)

echo "======================================================"
echo "             MORPHEUS LINUX DIAGNOSTIC"
echo "======================================================"

printf "%-14s : %s\n" "Hostname" "${HOSTNAME_VALUE}"
printf "%-14s : %s\n" "OS" "${OS_NAME:-Unknown}"
printf "%-14s : %s\n" "Kernel" "${KERNEL}"
printf "%-14s : %s\n" "Uptime" "${UPTIME_VALUE}"
echo

printf "[OK]   %-15s %s vCPU\n" "CPU" "${VCPU}"

if (( MEM_PERCENT >= 90 )); then
    STATUS="CRIT"
elif (( MEM_PERCENT >= 80 )); then
    STATUS="WARN"
else
    STATUS="OK"
fi

printf "[%-4s] %-15s %s%% used / %s GiB available\n" \
    "${STATUS}" "Memory" "${MEM_PERCENT}" "${MEM_AVAILABLE_GB}"

if (( ROOT_USAGE >= 90 )); then
    STATUS="CRIT"
elif (( ROOT_USAGE >= 80 )); then
    STATUS="WARN"
else
    STATUS="OK"
fi

printf "[%-4s] %-15s %s%% used / %s free / %s total\n" \
    "${STATUS}" "Root FS" "${ROOT_USAGE}" "${ROOT_FREE}" "${ROOT_SIZE}"

if [[ -n "${PRIMARY_IP}" ]]; then
    printf "[OK]   %-15s %s / %s\n" "Network" "${PRIMARY_IF}" "${PRIMARY_IP}"
else
    printf "[CRIT] %-15s No IPv4 address\n" "Network"
fi

if [[ -n "${DEFAULT_GW}" ]]; then
    printf "[OK]   %-15s %s\n" "Gateway" "${DEFAULT_GW}"
else
    printf "[CRIT] %-15s Missing\n" "Gateway"
fi

if getent hosts blog.nxway.fr/ >/dev/null 2>&1; then
    printf "[OK]   %-15s %s\n" "DNS" "${DNS_SERVERS:-resolution OK}"
else
    printf "[WARN] %-15s Resolution failed\n" "DNS"
fi

if [[ "${FAILED_SERVICES}" -eq 0 ]]; then
    printf "[OK]   %-15s 0 failed\n" "Services"
else
    printf "[WARN] %-15s %s failed\n" "Services" "${FAILED_SERVICES}"
fi

if [[ "${QEMU_STATUS}" == "active" ]]; then
    printf "[OK]   %-15s active\n" "QEMU Agent"
else
    printf "[WARN] %-15s %s\n" "QEMU Agent" "${QEMU_STATUS:-inactive}"
fi

if [[ "${CLOUD_STATUS}" == "done" ]]; then
    printf "[OK]   %-15s done\n" "Cloud-Init"
else
    printf "[WARN] %-15s %s\n" "Cloud-Init" "${CLOUD_STATUS:-unknown}"
fi

printf "[OK]   %-15s %s\n" "Load Average" "${LOAD_AVG}"

echo "======================================================"

Sur une machine saine, le résultat tient en quelques lignes :

MORPHEUS LINUX DIAGNOSTIC

Hostname       : vm-linux-001
OS             : Ubuntu 24.04 LTS
Kernel         : 6.8.x-generic
Uptime         : up 18 hours

[OK]   CPU             2 vCPU
[OK]   Memory          8% used / 7.1 GiB available
[OK]   Root FS         33% used / 16G free / 24G total
[OK]   Network         eth0 / 192.0.2.20
[OK]   Gateway         192.0.2.1
[OK]   DNS             resolution functional
[OK]   Services        0 failed
[OK]   QEMU Agent      active
[OK]   Cloud-Init      done
[OK]   Load Average    0.01 / 0.01 / 0.00

Les seuils simples apportent immédiatement de la lisibilité : un filesystem à plus de 80 % passe en WARN, au-delà de 90 % en CRIT. Le même principe peut ensuite être étendu à la mémoire, aux services ou à d’autres contrôles.

Operational Workflow ou Provisioning Workflow ?

La distinction est importante :

  • un Provisioning Workflow accompagne le cycle de création d’une nouvelle ressource ;
  • un Operational Workflow est particulièrement adapté aux actions réalisées sur une ressource déjà existante.

Pour mes trois exemples, l’Operational Workflow est donc le bon choix : créer un compte après déploiement, réinitialiser un mot de passe ou lancer un diagnostic sont des opérations d’exploitation.

Pourquoi ce modèle est intéressant

Au-delà des trois scripts présentés ici, le véritable intérêt est de construire progressivement une bibliothèque d’opérations standardisées.

On peut imaginer exactement le même mécanisme pour installer un agent de sécurité, relancer un service, étendre un filesystem LVM, poser une clé SSH, appliquer une configuration, vérifier une connectivité réseau ou déclencher une action de maintenance applicative.

Le modèle devient alors :

L'opérateur choisit une action
            ↓
Morpheus affiche uniquement les Inputs nécessaires
            ↓
Le Workflow appelle une Task contrôlée
            ↓
La Task exécute un Script Template versionné
            ↓
L'action est réalisée sur la ressource cible
            ↓
Le résultat reste visible dans l'historique Morpheus

C’est cette couche d’abstraction qui transforme Morpheus en véritable portail d’exploitation, et pas uniquement en outil de provisioning.

Quelques bonnes pratiques retenues

  • réutiliser les Inputs existants plutôt que les dupliquer ;
  • utiliser le type Password pour les secrets saisis par l’opérateur ;
  • ne jamais écrire les mots de passe dans les logs ;
  • tester systématiquement les variables contre une valeur vide ou null ;
  • respecter exactement la casse du Field Name dans customOptions ;
  • rendre les scripts idempotents lorsque c’est possible ;
  • privilégier une sortie courte et lisible dans Morpheus pour les workflows de diagnostic ;
  • utiliser les Script Templates pour éviter de dupliquer du code directement dans les Tasks.

Conclusion

Ces trois workflows sont simples, mais ils montrent déjà très bien ce que Morpheus peut apporter à l’exploitation quotidienne d’un environnement Linux.

La création d’un compte administrateur valide le passage d’Inputs vers un Script Template. Le reset de mot de passe montre comment réutiliser les mêmes composants. Enfin, le diagnostic Linux permet de transformer plusieurs commandes système en une action self-service immédiatement exploitable depuis l’interface.

À partir de cette base, il devient assez naturel de construire un véritable catalogue d’actions d’exploitation autour des instances HVM.

Sources HPE

Étiquetté :

Répondre

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *