summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Schneider <aksdb@gmx.de>2019-10-30 22:12:42 +0100
committerMatt Holt <mholt@users.noreply.github.com>2019-10-30 15:12:42 -0600
commit432b94239d6096e75b413de5a79c6707ab808bc9 (patch)
tree4c7dcef291ff40ea0fed7d6ca24f059a9c379cb8
parent4611537f06da0fe77214e4b2c3b4a3330ace0506 (diff)
admin listener as opt-in for initial config (#2834)
* Always cleanup admin endpoint first * Error out if no config has been set (#2833) * Ignore explicitly missing admin config (#2833) * Separate config loading from admin initialization (#2833) * Add admin option to specify admin listener address (#2833) * Use zap for reporting admin endpoint status
-rw-r--r--admin.go40
-rw-r--r--caddyconfig/httpcaddyfile/httptype.go5
-rw-r--r--caddyconfig/httpcaddyfile/options.go14
-rw-r--r--cmd/commandfuncs.go16
4 files changed, 55 insertions, 20 deletions
diff --git a/admin.go b/admin.go
index 0b4affd..e48a4ca 100644
--- a/admin.go
+++ b/admin.go
@@ -18,6 +18,7 @@ import (
"bytes"
"context"
"encoding/json"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -42,6 +43,8 @@ var (
cfgEndptSrvMu sync.Mutex
)
+var ErrAdminInterfaceNotConfigured = errors.New("no admin configuration has been set")
+
// AdminConfig configures the admin endpoint.
type AdminConfig struct {
Listen string `json:"listen,omitempty"`
@@ -60,10 +63,24 @@ var DefaultAdminConfig = &AdminConfig{
// in the format of JSON bytes. It opens a listener
// resource. When no longer needed, StopAdmin should
// be called.
+// If no configuration is given, a default listener is
+// started. If a configuration is given that does NOT
+// specifically configure the admin interface,
+// `ErrAdminInterfaceNotConfigured` is returned and no
+// listener is initialized.
func StartAdmin(initialConfigJSON []byte) error {
cfgEndptSrvMu.Lock()
defer cfgEndptSrvMu.Unlock()
+ if cfgEndptSrv != nil {
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+ err := cfgEndptSrv.Shutdown(ctx)
+ if err != nil {
+ return fmt.Errorf("shutting down old admin endpoint: %v", err)
+ }
+ }
+
adminConfig := DefaultAdminConfig
if len(initialConfigJSON) > 0 {
var config *Config
@@ -71,16 +88,11 @@ func StartAdmin(initialConfigJSON []byte) error {
if err != nil {
return fmt.Errorf("unmarshaling bootstrap config: %v", err)
}
- if config != nil && config.Admin != nil {
- adminConfig = config.Admin
- }
- if cfgEndptSrv != nil {
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
- err := cfgEndptSrv.Shutdown(ctx)
- if err != nil {
- return fmt.Errorf("shutting down old admin endpoint: %v", err)
+ if config != nil {
+ if config.Admin == nil {
+ return ErrAdminInterfaceNotConfigured
}
+ adminConfig = config.Admin
}
}
@@ -136,15 +148,7 @@ func StartAdmin(initialConfigJSON []byte) error {
go cfgEndptSrv.Serve(ln)
- fmt.Println("Caddy 2 admin endpoint listening on", adminConfig.Listen)
-
- if len(initialConfigJSON) > 0 {
- err := Load(bytes.NewReader(initialConfigJSON))
- if err != nil {
- return fmt.Errorf("loading initial config: %v", err)
- }
- fmt.Println("Caddy 2 serving initial configuration")
- }
+ Log().Named("admin").Info("Caddy 2 admin endpoint started.", zap.String("listenAddress", adminConfig.Listen))
return nil
}
diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go
index bc546b4..05022d1 100644
--- a/caddyconfig/httpcaddyfile/httptype.go
+++ b/caddyconfig/httpcaddyfile/httptype.go
@@ -74,6 +74,8 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
val, err = parseOptACMECA(disp)
case "email":
val, err = parseOptEmail(disp)
+ case "admin":
+ val, err = parseOptAdmin(disp)
default:
return nil, warnings, fmt.Errorf("unrecognized parameter name: %s", dir)
}
@@ -254,6 +256,9 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
storageCvtr.(caddy.Module).CaddyModule().ID(),
&warnings)
}
+ if adminConfig, ok := options["admin"].(string); ok && adminConfig != "" {
+ cfg.Admin = &caddy.AdminConfig{Listen: adminConfig}
+ }
return cfg, warnings, nil
}
diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go
index a60d060..74ec507 100644
--- a/caddyconfig/httpcaddyfile/options.go
+++ b/caddyconfig/httpcaddyfile/options.go
@@ -132,3 +132,17 @@ func parseOptEmail(d *caddyfile.Dispenser) (string, error) {
}
return val, nil
}
+
+func parseOptAdmin(d *caddyfile.Dispenser) (string, error) {
+ if d.Next() {
+ var listenAddress string
+ d.AllArgs(&listenAddress)
+
+ if listenAddress == "" {
+ listenAddress = caddy.DefaultAdminListen
+ }
+
+ return listenAddress, nil
+ }
+ return "", nil
+}
diff --git a/cmd/commandfuncs.go b/cmd/commandfuncs.go
index 7c08c2e..d73644c 100644
--- a/cmd/commandfuncs.go
+++ b/cmd/commandfuncs.go
@@ -161,12 +161,24 @@ func cmdRun(fl Flags) (int, error) {
certmagic.UserAgent = "Caddy/" + cleanModVersion
// start the admin endpoint along with any initial config
+ // a configuration without admin config is considered fine
+ // but does not enable the admin endpoint at all
err = caddy.StartAdmin(config)
- if err != nil {
+ if err == nil {
+ defer caddy.StopAdmin()
+ } else if err != caddy.ErrAdminInterfaceNotConfigured {
return caddy.ExitCodeFailedStartup,
fmt.Errorf("starting caddy administration endpoint: %v", err)
}
- defer caddy.StopAdmin()
+
+ // if a config has been supplied, load it as initial config
+ if len(config) > 0 {
+ err := caddy.Load(bytes.NewReader(config))
+ if err != nil {
+ return caddy.ExitCodeFailedStartup, fmt.Errorf("loading initial config: %v", err)
+ }
+ caddy.Log().Named("admin").Info("Caddy 2 serving initial configuration")
+ }
// if we are to report to another process the successful start
// of the server, do so now by echoing back contents of stdin