about summary refs log tree commit diff
path: root/main.go
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@gmail.com>2017-02-08T14·32+0100
committerVincent Ambo <tazjin@gmail.com>2017-02-08T14·42+0100
commitbc9fc9730dd30e2d302ce5f88cd93da9604eb6f0 (patch)
treee93d157b82e7b64833c302fe8fdbbaef1c04d091 /main.go
parent25f2a1616caf2a05199370998223f4a64bb55f81 (diff)
feat main: Add apply command
This integrates support for actually calling out to `kubectl apply`.

A dry-run flag is implemented, too.

The `run` command has been renamed to `template`.
Diffstat (limited to 'main.go')
-rw-r--r--main.go118
1 files changed, 91 insertions, 27 deletions
diff --git a/main.go b/main.go
index de734e8ac37d..c39972ff6010 100644
--- a/main.go
+++ b/main.go
@@ -3,6 +3,7 @@ package main
 import (
 	"fmt"
 	"os"
+	"os/exec"
 
 	"github.com/polydawn/meep"
 	"github.com/tazjin/kontemplate/context"
@@ -10,6 +11,10 @@ import (
 	"github.com/urfave/cli"
 )
 
+type KubeCtlError struct {
+	meep.AllTraits
+}
+
 func main() {
 	app := cli.NewApp()
 
@@ -18,56 +23,115 @@ func main() {
 	app.Version = "0.0.1"
 
 	app.Commands = []cli.Command{
-		ApplyCommand(),
+		templateCommand(),
+		applyCommand(),
 	}
 
 	app.Run(os.Args)
 }
 
-func ApplyCommand() cli.Command {
+func templateCommand() cli.Command {
 	return cli.Command{
-		Name:  "run",
+		Name:  "template",
 		Usage: "Interpolate and print templates",
-		Flags: []cli.Flag{
-			cli.StringFlag{
-				Name:  "file, f",
-				Usage: "Cluster configuration file to use",
-			},
-			cli.StringSliceFlag{
-				Name:  "limit, l",
-				Usage: "Limit templating to certain resource sets",
-			},
-		},
+		Flags: commonFlags(),
 		Action: func(c *cli.Context) error {
-			limit := c.StringSlice("limit")
-			f := c.String("file")
-
-			if f == "" {
-				return meep.New(
-					&meep.ErrInvalidParam{
-						Param:  "file",
-						Reason: "Cluster config file must be specified",
-					},
-				)
+			resources, err := templateResources(c)
+
+			if err != nil {
+				return err
 			}
 
-			ctx, err := context.LoadContextFromFile(f)
+			for _, r := range resources {
+				fmt.Println(r)
+			}
+
+			return nil
+		},
+	}
+}
+
+func applyCommand() cli.Command {
+	dryRun := false
+
+	return cli.Command{
+		Name:  "apply",
+		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 {
+			resources, err := templateResources(c)
 
 			if err != nil {
 				return err
 			}
 
-			resources, err := templater.LoadAndPrepareTemplates(&limit, ctx)
+			var kubectl *exec.Cmd
+			if dryRun {
+				kubectl = exec.Command("kubectl", "apply", "-f", "-", "--dry-run")
+			} else {
+				kubectl = exec.Command("kubectl", "apply", "-f", "-")
+			}
 
+			stdin, err := kubectl.StdinPipe()
 			if err != nil {
-				return err
+				return meep.New(&KubeCtlError{}, meep.Cause(err))
+			}
+
+			kubectl.Stdout = os.Stdout
+			kubectl.Stderr = os.Stderr
+
+			if err = kubectl.Start(); err != nil {
+				return meep.New(&KubeCtlError{}, meep.Cause(err))
 			}
 
 			for _, r := range resources {
-				fmt.Println(r)
+				fmt.Fprintln(stdin, r)
 			}
 
+			stdin.Close()
+
+			kubectl.Wait()
+
 			return nil
 		},
 	}
 }
+
+func commonFlags() []cli.Flag {
+	return []cli.Flag{
+		cli.StringFlag{
+			Name:  "file, f",
+			Usage: "Cluster configuration file to use",
+		},
+		cli.StringSliceFlag{
+			Name:  "limit, l",
+			Usage: "Limit templating to certain resource sets",
+		},
+	}
+}
+
+func templateResources(c *cli.Context) ([]string, error) {
+	limit := c.StringSlice("limit")
+	f := c.String("file")
+
+	if f == "" {
+		return nil, meep.New(
+			&meep.ErrInvalidParam{
+				Param:  "file",
+				Reason: "Cluster config file must be specified",
+			},
+		)
+	}
+
+	ctx, err := context.LoadContextFromFile(f)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return templater.LoadAndPrepareTemplates(&limit, ctx)
+}