diff --git a/chasquid.go b/chasquid.go
index f992c0b..059d2df 100644
--- a/chasquid.go
+++ b/chasquid.go
@@ -37,6 +37,8 @@ import (
var (
configDir = flag.String("config_dir", "/etc/chasquid",
"configuration directory")
+ configOverrides = flag.String("config_overrides", "",
+ "override configuration values (in text protobuf format)")
showVer = flag.Bool("version", false, "show version and exit")
)
@@ -70,7 +72,7 @@ func main() {
// Seed the PRNG, just to prevent for it to be totally predictable.
rand.Seed(time.Now().UnixNano())
- conf, err := config.Load(*configDir + "/chasquid.conf")
+ conf, err := config.Load(*configDir+"/chasquid.conf", *configOverrides)
if err != nil {
log.Fatalf("Error loading config: %v", err)
}
diff --git a/cmd/chasquid-util/chasquid-util.go b/cmd/chasquid-util/chasquid-util.go
index fa4be3d..f8eae2d 100644
--- a/cmd/chasquid-util/chasquid-util.go
+++ b/cmd/chasquid-util/chasquid-util.go
@@ -204,7 +204,7 @@ func userRemove() {
// chasquid-util aliases-resolve
func aliasesResolve() {
- conf, err := config.Load(configDir + "/chasquid.conf")
+ conf, err := config.Load(configDir+"/chasquid.conf", "")
if err != nil {
Fatalf("Error loading config: %v", err)
}
@@ -248,7 +248,7 @@ func aliasesResolve() {
// chasquid-util print-config
func printConfig() {
- conf, err := config.Load(configDir + "/chasquid.conf")
+ conf, err := config.Load(configDir+"/chasquid.conf", "")
if err != nil {
Fatalf("Error loading config: %v", err)
}
@@ -260,7 +260,7 @@ func printConfig() {
func domaininfoRemove() {
domain := args[""].(string)
- conf, err := config.Load(configDir + "/chasquid.conf")
+ conf, err := config.Load(configDir+"/chasquid.conf", "")
if err != nil {
Fatalf("Error loading config: %v", err)
}
@@ -290,7 +290,7 @@ func aliasesAdd() {
Fatalf("Domain doesn't exist")
}
- conf, err := config.Load(configDir + "/chasquid.conf")
+ conf, err := config.Load(configDir+"/chasquid.conf", "")
if err != nil {
Fatalf("Error loading config: %v", err)
}
diff --git a/docs/man/chasquid.1 b/docs/man/chasquid.1
index 0a9afb7..1394a43 100644
--- a/docs/man/chasquid.1
+++ b/docs/man/chasquid.1
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "chasquid 1"
-.TH chasquid 1 "2018-07-22" "" ""
+.TH chasquid 1 "2020-05-16" "" ""
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@@ -154,6 +154,11 @@ It's written in Go, and distributed under the Apache license 2.0.
.IP "\fB\-config_dir\fR \fIdir\fR" 8
.IX Item "-config_dir dir"
configuration directory (default \fI/etc/chasquid\fR)
+.IP "\fB\-config_overrides\fR \fIconfig\fR" 8
+.IX Item "-config_overrides config"
+configuration values (in text protobuf format) to override the on-disk
+configuration with. This should only be needed in very specific cases for
+deployments where editing the configuration file is not feasible.
.IP "\fB\-alsologtostderr\fR" 8
.IX Item "-alsologtostderr"
also log to stderr, in addition to the file
diff --git a/docs/man/chasquid.1.pod b/docs/man/chasquid.1.pod
index 56035d1..8f328e1 100644
--- a/docs/man/chasquid.1.pod
+++ b/docs/man/chasquid.1.pod
@@ -22,6 +22,12 @@ It's written in Go, and distributed under the Apache license 2.0.
configuration directory (default F)
+=item B<-config_overrides> I
+
+configuration values (in text protobuf format) to override the on-disk
+configuration with. This should only be needed in very specific cases for
+deployments where editing the configuration file is not feasible.
+
=item B<-alsologtostderr>
also log to stderr, in addition to the file
diff --git a/internal/config/config.go b/internal/config/config.go
index bb0564d..3731dc5 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -33,8 +33,8 @@ var defaultConfig = &Config{
MailLogPath: "",
}
-// Load the config from the given file.
-func Load(path string) (*Config, error) {
+// Load the config from the given file, with the given overrides.
+func Load(path, overrides string) (*Config, error) {
// Start with a copy of the default config.
c := proto.Clone(defaultConfig).(*Config)
@@ -51,6 +51,14 @@ func Load(path string) (*Config, error) {
}
override(c, fromFile)
+ // Handle command line overrides.
+ fromOverrides := &Config{}
+ err = prototext.Unmarshal([]byte(overrides), fromOverrides)
+ if err != nil {
+ return nil, fmt.Errorf("parsing override: %v", err)
+ }
+ override(c, fromOverrides)
+
// Handle hostname separate, because if it is set, we don't need to call
// os.Hostname which can fail.
if c.Hostname == "" {
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index b0e54c2..d539187 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -27,7 +27,7 @@ func mustCreateConfig(t *testing.T, contents string) (string, string) {
func TestEmptyConfig(t *testing.T) {
tmpDir, path := mustCreateConfig(t, "")
defer testlib.RemoveIfOk(t, tmpDir)
- c, err := Load(path)
+ c, err := Load(path, "")
if err != nil {
t.Fatalf("error loading empty config: %v", err)
}
@@ -59,12 +59,18 @@ func TestFullConfig(t *testing.T) {
tmpDir, path := mustCreateConfig(t, confStr)
defer testlib.RemoveIfOk(t, tmpDir)
+ overrideStr := `
+ hostname: "proust"
+ submission_address: ":999"
+ dovecot_auth: true
+ `
+
expected := &Config{
- Hostname: "joust",
+ Hostname: "proust",
MaxDataSizeMb: 26,
SmtpAddress: []string{":1234", ":5678"},
- SubmissionAddress: []string{":10001", ":10002"},
+ SubmissionAddress: []string{":999"},
SubmissionOverTlsAddress: []string{"systemd"},
MonitoringAddress: ":1111",
@@ -77,9 +83,11 @@ func TestFullConfig(t *testing.T) {
DropCharacters: ".",
MailLogPath: "",
+
+ DovecotAuth: true,
}
- c, err := Load(path)
+ c, err := Load(path, overrideStr)
if err != nil {
t.Fatalf("error loading non-existent config: %v", err)
}
@@ -93,7 +101,7 @@ func TestFullConfig(t *testing.T) {
}
func TestErrorLoading(t *testing.T) {
- c, err := Load("/does/not/exist")
+ c, err := Load("/does/not/exist", "")
if err == nil {
t.Fatalf("loaded a non-existent config: %v", c)
}
@@ -104,7 +112,18 @@ func TestBrokenConfig(t *testing.T) {
t, " this is not a valid protobuf")
defer testlib.RemoveIfOk(t, tmpDir)
- c, err := Load(path)
+ c, err := Load(path, "")
+ if err == nil {
+ t.Fatalf("loaded an invalid config: %v", c)
+ }
+}
+
+func TestBrokenOverride(t *testing.T) {
+ tmpDir, path := mustCreateConfig(
+ t, `hostname: "test"`)
+ defer testlib.RemoveIfOk(t, tmpDir)
+
+ c, err := Load(path, "broken override")
if err == nil {
t.Fatalf("loaded an invalid config: %v", c)
}