🔧 Create a configuration file interface
This commit adds the ability to provide a config file in different ways: The following options are given in the order in which they are checked: 1. A config file path passed by the -c parameter on the command line 2. A config file path passed by the HS_CONFIGFILE environment variable 3. A config.json file in the application root Should these fail we try to get the parameters for the config struct directly from environment variables or secret files as used in a container environment. As example the JwtKey can be supplied by either passing the value through: * An environment variable HS_CONFIG_JWTKEY which contains the value directly * An environment variable HS_CONFIG_JWTKEY_FILE which contains a path pointing to the Secret File
This commit is contained in:
parent
c08de78984
commit
83753c3ee1
|
@ -71,4 +71,7 @@ $RECYCLE.BIN/
|
||||||
!.gitsubmodules
|
!.gitsubmodules
|
||||||
|
|
||||||
# sqlite database
|
# sqlite database
|
||||||
*.db
|
*.db
|
||||||
|
|
||||||
|
# config file
|
||||||
|
config.json
|
|
@ -15,7 +15,7 @@ func GenerateToken(username string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
tokenString, err := token.SignedString(config.JwtKey)
|
tokenString, err := token.SignedString(config.GlobalConfig.JwtKey)
|
||||||
|
|
||||||
return tokenString, err
|
return tokenString, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"jwtKey": "your_secret_key",
|
||||||
|
"databaseFile": "hostname-service.db"
|
||||||
|
}
|
|
@ -1,3 +1,89 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
var JwtKey = []byte("your_secret_key")
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
// You might need additional imports for file handling, etc.
|
||||||
|
)
|
||||||
|
|
||||||
|
type AppConfig struct {
|
||||||
|
JwtKey string
|
||||||
|
DatabaseFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
var GlobalConfig *AppConfig
|
||||||
|
|
||||||
|
func LoadConfig() error {
|
||||||
|
GlobalConfig = &AppConfig{}
|
||||||
|
|
||||||
|
// Check command line arguments
|
||||||
|
configFile := flag.String("c", "", "path to config file")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *configFile != "" {
|
||||||
|
return loadConfigFromFile(*configFile, GlobalConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check environment variable for config file path
|
||||||
|
envConfigFile := os.Getenv("HS_CONFIGFILE")
|
||||||
|
if envConfigFile != "" {
|
||||||
|
return loadConfigFromFile(envConfigFile, GlobalConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load from a default config file
|
||||||
|
defaultConfigFile := "config.json" // Replace with your default config file name
|
||||||
|
if _, err := os.Stat(defaultConfigFile); err == nil {
|
||||||
|
return loadConfigFromFile(defaultConfigFile, GlobalConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load config from environment variables or docker secrets
|
||||||
|
loadConfigFromEnvOrSecrets(GlobalConfig)
|
||||||
|
|
||||||
|
// Check if the configuration has been loaded successfully
|
||||||
|
if GlobalConfig.JwtKey == "" || GlobalConfig.DatabaseFile == "" {
|
||||||
|
// Add more checks as necessary for other required config fields
|
||||||
|
return errors.New("failed to load configuration from any source")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfigFromFile(filePath string, config *AppConfig) error {
|
||||||
|
fileData, err := ioutil.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(fileData, config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfigFromEnvOrSecrets(config *AppConfig) {
|
||||||
|
val := reflect.ValueOf(config).Elem()
|
||||||
|
typ := val.Type()
|
||||||
|
|
||||||
|
for i := 0; i < val.NumField(); i++ {
|
||||||
|
field := typ.Field(i)
|
||||||
|
envVar := "HS_CONFIG_" + strings.ToUpper(field.Name)
|
||||||
|
if value, exists := os.LookupEnv(envVar); exists {
|
||||||
|
val.Field(i).SetString(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handling Docker secrets (file-based secrets)
|
||||||
|
secretFileEnvVar := envVar + "_FILE"
|
||||||
|
if secretFilePath, exists := os.LookupEnv(secretFileEnvVar); exists {
|
||||||
|
if secretValue, err := ioutil.ReadFile(secretFilePath); err == nil {
|
||||||
|
val.Field(i).SetString(string(secretValue))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
11
main.go
11
main.go
|
@ -1,8 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
"git.beisel.it/florian/hostname-service/api"
|
"git.beisel.it/florian/hostname-service/api"
|
||||||
"git.beisel.it/florian/hostname-service/auth"
|
"git.beisel.it/florian/hostname-service/auth"
|
||||||
|
"git.beisel.it/florian/hostname-service/config"
|
||||||
"git.beisel.it/florian/hostname-service/db"
|
"git.beisel.it/florian/hostname-service/db"
|
||||||
"git.beisel.it/florian/hostname-service/docs"
|
"git.beisel.it/florian/hostname-service/docs"
|
||||||
"git.beisel.it/florian/hostname-service/middleware"
|
"git.beisel.it/florian/hostname-service/middleware"
|
||||||
|
@ -29,9 +32,15 @@ import (
|
||||||
// @description Type "Bearer" followed by a space and JWT token.
|
// @description Type "Bearer" followed by a space and JWT token.
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
err := config.LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to load configuration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
gin.SetMode(gin.DebugMode)
|
gin.SetMode(gin.DebugMode)
|
||||||
|
|
||||||
db.Init("hostname-service.db")
|
db.Init(config.GlobalConfig.DatabaseFile)
|
||||||
|
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ func Authenticate() gin.HandlerFunc {
|
||||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
return nil, fmt.Errorf("unexpected signing method")
|
return nil, fmt.Errorf("unexpected signing method")
|
||||||
}
|
}
|
||||||
return config.JwtKey, nil
|
return config.GlobalConfig.JwtKey, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue