Improve configuration with config file
This adds explanations to the example config file, renames the file in order to enable yaml syntax highlighting and fixes the parsing of the flag specifying where to find the configuration file.
This commit is contained in:

committed by
Jan-Eric Hellenberg

parent
da38f56f64
commit
c497e2f19c
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,8 +1,9 @@
|
|||||||
# Project binary
|
# Project binary
|
||||||
poseidon
|
poseidon
|
||||||
|
|
||||||
|
# Configuration file
|
||||||
|
configuration.yaml
|
||||||
|
|
||||||
# TLS certificate/key
|
# TLS certificate/key
|
||||||
*.crt
|
*.crt
|
||||||
*.key
|
*.key
|
||||||
|
|
||||||
configuration.yaml
|
|
||||||
|
@ -2,6 +2,7 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/logging"
|
"gitlab.hpi.de/codeocean/codemoon/poseidon/logging"
|
||||||
@ -13,6 +14,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Config contains the default configuration of Poseidon.
|
||||||
var (
|
var (
|
||||||
Config = &configuration{
|
Config = &configuration{
|
||||||
Server: server{
|
Server: server{
|
||||||
@ -25,14 +27,16 @@ var (
|
|||||||
},
|
},
|
||||||
Nomad: nomad{
|
Nomad: nomad{
|
||||||
Address: "",
|
Address: "",
|
||||||
Token: "",
|
|
||||||
Port: 4646,
|
Port: 4646,
|
||||||
|
Token: "",
|
||||||
TLS: false,
|
TLS: false,
|
||||||
},
|
},
|
||||||
Logger: logger{
|
Logger: logger{
|
||||||
Level: "INFO",
|
Level: "INFO",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
configurationFilePath = "./configuration.yaml"
|
||||||
|
configurationInitialized = false
|
||||||
log = logging.GetLogger("config")
|
log = logging.GetLogger("config")
|
||||||
TLSConfig = &tls.Config{
|
TLSConfig = &tls.Config{
|
||||||
MinVersion: tls.VersionTLS13,
|
MinVersion: tls.VersionTLS13,
|
||||||
@ -41,6 +45,7 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// server configures the Poseidon webserver.
|
||||||
type server struct {
|
type server struct {
|
||||||
Address string
|
Address string
|
||||||
Port int
|
Port int
|
||||||
@ -50,27 +55,39 @@ type server struct {
|
|||||||
KeyFile string
|
KeyFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nomad configures the used Nomad cluster.
|
||||||
type nomad struct {
|
type nomad struct {
|
||||||
Address string
|
Address string
|
||||||
Token string
|
|
||||||
Port int
|
Port int
|
||||||
|
Token string
|
||||||
TLS bool
|
TLS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// logger configures the used logger.
|
||||||
type logger struct {
|
type logger struct {
|
||||||
Level string
|
Level string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// configuration contains the complete configuration of Poseidon.
|
||||||
type configuration struct {
|
type configuration struct {
|
||||||
Server server
|
Server server
|
||||||
Nomad nomad
|
Nomad nomad
|
||||||
Logger logger
|
Logger logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitConfig() {
|
// InitConfig merges configuration options from environment variables and
|
||||||
|
// a configuration file into the default configuration. Calls of InitConfig
|
||||||
|
// after the first call have no effect and return an error. InitConfig
|
||||||
|
// should be called directly after starting the program.
|
||||||
|
func InitConfig() error {
|
||||||
|
if configurationInitialized {
|
||||||
|
return errors.New("configuration is already initialized")
|
||||||
|
}
|
||||||
|
configurationInitialized = true
|
||||||
content := readConfigFile()
|
content := readConfigFile()
|
||||||
Config.mergeYaml(content)
|
Config.mergeYaml(content)
|
||||||
Config.mergeEnvironmentVariables()
|
Config.mergeEnvironmentVariables()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *configuration) NomadAPIURL() *url.URL {
|
func (c *configuration) NomadAPIURL() *url.URL {
|
||||||
@ -93,16 +110,21 @@ func parseURL(address string, port int, tls bool) *url.URL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func readConfigFile() []byte {
|
func readConfigFile() []byte {
|
||||||
var configFilePath string
|
parseFlags()
|
||||||
flag.StringVar(&configFilePath, "config", "./configuration.yaml", "path of the yaml config file")
|
data, err := os.ReadFile(configurationFilePath)
|
||||||
flag.Parse()
|
|
||||||
data, err := os.ReadFile(configFilePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Info("Using default configuration...")
|
log.WithError(err).Info("Using default configuration...")
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseFlags() {
|
||||||
|
if flag.Lookup("config") == nil {
|
||||||
|
flag.StringVar(&configurationFilePath, "config", configurationFilePath, "path of the yaml config file")
|
||||||
|
}
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *configuration) mergeYaml(content []byte) {
|
func (c *configuration) mergeYaml(content []byte) {
|
||||||
if err := yaml.Unmarshal(content, c); err != nil {
|
if err := yaml.Unmarshal(content, c); err != nil {
|
||||||
log.WithError(err).Fatal("Could not parse configuration file")
|
log.WithError(err).Fatal("Could not parse configuration file")
|
||||||
@ -114,20 +136,20 @@ func (c *configuration) mergeEnvironmentVariables() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func readFromEnvironment(prefix string, value reflect.Value) {
|
func readFromEnvironment(prefix string, value reflect.Value) {
|
||||||
if !value.CanSet() || !value.CanInterface() {
|
logEntry := log.WithField("prefix", prefix)
|
||||||
|
// if value was not derived from a pointer, it is not possible to alter its contents
|
||||||
|
if !value.CanSet() {
|
||||||
|
logEntry.Warn("Cannot overwrite struct field that can not be set")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if value.Kind() != reflect.Struct {
|
if value.Kind() != reflect.Struct {
|
||||||
content, ok := os.LookupEnv(prefix)
|
content, ok := os.LookupEnv(prefix)
|
||||||
|
|
||||||
logEntry := log.
|
|
||||||
WithField("prefix", prefix).
|
|
||||||
WithField("content", content)
|
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
logEntry = logEntry.WithField("content", content)
|
||||||
|
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
value.SetString(content)
|
value.SetString(content)
|
||||||
|
30
configuration.example.yaml
Normal file
30
configuration.example.yaml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Configuration of the Poseidon webserver
|
||||||
|
server:
|
||||||
|
# Address on which the webserver listens
|
||||||
|
address: 127.0.0.1
|
||||||
|
# Port on which the webserver listens
|
||||||
|
port: 3000
|
||||||
|
# If set, this token is required in the X-Poseidon-Token header for each route except /health
|
||||||
|
token: SECRET
|
||||||
|
# If set, the API uses TLS for all incoming connections
|
||||||
|
tls: true
|
||||||
|
# The path to the certificate file used for TLS
|
||||||
|
certfile: ./poseidon.crt
|
||||||
|
# The path to the key file used for TLS
|
||||||
|
keyfile: ./poseidon.key
|
||||||
|
|
||||||
|
# Configuration of the used Nomad cluster
|
||||||
|
nomad:
|
||||||
|
# IP address / domain of the Nomad server
|
||||||
|
address: 127.0.0.1
|
||||||
|
# Port of the Nomad server
|
||||||
|
port: 4646
|
||||||
|
# Authenticate requests to the Nomad server with this token
|
||||||
|
token: SECRET
|
||||||
|
# Specifies whether to use TLS when communicating with the Nomad server
|
||||||
|
tls: false
|
||||||
|
|
||||||
|
# Configuration of the logger
|
||||||
|
logger:
|
||||||
|
# Log level that is used after reading the config (INFO until then)
|
||||||
|
level: DEBUG
|
4
main.go
4
main.go
@ -63,7 +63,9 @@ func shutdownOnOSSignal(server *http.Server) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
config.InitConfig()
|
if err := config.InitConfig(); err != nil {
|
||||||
|
log.WithError(err).Warn("Could not initialize configuration")
|
||||||
|
}
|
||||||
logging.InitializeLogging(config.Config.Logger.Level)
|
logging.InitializeLogging(config.Config.Logger.Level)
|
||||||
server := initServer()
|
server := initServer()
|
||||||
log.WithField("address", server.Addr).Info("Starting server")
|
log.WithField("address", server.Addr).Info("Starting server")
|
||||||
|
Reference in New Issue
Block a user