Aller au contenu

Fenêtres de maintenance pour les installations

Les fenêtres de maintenance restreignent les moments où POST /install/jobs est autorisé à réellement pousser des paquets vers une machine — définies par tag d'inventaire ou en tant qu'override par machine. Une machine sans fenêtre applicable exécute les installations immédiatement, exactement comme avant l'existence de cette fonctionnalité ; ajouter une fenêtre est ce qui active la restriction.


1. Prérequis

  • Le rôle admin pour créer ou supprimer des fenêtres. Lister les fenêtres existantes ne nécessite que le rôle auditor ou supérieur.
  • Connaître le nom de fuseau horaire IANA pour la fenêtre (ex. Europe/Paris, America/New_York) — les fenêtres sont stockées en heure locale (horloge murale) plus un fuseau horaire nommé, et non un décalage UTC fixe, de sorte que le passage à l'heure d'été/hiver (DST) est géré automatiquement.
  • Décidez si vous ciblez un tag (toutes les machines qui le portent) ou une machine spécifique (un override qui remplace intégralement les fenêtres issues des tags de cette machine, sans jamais fusionner avec elles).

Ouvert par défaut

Une machine sans fenêtre de tag et sans override client exécute les jobs d'installation immédiatement, à tout moment — comportement inchangé pour les parcs qui ne configurent jamais cette fonctionnalité.


2. Vérifier les fenêtres existantes

curl -s http://repod.example.com:8000/api/v1/inventory/maintenance-windows \
  -H "Authorization: Bearer repod_xxxxxxxxxxxxxxxx" | jq .

Filtrer par principal :

curl -s "http://repod.example.com:8000/api/v1/inventory/maintenance-windows?principal_type=tag&principal_id=prod" \
  -H "Authorization: Bearer repod_xxxxxxxxxxxxxxxx" | jq .

3. Créer une fenêtre

curl -s -X POST http://repod.example.com:8000/api/v1/inventory/maintenance-windows \
  -H "Authorization: Bearer repod_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "principal_type": "tag",
    "principal_id": "prod",
    "days": ["mon", "tue", "wed", "thu", "fri"],
    "start_time": "02:00",
    "end_time": "04:00",
    "timezone": "Europe/Paris"
  }' | jq .
Champ Valeurs Signification
principal_type tag | client Indique si cette fenêtre s'applique à toutes les machines portant un tag, ou remplace celle d'une machine spécifique
principal_id chaîne Le nom du tag (ex. prod), ou l'id du client, selon principal_type
days liste de mon|tue|wed|thu|fri|sat|sun Les jours de la semaine où la fenêtre est ouverte
start_time "HH:MM" Heure de début locale
end_time "HH:MM" Heure de fin locale. Si antérieure à start_time, la fenêtre franchit minuit.
timezone nom IANA ex. Europe/Paris, UTC

Réponse (201) :

{
  "window": {
    "id": "...",
    "principal_type": "tag",
    "principal_id": "prod",
    "days": ["mon", "tue", "wed", "thu", "fri"],
    "start_time": "02:00",
    "end_time": "04:00",
    "timezone": "Europe/Paris",
    "created_by": "admin",
    "created_at": "..."
  }
}

Exemple complet — n'autoriser les installations sur les machines prod que du lundi au vendredi de 02h00 à 04h00, Europe/Paris :

Le POST ci-dessus fait exactement cela. À partir de ce moment :

  • POST /install/jobs ciblant une machine taguée prod (via target_ids ou target_tags) est accepté immédiatement si l'heure actuelle à Europe/Paris se situe dans une fenêtre correspondante ; sinon le job est créé mais son thread d'arrière-plan bloque à l'étape waiting_window jusqu'à l'ouverture de la fenêtre (ou l'annulation du job).
  • La fenêtre effective d'un job, lorsque plusieurs machines ciblées sont impliquées, est l'intersection des fenêtres de toutes les machines ciblées — les machines sans aucune fenêtre ne contraignent pas l'intersection.
  • Si l'intersection ne peut jamais être satisfaite — par exemple si deux machines ciblées ont des fenêtres sur des jours entièrement disjoints — POST /install/jobs renvoie immédiatement 409 plutôt que de mettre en file d'attente indéfiniment :
    {
      "detail": "Les fenêtres de maintenance des machines ciblées ne se chevauchent jamais — aucun créneau commun possible. Vérifiez la configuration des fenêtres (tags et/ou overrides par machine)."
    }
    

Une fenêtre client remplace les fenêtres de tag, elle ne fusionne jamais avec elles

Une fenêtre principal_type: "client" pour une machine spécifique remplace intégralement les fenêtres issues des tags de cette machine — les fenêtres de tag ne sont pas combinées avec elle. Cela reflète la même convention « override remplace, ne fusionne jamais » utilisée par machine_access (voir Restreindre l'accès aux distributions & aux machines). Pour donner à une machine prod un planning de maintenance différent du reste du parc, créez une fenêtre de type client référençant son id ; il n'est pas nécessaire de supprimer d'abord la fenêtre au niveau du tag.


4. Fenêtres franchissant minuit

Un end_time antérieur à start_time est interprété comme franchissant minuit :

curl -s -X POST http://repod.example.com:8000/api/v1/inventory/maintenance-windows \
  -H "Authorization: Bearer repod_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "principal_type": "tag",
    "principal_id": "batch-nodes",
    "days": ["sat", "sun"],
    "start_time": "23:00",
    "end_time": "01:00",
    "timezone": "UTC"
  }' | jq .

Cette fenêtre est ouverte de 23h00 le samedi à 01h00 le dimanche, puis à nouveau de 23h00 le dimanche à 01h00 le lundi.


5. Supprimer une fenêtre

curl -s -X DELETE http://repod.example.com:8000/api/v1/inventory/maintenance-windows/<window_id> \
  -H "Authorization: Bearer repod_xxxxxxxxxxxxxxxx"

Renvoie 204 en cas de succès, 404 si la fenêtre n'existe pas. Supprimer la dernière fenêtre d'un tag/d'une machine la rouvre aux installations à tout moment.


6. Vérifier que ça a fonctionné

En dehors de la fenêtre — créer un job ciblant uniquement des machines taguées prod doit soit attendre, soit, si aucune fenêtre commune n'existe du tout entre les cibles, échouer rapidement :

curl -s -X POST http://repod.example.com:8000/api/v1/install/jobs \
  -H "Authorization: Bearer repod_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "package_name": "nginx",
    "package_version": "1.24.0-1",
    "target_tags": ["prod"]
  }' | jq .

# Interroger le statut du job — attendu : step="waiting_window" en dehors de 02:00-04:00 Europe/Paris
curl -s http://repod.example.com:8000/api/v1/install/jobs/<job_id> \
  -H "Authorization: Bearer repod_xxxxxxxxxxxxxxxx" | jq '.step'

À l'intérieur de la fenêtre — la même requête doit passer directement au flux dry-run/confirmation, sans jamais signaler waiting_window.

Fenêtres disjointes entre les cibles — cibler deux machines dont les fenêtres ne se chevauchent jamais doit échouer immédiatement avec 409, sans jamais rester bloqué :

curl -s -o /dev/null -w "%{http_code}\n" -X POST http://repod.example.com:8000/api/v1/install/jobs \
  -H "Authorization: Bearer repod_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "package_name": "nginx",
    "target_ids": ["<id-machine-A-avec-fenêtre-lundi>", "<id-machine-B-avec-fenêtre-mardi-uniquement>"]
  }'
# → 409