k8s migration: add handler for multi proxy to forward (#164)

add global postprocess and handler for multi proxy to forward
This commit is contained in:
Chris O'Haver 2019-05-13 16:23:53 -04:00 committed by GitHub
parent 709b136563
commit d7f87ddf2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 129 additions and 15 deletions

View file

@ -25,7 +25,7 @@ type Option struct {
Args []string Args []string
} }
func New(s string) (Corefile, error) { func New(s string) (*Corefile, error) {
c := Corefile{} c := Corefile{}
cc := caddy.NewTestController("migration", s) cc := caddy.NewTestController("migration", s)
depth := 0 depth := 0
@ -63,7 +63,7 @@ func New(s string) (Corefile, error) {
}) })
} }
} }
return c, nil return &c, nil
} }
func (c *Corefile) ToString() (out string) { func (c *Corefile) ToString() (out string) {

View file

@ -200,7 +200,17 @@ func Migrate(fromCoreDNSVersion, toCoreDNSVersion, corefileStr string, deprecati
newSrvs = append(newSrvs, newSrv) newSrvs = append(newSrvs, newSrv)
} }
cf = corefile.Corefile{Servers: newSrvs}
cf = &corefile.Corefile{Servers: newSrvs}
// apply any global corefile level post processing
if Versions[v].postProcess != nil {
cf, err = Versions[v].postProcess(cf)
if err != nil {
return "", err
}
}
if v == toCoreDNSVersion { if v == toCoreDNSVersion {
break break
} }

View file

@ -1,6 +1,7 @@
package migration package migration
import ( import (
"github.com/andreyvit/diff"
"testing" "testing"
) )
@ -130,6 +131,59 @@ func TestMigrate(t *testing.T) {
loop loop
ready ready
} }
`,
},
{
name: "handle multiple proxy plugins",
fromVersion: "1.1.3",
toVersion: "1.5.0",
deprecations: true,
startCorefile: `.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
proxy mystub-1.example.org 1.2.3.4
proxy mystub-2.example.org 5.6.7.8
proxy . /etc/resolv.conf
cache 30
reload
loadbalance
}
`,
expectedCorefile: `.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
reload
loadbalance
loop
ready
}
mystub-1.example.org {
forward . 1.2.3.4
loop
errors
cache 30
}
mystub-2.example.org {
forward . 5.6.7.8
loop
errors
cache 30
}
`, `,
}, },
} }
@ -144,7 +198,7 @@ func TestMigrate(t *testing.T) {
} }
if result != testCase.expectedCorefile { if result != testCase.expectedCorefile {
t.Errorf("expected %v; got %v", testCase.expectedCorefile, result) t.Errorf("expected -> got diffs:\n%v", diff.LineDiff(testCase.expectedCorefile, result))
} }
}) })
} }

View file

@ -1,33 +1,40 @@
package migration package migration
import ( import (
"errors"
"github.com/coredns/deployment/kubernetes/migration/corefile" "github.com/coredns/deployment/kubernetes/migration/corefile"
) )
type plugin struct { type plugin struct {
status string status string
add serverActionFn
replacedBy string replacedBy string
additional string additional string
action pluginActionFn
options map[string]option options map[string]option
action pluginActionFn // action affecting this plugin only
add serverActionFn // action to add a new plugin to the server block
} }
type option struct { type option struct {
status string status string
add pluginActionFn
replacedBy string replacedBy string
additional string additional string
action optionActionFn action optionActionFn // take action affecting this option only
add pluginActionFn // take action to add the option to the plugin
} }
type release struct { type release struct {
k8sRelease string k8sRelease string
nextVersion string nextVersion string
dockerImageSHA string dockerImageSHA string
plugins map[string]plugin plugins map[string]plugin // list of plugins with deprecation status and migration actions
// defaultConf hold the default Corefile template packaged with the corresponding k8sRelease. // postProcess is a post processing action to take on the corefile as a whole. Used for complex migration
// tasks that dont fit well into the modular plugin/option migration framework. For example, when the
// action on a plugin would need to extend beyond the scope of that plugin (affecting other plugins, or
// server blocks, etc). e.g. Splitting plugins out into separate server blocks.
postProcess corefileAction
// defaultConf holds the default Corefile template packaged with the corresponding k8sRelease.
// Wildcards are used for fuzzy matching: // Wildcards are used for fuzzy matching:
// "*" matches exactly one token // "*" matches exactly one token
// "***" matches 0 all remaining tokens on the line // "***" matches 0 all remaining tokens on the line
@ -36,7 +43,8 @@ type release struct {
defaultConf string defaultConf string
} }
type serverActionFn func(server *corefile.Server) (*corefile.Server, error) type corefileAction func(*corefile.Corefile) (*corefile.Corefile, error)
type serverActionFn func(*corefile.Server) (*corefile.Server, error)
type pluginActionFn func(*corefile.Plugin) (*corefile.Plugin, error) type pluginActionFn func(*corefile.Plugin) (*corefile.Plugin, error)
type optionActionFn func(*corefile.Option) (*corefile.Option, error) type optionActionFn func(*corefile.Option) (*corefile.Option, error)
@ -48,7 +56,7 @@ func renamePlugin(p *corefile.Plugin, to string) (*corefile.Plugin, error) {
return p, nil return p, nil
} }
func addToServerBlocksWithPlugins(sb *corefile.Server, newPlugin *corefile.Plugin, with []string) (*corefile.Server, error) { func addToServerBlockWithPlugins(sb *corefile.Server, newPlugin *corefile.Plugin, with []string) (*corefile.Server, error) {
if len(with) == 0 { if len(with) == 0 {
// add to all blocks // add to all blocks
sb.Plugins = append(sb.Plugins, newPlugin) sb.Plugins = append(sb.Plugins, newPlugin)
@ -67,15 +75,15 @@ func addToServerBlocksWithPlugins(sb *corefile.Server, newPlugin *corefile.Plugi
} }
func addToKubernetesServerBlocks(sb *corefile.Server, newPlugin *corefile.Plugin) (*corefile.Server, error) { func addToKubernetesServerBlocks(sb *corefile.Server, newPlugin *corefile.Plugin) (*corefile.Server, error) {
return addToServerBlocksWithPlugins(sb, newPlugin, []string{"kubernetes"}) return addToServerBlockWithPlugins(sb, newPlugin, []string{"kubernetes"})
} }
func addToForwardingServerBlocks(sb *corefile.Server, newPlugin *corefile.Plugin) (*corefile.Server, error) { func addToForwardingServerBlocks(sb *corefile.Server, newPlugin *corefile.Plugin) (*corefile.Server, error) {
return addToServerBlocksWithPlugins(sb, newPlugin, []string{"forward", "proxy"}) return addToServerBlockWithPlugins(sb, newPlugin, []string{"forward", "proxy"})
} }
func addToAllServerBlocks(sb *corefile.Server, newPlugin *corefile.Plugin) (*corefile.Server, error) { func addToAllServerBlocks(sb *corefile.Server, newPlugin *corefile.Plugin) (*corefile.Server, error) {
return addToServerBlocksWithPlugins(sb, newPlugin, []string{}) return addToServerBlockWithPlugins(sb, newPlugin, []string{})
} }
var Versions = map[string]release{ var Versions = map[string]release{
@ -164,6 +172,7 @@ var Versions = map[string]release{
"reload": {}, "reload": {},
"loadbalance": {}, "loadbalance": {},
}, },
postProcess: breakForwardStubDomainsIntoServerBlocks,
}, },
"1.4.0": { "1.4.0": {
nextVersion: "1.5.0", nextVersion: "1.5.0",
@ -242,6 +251,7 @@ var Versions = map[string]release{
"reload": {}, "reload": {},
"loadbalance": {}, "loadbalance": {},
}, },
postProcess: breakForwardStubDomainsIntoServerBlocks,
}, },
"1.3.1": { "1.3.1": {
nextVersion: "1.4.0", nextVersion: "1.4.0",
@ -1056,3 +1066,43 @@ var proxyRemoveHttpsGoogleProtocol = func(o *corefile.Option) (*corefile.Option,
} }
return o, nil return o, nil
} }
func breakForwardStubDomainsIntoServerBlocks(cf *corefile.Corefile) (*corefile.Corefile, error) {
for _, sb := range cf.Servers {
for j, fwd := range sb.Plugins {
if fwd.Name != "forward" {
continue
}
if len(fwd.Args) == 0 {
return nil, errors.New("found invalid forward plugin declaration")
}
if fwd.Args[0] == "." {
// dont move the default upstream
continue
}
if len(sb.DomPorts) != 1 {
return cf, errors.New("unhandled migration of multi-domain/port server block")
}
if sb.DomPorts[0] != "." && sb.DomPorts[0] != ".:53" {
return cf, errors.New("unhandled migration of non-default domain/port server block")
}
newSb := &corefile.Server{} // create a new server block
newSb.DomPorts = []string{fwd.Args[0]} // copy the forward zone to the server block domain
fwd.Args[0] = "." // the plugin's zone changes to "." for brevity
newSb.Plugins = append(newSb.Plugins, fwd) // add the plugin to its new server block
// Add appropriate addtl plugins to new server block
newSb.Plugins = append(newSb.Plugins, &corefile.Plugin{Name: "loop"})
newSb.Plugins = append(newSb.Plugins, &corefile.Plugin{Name: "errors"})
newSb.Plugins = append(newSb.Plugins, &corefile.Plugin{Name: "cache", Args: []string{"30"}})
//add new server block to corefile
cf.Servers = append(cf.Servers, newSb)
//remove the forward plugin from the original server block
sb.Plugins = append(sb.Plugins[:j], sb.Plugins[j+1:]...)
}
}
return cf, nil
}