mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-26 13:43:47 +03:00
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
This commit is contained in:
parent
4611537f06
commit
432b94239d
4 changed files with 55 additions and 20 deletions
40
admin.go
40
admin.go
|
@ -18,6 +18,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -42,6 +43,8 @@ var (
|
||||||
cfgEndptSrvMu sync.Mutex
|
cfgEndptSrvMu sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrAdminInterfaceNotConfigured = errors.New("no admin configuration has been set")
|
||||||
|
|
||||||
// AdminConfig configures the admin endpoint.
|
// AdminConfig configures the admin endpoint.
|
||||||
type AdminConfig struct {
|
type AdminConfig struct {
|
||||||
Listen string `json:"listen,omitempty"`
|
Listen string `json:"listen,omitempty"`
|
||||||
|
@ -60,10 +63,24 @@ var DefaultAdminConfig = &AdminConfig{
|
||||||
// in the format of JSON bytes. It opens a listener
|
// in the format of JSON bytes. It opens a listener
|
||||||
// resource. When no longer needed, StopAdmin should
|
// resource. When no longer needed, StopAdmin should
|
||||||
// be called.
|
// 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 {
|
func StartAdmin(initialConfigJSON []byte) error {
|
||||||
cfgEndptSrvMu.Lock()
|
cfgEndptSrvMu.Lock()
|
||||||
defer cfgEndptSrvMu.Unlock()
|
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
|
adminConfig := DefaultAdminConfig
|
||||||
if len(initialConfigJSON) > 0 {
|
if len(initialConfigJSON) > 0 {
|
||||||
var config *Config
|
var config *Config
|
||||||
|
@ -71,16 +88,11 @@ func StartAdmin(initialConfigJSON []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unmarshaling bootstrap config: %v", err)
|
return fmt.Errorf("unmarshaling bootstrap config: %v", err)
|
||||||
}
|
}
|
||||||
if config != nil && config.Admin != nil {
|
if config != nil {
|
||||||
adminConfig = config.Admin
|
if config.Admin == nil {
|
||||||
}
|
return ErrAdminInterfaceNotConfigured
|
||||||
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 = config.Admin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,15 +148,7 @@ func StartAdmin(initialConfigJSON []byte) error {
|
||||||
|
|
||||||
go cfgEndptSrv.Serve(ln)
|
go cfgEndptSrv.Serve(ln)
|
||||||
|
|
||||||
fmt.Println("Caddy 2 admin endpoint listening on", adminConfig.Listen)
|
Log().Named("admin").Info("Caddy 2 admin endpoint started.", zap.String("listenAddress", 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")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,8 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
||||||
val, err = parseOptACMECA(disp)
|
val, err = parseOptACMECA(disp)
|
||||||
case "email":
|
case "email":
|
||||||
val, err = parseOptEmail(disp)
|
val, err = parseOptEmail(disp)
|
||||||
|
case "admin":
|
||||||
|
val, err = parseOptAdmin(disp)
|
||||||
default:
|
default:
|
||||||
return nil, warnings, fmt.Errorf("unrecognized parameter name: %s", dir)
|
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(),
|
storageCvtr.(caddy.Module).CaddyModule().ID(),
|
||||||
&warnings)
|
&warnings)
|
||||||
}
|
}
|
||||||
|
if adminConfig, ok := options["admin"].(string); ok && adminConfig != "" {
|
||||||
|
cfg.Admin = &caddy.AdminConfig{Listen: adminConfig}
|
||||||
|
}
|
||||||
|
|
||||||
return cfg, warnings, nil
|
return cfg, warnings, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,3 +132,17 @@ func parseOptEmail(d *caddyfile.Dispenser) (string, error) {
|
||||||
}
|
}
|
||||||
return val, nil
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -161,12 +161,24 @@ func cmdRun(fl Flags) (int, error) {
|
||||||
certmagic.UserAgent = "Caddy/" + cleanModVersion
|
certmagic.UserAgent = "Caddy/" + cleanModVersion
|
||||||
|
|
||||||
// start the admin endpoint along with any initial config
|
// 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)
|
err = caddy.StartAdmin(config)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
|
defer caddy.StopAdmin()
|
||||||
|
} else if err != caddy.ErrAdminInterfaceNotConfigured {
|
||||||
return caddy.ExitCodeFailedStartup,
|
return caddy.ExitCodeFailedStartup,
|
||||||
fmt.Errorf("starting caddy administration endpoint: %v", err)
|
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
|
// if we are to report to another process the successful start
|
||||||
// of the server, do so now by echoing back contents of stdin
|
// of the server, do so now by echoing back contents of stdin
|
||||||
|
|
Loading…
Reference in a new issue