feat main: Add proper CLI support
Adds a basic CLI structure with a single "run" command that takes a --file (-f) and --limit (-l) flag. --limit can be used to only output certain resource sets. Closes #4
This commit is contained in:
		
							parent
							
								
									8fac7c1a41
								
							
						
					
					
						commit
						7ac63613fb
					
				
					 3 changed files with 110 additions and 45 deletions
				
			
		|  | @ -2,9 +2,10 @@ package context | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"github.com/polydawn/meep" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"path" | 	"path" | ||||||
|  | 
 | ||||||
|  | 	"github.com/polydawn/meep" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ResourceSet struct { | type ResourceSet struct { | ||||||
|  |  | ||||||
							
								
								
									
										64
									
								
								main.go
									
										
									
									
									
								
							
							
						
						
									
										64
									
								
								main.go
									
										
									
									
									
								
							|  | @ -4,36 +4,70 @@ import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"os" | 	"os" | ||||||
| 
 | 
 | ||||||
|  | 	"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" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
| 	args := os.Args[1:] | 	app := cli.NewApp() | ||||||
| 	if len(args) == 0 { | 
 | ||||||
| 		fmt.Fprintln(os.Stderr, "Usage: kontemplate <cluster-config>") | 	app.Name = "kontemplate" | ||||||
| 		os.Exit(1) | 	app.Usage = "simple Kubernetes resource templating" | ||||||
|  | 	app.Version = "0.0.1" | ||||||
|  | 
 | ||||||
|  | 	app.Commands = []cli.Command{ | ||||||
|  | 		ApplyCommand(), | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	c, err := context.LoadContextFromFile(os.Args[1]) | 	app.Run(os.Args) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	if err != nil { | func ApplyCommand() cli.Command { | ||||||
| 		fmt.Fprintf(os.Stderr, "%v\n", err) | 	return cli.Command{ | ||||||
| 		os.Exit(1) | 		Name:  "run", | ||||||
|  | 		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", | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		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", | ||||||
|  | 					}, | ||||||
|  | 				) | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 	fmt.Fprintf(os.Stderr, "Applying cluster %s\n", c.Name) | 			ctx, err := context.LoadContextFromFile(f) | ||||||
| 
 |  | ||||||
| 	for _, rs := range c.ResourceSets { |  | ||||||
| 		fmt.Fprintf(os.Stderr, "Applying resource %s with values %v\n", rs.Name, rs.Values) |  | ||||||
| 		resources, err := templater.LoadAndPrepareTemplates(c) |  | ||||||
| 
 | 
 | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 			fmt.Println(err) | 				return err | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			resources, err := templater.LoadAndPrepareTemplates(&limit, ctx) | ||||||
|  | 
 | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			for _, r := range resources { | 			for _, r := range resources { | ||||||
| 			fmt.Print(r) | 				fmt.Println(r) | ||||||
| 			} | 			} | ||||||
|  | 
 | ||||||
|  | 			return nil | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,37 +24,67 @@ type TemplatingError struct { | ||||||
| 	meep.AllTraits | 	meep.AllTraits | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func LoadAndPrepareTemplates(c *context.Context) ([]string, error) { | func LoadAndPrepareTemplates(limit *[]string, c *context.Context) (output []string, err error) { | ||||||
| 	output := make([]string, 0) |  | ||||||
| 
 |  | ||||||
| 	for _, rs := range c.ResourceSets { | 	for _, rs := range c.ResourceSets { | ||||||
|  | 		if resourceSetIncluded(limit, &rs.Name) { | ||||||
|  | 			err = processResourceSet(c, &rs, &output) | ||||||
|  | 
 | ||||||
|  | 			if err != nil { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func resourceSetIncluded(limit *[]string, resourceSetName *string) bool { | ||||||
|  | 	if len(*limit) == 0 { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, name := range *limit { | ||||||
|  | 		if name == *resourceSetName { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func processResourceSet(c *context.Context, rs *context.ResourceSet, output *[]string) error { | ||||||
| 	fmt.Fprintf(os.Stderr, "Loading resources for %s\n", rs.Name) | 	fmt.Fprintf(os.Stderr, "Loading resources for %s\n", rs.Name) | ||||||
| 
 | 
 | ||||||
| 	rp := path.Join(c.BaseDir, rs.Name) | 	rp := path.Join(c.BaseDir, rs.Name) | ||||||
| 	files, err := ioutil.ReadDir(rp) | 	files, err := ioutil.ReadDir(rp) | ||||||
| 
 | 
 | ||||||
|  | 	err = processFiles(c, rs, rp, files, output) | ||||||
|  | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 			return nil, meep.New( | 		return meep.New( | ||||||
| 			&TemplateNotFoundError{Name: rs.Name}, | 			&TemplateNotFoundError{Name: rs.Name}, | ||||||
| 			meep.Cause(err), | 			meep.Cause(err), | ||||||
| 		) | 		) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func processFiles(c *context.Context, rs *context.ResourceSet, rp string, files []os.FileInfo, output *[]string) error { | ||||||
| 	for _, file := range files { | 	for _, file := range files { | ||||||
| 		if !file.IsDir() && isResourceFile(file) { | 		if !file.IsDir() && isResourceFile(file) { | ||||||
| 			p := path.Join(rp, file.Name()) | 			p := path.Join(rp, file.Name()) | ||||||
| 				o, err := templateFile(c, &rs, p) | 			o, err := templateFile(c, rs, p) | ||||||
| 
 | 
 | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 					return nil, err | 				return err | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 				output = append(output, o) | 			*output = append(*output, o) | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return output, nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func templateFile(c *context.Context, rs *context.ResourceSet, filename string) (string, error) { | func templateFile(c *context.Context, rs *context.ResourceSet, filename string) (string, error) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue