From eedb2d7fb0647344868660c194cfdc5d86d6bf19 Mon Sep 17 00:00:00 2001 From: MengMengCode <227010654+MengMengCode@users.noreply.github.com> Date: Wed, 10 Jun 2026 14:51:22 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E5=B7=B2=E7=9F=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/cli/cli.go | 2 +- backend/internal/kvm/kvm.go | 56 +++++++++++++++++++++++++- frontend/index.html | 2 +- frontend/src/pages/ContainerDetail.tsx | 13 +++++- frontend/src/pages/Containers.tsx | 16 ++++++-- frontend/src/pages/Login.tsx | 2 +- 6 files changed, 81 insertions(+), 10 deletions(-) diff --git a/backend/internal/cli/cli.go b/backend/internal/cli/cli.go index ca4588d..3d26060 100644 --- a/backend/internal/cli/cli.go +++ b/backend/internal/cli/cli.go @@ -34,7 +34,7 @@ var cliTranslations = map[string]string{ "请选择操作": "Select an action", "再见": "Goodbye", "无效选择": "Invalid choice", - "CLICD - LXC 容器管理器": "CLICD - LXC Container Manager", + "CLICD - LXC 容器管理器": "CLICD - Container Manager", "Web 面板": "Web panel", "端口": "port", "运行中": "running", diff --git a/backend/internal/kvm/kvm.go b/backend/internal/kvm/kvm.go index 7eabacf..bbee6f8 100644 --- a/backend/internal/kvm/kvm.go +++ b/backend/internal/kvm/kvm.go @@ -588,7 +588,7 @@ func (m *Manager) StartContainer(id int) error { } } } - config.UpdateContainerStatus(id, "running") + config.UpdateContainerStatus(id, "initializing") // Detect VNC port if _, err := m.RefreshVNCPort(id); err != nil { fmt.Printf("Warning: failed to refresh VNC port for %s: %v\n", name, err) @@ -625,6 +625,11 @@ func (m *Manager) StartContainer(id int) error { return err } } + // Wait for cloud-init to finish and SSH to be reachable (password-only mode) + if !isWindows && c.IP != "" { + m.waitForCloudInitReady(name, c.IP, c.SSHPassword) + } + config.UpdateContainerStatus(id, "running") if c.IPv6 != "" || len(c.IPv6Addresses) > 0 { if err := m.applyIPv6Runtime(c); err != nil { return err @@ -635,6 +640,50 @@ func (m *Manager) StartContainer(id int) error { return nil } +// waitForCloudInitReady waits for cloud-init to finish and SSH to be reachable. +func (m *Manager) waitForCloudInitReady(vmName, ip, password string) { + if ip == "" || password == "" { + return + } + deadline := time.Now().Add(3 * time.Minute) + target := net.JoinHostPort(ip, "22") + sshWasUp := false + qgaAttempted := false + + for time.Now().Before(deadline) { + client, err := ssh.Dial("tcp", target, &ssh.ClientConfig{ + User: "root", + Auth: []ssh.AuthMethod{ssh.Password(password)}, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + Timeout: 5 * time.Second, + }) + if err == nil { + client.Close() + if !sshWasUp { + sshWasUp = true + fmt.Printf("KVM %s SSH up, waiting for cloud-init to settle...\n", vmName) + time.Sleep(10 * time.Second) + continue + } + fmt.Printf("KVM %s ready\n", vmName) + return + } + + // Try guest agent ONCE to speed things up, with timeout to avoid blocking + if !qgaAttempted && qemuGuestPing(vmName) == nil { + qgaAttempted = true + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + cmd := exec.CommandContext(ctx, "virsh", "qemu-agent-command", vmName, + `{"execute":"guest-exec","arguments":{"path":"/bin/sh","arg":["-c","cloud-init status --wait 2>/dev/null; systemctl restart sshd 2>/dev/null || systemctl restart ssh 2>/dev/null; true"],"capture-output":false}}`) + cmd.Run() + cancel() + } + + time.Sleep(5 * time.Second) + } + fmt.Printf("Warning: KVM %s not ready after 3 minutes\n", vmName) +} + func (m *Manager) StopContainer(id int) error { c := config.FindContainer(id) if c == nil { @@ -2530,7 +2579,10 @@ if [ -n "$SSH_PUBLIC_KEY" ]; then chown -R root:root /root/.ssh 2>/dev/null || true fi if command -v chpasswd >/dev/null 2>&1; then - printf 'root:%s\n' "$ROOT_PASSWORD" | chpasswd || true + printf 'root:%s\n' "$ROOT_PASSWORD" | chpasswd 2>/tmp/clicd-chpasswd.log && echo "root password set via chpasswd" || echo "WARNING: chpasswd failed: $(cat /tmp/clicd-chpasswd.log 2>/dev/null)" +elif command -v openssl >/dev/null 2>&1 && command -v usermod >/dev/null 2>&1; then + HASH=$(echo "$ROOT_PASSWORD" | openssl passwd -6 -stdin 2>/dev/null) + [ -n "$HASH" ] && usermod -p "$HASH" root 2>/dev/null && echo "root password set via openssl/usermod" || echo "WARNING: openssl/usermod failed" fi ssh-keygen -A >/dev/null 2>&1 || true if command -v systemctl >/dev/null 2>&1; then diff --git a/frontend/index.html b/frontend/index.html index 5c1f271..2a91b89 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,7 @@ -