mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 10:13:14 -04:00 
			
		
		
		
	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>
This commit is contained in:
		
							
								
								
									
										147
									
								
								plugin/forwardcrd/setup.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								plugin/forwardcrd/setup.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
		Reference in New Issue
	
	Block a user