@marcel91200 / caddy Mirror · read-only / commits / 432b9423
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

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

Andreas Schneider committed Oct 30, 2019 at 22:12 UTC 432b94239d6096e75b413de5a79c6707ab808bc9
4 files changed +55 -20
admin.go
+22 -18
@@ -18,6 +18,7 @@ import (
18 "bytes"
19 "context"
20 "encoding/json"
21 + "errors"
22 "fmt"
23 "io"
24 "io/ioutil"
@@ -42,6 +43,8 @@ var (
43 cfgEndptSrvMu sync.Mutex
44 )
45
46 +var ErrAdminInterfaceNotConfigured = errors.New("no admin configuration has been set")
47 +
48 // AdminConfig configures the admin endpoint.
49 type AdminConfig struct {
50 Listen string `json:"listen,omitempty"`
@@ -60,10 +63,24 @@ var DefaultAdminConfig = &AdminConfig{
63 // in the format of JSON bytes. It opens a listener
64 // resource. When no longer needed, StopAdmin should
65 // be called.
66 +// If no configuration is given, a default listener is
67 +// started. If a configuration is given that does NOT
68 +// specifically configure the admin interface,
69 +// `ErrAdminInterfaceNotConfigured` is returned and no
70 +// listener is initialized.
71 func StartAdmin(initialConfigJSON []byte) error {
72 cfgEndptSrvMu.Lock()
73 defer cfgEndptSrvMu.Unlock()
74
75 + if cfgEndptSrv != nil {
76 + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
77 + defer cancel()
78 + err := cfgEndptSrv.Shutdown(ctx)
79 + if err != nil {
80 + return fmt.Errorf("shutting down old admin endpoint: %v", err)
81 + }
82 + }
83 +
84 adminConfig := DefaultAdminConfig
85 if len(initialConfigJSON) > 0 {
86 var config *Config
@@ -71,16 +88,11 @@ func StartAdmin(initialConfigJSON []byte) error {
88 if err != nil {
89 return fmt.Errorf("unmarshaling bootstrap config: %v", err)
90 }
74 - if config != nil && config.Admin != nil {
75 - adminConfig = config.Admin
76 - }
77 - if cfgEndptSrv != nil {
78 - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
79 - defer cancel()
80 - err := cfgEndptSrv.Shutdown(ctx)
81 - if err != nil {
82 - return fmt.Errorf("shutting down old admin endpoint: %v", err)
91 + if config != nil {
92 + if config.Admin == nil {
93 + return ErrAdminInterfaceNotConfigured
94 }
95 + adminConfig = config.Admin
96 }
97 }
98
@@ -136,15 +148,7 @@ func StartAdmin(initialConfigJSON []byte) error {
148
149 go cfgEndptSrv.Serve(ln)
150
139 - fmt.Println("Caddy 2 admin endpoint listening on", adminConfig.Listen)
140 -
141 - if len(initialConfigJSON) > 0 {
142 - err := Load(bytes.NewReader(initialConfigJSON))
143 - if err != nil {
144 - return fmt.Errorf("loading initial config: %v", err)
145 - }
146 - fmt.Println("Caddy 2 serving initial configuration")
147 - }
151 + Log().Named("admin").Info("Caddy 2 admin endpoint started.", zap.String("listenAddress", adminConfig.Listen))
152
153 return nil
154 }
caddyconfig/httpcaddyfile/httptype.go
+5
@@ -74,6 +74,8 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
74 val, err = parseOptACMECA(disp)
75 case "email":
76 val, err = parseOptEmail(disp)
77 + case "admin":
78 + val, err = parseOptAdmin(disp)
79 default:
80 return nil, warnings, fmt.Errorf("unrecognized parameter name: %s", dir)
81 }
@@ -254,6 +256,9 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
256 storageCvtr.(caddy.Module).CaddyModule().ID(),
257 &warnings)
258 }
259 + if adminConfig, ok := options["admin"].(string); ok && adminConfig != "" {
260 + cfg.Admin = &caddy.AdminConfig{Listen: adminConfig}
261 + }
262
263 return cfg, warnings, nil
264 }
caddyconfig/httpcaddyfile/options.go
+14
@@ -132,3 +132,17 @@ func parseOptEmail(d *caddyfile.Dispenser) (string, error) {
132 }
133 return val, nil
134 }
135 +
136 +func parseOptAdmin(d *caddyfile.Dispenser) (string, error) {
137 + if d.Next() {
138 + var listenAddress string
139 + d.AllArgs(&listenAddress)
140 +
141 + if listenAddress == "" {
142 + listenAddress = caddy.DefaultAdminListen
143 + }
144 +
145 + return listenAddress, nil
146 + }
147 + return "", nil
148 +}
cmd/commandfuncs.go
+14 -2
@@ -161,12 +161,24 @@ func cmdRun(fl Flags) (int, error) {
161 certmagic.UserAgent = "Caddy/" + cleanModVersion
162
163 // start the admin endpoint along with any initial config
164 + // a configuration without admin config is considered fine
165 + // but does not enable the admin endpoint at all
166 err = caddy.StartAdmin(config)
165 - if err != nil {
167 + if err == nil {
168 + defer caddy.StopAdmin()
169 + } else if err != caddy.ErrAdminInterfaceNotConfigured {
170 return caddy.ExitCodeFailedStartup,
171 fmt.Errorf("starting caddy administration endpoint: %v", err)
172 }
169 - defer caddy.StopAdmin()
173 +
174 + // if a config has been supplied, load it as initial config
175 + if len(config) > 0 {
176 + err := caddy.Load(bytes.NewReader(config))
177 + if err != nil {
178 + return caddy.ExitCodeFailedStartup, fmt.Errorf("loading initial config: %v", err)
179 + }
180 + caddy.Log().Named("admin").Info("Caddy 2 serving initial configuration")
181 + }
182
183 // if we are to report to another process the successful start
184 // of the server, do so now by echoing back contents of stdin