aboutsummaryrefslogtreecommitdiffhomepage
path: root/caddy.go
diff options
context:
space:
mode:
authorMatt Holt <[email protected]>2022-08-01 13:36:22 -0600
committerGitHub <[email protected]>2022-08-01 13:36:22 -0600
commitf783290f40febd3eef2a299911ad95bab4d2b414 (patch)
tree1baed0987f2ad5ed723dbda671f0eec13a414ca7 /caddy.go
parentebd6abcbd5f6b31b7b4cadca0a546d9f0eab9ad3 (diff)
downloadcaddy-f783290f40febd3eef2a299911ad95bab4d2b414.tar.gz
caddy-f783290f40febd3eef2a299911ad95bab4d2b414.zip
caddyhttp: Implement `caddy respond` command (#4870)
Diffstat (limited to 'caddy.go')
-rw-r--r--caddy.go81
1 files changed, 45 insertions, 36 deletions
diff --git a/caddy.go b/caddy.go
index 98ee5b39b..20da5de14 100644
--- a/caddy.go
+++ b/caddy.go
@@ -141,8 +141,8 @@ func changeConfig(method, path string, input []byte, ifMatchHeader string, force
return fmt.Errorf("method not allowed")
}
- currentCfgMu.Lock()
- defer currentCfgMu.Unlock()
+ currentCtxMu.Lock()
+ defer currentCtxMu.Unlock()
if ifMatchHeader != "" {
// expect the first and last character to be quotes
@@ -242,15 +242,15 @@ func changeConfig(method, path string, input []byte, ifMatchHeader string, force
// readConfig traverses the current config to path
// and writes its JSON encoding to out.
func readConfig(path string, out io.Writer) error {
- currentCfgMu.RLock()
- defer currentCfgMu.RUnlock()
+ currentCtxMu.RLock()
+ defer currentCtxMu.RUnlock()
return unsyncedConfigAccess(http.MethodGet, path, nil, out)
}
// indexConfigObjects recursively searches ptr for object fields named
// "@id" and maps that ID value to the full configPath in the index.
// This function is NOT safe for concurrent access; obtain a write lock
-// on currentCfgMu.
+// on currentCtxMu.
func indexConfigObjects(ptr interface{}, configPath string, index map[string]string) error {
switch val := ptr.(type) {
case map[string]interface{}:
@@ -290,7 +290,7 @@ func indexConfigObjects(ptr interface{}, configPath string, index map[string]str
// it as the new config, replacing any other current config.
// It does NOT update the raw config state, as this is a
// lower-level function; most callers will want to use Load
-// instead. A write lock on currentCfgMu is required! If
+// instead. A write lock on currentCtxMu is required! If
// allowPersist is false, it will not be persisted to disk,
// even if it is configured to.
func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
@@ -319,17 +319,17 @@ func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
}
// run the new config and start all its apps
- err = run(newCfg, true)
+ ctx, err := run(newCfg, true)
if err != nil {
return err
}
- // swap old config with the new one
- oldCfg := currentCfg
- currentCfg = newCfg
+ // swap old context (including its config) with the new one
+ oldCtx := currentCtx
+ currentCtx = ctx
// Stop, Cleanup each old app
- unsyncedStop(oldCfg)
+ unsyncedStop(oldCtx)
// autosave a non-nil config, if not disabled
if allowPersist &&
@@ -373,7 +373,7 @@ func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
// This is a low-level function; most callers
// will want to use Run instead, which also
// updates the config's raw state.
-func run(newCfg *Config, start bool) error {
+func run(newCfg *Config, start bool) (Context, error) {
// because we will need to roll back any state
// modifications if this function errors, we
// keep a single error value and scope all
@@ -404,8 +404,8 @@ func run(newCfg *Config, start bool) error {
cancel()
// also undo any other state changes we made
- if currentCfg != nil {
- certmagic.Default.Storage = currentCfg.storage
+ if currentCtx.cfg != nil {
+ certmagic.Default.Storage = currentCtx.cfg.storage
}
}
}()
@@ -417,14 +417,14 @@ func run(newCfg *Config, start bool) error {
}
err = newCfg.Logging.openLogs(ctx)
if err != nil {
- return err
+ return ctx, err
}
// start the admin endpoint (and stop any prior one)
if start {
err = replaceLocalAdminServer(newCfg)
if err != nil {
- return fmt.Errorf("starting caddy administration endpoint: %v", err)
+ return ctx, fmt.Errorf("starting caddy administration endpoint: %v", err)
}
}
@@ -453,7 +453,7 @@ func run(newCfg *Config, start bool) error {
return nil
}()
if err != nil {
- return err
+ return ctx, err
}
// Load and Provision each app and their submodules
@@ -466,18 +466,18 @@ func run(newCfg *Config, start bool) error {
return nil
}()
if err != nil {
- return err
+ return ctx, err
}
if !start {
- return nil
+ return ctx, nil
}
// Provision any admin routers which may need to access
// some of the other apps at runtime
err = newCfg.Admin.provisionAdminRouters(ctx)
if err != nil {
- return err
+ return ctx, err
}
// Start
@@ -502,12 +502,12 @@ func run(newCfg *Config, start bool) error {
return nil
}()
if err != nil {
- return err
+ return ctx, err
}
// now that the user's config is running, finish setting up anything else,
// such as remote admin endpoint, config loader, etc.
- return finishSettingUp(ctx, newCfg)
+ return ctx, finishSettingUp(ctx, newCfg)
}
// finishSettingUp should be run after all apps have successfully started.
@@ -612,10 +612,10 @@ type ConfigLoader interface {
// stop the others. Stop should only be called
// if not replacing with a new config.
func Stop() error {
- currentCfgMu.Lock()
- defer currentCfgMu.Unlock()
- unsyncedStop(currentCfg)
- currentCfg = nil
+ currentCtxMu.Lock()
+ defer currentCtxMu.Unlock()
+ unsyncedStop(currentCtx)
+ currentCtx = Context{}
rawCfgJSON = nil
rawCfgIndex = nil
rawCfg[rawConfigKey] = nil
@@ -628,13 +628,13 @@ func Stop() error {
// it is logged and the function continues stopping
// the next app. This function assumes all apps in
// cfg were successfully started first.
-func unsyncedStop(cfg *Config) {
- if cfg == nil {
+func unsyncedStop(ctx Context) {
+ if ctx.cfg == nil {
return
}
// stop each app
- for name, a := range cfg.apps {
+ for name, a := range ctx.cfg.apps {
err := a.Stop()
if err != nil {
log.Printf("[ERROR] stop %s: %v", name, err)
@@ -642,13 +642,13 @@ func unsyncedStop(cfg *Config) {
}
// clean up all modules
- cfg.cancelFunc()
+ ctx.cfg.cancelFunc()
}
// Validate loads, provisions, and validates
// cfg, but does not start running it.
func Validate(cfg *Config) error {
- err := run(cfg, false)
+ _, err := run(cfg, false)
if err == nil {
cfg.cancelFunc() // call Cleanup on all modules
}
@@ -823,16 +823,25 @@ func goModule(mod *debug.Module) *debug.Module {
return mod
}
+func ActiveContext() Context {
+ currentCtxMu.RLock()
+ defer currentCtxMu.RUnlock()
+ return currentCtx
+}
+
// CtxKey is a value type for use with context.WithValue.
type CtxKey string
// This group of variables pertains to the current configuration.
var (
- // currentCfgMu protects everything in this var block.
- currentCfgMu sync.RWMutex
-
- // currentCfg is the currently-running configuration.
- currentCfg *Config
+ // currentCtxMu protects everything in this var block.
+ currentCtxMu sync.RWMutex
+
+ // currentCtx is the root context for the currently-running
+ // configuration, which can be accessed through this value.
+ // If the Config contained in this value is not nil, then
+ // a config is currently active/running.
+ currentCtx Context
// rawCfg is the current, generic-decoded configuration;
// we initialize it as a map with one field ("config")