diff --git a/kubernetes/corefile-tool/.gitignore b/kubernetes/corefile-tool/.gitignore deleted file mode 100644 index 50d0b69..0000000 --- a/kubernetes/corefile-tool/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -Corefile -corefile-tool -*.yaml diff --git a/kubernetes/corefile-tool/README.md b/kubernetes/corefile-tool/README.md index 70b4e50..a352afe 100644 --- a/kubernetes/corefile-tool/README.md +++ b/kubernetes/corefile-tool/README.md @@ -1,73 +1,3 @@ ## Corefile-tool -Corefile-tool is a command line tool which helps you to evaluate and migrate your CoreDNS Corefile Configuration. -It uses the [CoreDNS migration tool library](https://github.com/coredns/deployment/tree/master/kubernetes/migration). - -## Usage - -Use the following syntax to run the `corefile-tool` command: - -``` -Usage: - corefile-tool default --corefile [--k8sversion ] - corefile-tool deprecated --from --to --corefile - corefile-tool migrate --from --to --corefile [--deprecations ] - corefile-tool downgrade --from --to --corefile - corefile-tool released --dockerImageId - corefile-tool unsupported --from --to --corefile - corefile-tool validversions -``` - - -### Operations - -The following operations are supported: - -- `default`: returns true if the Corefile is the default for the given version of Kubernetes. If `--k8sversion` is not specified, then this will return true if the Corefile is the default for any version of Kubernetes supported by the tool. - -- `deprecated`: returns a list of plugins/options in the Corefile that have been deprecated, removed, ignored or is a new default plugin/option. - -- `migrate`: updates your CoreDNS corefile to be compatible with the `-to` version. Setting the `--deprecations` flag to `true` will migrate plugins/options as soon as they are announced as deprecated. Setting the `--deprecations` flag to `false` will migrate plugins/options only once they are removed (or made a no-op). The default is `false`. - -- `downgrade` : downgrades your CoreDNS corefile to be compatible with the `-to` version. It will not restore plugins/options that might have been removed or altered during an upward migration. - -- `released`: determines if the `--dockerImageID` was an official CoreDNS release or not. Only official releases of CoreDNS are supported by the tool. - -- `unsupported`: returns a list of plugins/options in the Corefile that are not supported by the migration tool (but may still be valid in CoreDNS). - -- `validversions`: Shows the list of CoreDNS versions supported by the this tool. - - -### Examples - -The following examples will help you understand the basic usage of the migration tool. - -```bash -# See if the Corefile is the default in CoreDNS v1.4.0. -corefile-tool default --k8sversion 1.4.0 --corefile /path/to/Corefile -``` - -```bash -# See deprecated plugins CoreDNS from v1.4.0 to v1.5.0. -corefile-tool deprecated --from 1.4.0 --to 1.5.0 --corefile /path/to/Corefile -``` - -```bash -# See unsupported plugins CoreDNS from v1.4.0 to v1.5.0. -corefile-tool unsupported --from 1.4.0 --to 1.5.0 --corefile /path/to/Corefile -``` - -```bash -# Migrate CoreDNS from v1.4.0 to v1.5.0 and also migrate all the deprecations -# that are present in the current Corefile. -corefile-tool migrate --from 1.4.0 --to 1.5.0 --corefile /path/to/Corefile --deprecations true - -# Migrate CoreDNS from v1.2.2 to v1.3.1 and do not also migrate all the deprecations -# that are present in the current Corefile. -corefile-tool migrate --from 1.2.2 --to 1.3.1 --corefile /path/to/Corefile --deprecations false -``` -```bash -# Downgrade CoreDNS from v1.5.0 to v1.4.0 -corefile-tool downgrade --from 1.5.0 --to 1.4.0 --corefile /path/to/Corefile -``` - +Corefile-tool has moved to https://github.com/coredns/corefile-migration/tree/master/corefile-tool \ No newline at end of file diff --git a/kubernetes/corefile-tool/cmd/default.go b/kubernetes/corefile-tool/cmd/default.go deleted file mode 100644 index c719ac7..0000000 --- a/kubernetes/corefile-tool/cmd/default.go +++ /dev/null @@ -1,47 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/coredns/deployment/kubernetes/migration" - - "github.com/spf13/cobra" -) - -// NewDefaultCmd represents the default command -func NewDefaultCmd() *cobra.Command { - defaultCmd := &cobra.Command{ - Use: "default", - Short: "default returns true if the Corefile is the default for a that version of Kubernetes. If the Kubernetes version is omitted, returns true if the Corefile is the default for any version.", - Example: `# See if the Corefile is the default in CoreDNS v1.4.0. -corefile-tool default --k8sversion 1.4.0 --corefile /path/to/Corefile`, - RunE: func(cmd *cobra.Command, args []string) error { - k8sversion, _ := cmd.Flags().GetString("k8sversion") - corefile, _ := cmd.Flags().GetString("corefile") - - isDefault, err := defaultCorefileFromPath(k8sversion, corefile) - if err != nil { - return fmt.Errorf("error while checking if the Corefile is the default: %v \n", err) - } - fmt.Println(isDefault) - - return nil - }, - } - defaultCmd.Flags().String("k8sversion", "", "The Kubernetes version for which you are checking the default.") - defaultCmd.Flags().String("corefile", "", "Required: The path where your Corefile is located.") - defaultCmd.MarkFlagRequired("corefile") - - return defaultCmd -} - -// defaultCorefileFromPath takes the path where the Corefile is located and checks -// if the Corefile is the default for that version of Kubernetes. -func defaultCorefileFromPath(k8sVersion, corefilePath string) (bool, error) { - fileBytes, err := getCorefileFromPath(corefilePath) - if err != nil { - return false, err - } - corefileStr := string(fileBytes) - return migration.Default(k8sVersion, corefileStr), nil -} diff --git a/kubernetes/corefile-tool/cmd/deprecated.go b/kubernetes/corefile-tool/cmd/deprecated.go deleted file mode 100644 index b9cbad5..0000000 --- a/kubernetes/corefile-tool/cmd/deprecated.go +++ /dev/null @@ -1,51 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/coredns/deployment/kubernetes/migration" - - "github.com/spf13/cobra" -) - -// NewDeprecatedCmd represents the deprecated command -func NewDeprecatedCmd() *cobra.Command { - deprecatedCmd := &cobra.Command{ - Use: "deprecated", - Short: "Deprecated returns a list of deprecated, removed, ignored and new default plugins or directives present in the Corefile.", - Example: `# See deprecated, removed, ignored and new default plugins CoreDNS from v1.4.0 to v1.5.0. -corefile-tool deprecated --from 1.4.0 --to 1.5.0 --corefile /path/to/Corefile`, - RunE: func(cmd *cobra.Command, args []string) error { - from, _ := cmd.Flags().GetString("from") - to, _ := cmd.Flags().GetString("to") - corefile, _ := cmd.Flags().GetString("corefile") - deprecated, err := deprecatedCorefileFromPath(from, to, corefile) - if err != nil { - return fmt.Errorf("error while listing deprecated plugins: %v \n", err) - } - for _, dep := range deprecated { - fmt.Println(dep.ToString()) - } - return nil - }, - } - deprecatedCmd.Flags().String("from", "", "Required: The version you are migrating from. ") - deprecatedCmd.MarkFlagRequired("from") - deprecatedCmd.Flags().String("to", "", "Required: The version you are migrating to.") - deprecatedCmd.MarkFlagRequired("to") - deprecatedCmd.Flags().String("corefile", "", "Required: The path where your Corefile is located.") - deprecatedCmd.MarkFlagRequired("corefile") - - return deprecatedCmd -} - -// deprecatedCorefileFromPath takes the path where the Corefile is located and returns the deprecated plugins or directives -// present in the Corefile. -func deprecatedCorefileFromPath(fromCoreDNSVersion, toCoreDNSVersion, corefilePath string) ([]migration.Notice, error) { - fileBytes, err := getCorefileFromPath(corefilePath) - if err != nil { - return nil, err - } - corefileStr := string(fileBytes) - return migration.Deprecated(fromCoreDNSVersion, toCoreDNSVersion, corefileStr) -} diff --git a/kubernetes/corefile-tool/cmd/downgrade.go b/kubernetes/corefile-tool/cmd/downgrade.go deleted file mode 100644 index 632354f..0000000 --- a/kubernetes/corefile-tool/cmd/downgrade.go +++ /dev/null @@ -1,51 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/coredns/deployment/kubernetes/migration" - - "github.com/spf13/cobra" -) - -// NewDowngradeCmd represents the downgrade command -func NewDowngradeCmd() *cobra.Command { - var migrateCmd = &cobra.Command{ - Use: "downgrade", - Short: "Downgrade your CoreDNS corefile to a previous version", - Example: `# Downgrade CoreDNS from v1.5.0 to v1.4.0. -corefile-tool downgrade --from 1.5.0 --to 1.4.0 --corefile /path/to/Corefile`, - RunE: func(cmd *cobra.Command, args []string) error { - from, _ := cmd.Flags().GetString("from") - to, _ := cmd.Flags().GetString("to") - corefile, _ := cmd.Flags().GetString("corefile") - - migrated, err := downgradeCorefileFromPath(from, to, corefile) - if err != nil { - return fmt.Errorf("error while migration: %v \n", err) - } - fmt.Println(migrated) - return nil - }, - } - migrateCmd.Flags().String("from", "", "Required: The version you are migrating from. ") - migrateCmd.MarkFlagRequired("from") - migrateCmd.Flags().String("to", "", "Required: The version you are migrating to.") - migrateCmd.MarkFlagRequired("to") - migrateCmd.Flags().String("corefile", "", "Required: The path where your Corefile is located.") - migrateCmd.MarkFlagRequired("corefile") - migrateCmd.Flags().Bool("deprecations", false, "Specify whether you want to handle plugin deprecations. [True | False] ") - - return migrateCmd -} - -// downgradeCorefileFromPath takes the path where the Corefile is located and downgrades the Corefile to the -// desrired version. -func downgradeCorefileFromPath(fromCoreDNSVersion, toCoreDNSVersion, corefilePath string) (string, error) { - fileBytes, err := getCorefileFromPath(corefilePath) - if err != nil { - return "", err - } - corefileStr := string(fileBytes) - return migration.MigrateDown(fromCoreDNSVersion, toCoreDNSVersion, corefileStr) -} diff --git a/kubernetes/corefile-tool/cmd/migrate.go b/kubernetes/corefile-tool/cmd/migrate.go deleted file mode 100644 index 313ece5..0000000 --- a/kubernetes/corefile-tool/cmd/migrate.go +++ /dev/null @@ -1,55 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/coredns/deployment/kubernetes/migration" - - "github.com/spf13/cobra" -) - -// NewMigrateCmd represents the migrate command -func NewMigrateCmd() *cobra.Command { - var migrateCmd = &cobra.Command{ - Use: "migrate", - Short: "Migrate your CoreDNS corefile", - Example: `# Migrate CoreDNS from v1.4.0 to v1.5.0 and handle deprecations . -corefile-tool migrate --from 1.4.0 --to 1.5.0 --corefile /path/to/Corefile --deprecations true - -# Migrate CoreDNS from v1.2.2 to v1.3.1 and do not handle deprecations . -corefile-tool migrate --from 1.2.2 --to 1.3.1 --corefile /path/to/Corefile --deprecations false`, - RunE: func(cmd *cobra.Command, args []string) error { - from, _ := cmd.Flags().GetString("from") - to, _ := cmd.Flags().GetString("to") - corefile, _ := cmd.Flags().GetString("corefile") - deprecations, _ := cmd.Flags().GetBool("deprecations") - - migrated, err := migrateCorefileFromPath(from, to, corefile, deprecations) - if err != nil { - return fmt.Errorf("error while migration: %v \n", err) - } - fmt.Println(migrated) - return nil - }, - } - migrateCmd.Flags().String("from", "", "Required: The version you are migrating from. ") - migrateCmd.MarkFlagRequired("from") - migrateCmd.Flags().String("to", "", "Required: The version you are migrating to.") - migrateCmd.MarkFlagRequired("to") - migrateCmd.Flags().String("corefile", "", "Required: The path where your Corefile is located.") - migrateCmd.MarkFlagRequired("corefile") - migrateCmd.Flags().Bool("deprecations", false, "Specify whether you want to handle plugin deprecations. [True | False] ") - - return migrateCmd -} - -// migrateCorefileFromPath takes the path where the Corefile is located and migrates the Corefile to the -// desrired version. -func migrateCorefileFromPath(fromCoreDNSVersion, toCoreDNSVersion, corefilePath string, deprecations bool) (string, error) { - fileBytes, err := getCorefileFromPath(corefilePath) - if err != nil { - return "", err - } - corefileStr := string(fileBytes) - return migration.Migrate(fromCoreDNSVersion, toCoreDNSVersion, corefileStr, deprecations) -} diff --git a/kubernetes/corefile-tool/cmd/released.go b/kubernetes/corefile-tool/cmd/released.go deleted file mode 100644 index 0eb942d..0000000 --- a/kubernetes/corefile-tool/cmd/released.go +++ /dev/null @@ -1,32 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/coredns/deployment/kubernetes/migration" - - "github.com/spf13/cobra" -) - -// NewReleasedCmd represents the released command -func NewReleasedCmd() *cobra.Command { - releasedCmd := &cobra.Command{ - Use: "released", - Short: "Determines whether your Docker Image SHA of a CoreDNS release is valid or not", - Run: func(cmd *cobra.Command, args []string) { - image, _ := cmd.Flags().GetString("dockerImageSHA") - result := migration.Released(image) - - if result { - fmt.Println("The docker image SHA is valid") - } else { - fmt.Println("The docker image SHA is invalid") - } - }, - } - - releasedCmd.Flags().String("dockerImageSHA", "", "Required: The docker image SHA you want to check. ") - releasedCmd.MarkFlagRequired("dockerImageSHA") - - return releasedCmd -} diff --git a/kubernetes/corefile-tool/cmd/root.go b/kubernetes/corefile-tool/cmd/root.go deleted file mode 100644 index cc0949a..0000000 --- a/kubernetes/corefile-tool/cmd/root.go +++ /dev/null @@ -1,59 +0,0 @@ -package cmd - -import ( - "fmt" - "io/ioutil" - "os" - - "github.com/lithammer/dedent" - "github.com/spf13/cobra" -) - -// CorefileTool represents the base command for the corefile-tool. -func CorefileTool() *cobra.Command { - rootCmd := &cobra.Command{ - Use: "corefile-tool", - Short: "A brief description of your application", - Long: dedent.Dedent(` - - ┌──────────────────────────────────────────────────────────┐ - │ CoreDNS Migration Tool │ - │ Easily Migrate your Corefile │ - │ │ - │ Please give us feedback at: │ - │ https://github.com/coredns/deployment/issues │ - └──────────────────────────────────────────────────────────┘ - - `), - } - rootCmd.AddCommand(NewMigrateCmd()) - rootCmd.AddCommand(NewDowngradeCmd()) - rootCmd.AddCommand(NewDefaultCmd()) - rootCmd.AddCommand(NewDeprecatedCmd()) - rootCmd.AddCommand(NewUnsupportedCmd()) - rootCmd.AddCommand(NewValidVersionsCmd()) - rootCmd.AddCommand(NewReleasedCmd()) - - return rootCmd -} - -// Execute adds all child commands to the root command and sets flags appropriately. -func Execute() { - if err := CorefileTool().Execute(); err != nil { - fmt.Println(err) - os.Exit(1) - } -} - -func getCorefileFromPath(corefilePath string) ([]byte, error) { - if _, err := os.Stat(corefilePath); os.IsNotExist(err) { - return nil, err - } - - fileBytes, err := ioutil.ReadFile(corefilePath) - if err != nil { - return nil, err - } - - return fileBytes, nil -} diff --git a/kubernetes/corefile-tool/cmd/unsupported.go b/kubernetes/corefile-tool/cmd/unsupported.go deleted file mode 100644 index 60b8ac6..0000000 --- a/kubernetes/corefile-tool/cmd/unsupported.go +++ /dev/null @@ -1,52 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/coredns/deployment/kubernetes/migration" - - "github.com/spf13/cobra" -) - -// NewUnsupportedCmd represents the unsupported command -func NewUnsupportedCmd() *cobra.Command { - unsupportedCmd := &cobra.Command{ - Use: "unsupported", - Short: "Unsupported returns a list of plugins that are not recognized/supported by the migration tool (but may still be valid in CoreDNS).", - Example: `# See unsupported plugins CoreDNS from v1.4.0 to v1.5.0. -corefile-tool unsupported --from 1.4.0 --to 1.5.0 --corefile /path/to/Corefile`, - RunE: func(cmd *cobra.Command, args []string) error { - from, _ := cmd.Flags().GetString("from") - to, _ := cmd.Flags().GetString("to") - corefile, _ := cmd.Flags().GetString("corefile") - unsupported, err := unsupportedCorefileFromPath(from, to, corefile) - if err != nil { - return fmt.Errorf("error while listing deprecated plugins: %v \n", err) - } - for _, unsup := range unsupported { - fmt.Println(unsup.ToString()) - } - return nil - }, - } - - unsupportedCmd.Flags().String("from", "", "Required: The version you are migrating from. ") - unsupportedCmd.MarkFlagRequired("from") - unsupportedCmd.Flags().String("to", "", "Required: The version you are migrating to.") - unsupportedCmd.MarkFlagRequired("to") - unsupportedCmd.Flags().String("corefile", "", "Required: The path where your Corefile is located.") - unsupportedCmd.MarkFlagRequired("corefile") - - return unsupportedCmd -} - -// unsupportedCorefileFromPath takes the path where the Corefile is located and returns a list of plugins -// that have been removed. -func unsupportedCorefileFromPath(fromCoreDNSVersion, toCoreDNSVersion, corefilePath string) ([]migration.Notice, error) { - fileBytes, err := getCorefileFromPath(corefilePath) - if err != nil { - return nil, err - } - corefileStr := string(fileBytes) - return migration.Unsupported(fromCoreDNSVersion, toCoreDNSVersion, corefileStr) -} diff --git a/kubernetes/corefile-tool/cmd/validversions.go b/kubernetes/corefile-tool/cmd/validversions.go deleted file mode 100644 index e411d8c..0000000 --- a/kubernetes/corefile-tool/cmd/validversions.go +++ /dev/null @@ -1,23 +0,0 @@ -package cmd - -import ( - "fmt" - "strings" - - "github.com/coredns/deployment/kubernetes/migration" - - "github.com/spf13/cobra" -) - -// NewValidVersionsCmd represents the validversions command -func NewValidVersionsCmd() *cobra.Command { - validversionsCmd := &cobra.Command{ - Use: "validversions", - Short: "Shows valid versions of CoreDNS", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("The following are valid CoreDNS versions:") - fmt.Println(strings.Join(migration.ValidVersions(), ", ")) - }, - } - return validversionsCmd -} diff --git a/kubernetes/corefile-tool/main.go b/kubernetes/corefile-tool/main.go deleted file mode 100644 index af58c90..0000000 --- a/kubernetes/corefile-tool/main.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "github.com/coredns/deployment/kubernetes/corefile-tool/cmd" - -func main() { - cmd.Execute() -} diff --git a/kubernetes/migration/README.md b/kubernetes/migration/README.md index 1b60258..d8aa0f7 100644 --- a/kubernetes/migration/README.md +++ b/kubernetes/migration/README.md @@ -1,106 +1,3 @@ -# K8s/CoreDNS Corefile Migration Tools - -This Go library provides a set of functions to help handle migrations of CoreDNS Corefiles to be compatible -with new versions of CoreDNS. The task of upgrading CoreDNS is the responsibility of a variety of Kubernetes -management tools (e.g. kubeadm and others), and the precise behavior may be different for each one. This -library abstracts some basic helper functions that make this easier to implement. - -## Notifications - -Several functions in the library return a list of Notices. Each Notice is a warning of a feature deprecation, -an unsupported plugin/option, or a new required plugin/option added to the Corefile. A Notice has a `ToString()` -For display to an end user. e.g. - -``` -Plugin "foo" is deprecated in . It is replaced by "bar". -Plugin "bar" is removed in . It is replaced by "qux". -Option "foo" in plugin "bar" is added as a default in . -Plugin "baz" is unsupported by this migration tool in . -``` - - -## Functions - -### func Deprecated - -`Deprecated(fromCoreDNSVersion, toCoreDNSVersion, corefileStr string) ([]Notice, error)` - -Deprecated returns a list of deprecation notices affecting the given Corefile. Notices are returned for -any deprecated, removed, or ignored plugins/options present in the Corefile. Notices are also returned for -any new default plugins that would be added in a migration. - -### func Migrate - -`Migrate(fromCoreDNSVersion, toCoreDNSVersion, corefileStr string, deprecations bool) (string, error)` - -Migrate returns a migrated version of the Corefile, or an error if it cannot. The _to_ version -must be >= the _from_ version. It will: - * replace/convert any plugins/options that have replacements (e.g. _proxy_ -> _forward_) - * return an error if replacable plugins/options cannot be converted (e.g. proxy _options_ not available in _forward_) - * remove plugins/options that do not have replacements (e.g. kubernetes `upstream`) - * add in any new default plugins where applicable if they are not already present. - * If deprecations is true, deprecated plugins/options will be migrated as soon as they are deprecated. - * If deprecations is false, deprecated plugins/options will be migrated only once they become removed or ignored. - -### func MigrateDown - -`MigrateDown(fromCoreDNSVersion, toCoreDNSVersion, corefileStr string) (string, error)` - -MigrateDown returns a downward migrated version of the Corefile, or an error if it cannot. The _to_ version -must be <= the _from_ version. - * It will handle the removal of plugins and options that no longer exist in the destination - version when downgrading. - * It will not restore plugins/options that might have been removed or altered during an upward migration. - -### func Unsupported - -`Unsupported(fromCoreDNSVersion, toCoreDNSVersion, corefileStr string) ([]Notice, error)` - -Unsupported returns a list Notices for plugins/options that are unhandled by this migration tool, -but may still be valid in CoreDNS. Currently, only a subset of plugins included by default in CoreDNS are supported -by this tool. - - -### func Default - -`Default(k8sVersion, corefileStr string) bool` - -Default returns true if the Corefile is the default for a given version of Kubernetes. -Or, if k8sVersion is empty, Default returns true if the Corefile is the default for any version of Kubernetes. - - -### func Released - -`Released(dockerImageSHA string) bool` - -Released returns true if dockerImageSHA matches any released image of CoreDNS. - - -### func ValidVersions - -`ValidVersions() []string` - -ValidVersions returns a list of all versions supported by this tool. - - -## Command Line Converter Example - -An example use of this library is provided [here](../corefile-tool/). - - -## Kubernetes Cluster Managemnt Tool Usage - -This is an example flow of how this library could be used by a Kubernetes cluster management tool to perform a -Corefile migration during an upgrade... - -0. Check `Released()` to verify that the installed version of CoreDNS is an official release. -1. Check `Default()`, if the Corefile is a default, simply re-deploy the new default over top the old one. No migration needed. - If the Corefile is not a default, continue... -2. Check `Deprecated()`, if anything is deprecated, warn user, but continue install. -3. Check `Unsupported()`, if anything is unsupported, abort and warn user (allow user to override to pass this). -4. Call `Migrate()`, if there is an error, abort and warn user. -5. If there is no error, pause and ask user if they want to continue with the migration. If the starting Corefile was at defaults, - proceed use the migrated Corefile. - - +# K8s/CoreDNS Corefile Migration +Corefile Migration has moved to https://github.com/coredns/corefile-migration/tree/master/migration \ No newline at end of file diff --git a/kubernetes/migration/caddy/alltokens.go b/kubernetes/migration/caddy/alltokens.go deleted file mode 100644 index a8fdcab..0000000 --- a/kubernetes/migration/caddy/alltokens.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015 Light Code Labs, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package caddy - -import "io" - -// allTokens lexes the entire input, but does not parse it. -// It returns all the tokens from the input, unstructured -// and in order. -func allTokens(input io.Reader) ([]Token, error) { - l := new(lexer) - err := l.load(input) - if err != nil { - return nil, err - } - var tokens []Token - for l.next() { - tokens = append(tokens, l.token) - } - return tokens, nil -} diff --git a/kubernetes/migration/caddy/dispenser.go b/kubernetes/migration/caddy/dispenser.go deleted file mode 100644 index 0e12d5b..0000000 --- a/kubernetes/migration/caddy/dispenser.go +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2015 Light Code Labs, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package caddy - -import ( - "errors" - "fmt" - "io" - "strings" -) - -// Dispenser is a type that dispenses tokens, similarly to a lexer, -// except that it can do so with some notion of structure and has -// some really convenient methods. -type Dispenser struct { - filename string - tokens []Token - cursor int - nesting int -} - -// NewDispenser returns a Dispenser, ready to use for parsing the given input. -func NewDispenser(filename string, input io.Reader) Dispenser { - tokens, _ := allTokens(input) // ignoring error because nothing to do with it - return Dispenser{ - filename: filename, - tokens: tokens, - cursor: -1, - } -} - -// NewDispenserTokens returns a Dispenser filled with the given tokens. -func NewDispenserTokens(filename string, tokens []Token) Dispenser { - return Dispenser{ - filename: filename, - tokens: tokens, - cursor: -1, - } -} - -// Next loads the next token. Returns true if a token -// was loaded; false otherwise. If false, all tokens -// have been consumed. -func (d *Dispenser) Next() bool { - if d.cursor < len(d.tokens)-1 { - d.cursor++ - return true - } - return false -} - -// NextArg loads the next token if it is on the same -// line. Returns true if a token was loaded; false -// otherwise. If false, all tokens on the line have -// been consumed. It handles imported tokens correctly. -func (d *Dispenser) NextArg() bool { - if d.cursor < 0 { - d.cursor++ - return true - } - if d.cursor >= len(d.tokens) { - return false - } - if d.cursor < len(d.tokens)-1 && - d.tokens[d.cursor].File == d.tokens[d.cursor+1].File && - d.tokens[d.cursor].Line+d.numLineBreaks(d.cursor) == d.tokens[d.cursor+1].Line { - d.cursor++ - return true - } - return false -} - -// NextLine loads the next token only if it is not on the same -// line as the current token, and returns true if a token was -// loaded; false otherwise. If false, there is not another token -// or it is on the same line. It handles imported tokens correctly. -func (d *Dispenser) NextLine() bool { - if d.cursor < 0 { - d.cursor++ - return true - } - if d.cursor >= len(d.tokens) { - return false - } - if d.cursor < len(d.tokens)-1 && - (d.tokens[d.cursor].File != d.tokens[d.cursor+1].File || - d.tokens[d.cursor].Line+d.numLineBreaks(d.cursor) < d.tokens[d.cursor+1].Line) { - d.cursor++ - return true - } - return false -} - -// NextBlock can be used as the condition of a for loop -// to load the next token as long as it opens a block or -// is already in a block. It returns true if a token was -// loaded, or false when the block's closing curly brace -// was loaded and thus the block ended. Nested blocks are -// not supported. -func (d *Dispenser) NextBlock() bool { - if d.nesting > 0 { - d.Next() - if d.Val() == "}" { - d.nesting-- - return false - } - return true - } - if !d.NextArg() { // block must open on same line - return false - } - if d.Val() != "{" { - d.cursor-- // roll back if not opening brace - return false - } - d.Next() - if d.Val() == "}" { - // Open and then closed right away - return false - } - d.nesting++ - return true -} - -// Val gets the text of the current token. If there is no token -// loaded, it returns empty string. -func (d *Dispenser) Val() string { - if d.cursor < 0 || d.cursor >= len(d.tokens) { - return "" - } - return d.tokens[d.cursor].Text -} - -// Line gets the line number of the current token. If there is no token -// loaded, it returns 0. -func (d *Dispenser) Line() int { - if d.cursor < 0 || d.cursor >= len(d.tokens) { - return 0 - } - return d.tokens[d.cursor].Line -} - -// File gets the filename of the current token. If there is no token loaded, -// it returns the filename originally given when parsing started. -func (d *Dispenser) File() string { - if d.cursor < 0 || d.cursor >= len(d.tokens) { - return d.filename - } - if tokenFilename := d.tokens[d.cursor].File; tokenFilename != "" { - return tokenFilename - } - return d.filename -} - -// Args is a convenience function that loads the next arguments -// (tokens on the same line) into an arbitrary number of strings -// pointed to in targets. If there are fewer tokens available -// than string pointers, the remaining strings will not be changed -// and false will be returned. If there were enough tokens available -// to fill the arguments, then true will be returned. -func (d *Dispenser) Args(targets ...*string) bool { - enough := true - for i := 0; i < len(targets); i++ { - if !d.NextArg() { - enough = false - break - } - *targets[i] = d.Val() - } - return enough -} - -// RemainingArgs loads any more arguments (tokens on the same line) -// into a slice and returns them. Open curly brace tokens also indicate -// the end of arguments, and the curly brace is not included in -// the return value nor is it loaded. -func (d *Dispenser) RemainingArgs() []string { - var args []string - - for d.NextArg() { - if d.Val() == "{" { - d.cursor-- - break - } - args = append(args, d.Val()) - } - - return args -} - -// ArgErr returns an argument error, meaning that another -// argument was expected but not found. In other words, -// a line break or open curly brace was encountered instead of -// an argument. -func (d *Dispenser) ArgErr() error { - if d.Val() == "{" { - return d.Err("Unexpected token '{', expecting argument") - } - return d.Errf("Wrong argument count or unexpected line ending after '%s'", d.Val()) -} - -// SyntaxErr creates a generic syntax error which explains what was -// found and what was expected. -func (d *Dispenser) SyntaxErr(expected string) error { - msg := fmt.Sprintf("%s:%d - Syntax error: Unexpected token '%s', expecting '%s'", d.File(), d.Line(), d.Val(), expected) - return errors.New(msg) -} - -// EOFErr returns an error indicating that the dispenser reached -// the end of the input when searching for the next token. -func (d *Dispenser) EOFErr() error { - return d.Errf("Unexpected EOF") -} - -// Err generates a custom parse-time error with a message of msg. -func (d *Dispenser) Err(msg string) error { - msg = fmt.Sprintf("%s:%d - Error during parsing: %s", d.File(), d.Line(), msg) - return errors.New(msg) -} - -// Errf is like Err, but for formatted error messages -func (d *Dispenser) Errf(format string, args ...interface{}) error { - return d.Err(fmt.Sprintf(format, args...)) -} - -// numLineBreaks counts how many line breaks are in the token -// value given by the token index tknIdx. It returns 0 if the -// token does not exist or there are no line breaks. -func (d *Dispenser) numLineBreaks(tknIdx int) int { - if tknIdx < 0 || tknIdx >= len(d.tokens) { - return 0 - } - return strings.Count(d.tokens[tknIdx].Text, "\n") -} - -// isNewLine determines whether the current token is on a different -// line (higher line number) than the previous token. It handles imported -// tokens correctly. If there isn't a previous token, it returns true. -func (d *Dispenser) isNewLine() bool { - if d.cursor < 1 { - return true - } - if d.cursor > len(d.tokens)-1 { - return false - } - return d.tokens[d.cursor-1].File != d.tokens[d.cursor].File || - d.tokens[d.cursor-1].Line+d.numLineBreaks(d.cursor-1) < d.tokens[d.cursor].Line -} diff --git a/kubernetes/migration/caddy/lexer.go b/kubernetes/migration/caddy/lexer.go deleted file mode 100644 index 4114db9..0000000 --- a/kubernetes/migration/caddy/lexer.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2015 Light Code Labs, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package caddy - -import ( - "bufio" - "io" - "unicode" -) - -type ( - // lexer is a utility which can get values, token by - // token, from a Reader. A token is a word, and tokens - // are separated by whitespace. A word can be enclosed - // in quotes if it contains whitespace. - lexer struct { - reader *bufio.Reader - token Token - line int - } - - // Token represents a single parsable unit. - Token struct { - File string - Line int - Text string - } -) - -// load prepares the lexer to scan an input for tokens. -// It discards any leading byte order mark. -func (l *lexer) load(input io.Reader) error { - l.reader = bufio.NewReader(input) - l.line = 1 - - // discard byte order mark, if present - firstCh, _, err := l.reader.ReadRune() - if err != nil { - return err - } - if firstCh != 0xFEFF { - err := l.reader.UnreadRune() - if err != nil { - return err - } - } - - return nil -} - -// next loads the next token into the lexer. -// A token is delimited by whitespace, unless -// the token starts with a quotes character (") -// in which case the token goes until the closing -// quotes (the enclosing quotes are not included). -// Inside quoted strings, quotes may be escaped -// with a preceding \ character. No other chars -// may be escaped. The rest of the line is skipped -// if a "#" character is read in. Returns true if -// a token was loaded; false otherwise. -func (l *lexer) next() bool { - var val []rune - var comment, quoted, escaped bool - - makeToken := func() bool { - l.token.Text = string(val) - return true - } - - for { - ch, _, err := l.reader.ReadRune() - if err != nil { - if len(val) > 0 { - return makeToken() - } - if err == io.EOF { - return false - } - panic(err) - } - - if quoted { - if !escaped { - if ch == '\\' { - escaped = true - continue - } else if ch == '"' { - quoted = false - return makeToken() - } - } - if ch == '\n' { - l.line++ - } - if escaped { - // only escape quotes - if ch != '"' { - val = append(val, '\\') - } - } - val = append(val, ch) - escaped = false - continue - } - - if unicode.IsSpace(ch) { - if ch == '\r' { - continue - } - if ch == '\n' { - l.line++ - comment = false - } - if len(val) > 0 { - return makeToken() - } - continue - } - - if ch == '#' { - comment = true - } - - if comment { - continue - } - - if len(val) == 0 { - l.token = Token{Line: l.line} - if ch == '"' { - quoted = true - continue - } - } - - val = append(val, ch) - } -} diff --git a/kubernetes/migration/corefile/corefile.go b/kubernetes/migration/corefile/corefile.go deleted file mode 100644 index e548b6c..0000000 --- a/kubernetes/migration/corefile/corefile.go +++ /dev/null @@ -1,179 +0,0 @@ -package corefile - -import ( - "strings" - - "github.com/coredns/deployment/kubernetes/migration/caddy" -) - -type Corefile struct { - Servers []*Server -} - -type Server struct { - DomPorts []string - Plugins []*Plugin -} - -type Plugin struct { - Name string - Args []string - Options []*Option -} - -type Option struct { - Name string - Args []string -} - -func New(s string) (*Corefile, error) { - c := Corefile{} - cc := caddy.NewDispenser("migration", strings.NewReader(s)) - depth := 0 - var cSvr *Server - var cPlg *Plugin - for cc.Next() { - if cc.Val() == "{" { - depth += 1 - continue - } else if cc.Val() == "}" { - depth -= 1 - continue - } - val := cc.Val() - args := cc.RemainingArgs() - switch depth { - case 0: - c.Servers = append(c.Servers, - &Server{ - DomPorts: append([]string{val}, args...), - }) - cSvr = c.Servers[len(c.Servers)-1] - case 1: - cSvr.Plugins = append(cSvr.Plugins, - &Plugin{ - Name: val, - Args: args, - }) - cPlg = cSvr.Plugins[len(cSvr.Plugins)-1] - case 2: - cPlg.Options = append(cPlg.Options, - &Option{ - Name: val, - Args: args, - }) - } - } - return &c, nil -} - -func (c *Corefile) ToString() (out string) { - strs := []string{} - for _, s := range c.Servers { - strs = append(strs, s.ToString()) - } - return strings.Join(strs, "\n") -} - -func (s *Server) ToString() (out string) { - str := strings.Join(s.DomPorts, " ") - strs := []string{} - for _, p := range s.Plugins { - strs = append(strs, strings.Repeat(" ", indent)+p.ToString()) - } - if len(strs) > 0 { - str += " {\n" + strings.Join(strs, "\n") + "\n}\n" - } - return str -} - -func (p *Plugin) ToString() (out string) { - str := strings.Join(append([]string{p.Name}, p.Args...), " ") - strs := []string{} - for _, o := range p.Options { - strs = append(strs, strings.Repeat(" ", indent*2)+o.ToString()) - } - if len(strs) > 0 { - str += " {\n" + strings.Join(strs, "\n") + "\n" + strings.Repeat(" ", indent*1) + "}" - } - return str -} - -func (o *Option) ToString() (out string) { - str := strings.Join(append([]string{o.Name}, o.Args...), " ") - return str -} - -func (s *Server) FindMatch(def []*Server) (*Server, bool) { -NextServer: - for _, sDef := range def { - for i, dp := range sDef.DomPorts { - if dp == "*" { - continue - } - if dp == "***" { - return sDef, true - } - if i >= len(s.DomPorts) || dp != s.DomPorts[i] { - continue NextServer - } - } - if len(sDef.DomPorts) != len(s.DomPorts) { - continue - } - return sDef, true - } - return nil, false -} - -func (p *Plugin) FindMatch(def []*Plugin) (*Plugin, bool) { -NextPlugin: - for _, pDef := range def { - if pDef.Name != p.Name { - continue - } - for i, arg := range pDef.Args { - if arg == "*" { - continue - } - if arg == "***" { - return pDef, true - } - if i >= len(p.Args) || arg != p.Args[i] { - continue NextPlugin - } - } - if len(pDef.Args) != len(p.Args) { - continue - } - return pDef, true - } - return nil, false -} - -func (o *Option) FindMatch(def []*Option) (*Option, bool) { -NextPlugin: - for _, oDef := range def { - if oDef.Name != o.Name { - continue - } - for i, arg := range oDef.Args { - if arg == "*" { - continue - } - if arg == "***" { - return oDef, true - } - if i >= len(o.Args) || arg != o.Args[i] { - continue NextPlugin - } - } - if len(oDef.Args) != len(o.Args) { - continue - } - return oDef, true - } - return nil, false -} - -const indent = 4 diff --git a/kubernetes/migration/corefile/corefile_test.go b/kubernetes/migration/corefile/corefile_test.go deleted file mode 100644 index 04fcde2..0000000 --- a/kubernetes/migration/corefile/corefile_test.go +++ /dev/null @@ -1,121 +0,0 @@ -package corefile - -import ( - "testing" -) - -func TestCorefile(t *testing.T) { - - startCorefile := `.:53 { - error - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - proxy . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} - -.:5353 { - proxy . /etc/resolv.conf -} -` - c, err := New(startCorefile) - - if err != nil { - t.Error(err) - } - - got := c.ToString() - - if got != startCorefile { - t.Errorf("Corefile did not match expected.\nExpected:\n%v\nGot:\n%v", startCorefile, got) - } -} - -func TestServer_FindMatch(t *testing.T) { - tests := []struct { - server *Server - match bool - }{ - {server: &Server{DomPorts: []string{".:53"}}, match: true}, - {server: &Server{DomPorts: []string{".:54"}}, match: false}, - {server: &Server{DomPorts: []string{"abc:53"}}, match: false}, - {server: &Server{DomPorts: []string{"abc:53", "blah"}}, match: true}, - {server: &Server{DomPorts: []string{"abc:53", "blah", "blah"}}, match: false}, - {server: &Server{DomPorts: []string{"xyz:53"}}, match: true}, - {server: &Server{DomPorts: []string{"xyz:53", "blah", "blah"}}, match: true}, - } - - def := []*Server{ - {DomPorts: []string{".:53"}}, - {DomPorts: []string{"abc:53", "*"}}, - {DomPorts: []string{"xyz:53", "***"}}, - } - for i, test := range tests { - _, match := test.server.FindMatch(def) - if match != test.match { - t.Errorf("In test #%v, expected match to be %v but got %v.", i, test.match, match) - } - } -} - -func TestPlugin_FindMatch(t *testing.T) { - tests := []struct { - plugin *Plugin - match bool - }{ - {plugin: &Plugin{Name: "plugin1", Args: []string{}}, match: true}, - {plugin: &Plugin{Name: "plugin2", Args: []string{"1", "1.5", "2"}}, match: true}, - {plugin: &Plugin{Name: "plugin3", Args: []string{"1", "2", "3", "4"}}, match: true}, - {plugin: &Plugin{Name: "plugin1", Args: []string{"a"}}, match: false}, - {plugin: &Plugin{Name: "plugin2", Args: []string{"1", "1.5", "b"}}, match: false}, - {plugin: &Plugin{Name: "plugin3", Args: []string{"a", "2", "3", "4"}}, match: false}, - {plugin: &Plugin{Name: "plugin4", Args: []string{}}, match: false}, - } - - def := []*Plugin{ - {Name: "plugin1", Args: []string{}}, - {Name: "plugin2", Args: []string{"1", "*", "2"}}, - {Name: "plugin3", Args: []string{"1", "***"}}, - } - for i, test := range tests { - _, match := test.plugin.FindMatch(def) - if match != test.match { - t.Errorf("In test #%v, expected match to be %v but got %v.", i, test.match, match) - } - } -} - -func TestOption_FindMatch(t *testing.T) { - tests := []struct { - option *Plugin - match bool - }{ - {option: &Plugin{Name: "option1", Args: []string{}}, match: true}, - {option: &Plugin{Name: "option2", Args: []string{"1", "1.5", "2"}}, match: true}, - {option: &Plugin{Name: "option3", Args: []string{"1", "2", "3", "4"}}, match: true}, - {option: &Plugin{Name: "option1", Args: []string{"a"}}, match: false}, - {option: &Plugin{Name: "option2", Args: []string{"1", "1.5", "b"}}, match: false}, - {option: &Plugin{Name: "option3", Args: []string{"a", "2", "3", "4"}}, match: false}, - {option: &Plugin{Name: "option4", Args: []string{}}, match: false}, - } - - def := []*Plugin{ - {Name: "option1", Args: []string{}}, - {Name: "option2", Args: []string{"1", "*", "2"}}, - {Name: "option3", Args: []string{"1", "***"}}, - } - for i, test := range tests { - _, match := test.option.FindMatch(def) - if match != test.match { - t.Errorf("In test #%v, expected match to be %v but got %v.", i, test.match, match) - } - } -} diff --git a/kubernetes/migration/go.mod b/kubernetes/migration/go.mod deleted file mode 100644 index 3e424a4..0000000 --- a/kubernetes/migration/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/coredns/deployment/kubernetes/migration - -go 1.12 diff --git a/kubernetes/migration/go.sum b/kubernetes/migration/go.sum deleted file mode 100644 index e69de29..0000000 diff --git a/kubernetes/migration/migrate.go b/kubernetes/migration/migrate.go deleted file mode 100644 index 168bc1c..0000000 --- a/kubernetes/migration/migrate.go +++ /dev/null @@ -1,445 +0,0 @@ -package migration - -// This package provides a set of functions to help handle migrations of CoreDNS Corefiles to be compatible with new -// versions of CoreDNS. The task of upgrading CoreDNS is the responsibility of a variety of Kubernetes management tools -// (e.g. kubeadm and others), and the precise behavior may be different for each one. This library abstracts some basic -// helper functions that make this easier to implement. - -import ( - "fmt" - "sort" - - "github.com/coredns/deployment/kubernetes/migration/corefile" -) - -// Deprecated returns a list of deprecation notifications affecting the guven Corefile. Notifications are returned for -// any deprecated, removed, or ignored plugins/directives present in the Corefile. Notifications are also returned for -// any new default plugins that would be added in a migration. -func Deprecated(fromCoreDNSVersion, toCoreDNSVersion, corefileStr string) ([]Notice, error) { - return getStatus(fromCoreDNSVersion, toCoreDNSVersion, corefileStr, all) -} - -// Unsupported returns a list notifications of plugins/options that are not handled supported by this migration tool, -// but may still be valid in CoreDNS. -func Unsupported(fromCoreDNSVersion, toCoreDNSVersion, corefileStr string) ([]Notice, error) { - return getStatus(fromCoreDNSVersion, toCoreDNSVersion, corefileStr, unsupported) -} - -func getStatus(fromCoreDNSVersion, toCoreDNSVersion, corefileStr, status string) ([]Notice, error) { - if fromCoreDNSVersion == toCoreDNSVersion { - return nil, nil - } - err := validUpMigration(fromCoreDNSVersion, toCoreDNSVersion) - if err != nil { - return nil, err - } - cf, err := corefile.New(corefileStr) - if err != nil { - return nil, err - } - notices := []Notice{} - v := fromCoreDNSVersion - for { - v = Versions[v].nextVersion - for _, s := range cf.Servers { - for _, p := range s.Plugins { - vp, present := Versions[v].plugins[p.Name] - if status == unsupported { - if present { - continue - } - notices = append(notices, Notice{Plugin: p.Name, Severity: status, Version: v}) - continue - } - if !present { - continue - } - if vp.status != "" && vp.status != newdefault { - notices = append(notices, Notice{ - Plugin: p.Name, - Severity: vp.status, - Version: v, - ReplacedBy: vp.replacedBy, - Additional: vp.additional, - }) - continue - } - for _, o := range p.Options { - vo, present := Versions[v].plugins[p.Name].options[o.Name] - if status == unsupported { - if present { - continue - } - notices = append(notices, Notice{ - Plugin: p.Name, - Option: o.Name, - Severity: status, - Version: v, - ReplacedBy: vo.replacedBy, - Additional: vo.additional, - }) - continue - } - if !present { - continue - } - if vo.status != "" && vo.status != newdefault { - notices = append(notices, Notice{Plugin: p.Name, Option: o.Name, Severity: vo.status, Version: v}) - continue - } - } - if status != unsupported { - CheckForNewOptions: - for name, vo := range Versions[v].plugins[p.Name].options { - if vo.status != newdefault { - continue - } - for _, o := range p.Options { - if name == o.Name { - continue CheckForNewOptions - } - } - notices = append(notices, Notice{Plugin: p.Name, Option: name, Severity: newdefault, Version: v}) - } - } - } - if status != unsupported { - CheckForNewPlugins: - for name, vp := range Versions[v].plugins { - if vp.status != newdefault { - continue - } - for _, p := range s.Plugins { - if name == p.Name { - continue CheckForNewPlugins - } - } - notices = append(notices, Notice{Plugin: name, Option: "", Severity: newdefault, Version: v}) - } - } - } - if v == toCoreDNSVersion { - break - } - } - return notices, nil -} - -// Migrate returns the Corefile converted to toCoreDNSVersion, or an error if it cannot. This function only accepts -// a forward migration, where the destination version is => the start version. -// If deprecations is true, deprecated plugins/options will be migrated as soon as they are deprecated. -// If deprecations is false, deprecated plugins/options will be migrated only once they become removed or ignored. -func Migrate(fromCoreDNSVersion, toCoreDNSVersion, corefileStr string, deprecations bool) (string, error) { - if fromCoreDNSVersion == toCoreDNSVersion { - return corefileStr, nil - } - err := validUpMigration(fromCoreDNSVersion, toCoreDNSVersion) - if err != nil { - return "", err - } - cf, err := corefile.New(corefileStr) - if err != nil { - return "", err - } - v := fromCoreDNSVersion - for { - v = Versions[v].nextVersion - newSrvs := []*corefile.Server{} - for _, s := range cf.Servers { - newPlugs := []*corefile.Plugin{} - for _, p := range s.Plugins { - vp, present := Versions[v].plugins[p.Name] - if !present { - newPlugs = append(newPlugs, p) - continue - } - if !deprecations && vp.status == deprecated { - newPlugs = append(newPlugs, p) - continue - } - if vp.action != nil { - p, err := vp.action(p) - if err != nil { - return "", err - } - if p == nil { - // remove plugin, skip options processing - continue - } - } - newOpts := []*corefile.Option{} - for _, o := range p.Options { - vo, present := Versions[v].plugins[p.Name].options[o.Name] - if !present { - newOpts = append(newOpts, o) - continue - } - if !deprecations && vo.status == deprecated { - newOpts = append(newOpts, o) - continue - } - if vo.action == nil { - newOpts = append(newOpts, o) - continue - } - o, err := vo.action(o) - if err != nil { - return "", err - } - if o == nil { - // remove option - continue - } - newOpts = append(newOpts, o) - } - newPlug := &corefile.Plugin{ - Name: p.Name, - Args: p.Args, - Options: newOpts, - } - CheckForNewOptions: - for name, vo := range Versions[v].plugins[p.Name].options { - if vo.status != newdefault { - continue - } - for _, o := range p.Options { - if name == o.Name { - continue CheckForNewOptions - } - } - newPlug, err = vo.add(newPlug) - if err != nil { - return "", err - } - } - - newPlugs = append(newPlugs, newPlug) - } - newSrv := &corefile.Server{ - DomPorts: s.DomPorts, - Plugins: newPlugs, - } - CheckForNewPlugins: - for name, vp := range Versions[v].plugins { - if vp.status != newdefault { - continue - } - for _, p := range s.Plugins { - if name == p.Name { - continue CheckForNewPlugins - } - } - newSrv, err = vp.add(newSrv) - if err != nil { - return "", err - } - } - - newSrvs = append(newSrvs, newSrv) - } - - 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 { - break - } - } - return cf.ToString(), nil -} - -// MigrateDown returns the Corefile converted to toCoreDNSVersion, or an error if it cannot. This function only accepts -// a downward migration, where the destination version is <= the start version. -func MigrateDown(fromCoreDNSVersion, toCoreDNSVersion, corefileStr string) (string, error) { - if fromCoreDNSVersion == toCoreDNSVersion { - return corefileStr, nil - } - err := validDownMigration(fromCoreDNSVersion, toCoreDNSVersion) - if err != nil { - return "", err - } - cf, err := corefile.New(corefileStr) - if err != nil { - return "", err - } - v := fromCoreDNSVersion - for { - newSrvs := []*corefile.Server{} - for _, s := range cf.Servers { - newPlugs := []*corefile.Plugin{} - for _, p := range s.Plugins { - vp, present := Versions[v].plugins[p.Name] - if !present { - newPlugs = append(newPlugs, p) - continue - } - if vp.downAction == nil { - newPlugs = append(newPlugs, p) - continue - } - p, err := vp.downAction(p) - if err != nil { - return "", err - } - if p == nil { - // remove plugin, skip options processing - continue - } - - newOpts := []*corefile.Option{} - for _, o := range p.Options { - vo, present := Versions[v].plugins[p.Name].options[o.Name] - if !present { - newOpts = append(newOpts, o) - continue - } - if vo.downAction == nil { - newOpts = append(newOpts, o) - continue - } - o, err := vo.downAction(o) - if err != nil { - return "", err - } - if o == nil { - // remove option - continue - } - newOpts = append(newOpts, o) - } - newPlug := &corefile.Plugin{ - Name: p.Name, - Args: p.Args, - Options: newOpts, - } - newPlugs = append(newPlugs, newPlug) - } - newSrv := &corefile.Server{ - DomPorts: s.DomPorts, - Plugins: newPlugs, - } - newSrvs = append(newSrvs, newSrv) - } - - cf = &corefile.Corefile{Servers: newSrvs} - - if v == toCoreDNSVersion { - break - } - v = Versions[v].priorVersion - } - return cf.ToString(), nil -} - -// Default returns true if the Corefile is the default for a given version of Kubernetes. -// Or, if k8sVersion is empty, Default returns true if the Corefile is the default for any version of Kubernetes. -func Default(k8sVersion, corefileStr string) bool { - cf, err := corefile.New(corefileStr) - if err != nil { - return false - } -NextVersion: - for _, v := range Versions { - for _, release := range v.k8sReleases { - if k8sVersion != "" && k8sVersion != release { - continue - } - } - defCf, err := corefile.New(v.defaultConf) - if err != nil { - continue - } - // check corefile against k8s release default - if len(cf.Servers) != len(defCf.Servers) { - continue NextVersion - } - for _, s := range cf.Servers { - defS, found := s.FindMatch(defCf.Servers) - if !found { - continue NextVersion - } - if len(s.Plugins) != len(defS.Plugins) { - continue NextVersion - } - for _, p := range s.Plugins { - defP, found := p.FindMatch(defS.Plugins) - if !found { - continue NextVersion - } - if len(p.Options) != len(defP.Options) { - continue NextVersion - } - for _, o := range p.Options { - _, found := o.FindMatch(defP.Options) - if !found { - continue NextVersion - } - } - } - } - return true - } - return false -} - -// Released returns true if dockerImageSHA matches any released image of CoreDNS. -func Released(dockerImageSHA string) bool { - for _, v := range Versions { - if v.dockerImageSHA == dockerImageSHA { - return true - } - } - return false -} - -// ValidVersions returns a list of all versions defined -func ValidVersions() []string { - var vStrs []string - for vStr := range Versions { - vStrs = append(vStrs, vStr) - } - sort.Strings(vStrs) - return vStrs -} - -func validateVersion(fromCoreDNSVersion string) error { - if _, ok := Versions[fromCoreDNSVersion]; !ok { - return fmt.Errorf("start version '%v' not supported", fromCoreDNSVersion) - } - return nil -} - -func validUpMigration(fromCoreDNSVersion, toCoreDNSVersion string) error { - err := validateVersion(fromCoreDNSVersion) - if err != nil { - return err - } - for next := Versions[fromCoreDNSVersion].nextVersion; next != ""; next = Versions[next].nextVersion { - if next != toCoreDNSVersion { - continue - } - return nil - } - return fmt.Errorf("cannot migrate up to '%v' from '%v'", toCoreDNSVersion, fromCoreDNSVersion) -} - -func validDownMigration(fromCoreDNSVersion, toCoreDNSVersion string) error { - err := validateVersion(fromCoreDNSVersion) - if err != nil { - return err - } - for prior := Versions[fromCoreDNSVersion].priorVersion; prior != ""; prior = Versions[prior].priorVersion { - if prior != toCoreDNSVersion { - continue - } - return nil - } - return fmt.Errorf("cannot migrate down to '%v' from '%v'", toCoreDNSVersion, fromCoreDNSVersion) -} diff --git a/kubernetes/migration/migrate_test.go b/kubernetes/migration/migrate_test.go deleted file mode 100644 index 7cc78b6..0000000 --- a/kubernetes/migration/migrate_test.go +++ /dev/null @@ -1,572 +0,0 @@ -package migration - -import ( - "testing" -) - -func TestMigrate(t *testing.T) { - testCases := []struct { - name string - fromVersion string - toVersion string - deprecations bool - startCorefile string - expectedCorefile string - }{ - { - name: "Remove invalid proxy option", - fromVersion: "1.1.3", - toVersion: "1.2.6", - deprecations: true, - startCorefile: `.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - endpoint thing1 thing2 - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - proxy example.org 1.2.3.4:53 { - protocol https_google - } - cache 30 - loop - reload - loadbalance -} -`, - expectedCorefile: `.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - endpoint thing1 thing2 - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - proxy example.org 1.2.3.4:53 - cache 30 - loop - reload - loadbalance -} -`, - }, - { - name: "Migrate from proxy to forward and handle Kubernetes deprecations", - fromVersion: "1.3.1", - toVersion: "1.5.0", - deprecations: true, - startCorefile: `.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - endpoint thing1 thing2 - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - proxy . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -`, - expectedCorefile: `.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - endpoint thing1 - pods insecure - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - forward . /etc/resolv.conf - cache 30 - loop - reload - loadbalance - ready -} -`, - }, - { - name: "add missing loop and ready 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 . /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 -} -`, - }, - { - 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 -} -`, - }, - { - name: "no-op same version migration", - fromVersion: "1.3.1", - toVersion: "1.3.1", - 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 . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -`, - expectedCorefile: `.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - proxy . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -`, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - - result, err := Migrate(testCase.fromVersion, testCase.toVersion, testCase.startCorefile, testCase.deprecations) - - if err != nil { - t.Errorf("%v", err) - } - - if result != testCase.expectedCorefile { - t.Errorf("expected != result\n%v\n%v", testCase.expectedCorefile, result) - } - }) - } -} - -func TestMigrateDown(t *testing.T) { - testCases := []struct { - name string - fromVersion string - toVersion string - deprecations bool - startCorefile string - expectedCorefile string - }{ - { - name: "from 1.5.0 to 1.1.3", - fromVersion: "1.5.0", - toVersion: "1.1.3", - startCorefile: `.:53 { - errors - health - ready - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - forward . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -`, - expectedCorefile: `.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - forward . /etc/resolv.conf - cache 30 - reload - loadbalance -} -`, - }, - { - name: "no-op same version migration", - fromVersion: "1.3.1", - toVersion: "1.3.1", - 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 . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -`, - expectedCorefile: `.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - proxy . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -`, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - - result, err := MigrateDown(testCase.fromVersion, testCase.toVersion, testCase.startCorefile) - - if err != nil { - t.Errorf("%v", err) - } - - if result != testCase.expectedCorefile { - t.Errorf("expected != result:\n%v\n%v", testCase.expectedCorefile, result) - } - }) - } -} - -func TestDeprecated(t *testing.T) { - startCorefile := `.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - proxy . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -` - - expected := []Notice{ - {Plugin: "kubernetes", Option: "upstream", Severity: deprecated, Version: "1.4.0"}, - {Plugin: "proxy", Severity: deprecated, ReplacedBy: "forward", Version: "1.4.0"}, - {Option: "upstream", Plugin: "kubernetes", Severity: ignored, Version: "1.5.0"}, - {Plugin: "proxy", Severity: removed, ReplacedBy: "forward", Version: "1.5.0"}, - {Plugin: "ready", Severity: newdefault, Version: "1.5.0"}, - } - - result, err := Deprecated("1.2.0", "1.5.0", startCorefile) - - if err != nil { - t.Fatal(err) - } - - if len(result) != len(expected) { - t.Fatalf("expected to find %v notifications; got %v", len(expected), len(result)) - } - - for i, dep := range expected { - if result[i].ToString() != dep.ToString() { - t.Errorf("expected to get '%v'; got '%v'", dep.ToString(), result[i].ToString()) - } - } - - result, err = Deprecated("1.3.1", "1.3.1", startCorefile) - if err != nil { - t.Fatal(err) - } - expected = []Notice{} - if len(result) != len(expected) { - t.Fatalf("expected to find %v notifications in no-op upgrade; got %v", len(expected), len(result)) - } -} - -func TestUnsupported(t *testing.T) { - startCorefile := `.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - route53 example.org.:Z1Z2Z3Z4DZ5Z6Z7 - prometheus :9153 - proxy . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -` - - expected := []Notice{ - {Plugin: "route53", Severity: unsupported, Version: "1.4.0"}, - {Plugin: "route53", Severity: unsupported, Version: "1.5.0"}, - } - - result, err := Unsupported("1.3.1", "1.5.0", startCorefile) - - if err != nil { - t.Fatal(err) - } - - if len(result) != len(expected) { - t.Fatalf("expected to find %v deprecations; got %v", len(expected), len(result)) - } - - for i, dep := range expected { - if result[i].ToString() != dep.ToString() { - t.Errorf("expected to get '%v'; got '%v'", dep.ToString(), result[i].ToString()) - } - } -} - -func TestDefault(t *testing.T) { - defaultCorefiles := []string{`.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - forward . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -`, - `.:53 { - errors - health - kubernetes myzone.org in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - forward . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -`} - - nonDefaultCorefiles := []string{`.:53 { - errors - health - rewrite name suffix myzone.org cluster.local - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - forward . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -`, - `.:53 { - errors - health - kubernetes cluster.local in-addr.arpa ip6.arpa { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - forward . /etc/resolv.conf - cache 30 - loop - reload - loadbalance -} -stubzone.org:53 { - forward . 1.2.3.4 -} -`} - - for _, d := range defaultCorefiles { - if !Default("", d) { - t.Errorf("expected config to be identified as a default: %v", d) - } - } - for _, d := range nonDefaultCorefiles { - if Default("", d) { - t.Errorf("expected config to NOT be identified as a default: %v", d) - } - } -} - -func TestValidUpMigration(t *testing.T) { - testCases := []struct { - from string - to string - shouldErr bool - }{ - {"1.3.1", "1.3.1", true}, - {"1.3.1", "1.5.0", false}, - {"1.5.0", "1.3.1", true}, - {"banana", "1.5.0", true}, - {"1.3.1", "apple", true}, - {"banana", "apple", true}, - } - - for _, tc := range testCases { - err := validUpMigration(tc.from, tc.to) - - if !tc.shouldErr && err != nil { - t.Errorf("expected '%v' to '%v' to be valid versions.", tc.from, tc.to) - } - if tc.shouldErr && err == nil { - t.Errorf("expected '%v' to '%v' to be invalid versions.", tc.from, tc.to) - } - } -} - -func TestValidDownMigration(t *testing.T) { - testCases := []struct { - from string - to string - shouldErr bool - }{ - {"1.3.1", "1.3.1", true}, - {"1.3.1", "1.5.0", true}, - {"1.5.0", "1.3.1", false}, - {"banana", "1.5.0", true}, - {"1.3.1", "apple", true}, - {"banana", "apple", true}, - } - - for _, tc := range testCases { - err := validDownMigration(tc.from, tc.to) - - if !tc.shouldErr && err != nil { - t.Errorf("expected '%v' to '%v' to be valid versions.", tc.from, tc.to) - } - if tc.shouldErr && err == nil { - t.Errorf("expected '%v' to '%v' to be invalid versions.", tc.from, tc.to) - } - } -} diff --git a/kubernetes/migration/notice.go b/kubernetes/migration/notice.go deleted file mode 100644 index c5778d3..0000000 --- a/kubernetes/migration/notice.go +++ /dev/null @@ -1,48 +0,0 @@ -package migration - -import "fmt" - -// Notice is a migration warning -type Notice struct { - Plugin string - Option string - Severity string // 'deprecated', 'removed', or 'unsupported' - ReplacedBy string - Additional string - Version string -} - -func (n *Notice) ToString() string { - s := "" - if n.Option == "" { - s += fmt.Sprintf(`Plugin "%v" `, n.Plugin) - } else { - s += fmt.Sprintf(`Option "%v" in plugin "%v" `, n.Option, n.Plugin) - } - if n.Severity == unsupported { - s += "is unsupported by this migration tool in " + n.Version + "." - } else if n.Severity == newdefault { - s += "is added as a default in " + n.Version + "." - } else { - s += "is " + n.Severity + " in " + n.Version + "." - } - if n.ReplacedBy != "" { - s += fmt.Sprintf(` It is replaced by "%v".`, n.ReplacedBy) - } - if n.Additional != "" { - s += " " + n.Additional - } - return s -} - -const ( - // The following statuses are used to indicate the state of support/deprecation in a given release. - deprecated = "deprecated" // deprecated, but still completely functional - ignored = "ignored" // if included in the corefile, it will be ignored by CoreDNS - removed = "removed" // completely removed from CoreDNS, and would cause CoreDNS to exit if present in the Corefile - newdefault = "newdefault" // added to the default corefile. CoreDNS may not function properly if it is not present in the corefile. - unsupported = "unsupported" // the plugin/option is not supported by the migration tool - - // The following statuses are used for selecting/filtering notifications - all = "all" // show all statuses -) diff --git a/kubernetes/migration/versions.go b/kubernetes/migration/versions.go deleted file mode 100644 index 1da500c..0000000 --- a/kubernetes/migration/versions.go +++ /dev/null @@ -1,1126 +0,0 @@ -package migration - -import ( - "errors" - "github.com/coredns/deployment/kubernetes/migration/corefile" -) - -type plugin struct { - status string - replacedBy string - additional string - options map[string]option - action pluginActionFn // action affecting this plugin only - add serverActionFn // action to add a new plugin to the server block - downAction pluginActionFn // downgrade action affecting this plugin only -} - -type option struct { - status string - replacedBy string - additional string - action optionActionFn // action affecting this option only - add pluginActionFn // action to add the option to the plugin - downAction optionActionFn // downgrade action affecting this option only -} - -type release struct { - k8sReleases []string - nextVersion string - priorVersion string - dockerImageSHA string - plugins map[string]plugin // list of plugins with deprecation status and migration actions - - // 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 k8sReleases. - // Wildcards are used for fuzzy matching: - // "*" matches exactly one token - // "***" matches 0 all remaining tokens on the line - // Order of server blocks, plugins, and options does not matter. - // Order of arguments does matter. - defaultConf string -} - -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 optionActionFn func(*corefile.Option) (*corefile.Option, error) - -func removePlugin(*corefile.Plugin) (*corefile.Plugin, error) { return nil, nil } -func removeOption(*corefile.Option) (*corefile.Option, error) { return nil, nil } - -func renamePlugin(p *corefile.Plugin, to string) (*corefile.Plugin, error) { - p.Name = to - return p, nil -} - -func addToServerBlockWithPlugins(sb *corefile.Server, newPlugin *corefile.Plugin, with []string) (*corefile.Server, error) { - if len(with) == 0 { - // add to all blocks - sb.Plugins = append(sb.Plugins, newPlugin) - return sb, nil - } - for _, p := range sb.Plugins { - for _, w := range with { - if w == p.Name { - // add to this block - sb.Plugins = append(sb.Plugins, newPlugin) - return sb, nil - } - } - } - return sb, nil -} - -func addToKubernetesServerBlocks(sb *corefile.Server, newPlugin *corefile.Plugin) (*corefile.Server, error) { - return addToServerBlockWithPlugins(sb, newPlugin, []string{"kubernetes"}) -} - -func addToForwardingServerBlocks(sb *corefile.Server, newPlugin *corefile.Plugin) (*corefile.Server, error) { - return addToServerBlockWithPlugins(sb, newPlugin, []string{"forward", "proxy"}) -} - -func addToAllServerBlocks(sb *corefile.Server, newPlugin *corefile.Plugin) (*corefile.Server, error) { - return addToServerBlockWithPlugins(sb, newPlugin, []string{}) -} - -var Versions = map[string]release{ - "1.5.0": { - priorVersion: "1.4.0", - dockerImageSHA: "e83beb5e43f8513fa735e77ffc5859640baea30a882a11cc75c4c3244a737d3c", - plugins: map[string]plugin{ - "errors": { - options: map[string]option{ - "consolidate": {}, - }, - }, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "ready": { - status: newdefault, - add: func(c *corefile.Server) (*corefile.Server, error) { - return addToKubernetesServerBlocks(c, &corefile.Plugin{Name: "ready"}) - }, - downAction: removePlugin, - }, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": { - status: deprecated, - action: removeOption, - }, - "endpoint": { - status: ignored, - action: useFirstArgumentOnly, - }, - "tls": {}, - "kubeconfig": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": { - status: ignored, - action: removeOption, - }, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "k8s_external": { - options: map[string]option{ - "apex": {}, - "ttl": {}, - }, - }, - "prometheus": {}, - "proxy": { - status: removed, - replacedBy: "forward", - action: proxyToForwardPluginAction, - options: proxyToForwardOptionsMigrations, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "loop": {}, - "reload": {}, - "loadbalance": {}, - }, - postProcess: breakForwardStubDomainsIntoServerBlocks, - }, - "1.4.0": { - nextVersion: "1.5.0", - priorVersion: "1.3.1", - dockerImageSHA: "70a92e9f6fc604f9b629ca331b6135287244a86612f550941193ec7e12759417", - plugins: map[string]plugin{ - "errors": { - options: map[string]option{ - "consolidate": {}, - }, - }, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": { - status: ignored, - action: useFirstArgumentOnly, - }, - "tls": {}, - "kubeconfig": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": { - status: deprecated, - action: removeOption, - }, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "k8s_external": { - options: map[string]option{ - "apex": {}, - "ttl": {}, - }, - }, - "prometheus": {}, - "proxy": { - status: deprecated, - replacedBy: "forward", - action: proxyToForwardPluginAction, - options: proxyToForwardOptionsMigrations, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "loop": {}, - "reload": {}, - "loadbalance": {}, - }, - postProcess: breakForwardStubDomainsIntoServerBlocks, - }, - "1.3.1": { - nextVersion: "1.4.0", - priorVersion: "1.3.0", - k8sReleases: []string{"1.15", "1.14"}, - dockerImageSHA: "02382353821b12c21b062c59184e227e001079bb13ebd01f9d3270ba0fcbf1e4", - defaultConf: `.:53 { - errors - health - kubernetes * *** { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - forward . * - cache 30 - loop - reload - loadbalance -}`, - plugins: map[string]plugin{ - "errors": { - options: map[string]option{ - "consolidate": {}, - }, - }, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": { - status: deprecated, - action: useFirstArgumentOnly, - }, - "tls": {}, - "kubeconfig": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": {}, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "k8s_external": { - options: map[string]option{ - "apex": {}, - "ttl": {}, - }, - }, - "prometheus": {}, - "proxy": { - options: map[string]option{ - "policy": {}, - "fail_timeout": {}, - "max_fails": {}, - "health_check": {}, - "except": {}, - "spray": {}, - "protocol": {}, - }, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "loop": {}, - "reload": {}, - "loadbalance": {}, - }, - }, - "1.3.0": { - nextVersion: "1.3.1", - priorVersion: "1.2.6", - dockerImageSHA: "e030773c7fee285435ed7fc7623532ee54c4c1c4911fb24d95cd0170a8a768bc", - plugins: map[string]plugin{ - "errors": { - options: map[string]option{ - "consolidate": {}, - }, - }, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": {}, - "tls": {}, - "kubeconfig": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": {}, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "k8s_external": { - downAction: removePlugin, - options: map[string]option{ - "apex": {}, - "ttl": {}, - }, - }, - "prometheus": {}, - "proxy": { - options: map[string]option{ - "policy": {}, - "fail_timeout": {}, - "max_fails": {}, - "health_check": {}, - "except": {}, - "spray": {}, - "protocol": {}, - }, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "loop": {}, - "reload": {}, - "loadbalance": {}, - }, - }, - "1.2.6": { - nextVersion: "1.3.0", - priorVersion: "1.2.5", - k8sReleases: []string{"1.13"}, - dockerImageSHA: "81936728011c0df9404cb70b95c17bbc8af922ec9a70d0561a5d01fefa6ffa51", - defaultConf: `.:53 { - errors - health - kubernetes * *** { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - proxy . * - cache 30 - loop - reload - loadbalance -}`, - plugins: map[string]plugin{ - "errors": { - options: map[string]option{ - "consolidate": {}, - }, - }, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": {}, - "tls": {}, - "kubeconfig": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": {}, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "prometheus": {}, - "proxy": { - options: map[string]option{ - "policy": {}, - "fail_timeout": {}, - "max_fails": {}, - "health_check": {}, - "except": {}, - "spray": {}, - "protocol": {}, - }, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "loop": {}, - "reload": {}, - "loadbalance": {}, - }, - }, - "1.2.5": { - nextVersion: "1.2.6", - priorVersion: "1.2.4", - dockerImageSHA: "33c8da20b887ae12433ec5c40bfddefbbfa233d5ce11fb067122e68af30291d6", - plugins: map[string]plugin{ - "errors": {}, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": {}, - "tls": {}, - "kubeconfig": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": {}, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "prometheus": {}, - "proxy": { - options: map[string]option{ - "policy": {}, - "fail_timeout": {}, - "max_fails": {}, - "health_check": {}, - "except": {}, - "spray": {}, - "protocol": {}, - }, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "loop": {}, - "reload": {}, - "loadbalance": {}, - }, - }, - "1.2.4": { - nextVersion: "1.2.5", - priorVersion: "1.2.3", - dockerImageSHA: "a0d40ad961a714c699ee7b61b77441d165f6252f9fb84ac625d04a8d8554c0ec", - plugins: map[string]plugin{ - "errors": {}, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": {}, - "tls": {}, - "kubeconfig": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": {}, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "prometheus": {}, - "proxy": { - options: map[string]option{ - "policy": {}, - "fail_timeout": {}, - "max_fails": {}, - "health_check": {}, - "except": {}, - "spray": {}, - "protocol": {}, - }, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "loop": {}, - "reload": {}, - "loadbalance": {}, - }, - }, - "1.2.3": { - nextVersion: "1.2.4", - priorVersion: "1.2.2", - dockerImageSHA: "12f3cab301c826978fac736fd40aca21ac023102fd7f4aa6b4341ae9ba89e90e", - plugins: map[string]plugin{ - "errors": {}, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": {}, - "tls": {}, - "kubeconfig": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": {}, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "prometheus": {}, - "proxy": { - options: map[string]option{ - "policy": {}, - "fail_timeout": {}, - "max_fails": {}, - "health_check": {}, - "except": {}, - "spray": {}, - "protocol": {}, - }, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "loop": {}, - "reload": {}, - "loadbalance": {}, - }, - }, - "1.2.2": { - nextVersion: "1.2.3", - priorVersion: "1.2.1", - k8sReleases: []string{"1.12"}, - dockerImageSHA: "3e2be1cec87aca0b74b7668bbe8c02964a95a402e45ceb51b2252629d608d03a", - defaultConf: `.:53 { - errors - health - kubernetes * *** { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - proxy . * - cache 30 - loop - reload - loadbalance -}`, - plugins: map[string]plugin{ - "errors": {}, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": {}, - "tls": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": {}, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "prometheus": {}, - "proxy": { - options: map[string]option{ - "policy": {}, - "fail_timeout": {}, - "max_fails": {}, - "health_check": {}, - "except": {}, - "spray": {}, - "protocol": {}, - }, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "loop": {}, - "reload": {}, - "loadbalance": {}, - }, - }, - "1.2.1": { - nextVersion: "1.2.2", - priorVersion: "1.2.0", - dockerImageSHA: "fb129c6a7c8912bc6d9cc4505e1f9007c5565ceb1aa6369750e60cc79771a244", - plugins: map[string]plugin{ - "errors": {}, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": {}, - "tls": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": {}, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "prometheus": {}, - "proxy": { - options: map[string]option{ - "policy": {}, - "fail_timeout": {}, - "max_fails": {}, - "health_check": {}, - "except": {}, - "spray": {}, - "protocol": {}, - }, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "loop": { - status: newdefault, - add: func(s *corefile.Server) (*corefile.Server, error) { - return addToForwardingServerBlocks(s, &corefile.Plugin{Name: "loop"}) - }, - downAction: removePlugin, - }, - "reload": {}, - "loadbalance": {}, - }, - }, - "1.2.0": { - nextVersion: "1.2.1", - priorVersion: "1.1.4", - dockerImageSHA: "ae69a32f8cc29a3e2af9628b6473f24d3e977950a2cb62ce8911478a61215471", - plugins: map[string]plugin{ - "errors": {}, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": {}, - "tls": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": {}, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "prometheus": {}, - "proxy": { - options: map[string]option{ - "policy": {}, - "fail_timeout": {}, - "max_fails": {}, - "health_check": {}, - "except": {}, - "spray": {}, - "protocol": { - status: removed, - action: proxyRemoveHttpsGoogleProtocol, - }, - }, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "prefer_udp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "reload": {}, - "loadbalance": {}, - }, - }, - "1.1.4": { - nextVersion: "1.2.0", - priorVersion: "1.1.3", - dockerImageSHA: "463c7021141dd3bfd4a75812f4b735ef6aadc0253a128f15ffe16422abe56e50", - plugins: map[string]plugin{ - "errors": {}, - "log": { - options: map[string]option{ - "class": {}, - }, - }, - "health": {}, - "autopath": {}, - "kubernetes": { - options: map[string]option{ - "resyncperiod": {}, - "endpoint": {}, - "tls": {}, - "namespaces": {}, - "labels": {}, - "pods": {}, - "endpoint_pod_names": {}, - "upstream": {}, - "ttl": {}, - "noendpoints": {}, - "transfer": {}, - "fallthrough": {}, - "ignore": {}, - }, - }, - "prometheus": {}, - "proxy": { - options: map[string]option{ - "policy": {}, - "fail_timeout": {}, - "max_fails": {}, - "health_check": {}, - "except": {}, - "spray": {}, - "protocol": { - status: ignored, - action: proxyRemoveHttpsGoogleProtocol, - }, - }, - }, - "forward": { - options: map[string]option{ - "except": {}, - "force_tcp": {}, - "expire": {}, - "max_fails": {}, - "tls": {}, - "tls_servername": {}, - "policy": {}, - "health_check": {}, - }, - }, - "cache": { - options: map[string]option{ - "success": {}, - "denial": {}, - "prefetch": {}, - }, - }, - "reload": {}, - "loadbalance": {}, - }, - }, - "1.1.3": { - nextVersion: "1.1.4", - k8sReleases: []string{"1.11"}, - dockerImageSHA: "a5dd18e048983c7401e15648b55c3ef950601a86dd22370ef5dfc3e72a108aaa", - defaultConf: `.:53 { - errors - health - kubernetes * *** { - pods insecure - upstream - fallthrough in-addr.arpa ip6.arpa - } - prometheus :9153 - proxy . * - cache 30 - reload -}`}, -} - -var proxyToForwardOptionsMigrations = map[string]option{ - "policy": { - action: func(o *corefile.Option) (*corefile.Option, error) { - if len(o.Args) == 2 && o.Args[1] == "least_conn" { - o.Name = "force_tcp" - o.Args = nil - } - return o, nil - }, - }, - "except": {}, - "fail_timeout": {action: removeOption}, - "max_fails": {action: removeOption}, - "health_check": {action: removeOption}, - "spray": {action: removeOption}, - "protocol": { - action: func(o *corefile.Option) (*corefile.Option, error) { - if len(o.Args) >= 2 && o.Args[1] == "force_tcp" { - o.Name = "force_tcp" - o.Args = nil - return o, nil - } - return nil, nil - }, - }, -} - -var proxyToForwardPluginAction = func(p *corefile.Plugin) (*corefile.Plugin, error) { - return renamePlugin(p, "forward") -} - -var useFirstArgumentOnly = func(o *corefile.Option) (*corefile.Option, error) { - if len(o.Args) < 1 { - return o, nil - } - o.Args = o.Args[:1] - return o, nil -} - -var proxyRemoveHttpsGoogleProtocol = func(o *corefile.Option) (*corefile.Option, error) { - if len(o.Args) > 0 && o.Args[0] == "https_google" { - return nil, 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 -}