Aller au contenu principal

Le Langage HCL

Dans le vaste univers des outils DevOps dédiés à l'automatisation et à la gestion de l'infrastructure, il est courant de croiser des langages tels que JSON ou YAML. Cependant, la société HashCorp a fait le choix de proposer son propre langage : le HCL pour HashiCorp Configuration Language. On le retrouve ainsi sur les outils tels que Terraform, Packer, Consul et Vault.

La syntaxe HCL est inspirée de libucl, de la configuration nginx et d'autres.

Cette documentation porte sur la version 2 de ce langage.

Les bases du HCL

L'un des principaux atouts du HCL réside dans sa syntaxe simple et lisible. Contrairement à certains langages de configuration plus verbeux, le HCL utilise une approche minimaliste qui le rend accessible aux développeurs, aux administrateurs système et à toute personne impliquée dans la gestion de l'infrastructure.

Voici un exemple de configuration HCL pour illustrer sa simplicité :

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  tags = {
    Name = "ExampleInstance"
  }
}

Cette configuration déclare une instance EC2 sur Amazon Web Services (AWS). La syntaxe est claire et compréhensible, ce qui facilite la définition d'infrastructures complexes en toute simplicité.

Commentaires

Les commentaires sont également pris en charge en HCL pour documenter votre code. Vous pouvez ajouter des commentaires en utilisant le symbole #. Les commentaires sont utiles pour expliquer la logique de votre configuration et pour rendre le code plus compréhensible pour d'autres collaborateurs.

Exemple de commentaires en HCL :

server "web" {
  # Configuration du serveur web ici
  # Cet attribut spécifie l'adresse IP du serveur
  ip_address = "192.168.1.10"
}

Sections, Blocs et Attributs

Le HCL repose sur un modèle de configuration basé sur des sections, des blocs et des attributs. Cette structure hiérarchique facilite la définition des composants de votre configuration.

Sections

Une configuration HCL est généralement organisée en sections. Chaque section est délimitée par des accolades {} et peut contenir un ou plusieurs blocs de configuration. Par exemple, une section pourrait être dédiée à la configuration d'une infrastructure réseau, tandis qu'une autre pourrait être utilisée pour définir des instances de serveurs.

Exemple de section en HCL :

network {
  # Configuration du réseau ici
}

servers {
  # Configuration des serveurs ici
}

Blocs

À l'intérieur des sections, vous pouvez définir des blocs de configuration. Les blocs sont utilisés pour regrouper des attributs associés à un composant spécifique. Par exemple, dans la section "servers", vous pouvez avoir plusieurs blocs pour décrire différents serveurs.

Exemple de bloc en HCL :

server "web" {
  # Configuration du serveur web ici
}

server "database" {
  # Configuration du serveur de base de données ici
}

Attributs

Les attributs sont les éléments de données qui définissent les caractéristiques et les paramètres d'un composant. Ils sont généralement associés à un bloc de configuration. Par exemple, dans le bloc "server web", vous pouvez définir des attributs tels que l'adresse IP, le type de serveur, ou d'autres paramètres spécifiques.

Exemple d'attributs en HCL :

server "web" {
  ip_address = "192.168.1.10"
  instance_type = "t2.micro"
  # Autres attributs ici
}

Types de Données en HCL

Le HCL (HashiCorp Configuration Language) prend en charge différents types de données pour permettre la définition de configurations.

Types de Données Simples

Chaînes de Caractères (Strings)

Les chaînes de caractères sont utilisées pour représenter du texte. Elles sont définies en entourant le texte de guillemets doubles ou simples.

Exemple :

nom = "John Doe"
Nombres (Numbers)

Les nombres sont utilisés pour représenter des valeurs numériques, qu'elles soient entières ou à virgule flottante.

Exemples :

age = 30
prix = 19.99
Booléens (Booleans)

Les booléens représentent des valeurs de vérité, soit vrai (true) ou faux (false).

Exemple :

actif = true

Types de Données Complexes

Listes (Tuples)

Les listes sont utilisées pour stocker une collection ordonnée d'éléments. Chaque élément de la liste peut avoir un type de données différent.

Exemple :

couleurs = ["rouge", "vert", "bleu"]
Maps (Dictionnaires)

Les maps (ou dictionnaires) permettent d'associer des paires clé-valeur. Ils sont particulièrement utiles pour représenter des ensembles de paramètres.

Exemple :

