Les deux reconstructions de la semaine rebatissaient Chezlepro sur son propre materiel : une preuve de reproductibilite, pas de portabilite. La vraie epreuve est un second tenant — Technolibre, index 11, plan distinct, voute separee, meme cluster. 1. LE CLONAGE RESOLVAIT PAR NOM. proxmox_kvm cherche une VM portant le `name` demande ; s'il en trouve une il rend `ok` et ne clone RIEN — aucune tache cote cluster. Or les noms courts sont VOLONTAIREMENT identiques d'un tenant a l'autre. `backup-01` de Technolibre tombait sur celui de Chezlepro. Mesure : id-ldap-01 et sup-01 (noms absents chez Chezlepro) passaient du premier coup, backup-01 echouait toujours. Le clonage cible desormais par VMID, via l'API. Deux defauts de ce correctif, trouves en le mesurant : le corps assemble en Jinja avec `>-` rendait une CHAINE et perdait le `pool` (VM nee hors de son pool, sans un mot) ; et l'application du gabarit de calcul expirait a 5 s, laissant la VM aux valeurs du gabarit — 2 coeurs/2 Go au lieu du plan, en silence. Corps en mapping YAML avec omit ; six tentatives espacees. Et `no_log` a masque la cause au moment ou elle servait. Les deux attentes disent maintenant ce qu'elles ont constate. 2. LE GUI DETRUISAIT DES INTRANTS. Dans ecrire_intrants, `identite` etait la seule branche sur quatre a ecrire par-dessus le disque au lieu de fusionner. Un enregistrement a supprime dns_amorcage et amorcage_acces_courriel. Le meme geste sur Chezlepro aurait mange les memes cles. 3. LE VERROU DE `raser` N'ETAIT PROUVE QUE POUR UN TENANT. Le faux cluster codait en dur les VMID de Chezlepro ; monte ailleurs, le test rendait 0 au lieu de 2. Il fabrique desormais la collision sur le plan courant. Verifie : prouver.py 34 OK sur Technolibre, test_raser vert sur les deux tenants, ansible-lint production sur le playbook de clonage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
390 lines
20 KiB
YAML
390 lines
20 KiB
YAML
---
|
|
- name: Cloner une VM Debian depuis le modele Proxmox
|
|
hosts: localhost
|
|
connection: local
|
|
gather_facts: false
|
|
become: false
|
|
|
|
vars:
|
|
# Config Proxmox de l'instance : on cherche dans l'inventaire de l'instance,
|
|
# quel que soit son nom (lab > principal > production). Compatible « par instance ».
|
|
setops_inventaires: [lab, principal, production]
|
|
# Voute UNIQUE de l'instance : all/vault.yml porte TOUS les secrets, jeton
|
|
# d'hyperviseur compris (D-19). `proxmox.vault.yml` a ete retire le 2026-08-03 :
|
|
# tolere "en compatibilite", il restait le SEUL porteur du jeton chez un tenant,
|
|
# et il etait gitignore — une voute unique qui ne l'etait pas, dans un fichier
|
|
# qui ne voyageait avec aucun depot. P18 ne pouvait pas le voir : il verifie le
|
|
# gabarit, pas le contenu reel.
|
|
# `proxmox.local.yml` reste une surcharge locale volontaire, non versionnee.
|
|
setops_gv_proxmox: [proxmox.yml, proxmox.local.yml, all/vault.yml]
|
|
# Le CLUSTER appartient a l'HEBERGEUR (API, noeuds, stockages, ponts). Son fichier
|
|
# vit dans le depot de l'hebergeur, que le symlink `underlay.yml` designe deja
|
|
# (D-14/D-17) : on en DERIVE le chemin plutot que de redeclarer l'hebergeur. Absent
|
|
# (depot sans underlay monte), le `stat` echoue simplement et rien n'est charge.
|
|
setops_proxmox_hebergeur: "{{ (playbook_dir ~ '/../../underlay.yml') | realpath | dirname }}/proxmox-hebergeur.yml"
|
|
|
|
tasks:
|
|
- name: Verifier les fichiers de variables Proxmox optionnels
|
|
ansible.builtin.stat:
|
|
path: "{{ playbook_dir }}/../../instance/inventories/{{ item.0 }}/group_vars/{{ item.1 }}"
|
|
loop: "{{ setops_inventaires | product(setops_gv_proxmox) | list }}"
|
|
loop_control:
|
|
label: "{{ item.0 }}/{{ item.1 }}"
|
|
register: proxmox_fichiers_variables
|
|
|
|
- name: Charger les variables Proxmox non sensibles disponibles
|
|
ansible.builtin.include_vars:
|
|
file: "{{ item.stat.path }}"
|
|
loop: "{{ proxmox_fichiers_variables.results }}"
|
|
when:
|
|
- item.stat.exists
|
|
- item.stat.path is not search('vault')
|
|
|
|
- name: Localiser le fichier Proxmox de l'hebergeur
|
|
ansible.builtin.stat:
|
|
path: "{{ setops_proxmox_hebergeur }}"
|
|
register: proxmox_fichier_hebergeur
|
|
|
|
- name: Charger le cluster de l'hebergeur (autoritaire sur ses propres cles)
|
|
ansible.builtin.include_vars:
|
|
file: "{{ setops_proxmox_hebergeur }}"
|
|
when: proxmox_fichier_hebergeur.stat.exists
|
|
|
|
- name: Charger les secrets Proxmox Vault
|
|
block:
|
|
- name: Charger les secrets de la voute Proxmox
|
|
ansible.builtin.include_vars:
|
|
file: "{{ item.stat.path }}"
|
|
loop: "{{ proxmox_fichiers_variables.results }}"
|
|
when:
|
|
- item.stat.exists
|
|
- item.stat.path is search('vault')
|
|
no_log: true
|
|
rescue:
|
|
- name: Expliquer l echec de chargement du Vault
|
|
ansible.builtin.fail:
|
|
msg: >-
|
|
Impossible de charger la voute Proxmox (group_vars/all/vault.yml ou
|
|
proxmox.vault.yml). Si elle est chiffree avec Ansible Vault, fournir son
|
|
mot de passe ou definir ANSIBLE_VAULT_PASSWORD_FILE avant de relancer make creer-vm.
|
|
|
|
- name: Appliquer les valeurs Proxmox avec repli environnement
|
|
ansible.builtin.set_fact:
|
|
proxmox_api_host_effectif: "{{ proxmox_api_host | default(lookup('env', 'PROXMOX_API_HOST'), true) }}"
|
|
proxmox_api_user_effectif: "{{ proxmox_api_user | default(lookup('env', 'PROXMOX_API_USER'), true) }}"
|
|
# `split('!')[-1]` : proxmoxer recompose lui-meme `utilisateur!nom` a partir de
|
|
# `api_user` et `api_token_id`. Lui passer la forme COMPLETE produit
|
|
# `ansible@pve!ansible@pve!nom` et un 401 muet — le meme jeton fonctionne en
|
|
# HTTP direct, ce qui rend le diagnostic trompeur. Verifie contre le cluster le
|
|
# 2026-08-03 : forme complete = 401, forme courte = OK. Sans effet si la voute
|
|
# stocke deja le nom seul, donc les deux ecritures restent acceptees.
|
|
proxmox_api_token_id_effectif: "{{ (proxmox_api_token_id | default(lookup('env', 'PROXMOX_API_TOKEN_ID'), true)) | string | split('!') | last }}"
|
|
proxmox_api_token_secret_effectif: "{{ proxmox_api_token_secret | default(lookup('env', 'PROXMOX_API_TOKEN_SECRET'), true) }}"
|
|
proxmox_api_port_effectif: "{{ proxmox_api_port | default(lookup('env', 'PROXMOX_API_PORT'), true) }}"
|
|
no_log: true
|
|
|
|
- name: Valider les parametres obligatoires Proxmox
|
|
ansible.builtin.assert:
|
|
that:
|
|
- proxmox_api_host_effectif | length > 0
|
|
- proxmox_api_user_effectif | length > 0
|
|
- proxmox_api_token_id_effectif | length > 0
|
|
- proxmox_api_token_secret_effectif | length > 0
|
|
- proxmox_clone_nom is defined
|
|
- proxmox_clone_nom | length > 0
|
|
- proxmox_clone_vmid_modele is defined
|
|
- proxmox_clone_vmid is defined
|
|
- proxmox_clone_noeud is defined
|
|
- proxmox_clone_noeud | length > 0
|
|
- proxmox_clone_ipconfig0 is defined
|
|
- proxmox_clone_ipconfig0 | length > 0
|
|
fail_msg: "Parametres Proxmox incomplets. Verifier proxmox.yml, la voute (all/vault.yml ou proxmox.vault.yml) et les variables make propres a la VM."
|
|
|
|
- name: Lire la cle publique SSH depuis le fichier fourni
|
|
ansible.builtin.set_fact:
|
|
proxmox_clone_sshkeys: "{{ lookup('ansible.builtin.file', proxmox_clone_cle_publique_fichier) }}"
|
|
when:
|
|
- proxmox_clone_cle_publique is not defined
|
|
- proxmox_clone_cle_publique_fichier is defined
|
|
- proxmox_clone_cle_publique_fichier | length > 0
|
|
|
|
- name: Utiliser la cle publique SSH fournie directement
|
|
ansible.builtin.set_fact:
|
|
proxmox_clone_sshkeys: "{{ proxmox_clone_cle_publique }}"
|
|
when:
|
|
- proxmox_clone_cle_publique is defined
|
|
- proxmox_clone_cle_publique | length > 0
|
|
|
|
- name: Construire les serveurs DNS Cloud-Init
|
|
ansible.builtin.set_fact:
|
|
proxmox_clone_nameservers: >-
|
|
{{
|
|
(proxmox_clone_dns | default('') | split(','))
|
|
| map('trim')
|
|
| reject('equalto', '')
|
|
| list
|
|
}}
|
|
|
|
- name: Verifier la bibliotheque Python proxmoxer locale
|
|
ansible.builtin.command:
|
|
cmd: "{{ ansible_playbook_python }} -c 'import proxmoxer'"
|
|
changed_when: false
|
|
failed_when: false
|
|
register: proxmoxer_verification
|
|
|
|
- name: Refuser si proxmoxer est absent
|
|
ansible.builtin.fail:
|
|
msg: >-
|
|
La bibliotheque Python proxmoxer est absente pour {{ ansible_playbook_python }}.
|
|
Installer le paquet systeme approprie, par exemple
|
|
sudo apt install python3-proxmoxer, ou installer proxmoxer dans
|
|
l'environnement Python utilise par Ansible, puis relancer make creer-vm.
|
|
when: proxmoxer_verification.rc != 0
|
|
|
|
- name: S'assurer que le pool du tenant existe
|
|
# Un pool par tenant : la console Proxmox affiche le NOM, et onze serveurs
|
|
# portent le meme d'un tenant a l'autre. Le pool restitue l'appartenance sans
|
|
# rien renommer. Il doit exister AVANT le clone — `proxmox_kvm` echoue sur un
|
|
# pool inconnu, et l'API ne sait pas changer le pool d'une VM deja creee.
|
|
community.general.proxmox_pool:
|
|
api_host: "{{ proxmox_api_host_effectif }}"
|
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
|
api_user: "{{ proxmox_api_user_effectif }}"
|
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
|
poolid: "{{ proxmox_clone_pool }}"
|
|
comment: "Tenant Set-OPS — genere, ne pas renommer a la main"
|
|
state: present
|
|
when: proxmox_clone_pool | default('', true) | length > 0
|
|
|
|
# LE CLONE SE CIBLE PAR VMID, JAMAIS PAR NOM — et c'est tout l'objet de ces trois
|
|
# taches. `community.general.proxmox_kvm` cherche d'abord une VM portant le `name`
|
|
# demande ; s'il en trouve une, il conclut « elle existe deja », rend `ok` et ne
|
|
# clone RIEN. Aucune tache n'apparait meme cote cluster.
|
|
#
|
|
# Or les noms courts sont VOLONTAIREMENT identiques d'un tenant a l'autre (meme
|
|
# fonction, meme nom) : c'est le pool qui restitue l'appartenance. Le premier clone
|
|
# de Technolibre — `backup-01` — est donc tombe sur le `backup-01` de Chezlepro et
|
|
# n'a rien fait, puis l'attente a expire sur une configuration qui n'existerait
|
|
# jamais. Mesure du 2026-08-10 : zero VM creee, zero tache `qmclone` au cluster.
|
|
#
|
|
# Le defaut etait invisible tant qu'un seul tenant existait. C'est exactement ce
|
|
# qu'une epreuve de portabilite doit trouver.
|
|
- name: Recenser les VM du cluster (pour cibler par VMID)
|
|
vars:
|
|
proxmox_api_racine: "https://{{ proxmox_api_host_effectif }}:{{ proxmox_api_port_effectif | default(8006, true) }}"
|
|
ansible.builtin.uri:
|
|
url: "{{ proxmox_api_racine }}/api2/json/cluster/resources?type=vm"
|
|
method: GET
|
|
headers:
|
|
Authorization: >-
|
|
PVEAPIToken={{ proxmox_api_user_effectif }}!{{ proxmox_api_token_id_effectif }}={{ proxmox_api_token_secret_effectif }}
|
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
|
status_code: 200
|
|
register: proxmox_inventaire_vm
|
|
changed_when: false
|
|
no_log: true
|
|
|
|
- name: Retenir si le VMID cible est deja pris
|
|
ansible.builtin.set_fact:
|
|
proxmox_clone_deja_la: >-
|
|
{{ (proxmox_inventaire_vm.json.data | default([]))
|
|
| selectattr('vmid', 'defined')
|
|
| selectattr('vmid', 'equalto', proxmox_clone_vmid | int)
|
|
| list | length > 0 }}
|
|
|
|
- name: Cloner la VM depuis le modele (API directe, cible par VMID)
|
|
vars:
|
|
proxmox_api_racine: "https://{{ proxmox_api_host_effectif }}:{{ proxmox_api_port_effectif | default(8006, true) }}"
|
|
ansible.builtin.uri:
|
|
url: "{{ proxmox_api_racine }}/api2/json/nodes/{{ proxmox_clone_noeud }}/qemu/{{ proxmox_clone_vmid_modele | int }}/clone"
|
|
method: POST
|
|
headers:
|
|
Authorization: >-
|
|
PVEAPIToken={{ proxmox_api_user_effectif }}!{{ proxmox_api_token_id_effectif }}={{ proxmox_api_token_secret_effectif }}
|
|
body_format: form-urlencoded
|
|
# Corps ecrit en MAPPING YAML, pas assemble en Jinja : une expression `>-` rend
|
|
# une CHAINE, et le premier jet a ainsi perdu le `pool` en route — la VM est
|
|
# nee hors de son pool, sans un mot. `omit` retire proprement les cles vides.
|
|
body:
|
|
newid: "{{ proxmox_clone_vmid | int }}"
|
|
name: "{{ proxmox_clone_nom }}"
|
|
full: "{{ 1 if (proxmox_clone_complet | default(true) | bool) else 0 }}"
|
|
storage: "{{ proxmox_clone_stockage | default(omit, true) }}"
|
|
format: "{{ proxmox_clone_format | default(omit, true) }}"
|
|
# A la CREATION seulement : l'API ne sait pas changer le pool d'une VM
|
|
# existante par cet appel (il faut passer par le membre du pool).
|
|
pool: "{{ proxmox_clone_pool | default(omit, true) }}"
|
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
|
status_code: 200
|
|
register: proxmox_clone_lance
|
|
# Le corps ne porte aucun secret, mais l'en-tete si : `no_log` masquerait alors
|
|
# l'erreur de l'API, qui est justement ce qu'on veut lire. On ne journalise donc
|
|
# que l'ECHEC, et sans les en-tetes.
|
|
failed_when: false
|
|
no_log: true
|
|
when: not proxmox_clone_deja_la
|
|
|
|
- name: Dire pourquoi le clonage a echoue, s'il a echoue
|
|
ansible.builtin.fail:
|
|
msg: >-
|
|
Le clonage de {{ proxmox_clone_nom }} (VMID {{ proxmox_clone_vmid }}) depuis le
|
|
gabarit {{ proxmox_clone_vmid_modele }} a ete refuse par l'API Proxmox
|
|
(HTTP {{ proxmox_clone_lance.status | default('?') }}).
|
|
Verifier que le gabarit existe sur {{ proxmox_clone_noeud }}, que le pool
|
|
{{ proxmox_clone_pool | default('(aucun)', true) }} existe, et que le VMID
|
|
cible est libre.
|
|
when:
|
|
- not proxmox_clone_deja_la
|
|
- proxmox_clone_lance.status | default(0) != 200
|
|
|
|
# L'API de CLONAGE ignore `cores` et `memory` : le clone herite du gabarit, et le
|
|
# plan est contredit sans un mot. Mesure du 2026-08-06 : plan 1 coeur / 1024 Mo,
|
|
# VM creee avec 2 / 2048 — ceux du gabarit. Il faut donc les reposer APRES le clone.
|
|
# Le clone COMPLET rend la main avant que sa configuration ne soit ecrite : sur
|
|
# un stockage lent, `qm clone` retourne, et le `.conf` n'existe pas encore. La
|
|
# tache suivante echouait alors sur « Configuration file ... does not exist ».
|
|
# Observe deux fois sur quinze clones (2026-08-07) — une course, pas un hasard.
|
|
- name: Attendre que la configuration du clone existe
|
|
vars:
|
|
# Assemblee dans une variable : un `>-` replie les retours en ESPACES, ce qui
|
|
# inserait une espace au milieu de l'URL. Le lint passait, la requete non.
|
|
proxmox_api_racine: "https://{{ proxmox_api_host_effectif }}:{{ proxmox_api_port_effectif | default(8006, true) }}"
|
|
ansible.builtin.uri:
|
|
url: "{{ proxmox_api_racine }}/api2/json/nodes/{{ proxmox_clone_noeud }}/qemu/{{ proxmox_clone_vmid | int }}/config"
|
|
method: GET
|
|
headers:
|
|
Authorization: >-
|
|
PVEAPIToken={{ proxmox_api_user_effectif }}!{{ proxmox_api_token_id_effectif }}={{ proxmox_api_token_secret_effectif }}
|
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
|
status_code: 200
|
|
register: proxmox_clone_conf
|
|
until: proxmox_clone_conf.status == 200
|
|
retries: 30
|
|
delay: 5
|
|
changed_when: false
|
|
failed_when: false
|
|
no_log: true
|
|
|
|
# `no_log` masque la cause au moment ou on en a besoin : le 2026-08-10, l'echec de
|
|
# cette attente s'est lu « the output has been hidden », et il a fallu interroger le
|
|
# cluster a la main pour comprendre que le clone n'avait jamais eu lieu. On rend
|
|
# donc le verdict lisible ici, sans reveler l'en-tete d'autorisation.
|
|
- name: Dire ce que l'attente du clone a constate
|
|
ansible.builtin.fail:
|
|
msg: >-
|
|
La configuration de {{ proxmox_clone_nom }} (VMID {{ proxmox_clone_vmid }})
|
|
n'existe toujours pas apres {{ 30 * 5 }} s sur {{ proxmox_clone_noeud }}.
|
|
Le clonage n'a donc pas abouti — verifier les taches du cluster
|
|
(`/cluster/tasks`) : si aucune tache de clonage n'apparait, c'est que rien
|
|
n'a ete demande a l'API.
|
|
when: proxmox_clone_conf.status | default(0) != 200
|
|
|
|
- name: Appliquer le gabarit de calcul du plan (le clonage ne le fait pas)
|
|
community.general.proxmox_kvm:
|
|
api_host: "{{ proxmox_api_host_effectif }}"
|
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
|
api_user: "{{ proxmox_api_user_effectif }}"
|
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
|
node: "{{ proxmox_clone_noeud }}"
|
|
vmid: "{{ proxmox_clone_vmid | int }}"
|
|
cores: "{{ proxmox_clone_coeurs | int }}"
|
|
memory: "{{ proxmox_clone_memoire | int }}"
|
|
update: true
|
|
# Le noeud vient de finir un clone COMPLET : son API repond encore lentement, et
|
|
# la lecture expire a 5 s. Mesure du 2026-08-10 : « Read timed out » sur le tout
|
|
# premier clone, VM creee mais laissee aux valeurs du gabarit — 2 coeurs / 2 Go au
|
|
# lieu du plan. Une VM sous-dimensionnee en silence est pire qu'un echec franc.
|
|
register: proxmox_gabarit_calcul
|
|
until: proxmox_gabarit_calcul is succeeded
|
|
retries: 6
|
|
delay: 10
|
|
when:
|
|
- proxmox_clone_coeurs is defined and proxmox_clone_coeurs | string | length > 0
|
|
- proxmox_clone_memoire is defined and proxmox_clone_memoire | string | length > 0
|
|
|
|
- name: Ajuster le reseau de la VM clonee
|
|
community.general.proxmox_nic:
|
|
api_host: "{{ proxmox_api_host_effectif }}"
|
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
|
api_user: "{{ proxmox_api_user_effectif }}"
|
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
|
vmid: "{{ proxmox_clone_vmid | int }}"
|
|
interface: "{{ proxmox_clone_interface | default('net0') }}"
|
|
model: virtio
|
|
bridge: "{{ proxmox_clone_pont }}"
|
|
tag: "{{ proxmox_clone_vlan | int if proxmox_clone_vlan is defined and proxmox_clone_vlan | string | length > 0 else omit }}"
|
|
firewall: "{{ proxmox_clone_parefeu_interface | default(false) | bool }}"
|
|
state: present
|
|
when:
|
|
- proxmox_clone_pont is defined
|
|
- proxmox_clone_pont | length > 0
|
|
|
|
- name: Agrandir le disque principal du clone (grow-only)
|
|
community.general.proxmox_disk:
|
|
api_host: "{{ proxmox_api_host_effectif }}"
|
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
|
api_user: "{{ proxmox_api_user_effectif }}"
|
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
|
vmid: "{{ proxmox_clone_vmid | int }}"
|
|
disk: "{{ proxmox_clone_disque | default('scsi0') }}"
|
|
size: "{{ proxmox_clone_taille_disque }}"
|
|
state: resized
|
|
register: proxmox_redim_disque
|
|
# Le disque derive du plan est un MINIMUM. Si le template est deja plus grand,
|
|
# Proxmox refuse de retrecir : on tolere ce cas (grow-only), la VM garde le
|
|
# disque du template. Toute autre erreur reste bloquante.
|
|
failed_when:
|
|
- proxmox_redim_disque is failed
|
|
- "'shrinking disks is not supported' not in (proxmox_redim_disque.msg | default(''))"
|
|
when:
|
|
- proxmox_clone_taille_disque is defined
|
|
- proxmox_clone_taille_disque | length > 0
|
|
|
|
- name: Configurer Cloud-Init sur le clone
|
|
community.general.proxmox_kvm:
|
|
api_host: "{{ proxmox_api_host_effectif }}"
|
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
|
api_user: "{{ proxmox_api_user_effectif }}"
|
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
|
node: "{{ proxmox_clone_noeud }}"
|
|
vmid: "{{ proxmox_clone_vmid | int }}"
|
|
name: "{{ proxmox_clone_nom }}"
|
|
update: true
|
|
ciuser: "{{ proxmox_clone_ciuser | default(omit, true) }}"
|
|
sshkeys: "{{ proxmox_clone_sshkeys | default(omit) }}"
|
|
ipconfig:
|
|
ipconfig0: "{{ proxmox_clone_ipconfig0 }}"
|
|
nameservers: "{{ proxmox_clone_nameservers if proxmox_clone_nameservers | length > 0 else omit }}"
|
|
searchdomains: "{{ proxmox_clone_domaines_recherche | default(omit, true) }}"
|
|
agent: "enabled=1"
|
|
|
|
- name: Demarrer le clone
|
|
community.general.proxmox_kvm:
|
|
api_host: "{{ proxmox_api_host_effectif }}"
|
|
api_port: "{{ proxmox_api_port_effectif | int if proxmox_api_port_effectif | length > 0 else omit }}"
|
|
api_user: "{{ proxmox_api_user_effectif }}"
|
|
api_token_id: "{{ proxmox_api_token_id_effectif }}"
|
|
api_token_secret: "{{ proxmox_api_token_secret_effectif }}"
|
|
validate_certs: "{{ proxmox_validate_certs | default(false) | bool }}"
|
|
node: "{{ proxmox_clone_noeud }}"
|
|
vmid: "{{ proxmox_clone_vmid | int }}"
|
|
name: "{{ proxmox_clone_nom }}"
|
|
state: started
|
|
when: proxmox_clone_demarrer | default(true) | bool
|
|
|
|
- name: Afficher le resume du clone
|
|
ansible.builtin.debug:
|
|
msg:
|
|
- "VM creee: {{ proxmox_clone_nom }} (VMID {{ proxmox_clone_vmid }})"
|
|
- "Pool: {{ proxmox_clone_pool | default('(aucun)', true) }}"
|
|
- "Cloud-Init ipconfig0: {{ proxmox_clone_ipconfig0 }}"
|