From 5e650544fc61ab8c0ab4b5bc92cfeec7762ee72c Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 11 Apr 2024 12:42:53 -0600 Subject: [PATCH 1/5] Added output argument, argument checks, and target paths --- cmd/generate.go | 69 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/cmd/generate.go b/cmd/generate.go index 10dc3f4..b109814 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -6,6 +6,7 @@ package cmd import ( "fmt" "os" + "path/filepath" "strings" configurator "github.com/OpenCHAMI/configurator/internal" @@ -15,12 +16,12 @@ import ( ) var ( - targets []string tokenFetchRetries int ) + var generateCmd = &cobra.Command{ Use: "generate", - Short: "Create a config file from current system state", + Short: "Generate a config file from system state", Run: func(cmd *cobra.Command, args []string) { client := configurator.SmdClient{ Host: config.SmdHost, @@ -43,27 +44,60 @@ var generateCmd = &cobra.Command{ if targets == nil { logrus.Errorf("no target supplied (--target type:template)") } else { + // if we have more than one target and output is set, create configs in directory + targetCount := len(targets) + if outputPath != "" && targetCount > 1 { + err := os.MkdirAll(outputPath, 0o755) + if err != nil { + logrus.Errorf("failed to make output directory: %v", err) + return + } + } + for _, target := range targets { // split the target and type tmp := strings.Split(target, ":") + + // make sure each target has at least two args + if len(tmp) < 2 { + message := "target" + if len(tmp) == 1 { + message += fmt.Sprintf(" '%s'", tmp[1]) + } + message += " does not provide enough arguments (args: \"type:template\")" + logrus.Errorf(message) + continue + } g := generator.Generator{ Type: tmp[0], Template: tmp[1], } + // check if another param is specified + targetPath := "" + if len(tmp) > 2 { + targetPath = tmp[2] + } + // NOTE: we probably don't want to hardcode the types, but should do for now + ext := "" if g.Type == "dhcp" { // fetch eths from SMD eths, err := client.FetchEthernetInterfaces() if err != nil { logrus.Errorf("failed to fetch DHCP metadata: %v\n", err) + continue } if len(eths) <= 0 { - break + continue } // generate a new config from that data - - g.GenerateDHCP(&config, eths) + b, err := g.GenerateDHCP(&config, eths) + if err != nil { + logrus.Errorf("failed to generate DHCP config file: %v\n", err) + continue + } + ext = "conf" } else if g.Type == "dns" { // TODO: fetch from SMD // TODO: generate config from pulled info @@ -76,14 +110,35 @@ var generateCmd = &cobra.Command{ } - } + // write config output if no specific targetPath is set + if targetPath == "" { + if outputPath == "" { + // write only to stdout + fmt.Printf("%s\n", "") + } else if outputPath != "" && targetCount == 1 { + // write just a single file using template name + err := os.WriteFile(outputPath) + if err != nil { + logrus.Errorf("failed to write config to file: %v", err) + continue + } + } else if outputPath != "" && targetCount > 1 { + // write multiple files in directory using template name + err := os.WriteFile(fmt.Sprintf("%s/%s.%s", filepath.Clean(outputPath), g.Template, ext)) + if err != nil { + logrus.Errorf("failed to write config to file: %v", err) + continue + } + } + } + } // for targets } - }, } func init() { generateCmd.Flags().StringSliceVar(&targets, "target", nil, "set the target configs to make") + generateCmd.Flags().StringVarP(&outputPath, "output", "o", "", "set the output path for config targets") generateCmd.Flags().IntVar(&tokenFetchRetries, "fetch-retries", 5, "set the number of retries to fetch an access token") rootCmd.AddCommand(generateCmd) From 977ddf8a79c4eb19bcbb4f807f08607189366012 Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 11 Apr 2024 12:43:31 -0600 Subject: [PATCH 2/5] Moved common vars to cmd/root.go --- cmd/root.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/root.go b/cmd/root.go index be4697d..b36bfd2 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -12,6 +12,8 @@ import ( var ( configPath string config configurator.Config + targets []string + output string ) var rootCmd = &cobra.Command{ From 80c9eb29a6880c543931baec7d62b2cf900b1e8e Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 11 Apr 2024 12:44:32 -0600 Subject: [PATCH 3/5] Changed generate functions to return config as bytes --- internal/generator/generator.go | 13 +++++++------ internal/server/server.go | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 589adb6..3d67e26 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -1,7 +1,7 @@ package generator import ( - "os" + "bytes" "fmt" @@ -26,13 +26,13 @@ func (g *Generator) GenerateDNS(config *configurator.Config) { // TODO: print generated config file to STDOUT } -func (g *Generator) GenerateDHCP(config *configurator.Config, eths []configurator.EthernetInterface) error { +func (g *Generator) GenerateDHCP(config *configurator.Config, eths []configurator.EthernetInterface) ([]byte, error) { // generate file using gonja template path := config.TemplatePaths[g.Template] fmt.Printf("path: %s\neth count: %v\n", path, len(eths)) t, err := gonja.FromFile(path) if err != nil { - return fmt.Errorf("failed to read template from file: %v", err) + return nil, fmt.Errorf("failed to read template from file: %v", err) } template := "# ========== GENERATED BY OCHAMI CONFIGURATOR ==========\n" for _, eth := range eths { @@ -46,9 +46,10 @@ func (g *Generator) GenerateDHCP(config *configurator.Config, eths []configurato data := exec.NewContext(map[string]any{ "hosts": template, }) - if err = t.Execute(os.Stdout, data); err != nil { - return fmt.Errorf("failed to execute: %v", err) + b := bytes.Buffer{} + if err = t.Execute(&b, data); err != nil { + return nil, fmt.Errorf("failed to execute: %v", err) } - return nil + return b.Bytes(), nil } diff --git a/internal/server/server.go b/internal/server/server.go index b632ff3..6d3c324 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -86,12 +86,13 @@ func (s *Server) Start(config *configurator.Config) error { } // generate a new config from that data - err = g.GenerateDHCP(config, eths) + b, err := g.GenerateDHCP(config, eths) if err != nil { logrus.Errorf("failed to generate DHCP: %v", err) w.Write([]byte("An error has occurred.")) return } + w.Write(b) } }) r.HandleFunc("/templates", func(w http.ResponseWriter, r *http.Request) { From ce553d5cc0df004db5df75c8b4678a5fe5f1f680 Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 11 Apr 2024 13:06:00 -0600 Subject: [PATCH 4/5] Fixed minor issues --- cmd/generate.go | 7 ++++--- cmd/root.go | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/generate.go b/cmd/generate.go index b109814..8040aaa 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -81,6 +81,7 @@ var generateCmd = &cobra.Command{ // NOTE: we probably don't want to hardcode the types, but should do for now ext := "" + contents := []byte{} if g.Type == "dhcp" { // fetch eths from SMD eths, err := client.FetchEthernetInterfaces() @@ -92,7 +93,7 @@ var generateCmd = &cobra.Command{ continue } // generate a new config from that data - b, err := g.GenerateDHCP(&config, eths) + contents, err = g.GenerateDHCP(&config, eths) if err != nil { logrus.Errorf("failed to generate DHCP config file: %v\n", err) continue @@ -117,14 +118,14 @@ var generateCmd = &cobra.Command{ fmt.Printf("%s\n", "") } else if outputPath != "" && targetCount == 1 { // write just a single file using template name - err := os.WriteFile(outputPath) + err := os.WriteFile(outputPath, contents, 0o644) if err != nil { logrus.Errorf("failed to write config to file: %v", err) continue } } else if outputPath != "" && targetCount > 1 { // write multiple files in directory using template name - err := os.WriteFile(fmt.Sprintf("%s/%s.%s", filepath.Clean(outputPath), g.Template, ext)) + err := os.WriteFile(fmt.Sprintf("%s/%s.%s", filepath.Clean(outputPath), g.Template, ext), contents, 0o644) if err != nil { logrus.Errorf("failed to write config to file: %v", err) continue diff --git a/cmd/root.go b/cmd/root.go index b36bfd2..89f92c8 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -13,7 +13,7 @@ var ( configPath string config configurator.Config targets []string - output string + outputPath string ) var rootCmd = &cobra.Command{ From 3c90e72eb78e9985be048e96e02e0d37a940c76b Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 11 Apr 2024 13:59:56 -0600 Subject: [PATCH 5/5] Added TODO comments for token fetching --- cmd/generate.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/generate.go b/cmd/generate.go index 8040aaa..96553ec 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -31,12 +31,14 @@ var generateCmd = &cobra.Command{ // make sure that we have a token present before trying to make request if config.AccessToken == "" { - // check if OCHAMI_ACCESS_TOKEN env var is set if no access token is provided and use that instead + // TODO: make request to check if request will need token + // check if OCHAMI_ACCESS_TOKEN env var is set if no access token is provided and use that instead accessToken := os.Getenv("OCHAMI_ACCESS_TOKEN") if accessToken != "" { config.AccessToken = accessToken } else { + // TODO: try and fetch token first if it is needed fmt.Printf("No token found. Attempting to generate config without one...\n") } }