From dac6c2306f7a3c9d5ae3f03c76b6a27f537f7e90 Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 14 Nov 2024 16:53:00 -0700 Subject: [PATCH] client: moved cacert logic from 'serve' cmd to client --- cmd/serve.go | 28 +------------ pkg/generator/generator.go | 18 ++++++--- pkg/server/server.go | 83 +++++++++++++++++++++++++------------- 3 files changed, 70 insertions(+), 59 deletions(-) diff --git a/cmd/serve.go b/cmd/serve.go index 507d330..647482b 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -4,15 +4,11 @@ package cmd import ( - "crypto/tls" - "crypto/x509" "encoding/json" "errors" "fmt" - "net" "net/http" "os" - "time" "github.com/OpenCHAMI/configurator/pkg/generator" "github.com/OpenCHAMI/configurator/pkg/server" @@ -48,7 +44,7 @@ var serveCmd = &cobra.Command{ fmt.Printf("%v\n", string(b)) } - // set up the routes and start the server + // set up the routes and start the serve server := server.Server{ Config: &config, Server: &http.Server{ @@ -66,28 +62,8 @@ var serveCmd = &cobra.Command{ }, } - // add cert to client if `--cacert` flag is passed - if cacertPath != "" { - cacert, _ := os.ReadFile(cacertPath) - certPool := x509.NewCertPool() - certPool.AppendCertsFromPEM(cacert) - server.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{ - RootCAs: certPool, - InsecureSkipVerify: true, - }, - DisableKeepAlives: true, - Dial: (&net.Dialer{ - Timeout: 120 * time.Second, - KeepAlive: 120 * time.Second, - }).Dial, - TLSHandshakeTimeout: 120 * time.Second, - ResponseHeaderTimeout: 120 * time.Second, - } - } - // start listening with the server - err := server.Serve() + err := server.Serve(cacertPath) if errors.Is(err, http.ErrServerClosed) { if verbose { fmt.Printf("Server closed.") diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index e46b576..e705e16 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -36,6 +36,7 @@ type ( TemplatePaths []string PluginPath string Target string + Client *configurator.SmdClient Verbose bool } ) @@ -409,17 +410,24 @@ func Generate(config *configurator.Config, params Params) (FileMap, error) { func GenerateWithTarget(config *configurator.Config, params Params) (FileMap, error) { // load generator plugins to generate configs or to print var ( + client configurator.SmdClient + target configurator.Target + generator Generator + err error + ok bool + ) + + // check if we have a client from params first and create new one if not + if params.Client == nil { client = configurator.NewSmdClient( configurator.WithHost(config.SmdClient.Host), configurator.WithPort(config.SmdClient.Port), configurator.WithAccessToken(config.AccessToken), configurator.WithCertPoolFile(config.CertPath), ) - target configurator.Target - generator Generator - err error - ok bool - ) + } else { + client = *params.Client + } // check if a target is supplied if len(params.Args) == 0 && params.Target == "" { diff --git a/pkg/server/server.go b/pkg/server/server.go index 66fdc58..9afc7db 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -4,8 +4,11 @@ package server import ( + "crypto/tls" + "crypto/x509" "encoding/json" "fmt" + "net" "net/http" "os" "time" @@ -60,13 +63,33 @@ func New(config *configurator.Config) *Server { } // Main function to start up configurator as a service. -func (s *Server) Serve() error { +func (s *Server) Serve(cacertPath string) error { // create client just for the server to use to fetch data from SMD - _ = &configurator.SmdClient{ + client := &configurator.SmdClient{ Host: s.Config.SmdClient.Host, Port: s.Config.SmdClient.Port, } + // add cert to client if `--cacert` flag is passed + if cacertPath != "" { + cacert, _ := os.ReadFile(cacertPath) + certPool := x509.NewCertPool() + certPool.AppendCertsFromPEM(cacert) + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: certPool, + InsecureSkipVerify: true, + }, + DisableKeepAlives: true, + Dial: (&net.Dialer{ + Timeout: 120 * time.Second, + KeepAlive: 120 * time.Second, + }).Dial, + TLSHandshakeTimeout: 120 * time.Second, + ResponseHeaderTimeout: 120 * time.Second, + } + } + // set the server address with config values s.Server.Addr = fmt.Sprintf("%s:%d", s.Config.Server.Host, s.Config.Server.Port) @@ -104,12 +127,12 @@ func (s *Server) Serve() error { ) // protected routes if using auth - r.HandleFunc("/generate", s.Generate) + r.HandleFunc("/generate", s.Generate(client)) r.HandleFunc("/templates", s.ManageTemplates) }) } else { // public routes without auth - router.HandleFunc("/generate", s.Generate) + router.HandleFunc("/generate", s.Generate(client)) router.HandleFunc("/templates", s.ManageTemplates) } @@ -127,32 +150,36 @@ func (s *Server) Close() { // This is the corresponding service function to generate templated files, that // works similarly to the CLI variant. This function takes similiar arguments as // query parameters that are included in the HTTP request URL. -func (s *Server) Generate(w http.ResponseWriter, r *http.Request) { - // get all of the expect query URL params and validate - s.GeneratorParams.Target = r.URL.Query().Get("target") - if s.GeneratorParams.Target == "" { - writeErrorResponse(w, "must specify a target") - return - } +func (s *Server) Generate(client *configurator.SmdClient) func(w http.ResponseWriter, r *http.Request) { - // generate a new config file from supplied params - outputs, err := generator.GenerateWithTarget(s.Config, s.GeneratorParams) - if err != nil { - writeErrorResponse(w, "failed to generate file: %v", err) - return - } + return func(w http.ResponseWriter, r *http.Request) { + // get all of the expect query URL params and validate + s.GeneratorParams.Target = r.URL.Query().Get("target") + s.GeneratorParams.Client = client + if s.GeneratorParams.Target == "" { + writeErrorResponse(w, "must specify a target") + return + } - // marshal output to JSON then send response to client - tmp := generator.ConvertContentsToString(outputs) - b, err := json.Marshal(tmp) - if err != nil { - writeErrorResponse(w, "failed to marshal output: %v", err) - return - } - _, err = w.Write(b) - if err != nil { - writeErrorResponse(w, "failed to write response: %v", err) - return + // generate a new config file from supplied params + outputs, err := generator.GenerateWithTarget(s.Config, s.GeneratorParams) + if err != nil { + writeErrorResponse(w, "failed to generate file: %v", err) + return + } + + // marshal output to JSON then send response to client + tmp := generator.ConvertContentsToString(outputs) + b, err := json.Marshal(tmp) + if err != nil { + writeErrorResponse(w, "failed to marshal output: %v", err) + return + } + _, err = w.Write(b) + if err != nil { + writeErrorResponse(w, "failed to write response: %v", err) + return + } } }