mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2026-03-19 19:42:38 +00:00
Compare commits
16 Commits
chore/tidy
...
v0.0.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be67fd03b5 | ||
|
|
9fecc1ea6d | ||
|
|
00e8ec0c88 | ||
|
|
8da8945d1b | ||
|
|
9a093fa1fb | ||
|
|
c8385531e6 | ||
|
|
1a486d4532 | ||
|
|
bdb2e739d4 | ||
|
|
ca8ce8188a | ||
|
|
f3b2171e51 | ||
|
|
23da1170f5 | ||
|
|
249c95490b | ||
|
|
a5846b08ba | ||
|
|
2537376eea | ||
|
|
ca5e0fab21 | ||
|
|
2dd18c3ba1 |
@@ -1 +1 @@
|
||||
{".":"0.0.4"}
|
||||
{".":"0.0.5"}
|
||||
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## [0.0.5](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.4...v0.0.5) (2023-03-24)
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* release 0.0.5 ([8da8945](https://github.com/k8sgpt-ai/k8sgpt/commit/8da8945d1b8d898440be235f88bdb2c08b0f9f84))
|
||||
|
||||
## [0.0.4](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.4...v0.0.4) (2023-03-24)
|
||||
|
||||
|
||||
|
||||
16
README.md
16
README.md
@@ -1,9 +1,9 @@
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./images/logo-white.png" width="100px;">
|
||||
<img alt="Text changing depending on mode. Light: 'So light!' Dark: 'So dark!'" src="./images/logo-black.png" width="100px;">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./images/banner-white.png" width="600px;">
|
||||
<img alt="Text changing depending on mode. Light: 'So light!' Dark: 'So dark!'" src="./images/banner-black.png" width="600px;">
|
||||
</picture>
|
||||
|
||||
_Try it out now_
|
||||
_Install it now_
|
||||
|
||||
```
|
||||
brew tap k8sgpt-ai/k8sgpt
|
||||
@@ -20,14 +20,18 @@ It has SRE experience codified into it's analyzers and helps to pull out the mos
|
||||
|
||||
```
|
||||
# Ensure KUBECONFIG env is set to an active Kubernetes cluster
|
||||
k8sgpt auth key <Your OpenAI key>
|
||||
|
||||
k8sgpt auth
|
||||
k8sgpt find problems
|
||||
# for more detail
|
||||
k8s find problems --explain
|
||||
|
||||
```
|
||||
|
||||
## Upcoming major milestones
|
||||
|
||||
- [] Multiple AI backend support
|
||||
- [] Custom AI/ML model backend support
|
||||
- [] Custom analyzers
|
||||
|
||||
### What about kubectl-ai?
|
||||
|
||||
The the kubectl-ai [project](https://github.com/sozercan/kubectl-ai) uses AI to create manifests and apply them to the cluster. It is not what we are trying to do here, it is focusing on writing YAML manifests.
|
||||
|
||||
@@ -1,24 +1,57 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
var (
|
||||
backend string
|
||||
)
|
||||
|
||||
// authCmd represents the auth command
|
||||
var AuthCmd = &cobra.Command{
|
||||
Use: "auth",
|
||||
Short: "A brief description of your command",
|
||||
Long: `A longer description that spans multiple lines and likely contains examples
|
||||
and usage of using your command. For example:
|
||||
|
||||
Cobra is a CLI library for Go that empowers applications.
|
||||
This application is a tool to generate the needed files
|
||||
to quickly create a Cobra application.`,
|
||||
Short: "Authenticate with your chosen backend",
|
||||
Long: `Provide the necessary credentials to authenticate with your chosen backend.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.Help()
|
||||
|
||||
backendType := viper.GetString("backend_type")
|
||||
if backendType == "" && backend == "" {
|
||||
color.Red("No backend set. Please run k8sgpt auth")
|
||||
os.Exit(1)
|
||||
}
|
||||
// override the default backend if a flag is provided
|
||||
if backend != "" {
|
||||
backendType = backend
|
||||
}
|
||||
|
||||
fmt.Printf("Enter %s Key: ", backendType)
|
||||
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
color.Red("Error reading %s Key from stdin: %s", backendType,
|
||||
err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
password := strings.TrimSpace(string(bytePassword))
|
||||
|
||||
viper.Set(fmt.Sprintf("%s_key", backendType), password)
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
color.Red("Error writing config file: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
color.Green("key added")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
// add flag for backend
|
||||
AuthCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
// keyCmd represents the key command
|
||||
var keyCmd = &cobra.Command{
|
||||
Use: "key",
|
||||
Short: "Add a key to OpenAI",
|
||||
Long: `This command will add a key from OpenAI to enable you to interact with the API`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
fmt.Print("Enter OpenAI API Key: ")
|
||||
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
color.Red("Error reading OpenAI API Key from stdin: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
password := strings.TrimSpace(string(bytePassword))
|
||||
|
||||
viper.Set("openai_api_key", password)
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
color.Red("Error writing config file: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
color.Green("key added")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AuthCmd.AddCommand(keyCmd)
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package find
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/fatih/color"
|
||||
@@ -12,7 +13,10 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var explain bool
|
||||
var (
|
||||
explain bool
|
||||
backend string
|
||||
)
|
||||
|
||||
// problemsCmd represents the problems command
|
||||
var problemsCmd = &cobra.Command{
|
||||
@@ -22,10 +26,34 @@ var problemsCmd = &cobra.Command{
|
||||
provide you with a list of issues that need to be resolved`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// Initialise the openAI client
|
||||
openAIClient, err := ai.NewClient()
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
// get backend from file
|
||||
backendType := viper.GetString("backend_type")
|
||||
if backendType == "" {
|
||||
color.Red("No backend set. Please run k8sgpt auth")
|
||||
os.Exit(1)
|
||||
}
|
||||
// override the default backend if a flag is provided
|
||||
if backend != "" {
|
||||
backendType = backend
|
||||
}
|
||||
// get the token with viper
|
||||
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)
|
||||
}
|
||||
|
||||
var aiClient ai.IAI
|
||||
switch backendType {
|
||||
case "openai":
|
||||
aiClient = &ai.OpenAIClient{}
|
||||
if err := aiClient.Configure(token); err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
default:
|
||||
color.Red("Backend not supported")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -33,7 +61,7 @@ var problemsCmd = &cobra.Command{
|
||||
// Get kubernetes client from viper
|
||||
client := viper.Get("kubernetesClient").(*kubernetes.Client)
|
||||
|
||||
if err := analyzer.RunAnalysis(ctx, client, openAIClient, explain); err != nil {
|
||||
if err := analyzer.RunAnalysis(ctx, client, aiClient, explain); err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -43,7 +71,8 @@ var problemsCmd = &cobra.Command{
|
||||
func init() {
|
||||
|
||||
problemsCmd.Flags().BoolVarP(&explain, "explain", "e", false, "Explain the problem to me")
|
||||
|
||||
// add flag for backend
|
||||
problemsCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
|
||||
FindCmd.AddCommand(problemsCmd)
|
||||
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ func init() {
|
||||
// will be global for your application.
|
||||
rootCmd.AddCommand(auth.AuthCmd)
|
||||
rootCmd.AddCommand(find.FindCmd)
|
||||
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.k8sgpt.git.yaml)")
|
||||
rootCmd.PersistentFlags().StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
|
||||
rootCmd.PersistentFlags().StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
|
||||
@@ -59,6 +58,7 @@ func init() {
|
||||
}
|
||||
|
||||
viper.Set("kubernetesClient", kubernetesClient)
|
||||
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
|
||||
BIN
images/banner-black.png
Normal file
BIN
images/banner-black.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
BIN
images/banner-white.png
Normal file
BIN
images/banner-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
3
main.go
3
main.go
@@ -1,3 +1,6 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package main
|
||||
|
||||
import "github.com/k8sgpt-ai/k8sgpt/cmd"
|
||||
|
||||
29
pkg/ai/ai.go
29
pkg/ai/ai.go
@@ -2,36 +2,25 @@ package ai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"errors"
|
||||
|
||||
"github.com/sashabaranov/go-openai"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
type OpenAIClient struct {
|
||||
client *openai.Client
|
||||
}
|
||||
|
||||
func (c *Client) GetClient() *openai.Client {
|
||||
return c.client
|
||||
}
|
||||
|
||||
func NewClient() (*Client, error) {
|
||||
|
||||
// get the token with viper
|
||||
token := viper.GetString("openai_api_key")
|
||||
// check if nil
|
||||
if token == "" {
|
||||
return nil, fmt.Errorf("no OpenAI API Key found")
|
||||
}
|
||||
|
||||
func (c *OpenAIClient) Configure(token string) error {
|
||||
client := openai.NewClient(token)
|
||||
return &Client{
|
||||
client: client,
|
||||
}, nil
|
||||
|
||||
if client == nil {
|
||||
return errors.New("error creating OpenAI client")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) GetCompletion(ctx context.Context, prompt string) (string, error) {
|
||||
func (c *OpenAIClient) GetCompletion(ctx context.Context, prompt string) (string, error) {
|
||||
// Create a completion request
|
||||
resp, err := c.client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
|
||||
Model: openai.GPT3Dot5Turbo,
|
||||
|
||||
8
pkg/ai/iai.go
Normal file
8
pkg/ai/iai.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package ai
|
||||
|
||||
import "context"
|
||||
|
||||
type IAI interface {
|
||||
Configure(token string) error
|
||||
GetCompletion(ctx context.Context, prompt string) (string, error)
|
||||
}
|
||||
@@ -2,11 +2,12 @@ package analyzer
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
)
|
||||
|
||||
func RunAnalysis(ctx context.Context, client *kubernetes.Client, aiClient *ai.Client, explain bool) error {
|
||||
func RunAnalysis(ctx context.Context, client *kubernetes.Client, aiClient ai.IAI, explain bool) error {
|
||||
err := AnalyzePod(ctx, client, aiClient, explain)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -4,17 +4,18 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/briandowns/spinner"
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/spf13/viper"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func AnalyzePod(ctx context.Context, client *kubernetes.Client, aiClient *ai.Client, explain bool) error {
|
||||
func AnalyzePod(ctx context.Context, client *kubernetes.Client, aiClient ai.IAI, explain bool) error {
|
||||
|
||||
// search all namespaces for pods that are not running
|
||||
list, err := client.GetClient().CoreV1().Pods("").List(ctx, metav1.ListOptions{})
|
||||
|
||||
@@ -4,17 +4,18 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/briandowns/spinner"
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/spf13/viper"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func AnalyzeReplicaSet(ctx context.Context, client *kubernetes.Client, aiClient *ai.Client, explain bool) error {
|
||||
func AnalyzeReplicaSet(ctx context.Context, client *kubernetes.Client, aiClient ai.IAI, explain bool) error {
|
||||
|
||||
// search all namespaces for pods that are not running
|
||||
list, err := client.GetClient().AppsV1().ReplicaSets("").List(ctx, metav1.ListOptions{})
|
||||
|
||||
Reference in New Issue
Block a user