From 9157d4dd1312bf75b336beb0e097422b303d22f1 Mon Sep 17 00:00:00 2001 From: Thomas Schuetz Date: Thu, 13 Apr 2023 08:11:56 +0200 Subject: [PATCH] feat: unified cmd and api Signed-off-by: Thomas Schuetz --- cmd/analyze/analyze.go | 55 ++------------------------------------- cmd/serve/serve.go | 2 -- pkg/ai/noopai.go | 6 +++-- pkg/ai/openai.go | 10 ++++--- pkg/analysis/analysis.go | 56 +++++++++++++++++++++++++++++++++++++++- pkg/server/main.go | 56 +++------------------------------------- pkg/util/util.go | 4 +++ 7 files changed, 74 insertions(+), 115 deletions(-) diff --git a/cmd/analyze/analyze.go b/cmd/analyze/analyze.go index a1b371a549..39ced28bd1 100644 --- a/cmd/analyze/analyze.go +++ b/cmd/analyze/analyze.go @@ -1,16 +1,12 @@ package analyze import ( - "context" "fmt" "os" "github.com/fatih/color" - "github.com/k8sgpt-ai/k8sgpt/pkg/ai" "github.com/k8sgpt-ai/k8sgpt/pkg/analysis" - "github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes" "github.com/spf13/cobra" - "github.com/spf13/viper" ) var ( @@ -33,60 +29,13 @@ var AnalyzeCmd = &cobra.Command{ provide you with a list of issues that need to be resolved`, Run: func(cmd *cobra.Command, args []string) { - // get ai configuration - var configAI ai.AIConfiguration - err := viper.UnmarshalKey("ai", &configAI) + // AnalysisResult configuration + config, err := analysis.NewAnalysis(backend, language, filters, namespace, nocache, explain) if err != nil { color.Red("Error: %v", err) os.Exit(1) } - if len(configAI.Providers) == 0 { - color.Red("Error: AI provider not specified in configuration. Please run k8sgpt auth") - os.Exit(1) - } - - var aiProvider ai.AIProvider - for _, provider := range configAI.Providers { - if backend == provider.Name { - aiProvider = provider - break - } - } - - if aiProvider.Name == "" { - color.Red("Error: AI provider %s not specified in configuration. Please run k8sgpt auth", backend) - os.Exit(1) - } - - aiClient := ai.NewClient(aiProvider.Name) - if err := aiClient.Configure(aiProvider.Password, aiProvider.Model, language); err != nil { - color.Red("Error: %v", err) - os.Exit(1) - } - - ctx := context.Background() - // Get kubernetes client from viper - - kubecontext := viper.GetString("kubecontext") - kubeconfig := viper.GetString("kubeconfig") - client, err := kubernetes.NewClient(kubecontext, kubeconfig) - if err != nil { - color.Red("Error initialising kubernetes client: %v", err) - os.Exit(1) - } - - // AnalysisResult configuration - config := &analysis.Analysis{ - Namespace: namespace, - NoCache: nocache, - Filters: filters, - Explain: explain, - AIClient: aiClient, - Client: client, - Context: ctx, - } - err = config.RunAnalysis() if err != nil { color.Red("Error: %v", err) diff --git a/cmd/serve/serve.go b/cmd/serve/serve.go index c00aefe70a..e6350902e3 100644 --- a/cmd/serve/serve.go +++ b/cmd/serve/serve.go @@ -44,8 +44,6 @@ var ServeCmd = &cobra.Command{ Token: token, } - fmt.Println(server) - err := server.Serve() if err != nil { color.Red("Error: %v", err) diff --git a/pkg/ai/noopai.go b/pkg/ai/noopai.go index b544109033..8ea24d8516 100644 --- a/pkg/ai/noopai.go +++ b/pkg/ai/noopai.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "fmt" "github.com/fatih/color" + "github.com/k8sgpt-ai/k8sgpt/pkg/util" "github.com/spf13/viper" "strings" ) @@ -33,6 +34,7 @@ func (a *NoOpAIClient) Parse(ctx context.Context, prompt []string, nocache bool) inputKey := strings.Join(prompt, " ") // Check for cached data sEnc := base64.StdEncoding.EncodeToString([]byte(inputKey)) + cacheKey := util.GetCacheKey(a.GetName(), sEnc) response, err := a.GetCompletion(ctx, inputKey) if err != nil { @@ -40,8 +42,8 @@ func (a *NoOpAIClient) Parse(ctx context.Context, prompt []string, nocache bool) return "", err } - if !viper.IsSet(sEnc) { - viper.Set(sEnc, base64.StdEncoding.EncodeToString([]byte(response))) + if !viper.IsSet(cacheKey) { + viper.Set(cacheKey, base64.StdEncoding.EncodeToString([]byte(response))) if err := viper.WriteConfig(); err != nil { color.Red("error writing config: %v", err) return "", nil diff --git a/pkg/ai/openai.go b/pkg/ai/openai.go index 91a70c474e..4ffca36506 100644 --- a/pkg/ai/openai.go +++ b/pkg/ai/openai.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "errors" "fmt" + "github.com/k8sgpt-ai/k8sgpt/pkg/util" "strings" "github.com/fatih/color" @@ -58,10 +59,11 @@ func (a *OpenAIClient) Parse(ctx context.Context, prompt []string, nocache bool) inputKey := strings.Join(prompt, " ") // Check for cached data sEnc := base64.StdEncoding.EncodeToString([]byte(inputKey)) + cacheKey := util.GetCacheKey(a.GetName(), sEnc) // find in viper cache - if viper.IsSet(sEnc) && !nocache { + if viper.IsSet(cacheKey) && !nocache { // retrieve data from cache - response := viper.GetString(sEnc) + response := viper.GetString(cacheKey) if response == "" { color.Red("error retrieving cached data") return "", nil @@ -79,8 +81,8 @@ func (a *OpenAIClient) Parse(ctx context.Context, prompt []string, nocache bool) return "", err } - if !viper.IsSet(sEnc) { - viper.Set(sEnc, base64.StdEncoding.EncodeToString([]byte(response))) + if !viper.IsSet(cacheKey) || nocache { + viper.Set(cacheKey, base64.StdEncoding.EncodeToString([]byte(response))) if err := viper.WriteConfig(); err != nil { color.Red("error writing config: %v", err) return "", nil diff --git a/pkg/analysis/analysis.go b/pkg/analysis/analysis.go index f2ac1a7a4e..f7948aa66f 100644 --- a/pkg/analysis/analysis.go +++ b/pkg/analysis/analysis.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "os" "strings" "github.com/fatih/color" @@ -41,8 +42,61 @@ type JsonOutput struct { Results []common.Result `json:"results"` } -func (a *Analysis) RunAnalysis() error { +func NewAnalysis(backend string, language string, filters []string, namespace string, noCache bool, explain bool) (*Analysis, error) { + var configAI ai.AIConfiguration + err := viper.UnmarshalKey("ai", &configAI) + if err != nil { + color.Red("Error: %v", err) + os.Exit(1) + } + + if len(configAI.Providers) == 0 { + color.Red("Error: AI provider not specified in configuration. Please run k8sgpt auth") + os.Exit(1) + } + + var aiProvider ai.AIProvider + for _, provider := range configAI.Providers { + if backend == provider.Name { + aiProvider = provider + break + } + } + + if aiProvider.Name == "" { + color.Red("Error: AI provider %s not specified in configuration. Please run k8sgpt auth", backend) + return nil, errors.New("AI provider not specified in configuration") + } + aiClient := ai.NewClient(aiProvider.Name) + if err := aiClient.Configure(aiProvider.Password, aiProvider.Model, language); err != nil { + color.Red("Error: %v", err) + return nil, err + } + + ctx := context.Background() + // Get kubernetes client from viper + + kubecontext := viper.GetString("kubecontext") + kubeconfig := viper.GetString("kubeconfig") + client, err := kubernetes.NewClient(kubecontext, kubeconfig) + if err != nil { + color.Red("Error initialising kubernetes client: %v", err) + return nil, err + } + + return &Analysis{ + Context: ctx, + Filters: filters, + Client: client, + AIClient: aiClient, + Namespace: namespace, + NoCache: noCache, + Explain: explain, + }, nil +} + +func (a *Analysis) RunAnalysis() error { activeFilters := viper.GetStringSlice("active_filters") analyzerMap := analyzer.GetAnalyzerMap() diff --git a/pkg/server/main.go b/pkg/server/main.go index ade7012bb6..bfb4a1d865 100644 --- a/pkg/server/main.go +++ b/pkg/server/main.go @@ -1,13 +1,9 @@ package server import ( - "context" "fmt" "github.com/fatih/color" - "github.com/k8sgpt-ai/k8sgpt/pkg/ai" "github.com/k8sgpt-ai/k8sgpt/pkg/analysis" - "github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes" - "github.com/spf13/viper" "net/http" "os" ) @@ -31,56 +27,9 @@ func (s *K8sGPTServer) analyzeHandler(w http.ResponseWriter, r *http.Request) { nocache := getBoolParam(r.URL.Query().Get("nocache")) language := r.URL.Query().Get("language") - // get ai configuration - var configAI ai.AIConfiguration - err := viper.UnmarshalKey("ai", &configAI) + config, err := analysis.NewAnalysis(s.Backend, language, []string{}, namespace, nocache, explain) if err != nil { - color.Red("Error: %v", err) - os.Exit(1) - } - - if len(configAI.Providers) == 0 { - color.Red("Error: AI provider not specified in configuration. Please run k8sgpt auth") - os.Exit(1) - } - - var aiProvider ai.AIProvider - for _, provider := range configAI.Providers { - if s.Backend == provider.Name { - aiProvider = provider - break - } - } - - if aiProvider.Name == "" { - color.Red("Error: AI provider %s not specified in configuration. Please run k8sgpt auth", s.Backend) - os.Exit(1) - } - - aiClient := ai.NewClient(aiProvider.Name) - if err := aiClient.Configure(aiProvider.Password, aiProvider.Model, language); err != nil { - color.Red("Error: %v", err) - os.Exit(1) - } - - ctx := context.Background() - // Get kubernetes client from viper - - kubecontext := viper.GetString("kubecontext") - kubeconfig := viper.GetString("kubeconfig") - client, err := kubernetes.NewClient(kubecontext, kubeconfig) - if err != nil { - color.Red("Error initialising kubernetes client: %v", err) - os.Exit(1) - } - - config := &analysis.Analysis{ - Namespace: namespace, - Explain: explain, - AIClient: aiClient, - Client: client, - Context: ctx, - NoCache: nocache, + fmt.Fprintf(w, err.Error()) } err = config.RunAnalysis() @@ -108,6 +57,7 @@ func (s *K8sGPTServer) analyzeHandler(w http.ResponseWriter, r *http.Request) { func (s *K8sGPTServer) Serve() error { http.HandleFunc("/analyze", s.analyzeHandler) + color.Green("Starting server on port " + s.Port) err := http.ListenAndServe(":"+s.Port, nil) if err != nil { fmt.Printf("error starting server: %s\n", err) diff --git a/pkg/util/util.go b/pkg/util/util.go index 37f504c733..8cf273cbde 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -129,3 +129,7 @@ func ReplaceIfMatch(text string, pattern string, replacement string) string { } return text } + +func GetCacheKey(provider string, sEnc string) string { + return fmt.Sprintf("%s-%s", provider, sEnc) +}