mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-30 06:29:23 +02:00
Add setup script
This commit is contained in:
parent
af31ed66ba
commit
5673530356
11 changed files with 556 additions and 1 deletions
296
install/main.go
Normal file
296
install/main.go
Normal file
|
@ -0,0 +1,296 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
//go:embed fs/*
|
||||
var configFiles embed.FS
|
||||
|
||||
type Config struct {
|
||||
Domain string `yaml:"domain"`
|
||||
LetsEncryptEmail string `yaml:"letsEncryptEmail"`
|
||||
AdminUserEmail string `yaml:"adminUserEmail"`
|
||||
AdminUserPassword string `yaml:"adminUserPassword"`
|
||||
DisableSignupWithoutInvite bool `yaml:"disableSignupWithoutInvite"`
|
||||
DisableUserCreateOrg bool `yaml:"disableUserCreateOrg"`
|
||||
EnableEmail bool `yaml:"enableEmail"`
|
||||
EmailSMTPHost string `yaml:"emailSMTPHost"`
|
||||
EmailSMTPPort int `yaml:"emailSMTPPort"`
|
||||
EmailSMTPUser string `yaml:"emailSMTPUser"`
|
||||
EmailSMTPPass string `yaml:"emailSMTPPass"`
|
||||
EmailNoReply string `yaml:"emailNoReply"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
config := collectUserInput(reader)
|
||||
createConfigFiles(config)
|
||||
|
||||
if !isDockerInstalled() && runtime.GOOS == "linux" {
|
||||
if shouldInstallDocker() {
|
||||
// ask user if they want to install docker
|
||||
if readBool(reader, "Would you like to install Docker?", true) {
|
||||
installDocker()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isDockerInstalled() {
|
||||
if readBool(reader, "Would you like to install and start the containers?", true) {
|
||||
pullAndStartContainers()
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Installation complete!")
|
||||
}
|
||||
|
||||
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 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 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{}
|
||||
|
||||
// Basic configuration
|
||||
fmt.Println("\n=== Basic Configuration ===")
|
||||
config.Domain = readString(reader, "Enter your domain name", "")
|
||||
config.LetsEncryptEmail = readString(reader, "Enter email for Let's Encrypt certificates", "")
|
||||
|
||||
// Admin user configuration
|
||||
fmt.Println("\n=== Admin User Configuration ===")
|
||||
config.AdminUserEmail = readString(reader, "Enter admin user email", "admin@"+config.Domain)
|
||||
config.AdminUserPassword = readString(reader, "Enter admin user password", "")
|
||||
|
||||
// Security settings
|
||||
fmt.Println("\n=== Security Settings ===")
|
||||
config.DisableSignupWithoutInvite = readBool(reader, "Disable signup without invite", true)
|
||||
config.DisableUserCreateOrg = readBool(reader, "Disable users from creating organizations", false)
|
||||
|
||||
// Email configuration
|
||||
fmt.Println("\n=== Email Configuration ===")
|
||||
config.EnableEmail = readBool(reader, "Enable email functionality", false)
|
||||
|
||||
if config.EnableEmail {
|
||||
config.EmailSMTPHost = readString(reader, "Enter SMTP host: ", "")
|
||||
config.EmailSMTPPort = readInt(reader, "Enter SMTP port (default 587): ", 587)
|
||||
config.EmailSMTPUser = readString(reader, "Enter SMTP username: ", "")
|
||||
config.EmailSMTPPass = readString(reader, "Enter SMTP password: ", "")
|
||||
config.EmailNoReply = readString(reader, "Enter no-reply email address: ", "")
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
if config.Domain == "" {
|
||||
fmt.Println("Error: Domain name is required")
|
||||
os.Exit(1)
|
||||
}
|
||||
if config.LetsEncryptEmail == "" {
|
||||
fmt.Println("Error: Let's Encrypt email is required")
|
||||
os.Exit(1)
|
||||
}
|
||||
if config.AdminUserEmail == "" || config.AdminUserPassword == "" {
|
||||
fmt.Println("Error: Admin user email and password are required")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func createConfigFiles(config Config) error {
|
||||
os.MkdirAll("config", 0755)
|
||||
os.MkdirAll("config/letsencrypt", 0755)
|
||||
os.MkdirAll("config/db", 0755)
|
||||
os.MkdirAll("config/logs", 0755)
|
||||
|
||||
// Walk through all embedded files
|
||||
err := fs.WalkDir(configFiles, "fs", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Skip the root fs directory itself
|
||||
if path == "fs" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get the relative path by removing the "fs/" prefix
|
||||
relPath := strings.TrimPrefix(path, "fs/")
|
||||
|
||||
// Create the full output path under "config/"
|
||||
outPath := filepath.Join("config", relPath)
|
||||
|
||||
if d.IsDir() {
|
||||
// Create directory
|
||||
if err := os.MkdirAll(outPath, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create directory %s: %v", outPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read the template file
|
||||
content, err := configFiles.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read %s: %v", path, err)
|
||||
}
|
||||
|
||||
// Parse template
|
||||
tmpl, err := template.New(d.Name()).Parse(string(content))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse template %s: %v", path, err)
|
||||
}
|
||||
|
||||
// Ensure parent directory exists
|
||||
if err := os.MkdirAll(filepath.Dir(outPath), 0755); err != nil {
|
||||
return fmt.Errorf("failed to create parent directory for %s: %v", outPath, err)
|
||||
}
|
||||
|
||||
// Create output file
|
||||
outFile, err := os.Create(outPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create %s: %v", outPath, err)
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
// Execute template
|
||||
if err := tmpl.Execute(outFile, config); err != nil {
|
||||
return fmt.Errorf("failed to execute template %s: %v", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error walking config files: %v", err)
|
||||
}
|
||||
|
||||
// move the docker-compose.yml file to the root directory
|
||||
os.Rename("config/docker-compose.yml", "docker-compose.yml")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func shouldInstallDocker() bool {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print("Would you like to install Docker? (yes/no): ")
|
||||
response, _ := reader.ReadString('\n')
|
||||
return strings.ToLower(strings.TrimSpace(response)) == "yes"
|
||||
}
|
||||
|
||||
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)
|
||||
var installCmd *exec.Cmd
|
||||
|
||||
switch {
|
||||
case strings.Contains(osRelease, "ID=ubuntu") || strings.Contains(osRelease, "ID=debian"):
|
||||
installCmd = exec.Command("bash", "-c", `
|
||||
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=amd64 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
|
||||
`)
|
||||
case strings.Contains(osRelease, "ID=fedora"):
|
||||
installCmd = exec.Command("bash", "-c", `
|
||||
dnf -y install dnf-plugins-core &&
|
||||
dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo &&
|
||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
`)
|
||||
default:
|
||||
return fmt.Errorf("unsupported Linux distribution")
|
||||
}
|
||||
|
||||
installCmd.Stdout = os.Stdout
|
||||
installCmd.Stderr = os.Stderr
|
||||
return installCmd.Run()
|
||||
}
|
||||
|
||||
func isDockerInstalled() bool {
|
||||
cmd := exec.Command("docker", "--version")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func pullAndStartContainers() error {
|
||||
containers := []string{
|
||||
"traefik:v3.1",
|
||||
"fossorial/pangolin:latest",
|
||||
"fossorial/gerbil:latest",
|
||||
}
|
||||
|
||||
for _, container := range containers {
|
||||
fmt.Printf("Pulling %s...\n", container)
|
||||
cmd := exec.Command("docker", "pull", container)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("failed to pull %s: %v", container, err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Starting containers...")
|
||||
|
||||
// First try docker compose (new style)
|
||||
cmd := exec.Command("docker", "compose", "-f", "docker-compose.yml", "up", "-d")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
|
||||
// If docker compose fails, try docker-compose (legacy style)
|
||||
if err != nil {
|
||||
cmd = exec.Command("docker-compose", "-f", "docker-compose.yml", "up", "-d")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err = cmd.Run()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue