feat: sortie de domaine, et corrections issues d'un echec reel de jointure
Sortie de domaine (demandee) : - Bouton « Quitter le domaine » et commande CLI `leave`, via Remove-Computer sous Windows et realm leave sous Linux. - Nettoyage optionnel des paquets sous Linux. packagekit est exclu de la liste : il sert aussi au gestionnaire de logiciels du bureau. - Le champ « Nom de la machine » passe en lecture seule : il ne peut pas etre modifie depuis cette fenetre. Corrections tirees de la sortie PowerShell rapportee : - Les barres de progression etaient serialisees en CLIXML et polluaient le journal ; les accents arrivaient illisibles (console OEM lue en cp1252). Progression desactivee, console en UTF-8, CLIXML residuel filtre. - Le marqueur interne JOIN_FAILURE: n'apparait plus dans le message affiche. Diagnostic : - Ajout du SRV `_ldap._tcp.dc._msdcs`, celui que DsGetDcName utilise pour localiser un DC. Son absence donne exactement l'erreur rencontree, et le diagnostic ne le verifiait pas. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+113
-3
@@ -9,6 +9,7 @@ from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QColor
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication,
|
||||
QCheckBox,
|
||||
QFormLayout,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
@@ -26,7 +27,8 @@ from PySide6.QtWidgets import (
|
||||
|
||||
from . import __version__, diagnostics, privileges
|
||||
from .backend import get_backend
|
||||
from .worker import DiagnosticsWorker, InstallPrerequisitesWorker, JoinWorker
|
||||
from .backend.linux_realmd import REMOVABLE_PACKAGES
|
||||
from .worker import DiagnosticsWorker, InstallPrerequisitesWorker, JoinWorker, LeaveWorker
|
||||
|
||||
DEFAULT_DOMAIN = "h3adm.lan"
|
||||
|
||||
@@ -114,6 +116,7 @@ class JoinTab(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._worker: JoinWorker | None = None
|
||||
self._leave_worker: LeaveWorker | None = None
|
||||
self.backend = get_backend()
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
@@ -126,14 +129,37 @@ class JoinTab(QWidget):
|
||||
self.password_edit.setEchoMode(QLineEdit.EchoMode.Password)
|
||||
self.ou_edit = QLineEdit()
|
||||
self.ou_edit.setPlaceholderText("optionnel, ex : OU=Postes,DC=h3adm,DC=lan")
|
||||
# Le nom de machine ne se change pas depuis cette fenetre : sous Linux
|
||||
# `realm join` reprend le hostname systeme, et sous Windows le renommage
|
||||
# releve des parametres systeme. Le champ reste affiche, en lecture
|
||||
# seule, pour montrer le nom sous lequel le poste apparaitra.
|
||||
self.computer_name_edit = QLineEdit(socket.gethostname())
|
||||
self.computer_name_edit.setEnabled(False)
|
||||
self.computer_name_edit.setToolTip(
|
||||
"Le nom de la machine ne peut pas être modifié depuis cette fenêtre.\n"
|
||||
+ (
|
||||
"Renommez le poste depuis les paramètres système de Windows, puis redémarrez."
|
||||
if platform.system() == "Windows"
|
||||
else "Changez le nom d'hôte avec : sudo hostnamectl set-hostname <nom>"
|
||||
)
|
||||
)
|
||||
|
||||
form.addRow("Domaine :", self.domain_edit)
|
||||
form.addRow("Utilisateur :", self.username_edit)
|
||||
form.addRow("Mot de passe :", self.password_edit)
|
||||
form.addRow("Unité d'organisation :", self.ou_edit)
|
||||
form.addRow("Nom de la machine :", self.computer_name_edit)
|
||||
|
||||
self.remove_packages_check = QCheckBox(
|
||||
"Désinstaller aussi les paquets système du domaine en quittant"
|
||||
)
|
||||
self.remove_packages_check.setVisible(platform.system() != "Windows")
|
||||
self.remove_packages_check.setToolTip(
|
||||
"Retire " + ", ".join(REMOVABLE_PACKAGES) + ".\n"
|
||||
"packagekit est conservé : il sert aussi au gestionnaire de logiciels."
|
||||
)
|
||||
layout.addLayout(form)
|
||||
layout.addWidget(self.remove_packages_check)
|
||||
|
||||
self.prereq_label = QLabel("")
|
||||
self.prereq_label.setWordWrap(True)
|
||||
@@ -148,6 +174,9 @@ class JoinTab(QWidget):
|
||||
self.install_button.clicked.connect(self._start_install)
|
||||
self.install_button.setVisible(False)
|
||||
buttons.addWidget(self.install_button)
|
||||
self.leave_button = QPushButton("Quitter le domaine")
|
||||
self.leave_button.clicked.connect(self._start_leave)
|
||||
buttons.addWidget(self.leave_button)
|
||||
buttons.addStretch()
|
||||
layout.addLayout(buttons)
|
||||
|
||||
@@ -187,6 +216,21 @@ class JoinTab(QWidget):
|
||||
self.join_button.setEnabled(True)
|
||||
self.join_button.setToolTip("")
|
||||
|
||||
can_leave = self.backend.can_leave()
|
||||
self.leave_button.setVisible(can_leave)
|
||||
self.remove_packages_check.setVisible(can_leave and platform.system() != "Windows")
|
||||
if not elevated:
|
||||
self.leave_button.setEnabled(False)
|
||||
self.leave_button.setToolTip(
|
||||
"Droits insuffisants pour quitter le domaine.\n" + privileges.elevation_hint()
|
||||
)
|
||||
elif not available:
|
||||
self.leave_button.setEnabled(False)
|
||||
self.leave_button.setToolTip("Prérequis manquants — installez-les d'abord.")
|
||||
else:
|
||||
self.leave_button.setEnabled(True)
|
||||
self.leave_button.setToolTip("")
|
||||
|
||||
def _start_install(self) -> None:
|
||||
confirm = QMessageBox.question(
|
||||
self,
|
||||
@@ -220,7 +264,6 @@ class JoinTab(QWidget):
|
||||
username = self.username_edit.text().strip()
|
||||
password = self.password_edit.text()
|
||||
ou = self.ou_edit.text().strip() or None
|
||||
computer_name = self.computer_name_edit.text().strip() or None
|
||||
|
||||
if not domain or not username or not password:
|
||||
QMessageBox.warning(self, "Champs manquants", "Domaine, utilisateur et mot de passe sont requis.")
|
||||
@@ -246,11 +289,78 @@ class JoinTab(QWidget):
|
||||
self.log.clear()
|
||||
self.join_button.setEnabled(False)
|
||||
|
||||
self._worker = JoinWorker(self.backend, domain, username, password, ou, computer_name)
|
||||
self._worker = JoinWorker(self.backend, domain, username, password, ou, None)
|
||||
self._worker.output_line.connect(self.log.appendPlainText)
|
||||
self._worker.finished_join.connect(self._on_join_finished)
|
||||
self._worker.start()
|
||||
|
||||
def _start_leave(self) -> None:
|
||||
domain = self.domain_edit.text().strip()
|
||||
username = self.username_edit.text().strip()
|
||||
password = self.password_edit.text()
|
||||
remove_packages = self.remove_packages_check.isChecked() and self.remove_packages_check.isVisible()
|
||||
|
||||
if not domain:
|
||||
QMessageBox.warning(self, "Champ manquant", "Le domaine est requis.")
|
||||
return
|
||||
|
||||
# Sous Windows, Remove-Computer exige un compte autorise a retirer
|
||||
# l'objet ordinateur ; sous Linux, realm leave s'en passe.
|
||||
if platform.system() == "Windows" and (not username or not password):
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"Identifiants requis",
|
||||
"Sous Windows, quitter le domaine demande un compte du domaine "
|
||||
"autorisé à retirer cette machine de l'annuaire.",
|
||||
)
|
||||
return
|
||||
|
||||
available, reason = self.backend.is_available()
|
||||
if not available:
|
||||
QMessageBox.critical(self, "Backend indisponible", reason)
|
||||
return
|
||||
|
||||
details = (
|
||||
f"Faire quitter le domaine « {domain} » à ce poste ?\n\n"
|
||||
"Les comptes du domaine ne pourront plus s'y connecter et un "
|
||||
"redémarrage sera nécessaire."
|
||||
)
|
||||
if remove_packages:
|
||||
details += (
|
||||
"\n\nLes paquets suivants seront également désinstallés :\n"
|
||||
+ ", ".join(REMOVABLE_PACKAGES)
|
||||
+ "\n\nAssurez-vous qu'aucune session de compte du domaine n'est ouverte."
|
||||
)
|
||||
|
||||
confirm = QMessageBox.question(
|
||||
self,
|
||||
"Confirmer la sortie du domaine",
|
||||
details,
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
if confirm != QMessageBox.StandardButton.Yes:
|
||||
return
|
||||
|
||||
self.log.clear()
|
||||
self.join_button.setEnabled(False)
|
||||
self.leave_button.setEnabled(False)
|
||||
|
||||
self._leave_worker = LeaveWorker(self.backend, domain, username, password, remove_packages)
|
||||
self._leave_worker.output_line.connect(self.log.appendPlainText)
|
||||
self._leave_worker.finished_leave.connect(self._on_leave_finished)
|
||||
self._leave_worker.start()
|
||||
|
||||
def _on_leave_finished(self, result) -> None:
|
||||
self._refresh_backend_state()
|
||||
if result.success:
|
||||
msg = result.message
|
||||
if result.needs_reboot:
|
||||
msg += "\n\nUn redémarrage est nécessaire pour finaliser la sortie."
|
||||
QMessageBox.information(self, "Sortie du domaine réussie", msg)
|
||||
else:
|
||||
QMessageBox.critical(self, "Échec de la sortie du domaine", result.message)
|
||||
|
||||
def _on_join_finished(self, result) -> None:
|
||||
self._refresh_backend_state()
|
||||
if result.success:
|
||||
|
||||
Reference in New Issue
Block a user