Browse Source

caddyfile: Refactor unmarshaling of module tokens

Eliminates a fair amount of repeated code
master
Matthew Holt 4 years ago
parent
commit
f0216967dc
No known key found for this signature in database GPG Key ID: 2A349DD577D586A5
  1. 26
      caddyconfig/caddyfile/adapter.go
  2. 52
      caddyconfig/httpcaddyfile/builtins.go
  3. 45
      caddyconfig/httpcaddyfile/options.go
  4. 13
      caddyconfig/httpcaddyfile/serveroptions.go
  5. 7
      caddyconfig/httpcaddyfile/tlsapp.go
  6. 13
      modules/caddyhttp/encode/caddyfile.go
  7. 26
      modules/caddyhttp/reverseproxy/caddyfile.go
  8. 11
      modules/caddytls/acmeissuer.go
  9. 30
      modules/logging/filterencoder.go

26
caddyconfig/caddyfile/adapter.go

@ -94,5 +94,31 @@ type ServerType interface {
Setup([]ServerBlock, map[string]interface{}) (*caddy.Config, []caddyconfig.Warning, error) Setup([]ServerBlock, map[string]interface{}) (*caddy.Config, []caddyconfig.Warning, error)
} }
// UnmarshalModule instantiates a module with the given ID and invokes
// UnmarshalCaddyfile on the new value using the immediate next segment
// of d as input. In other words, d's next token should be the first
// token of the module's Caddyfile input.
//
// This function is used when the next segment of Caddyfile tokens
// belongs to another Caddy module. The returned value is often
// type-asserted to the module's associated type for practical use
// when setting up a config.
func UnmarshalModule(d *Dispenser, moduleID string) (Unmarshaler, error) {
mod, err := caddy.GetModule(moduleID)
if err != nil {
return nil, d.Errf("getting module named '%s': %v", moduleID, err)
}
inst := mod.New()
unm, ok := inst.(Unmarshaler)
if !ok {
return nil, d.Errf("module %s is not a Caddyfile unmarshaler; is %T", mod.ID, inst)
}
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil {
return nil, err
}
return unm, nil
}
// Interface guard // Interface guard
var _ caddyconfig.Adapter = (*Adapter)(nil) var _ caddyconfig.Adapter = (*Adapter)(nil)

52
caddyconfig/httpcaddyfile/builtins.go

@ -285,21 +285,14 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
modName := h.Val() modName := h.Val()
mod, err := caddy.GetModule("tls.issuance." + modName) modID := "tls.issuance." + modName
if err != nil { unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
return nil, h.Errf("getting issuer module '%s': %v", modName, err)
}
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return nil, h.Errf("issuer module '%s' is not a Caddyfile unmarshaler", mod.ID)
}
err = unm.UnmarshalCaddyfile(h.NewFromNextSegment())
if err != nil { if err != nil {
return nil, err return nil, err
} }
issuer, ok := unm.(certmagic.Issuer) issuer, ok := unm.(certmagic.Issuer)
if !ok { if !ok {
return nil, h.Errf("module %s is not a certmagic.Issuer", mod.ID) return nil, h.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
} }
issuers = append(issuers, issuer) issuers = append(issuers, issuer)
@ -315,18 +308,12 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
acmeIssuer.Challenges = new(caddytls.ChallengesConfig) acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig) acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
} }
dnsProvModule, err := caddy.GetModule("dns.providers." + provName) modID := "dns.providers." + provName
if err != nil { unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
return nil, h.Errf("getting DNS provider module named '%s': %v", provName, err)
}
dnsProvModuleInstance := dnsProvModule.New()
if unm, ok := dnsProvModuleInstance.(caddyfile.Unmarshaler); ok {
err = unm.UnmarshalCaddyfile(h.NewFromNextSegment())
if err != nil { if err != nil {
return nil, err return nil, err
} }
} acmeIssuer.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(unm, "name", provName, h.warnings)
acmeIssuer.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(dnsProvModuleInstance, "name", provName, h.warnings)
case "ca_root": case "ca_root":
arg := h.RemainingArgs() arg := h.RemainingArgs()
@ -583,21 +570,15 @@ func parseLog(h Helper) ([]ConfigValue, error) {
case "discard": case "discard":
wo = caddy.DiscardWriter{} wo = caddy.DiscardWriter{}
default: default:
mod, err := caddy.GetModule("caddy.logging.writers." + moduleName) modID := "caddy.logging.writers." + moduleName
if err != nil { unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
return nil, h.Errf("getting log writer module named '%s': %v", moduleName, err)
}
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return nil, h.Errf("log writer module '%s' is not a Caddyfile unmarshaler", mod)
}
err = unm.UnmarshalCaddyfile(h.NewFromNextSegment())
if err != nil { if err != nil {
return nil, err return nil, err
} }
var ok bool
wo, ok = unm.(caddy.WriterOpener) wo, ok = unm.(caddy.WriterOpener)
if !ok { if !ok {
return nil, h.Errf("module %s is not a WriterOpener", mod) return nil, h.Errf("module %s (%T) is not a WriterOpener", modID, unm)
} }
} }
cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings) cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings)
@ -607,21 +588,14 @@ func parseLog(h Helper) ([]ConfigValue, error) {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
moduleName := h.Val() moduleName := h.Val()
mod, err := caddy.GetModule("caddy.logging.encoders." + moduleName) moduleID := "caddy.logging.encoders." + moduleName
if err != nil { unm, err := caddyfile.UnmarshalModule(h.Dispenser, moduleID)
return nil, h.Errf("getting log encoder module named '%s': %v", moduleName, err)
}
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return nil, h.Errf("log encoder module '%s' is not a Caddyfile unmarshaler", mod)
}
err = unm.UnmarshalCaddyfile(h.NewFromNextSegment())
if err != nil { if err != nil {
return nil, err return nil, err
} }
enc, ok := unm.(zapcore.Encoder) enc, ok := unm.(zapcore.Encoder)
if !ok { if !ok {
return nil, h.Errf("module %s is not a zapcore.Encoder", mod) return nil, h.Errf("module %s (%T) is not a zapcore.Encoder", moduleID, unm)
} }
cl.EncoderRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, h.warnings) cl.EncoderRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, h.warnings)

45
caddyconfig/httpcaddyfile/options.go

@ -34,7 +34,7 @@ func init() {
RegisterGlobalOption("storage", parseOptStorage) RegisterGlobalOption("storage", parseOptStorage)
RegisterGlobalOption("acme_ca", parseOptSingleString) RegisterGlobalOption("acme_ca", parseOptSingleString)
RegisterGlobalOption("acme_ca_root", parseOptSingleString) RegisterGlobalOption("acme_ca_root", parseOptSingleString)
RegisterGlobalOption("acme_dns", parseOptSingleString) RegisterGlobalOption("acme_dns", parseOptACMEDNS)
RegisterGlobalOption("acme_eab", parseOptACMEEAB) RegisterGlobalOption("acme_eab", parseOptACMEEAB)
RegisterGlobalOption("cert_issuer", parseOptCertIssuer) RegisterGlobalOption("cert_issuer", parseOptCertIssuer)
RegisterGlobalOption("email", parseOptSingleString) RegisterGlobalOption("email", parseOptSingleString)
@ -165,24 +165,35 @@ func parseOptStorage(d *caddyfile.Dispenser) (interface{}, error) {
if !d.Next() { // get storage module name if !d.Next() { // get storage module name
return nil, d.ArgErr() return nil, d.ArgErr()
} }
modName := d.Val() modID := "caddy.storage." + d.Val()
mod, err := caddy.GetModule("caddy.storage." + modName) unm, err := caddyfile.UnmarshalModule(d, modID)
if err != nil { if err != nil {
return nil, d.Errf("getting storage module '%s': %v", modName, err) return nil, err
} }
unm, ok := mod.New().(caddyfile.Unmarshaler) storage, ok := unm.(caddy.StorageConverter)
if !ok { if !ok {
return nil, d.Errf("storage module '%s' is not a Caddyfile unmarshaler", mod.ID) return nil, d.Errf("module %s is not a caddy.StorageConverter", modID)
}
return storage, nil
}
func parseOptACMEDNS(d *caddyfile.Dispenser) (interface{}, error) {
if !d.Next() { // consume option name
return nil, d.ArgErr()
} }
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment()) if !d.Next() { // get DNS module name
return nil, d.ArgErr()
}
modID := "dns.providers." + d.Val()
unm, err := caddyfile.UnmarshalModule(d, modID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
storage, ok := unm.(caddy.StorageConverter) prov, ok := unm.(certmagic.ACMEDNSProvider)
if !ok { if !ok {
return nil, d.Errf("module %s is not a StorageConverter", mod.ID) return nil, d.Errf("module %s (%T) is not a certmagic.ACMEDNSProvider", modID, unm)
} }
return storage, nil return prov, nil
} }
func parseOptACMEEAB(d *caddyfile.Dispenser) (interface{}, error) { func parseOptACMEEAB(d *caddyfile.Dispenser) (interface{}, error) {
@ -220,22 +231,14 @@ func parseOptCertIssuer(d *caddyfile.Dispenser) (interface{}, error) {
if !d.Next() { // get issuer module name if !d.Next() { // get issuer module name
return nil, d.ArgErr() return nil, d.ArgErr()
} }
modName := d.Val() modID := "tls.issuance." + d.Val()
mod, err := caddy.GetModule("tls.issuance." + modName) unm, err := caddyfile.UnmarshalModule(d, modID)
if err != nil {
return nil, d.Errf("getting issuer module '%s': %v", modName, err)
}
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return nil, d.Errf("issuer module '%s' is not a Caddyfile unmarshaler", mod.ID)
}
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return nil, err return nil, err
} }
iss, ok := unm.(certmagic.Issuer) iss, ok := unm.(certmagic.Issuer)
if !ok { if !ok {
return nil, d.Errf("module %s is not a certmagic.Issuer", mod.ID) return nil, d.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
} }
return iss, nil return iss, nil
} }

13
caddyconfig/httpcaddyfile/serveroptions.go

@ -57,21 +57,14 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (interface{}, error
switch d.Val() { switch d.Val() {
case "listener_wrappers": case "listener_wrappers":
for nesting := d.Nesting(); d.NextBlock(nesting); { for nesting := d.Nesting(); d.NextBlock(nesting); {
mod, err := caddy.GetModule("caddy.listeners." + d.Val()) modID := "caddy.listeners." + d.Val()
if err != nil { unm, err := caddyfile.UnmarshalModule(d, modID)
return nil, fmt.Errorf("finding listener module '%s': %v", d.Val(), err)
}
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return nil, fmt.Errorf("listener module '%s' is not a Caddyfile unmarshaler", mod)
}
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return nil, err return nil, err
} }
listenerWrapper, ok := unm.(caddy.ListenerWrapper) listenerWrapper, ok := unm.(caddy.ListenerWrapper)
if !ok { if !ok {
return nil, fmt.Errorf("module %s is not a listener wrapper", mod) return nil, fmt.Errorf("module %s (%T) is not a listener wrapper", modID, unm)
} }
jsonListenerWrapper := caddyconfig.JSONModuleObject( jsonListenerWrapper := caddyconfig.JSONModuleObject(
listenerWrapper, listenerWrapper,

7
caddyconfig/httpcaddyfile/tlsapp.go

@ -392,14 +392,9 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]interf
acmeIssuer.TrustedRootsPEMFiles = append(acmeIssuer.TrustedRootsPEMFiles, globalACMECARoot.(string)) acmeIssuer.TrustedRootsPEMFiles = append(acmeIssuer.TrustedRootsPEMFiles, globalACMECARoot.(string))
} }
if globalACMEDNS != nil && (acmeIssuer.Challenges == nil || acmeIssuer.Challenges.DNS == nil) { if globalACMEDNS != nil && (acmeIssuer.Challenges == nil || acmeIssuer.Challenges.DNS == nil) {
provName := globalACMEDNS.(string)
dnsProvModule, err := caddy.GetModule("dns.providers." + provName)
if err != nil {
return fmt.Errorf("getting DNS provider module named '%s': %v", provName, err)
}
acmeIssuer.Challenges = &caddytls.ChallengesConfig{ acmeIssuer.Challenges = &caddytls.ChallengesConfig{
DNS: &caddytls.DNSChallengeConfig{ DNS: &caddytls.DNSChallengeConfig{
ProviderRaw: caddyconfig.JSONModuleObject(dnsProvModule.New(), "name", provName, nil), ProviderRaw: caddyconfig.JSONModuleObject(globalACMEDNS, "name", globalACMEDNS.(caddy.Module).CaddyModule().ID.Name(), nil),
}, },
} }
} }

13
modules/caddyhttp/encode/caddyfile.go

@ -64,21 +64,14 @@ func (enc *Encode) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.NextBlock(0) { for d.NextBlock(0) {
name := d.Val() name := d.Val()
mod, err := caddy.GetModule("http.encoders." + name) modID := "http.encoders." + name
if err != nil { unm, err := caddyfile.UnmarshalModule(d, modID)
return fmt.Errorf("getting encoder module '%s': %v", name, err)
}
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return fmt.Errorf("encoder module '%s' is not a Caddyfile unmarshaler", mod)
}
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return err return err
} }
encoding, ok := unm.(Encoding) encoding, ok := unm.(Encoding)
if !ok { if !ok {
return fmt.Errorf("module %s is not an HTTP encoding", mod) return fmt.Errorf("module %s is not an HTTP encoding; is %T", modID, unm)
} }
if enc.EncodingsRaw == nil { if enc.EncodingsRaw == nil {
enc.EncodingsRaw = make(caddy.ModuleMap) enc.EncodingsRaw = make(caddy.ModuleMap)

26
modules/caddyhttp/reverseproxy/caddyfile.go

@ -241,21 +241,14 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Err("load balancing selection policy already specified") return d.Err("load balancing selection policy already specified")
} }
name := d.Val() name := d.Val()
mod, err := caddy.GetModule("http.reverse_proxy.selection_policies." + name) modID := "http.reverse_proxy.selection_policies." + name
if err != nil { unm, err := caddyfile.UnmarshalModule(d, modID)
return d.Errf("getting load balancing policy module '%s': %v", mod, err)
}
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return d.Errf("load balancing policy module '%s' is not a Caddyfile unmarshaler", mod)
}
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return err return err
} }
sel, ok := unm.(Selector) sel, ok := unm.(Selector)
if !ok { if !ok {
return d.Errf("module %s is not a Selector", mod) return d.Errf("module %s (%T) is not a reverseproxy.Selector", modID, unm)
} }
if h.LoadBalancing == nil { if h.LoadBalancing == nil {
h.LoadBalancing = new(LoadBalancing) h.LoadBalancing = new(LoadBalancing)
@ -574,21 +567,14 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Err("transport already specified") return d.Err("transport already specified")
} }
transportModuleName = d.Val() transportModuleName = d.Val()
mod, err := caddy.GetModule("http.reverse_proxy.transport." + transportModuleName) modID := "http.reverse_proxy.transport." + transportModuleName
if err != nil { unm, err := caddyfile.UnmarshalModule(d, modID)
return d.Errf("getting transport module '%s': %v", mod, err)
}
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return d.Errf("transport module '%s' is not a Caddyfile unmarshaler", mod)
}
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return err return err
} }
rt, ok := unm.(http.RoundTripper) rt, ok := unm.(http.RoundTripper)
if !ok { if !ok {
return d.Errf("module %s is not a RoundTripper", mod) return d.Errf("module %s (%T) is not a RoundTripper", modID, unm)
} }
transport = rt transport = rt

11
modules/caddytls/acmeissuer.go

@ -354,18 +354,11 @@ func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if iss.Challenges.DNS == nil { if iss.Challenges.DNS == nil {
iss.Challenges.DNS = new(DNSChallengeConfig) iss.Challenges.DNS = new(DNSChallengeConfig)
} }
dnsProvModule, err := caddy.GetModule("dns.providers." + provName) unm, err := caddyfile.UnmarshalModule(d, "dns.providers."+provName)
if err != nil {
return d.Errf("getting DNS provider module named '%s': %v", provName, err)
}
dnsProvModuleInstance := dnsProvModule.New()
if unm, ok := dnsProvModuleInstance.(caddyfile.Unmarshaler); ok {
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return err return err
} }
} iss.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(unm, "name", provName, nil)
iss.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(dnsProvModuleInstance, "name", provName, nil)
case "resolvers": case "resolvers":
if iss.Challenges == nil { if iss.Challenges == nil {

30
modules/logging/filterencoder.go

@ -115,21 +115,14 @@ func (fe *FilterEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.ArgErr() return d.ArgErr()
} }
moduleName := d.Val() moduleName := d.Val()
mod, err := caddy.GetModule("caddy.logging.encoders." + moduleName) moduleID := "caddy.logging.encoders." + moduleName
if err != nil { unm, err := caddyfile.UnmarshalModule(d, moduleID)
return d.Errf("getting log encoder module named '%s': %v", moduleName, err)
}
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return d.Errf("log encoder module '%s' is not a Caddyfile unmarshaler", mod)
}
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return err return err
} }
enc, ok := unm.(zapcore.Encoder) enc, ok := unm.(zapcore.Encoder)
if !ok { if !ok {
return d.Errf("module %s is not a zapcore.Encoder", mod) return d.Errf("module %s (%T) is not a zapcore.Encoder", moduleID, unm)
} }
fe.WrappedRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, nil) fe.WrappedRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, nil)
@ -140,26 +133,19 @@ func (fe *FilterEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.ArgErr() return d.ArgErr()
} }
filterName := d.Val() filterName := d.Val()
mod, err := caddy.GetModule("caddy.logging.encoders.filter." + filterName) moduleID := "caddy.logging.encoders.filter." + filterName
if err != nil { unm, err := caddyfile.UnmarshalModule(d, moduleID)
return d.Errf("getting log filter module named '%s': %v", filterName, err)
}
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return d.Errf("log encoder module '%s' is not a Caddyfile unmarshaler", mod)
}
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return err return err
} }
f, ok := unm.(LogFieldFilter) filter, ok := unm.(LogFieldFilter)
if !ok { if !ok {
return d.Errf("module %s is not a LogFieldFilter", mod) return d.Errf("module %s (%T) is not a logging.LogFieldFilter", moduleID, unm)
} }
if fe.FieldsRaw == nil { if fe.FieldsRaw == nil {
fe.FieldsRaw = make(map[string]json.RawMessage) fe.FieldsRaw = make(map[string]json.RawMessage)
} }
fe.FieldsRaw[field] = caddyconfig.JSONModuleObject(f, "filter", filterName, nil) fe.FieldsRaw[field] = caddyconfig.JSONModuleObject(filter, "filter", filterName, nil)
} }
default: default:

Loading…
Cancel
Save