mirror of
https://github.com/fosrl/pangolin.git
synced 2025-07-27 22:25:58 +02:00
simplify installer and remove parsing from read config
This commit is contained in:
parent
9f38ad9b4d
commit
ead5df0a8c
9 changed files with 51 additions and 70 deletions
|
@ -21,4 +21,4 @@ update-versions:
|
||||||
echo "Updated main.go with latest versions"
|
echo "Updated main.go with latest versions"
|
||||||
|
|
||||||
put-back:
|
put-back:
|
||||||
mv main.go.bak main.go
|
mv main.go.bak main.go
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
app:
|
app:
|
||||||
dashboard_url: "https://{{.DashboardDomain}}"
|
dashboard_url: "https://{{.DashboardDomain}}"
|
||||||
log_level: "info"
|
log_level: "info"
|
||||||
save_logs: false
|
|
||||||
|
|
||||||
domains:
|
domains:
|
||||||
domain1:
|
domain1:
|
||||||
|
@ -12,40 +11,17 @@ domains:
|
||||||
cert_resolver: "letsencrypt"
|
cert_resolver: "letsencrypt"
|
||||||
|
|
||||||
server:
|
server:
|
||||||
external_port: 3000
|
secret: "{{.Secret}}"
|
||||||
internal_port: 3001
|
|
||||||
next_port: 3002
|
|
||||||
internal_hostname: "pangolin"
|
|
||||||
session_cookie_name: "p_session_token"
|
|
||||||
resource_access_token_param: "p_token"
|
|
||||||
resource_access_token_headers:
|
|
||||||
id: "P-Access-Token-Id"
|
|
||||||
token: "P-Access-Token"
|
|
||||||
resource_session_request_param: "p_session_request"
|
|
||||||
secret: {{.Secret}}
|
|
||||||
cors:
|
cors:
|
||||||
origins: ["https://{{.DashboardDomain}}"]
|
origins: ["https://{{.DashboardDomain}}"]
|
||||||
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
|
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
|
||||||
allowed_headers: ["X-CSRF-Token", "Content-Type"]
|
allowed_headers: ["X-CSRF-Token", "Content-Type"]
|
||||||
credentials: false
|
credentials: false
|
||||||
|
|
||||||
traefik:
|
|
||||||
cert_resolver: "letsencrypt"
|
|
||||||
http_entrypoint: "web"
|
|
||||||
https_entrypoint: "websecure"
|
|
||||||
|
|
||||||
gerbil:
|
gerbil:
|
||||||
start_port: 51820
|
start_port: 51820
|
||||||
base_endpoint: "{{.DashboardDomain}}"
|
base_endpoint: "{{.DashboardDomain}}"
|
||||||
use_subdomain: false
|
|
||||||
block_size: 24
|
|
||||||
site_block_size: 30
|
|
||||||
subnet_group: 100.89.137.0/20
|
|
||||||
|
|
||||||
rate_limits:
|
|
||||||
global:
|
|
||||||
window_minutes: 1
|
|
||||||
max_requests: 500
|
|
||||||
{{if .EnableEmail}}
|
{{if .EnableEmail}}
|
||||||
email:
|
email:
|
||||||
smtp_host: "{{.EmailSMTPHost}}"
|
smtp_host: "{{.EmailSMTPHost}}"
|
||||||
|
@ -57,7 +33,7 @@ email:
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
require_email_verification: {{.EnableEmail}}
|
require_email_verification: {{.EnableEmail}}
|
||||||
disable_signup_without_invite: {{.DisableSignupWithoutInvite}}
|
disable_signup_without_invite: true
|
||||||
disable_user_create_org: {{.DisableUserCreateOrg}}
|
disable_user_create_org: false
|
||||||
allow_raw_resources: true
|
allow_raw_resources: true
|
||||||
allow_base_domain_resources: true
|
allow_base_domain_resources: true
|
||||||
|
|
|
@ -24,9 +24,9 @@ import (
|
||||||
|
|
||||||
// DO NOT EDIT THIS FUNCTION; IT MATCHED BY REGEX IN CICD
|
// DO NOT EDIT THIS FUNCTION; IT MATCHED BY REGEX IN CICD
|
||||||
func loadVersions(config *Config) {
|
func loadVersions(config *Config) {
|
||||||
config.PangolinVersion = "replaceme"
|
config.PangolinVersion = "1.5.1"
|
||||||
config.GerbilVersion = "replaceme"
|
config.GerbilVersion = "1.0.0"
|
||||||
config.BadgerVersion = "replaceme"
|
config.BadgerVersion = "v1.2.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:embed config/*
|
//go:embed config/*
|
||||||
|
@ -39,8 +39,6 @@ type Config struct {
|
||||||
BaseDomain string
|
BaseDomain string
|
||||||
DashboardDomain string
|
DashboardDomain string
|
||||||
LetsEncryptEmail string
|
LetsEncryptEmail string
|
||||||
DisableSignupWithoutInvite bool
|
|
||||||
DisableUserCreateOrg bool
|
|
||||||
EnableEmail bool
|
EnableEmail bool
|
||||||
EmailSMTPHost string
|
EmailSMTPHost string
|
||||||
EmailSMTPPort int
|
EmailSMTPPort int
|
||||||
|
@ -72,15 +70,15 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var config Config
|
var config Config
|
||||||
|
|
||||||
// check if there is already a config file
|
// check if there is already a config file
|
||||||
if _, err := os.Stat("config/config.yml"); err != nil {
|
if _, err := os.Stat("config/config.yml"); err != nil {
|
||||||
config = collectUserInput(reader)
|
config = collectUserInput(reader)
|
||||||
|
|
||||||
loadVersions(&config)
|
loadVersions(&config)
|
||||||
config.DoCrowdsecInstall = false
|
config.DoCrowdsecInstall = false
|
||||||
config.Secret = generateRandomSecretKey()
|
config.Secret = generateRandomSecretKey()
|
||||||
|
|
||||||
if err := createConfigFiles(config); err != nil {
|
if err := createConfigFiles(config); err != nil {
|
||||||
fmt.Printf("Error creating config files: %v\n", err)
|
fmt.Printf("Error creating config files: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -234,14 +232,9 @@ func collectUserInput(reader *bufio.Reader) Config {
|
||||||
config.LetsEncryptEmail = readString(reader, "Enter email for Let's Encrypt certificates", "")
|
config.LetsEncryptEmail = readString(reader, "Enter email for Let's Encrypt certificates", "")
|
||||||
config.InstallGerbil = readBool(reader, "Do you want to use Gerbil to allow tunneled connections", true)
|
config.InstallGerbil = readBool(reader, "Do you want to use Gerbil to allow tunneled connections", true)
|
||||||
|
|
||||||
// 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
|
// Email configuration
|
||||||
fmt.Println("\n=== Email Configuration ===")
|
fmt.Println("\n=== Email Configuration ===")
|
||||||
config.EnableEmail = readBool(reader, "Enable email functionality", false)
|
config.EnableEmail = readBool(reader, "Enable email functionality (SMTP)", false)
|
||||||
|
|
||||||
if config.EnableEmail {
|
if config.EnableEmail {
|
||||||
config.EmailSMTPHost = readString(reader, "Enter SMTP host", "")
|
config.EmailSMTPHost = readString(reader, "Enter SMTP host", "")
|
||||||
|
@ -353,7 +346,7 @@ func installDocker() error {
|
||||||
return fmt.Errorf("failed to detect Linux distribution: %v", err)
|
return fmt.Errorf("failed to detect Linux distribution: %v", err)
|
||||||
}
|
}
|
||||||
osRelease := string(output)
|
osRelease := string(output)
|
||||||
|
|
||||||
// Detect system architecture
|
// Detect system architecture
|
||||||
archCmd := exec.Command("uname", "-m")
|
archCmd := exec.Command("uname", "-m")
|
||||||
archOutput, err := archCmd.Output()
|
archOutput, err := archCmd.Output()
|
||||||
|
@ -361,7 +354,7 @@ func installDocker() error {
|
||||||
return fmt.Errorf("failed to detect system architecture: %v", err)
|
return fmt.Errorf("failed to detect system architecture: %v", err)
|
||||||
}
|
}
|
||||||
arch := strings.TrimSpace(string(archOutput))
|
arch := strings.TrimSpace(string(archOutput))
|
||||||
|
|
||||||
// Map architecture to Docker's architecture naming
|
// Map architecture to Docker's architecture naming
|
||||||
var dockerArch string
|
var dockerArch string
|
||||||
switch arch {
|
switch arch {
|
||||||
|
@ -403,7 +396,7 @@ func installDocker() error {
|
||||||
fedoraVersion = v
|
fedoraVersion = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use appropriate DNF syntax based on version
|
// Use appropriate DNF syntax based on version
|
||||||
var repoCmd string
|
var repoCmd string
|
||||||
if fedoraVersion >= 41 {
|
if fedoraVersion >= 41 {
|
||||||
|
@ -413,7 +406,7 @@ func installDocker() error {
|
||||||
// DNF 4 syntax for Fedora < 41
|
// DNF 4 syntax for Fedora < 41
|
||||||
repoCmd = "dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo"
|
repoCmd = "dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo"
|
||||||
}
|
}
|
||||||
|
|
||||||
installCmd = exec.Command("bash", "-c", fmt.Sprintf(`
|
installCmd = exec.Command("bash", "-c", fmt.Sprintf(`
|
||||||
dnf -y install dnf-plugins-core &&
|
dnf -y install dnf-plugins-core &&
|
||||||
%s &&
|
%s &&
|
||||||
|
@ -442,7 +435,7 @@ func installDocker() error {
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported Linux distribution")
|
return fmt.Errorf("unsupported Linux distribution")
|
||||||
}
|
}
|
||||||
|
|
||||||
installCmd.Stdout = os.Stdout
|
installCmd.Stdout = os.Stdout
|
||||||
installCmd.Stderr = os.Stderr
|
installCmd.Stderr = os.Stderr
|
||||||
return installCmd.Run()
|
return installCmd.Run()
|
||||||
|
@ -527,7 +520,7 @@ func executeDockerComposeCommandWithArgs(args ...string) error {
|
||||||
return fmt.Errorf("neither 'docker compose' nor 'docker-compose' command is available")
|
return fmt.Errorf("neither 'docker compose' nor 'docker-compose' command is available")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if useNewStyle {
|
if useNewStyle {
|
||||||
cmd = exec.Command("docker", append([]string{"compose"}, args...)...)
|
cmd = exec.Command("docker", append([]string{"compose"}, args...)...)
|
||||||
} else {
|
} else {
|
||||||
|
@ -563,7 +556,7 @@ func startContainers() error {
|
||||||
// stopContainers stops the containers using the appropriate command.
|
// stopContainers stops the containers using the appropriate command.
|
||||||
func stopContainers() error {
|
func stopContainers() error {
|
||||||
fmt.Println("Stopping containers...")
|
fmt.Println("Stopping containers...")
|
||||||
|
|
||||||
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "down"); err != nil {
|
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "down"); err != nil {
|
||||||
return fmt.Errorf("failed to stop containers: %v", err)
|
return fmt.Errorf("failed to stop containers: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -574,7 +567,7 @@ func stopContainers() error {
|
||||||
// restartContainer restarts a specific container using the appropriate command.
|
// restartContainer restarts a specific container using the appropriate command.
|
||||||
func restartContainer(container string) error {
|
func restartContainer(container string) error {
|
||||||
fmt.Println("Restarting containers...")
|
fmt.Println("Restarting containers...")
|
||||||
|
|
||||||
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "restart", container); err != nil {
|
if err := executeDockerComposeCommandWithArgs("-f", "docker-compose.yml", "restart", container); err != nil {
|
||||||
return fmt.Errorf("failed to stop the container \"%s\": %v", container, err)
|
return fmt.Errorf("failed to stop the container \"%s\": %v", container, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,12 @@ import { withReplicas } from "drizzle-orm/pg-core";
|
||||||
function createDb() {
|
function createDb() {
|
||||||
const config = readConfigFile();
|
const config = readConfigFile();
|
||||||
|
|
||||||
|
if (!config.postgres) {
|
||||||
|
throw new Error(
|
||||||
|
"Postgres configuration is missing in the configuration file."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const connectionString = config.postgres?.connection_string;
|
const connectionString = config.postgres?.connection_string;
|
||||||
const replicaConnections = config.postgres?.replicas || [];
|
const replicaConnections = config.postgres?.replicas || [];
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import path from "path";
|
||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
import { APP_PATH } from "@server/lib/consts";
|
import { APP_PATH } from "@server/lib/consts";
|
||||||
import { existsSync, mkdirSync } from "fs";
|
import { existsSync, mkdirSync } from "fs";
|
||||||
import { readConfigFile } from "@server/lib/readConfigFile";
|
|
||||||
|
|
||||||
export const location = path.join(APP_PATH, "db", "db.sqlite");
|
export const location = path.join(APP_PATH, "db", "db.sqlite");
|
||||||
export const exists = await checkFileExists(location);
|
export const exists = await checkFileExists(location);
|
||||||
|
@ -13,8 +12,6 @@ export const exists = await checkFileExists(location);
|
||||||
bootstrapVolume();
|
bootstrapVolume();
|
||||||
|
|
||||||
function createDb() {
|
function createDb() {
|
||||||
const config = readConfigFile();
|
|
||||||
|
|
||||||
const sqlite = new Database(location);
|
const sqlite = new Database(location);
|
||||||
return DrizzleSqlite(sqlite, { schema });
|
return DrizzleSqlite(sqlite, { schema });
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { SupporterKey, supporterKey } from "@server/db";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { license } from "@server/license/license";
|
import { license } from "@server/license/license";
|
||||||
import { configSchema, readConfigFile } from "./readConfigFile";
|
import { configSchema, readConfigFile } from "./readConfigFile";
|
||||||
|
import { fromError } from "zod-validation-error";
|
||||||
|
|
||||||
export class Config {
|
export class Config {
|
||||||
private rawConfig!: z.infer<typeof configSchema>;
|
private rawConfig!: z.infer<typeof configSchema>;
|
||||||
|
@ -20,7 +21,29 @@ export class Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
public load() {
|
public load() {
|
||||||
const parsedConfig = readConfigFile();
|
const environment = readConfigFile();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: parsedConfig,
|
||||||
|
success,
|
||||||
|
error
|
||||||
|
} = configSchema.safeParse(environment);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
const errors = fromError(error);
|
||||||
|
throw new Error(`Invalid configuration file: ${errors}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.APP_BASE_DOMAIN) {
|
||||||
|
console.log(
|
||||||
|
"You're using deprecated environment variables. Transition to the configuration file. https://docs.fossorial.io/"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
if (parsedConfig.users) {
|
||||||
|
console.log("You're admin credentials are still in the config file. This method of setting admin credentials is deprecated. It is recommended to remove them from the config file.");
|
||||||
|
}
|
||||||
|
|
||||||
process.env.APP_VERSION = APP_VERSION;
|
process.env.APP_VERSION = APP_VERSION;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import path from "path";
|
||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
// This is a placeholder value replaced by the build process
|
// This is a placeholder value replaced by the build process
|
||||||
export const APP_VERSION = "1.5.1";
|
export const APP_VERSION = "1.6.0";
|
||||||
|
|
||||||
export const __FILENAME = fileURLToPath(import.meta.url);
|
export const __FILENAME = fileURLToPath(import.meta.url);
|
||||||
export const __DIRNAME = path.dirname(__FILENAME);
|
export const __DIRNAME = path.dirname(__FILENAME);
|
||||||
|
|
|
@ -233,24 +233,11 @@ export function readConfigFile() {
|
||||||
environment = loadConfig(configFilePath2);
|
environment = loadConfig(configFilePath2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.APP_BASE_DOMAIN) {
|
|
||||||
console.log(
|
|
||||||
"You're using deprecated environment variables. Transition to the configuration file. https://docs.fossorial.io/"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!environment) {
|
if (!environment) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"No configuration file found. Please create one. https://docs.fossorial.io/"
|
"No configuration file found. Please create one. https://docs.fossorial.io/"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedConfig = configSchema.safeParse(environment);
|
return environment;
|
||||||
|
|
||||||
if (!parsedConfig.success) {
|
|
||||||
const errors = fromError(parsedConfig.error);
|
|
||||||
throw new Error(`Invalid configuration file: ${errors}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedConfig.data;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ export default async function Page(props: {
|
||||||
>(`/auth/initial-setup-complete`, await authCookieHeader());
|
>(`/auth/initial-setup-complete`, await authCookieHeader());
|
||||||
const complete = setupRes.data.data.complete;
|
const complete = setupRes.data.data.complete;
|
||||||
if (!complete) {
|
if (!complete) {
|
||||||
console.log("compelte", complete);
|
|
||||||
redirect("/auth/initial-setup");
|
redirect("/auth/initial-setup");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue