-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
109 lines (88 loc) · 4.42 KB
/
config.go
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
package peerdb
import (
"github.com/alecthomas/kong"
mapset "github.com/deckarep/golang-set/v2"
"gitlab.com/tozd/go/cli"
"gitlab.com/tozd/go/errors"
"gitlab.com/tozd/go/zerolog"
"gitlab.com/tozd/waf"
)
const (
DefaultProxyTo = "http://localhost:5173"
DefaultTLSCache = "letsencrypt"
DefaultElastic = "http://127.0.0.1:9200"
DefaultIndex = "docs"
DefaultSchema = "docs"
DefaultTitle = "PeerDB"
)
//nolint:lll
type PostgresConfig struct {
URL kong.FileContentFlag ` env:"URL_PATH" help:"File with PostgreSQL database URL. Environment variable: ${env}." placeholder:"PATH" required:"" short:"d" yaml:"database"`
Schema string `default:"${defaultSchema}" help:"Name of PostgreSQL schema to use when sites are not configured. Default: ${defaultSchema}." placeholder:"NAME" yaml:"schema"`
}
//nolint:lll
type ElasticConfig struct {
URL string `default:"${defaultElastic}" help:"URL of the ElasticSearch instance. Default: ${defaultElastic}." placeholder:"URL" short:"e" yaml:"elastic"`
Index string `default:"${defaultIndex}" help:"Name of ElasticSearch index to use when sites are not configured. Default: ${defaultIndex}." placeholder:"NAME" yaml:"index"`
SizeField bool ` help:"Enable size field on documents when sites are not configured. Requires mapper-size ElasticSearch plugin installed." yaml:"sizeField"`
}
// Globals describes top-level (global) flags.
//
//nolint:lll
type Globals struct {
zerolog.LoggingConfig `yaml:",inline"`
Version kong.VersionFlag `help:"Show program's version and exit." short:"V" yaml:"-"`
Config cli.ConfigFlag `help:"Load configuration from a JSON or YAML file." name:"config" placeholder:"PATH" short:"c" yaml:"-"`
Postgres PostgresConfig `embed:"" envprefix:"POSTGRES_" prefix:"postgres." yaml:"postgres"`
Elastic ElasticConfig `embed:"" envprefix:"ELASTIC_" prefix:"elastic." yaml:"elastic"`
Sites []Site `help:"Site configuration as JSON or YAML with fields \"domain\", \"index\", \"schema\", \"title\", \"cert\", \"key\", and \"sizeField\". Can be provided multiple times." name:"site" placeholder:"SITE" sep:"none" short:"s" yaml:"sites"`
}
func (g *Globals) Validate() error {
domains := mapset.NewThreadUnsafeSet[string]()
for i, site := range g.Sites {
// This is not validated when Site is not populated by Kong.
if site.Domain == "" {
return errors.Errorf(`domain is required for site at index %d`, i)
}
// To make sure validation is called.
if err := site.Validate(); err != nil {
return errors.WithStack(err)
}
// We cannot use kong to set these defaults, so we do it here.
if site.Index == "" {
site.Index = DefaultIndex
}
if site.Title == "" {
site.Title = DefaultTitle
}
if !domains.Add(site.Domain) {
return errors.Errorf(`duplicate site for domain "%s"`, site.Domain)
}
}
return nil
}
// Config provides configuration.
// It is used as configuration for Kong command-line parser as well.
type Config struct {
Globals `yaml:"globals"`
Serve ServeCommand `cmd:"" default:"withargs" help:"Run PeerDB server. Default command." yaml:"serve"`
Populate PopulateCommand `cmd:"" help:"Populate search index or indices with core properties." yaml:"populate"`
}
//nolint:lll
type ServeCommand struct {
Server waf.Server[*Site] `embed:"" yaml:",inline"`
Domain string ` group:"Let's Encrypt:" help:"Domain name to request for Let's Encrypt's certificate when sites are not configured." name:"tls.domain" placeholder:"STRING" yaml:"domain"`
Title string `default:"${defaultTitle}" help:"Title to be shown to the users when sites are not configured. Default: ${defaultTitle}." placeholder:"NAME" short:"T" yaml:"title"`
}
func (c *ServeCommand) Validate() error {
// We have to call Validate on kong-embedded structs ourselves.
// See: https://github.com/alecthomas/kong/issues/90
if err := c.Server.TLS.Validate(); err != nil {
return errors.WithStack(err)
}
if c.Domain != "" && c.Server.TLS.Email == "" {
return errors.New("contact e-mail is required for Let's Encrypt's certificate")
}
return nil
}
type PopulateCommand struct{}