Merge branch 'dev' into feat/deploy
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
terraform {
|
||||
required_version = ">= 1.7"
|
||||
|
||||
required_providers {
|
||||
null = {
|
||||
source = "hashicorp/null"
|
||||
version = "~> 3.2"
|
||||
}
|
||||
}
|
||||
|
||||
backend "local" {
|
||||
path = "terraform.tfstate"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/null" {
|
||||
version = "3.3.2"
|
||||
constraints = "~> 3.2"
|
||||
hashes = [
|
||||
"h1:IQ1qrkht1sC1nibUR+AJ3ulryyhVDHfCHZhoJi0sg2Y=",
|
||||
"zh:10ec43b8b7b18d5639238c7fb9e111f6a4b038523dd66c7a426bf27b25fa4c08",
|
||||
"zh:60beb9cc2ad5b871c710860cee75b42850cc6acd43db0d77cb5e00fda7288b55",
|
||||
"zh:62538582d0a4a2f10ad8a8d9a6c3cd3f05af6c6d91c6641ffc78d4f0e8e69b27",
|
||||
"zh:64a8f9ce7852d9efc5b464c12306c946366d59f5e2757def97969c9fd64bd1d6",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:92a374fb736a52f465283326d0a5bf4f495132eb99be209dfb4c75ec803fe8db",
|
||||
"zh:98da9c42785d27a50f0604758bcb61a30f6278b9f2acd92bb3b2046e0e71916c",
|
||||
"zh:b0f7896fae554729cdf4a24ac06359a050cff5817e6cd8597cba8a4ae01a7409",
|
||||
"zh:bc8179ee35d67c72fb03012e7023b9f9816f033a7ec4109c001dd6d29752e812",
|
||||
"zh:d23a598f713bfb6098bc003571d7de90b5a33b78f9be240488252fe5f3c2a60d",
|
||||
"zh:d2855b922ea345dbd89ea287e4c6c4757e38bc0aaffeb2b79aa0b8004f9c53ff",
|
||||
"zh:d3a60422bc6a2f9244d076c5222c07060c826ef91bdbaf4634cb752b86057473",
|
||||
"zh:faa01928c25d2a6ecd9c7eb8b88134cb08de55a6b11ca6c703ac0092845344ba",
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
# Pourquoi : Terraform provisionne la machine, GitHub Actions la deploie (ADR 0010). Rien ici ne
|
||||
# construit d'image ni ne lance de conteneur : la livraison reste portee par `deploy.yml` et
|
||||
# `make stack-up`, et un `apply` n'interrompt pas la stack qui tourne.
|
||||
# Piege : seul le bloc `triggers` d'un `null_resource` atterrit dans le state. Ni le jeton du
|
||||
# runner ni la cle SSH n'y figurent, et ne doivent jamais y etre ajoutes pour forcer un rejeu.
|
||||
# Contrainte : pas de provisioner `destroy` sur le runner. Il imposerait une connexion ne lisant
|
||||
# que `self`, donc le chemin de la cle SSH dans le state, et `svc.sh uninstall` ne desinscrit pas
|
||||
# le runner cote GitHub : le retrait reste manuel, depuis les parametres du depot.
|
||||
# Ref : ADR 0009 pour les deux environnements, `scripts/provision-host.sh` pour leur contenu.
|
||||
|
||||
locals {
|
||||
sudo = var.ssh_user == "root" ? "" : "sudo "
|
||||
en_tant_que = "${var.ssh_user == "root" ? "" : "sudo "}runuser -u ${var.proprietaire} --"
|
||||
provisionneur = "${path.root}/../../../../scripts/provision-host.sh"
|
||||
runner_archive = "actions-runner-linux-x64-${var.runner_version}.tar.gz"
|
||||
# Substitution shell, evaluee par le sh -c distant : un nom de runner doit etre unique dans
|
||||
# le depot, le nom d'hote l'est deja et le reste si cette racine sert a une autre machine.
|
||||
runner_nom = var.runner_nom != "" ? var.runner_nom : "$(hostname -s)"
|
||||
}
|
||||
|
||||
resource "null_resource" "docker_engine" {
|
||||
triggers = {
|
||||
hote = var.ssh_host
|
||||
user = var.proprietaire
|
||||
}
|
||||
|
||||
connection {
|
||||
type = "ssh"
|
||||
host = var.ssh_host
|
||||
port = var.ssh_port
|
||||
user = var.ssh_user
|
||||
private_key = file(pathexpand(var.ssh_private_key_path))
|
||||
timeout = "5m"
|
||||
}
|
||||
|
||||
provisioner "remote-exec" {
|
||||
inline = [
|
||||
<<-EOT
|
||||
set -eu
|
||||
id ${var.proprietaire} >/dev/null 2>&1 || {
|
||||
echo "l'utilisateur ${var.proprietaire} n'existe pas sur la machine" >&2
|
||||
exit 1
|
||||
}
|
||||
command -v docker >/dev/null || ${local.sudo}sh -c 'curl -fsSL https://get.docker.com | sh'
|
||||
${local.sudo}systemctl enable --now docker
|
||||
${local.sudo}usermod -aG docker ${var.proprietaire}
|
||||
${local.sudo}docker compose version
|
||||
EOT
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# `provision-host.sh` verifie lui-meme docker, compose et la sortie HTTPS, puis prepare un clone
|
||||
# par environnement, son `.env` et son certificat. Il est rejouable : un `.env` existant n'est
|
||||
# jamais reecrit, un certificat present jamais regenere.
|
||||
resource "null_resource" "environnements" {
|
||||
depends_on = [null_resource.docker_engine]
|
||||
|
||||
triggers = {
|
||||
script = filesha256(local.provisionneur)
|
||||
racine = var.racine
|
||||
depot = var.depot_url
|
||||
}
|
||||
|
||||
connection {
|
||||
type = "ssh"
|
||||
host = var.ssh_host
|
||||
port = var.ssh_port
|
||||
user = var.ssh_user
|
||||
private_key = file(pathexpand(var.ssh_private_key_path))
|
||||
timeout = "5m"
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
source = local.provisionneur
|
||||
destination = "/tmp/provision-host.sh"
|
||||
}
|
||||
|
||||
provisioner "remote-exec" {
|
||||
inline = [
|
||||
<<-EOT
|
||||
set -eu
|
||||
${local.sudo}env RACINE='${var.racine}' \
|
||||
REPO_URL='${var.depot_url}' \
|
||||
PROPRIETAIRE='${var.proprietaire}' \
|
||||
PUBLIC_IP='${var.adresse_publique}' \
|
||||
bash /tmp/provision-host.sh
|
||||
rm -f /tmp/provision-host.sh
|
||||
EOT
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# Piege : le jeton d'enregistrement expire en une heure. Un `apply` rejoue cette ressource des
|
||||
# que `runner_version`, `runner_labels` ou `runner_nom` change, et redemande donc un jeton frais.
|
||||
resource "null_resource" "runner_github" {
|
||||
depends_on = [null_resource.environnements]
|
||||
|
||||
triggers = {
|
||||
version = var.runner_version
|
||||
labels = var.runner_labels
|
||||
nom = local.runner_nom
|
||||
dossier = var.runner_dossier
|
||||
}
|
||||
|
||||
connection {
|
||||
type = "ssh"
|
||||
host = var.ssh_host
|
||||
port = var.ssh_port
|
||||
user = var.ssh_user
|
||||
private_key = file(pathexpand(var.ssh_private_key_path))
|
||||
timeout = "5m"
|
||||
}
|
||||
|
||||
provisioner "remote-exec" {
|
||||
inline = [
|
||||
<<-EOT
|
||||
set -eu
|
||||
${local.sudo}install -d -o ${var.proprietaire} -g ${var.proprietaire} ${var.runner_dossier}
|
||||
if [ ! -x ${var.runner_dossier}/config.sh ]; then
|
||||
curl -fsSL -o /tmp/${local.runner_archive} \
|
||||
https://github.com/actions/runner/releases/download/v${var.runner_version}/${local.runner_archive}
|
||||
${local.sudo}tar -xzf /tmp/${local.runner_archive} -C ${var.runner_dossier}
|
||||
${local.sudo}chown -R ${var.proprietaire}:${var.proprietaire} ${var.runner_dossier}
|
||||
rm -f /tmp/${local.runner_archive}
|
||||
fi
|
||||
if [ ! -f ${var.runner_dossier}/.runner ]; then
|
||||
${local.en_tant_que} sh -c 'cd ${var.runner_dossier} && ./config.sh --unattended --replace \
|
||||
--url ${var.runner_url} --token ${var.runner_token} \
|
||||
--labels ${var.runner_labels} --name ${local.runner_nom} --work _work'
|
||||
${local.sudo}${var.runner_dossier}/svc.sh install ${var.proprietaire}
|
||||
fi
|
||||
${local.sudo}${var.runner_dossier}/svc.sh start
|
||||
EOT
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
output "machine" {
|
||||
description = "Machine provisionnee et racine qui porte un clone par environnement."
|
||||
value = "${var.ssh_user}@${var.ssh_host}:${var.racine}"
|
||||
}
|
||||
|
||||
output "runner" {
|
||||
description = "Dossier d'installation du runner et libelles supplementaires annonces a GitHub."
|
||||
value = "${var.runner_dossier} (${var.runner_labels})"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
ssh_host = "10.101.200.37"
|
||||
ssh_port = 22
|
||||
ssh_user = "root"
|
||||
ssh_private_key_path = "~/.ssh/id_ed25519"
|
||||
|
||||
# Utilisateur qui possede la racine et fait tourner le runner. Il doit deja exister sur la
|
||||
# machine : git refuse les depots appartenant a un autre utilisateur, et un .env en 600 lui
|
||||
# echapperait.
|
||||
proprietaire = "enervision"
|
||||
|
||||
# Epingler une version reelle : https://github.com/actions/runner/releases
|
||||
runner_version = "2.330.0"
|
||||
|
||||
# Jeton d'enregistrement du runner, valable une heure et pour une seule inscription :
|
||||
# Parametres du depot > Actions > Runners > New self-hosted runner. Seul un administrateur du
|
||||
# depot peut le creer. terraform.tfvars est ignore par git, mais le jeton ne doit pas y rester
|
||||
# apres l'apply.
|
||||
runner_token = "A_RENSEIGNER"
|
||||
|
||||
# Nom du runner cote GitHub. Vide par defaut : le nom d'hote de la machine. A renseigner
|
||||
# seulement si deux runners doivent tourner sur la meme machine, leurs noms devant differer.
|
||||
# runner_nom = "eni-g3-bis"
|
||||
@@ -0,0 +1,90 @@
|
||||
variable "ssh_host" {
|
||||
type = string
|
||||
description = "Adresse de la VM ENI qui porte les deux environnements (ADR 0009)."
|
||||
}
|
||||
|
||||
variable "ssh_port" {
|
||||
type = number
|
||||
description = "Port SSH de la VM."
|
||||
default = 22
|
||||
}
|
||||
|
||||
variable "ssh_user" {
|
||||
type = string
|
||||
description = "Utilisateur SSH du provisionnement. Different de root, les commandes privilegiees sont prefixees par sudo."
|
||||
default = "root"
|
||||
}
|
||||
|
||||
variable "ssh_private_key_path" {
|
||||
type = string
|
||||
description = "Chemin local vers la cle privee SSH. L'authentification par mot de passe n'est volontairement pas prise en charge : une variable de mot de passe finit en clair dans le state ou dans les triggers."
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "proprietaire" {
|
||||
type = string
|
||||
description = "Utilisateur qui possede la racine et fait tourner le runner. Il doit exister sur la machine : git refuse les depots appartenant a un autre utilisateur, et un .env en 600 lui echapperait."
|
||||
|
||||
validation {
|
||||
condition = can(regex("^[a-z_][a-z0-9_-]*$", var.proprietaire))
|
||||
error_message = "proprietaire doit etre un nom d'utilisateur Unix valide."
|
||||
}
|
||||
}
|
||||
|
||||
variable "racine" {
|
||||
type = string
|
||||
description = "Dossier qui porte un clone du depot par environnement."
|
||||
default = "/srv/enervision"
|
||||
}
|
||||
|
||||
variable "depot_url" {
|
||||
type = string
|
||||
description = "URL de clonage du depot, passee a provision-host.sh."
|
||||
default = "https://github.com/ineszang/ProjetPiscine_EnerVision.git"
|
||||
}
|
||||
|
||||
variable "adresse_publique" {
|
||||
type = string
|
||||
description = "Adresse annoncee dans les certificats auto-signes. Vide : la premiere adresse de la VM."
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "runner_url" {
|
||||
type = string
|
||||
description = "Depot GitHub auquel le runner s'enregistre."
|
||||
default = "https://github.com/ineszang/ProjetPiscine_EnerVision"
|
||||
}
|
||||
|
||||
variable "runner_version" {
|
||||
type = string
|
||||
description = "Version d'actions-runner a installer, sans le v initial (ex: 2.330.0). Voir https://github.com/actions/runner/releases."
|
||||
|
||||
validation {
|
||||
condition = can(regex("^[0-9]+\\.[0-9]+\\.[0-9]+$", var.runner_version))
|
||||
error_message = "runner_version doit etre epinglee explicitement (ex: 2.330.0), sinon l'installation cesse d'etre reproductible."
|
||||
}
|
||||
}
|
||||
|
||||
variable "runner_token" {
|
||||
type = string
|
||||
description = "Jeton d'enregistrement du runner. Expire au bout d'une heure et ne vaut que pour une inscription : Parametres du depot > Actions > Runners > New self-hosted runner. Seul un administrateur du depot peut le creer."
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "runner_labels" {
|
||||
type = string
|
||||
description = "Libelles supplementaires du runner. deploy.yml cible [self-hosted, linux, eni-g3], les deux premiers etant poses par GitHub."
|
||||
default = "eni-g3"
|
||||
}
|
||||
|
||||
variable "runner_nom" {
|
||||
type = string
|
||||
description = "Nom du runner cote GitHub, unique dans le depot. Vide : le nom d'hote de la machine, qui reste unique si cette racine est reprise pour une seconde VM. A renseigner pour faire tourner deux runners sur la meme machine."
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "runner_dossier" {
|
||||
type = string
|
||||
description = "Dossier d'installation du runner sur la machine."
|
||||
default = "/opt/actions-runner"
|
||||
}
|
||||
Reference in New Issue
Block a user