refactor main: Move to Kingpin CLI library
Replace urfave/cli with the kingpin[1] library. It has slightly more sensible argument validation than the other Go libraries. Additionally I've opted for removing the '-f / --file' flag in favour of positional arguments to commands. A previous command like `kontemplate template -f somefile.yml` is now just `kontemplate template somefile.yml`. All other arguments remain the same. [1]: https://github.com/alecthomas/kingpin
This commit is contained in:
parent
32ca64c50a
commit
c8a63861ae
1 changed files with 77 additions and 145 deletions
222
main.go
222
main.go
|
@ -8,141 +8,111 @@ import (
|
||||||
"github.com/polydawn/meep"
|
"github.com/polydawn/meep"
|
||||||
"github.com/tazjin/kontemplate/context"
|
"github.com/tazjin/kontemplate/context"
|
||||||
"github.com/tazjin/kontemplate/templater"
|
"github.com/tazjin/kontemplate/templater"
|
||||||
"github.com/urfave/cli"
|
"gopkg.in/alecthomas/kingpin.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type KubeCtlError struct {
|
type KubeCtlError struct {
|
||||||
meep.AllTraits
|
meep.AllTraits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
app = kingpin.New("kontemplate", "simple Kubernetes resource templating")
|
||||||
|
|
||||||
|
// Global flags
|
||||||
|
includes = app.Flag("include", "Resource sets to include explicitly").Short('i').Strings()
|
||||||
|
excludes = app.Flag("exclude", "Resource sets to exclude explicitly").Short('e').Strings()
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
template = app.Command("template", "Template resource sets and print them")
|
||||||
|
templateFile = template.Arg("file", "Cluster configuration file to use").Required().String()
|
||||||
|
|
||||||
|
apply = app.Command("apply", "Template resources and pass to 'kubectl apply'")
|
||||||
|
applyFile = apply.Arg("file", "Cluster configuration file to use").Required().String()
|
||||||
|
applyDryRun = apply.Flag("dry-run", "Print remote operations without executing them").Default("false").Bool()
|
||||||
|
|
||||||
|
replace = app.Command("replace", "Template resources and pass to 'kubectl replace'")
|
||||||
|
replaceFile = replace.Arg("file", "Cluster configuration file to use").Required().String()
|
||||||
|
|
||||||
|
delete = app.Command("delete", "Template resources and pass to 'kubectl delete'")
|
||||||
|
deleteFile = delete.Arg("file", "Cluster configuration file to use").Required().String()
|
||||||
|
|
||||||
|
create = app.Command("create", "Template resources and pass to 'kubectl create'")
|
||||||
|
createFile = create.Arg("file", "Cluster configuration file to use").Required().String()
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := cli.NewApp()
|
app.HelpFlag.Short('h')
|
||||||
|
|
||||||
app.Name = "kontemplate"
|
switch kingpin.MustParse(app.Parse(os.Args[1:])) {
|
||||||
app.Usage = "simple Kubernetes resource templating"
|
case template.FullCommand():
|
||||||
app.Version = "v1.0.0-beta1"
|
templateCommand()
|
||||||
|
|
||||||
app.Commands = []cli.Command{
|
case apply.FullCommand():
|
||||||
templateCommand(),
|
applyCommand()
|
||||||
applyCommand(),
|
|
||||||
replaceCommand(),
|
|
||||||
deleteCommand(),
|
|
||||||
}
|
|
||||||
|
|
||||||
app.Run(os.Args)
|
case replace.FullCommand():
|
||||||
}
|
replaceCommand()
|
||||||
|
|
||||||
func templateCommand() cli.Command {
|
case delete.FullCommand():
|
||||||
return cli.Command{
|
deleteCommand()
|
||||||
Name: "template",
|
|
||||||
Usage: "Interpolate and print templates",
|
|
||||||
Flags: commonFlags(),
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
include := c.StringSlice("include")
|
|
||||||
exclude := c.StringSlice("exclude")
|
|
||||||
|
|
||||||
ctx, err := loadContext(c)
|
case create.FullCommand():
|
||||||
if err != nil {
|
createCommand()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
resources, err := templater.LoadAndPrepareTemplates(&include, &exclude, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range resources {
|
|
||||||
fmt.Println(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyCommand() cli.Command {
|
func templateCommand() {
|
||||||
dryRun := false
|
_, resources := loadContextAndResources(templateFile)
|
||||||
|
|
||||||
return cli.Command{
|
for _, r := range *resources {
|
||||||
Name: "apply",
|
fmt.Println(r)
|
||||||
Usage: "Interpolate templates and run 'kubectl apply'",
|
|
||||||
Flags: append(commonFlags(), cli.BoolFlag{
|
|
||||||
Name: "dry-run",
|
|
||||||
Usage: "Only print objects that would be sent, without sending them",
|
|
||||||
Destination: &dryRun,
|
|
||||||
}),
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
include := c.StringSlice("include")
|
|
||||||
exclude := c.StringSlice("exclude")
|
|
||||||
ctx, err := loadContext(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
resources, err := templater.LoadAndPrepareTemplates(&include, &exclude, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var args []string
|
|
||||||
if dryRun {
|
|
||||||
args = []string{"apply", "-f", "-", "--dry-run"}
|
|
||||||
} else {
|
|
||||||
args = []string{"apply", "-f", "-"}
|
|
||||||
}
|
|
||||||
|
|
||||||
return runKubectlWithResources(ctx, &args, &resources)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func replaceCommand() cli.Command {
|
func applyCommand() {
|
||||||
return cli.Command{
|
ctx, resources := loadContextAndResources(applyFile)
|
||||||
Name: "replace",
|
|
||||||
Usage: "Interpolate templates and run 'kubectl replace'",
|
|
||||||
Flags: commonFlags(),
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
include := c.StringSlice("include")
|
|
||||||
exclude := c.StringSlice("exclude")
|
|
||||||
ctx, err := loadContext(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
resources, err := templater.LoadAndPrepareTemplates(&include, &exclude, ctx)
|
var kubectlArgs []string
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{"replace", "--save-config=true", "-f", "-"}
|
if *applyDryRun {
|
||||||
return runKubectlWithResources(ctx, &args, &resources)
|
kubectlArgs = []string{"apply", "-f", "-", "--dry-run"}
|
||||||
},
|
} else {
|
||||||
|
kubectlArgs = []string{"apply", "-f", "-"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runKubectlWithResources(ctx, &kubectlArgs, resources)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteCommand() cli.Command {
|
func replaceCommand() {
|
||||||
return cli.Command{
|
ctx, resources := loadContextAndResources(replaceFile)
|
||||||
Name: "delete",
|
args := []string{"replace", "--save-config=true", "-f", "-"}
|
||||||
Usage: "Interpolate templates and run 'kubectl delete'",
|
runKubectlWithResources(ctx, &args, resources)
|
||||||
Flags: commonFlags(),
|
}
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
include := c.StringSlice("include")
|
|
||||||
exclude := c.StringSlice("exclude")
|
|
||||||
|
|
||||||
ctx, err := loadContext(c)
|
func deleteCommand() {
|
||||||
if err != nil {
|
ctx, resources := loadContextAndResources(deleteFile)
|
||||||
return err
|
args := []string{"delete", "-f", "-"}
|
||||||
}
|
runKubectlWithResources(ctx, &args, resources)
|
||||||
|
}
|
||||||
|
|
||||||
resources, err := templater.LoadAndPrepareTemplates(&include, &exclude, ctx)
|
func createCommand() {
|
||||||
if err != nil {
|
ctx, resources := loadContextAndResources(createFile)
|
||||||
return err
|
args := []string{"create", "--save-config=true", "-f", "-"}
|
||||||
}
|
runKubectlWithResources(ctx, &args, resources)
|
||||||
|
}
|
||||||
|
|
||||||
args := []string{"delete", "-f", "-"}
|
func loadContextAndResources(file *string) (*context.Context, *[]string) {
|
||||||
return runKubectlWithResources(ctx, &args, &resources)
|
ctx, err := context.LoadContextFromFile(*file)
|
||||||
},
|
if err != nil {
|
||||||
|
app.Fatalf("Error loading context: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resources, err := templater.LoadAndPrepareTemplates(includes, excludes, ctx)
|
||||||
|
if err != nil {
|
||||||
|
app.Fatalf("Error templating resource sets: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx, &resources
|
||||||
}
|
}
|
||||||
|
|
||||||
func runKubectlWithResources(c *context.Context, kubectlArgs *[]string, resources *[]string) error {
|
func runKubectlWithResources(c *context.Context, kubectlArgs *[]string, resources *[]string) error {
|
||||||
|
@ -171,41 +141,3 @@ func runKubectlWithResources(c *context.Context, kubectlArgs *[]string, resource
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func commonFlags() []cli.Flag {
|
|
||||||
return []cli.Flag{
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "file, f",
|
|
||||||
Usage: "Cluster configuration file to use",
|
|
||||||
},
|
|
||||||
cli.StringSliceFlag{
|
|
||||||
Name: "include, i",
|
|
||||||
Usage: "Limit templating to explicitly included resource sets",
|
|
||||||
},
|
|
||||||
cli.StringSliceFlag{
|
|
||||||
Name: "exclude, e",
|
|
||||||
Usage: "Exclude certain resource sets from templating",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadContext(c *cli.Context) (*context.Context, error) {
|
|
||||||
f := c.String("file")
|
|
||||||
|
|
||||||
if f == "" {
|
|
||||||
return nil, meep.New(
|
|
||||||
&meep.ErrInvalidParam{
|
|
||||||
Param: "file",
|
|
||||||
Reason: "Cluster config file must be specified (-f)",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, err := context.LoadContextFromFile(f)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx, nil
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue