DEVELOPMENT ENVIRONMENT

~liljamo/felu

ref: 3cd37b5d7df372ecbf494843ba642e004a54621a felu/internal/config/config.go -rw-r--r-- 3.0 KiB
3cd37b5dJonni Liljamo feat: custom TsigProvider implementation 17 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
 * Copyright (C) 2024 Jonni Liljamo <jonni@liljamo.com>
 *
 * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for
 * more information.
 */

// Package config implements the global program config.
package config

import (
	"fmt"
	"log/slog"
	"net"
	"os"
	"strconv"

	"github.com/miekg/dns"
)

// TODO: Switch back to erya-go once I've rearchitected it.
//import "git.src.quest/~liljamo/erya-go/util"

// FeluConfig is a global for accessing the global config.
var FeluConfig *config

type config struct {
	// Domain, is fqdn'd when read.
	//
	// Used for NS records and as DNS pattern.
	Domain string
	// IPv4 address to return on A queries for Domain.
	IPv4 string

	// The name displayed in the frontend.
	ServiceName string

	// The email to return in SOAs (e.g. admin.felu.arpa.), is fqdn'd when read.
	SOAEmail string

	// Initial email for the admin user, used if no admin account exists (e.g. first boot).
	InitialAdminEmail string
	// Initial password for the admin user, used if no admin account exists (e.g. first boot).
	InitialAdminPwd string

	LogLevel string

	// Data directory, with trailing slash
	DataDir string

	FrontendBindAddr string

	// API url, where the API is served at (e.g. https://api.felud.arpa)
	APIUrl      string
	APIBindAddr string

	DNSBindIP   string
	DNSBindPort int32
}

// InitConfig initializes the global program config from environment variables.
func InitConfig() {
	ipv4 := net.ParseIP(loadEnvStr("FELU_IPV4")).To4()
	if ipv4 == nil {
		panic("Invalid IPv4")
	}

	FeluConfig = &config{
		Domain: dns.Fqdn(loadEnvStr("FELU_DOMAIN")),
		IPv4:   ipv4.String(),

		ServiceName: loadEnvStrDef("FELU_SERVICE_NAME", "FeluDDNS"),

		SOAEmail: dns.Fqdn(loadEnvStr("FELU_SOA_EMAIL")),

		InitialAdminEmail: loadEnvStrDef("FELU_INITIAL_ADMIN_EMAIL", "admin@example.com"),
		InitialAdminPwd:   loadEnvStrDef("FELU_INITIAL_ADMIN_PWD", "feluadmin"),

		LogLevel: loadEnvStrDef("FELU_LOG_LEVEL", "info"),

		DataDir: loadEnvStrDef("FELU_DB_PATH", "/var/felu/"),

		FrontendBindAddr: loadEnvStrDef("FELU_FRONTEND_BIND_ADDR", "0.0.0.0:8080"),

		APIUrl:      loadEnvStr("FELU_API_URL"),
		APIBindAddr: loadEnvStrDef("FELU_API_BIND_ADDR", "0.0.0.0:8081"),

		DNSBindIP:   loadEnvStrDef("FELU_DNS_BIND_IP", "0.0.0.0"),
		DNSBindPort: loadEnvInt32Def("FELU_DNS_BIND_PORT", 53),
	}
}

func loadEnvStr(key string) string {
	value, found := os.LookupEnv(key)
	if found {
		return value
	}
	panic(fmt.Sprintf("Env var '%s' not found", key))
}

func loadEnvStrDef(key string, def string) string {
	value, found := os.LookupEnv(key)
	if found {
		return value
	}
	slog.Warn("Env var not set, using default", slog.String("key", key), slog.String("def", def))
	return def
}

func loadEnvInt32Def(key string, def int32) int32 {
	value, found := os.LookupEnv(key)
	if found {
		res, err := strconv.ParseInt(value, 10, 32)
		if err != nil {
			panic(fmt.Sprintf("Couldn't parse env var '%s' into an integer", key))
		}
		return int32(res)
	}
	slog.Warn("Env var not set, using default", slog.String("key", key), slog.Int("def", int(def)))
	return def
}