diff --git a/install/config/config.yml b/install/config/config.yml index 2928b425..2fd9ee68 100644 --- a/install/config/config.yml +++ b/install/config/config.yml @@ -1,5 +1,5 @@ # To see all available options, please visit the docs: -# https://docs.digpangolin.com/self-host/dns-and-networking +# https://docs.digpangolin.com/self-host/advanced/config-file app: dashboard_url: "https://{{.DashboardDomain}}" @@ -36,3 +36,9 @@ flags: disable_signup_without_invite: true disable_user_create_org: false allow_raw_resources: true + +{{if and .HybridMode .HybridId .HybridSecret}} +hybrid: + id: "{{.HybridId}}" + secret: "{{.HybridSecret}}" +{{end}} \ No newline at end of file diff --git a/install/containers.go b/install/containers.go new file mode 100644 index 00000000..cea3a6ef --- /dev/null +++ b/install/containers.go @@ -0,0 +1,332 @@ +package main + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "os/user" + "runtime" + "strconv" + "strings" + "time" +) + +func waitForContainer(containerName string, containerType SupportedContainer) error { + maxAttempts := 30 + retryInterval := time.Second * 2 + + for attempt := 0; attempt < maxAttempts; attempt++ { + // Check if container is running + cmd := exec.Command(string(containerType), "container", "inspect", "-f", "{{.State.Running}}", containerName) + var out bytes.Buffer + cmd.Stdout = &out + + if err := cmd.Run(); err != nil { + // If the container doesn't exist or there's another error, wait and retry + time.Sleep(retryInterval) + continue + } + + isRunning := strings.TrimSpace(out.String()) == "true" + if isRunning { + return nil + } + + // Container exists but isn't running yet, wait and retry + time.Sleep(retryInterval) + } + + return fmt.Errorf("container %s did not start within %v seconds", containerName, maxAttempts*int(retryInterval.Seconds())) +} + +func installDocker() error { + // Detect Linux distribution + cmd := exec.Command("cat", "/etc/os-release") + output, err := cmd.Output() + if err != nil { + return fmt.Errorf("failed to detect Linux distribution: %v", err) + } + osRelease := string(output) + + // Detect system architecture + archCmd := exec.Command("uname", "-m") + archOutput, err := archCmd.Output() + if err != nil { + return fmt.Errorf("failed to detect system architecture: %v", err) + } + arch := strings.TrimSpace(string(archOutput)) + + // Map architecture to Docker's architecture naming + var dockerArch string + switch arch { + case "x86_64": + dockerArch = "amd64" + case "aarch64": + dockerArch = "arm64" + default: + return fmt.Errorf("unsupported architecture: %s", arch) + } + + var installCmd *exec.Cmd + switch { + case strings.Contains(osRelease, "ID=ubuntu"): + installCmd = exec.Command("bash", "-c", fmt.Sprintf(` + apt-get update && + apt-get install -y apt-transport-https ca-certificates curl software-properties-common && + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && + echo "deb [arch=%s signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list && + apt-get update && + apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin + `, dockerArch)) + case strings.Contains(osRelease, "ID=debian"): + installCmd = exec.Command("bash", "-c", fmt.Sprintf(` + apt-get update && + apt-get install -y apt-transport-https ca-certificates curl software-properties-common && + curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && + echo "deb [arch=%s signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list && + apt-get update && + apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin + `, dockerArch)) + case strings.Contains(osRelease, "ID=fedora"): + // Detect Fedora version to handle DNF 5 changes + versionCmd := exec.Command("bash", "-c", "grep VERSION_ID /etc/os-release | cut -d'=' -f2 | tr -d '\"'") + versionOutput, err := versionCmd.Output() + var fedoraVersion int + if err == nil { + if v, parseErr := strconv.Atoi(strings.TrimSpace(string(versionOutput))); parseErr == nil { + fedoraVersion = v + } + } + + // Use appropriate DNF syntax based on version + var repoCmd string + if fedoraVersion >= 41 { + // DNF 5 syntax for Fedora 41+ + repoCmd = "dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo" + } else { + // DNF 4 syntax for Fedora < 41 + repoCmd = "dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo" + } + + installCmd = exec.Command("bash", "-c", fmt.Sprintf(` + dnf -y install dnf-plugins-core && + %s && + dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin + `, repoCmd)) + case strings.Contains(osRelease, "ID=opensuse") || strings.Contains(osRelease, "ID=\"opensuse-"): + installCmd = exec.Command("bash", "-c", ` + zypper install -y docker docker-compose && + systemctl enable docker + `) + case strings.Contains(osRelease, "ID=rhel") || strings.Contains(osRelease, "ID=\"rhel"): + installCmd = exec.Command("bash", "-c", ` + dnf remove -y runc && + dnf -y install yum-utils && + dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo && + dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin && + systemctl enable docker + `) + case strings.Contains(osRelease, "ID=amzn"): + installCmd = exec.Command("bash", "-c", ` + yum update -y && + yum install -y docker && + systemctl enable docker && + usermod -a -G docker ec2-user + `) + default: + return fmt.Errorf("unsupported Linux distribution") + } + + installCmd.Stdout = os.Stdout + installCmd.Stderr = os.Stderr + return installCmd.Run() +} + +func startDockerService() error { + if runtime.GOOS == "linux" { + cmd := exec.Command("systemctl", "enable", "--now", "docker") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() + } else if runtime.GOOS == "darwin" { + // On macOS, Docker is usually started via the Docker Desktop application + fmt.Println("Please start Docker Desktop manually on macOS.") + return nil + } + return fmt.Errorf("unsupported operating system for starting Docker service") +} + +func isDockerInstalled() bool { + return isContainerInstalled("docker") +} + +func isPodmanInstalled() bool { + return isContainerInstalled("podman") && isContainerInstalled("podman-compose") +} + +func isContainerInstalled(container string) bool { + cmd := exec.Command(container, "--version") + if err := cmd.Run(); err != nil { + return false + } + return true +} + +func isUserInDockerGroup() bool { + if runtime.GOOS == "darwin" { + // Docker group is not applicable on macOS + // So we assume that the user can run Docker commands + return true + } + + if os.Geteuid() == 0 { + return true // Root user can run Docker commands anyway + } + + // Check if the current user is in the docker group + if dockerGroup, err := user.LookupGroup("docker"); err == nil { + if currentUser, err := user.Current(); err == nil { + if currentUserGroupIds, err := currentUser.GroupIds(); err == nil { + for _, groupId := range currentUserGroupIds { + if groupId == dockerGroup.Gid { + return true + } + } + } + } + } + + // Eventually, if any of the checks fail, we assume the user cannot run Docker commands + return false +} + +// isDockerRunning checks if the Docker daemon is running by using the `docker info` command. +func isDockerRunning() bool { + cmd := exec.Command("docker", "info") + if err := cmd.Run(); err != nil { + return false + } + return true +} + +// executeDockerComposeCommandWithArgs executes the appropriate docker command with arguments supplied +func executeDockerComposeCommandWithArgs(args ...string) error { + var cmd *exec.Cmd + var useNewStyle bool + + if !isDockerInstalled() { + return fmt.Errorf("docker is not installed") + } + + checkCmd := exec.Command("docker", "compose", "version") + if err := checkCmd.Run(); err == nil { + useNewStyle = true + } else { + checkCmd = exec.Command("docker-compose", "version") + if err := checkCmd.Run(); err == nil { + useNewStyle = false + } else { + return fmt.Errorf("neither 'docker compose' nor 'docker-compose' command is available") + } + } + + if useNewStyle { + cmd = exec.Command("docker", append([]string{"compose"}, args...)...) + } else { + cmd = exec.Command("docker-compose", args...) + } + + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +// pullContainers pulls the containers using the appropriate command. +func pullContainers(containerType SupportedContainer) error { + fmt.Println("Pulling the container images...") + if containerType == Podman { + if err := run("podman-compose", "-f", "docker-compose.yml", "pull"); err != nil { + return fmt.Errorf("failed to pull the containers: %v", err) + } + + return nil + } + + if containerType == Docker { + if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "pull", "--policy", "always"); err != nil { + return fmt.Errorf("failed to pull the containers: %v", err) + } + + return nil + } + + return fmt.Errorf("Unsupported container type: %s", containerType) +} + +// startContainers starts the containers using the appropriate command. +func startContainers(containerType SupportedContainer) error { + fmt.Println("Starting containers...") + + if containerType == Podman { + if err := run("podman-compose", "-f", "docker-compose.yml", "up", "-d", "--force-recreate"); err != nil { + return fmt.Errorf("failed start containers: %v", err) + } + + return nil + } + + if containerType == Docker { + if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "up", "-d", "--force-recreate"); err != nil { + return fmt.Errorf("failed to start containers: %v", err) + } + + return nil + } + + return fmt.Errorf("Unsupported container type: %s", containerType) +} + +// stopContainers stops the containers using the appropriate command. +func stopContainers(containerType SupportedContainer) error { + fmt.Println("Stopping containers...") + if containerType == Podman { + if err := run("podman-compose", "-f", "docker-compose.yml", "down"); err != nil { + return fmt.Errorf("failed to stop containers: %v", err) + } + + return nil + } + + if containerType == Docker { + if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "down"); err != nil { + return fmt.Errorf("failed to stop containers: %v", err) + } + + return nil + } + + return fmt.Errorf("Unsupported container type: %s", containerType) +} + +// restartContainer restarts a specific container using the appropriate command. +func restartContainer(container string, containerType SupportedContainer) error { + fmt.Println("Restarting containers...") + if containerType == Podman { + if err := run("podman-compose", "-f", "docker-compose.yml", "restart"); err != nil { + return fmt.Errorf("failed to stop the container \"%s\": %v", container, err) + } + + return nil + } + + if containerType == Docker { + if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "restart", container); err != nil { + return fmt.Errorf("failed to stop the container \"%s\": %v", container, err) + } + + return nil + } + + return fmt.Errorf("Unsupported container type: %s", containerType) +} diff --git a/install/input.go b/install/input.go new file mode 100644 index 00000000..cf8fd7a3 --- /dev/null +++ b/install/input.go @@ -0,0 +1,74 @@ +package main + +import ( + "bufio" + "fmt" + "strings" + "syscall" + + "golang.org/x/term" +) + +func readString(reader *bufio.Reader, prompt string, defaultValue string) string { + if defaultValue != "" { + fmt.Printf("%s (default: %s): ", prompt, defaultValue) + } else { + fmt.Print(prompt + ": ") + } + input, _ := reader.ReadString('\n') + input = strings.TrimSpace(input) + if input == "" { + return defaultValue + } + return input +} + +func readStringNoDefault(reader *bufio.Reader, prompt string) string { + fmt.Print(prompt + ": ") + input, _ := reader.ReadString('\n') + return strings.TrimSpace(input) +} + +func readPassword(prompt string, reader *bufio.Reader) string { + if term.IsTerminal(int(syscall.Stdin)) { + fmt.Print(prompt + ": ") + // Read password without echo if we're in a terminal + password, err := term.ReadPassword(int(syscall.Stdin)) + fmt.Println() // Add a newline since ReadPassword doesn't add one + if err != nil { + return "" + } + input := strings.TrimSpace(string(password)) + if input == "" { + return readPassword(prompt, reader) + } + return input + } else { + // Fallback to reading from stdin if not in a terminal + return readString(reader, prompt, "") + } +} + +func readBool(reader *bufio.Reader, prompt string, defaultValue bool) bool { + defaultStr := "no" + if defaultValue { + defaultStr = "yes" + } + input := readString(reader, prompt+" (yes/no)", defaultStr) + return strings.ToLower(input) == "yes" +} + +func readBoolNoDefault(reader *bufio.Reader, prompt string) bool { + input := readStringNoDefault(reader, prompt+" (yes/no)") + return strings.ToLower(input) == "yes" +} + +func readInt(reader *bufio.Reader, prompt string, defaultValue int) int { + input := readString(reader, prompt, fmt.Sprintf("%d", defaultValue)) + if input == "" { + return defaultValue + } + value := defaultValue + fmt.Sscanf(input, "%d", &value) + return value +} diff --git a/install/main.go b/install/main.go index 55eab5e3..8b5284f7 100644 --- a/install/main.go +++ b/install/main.go @@ -10,17 +10,12 @@ import ( "math/rand" "os" "os/exec" - "os/user" "path/filepath" "runtime" - "strconv" "strings" - "syscall" "text/template" "time" "net" - - "golang.org/x/term" ) // DO NOT EDIT THIS FUNCTION; IT MATCHED BY REGEX IN CICD @@ -52,7 +47,9 @@ type Config struct { TraefikBouncerKey string DoCrowdsecInstall bool Secret string - HybridMode bool + HybridMode bool + HybridId string + HybridSecret string } type SupportedContainer string @@ -308,70 +305,6 @@ func podmanOrDocker(reader *bufio.Reader) SupportedContainer { return chosenContainer } -func readString(reader *bufio.Reader, prompt string, defaultValue string) string { - if defaultValue != "" { - fmt.Printf("%s (default: %s): ", prompt, defaultValue) - } else { - fmt.Print(prompt + ": ") - } - input, _ := reader.ReadString('\n') - input = strings.TrimSpace(input) - if input == "" { - return defaultValue - } - return input -} - -func readStringNoDefault(reader *bufio.Reader, prompt string) string { - fmt.Print(prompt + ": ") - input, _ := reader.ReadString('\n') - return strings.TrimSpace(input) -} - -func readPassword(prompt string, reader *bufio.Reader) string { - if term.IsTerminal(int(syscall.Stdin)) { - fmt.Print(prompt + ": ") - // Read password without echo if we're in a terminal - password, err := term.ReadPassword(int(syscall.Stdin)) - fmt.Println() // Add a newline since ReadPassword doesn't add one - if err != nil { - return "" - } - input := strings.TrimSpace(string(password)) - if input == "" { - return readPassword(prompt, reader) - } - return input - } else { - // Fallback to reading from stdin if not in a terminal - return readString(reader, prompt, "") - } -} - -func readBool(reader *bufio.Reader, prompt string, defaultValue bool) bool { - defaultStr := "no" - if defaultValue { - defaultStr = "yes" - } - input := readString(reader, prompt+" (yes/no)", defaultStr) - return strings.ToLower(input) == "yes" -} - -func readBoolNoDefault(reader *bufio.Reader, prompt string) bool { - input := readStringNoDefault(reader, prompt+" (yes/no)") - return strings.ToLower(input) == "yes" -} - -func readInt(reader *bufio.Reader, prompt string, defaultValue int) int { - input := readString(reader, prompt, fmt.Sprintf("%d", defaultValue)) - if input == "" { - return defaultValue - } - value := defaultValue - fmt.Sscanf(input, "%d", &value) - return value -} - func collectUserInput(reader *bufio.Reader) Config { config := Config{} @@ -379,6 +312,15 @@ func collectUserInput(reader *bufio.Reader) Config { fmt.Println("\n=== Basic Configuration ===") config.HybridMode = readBoolNoDefault(reader, "Do you want to use hybrid mode?") + if config.HybridMode { + alreadyHaveCreds := readBool(reader, "Do you already have credentials from the dashboard?", false) + + if alreadyHaveCreds { + config.HybridId = readString(reader, "Enter your hybrid ID", "") + config.HybridSecret = readString(reader, "Enter your hybrid secret", "") + } + } + if !config.HybridMode { config.BaseDomain = readString(reader, "Enter your base domain (no subdomain e.g. example.com)", "") @@ -501,298 +443,6 @@ func createConfigFiles(config Config) error { return nil } - -func installDocker() error { - // Detect Linux distribution - cmd := exec.Command("cat", "/etc/os-release") - output, err := cmd.Output() - if err != nil { - return fmt.Errorf("failed to detect Linux distribution: %v", err) - } - osRelease := string(output) - - // Detect system architecture - archCmd := exec.Command("uname", "-m") - archOutput, err := archCmd.Output() - if err != nil { - return fmt.Errorf("failed to detect system architecture: %v", err) - } - arch := strings.TrimSpace(string(archOutput)) - - // Map architecture to Docker's architecture naming - var dockerArch string - switch arch { - case "x86_64": - dockerArch = "amd64" - case "aarch64": - dockerArch = "arm64" - default: - return fmt.Errorf("unsupported architecture: %s", arch) - } - - var installCmd *exec.Cmd - switch { - case strings.Contains(osRelease, "ID=ubuntu"): - installCmd = exec.Command("bash", "-c", fmt.Sprintf(` - apt-get update && - apt-get install -y apt-transport-https ca-certificates curl software-properties-common && - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && - echo "deb [arch=%s signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list && - apt-get update && - apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin - `, dockerArch)) - case strings.Contains(osRelease, "ID=debian"): - installCmd = exec.Command("bash", "-c", fmt.Sprintf(` - apt-get update && - apt-get install -y apt-transport-https ca-certificates curl software-properties-common && - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && - echo "deb [arch=%s signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list && - apt-get update && - apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin - `, dockerArch)) - case strings.Contains(osRelease, "ID=fedora"): - // Detect Fedora version to handle DNF 5 changes - versionCmd := exec.Command("bash", "-c", "grep VERSION_ID /etc/os-release | cut -d'=' -f2 | tr -d '\"'") - versionOutput, err := versionCmd.Output() - var fedoraVersion int - if err == nil { - if v, parseErr := strconv.Atoi(strings.TrimSpace(string(versionOutput))); parseErr == nil { - fedoraVersion = v - } - } - - // Use appropriate DNF syntax based on version - var repoCmd string - if fedoraVersion >= 41 { - // DNF 5 syntax for Fedora 41+ - repoCmd = "dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo" - } else { - // DNF 4 syntax for Fedora < 41 - repoCmd = "dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo" - } - - installCmd = exec.Command("bash", "-c", fmt.Sprintf(` - dnf -y install dnf-plugins-core && - %s && - dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin - `, repoCmd)) - case strings.Contains(osRelease, "ID=opensuse") || strings.Contains(osRelease, "ID=\"opensuse-"): - installCmd = exec.Command("bash", "-c", ` - zypper install -y docker docker-compose && - systemctl enable docker - `) - case strings.Contains(osRelease, "ID=rhel") || strings.Contains(osRelease, "ID=\"rhel"): - installCmd = exec.Command("bash", "-c", ` - dnf remove -y runc && - dnf -y install yum-utils && - dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo && - dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin && - systemctl enable docker - `) - case strings.Contains(osRelease, "ID=amzn"): - installCmd = exec.Command("bash", "-c", ` - yum update -y && - yum install -y docker && - systemctl enable docker && - usermod -a -G docker ec2-user - `) - default: - return fmt.Errorf("unsupported Linux distribution") - } - - installCmd.Stdout = os.Stdout - installCmd.Stderr = os.Stderr - return installCmd.Run() -} - -func startDockerService() error { - if runtime.GOOS == "linux" { - cmd := exec.Command("systemctl", "enable", "--now", "docker") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() - } else if runtime.GOOS == "darwin" { - // On macOS, Docker is usually started via the Docker Desktop application - fmt.Println("Please start Docker Desktop manually on macOS.") - return nil - } - return fmt.Errorf("unsupported operating system for starting Docker service") -} - -func isDockerInstalled() bool { - return isContainerInstalled("docker") -} - -func isPodmanInstalled() bool { - return isContainerInstalled("podman") && isContainerInstalled("podman-compose") -} - -func isContainerInstalled(container string) bool { - cmd := exec.Command(container, "--version") - if err := cmd.Run(); err != nil { - return false - } - return true -} - -func isUserInDockerGroup() bool { - if runtime.GOOS == "darwin" { - // Docker group is not applicable on macOS - // So we assume that the user can run Docker commands - return true - } - - if os.Geteuid() == 0 { - return true // Root user can run Docker commands anyway - } - - // Check if the current user is in the docker group - if dockerGroup, err := user.LookupGroup("docker"); err == nil { - if currentUser, err := user.Current(); err == nil { - if currentUserGroupIds, err := currentUser.GroupIds(); err == nil { - for _, groupId := range currentUserGroupIds { - if groupId == dockerGroup.Gid { - return true - } - } - } - } - } - - // Eventually, if any of the checks fail, we assume the user cannot run Docker commands - return false -} - -// isDockerRunning checks if the Docker daemon is running by using the `docker info` command. -func isDockerRunning() bool { - cmd := exec.Command("docker", "info") - if err := cmd.Run(); err != nil { - return false - } - return true -} - -// executeDockerComposeCommandWithArgs executes the appropriate docker command with arguments supplied -func executeDockerComposeCommandWithArgs(args ...string) error { - var cmd *exec.Cmd - var useNewStyle bool - - if !isDockerInstalled() { - return fmt.Errorf("docker is not installed") - } - - checkCmd := exec.Command("docker", "compose", "version") - if err := checkCmd.Run(); err == nil { - useNewStyle = true - } else { - checkCmd = exec.Command("docker-compose", "version") - if err := checkCmd.Run(); err == nil { - useNewStyle = false - } else { - return fmt.Errorf("neither 'docker compose' nor 'docker-compose' command is available") - } - } - - if useNewStyle { - cmd = exec.Command("docker", append([]string{"compose"}, args...)...) - } else { - cmd = exec.Command("docker-compose", args...) - } - - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() -} - -// pullContainers pulls the containers using the appropriate command. -func pullContainers(containerType SupportedContainer) error { - fmt.Println("Pulling the container images...") - if containerType == Podman { - if err := run("podman-compose", "-f", "docker-compose.yml", "pull"); err != nil { - return fmt.Errorf("failed to pull the containers: %v", err) - } - - return nil - } - - if containerType == Docker { - if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "pull", "--policy", "always"); err != nil { - return fmt.Errorf("failed to pull the containers: %v", err) - } - - return nil - } - - return fmt.Errorf("Unsupported container type: %s", containerType) -} - -// startContainers starts the containers using the appropriate command. -func startContainers(containerType SupportedContainer) error { - fmt.Println("Starting containers...") - - if containerType == Podman { - if err := run("podman-compose", "-f", "docker-compose.yml", "up", "-d", "--force-recreate"); err != nil { - return fmt.Errorf("failed start containers: %v", err) - } - - return nil - } - - if containerType == Docker { - if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "up", "-d", "--force-recreate"); err != nil { - return fmt.Errorf("failed to start containers: %v", err) - } - - return nil - } - - return fmt.Errorf("Unsupported container type: %s", containerType) -} - -// stopContainers stops the containers using the appropriate command. -func stopContainers(containerType SupportedContainer) error { - fmt.Println("Stopping containers...") - if containerType == Podman { - if err := run("podman-compose", "-f", "docker-compose.yml", "down"); err != nil { - return fmt.Errorf("failed to stop containers: %v", err) - } - - return nil - } - - if containerType == Docker { - if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "down"); err != nil { - return fmt.Errorf("failed to stop containers: %v", err) - } - - return nil - } - - return fmt.Errorf("Unsupported container type: %s", containerType) -} - -// restartContainer restarts a specific container using the appropriate command. -func restartContainer(container string, containerType SupportedContainer) error { - fmt.Println("Restarting containers...") - if containerType == Podman { - if err := run("podman-compose", "-f", "docker-compose.yml", "restart"); err != nil { - return fmt.Errorf("failed to stop the container \"%s\": %v", container, err) - } - - return nil - } - - if containerType == Docker { - if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "restart", container); err != nil { - return fmt.Errorf("failed to stop the container \"%s\": %v", container, err) - } - - return nil - } - - return fmt.Errorf("Unsupported container type: %s", containerType) -} - func copyFile(src, dst string) error { source, err := os.Open(src) if err != nil { @@ -818,34 +468,6 @@ func moveFile(src, dst string) error { return os.Remove(src) } -func waitForContainer(containerName string, containerType SupportedContainer) error { - maxAttempts := 30 - retryInterval := time.Second * 2 - - for attempt := 0; attempt < maxAttempts; attempt++ { - // Check if container is running - cmd := exec.Command(string(containerType), "container", "inspect", "-f", "{{.State.Running}}", containerName) - var out bytes.Buffer - cmd.Stdout = &out - - if err := cmd.Run(); err != nil { - // If the container doesn't exist or there's another error, wait and retry - time.Sleep(retryInterval) - continue - } - - isRunning := strings.TrimSpace(out.String()) == "true" - if isRunning { - return nil - } - - // Container exists but isn't running yet, wait and retry - time.Sleep(retryInterval) - } - - return fmt.Errorf("container %s did not start within %v seconds", containerName, maxAttempts*int(retryInterval.Seconds())) -} - func printSetupToken(containerType SupportedContainer, dashboardDomain string) { fmt.Println("Waiting for Pangolin to generate setup token...")