Skip to content

Commit

Permalink
Better server configuration
Browse files Browse the repository at this point in the history
Switched to viper for configuration
  • Loading branch information
nt0xa committed Jul 21, 2024
1 parent f94af79 commit 4570a1c
Show file tree
Hide file tree
Showing 22 changed files with 238 additions and 131 deletions.
2 changes: 1 addition & 1 deletion .air.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ testdata_dir = "testdata"
tmp_dir = ".tmp"

[build]
args_bin = []
args_bin = ["serve", "--config", "server.toml"]
bin = "./.tmp/server"
cmd = "go build -o ./.tmp/server ./cmd/server/"
delay = 1000
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ RUN apk add --no-cache ca-certificates
WORKDIR /opt/app
COPY --from=builder /opt/app/server .
EXPOSE 53/udp 21 25 80 443
CMD ["./server"]
CMD ["./server", "serve"]
2 changes: 1 addition & 1 deletion Dockerfile.ci
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ RUN apk add --no-cache ca-certificates
WORKDIR /opt/app
COPY server /opt/app/
EXPOSE 53/udp 25 80 443
CMD ["./server"]
CMD ["./server", "serve"]
95 changes: 79 additions & 16 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,81 @@ package main

import (
"database/sql"
"errors"
"fmt"
"net"
"strings"
"sync"
"time"

"github.com/kelseyhightower/envconfig"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/nt0xa/sonar/internal/actionsdb"
"github.com/nt0xa/sonar/internal/cache"
"github.com/nt0xa/sonar/internal/cmd/server"
"github.com/nt0xa/sonar/internal/database"
"github.com/nt0xa/sonar/internal/database/models"
"github.com/nt0xa/sonar/internal/utils"
"github.com/nt0xa/sonar/pkg/dnsx"
"github.com/nt0xa/sonar/pkg/ftpx"
"github.com/nt0xa/sonar/pkg/httpx"
"github.com/nt0xa/sonar/pkg/smtpx"
)

func init() {
validation.ErrorTag = "mapstructure"
}

func main() {
var (
cfg server.Config
cfgFile string
)

root := &cobra.Command{
Use: "server",
Short: "CLI for sonar server",
PersistentPreRunE: func(_ *cobra.Command, _ []string) error {
if err := initConfig(cfgFile, &cfg); err != nil {
return fmt.Errorf("fail to init config: %w", err)
}

return nil
},
SilenceUsage: true,
}

root.PersistentFlags().StringVar(&cfgFile, "config", "", "config file")

serve := &cobra.Command{
Use: "serve",
Short: "start the server",
Run: func(cmd *cobra.Command, args []string) {
serve(&cfg)
},
}

root.AddCommand(serve)

root.Execute()
}

func serve(cfg *server.Config) {
//
// Logger
//

log := logrus.New()
log.SetFormatter(&logrus.TextFormatter{})

//
// Config
//

var cfg server.Config

if err := envconfig.Process("sonar", &cfg); err != nil {
log.Fatal(err.Error())
}

if err := cfg.Validate(); err != nil {
log.Fatal(err)
}

//
// DB
//

db, err := database.New(&cfg.DB, log)
db, err := database.New(cfg.DB.DSN, log)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -276,3 +304,38 @@ func main() {
// Wait forever
select {}
}

func initConfig(cfgFile string, cfg *server.Config) error {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
}

viper.SetEnvPrefix("sonar")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()

for _, key := range utils.StructKeys(*cfg, "mapstructure") {
viper.BindEnv(key)
}

if err := viper.ReadInConfig(); err != nil {
if !errors.As(err, new(viper.ConfigFileNotFoundError)) {
return err
}
}

if err := viper.Unmarshal(cfg); err != nil {
return err
}

if err := cfg.Validate(); err != nil {
return err
}

return nil
}
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ require (
github.com/gorilla/schema v1.4.0
github.com/invopop/jsonschema v0.8.0
github.com/jmoiron/sqlx v1.4.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/larksuite/oapi-sdk-go/v3 v3.2.7
github.com/lib/pq v1.10.9
github.com/miekg/dns v1.1.61
Expand All @@ -28,6 +27,7 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
)

require (
Expand Down Expand Up @@ -95,7 +95,6 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/sync v0.7.0 // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
Expand Down
2 changes: 1 addition & 1 deletion internal/actionsdb/actions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestMain(m *testing.M) {

log := logrus.New()

db, err = database.New(&database.Config{DSN: dsn}, log)
db, err = database.New(dsn, log)
if err != nil {
fmt.Fprintf(os.Stderr, "fail to init database: %v\n", err)
os.Exit(1)
Expand Down
108 changes: 99 additions & 9 deletions internal/cmd/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,118 @@ package server
import (
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/go-ozzo/ozzo-validation/v4/is"
"github.com/nt0xa/sonar/internal/database"
"github.com/nt0xa/sonar/internal/utils/valid"
"github.com/spf13/viper"
)

type Config struct {
DB database.Config `json:"db"`
Domain string `json:"domain"`
IP string `json:"ip"`
func init() {
viper.SetDefault("tls.letsencrypt.directory", "./tls")
viper.SetDefault("tls.letsencrypt.ca_dir_url", "https://acme-v02.api.letsencrypt.org/directory")
viper.SetDefault("tls.letsencrypt.ca_insecure", false)

DNS DNSConfig `json:"dns"`
viper.SetDefault("modules.enabled", "api")
viper.SetDefault("modules.api.port", 31337)

TLS TLSConfig `json:"tls"`
viper.SetDefault("modules.lark.tls_enabled", true)
}

Modules ModulesConfig `json:"modules"`
type Config struct {
Domain string `mapstructure:"domain"`
IP string `mapstructure:"ip"`
DB DBConfig `mapstructure:"db"`
DNS DNSConfig `mapstructure:"dns"`
TLS TLSConfig `mapstructure:"tls"`
Modules ModulesConfig `mapstructure:"modules"`
}

func (c Config) Validate() error {
return validation.ValidateStruct(&c,
validation.Field(&c.DB),
validation.Field(&c.Domain, validation.Required, is.Domain),
validation.Field(&c.IP, validation.Required, is.IP),
validation.Field(&c.DB, validation.Required),
validation.Field(&c.DNS),
validation.Field(&c.TLS),
validation.Field(&c.Modules),
)
}

//
// DB
//

type DBConfig struct {
DSN string `mapstructure:"dsn"`
}

func (c DBConfig) Validate() error {
return validation.ValidateStruct(&c,
validation.Field(&c.DSN, validation.Required))
}

//
// DNS
//

type DNSConfig struct {
Zone string `mapstructure:"zone"`
}

func (c DNSConfig) Validate() error {
return validation.ValidateStruct(&c)
}

//
// TLS
//

type TLSConfig struct {
Type string `mapstructure:"type"`
Custom TLSCustomConfig `mapstructure:"custom"`
LetsEncrypt TLSLetsEncryptConfig `mapstructure:"letsencrypt"`
}

func (c TLSConfig) Validate() error {
rules := make([]*validation.FieldRules, 0)

rules = append(rules,
validation.Field(&c.Type, validation.Required, validation.In("custom", "letsencrypt")))

switch c.Type {
case "custom":
rules = append(rules, validation.Field(&c.Custom))
case "letsencrypt":
rules = append(rules, validation.Field(&c.LetsEncrypt))
}

return validation.ValidateStruct(&c, rules...)
}

// Custom

type TLSCustomConfig struct {
Key string `mapstructure:"key"`
Cert string `mapstructure:"cert"`
}

func (c TLSCustomConfig) Validate() error {
return validation.ValidateStruct(&c,
validation.Field(&c.Key, validation.Required, validation.By(valid.File)),
validation.Field(&c.Cert, validation.Required, validation.By(valid.File)),
)
}

// LetsEncrypt

type TLSLetsEncryptConfig struct {
Email string `mapstructure:"email"`
Directory string `mapstructure:"directory"`
CADirURL string `mapstructure:"ca_dir_url"`
CAInsecure bool `mapstructure:"ca_insecure"`
}

func (c TLSLetsEncryptConfig) Validate() error {
return validation.ValidateStruct(&c,
validation.Field(&c.Email, validation.Required),
validation.Field(&c.Directory, validation.Required, validation.By(valid.Directory)),
)
}
9 changes: 0 additions & 9 deletions internal/cmd/server/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"strings"

"github.com/fatih/structs"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/miekg/dns"

"github.com/nt0xa/sonar/internal/database"
Expand Down Expand Up @@ -40,14 +39,6 @@ var dnsTemplate = tpl.MustParse(`
* SOA ns1 hostmaster 1337 86400 7200 4000000 11200
`)

type DNSConfig struct {
Zone string `json:"zone"`
}

func (c DNSConfig) Validate() error {
return validation.ValidateStruct(&c)
}

func parseDNSRecords(s, origin string, ip net.IP) *dnsx.Records {
rrs, err := dnsx.ParseRecords(s, origin)
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions internal/cmd/server/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ type Controller interface {
}

type ModulesConfig struct {
Enabled []string `json:"enabled"`
Enabled []string `mapstructure:"enabled"`

// TODO: dynamic modules config (something like json.RawMessage) to be able to not include
// unnecessary modules in binary.
Telegram telegram.Config `json:"telegram"`
API api.Config `json:"api"`
Lark lark.Config `json:"lark"`
Telegram telegram.Config `mapstructure:"telegram"`
API api.Config `mapstructure:"api"`
Lark lark.Config `mapstructure:"lark"`
}

func (c ModulesConfig) Validate() error {
Expand Down
Loading

0 comments on commit 4570a1c

Please sign in to comment.