utilisateur {
  nom = "Alice"
  âge = 25
}

Objets (Objects)

Avec le HCL il est possible de manipuler des objets afvec la syntaxe suivante :

<type> <variable/object name> {...}

Exemple :

provider "aws" {
       description = "AWS server"
}

Conversion de Types

En HCL, il est souvent nécessaire de convertir des types de données d'un format à un autre, par exemple, de chaînes de caractères à des nombres. Vous pouvez utiliser des fonctions de conversion pour effectuer ces opérations lorsque nécessaire.

nombre_texte = "42"
nombre = tonumber(nombre_texte)

Utilisation de Variables en HCL

Les variables en HCL sont utilisées pour stocker des valeurs réutilisables dans vos configurations. Elles offrent plusieurs avantages, notamment :

  • Réutilisabilité : Vous pouvez définir une variable une fois et l'utiliser à plusieurs endroits de votre configuration.
  • Maintenabilité : Les variables rendent votre code plus lisible et facilitent les mises à jour globales.
  • Dynamisme : Vous pouvez modifier la valeur d'une variable en fonction de diverses conditions ou entrées.

Déclaration de Variables

Pour déclarer une variable en HCL, utilisez la syntaxe suivante :

variable "nom_de_variable" {
  type    = type_de_variable
  default = valeur_par_défaut
}

Exemple :

variable "adresse_ip" {
  type    = string
  default = "192.168.1.10"
}

Utilisation de Variables

Une fois que vous avez défini une variable, vous pouvez l'utiliser dans votre configuration en référençant son nom. Par exemple, pour utiliser la variable "adresse_ip" définie précédemment :

serveur "web" {
  adresse_ip = var.adresse_ip
}

Utilisation d'Expressions en HCL

Les expressions en HCL permettent d'effectuer des calculs, des opérations conditionnelles et d'autres transformations de données au sein de vos configurations. Elles sont utiles pour créer des configurations dynamiques.

Syntaxe des Expressions

Les expressions en HCL sont délimitées par des ${} et peuvent contenir du code HCL. Vous pouvez y référencer des variables, des attributs et d'autres données.

Exemple d'expression en HCL :

message = "Bonjour, ${var.nom_utilisateur} !"

Expressions Conditionnelles

Vous pouvez utiliser des expressions conditionnelles pour déterminer la valeur d'un attribut en fonction de conditions spécifiques. Par exemple, pour définir un attribut en fonction de la valeur d'une variable :

taille_instance = var.environnement == "production" ? "t2.large" : "t2.micro"
Exemples concrets

Pour illustrer l'utilisation de variables et d'expressions en HCL, voici un exemple concret :

variable "environnement" {
  type    = string
  default = "développement"
}

variable "nom_utilisateur" {
  type    = string
  default = "John"
}

serveur "web" {
  adresse_ip = var.environnement == "production" ? "192.168.1.20" : "192.168.1.10"
  message    = "Bonjour, ${var.nom_utilisateur} !"
}

Dans cet exemple, nous utilisons des variables pour définir la configuration d'un serveur web en fonction de l'environnement et du nom d'utilisateur, en utilisant des expressions conditionnelles pour déterminer l'adresse IP et le message appropriés.

Les opérateurs

Opérateurs de comparaison

Les opérateurs de comparaison produisent toujours des valeurs booléennes, suite au test de la relation entre deux valeurs.

Les deux opérateurs d'égalité s'appliquent aux valeurs de tout type :

a == b  equal
a != b  not equal

Deux valeurs sont égales si elles sont de types identiques et que leurs valeurs sont égales.

Les quatre opérateurs de comparaison numérique s'appliquent uniquement aux nombres :

a < b   less than
a <= b  less than or equal to
a > b   greater than
a >= b  greater than or equal to

Si l'une des opérandes d'un opérateur de comparaison est une valeur inconnue correctement typée ou une valeur du pseudo-type dynamique, le résultat est un booléen inconnu.

Opérateurs arithmétiques

Les opérateurs arithmétiques s'appliquent uniquement aux valeurs numériques et produisent toujours des valeurs numériques comme résultats.

a + b   sum        (addition)
a - b   difference (subtraction)
a * b   product    (multiplication)
a / b   quotient   (division)
a % b   remainder  (modulo)
-a      negation

Les opérations arithmétiques sont considérées comme étant effectuées dans un espace numérique de précision arbitraire.

