Adding CLI for the migration tool (#154)

* Initial commit for the corefile-tool cli for the migration tool

* cleanup implementation

* nit

* add fn to get corefile path

* add released command and improve readme
This commit is contained in:
Sandeep Rajan 2019-04-24 11:22:13 -04:00 committed by Chris O'Haver
parent 631694b4e3
commit 37f5d0dad4
12 changed files with 495 additions and 3 deletions

3
kubernetes/corefile-tool/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
Corefile
corefile-tool
*.yaml

View file

@ -0,0 +1,107 @@
## Corefile-tool
Corefile-tool is a simple command line tool which helps you to evaluate and migrate your CoreDNS Corefile Configuration.
It is based on 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:
`corefile-tool [command] [flags]`
where `command`, `flags` are:
- `command`: The operation you want to perform.
- `flags` : Specifies flags required to carry out the operations.
### Operations
The following commands are supported:
- `default`: 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.
The following flags are accepted by the `default` command:
- `k8sversion`: The Kubernetes version for which you are checking the default.
If the Kubernetes version is omitted, returns true if the Corefile is the default for any version.
- `corefile` : The path where your Corefile is located. This flag is mandatory.
- `deprecated` : Deprecated returns a list of deprecated plugins or directives present in the Corefile.
The following flags are accepted and mandatory for the `deprecated` command:
- `from`: The CoreDNS version you are migrating from.
- `to` : The CoreDNS version you are migrating to.
- `corefile` : The path where your Corefile is located.
- `migrate` : Migrate your CoreDNS corefile.
The following flags are accepted and mandatory for the `migrate` command:
- `from` : The CoreDNS version you are migrating from.
- `to` : The CoreDNS version you are migrating to. This flag is mandatory.
- `corefile` : The path where your Corefile is located. This flag is mandatory.
- `deprecations`: Specify whether you want to migrate all the deprecations that are present in the current Corefile.
Specifying `false` will result in the `migrate` command not migrating the deprecated plugins present in the Corefile.
- `released` : Released determines whether your Docker Image ID of a CoreDNS release is valid or not.
The following flags are accepted and mandatory for the `released` command:
- `dockerImageID` : The docker image ID you want to check.
- `removed` : Removed returns a list of removed plugins or directives present in the Corefile.
The following flags are accepted and mandatory for the `removed` command:
- `from` : The CoreDNS version you are migrating from.
- `to` : The CoreDNS version you are migrating to. This flag is mandatory.
- `corefile` : The path where your Corefile is located. This flag is mandatory.
- `unsupported` : Unsupported returns a list of plugins that are not recognized/supported by the migration tool (but may still be valid in CoreDNS).
The following flags are accepted and mandatory for the `unsupported` command:
- `from` : The CoreDNS version you are migrating from.
- `to` : The CoreDNS version you are migrating to. This flag is mandatory.
- `corefile` : The path where your Corefile is located. This flag is mandatory.
- `validversions` : Shows valid versions of CoreDNS.
### 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
# See removed plugins CoreDNS from v1.4.0 to v1.5.0.
corefile-tool removed --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
```

View file

@ -0,0 +1,47 @@
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
}

View file

@ -0,0 +1,51 @@
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 plugins or directives present in the Corefile.",
Example: `# 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`,
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)
}

View file

@ -0,0 +1,56 @@
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, "Required: Specify whether you want to handle plugin deprecations. [True | False] ")
migrateCmd.MarkFlagRequired("deprecations")
return migrateCmd
}
// migrateCorefileFromPath takes the path where the Corefile is located and returns the deprecated plugins or directives
// present in the Corefile.
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)
}

View file

@ -0,0 +1,32 @@
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 ID of a CoreDNS release is valid or not",
Run: func(cmd *cobra.Command, args []string) {
image, _ := cmd.Flags().GetString("dockerImageID")
result := migration.Released(image)
if result {
fmt.Println("The docker image ID is valid")
} else {
fmt.Println("The docker image ID is invalid")
}
},
}
releasedCmd.Flags().String("dockerImageID", "", "Required: The docker image ID you want to check. ")
releasedCmd.MarkFlagRequired("dockerImageID")
return releasedCmd
}

View file

@ -0,0 +1,52 @@
package cmd
import (
"fmt"
"github.com/coredns/deployment/kubernetes/migration"
"github.com/spf13/cobra"
)
// NewRemovedCmd represents the removed command
func NewRemovedCmd() *cobra.Command {
removedCmd := &cobra.Command{
Use: "removed",
Short: "Removed returns a list of removed plugins or directives present in the Corefile.",
Example: `# See removed plugins CoreDNS from v1.4.0 to v1.5.0.
corefile-tool removed --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")
removed, err := removedCorefileFromPath(from, to, corefile)
if err != nil {
return fmt.Errorf("error while listing deprecated plugins: %v \n", err)
}
for _, rem := range removed {
fmt.Println(rem.ToString())
}
return nil
},
}
removedCmd.Flags().String("from", "", "Required: The version you are migrating from. ")
removedCmd.MarkFlagRequired("from")
removedCmd.Flags().String("to", "", "Required: The version you are migrating to.")
removedCmd.MarkFlagRequired("to")
removedCmd.Flags().String("corefile", "", "Required: The path where your Corefile is located.")
removedCmd.MarkFlagRequired("corefile")
return removedCmd
}
// removedCorefileFromPath takes the path where the Corefile is located and returns the plugins or directives
// that have been removed.
func removedCorefileFromPath(fromCoreDNSVersion, toCoreDNSVersion, corefilePath string) ([]migration.Notice, error) {
fileBytes, err := getCorefileFromPath(corefilePath)
if err != nil {
return nil, err
}
corefileStr := string(fileBytes)
return migration.Removed(fromCoreDNSVersion, toCoreDNSVersion, corefileStr)
}

View file

@ -0,0 +1,59 @@
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(NewRemovedCmd())
rootCmd.AddCommand(NewMigrateCmd())
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
}

View file

@ -0,0 +1,52 @@
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)
}

View file

@ -0,0 +1,23 @@
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
}

View file

@ -0,0 +1,7 @@
package main
import "github.com/coredns/deployment/kubernetes/corefile-tool/cmd"
func main() {
cmd.Execute()
}

View file

@ -7,6 +7,8 @@ package migration
import (
"fmt"
"sort"
"github.com/coredns/deployment/kubernetes/migration/corefile"
)
@ -243,9 +245,10 @@ func Released(dockerImageID string) bool {
// ValidVersions returns a list of all versions defined
func ValidVersions() []string {
var vStrs []string
for vStr, _ := range Versions {
for vStr := range Versions {
vStrs = append(vStrs, vStr)
}
sort.Strings(vStrs)
return vStrs
}
@ -261,11 +264,11 @@ func validateVersions(fromCoreDNSVersion, toCoreDNSVersion string) error {
if err != nil {
return err
}
for next := Versions[fromCoreDNSVersion].nextVersion; next != ""; next = Versions[next].nextVersion {
for next := Versions[fromCoreDNSVersion].nextVersion; next != ""; next = Versions[next].nextVersion {
if next != toCoreDNSVersion {
continue
}
return nil
}
return fmt.Errorf("cannot migrate to '%v' from '%v'", toCoreDNSVersion, fromCoreDNSVersion)
}
}