aboutsummaryrefslogtreecommitdiff
path: root/plugin/forwardcrd/setup.go
diff options
context:
space:
mode:
authorGravatar Christian Ang <christian.ang@outlook.com> 2021-11-12 08:22:34 -0800
committerGravatar GitHub <noreply@github.com> 2021-11-12 11:22:34 -0500
commit2e6953c7dbd1d6b359911e1ce92e2567df07ca8c (patch)
treed91514ca867bb5b000bec3ea219e6a2ab0a0c244 /plugin/forwardcrd/setup.go
parent6953ab2b4f23f916a08b68ba51b9a26e41e9a748 (diff)
downloadcoredns-2e6953c7dbd1d6b359911e1ce92e2567df07ca8c.tar.gz
coredns-2e6953c7dbd1d6b359911e1ce92e2567df07ca8c.tar.zst
coredns-2e6953c7dbd1d6b359911e1ce92e2567df07ca8c.zip
Initial implementation of ForwardCRD plugin (#4512)
* Add forwardcrd plugin README.md Co-authored-by: Aidan Obley <aobley@vmware.com> Signed-off-by: Christian Ang <angc@vmware.com> * Create forwardcrd plugin - Place forwardcrd before forward plugin in plugin list. This will avoid forward from preventing the forwardcrd plugin from handling any queries in the case of having a default upstream forwarder in a server block (as is the case in the default kubernetes Corefile). Co-authored-by: Aidan Obley <aobley@vmware.com> Signed-off-by: Christian Ang <angc@vmware.com> * Add Forward CRD Signed-off-by: Christian Ang <angc@vmware.com> * Add NewWithConfig to forward plugin - allows external packages to instanciate forward plugins Co-authored-by: Aidan Obley <aobley@vmware.com> Signed-off-by: Christian Ang <angc@vmware.com> * ForwardCRD plugin handles requests for Forward CRs - add a Kubernetes controller that can read Forward CRs - instances of the forward plugin are created based on Forward CRs from the Kubernetes controller - DNS requests are handled by calling matching Forward plugin instances based on zone name - Defaults to the kube-system namespace to align with Corefile RBAC Signed-off-by: Christian Ang <angc@vmware.com> Use klog v2 in forwardcrd plugin * Refactor forward setup to use NewWithConfig Co-authored-by: Christian Ang <angc@vmware.com> Signed-off-by: Edwin Xie <exie@vmware.com> * Use ParseInt instead of Atoi - to ensure that the bitsize is 32 for later casting to uint32 Signed-off-by: Christian Ang <angc@vmware.com> * Add @christianang to CODEOWNERS for forwardcrd Signed-off-by: Christian Ang <angc@vmware.com> Co-authored-by: Edwin Xie <exie@vmware.com>
Diffstat (limited to 'plugin/forwardcrd/setup.go')
-rw-r--r--plugin/forwardcrd/setup.go147
1 files changed, 147 insertions, 0 deletions
diff --git a/plugin/forwardcrd/setup.go b/plugin/forwardcrd/setup.go
new file mode 100644
index 000000000..6be322bc6
--- /dev/null
+++ b/plugin/forwardcrd/setup.go
@@ -0,0 +1,147 @@
+package forwardcrd
+
+import (
+ "context"
+ "os"
+ "time"
+
+ "github.com/coredns/caddy"
+ "github.com/coredns/coredns/core/dnsserver"
+ "github.com/coredns/coredns/plugin"
+ "github.com/coredns/coredns/plugin/dnstap"
+ clog "github.com/coredns/coredns/plugin/pkg/log"
+
+ "k8s.io/client-go/tools/clientcmd"
+ "k8s.io/klog/v2"
+)
+
+const pluginName = "forwardcrd"
+
+var log = clog.NewWithPlugin(pluginName)
+
+func init() {
+ plugin.Register(pluginName, setup)
+}
+
+func setup(c *caddy.Controller) error {
+ klog.SetOutput(os.Stdout)
+
+ k, err := parseForwardCRD(c)
+ if err != nil {
+ return plugin.Error(pluginName, err)
+ }
+
+ err = k.InitKubeCache(context.Background())
+ if err != nil {
+ return plugin.Error(pluginName, err)
+ }
+
+ dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
+ k.Next = next
+ return k
+ })
+
+ c.OnStartup(func() error {
+ go k.APIConn.Run(1)
+
+ timeout := time.After(5 * time.Second)
+ ticker := time.NewTicker(100 * time.Millisecond)
+ for {
+ select {
+ case <-ticker.C:
+ if k.APIConn.HasSynced() {
+ return nil
+ }
+ case <-timeout:
+ return nil
+ }
+ }
+ })
+
+ c.OnStartup(func() error {
+ if taph := dnsserver.GetConfig(c).Handler("dnstap"); taph != nil {
+ if tapPlugin, ok := taph.(dnstap.Dnstap); ok {
+ k.APIConn.(*forwardCRDControl).tapPlugin = &tapPlugin
+ }
+ }
+ return nil
+ })
+
+ c.OnShutdown(func() error {
+ return k.APIConn.Stop()
+ })
+
+ return nil
+}
+
+func parseForwardCRD(c *caddy.Controller) (*ForwardCRD, error) {
+ var (
+ k *ForwardCRD
+ err error
+ i int
+ )
+
+ for c.Next() {
+ if i > 0 {
+ return nil, plugin.ErrOnce
+ }
+ i++
+ k, err = parseStanza(c)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return k, nil
+}
+
+func parseStanza(c *caddy.Controller) (*ForwardCRD, error) {
+ k := New()
+
+ args := c.RemainingArgs()
+ k.Zones = plugin.OriginsFromArgsOrServerBlock(args, c.ServerBlockKeys)
+
+ for c.NextBlock() {
+ switch c.Val() {
+ case "endpoint":
+ args := c.RemainingArgs()
+ if len(args) != 1 {
+ return nil, c.ArgErr()
+ }
+ k.APIServerEndpoint = args[0]
+ case "tls":
+ args := c.RemainingArgs()
+ if len(args) != 3 {
+ return nil, c.ArgErr()
+ }
+ k.APIClientCert, k.APIClientKey, k.APICertAuth = args[0], args[1], args[2]
+ case "kubeconfig":
+ args := c.RemainingArgs()
+ if len(args) != 1 && len(args) != 2 {
+ return nil, c.ArgErr()
+ }
+ overrides := &clientcmd.ConfigOverrides{}
+ if len(args) == 2 {
+ overrides.CurrentContext = args[1]
+ }
+ config := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
+ &clientcmd.ClientConfigLoadingRules{ExplicitPath: args[0]},
+ overrides,
+ )
+ k.ClientConfig = config
+ case "namespace":
+ args := c.RemainingArgs()
+ if len(args) == 0 {
+ k.Namespace = ""
+ } else if len(args) == 1 {
+ k.Namespace = args[0]
+ } else {
+ return nil, c.ArgErr()
+ }
+ default:
+ return nil, c.Errf("unknown property '%s'", c.Val())
+ }
+ }
+
+ return k, nil
+}