feat: initial commit

This commit is contained in:
2023-02-02 10:55:24 +01:00
commit d3c238fa3d
86 changed files with 6855 additions and 0 deletions

57
internal/config/agent.go Normal file
View File

@ -0,0 +1,57 @@
package config
type AgentConfig struct {
ReconciliationInterval InterpolatedInt `yaml:"reconciliationInterval"`
Controllers ControllersConfig `yaml:"controllers"`
}
type ControllersConfig struct {
Persistence PersistenceControllerConfig `yaml:"persistence"`
Spec SpecControllerConfig `yaml:"spec"`
Gateway GatewayControllerConfig `yaml:"gateway"`
UCI UCIControllerConfig `yaml:"uci"`
}
type PersistenceControllerConfig struct {
Enabled InterpolatedBool `yaml:"enabled"`
StateFile InterpolatedString `yaml:"stateFile"`
}
type SpecControllerConfig struct {
Enabled InterpolatedBool `yaml:"enabled"`
ServerURL InterpolatedString `yaml:"serverUrl"`
}
type GatewayControllerConfig struct {
Enabled InterpolatedBool `yaml:"enabled"`
}
type UCIControllerConfig struct {
Enabled InterpolatedBool `yaml:"enabled"`
BinPath InterpolatedString `yaml:"binPath"`
ConfigBackupFile InterpolatedString `yaml:"configBackupFile"`
}
func NewDefaultAgentConfig() AgentConfig {
return AgentConfig{
ReconciliationInterval: 5,
Controllers: ControllersConfig{
Spec: SpecControllerConfig{
Enabled: true,
ServerURL: "http://127.0.0.1:3000",
},
Persistence: PersistenceControllerConfig{
Enabled: true,
StateFile: "state.json",
},
Gateway: GatewayControllerConfig{
Enabled: true,
},
UCI: UCIControllerConfig{
Enabled: true,
ConfigBackupFile: "uci-backup.conf",
BinPath: "uci",
},
},
}
}

66
internal/config/config.go Normal file
View File

@ -0,0 +1,66 @@
package config
import (
"io"
"io/ioutil"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)
// Config definition
type Config struct {
HTTP HTTPConfig `yaml:"http"`
Logger LoggerConfig `yaml:"logger"`
Database DatabaseConfig `yaml:"database"`
CORS CORSConfig `yaml:"cors"`
Agent AgentConfig `yaml:"agent"`
}
// NewFromFile retrieves the configuration from the given file
func NewFromFile(path string) (*Config, error) {
config := NewDefault()
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, errors.Wrapf(err, "could not read file '%s'", path)
}
if err := yaml.Unmarshal(data, config); err != nil {
return nil, errors.Wrapf(err, "could not unmarshal configuration")
}
return config, nil
}
// NewDumpDefault dump the new default configuration
func NewDumpDefault() *Config {
config := NewDefault()
return config
}
// NewDefault return new default configuration
func NewDefault() *Config {
return &Config{
HTTP: NewDefaultHTTPConfig(),
Logger: NewDefaultLoggerConfig(),
Database: NewDefaultDatabaseConfig(),
CORS: NewDefaultCORSConfig(),
Agent: NewDefaultAgentConfig(),
}
}
// Dump the given configuration in the given writer
func Dump(config *Config, w io.Writer) error {
data, err := yaml.Marshal(config)
if err != nil {
return errors.Wrap(err, "could not dump config")
}
if _, err := w.Write(data); err != nil {
return errors.WithStack(err)
}
return nil
}

View File

@ -0,0 +1,19 @@
package config
import (
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/pkg/errors"
)
func TestConfigLoad(t *testing.T) {
filepath := "./testdata/config.yml"
conf, err := NewFromFile(filepath)
if err != nil {
t.Fatal(errors.WithStack(err))
}
t.Logf("%s", spew.Sdump(conf))
}

20
internal/config/cors.go Normal file
View File

@ -0,0 +1,20 @@
package config
type CORSConfig struct {
AllowedOrigins InterpolatedStringSlice `yaml:"allowedOrigins"`
AllowCredentials InterpolatedBool `yaml:"allowCredentials"`
AllowedMethods InterpolatedStringSlice `yaml:"allowMethods"`
AllowedHeaders InterpolatedStringSlice `yaml:"allowedHeaders"`
Debug InterpolatedBool `yaml:"debug"`
}
// NewDefaultCorsConfig return the default CORS configuration.
func NewDefaultCORSConfig() CORSConfig {
return CORSConfig{
AllowedOrigins: InterpolatedStringSlice{"http://localhost:3001"},
AllowCredentials: true,
AllowedMethods: InterpolatedStringSlice{"POST", "GET", "PUT", "DELETE"},
AllowedHeaders: InterpolatedStringSlice{"Origin", "Accept", "Content-Type", "Authorization", "Sentry-Trace"},
Debug: false,
}
}

View File

@ -0,0 +1,20 @@
package config
const (
DatabaseDriverPostgres = "postgres"
DatabaseDriverSQLite = "sqlite"
)
// DatabaseConfig definition
type DatabaseConfig struct {
Driver InterpolatedString `yaml:"driver"`
DSN InterpolatedString `yaml:"dsn"`
}
// NewDefaultDatabaseConfig return the default database configuration
func NewDefaultDatabaseConfig() DatabaseConfig {
return DatabaseConfig{
Driver: "sqlite",
DSN: "sqlite://emissary.sqlite",
}
}

View File

@ -0,0 +1,125 @@
package config
import (
"os"
"regexp"
"strconv"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)
var reVar = regexp.MustCompile(`^\${(\w+)}$`)
type InterpolatedString string
func (is *InterpolatedString) UnmarshalYAML(value *yaml.Node) error {
var str string
if err := value.Decode(&str); err != nil {
return errors.WithStack(err)
}
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
*is = InterpolatedString(os.Getenv(match[1]))
} else {
*is = InterpolatedString(str)
}
return nil
}
type InterpolatedInt int
func (ii *InterpolatedInt) UnmarshalYAML(value *yaml.Node) error {
var str string
if err := value.Decode(&str); err != nil {
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
}
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
str = os.Getenv(match[1])
}
intVal, err := strconv.ParseInt(str, 10, 32)
if err != nil {
return errors.Wrapf(err, "could not parse int '%v', line '%d'", str, value.Line)
}
*ii = InterpolatedInt(int(intVal))
return nil
}
type InterpolatedBool bool
func (ib *InterpolatedBool) UnmarshalYAML(value *yaml.Node) error {
var str string
if err := value.Decode(&str); err != nil {
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
}
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
str = os.Getenv(match[1])
}
boolVal, err := strconv.ParseBool(str)
if err != nil {
return errors.Wrapf(err, "could not parse bool '%v', line '%d'", str, value.Line)
}
*ib = InterpolatedBool(boolVal)
return nil
}
type InterpolatedMap map[string]interface{}
func (im *InterpolatedMap) UnmarshalYAML(value *yaml.Node) error {
var data map[string]interface{}
if err := value.Decode(&data); err != nil {
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into map", value.Value, value.Line)
}
for key, value := range data {
strVal, ok := value.(string)
if !ok {
continue
}
if match := reVar.FindStringSubmatch(strVal); len(match) > 0 {
strVal = os.Getenv(match[1])
}
data[key] = strVal
}
*im = data
return nil
}
type InterpolatedStringSlice []string
func (iss *InterpolatedStringSlice) UnmarshalYAML(value *yaml.Node) error {
var data []string
if err := value.Decode(&data); err != nil {
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into map", value.Value, value.Line)
}
for index, value := range data {
if match := reVar.FindStringSubmatch(value); len(match) > 0 {
value = os.Getenv(match[1])
}
data[index] = value
}
*iss = data
return nil
}

13
internal/config/http.go Normal file
View File

@ -0,0 +1,13 @@
package config
type HTTPConfig struct {
Host InterpolatedString `yaml:"host"`
Port uint `yaml:"port"`
}
func NewDefaultHTTPConfig() HTTPConfig {
return HTTPConfig{
Host: "0.0.0.0",
Port: 3000,
}
}

15
internal/config/logger.go Normal file
View File

@ -0,0 +1,15 @@
package config
import "gitlab.com/wpetit/goweb/logger"
type LoggerConfig struct {
Level InterpolatedInt `yaml:"level"`
Format InterpolatedString `yaml:"format"`
}
func NewDefaultLoggerConfig() LoggerConfig {
return LoggerConfig{
Level: InterpolatedInt(logger.LevelInfo),
Format: InterpolatedString(logger.FormatHuman),
}
}

6
internal/config/testdata/config.yml vendored Normal file
View File

@ -0,0 +1,6 @@
logger:
level: 0
format: human
http:
host: "0.0.0.0"
port: 3000