[IMP] script todo: default erplibre/erplibre login + ~/.ssh/config entry
VMs were created with user "erplibre" but NO password (lock_passwd: true), so the serial console refused every login and only SSH-by-key worked — hence "can't connect". - The todo deploy flow (single VM and infra) now sets a default console password "erplibre" for the "erplibre" user, in addition to the SSH key, so virsh console and password SSH both work. It is shown as "Console/SSH login: erplibre / erplibre" and can be changed at the single-VM prompt. - The console entry now prints the default login and the Ctrl+] hint. - After creating a VM, offer to add it to ~/.ssh/config (Host <name>, HostName <ip>, User erplibre) so "ssh <name>" just works; the infra flow asks once and adds every VM. Existing blocks for the same Host are replaced, the rest of the file is preserved, mode kept 600. Note: VMs created before this change have no console password — delete and redeploy them to get the erplibre/erplibre login. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9876a03ac7
commit
78e7cf55c6
2 changed files with 108 additions and 7 deletions
|
|
@ -954,11 +954,15 @@ class TODO:
|
||||||
# sous sudo (HOME=/root) et ne pourrait pas déduire ~ correctement.
|
# sous sudo (HOME=/root) et ne pourrait pas déduire ~ correctement.
|
||||||
ssh_key = os.path.expanduser(ssh_key)
|
ssh_key = os.path.expanduser(ssh_key)
|
||||||
|
|
||||||
use_password = False
|
# Mot de passe console (défaut « erplibre ») : permet la connexion par
|
||||||
if not ssh_key:
|
# la console série (virsh console) EN PLUS de la clé SSH. Sans lui, le
|
||||||
ans = input(t("No SSH key found. Set a password instead? (Y/n): "))
|
# compte est verrouillé et la console refuse tout login.
|
||||||
# Défaut oui : tout sauf une réponse négative explicite vaut oui.
|
password = (
|
||||||
use_password = not self._is_no(ans)
|
input(
|
||||||
|
t("Console password for 'erplibre' (default: erplibre): ")
|
||||||
|
).strip()
|
||||||
|
or "erplibre"
|
||||||
|
)
|
||||||
|
|
||||||
force = False
|
force = False
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
|
|
@ -978,8 +982,8 @@ class TODO:
|
||||||
parts += ["--disk-size", disk_size]
|
parts += ["--disk-size", disk_size]
|
||||||
if ssh_key:
|
if ssh_key:
|
||||||
parts += ["--ssh-key", ssh_key]
|
parts += ["--ssh-key", ssh_key]
|
||||||
if use_password:
|
if password:
|
||||||
parts.append("--ask-password")
|
parts += ["--password", password]
|
||||||
if force:
|
if force:
|
||||||
parts.append("--force")
|
parts.append("--force")
|
||||||
if dry_run:
|
if dry_run:
|
||||||
|
|
@ -989,8 +993,14 @@ class TODO:
|
||||||
|
|
||||||
cmd = " ".join(shlex.quote(p) for p in parts)
|
cmd = " ".join(shlex.quote(p) for p in parts)
|
||||||
print(f"{t('Will execute:')} {cmd}")
|
print(f"{t('Will execute:')} {cmd}")
|
||||||
|
if password:
|
||||||
|
print(f"🔑 {t('Console/SSH login:')} erplibre / {password}")
|
||||||
self.execute.exec_command_live(cmd, source_erplibre=False)
|
self.execute.exec_command_live(cmd, source_erplibre=False)
|
||||||
|
|
||||||
|
# Proposer d'enregistrer la VM dans ~/.ssh/config (après le 1er boot).
|
||||||
|
if not dry_run:
|
||||||
|
self._qemu_offer_ssh_config(name, "erplibre")
|
||||||
|
|
||||||
def _qemu_download_image(self):
|
def _qemu_download_image(self):
|
||||||
script_path = self._qemu_script_path()
|
script_path = self._qemu_script_path()
|
||||||
distro = self._qemu_prompt_distro()
|
distro = self._qemu_prompt_distro()
|
||||||
|
|
@ -1047,10 +1057,52 @@ class TODO:
|
||||||
print(t("VM name is required!"))
|
print(t("VM name is required!"))
|
||||||
return
|
return
|
||||||
print(f"\n💡 {t('To leave the console, press Ctrl+] (then Enter).')}")
|
print(f"\n💡 {t('To leave the console, press Ctrl+] (then Enter).')}")
|
||||||
|
print(
|
||||||
|
f"👤 {t('Default login (if set at deploy): erplibre / erplibre')}"
|
||||||
|
)
|
||||||
cmd = f"sudo virsh console {shlex.quote(name)}"
|
cmd = f"sudo virsh console {shlex.quote(name)}"
|
||||||
print(f"{t('Will execute:')} {cmd}")
|
print(f"{t('Will execute:')} {cmd}")
|
||||||
self.execute.exec_command_live(cmd, source_erplibre=False)
|
self.execute.exec_command_live(cmd, source_erplibre=False)
|
||||||
|
|
||||||
|
def _qemu_offer_ssh_config(self, name, user):
|
||||||
|
"""Propose d'enregistrer la VM dans ~/.ssh/config (bloc Host name)."""
|
||||||
|
if not self._is_yes(input(t("Add this VM to ~/.ssh/config? (y/N): "))):
|
||||||
|
return
|
||||||
|
print(t("Waiting for the VM IP (DHCP lease)..."))
|
||||||
|
ip = self._qemu_vm_ip(name)
|
||||||
|
if not ip:
|
||||||
|
print(t("No IP yet; add it later once the VM has booted."))
|
||||||
|
return
|
||||||
|
self._write_ssh_config_entry(name, user, ip)
|
||||||
|
|
||||||
|
def _write_ssh_config_entry(self, host, user, ip):
|
||||||
|
"""Écrit/remplace un bloc « Host <host> » dans ~/.ssh/config."""
|
||||||
|
cfg = os.path.expanduser("~/.ssh/config")
|
||||||
|
os.makedirs(os.path.dirname(cfg), exist_ok=True)
|
||||||
|
existing = ""
|
||||||
|
if os.path.exists(cfg):
|
||||||
|
with open(cfg, encoding="utf-8") as fh:
|
||||||
|
existing = fh.read()
|
||||||
|
# Retire un ancien bloc du même Host (jusqu'au prochain Host / EOF).
|
||||||
|
pattern = re.compile(
|
||||||
|
rf"(?ms)^[ \t]*Host[ \t]+{re.escape(host)}[ \t]*\n"
|
||||||
|
r"(?:[ \t]+.*\n?)*"
|
||||||
|
)
|
||||||
|
existing = pattern.sub("", existing).rstrip("\n")
|
||||||
|
block = (
|
||||||
|
f"Host {host}\n"
|
||||||
|
f" HostName {ip}\n"
|
||||||
|
f" User {user}\n"
|
||||||
|
# IP DHCP réutilisées entre VM -> on évite l'erreur de clé d'hôte.
|
||||||
|
f" StrictHostKeyChecking no\n"
|
||||||
|
f" UserKnownHostsFile /dev/null\n"
|
||||||
|
)
|
||||||
|
content = (existing + "\n\n" + block) if existing else block
|
||||||
|
with open(cfg, "w", encoding="utf-8") as fh:
|
||||||
|
fh.write(content)
|
||||||
|
os.chmod(cfg, 0o600)
|
||||||
|
print(f"✅ {t('Added to ~/.ssh/config:')} ssh {host}")
|
||||||
|
|
||||||
def _qemu_list_domains(self):
|
def _qemu_list_domains(self):
|
||||||
"""Noms des VM libvirt définies (via virsh)."""
|
"""Noms des VM libvirt définies (via virsh)."""
|
||||||
try:
|
try:
|
||||||
|
|
@ -1377,6 +1429,10 @@ class TODO:
|
||||||
if self._is_yes(ans):
|
if self._is_yes(ans):
|
||||||
install_branch = self._qemu_pick_branch()
|
install_branch = self._qemu_pick_branch()
|
||||||
|
|
||||||
|
add_ssh_config = self._is_yes(
|
||||||
|
input(t("Add each VM to ~/.ssh/config? (y/N): "))
|
||||||
|
)
|
||||||
|
|
||||||
# 5) Confirmation puis déploiement séquentiel.
|
# 5) Confirmation puis déploiement séquentiel.
|
||||||
ans = input(f"\n{t('Deploy these VMs now? (y/N): ')}")
|
ans = input(f"\n{t('Deploy these VMs now? (y/N): ')}")
|
||||||
if not self._is_yes(ans):
|
if not self._is_yes(ans):
|
||||||
|
|
@ -1403,6 +1459,9 @@ class TODO:
|
||||||
]
|
]
|
||||||
if ssh_key:
|
if ssh_key:
|
||||||
parts += ["--ssh-key", ssh_key]
|
parts += ["--ssh-key", ssh_key]
|
||||||
|
# Mot de passe console par défaut « erplibre » (login virsh
|
||||||
|
# console + SSH par mot de passe), en plus de la clé.
|
||||||
|
parts += ["--password", "erplibre"]
|
||||||
if install_branch:
|
if install_branch:
|
||||||
parts += ["--package", "git"]
|
parts += ["--package", "git"]
|
||||||
parts.append("-y")
|
parts.append("-y")
|
||||||
|
|
@ -1410,6 +1469,10 @@ class TODO:
|
||||||
print(f"\n▶ {name}: {cmd}")
|
print(f"\n▶ {name}: {cmd}")
|
||||||
self.execute.exec_command_live(cmd, source_erplibre=False)
|
self.execute.exec_command_live(cmd, source_erplibre=False)
|
||||||
deployed.append(name)
|
deployed.append(name)
|
||||||
|
if add_ssh_config:
|
||||||
|
ip = self._qemu_vm_ip(name)
|
||||||
|
if ip:
|
||||||
|
self._write_ssh_config_entry(name, "erplibre", ip)
|
||||||
|
|
||||||
# 6) Installation ERPLibre (clone) si demandée.
|
# 6) Installation ERPLibre (clone) si demandée.
|
||||||
if install_branch:
|
if install_branch:
|
||||||
|
|
@ -1418,6 +1481,7 @@ class TODO:
|
||||||
self._qemu_install_erplibre_vm(name, ssh_key, install_branch)
|
self._qemu_install_erplibre_vm(name, ssh_key, install_branch)
|
||||||
|
|
||||||
print(f"\n✅ {t('ERPLibre infra deployment done.')}")
|
print(f"\n✅ {t('ERPLibre infra deployment done.')}")
|
||||||
|
print(f" {t('Default login:')} erplibre / erplibre")
|
||||||
print(f" {t('Manage with:')} sudo virsh list --all")
|
print(f" {t('Manage with:')} sudo virsh list --all")
|
||||||
|
|
||||||
def _deploy_clone_erplibre(self):
|
def _deploy_clone_erplibre(self):
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,43 @@ TRANSLATIONS = {
|
||||||
"fr": "Pour quitter la console, appuyez sur Ctrl+] (puis Entrée).",
|
"fr": "Pour quitter la console, appuyez sur Ctrl+] (puis Entrée).",
|
||||||
"en": "To leave the console, press Ctrl+] (then Enter).",
|
"en": "To leave the console, press Ctrl+] (then Enter).",
|
||||||
},
|
},
|
||||||
|
"Default login (if set at deploy): erplibre / erplibre": {
|
||||||
|
"fr": "Login par défaut (si défini au déploiement) : "
|
||||||
|
"erplibre / erplibre",
|
||||||
|
"en": "Default login (if set at deploy): erplibre / erplibre",
|
||||||
|
},
|
||||||
|
"Console password for 'erplibre' (default: erplibre): ": {
|
||||||
|
"fr": "Mot de passe console pour « erplibre » (défaut : erplibre) : ",
|
||||||
|
"en": "Console password for 'erplibre' (default: erplibre): ",
|
||||||
|
},
|
||||||
|
"Console/SSH login:": {
|
||||||
|
"fr": "Connexion console/SSH :",
|
||||||
|
"en": "Console/SSH login:",
|
||||||
|
},
|
||||||
|
"Default login:": {
|
||||||
|
"fr": "Login par défaut :",
|
||||||
|
"en": "Default login:",
|
||||||
|
},
|
||||||
|
"Add this VM to ~/.ssh/config? (y/N): ": {
|
||||||
|
"fr": "Ajouter cette VM à ~/.ssh/config ? (o/N) : ",
|
||||||
|
"en": "Add this VM to ~/.ssh/config? (y/N): ",
|
||||||
|
},
|
||||||
|
"Add each VM to ~/.ssh/config? (y/N): ": {
|
||||||
|
"fr": "Ajouter chaque VM à ~/.ssh/config ? (o/N) : ",
|
||||||
|
"en": "Add each VM to ~/.ssh/config? (y/N): ",
|
||||||
|
},
|
||||||
|
"Waiting for the VM IP (DHCP lease)...": {
|
||||||
|
"fr": "Attente de l'IP de la VM (bail DHCP)...",
|
||||||
|
"en": "Waiting for the VM IP (DHCP lease)...",
|
||||||
|
},
|
||||||
|
"No IP yet; add it later once the VM has booted.": {
|
||||||
|
"fr": "Pas encore d'IP ; à ajouter plus tard une fois la VM démarrée.",
|
||||||
|
"en": "No IP yet; add it later once the VM has booted.",
|
||||||
|
},
|
||||||
|
"Added to ~/.ssh/config:": {
|
||||||
|
"fr": "Ajouté à ~/.ssh/config :",
|
||||||
|
"en": "Added to ~/.ssh/config:",
|
||||||
|
},
|
||||||
"SSH address input method": {
|
"SSH address input method": {
|
||||||
"fr": "Méthode de saisie de l'adresse SSH",
|
"fr": "Méthode de saisie de l'adresse SSH",
|
||||||
"en": "SSH address input method",
|
"en": "SSH address input method",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue