Closed Xuanwo closed 4 years ago
I'm trying to build a plugin that can take action depending on different conditions. For example, the following config will forward dns query to 127.0.0.1:5353 while condition domain_in_file domain_with_local_cdn.txt is satisfied.
127.0.0.1:5353
domain_in_file domain_with_local_cdn.txt
policy { condition domain_in_file domain_with_local_cdn.txt action forward . 127.0.0.1:5353 }
However, I found it's hard to reuse existing plugin forward.
forward
First of all, to support plugin defined config, coredns let plugin to parse config by themself. Such as forward:
coredns
func parseForward(c *caddy.Controller) (*Forward, error) { var ( f *Forward err error i int ) for c.Next() { if i > 0 { return nil, plugin.ErrOnce } i++ f, err = parseStanza(c) if err != nil { return nil, err } } return f, nil }
This function isn't exported so we can't pass the forward config to build a new forward plugin instance.
Secondly, forward doesn't provide a configurable initialization function:
// New returns a new Forward. func New() *Forward { f := &Forward{maxfails: 2, tlsConfig: new(tls.Config), expire: defaultExpire, p: new(policy.Random), from: ".", hcInterval: hcInterval, opts: options{forceTCP: false, preferUDP: false, hcRecursionDesired: true}} return f } // SetProxy appends p to the proxy list and starts healthchecking. func (f *Forward) SetProxy(p *Proxy) { f.proxies = append(f.proxies, p) p.start(f.hcInterval) }
No arguments for New() and only SetProxy is supported. So it's harder for other plugins to reuse forward.
New()
SetProxy
Embeddable plugin allows the plugin to be reusable.
Parse(*caddy.Controller) (plugin.Handler, error)
*caddy.Controller
proxy
fallback
fallback is an external plugin allow redirecting queries to an alternate set of upstreams based on RCODE.
It's reuse proxy via proxy.NewStaticUpstream:
proxy.NewStaticUpstream
func setup(c *caddy.Controller) error { ... for c.Next() { .. u, err := proxy.NewStaticUpstream(&c.Dispenser) if err != nil { return plugin.Error("fallback", err) } ... } ... return nil }
https://github.com/coredns/fallback/blob/master/setup.go
fanout is an external plugin that parallel proxying DNS messages to upstream resolvers.
fanout
Without embed support, they have to implement a dns client by themself:
func (c *client) Request(r *request.Request) (*dns.Msg, error) { start := time.Now() conn, err := c.transport.Dial(c.net) if err != nil { return nil, err } defer func() { logErrIfNotNil(conn.Close()) }() logErrIfNotNil(conn.SetWriteDeadline(time.Now().Add(maxTimeout))) if err = conn.WriteMsg(r.Req); err != nil { logErrIfNotNil(err) return nil, err } logErrIfNotNil(conn.SetReadDeadline(time.Now().Add(readTimeout))) var ret *dns.Msg for { ret, err = conn.ReadMsg() if err != nil { logErrIfNotNil(err) return nil, err } if r.Req.Id == ret.Id { break } } rc, ok := dns.RcodeToString[ret.Rcode] if !ok { rc = fmt.Sprint(ret.Rcode) } RequestCount.WithLabelValues(c.addr).Add(1) RcodeCount.WithLabelValues(rc, c.addr).Add(1) RequestDuration.WithLabelValues(c.addr).Observe(time.Since(start).Seconds()) return ret, nil }
https://github.com/networkservicemesh/fanout/blob/master/client.go
kubernetai serves multiple Kubernetes within a Server which is another example for the embeddable plugin.
kubernetai
They don't need to parse kubernetes config anymore:
kubernetes
func Parse(c *caddy.Controller) (*Kubernetai, error) { ... for c.Next() { var k8s *kubernetes.Kubernetes k8s, err = kubernetes.ParseStanza(c) if err != nil { return nil, err } k8i.Kubernetes = append(k8i.Kubernetes, k8s) } ... return k8i, nil }
https://github.com/coredns/kubernetai/blob/master/plugin/kubernetai/setup.go
Closed for no response.
Background
I'm trying to build a plugin that can take action depending on different conditions. For example, the following config will forward dns query to
127.0.0.1:5353
while conditiondomain_in_file domain_with_local_cdn.txt
is satisfied.However, I found it's hard to reuse existing plugin
forward
.First of all, to support plugin defined config,
coredns
let plugin to parse config by themself. Such asforward
:This function isn't exported so we can't pass the forward config to build a new
forward
plugin instance.Secondly,
forward
doesn't provide a configurable initialization function:No arguments for
New()
and onlySetProxy
is supported. So it's harder for other plugins to reuseforward
.Motivation
Embeddable plugin allows the plugin to be reusable.
Proposal
Parse(*caddy.Controller) (plugin.Handler, error)
*caddy.Controller
Relate
proxy
infallback
fallback
is an external plugin allow redirecting queries to an alternate set of upstreams based on RCODE.It's reuse
proxy
viaproxy.NewStaticUpstream
:fanout
fanout
is an external plugin that parallel proxying DNS messages to upstream resolvers.Without embed support, they have to implement a dns client by themself:
kubernetai
kubernetai
serves multiple Kubernetes within a Server which is another example for the embeddable plugin.They don't need to parse
kubernetes
config anymore: