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(" 8. Reset web admin password")
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(" 0. System info")
fmt.Println(" q. Quit")
@@ -330,9 +330,9 @@ func isWebPanelRunning() bool {
}
func cliImportExistingContainers() {
fmt.Println("\n--- Import existing CLICD containers ---")
fmt.Println("This imports LXC containers named ct-{id} 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("\n--- Import existing LXC containers ---")
fmt.Println("This imports containers from /var/lib/lxc into CLICD config.")
fmt.Println("Imported containers keep their real LXC name so Web and CLI manage the same container.")
imported, err := manager.ImportExistingClicdContainers()
if err != nil {
+4
View File
@@ -68,6 +68,7 @@ type Container struct {
ID int `json:"id"`
UUID string `json:"uuid"`
Name string `json:"name"`
LXCName string `json:"lxc_name,omitempty"`
Template string `json:"template"`
VCPU float64 `json:"vcpu"`
RAMMB int `json:"ram_mb"`
@@ -97,6 +98,9 @@ type Container struct {
// LxcName returns the internal LXC container name (ct-{id})
func (c *Container) LxcName() string {
if c.LXCName != "" {
return c.LXCName
}
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
}
// ImportExistingClicdContainers imports LXC containers named ct-{id} into the
// CLICD config. Containers with arbitrary LXC names cannot be imported because
// CLICD derives the runtime LXC name from the numeric container ID.
// ImportExistingClicdContainers imports existing LXC containers into the CLICD
// config. Native CLICD containers keep ct-{id}; arbitrary LXC names are stored
// in Container.LXCName so Web and CLI can manage the same imported container.
func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
entries, err := os.ReadDir(m.LxcPath)
if err != nil {
@@ -1926,10 +1926,12 @@ func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
existingIDs := make(map[int]bool)
existingNames := make(map[string]bool)
existingLXCNames := make(map[string]bool)
maxID := config.AppConfig.NextContainerID - 1
for _, c := range config.AppConfig.Containers {
existingIDs[c.ID] = true
existingNames[c.Name] = true
existingLXCNames[c.LxcName()] = true
if c.ID > maxID {
maxID = c.ID
}
@@ -1941,22 +1943,30 @@ func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
if !entry.IsDir() {
continue
}
matches := re.FindStringSubmatch(entry.Name())
if len(matches) != 2 {
lxcName := entry.Name()
if existingLXCNames[lxcName] {
continue
}
id, err := strconv.Atoi(matches[1])
if err != nil || id <= 0 || existingIDs[id] {
continue
id := 0
if matches := re.FindStringSubmatch(lxcName); len(matches) == 2 {
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] {
name = fmt.Sprintf("imported-%d", id)
}
status, err := m.GetContainerStatus(entry.Name())
status, err := m.GetContainerStatus(lxcName)
if err != nil || status == "" {
status = "unknown"
}
@@ -1965,6 +1975,7 @@ func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
ID: id,
UUID: config.NewContainerUUID(),
Name: name,
LXCName: lxcName,
Template: "imported",
VCPU: 1,
RAMMB: 512,
@@ -1978,7 +1989,7 @@ func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
}
if status == "running" {
if ip, err := m.GetContainerIP(entry.Name()); err == nil {
if ip, err := m.GetContainerIP(lxcName); err == nil {
c.IP = ip
}
}
@@ -1987,6 +1998,7 @@ func (m *Manager) ImportExistingClicdContainers() ([]config.Container, error) {
imported = append(imported, c)
existingIDs[id] = true
existingNames[name] = true
existingLXCNames[lxcName] = true
if id > maxID {
maxID = id
}
+11 -1
View File
@@ -416,7 +416,17 @@ download_release_if_needed() {
}
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
log "Installed binary: /usr/local/bin/clicd"
}