Skip to content

Commit

Permalink
Merge pull request #254 from k8sgpt-ai/feat/serve
Browse files Browse the repository at this point in the history
feat: http server
  • Loading branch information
AlexsJones committed Apr 13, 2023
2 parents 7551f8b + 26c0cb2 commit 5dcc190
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 60 deletions.
55 changes: 2 additions & 53 deletions cmd/analyze/analyze.go
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -33,67 +29,20 @@ 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)
}

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)
os.Exit(1)
}

if explain {
if len(configAI.Providers) == 0 {
color.Red("Error: AI provider not specified in configuration. Please run k8sgpt auth")
os.Exit(1)
}

err := config.GetAIResults(output, anonymize)
if err != nil {
color.Red("Error: %v", err)
Expand Down
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"github.com/k8sgpt-ai/k8sgpt/cmd/serve"
"os"
"path/filepath"

Expand Down Expand Up @@ -53,6 +54,7 @@ func init() {
rootCmd.AddCommand(filters.FiltersCmd)
rootCmd.AddCommand(generate.GenerateCmd)
rootCmd.AddCommand(integration.IntegrationCmd)
rootCmd.AddCommand(serve.ServeCmd)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.k8sgpt.yaml)")
rootCmd.PersistentFlags().StringVar(&kubecontext, "kubecontext", "", "Kubernetes context to use. Only required if out-of-cluster.")
rootCmd.PersistentFlags().StringVar(&kubeconfig, "kubeconfig", kubeconfigPath, "Path to a kubeconfig. Only required if out-of-cluster.")
Expand Down
60 changes: 60 additions & 0 deletions cmd/serve/serve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package serve

import (
"fmt"
"github.com/fatih/color"
k8sgptserver "github.com/k8sgpt-ai/k8sgpt/pkg/server"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"os"
)

var (
port string
backend string
token string
)

var ServeCmd = &cobra.Command{
Use: "serve",
Short: "Runs k8sgpt as a server",
Long: `Runs k8sgpt as a server to allow for easy integration with other applications.`,
Run: func(cmd *cobra.Command, args []string) {

backendType := viper.GetString("backend_type")
if backendType == "" {
color.Red("No backend set. Please run k8sgpt auth")
os.Exit(1)
}

if backend != "" {
backendType = backend
}

token := viper.GetString(fmt.Sprintf("%s_key", backendType))
// check if nil
if token == "" {
color.Red("No %s key set. Please run k8sgpt auth", backendType)
os.Exit(1)
}

server := k8sgptserver.Config{
Backend: backend,
Port: port,
Token: token,
}

err := server.Serve()
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
// override the default backend if a flag is provided
},
}

func init() {
// add flag for backend
ServeCmd.Flags().StringVarP(&port, "port", "p", "8080", "Port to run the server on")
ServeCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.20
require (
github.com/aquasecurity/trivy-operator v0.13.0
github.com/fatih/color v1.15.0
github.com/julienschmidt/httprouter v1.3.0
github.com/magiconair/properties v1.8.7
github.com/mittwald/go-helm-client v0.12.1
github.com/sashabaranov/go-openai v1.7.0
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
Expand Down
6 changes: 4 additions & 2 deletions pkg/ai/noopai.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/base64"
"fmt"
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
"github.com/spf13/viper"
"strings"
)
Expand Down Expand Up @@ -33,15 +34,16 @@ 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 {
color.Red("error getting completion: %v", err)
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
Expand Down
10 changes: 6 additions & 4 deletions pkg/ai/openai.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/base64"
"errors"
"fmt"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
"strings"

"github.com/fatih/color"
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
56 changes: 55 additions & 1 deletion pkg/analysis/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"os"
"strings"

"github.com/fatih/color"
Expand Down Expand Up @@ -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 && explain {
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()
Expand Down
Loading

0 comments on commit 5dcc190

Please sign in to comment.