Si l'un des opérandes d'un opérateur arithmétique est un nombre inconnu ou une valeur du pseudo-type dynamique, le résultat est un nombre inconnu.

Opérateurs logiques

Les opérateurs logiques s'appliquent uniquement aux valeurs booléennes et produisent toujours des valeurs booléennes comme résultats.

a && b   logical AND
a || b   logical OR
!a       logical NOT

Si l'un des opérandes d'un opérateur logique est une valeur booléenne inconnue ou une valeur du pseudo-type dynamique, le résultat est une valeur booléenne inconnue.

Opérateur conditionnel

L'opérateur conditionnel permet de sélectionner l'une des deux expressions en fonction du résultat d'une expression booléenne.

Conditional = Expression "?" Expression ":" Expression;

La première expression est le prédicat, qui est évalué et doit produire un résultat booléen. Si la valeur du prédicat est true, le résultat de la deuxième expression est le résultat du conditionnel. Si la valeur du prédicat est false, le résultat de la troisième expression est le résultat du conditionnel.

Les appels de fonctions

Le HCL comprend un certain nombre de fonctions intégrées que vous pouvez appeler à partir d'expressions pour transformer et combiner des valeurs. La syntaxe générale des appels de fonction est un nom de fonction suivi d'arguments séparés par des virgules entre parenthèses :

max(5, 12, 9)

Une liste non exhaustive des fonctions disponibles :

  • abs(number) : renvoie la valeur absolue (positive) du nombre donné.
  • coalesce(vals...) : renvoie la valeur du premier argument qui n'est pas nulle. Utile uniquement dans les formats où des valeurs nulles peuvent apparaître.
  • compact(vals...) : renvoie un nouveau tuple avec les valeurs non nulles données en arguments, en préservant l'ordre.
  • concat(seqs...) : construit une valeur de tuple en concaténant ensemble tous les arguments de la séquence donnée (liste ou tuple).
  • format(fmt, args...)printf : effectue un formatage de chaîne simple similaire à la fonction de la bibliothèque C.
  • hasindex(coll, idx) : renvoie vrai si la collection donnée à l'index donné. coll peut être de type liste, tuple, carte ou objet.
  • int(number) : renvoie la composante entière du nombre donné.
  • jsondecode(str) : interprète la chaîne donnée au format JSON et renvoie la valeur décodée correspondante.
  • jsonencode(val) : encode la valeur donnée sous forme de chaîne JSON.
  • length(coll) : renvoie la longueur de la collection donnée.
  • lower(str) : convertit les lettres de la chaîne donnée en minuscules, en utilisant les règles de pliage de casse Unicode.
  • max(numbers...) : renvoie la plus élevée des valeurs numériques données.
  • min(numbers...) : renvoie la plus petite des valeurs numériques données.
  • sethas(set, val) : renvoie vrai uniquement si l'ensemble donné a la valeur donnée comme élément.
  • setintersection(sets...) : renvoie l'intersection des ensembles donnés
  • setsubtract(set1, set2) : renvoie un ensemble avec les éléments set1qui ne sont pas également dans set2.
  • setsymdiff(sets...) : renvoie la différence symétrique des ensembles donnés.
  • setunion(sets...) : renvoie l'union des ensembles donnés.
  • strlen(str) : renvoie la longueur de la chaîne donnée dans les clusters de graphèmes Unicode.
  • substr(str, offset, length) : renvoie une sous-chaîne de la chaîne donnée en la divisant entre des clusters de graphèmes Unicode.
  • timeadd(time, duration) : prend un horodatage au format RFC3339 et une durée éventuellement négative donnée sous forme de chaîne comme "1h"(pour « une heure ») et renvoie un nouvel horodatage RFC3339 après avoir ajouté la durée à l'horodatage donné.
  • upper(str) : convertit les lettres de la chaîne donnée en majuscules, en utilisant les règles de pliage de casse Unicode.

La liste des fonctions utilisées dans Terraform.

Reste A documenter

For, Splat, Index, GetAttr, Template

Conclusion

Vous l'aurez compris, Le HCL se distingue par rapport au YAML, par sa syntaxe simple et lisible, qui permet de définir des configurations de manière claire et concise. Il offre une structure modulaire, des types de données flexibles, des variables et des expressions, ainsi que la possibilité d'importer des modules, autant d'éléments qui facilitent la création, la gestion et l'automatisation de l'infrastructure.

Plus d'infos