Compare commits

..

25 Commits

Author SHA1 Message Date
Alex Jones
9f0cb6240e Merge pull request #152 from k8sgpt-ai/release-please--branches--main
chore(main): release 0.1.4
2023-03-30 13:42:14 +01:00
github-actions[bot]
26db0f6941 chore(main): release 0.1.4 2023-03-30 12:29:37 +00:00
Alex Jones
2acab541bc Merge pull request #155 from k8sgpt-ai/fix/kubectx
fix: now supports different kubeconfig and kubectx
2023-03-30 13:29:05 +01:00
Thomas Schuetz
53a19bb04d Merge branch 'main' into fix/kubectx 2023-03-30 14:27:56 +02:00
Alex Jones
c8f3c946b0 fix: now supports different kubeconfig and kubectx
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2023-03-30 12:49:02 +01:00
HOLLEVILLE Matthis
b061566404 feat: add Ingress class validation (#154)
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-30 13:48:53 +02:00
Alexandre Steppé
be061da5b6 feat: output selected backend (#153)
Signed-off-by: Alexandre Steppé <alexandre.steppe@gmail.com>
2023-03-30 13:37:10 +02:00
Roberth Strand
5f548421c7 Merge pull request #151 from k8sgpt-ai/feat/rs-cleanup
refactor: removed sample flag
2023-03-30 12:04:40 +02:00
Roberth Strand
0afd52844b refactor: removed sample flag
Commented out the sample flag that the framework comes with, as it was not in use. Choose to comment it out for now for easy reference, just in case we want to implement that type of toggle flags.

Signed-off-by: Roberth Strand <me@robstr.dev>
2023-03-30 11:48:43 +02:00
Alex Jones
f95c1e1d8c Merge pull request #130 from k8sgpt-ai/release-please--branches--main
chore(main): release 0.1.3
2023-03-30 09:00:17 +01:00
github-actions[bot]
3fc0d45823 chore(main): release 0.1.3 2023-03-30 07:51:31 +00:00
Alex Jones
cf633b606d Merge pull request #144 from matthisholleville/fix/ingress-object-meta-value
fix: ingress object meta value
2023-03-30 08:51:03 +01:00
Alex Jones
ab63bd0dd1 Merge branch 'main' into fix/ingress-object-meta-value 2023-03-30 08:49:48 +01:00
Alex Jones
3e05eb2af2 Merge pull request #149 from k8sgpt-ai/feat/analysis-speed
feat: analysis speed
2023-03-30 08:44:03 +01:00
Alex Jones
548039ebe6 feat: improvement to analysis speed
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2023-03-30 08:19:35 +01:00
Alex Jones
0d5b8ad027 Merge branch 'main' of github.com:k8sgpt-ai/k8sgpt into main 2023-03-30 07:52:24 +01:00
Thomas Schuetz
0f910e497a Merge branch 'main' into fix/ingress-object-meta-value 2023-03-30 08:38:45 +02:00
Alex Jones
172c2df6c5 fix: bugfix for output (#148) 2023-03-30 08:38:11 +02:00
Alex Jones
2eab0c544f feat: bugfix for output
Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2023-03-30 07:28:42 +01:00
Chadi Laoulaou
f4765bed1b fix: typo in description of the filter flag in analyze command (#147)
Signed-off-by: Chadi Laoulaou <chadilaoulaou@gmail.com>
2023-03-30 05:38:47 +02:00
Matthis Holleville
14ba8d5550 fix: add Ingress in GetParent switch case
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-30 01:35:09 +02:00
Aris Boutselis
bf49a51c62 fix: Change ObjectMeta value in Ingress analyser.
Signed-off-by: Aris Boutselis <aris.boutselis@senseon.io>
2023-03-30 00:10:19 +01:00
HOLLEVILLE Matthis
86c7e81e18 feat: add secret validation to ingress analyzer (#141)
This commit adds a check to the ingress analyzer that verifies whether the secret declared in the ingress exists on the cluster. This helps to ensure that only valid secrets are used in the ingress configuration.

Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-29 20:36:50 +00:00
Mike Levan
cdc7bb1272 readme update to specifiy WSL and Linux (#142)
Co-authored-by: michael levan <michael.levan@orbica.world>
2023-03-29 21:42:56 +02:00
HOLLEVILLE Matthis
fe683b71b8 feat: init ingress analyzer (#138)
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-03-29 18:27:05 +02:00
11 changed files with 211 additions and 61 deletions

View File

@@ -1 +1 @@
{".":"0.1.2"}
{".":"0.1.4"}

View File

@@ -1,5 +1,53 @@
# Changelog
## [0.1.4](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.1.3...v0.1.4) (2023-03-30)
### Features
* add Ingress class validation ([#154](https://github.com/k8sgpt-ai/k8sgpt/issues/154)) ([b061566](https://github.com/k8sgpt-ai/k8sgpt/commit/b061566404ef80288ca29add2d401574109d44c0))
* output selected backend ([#153](https://github.com/k8sgpt-ai/k8sgpt/issues/153)) ([be061da](https://github.com/k8sgpt-ai/k8sgpt/commit/be061da5b65045938acd70ad2eb2d21b87d2d6bf))
### Bug Fixes
* now supports different kubeconfig and kubectx ([c8f3c94](https://github.com/k8sgpt-ai/k8sgpt/commit/c8f3c946b00c00cd185961a4fa777806da94014e))
### Refactoring
* removed sample flag ([0afd528](https://github.com/k8sgpt-ai/k8sgpt/commit/0afd52844b96579391f77698bf0555145b6d2be8))
## [0.1.3](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.1.2...v0.1.3) (2023-03-30)
### Features
* add secret validation to ingress analyzer ([#141](https://github.com/k8sgpt-ai/k8sgpt/issues/141)) ([86c7e81](https://github.com/k8sgpt-ai/k8sgpt/commit/86c7e81e18db02ebcbfe35d470682c982871375f))
* bugfix for output ([2eab0c5](https://github.com/k8sgpt-ai/k8sgpt/commit/2eab0c544fbb6026f6aea79b08d8f29c061acf2e))
* CODE_OF_CONDUCT.md ([#129](https://github.com/k8sgpt-ai/k8sgpt/issues/129)) ([fe73633](https://github.com/k8sgpt-ai/k8sgpt/commit/fe73633273c5c1f4188bca48471283535967d5aa))
* create-security.md ([27b8916](https://github.com/k8sgpt-ai/k8sgpt/commit/27b8916f297570907437686c6d958636fb249d50))
* improvement to analysis speed ([548039e](https://github.com/k8sgpt-ai/k8sgpt/commit/548039ebe62bb609c1aa288e5e49845850fd2dd8))
* init ingress analyzer ([#138](https://github.com/k8sgpt-ai/k8sgpt/issues/138)) ([fe683b7](https://github.com/k8sgpt-ai/k8sgpt/commit/fe683b71b84fe82459b0ffe366b4dcfa1c978cfe))
### Bug Fixes
* add Ingress in GetParent switch case ([14ba8d5](https://github.com/k8sgpt-ai/k8sgpt/commit/14ba8d555005f31fc2201cb8b61653093c19b8a7))
* bugfix for output ([#148](https://github.com/k8sgpt-ai/k8sgpt/issues/148)) ([172c2df](https://github.com/k8sgpt-ai/k8sgpt/commit/172c2df6c55f5fddbfec7f8526be5f2323d1b900))
* Change ObjectMeta value in Ingress analyser. ([bf49a51](https://github.com/k8sgpt-ai/k8sgpt/commit/bf49a51c62af450cff51a590547ef30989bd2e93))
* typo in description of the filter flag in analyze command ([#147](https://github.com/k8sgpt-ai/k8sgpt/issues/147)) ([f4765be](https://github.com/k8sgpt-ai/k8sgpt/commit/f4765bed1b1ad121a81b35878fdb866354b5e34a))
### Other
* **deps:** update google-github-actions/release-please-action digest to ee9822e ([#132](https://github.com/k8sgpt-ai/k8sgpt/issues/132)) ([01b2826](https://github.com/k8sgpt-ai/k8sgpt/commit/01b282647512a4eaebd42ab5847b5534de148d14))
### Docs
* add new slack link ([#134](https://github.com/k8sgpt-ai/k8sgpt/issues/134)) ([#135](https://github.com/k8sgpt-ai/k8sgpt/issues/135)) ([cad2b38](https://github.com/k8sgpt-ai/k8sgpt/commit/cad2b38d037658495024ec0166ebd3e936f65c2e))
## [0.1.2](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.1.1...v0.1.2) (2023-03-28)

View File

@@ -17,8 +17,8 @@ brew install k8sgpt
```
<details>
<summary>Failing Installation on WSL (missing gcc)</summary>
When installing Homebrew on WSL, you may encounter the following error:
<summary>Failing Installation on WSL or Linux (missing gcc)</summary>
When installing Homebrew on WSL or Linux, you may encounter the following error:
```
==> Installing k8sgpt from k8sgpt-ai/k8sgpt Error: The following formula cannot be installed from bottle and must be
@@ -64,6 +64,7 @@ you will be able to write your own analyzers.
- [x] rsAnalyzer
- [x] serviceAnalyzer
- [x] eventAnalyzer
- [x] ingressAnalyzer
## Usage

View File

@@ -77,23 +77,11 @@ var AnalyzeCmd = &cobra.Command{
}
var analysisResults *[]analyzer.Analysis = &[]analyzer.Analysis{}
if err := analyzer.RunAnalysis(ctx, config, client,
if err := analyzer.RunAnalysis(ctx, filters, config, client,
aiClient, analysisResults); err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
// Removed filtered results from slice
if len(filters) > 0 {
var filteredResults []analyzer.Analysis
for _, analysis := range *analysisResults {
for _, filter := range filters {
if strings.Contains(analysis.Kind, filter) {
filteredResults = append(filteredResults, analysis)
}
}
}
analysisResults = &filteredResults
}
var bar *progressbar.ProgressBar
if len(*analysisResults) > 0 {
@@ -139,9 +127,12 @@ var AnalyzeCmd = &cobra.Command{
}
fmt.Println(string(j))
default:
fmt.Printf("%s %s(%s): %s \n%s\n", color.CyanString("%d", n),
color.YellowString(analysis.Name), color.CyanString(analysis.ParentObject),
color.RedString(analysis.Error[0]), color.GreenString(analysis.Details))
fmt.Printf("%s %s(%s)\n", color.CyanString("%d", n),
color.YellowString(analysis.Name), color.CyanString(analysis.ParentObject))
for _, err := range analysis.Error {
fmt.Printf("- %s %s\n", color.RedString("Error:"), color.RedString(err))
}
color.GreenString(analysis.Details)
}
}
},
@@ -154,7 +145,7 @@ func init() {
// no cache flag
AnalyzeCmd.Flags().BoolVarP(&nocache, "no-cache", "c", false, "Do not use cached data")
// array of strings flag
AnalyzeCmd.Flags().StringSliceVarP(&filters, "filter", "f", []string{}, "Filter for these analzyers (e.g. Pod,PersistentVolumeClaim,Service,ReplicaSet)")
AnalyzeCmd.Flags().StringSliceVarP(&filters, "filter", "f", []string{}, "Filter for these analyzers (e.g. Pod, PersistentVolumeClaim, Service, ReplicaSet)")
// explain flag
AnalyzeCmd.Flags().BoolVarP(&explain, "explain", "e", false, "Explain the problem to me")
// add flag for backend

View File

@@ -35,6 +35,7 @@ var AuthCmd = &cobra.Command{
// override the default backend if a flag is provided
if backend != "" {
backendType = backend
color.Green("Using %s as backend AI provider", backendType)
}
fmt.Printf("Enter %s Key: ", backendType)

View File

@@ -1,8 +1,11 @@
package cmd
import (
"github.com/k8sgpt-ai/k8sgpt/cmd/generate"
"os"
"path/filepath"
"github.com/k8sgpt-ai/k8sgpt/cmd/generate"
"k8s.io/client-go/util/homedir"
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/cmd/analyze"
@@ -13,10 +16,10 @@ import (
)
var (
cfgFile string
masterURL string
kubeconfig string
version string
cfgFile string
kubecontext string
kubeconfig string
version string
)
// rootCmd represents the base command when called without any subcommands
@@ -42,23 +45,25 @@ func Execute(v string) {
func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
var kubeconfigPath string
if home := homedir.HomeDir(); home != "" {
kubeconfigPath = filepath.Join(home, ".kube", "config")
}
rootCmd.AddCommand(auth.AuthCmd)
rootCmd.AddCommand(analyze.AnalyzeCmd)
rootCmd.AddCommand(generate.GenerateCmd)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.k8sgpt.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.")
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.")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
// rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
//Initialise the kubeconfig
kubernetesClient, err := kubernetes.NewClient(masterURL, kubeconfig)
kubernetesClient, err := kubernetes.NewClient(kubecontext, kubeconfig)
if err != nil {
color.Red("Error initialising kubernetes client: %v", err)
os.Exit(1)
}
viper.Set("kubernetesClient", kubernetesClient)

View File

@@ -3,6 +3,7 @@ package analyzer
import (
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
)
type AnalysisConfiguration struct {
@@ -17,6 +18,7 @@ type PreAnalysis struct {
ReplicaSet appsv1.ReplicaSet
PersistentVolumeClaim v1.PersistentVolumeClaim
Endpoint v1.Endpoints
Ingress networkingv1.Ingress
}
type Analysis struct {

View File

@@ -11,28 +11,35 @@ import (
"github.com/spf13/viper"
)
func RunAnalysis(ctx context.Context, config *AnalysisConfiguration,
var analyzerMap = map[string]func(ctx context.Context, config *AnalysisConfiguration,
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error{
"Pod": AnalyzePod,
"ReplicaSet": AnalyzeReplicaSet,
"PersistentVolumeClaim": AnalyzePersistentVolumeClaim,
"Service": AnalyzeEndpoints,
"Ingress": AnalyzeIngress,
}
func RunAnalysis(ctx context.Context, filters []string, config *AnalysisConfiguration,
client *kubernetes.Client,
aiClient ai.IAI, analysisResults *[]Analysis) error {
err := AnalyzePod(ctx, config, client, aiClient, analysisResults)
if err != nil {
return err
// if there are no filters selected then run all of them
if len(filters) == 0 {
for _, analyzer := range analyzerMap {
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
return err
}
}
return nil
}
err = AnalyzeReplicaSet(ctx, config, client, aiClient, analysisResults)
if err != nil {
return err
}
err = AnalyzePersistentVolumeClaim(ctx, config, client, aiClient, analysisResults)
if err != nil {
return err
}
err = AnalyzeEndpoints(ctx, config, client, aiClient, analysisResults)
if err != nil {
return err
for _, filter := range filters {
if analyzer, ok := analyzerMap[filter]; ok {
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
return err
}
}
}
return nil
}

View File

@@ -0,0 +1,84 @@
package analyzer
import (
"context"
"fmt"
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func AnalyzeIngress(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI,
analysisResults *[]Analysis) error {
list, err := client.GetClient().NetworkingV1().Ingresses(config.Namespace).List(ctx, metav1.ListOptions{})
if err != nil {
return err
}
var preAnalysis = map[string]PreAnalysis{}
for _, ing := range list.Items {
var failures []string
// get ingressClassName
ingressClassName := ing.Spec.IngressClassName
if ingressClassName == nil {
ingClassValue := ing.Annotations["kubernetes.io/ingress.class"]
if ingClassValue == "" {
failures = append(failures, fmt.Sprintf("Ingress %s/%s does not specify an Ingress class.", ing.Namespace, ing.Name))
} else {
ingressClassName = &ingClassValue
}
}
// check if ingressclass exist
if ingressClassName != nil {
_, err := client.GetClient().NetworkingV1().IngressClasses().Get(ctx, *ingressClassName, metav1.GetOptions{})
if err != nil {
failures = append(failures, fmt.Sprintf("Ingress uses the ingress class %s which does not exist.", *ingressClassName))
}
}
// loop over rules
for _, rule := range ing.Spec.Rules {
// loop over paths
for _, path := range rule.HTTP.Paths {
_, err := client.GetClient().CoreV1().Services(ing.Namespace).Get(ctx, path.Backend.Service.Name, metav1.GetOptions{})
if err != nil {
failures = append(failures, fmt.Sprintf("Ingress uses the service %s/%s which does not exist.", ing.Namespace, path.Backend.Service.Name))
}
}
}
for _, tls := range ing.Spec.TLS {
_, err := client.GetClient().CoreV1().Secrets(ing.Namespace).Get(ctx, tls.SecretName, metav1.GetOptions{})
if err != nil {
failures = append(failures, fmt.Sprintf("Ingress uses the secret %s/%s as a TLS certificate which does not exist.", ing.Namespace, tls.SecretName))
}
}
if len(failures) > 0 {
preAnalysis[fmt.Sprintf("%s/%s", ing.Namespace, ing.Name)] = PreAnalysis{
Ingress: ing,
FailureDetails: failures,
}
}
}
for key, value := range preAnalysis {
var currentAnalysis = Analysis{
Kind: "Ingress",
Name: key,
Error: value.FailureDetails,
}
parent, _ := util.GetParent(client, value.Ingress.ObjectMeta)
currentAnalysis.ParentObject = parent
*analysisResults = append(*analysisResults, currentAnalysis)
}
return nil
}

View File

@@ -2,7 +2,6 @@ package kubernetes
import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
@@ -14,21 +13,23 @@ func (c *Client) GetClient() *kubernetes.Clientset {
return c.client
}
func NewClient(masterURL string, kubeconfig string) (*Client, error) {
func NewClient(kubecontext string, kubeconfig string) (*Client, error) {
config, err := rest.InClusterConfig()
if err != nil {
kubeconfig :=
clientcmd.NewDefaultClientConfigLoadingRules().GetDefaultFilename()
config, err = clientcmd.BuildConfigFromFlags(masterURL, kubeconfig)
if err != nil {
return nil, err
}
}
clientSet, err := kubernetes.NewForConfig(config)
config := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
&clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig},
&clientcmd.ConfigOverrides{
CurrentContext: kubecontext,
})
// create the clientset
c, err := config.ClientConfig()
if err != nil {
return nil, err
}
clientSet, err := kubernetes.NewForConfig(c)
if err != nil {
return nil, err
}
return &Client{
client: clientSet,
}, nil

View File

@@ -50,6 +50,16 @@ func GetParent(client *kubernetes.Client, meta metav1.ObjectMeta) (string, bool)
return GetParent(client, ds.ObjectMeta)
}
return "DaemonSet/" + ds.Name, false
case "Ingress":
ds, err := client.GetClient().NetworkingV1().Ingresses(meta.Namespace).Get(context.Background(), owner.Name, metav1.GetOptions{})
if err != nil {
return "", false
}
if ds.OwnerReferences != nil {
return GetParent(client, ds.ObjectMeta)
}
return "Ingress/" + ds.Name, false
}
}
}