mirror of
https://github.com/caddyserver/caddy.git
synced 2025-07-31 15:08:42 -04:00
core: Save app provisioning errors with context (#7070)
* fix(provisioning): remove app from apps map when its provision failed * Clean up failed app provisioning with defer * fix(provisioning): record apps that failed to provision with their error * save the error when an app fails to initialize and return this error when this app is requested by a module --------- Co-authored-by: Matt Holt <mholt@users.noreply.github.com> Co-authored-by: WeidiDeng <weidi_deng@icloud.com>
This commit is contained in:
parent
b7ae39e906
commit
fe41ff3c5b
4
caddy.go
4
caddy.go
@ -82,6 +82,9 @@ type Config struct {
|
|||||||
AppsRaw ModuleMap `json:"apps,omitempty" caddy:"namespace="`
|
AppsRaw ModuleMap `json:"apps,omitempty" caddy:"namespace="`
|
||||||
|
|
||||||
apps map[string]App
|
apps map[string]App
|
||||||
|
|
||||||
|
// failedApps is a map of apps that failed to provision with their underlying error.
|
||||||
|
failedApps map[string]error
|
||||||
storage certmagic.Storage
|
storage certmagic.Storage
|
||||||
eventEmitter eventEmitter
|
eventEmitter eventEmitter
|
||||||
|
|
||||||
@ -522,6 +525,7 @@ func provisionContext(newCfg *Config, replaceAdminServer bool) (Context, error)
|
|||||||
|
|
||||||
// prepare the new config for use
|
// prepare the new config for use
|
||||||
newCfg.apps = make(map[string]App)
|
newCfg.apps = make(map[string]App)
|
||||||
|
newCfg.failedApps = make(map[string]error)
|
||||||
|
|
||||||
// set up global storage and make it CertMagic's default storage, too
|
// set up global storage and make it CertMagic's default storage, too
|
||||||
err = func() error {
|
err = func() error {
|
||||||
|
19
context.go
19
context.go
@ -393,6 +393,8 @@ func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error
|
|||||||
return nil, fmt.Errorf("module value cannot be null")
|
return nil, fmt.Errorf("module value cannot be null")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
// if this is an app module, keep a reference to it,
|
// if this is an app module, keep a reference to it,
|
||||||
// since submodules may need to reference it during
|
// since submodules may need to reference it during
|
||||||
// provisioning (even though the parent app module
|
// provisioning (even though the parent app module
|
||||||
@ -402,12 +404,17 @@ func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error
|
|||||||
// module has been configured for DNS challenges)
|
// module has been configured for DNS challenges)
|
||||||
if appModule, ok := val.(App); ok {
|
if appModule, ok := val.(App); ok {
|
||||||
ctx.cfg.apps[id] = appModule
|
ctx.cfg.apps[id] = appModule
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
ctx.cfg.failedApps[id] = err
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ancestry = append(ctx.ancestry, val)
|
ctx.ancestry = append(ctx.ancestry, val)
|
||||||
|
|
||||||
if prov, ok := val.(Provisioner); ok {
|
if prov, ok := val.(Provisioner); ok {
|
||||||
err := prov.Provision(ctx)
|
err = prov.Provision(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// incomplete provisioning could have left state
|
// incomplete provisioning could have left state
|
||||||
// dangling, so make sure it gets cleaned up
|
// dangling, so make sure it gets cleaned up
|
||||||
@ -422,7 +429,7 @@ func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
if validator, ok := val.(Validator); ok {
|
if validator, ok := val.(Validator); ok {
|
||||||
err := validator.Validate()
|
err = validator.Validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// since the module was already provisioned, make sure we clean up
|
// since the module was already provisioned, make sure we clean up
|
||||||
if cleanerUpper, ok := val.(CleanerUpper); ok {
|
if cleanerUpper, ok := val.(CleanerUpper); ok {
|
||||||
@ -487,6 +494,10 @@ func (ctx Context) loadModuleInline(moduleNameKey, moduleScope string, raw json.
|
|||||||
// or stop App modules. The caller is expected to assert to the
|
// or stop App modules. The caller is expected to assert to the
|
||||||
// concrete type.
|
// concrete type.
|
||||||
func (ctx Context) App(name string) (any, error) {
|
func (ctx Context) App(name string) (any, error) {
|
||||||
|
// if the app failed to load before, return the cached error
|
||||||
|
if err, ok := ctx.cfg.failedApps[name]; ok {
|
||||||
|
return nil, fmt.Errorf("loading %s app module: %v", name, err)
|
||||||
|
}
|
||||||
if app, ok := ctx.cfg.apps[name]; ok {
|
if app, ok := ctx.cfg.apps[name]; ok {
|
||||||
return app, nil
|
return app, nil
|
||||||
}
|
}
|
||||||
@ -511,6 +522,10 @@ func (ctx Context) AppIfConfigured(name string) (any, error) {
|
|||||||
if ctx.cfg == nil {
|
if ctx.cfg == nil {
|
||||||
return nil, fmt.Errorf("app module %s: %w", name, ErrNotConfigured)
|
return nil, fmt.Errorf("app module %s: %w", name, ErrNotConfigured)
|
||||||
}
|
}
|
||||||
|
// if the app failed to load before, return the cached error
|
||||||
|
if err, ok := ctx.cfg.failedApps[name]; ok {
|
||||||
|
return nil, fmt.Errorf("loading %s app module: %v", name, err)
|
||||||
|
}
|
||||||
if app, ok := ctx.cfg.apps[name]; ok {
|
if app, ok := ctx.cfg.apps[name]; ok {
|
||||||
return app, nil
|
return app, nil
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user