Compare commits

...

2 Commits

Author SHA1 Message Date
MengMengCode a2da61e076 Install binary with atomic replacement 2026-06-05 20:03:16 +08:00
MengMengCode 49a6981e28 Import existing LXC containers into CLICD 2026-06-05 20:01:24 +08:00
4 changed files with 42 additions and 16 deletions
+4 -4
View File
@@ -113,7 +113,7 @@ func printMenu() {
fmt.Println(" 7. Reinstall container") fmt.Println(" 7. Reinstall container")
fmt.Println(" 8. Reset web admin password") fmt.Println(" 8. Reset web admin password")
fmt.Printf(" 9. %s web panel\n", webStatus) fmt.Printf(" 9. %s web panel\n", webStatus)
fmt.Println(" 10. Import existing ct-* containers") fmt.Println(" 10. Import existing LXC containers")
fmt.Println(" 11. Uninstall CLICD") fmt.Println(" 11. Uninstall CLICD")
fmt.Println(" 0. System info") fmt.Println(" 0. System info")
fmt.Println(" q. Quit") fmt.Println(" q. Quit")
@@ -330,9 +330,9 @@ func isWebPanelRunning() bool {
} }
func cliImportExistingContainers() { func cliImportExistingContainers() {
fmt.Println("\n--- Import existing CLICD containers ---") fmt.Println("\n--- Import existing LXC containers ---")
fmt.Println("This imports LXC containers named ct-{id} from /var/lib/lxc into CLICD config.") fmt.Println("This imports containers from /var/lib/lxc into CLICD config.")
fmt.Println("Containers with names like ubuntu or alpine are skipped because CLICD requires ct-{id}.") fmt.Println("Imported containers keep their real LXC name so Web and CLI manage the same container.")
imported, err := manager.ImportExistingClicdContainers() imported, err := manager.ImportExistingClicdContainers()
if err != nil { if err != nil {
+4
View File
@@ -68,6 +68,7 @@ type Container struct {
ID int `json:"id"` ID int `json:"id"`
UUID string `json:"uuid"` UUID string `json:"uuid"`
Name string `json:"name"` Name string `json:"name"`
LXCName string `json:"lxc_name,omitempty"`
Template string `json:"template"` Template string `json:"template"`
VCPU float64 `json:"vcpu"` VCPU float64 `json:"vcpu"`
RAMMB int `json:"ram_mb"` RAMMB int `json:"ram_mb"`
@@ -97,6 +98,9 @@ type Container struct {
// LxcName returns the internal LXC container name (ct-{id}) // LxcName returns the internal LXC container name (ct-{id})
func (c *Container) LxcName() string { func (c *Container) LxcName() string {
if c.LXCName != "" {
return c.LXCName
}
return fmt.Sprintf("ct-%d", c.ID) return fmt.Sprintf("ct-%d", c.ID)
} }
+23 -11
View File
@@ -1915,9 +1915,9 @@ func (m *Manager) ListContainers() ([]config.Container, error) {
return containers, nil return containers, nil
} }
// ImportExistingClicdContainers imports LXC containers named ct-{id} into the // ImportExistingClicdContainers imports existing LXC containers into the CLICD
// CLICD config. Containers with arbitrary LXC names cannot be imported because // config. Native CLICD containers keep ct-{id}; arbitrary LXC names are stored
// CLICD derives the runtime LXC name from the numeric container ID. // in Container.LXCName so Web and CLI can manage the same imported container.
func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) { func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
entries, err := os.ReadDir(m.LxcPath) entries, err := os.ReadDir(m.LxcPath)
if err != nil { if err != nil {
@@ -1926,10 +1926,12 @@ func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
existingIDs := make(map[int]bool) existingIDs := make(map[int]bool)
existingNames := make(map[string]bool) existingNames := make(map[string]bool)
existingLXCNames := make(map[string]bool)
maxID := config.AppConfig.NextContainerID - 1 maxID := config.AppConfig.NextContainerID - 1
for _, c := range config.AppConfig.Containers { for _, c := range config.AppConfig.Containers {
existingIDs[c.ID] = true existingIDs[c.ID] = true
existingNames[c.Name] = true existingNames[c.Name] = true
existingLXCNames[c.LxcName()] = true
if c.ID > maxID { if c.ID > maxID {
maxID = c.ID maxID = c.ID
} }
@@ -1941,22 +1943,30 @@ func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
if !entry.IsDir() { if !entry.IsDir() {
continue continue
} }
matches := re.FindStringSubmatch(entry.Name()) lxcName := entry.Name()
if len(matches) != 2 { if existingLXCNames[lxcName] {
continue continue
} }
id, err := strconv.Atoi(matches[1]) id := 0
if err != nil || id <= 0 || existingIDs[id] { if matches := re.FindStringSubmatch(lxcName); len(matches) == 2 {
continue if parsed, err := strconv.Atoi(matches[1]); err == nil && parsed > 0 && !existingIDs[parsed] {
id = parsed
}
}
if id == 0 {
id = maxID + 1
for existingIDs[id] {
id++
}
} }
name := entry.Name() name := lxcName
if existingNames[name] { if existingNames[name] {
name = fmt.Sprintf("imported-%d", id) name = fmt.Sprintf("imported-%d", id)
} }
status, err := m.GetContainerStatus(entry.Name()) status, err := m.GetContainerStatus(lxcName)
if err != nil || status == "" { if err != nil || status == "" {
status = "unknown" status = "unknown"
} }
@@ -1965,6 +1975,7 @@ func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
ID: id, ID: id,
UUID: config.NewContainerUUID(), UUID: config.NewContainerUUID(),
Name: name, Name: name,
LXCName: lxcName,
Template: "imported", Template: "imported",
VCPU: 1, VCPU: 1,
RAMMB: 512, RAMMB: 512,
@@ -1978,7 +1989,7 @@ func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
} }
if status == "running" { if status == "running" {
if ip, err := m.GetContainerIP(entry.Name()); err == nil { if ip, err := m.GetContainerIP(lxcName); err == nil {
c.IP = ip c.IP = ip
} }
} }
@@ -1987,6 +1998,7 @@ func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
imported = append(imported, c) imported = append(imported, c)
existingIDs[id] = true existingIDs[id] = true
existingNames[name] = true existingNames[name] = true
existingLXCNames[lxcName] = true
if id > maxID { if id > maxID {
maxID = id maxID = id
} }
+11 -1
View File
@@ -416,7 +416,17 @@ download_release_if_needed() {
} }
install_binary() { install_binary() {
cp ./clicd /usr/local/bin/clicd if has_cmd systemctl; then
systemctl stop clicd >/dev/null 2>&1 || true
fi
if has_cmd rc-service; then
rc-service clicd stop >/dev/null 2>&1 || true
fi
tmp_bin="/usr/local/bin/clicd.new.$$"
cp ./clicd "$tmp_bin"
chmod +x "$tmp_bin"
mv -f "$tmp_bin" /usr/local/bin/clicd
chmod +x /usr/local/bin/clicd chmod +x /usr/local/bin/clicd
log "Installed binary: /usr/local/bin/clicd" log "Installed binary: /usr/local/bin/clicd"
} }