Skip to content

Commit

Permalink
feat: get official field doc
Browse files Browse the repository at this point in the history
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>
  • Loading branch information
golgoth31 committed May 23, 2023
1 parent 49e120c commit cf67dc2
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 8 deletions.
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230515081240-6b5b845c638e.1
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230514071713-3d78cb8bbc06.1
github.com/aws/aws-sdk-go v1.44.267
github.com/go-resty/resty/v2 v2.7.0
)

require github.com/jmespath/go-jmespath v0.4.0 // indirect
Expand Down Expand Up @@ -152,7 +153,7 @@ require (
go.uber.org/zap v1.24.0
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/exp v0.0.0-20230124195608-d38c7dcee874 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/net v0.9.0
golang.org/x/oauth2 v0.6.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.8.0 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,8 @@ github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2Kv
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
Expand Down Expand Up @@ -1232,6 +1234,7 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
Expand Down
13 changes: 12 additions & 1 deletion pkg/analyzer/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type StatefulSetAnalyzer struct{}
func (StatefulSetAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {

kind := "StatefulSet"
apiDoc := util.K8sApiReference{
Kind: kind,
ApiVersion: "apps/v1",
ServerVersion: a.Client.ServerVersion,
}

AnalyzerErrorsMetric.DeletePartialMatch(map[string]string{
"analyzer_name": kind,
Expand All @@ -44,8 +49,14 @@ func (StatefulSetAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
serviceName := sts.Spec.ServiceName
_, err := a.Client.GetClient().CoreV1().Services(sts.Namespace).Get(a.Context, serviceName, metav1.GetOptions{})
if err != nil {
doc, _ := apiDoc.GetApiDoc("serviceName")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("StatefulSet uses the service %s/%s which does not exist.", sts.Namespace, serviceName),
Text: fmt.Sprintf(
"StatefulSet uses the service %s/%s which does not exist.\n Official Doc: %s",
sts.Namespace,
serviceName,
doc,
),
Sensitive: []common.Sensitive{
{
Unmasked: sts.Namespace,
Expand Down
20 changes: 14 additions & 6 deletions pkg/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package kubernetes

import (
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/kubernetes"
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
"k8s.io/client-go/rest"
Expand All @@ -23,9 +24,10 @@ import (
)

type Client struct {
Client kubernetes.Interface
RestClient rest.Interface
Config *rest.Config
Client kubernetes.Interface
RestClient rest.Interface
Config *rest.Config
ServerVersion *version.Info
}

func (c *Client) GetConfig() *rest.Config {
Expand Down Expand Up @@ -74,9 +76,15 @@ func NewClient(kubecontext string, kubeconfig string) (*Client, error) {
return nil, err
}

serverVersion, err := clientSet.ServerVersion()
if err != nil {
return nil, err
}

return &Client{
Client: clientSet,
RestClient: restClient,
Config: config,
Client: clientSet,
RestClient: restClient,
Config: config,
ServerVersion: serverVersion,
}, nil
}
75 changes: 75 additions & 0 deletions pkg/util/k8sapireference.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package util

import (
"fmt"
"strings"

"github.com/go-resty/resty/v2"
"golang.org/x/net/html"
)

func (k *K8sApiReference) GetApiDoc(field string) (string, error) {
client := resty.New()
splitApiVersion := strings.Split(
strings.ToLower(k.ApiVersion),
"/",
)

resp, err := client.R().
EnableTrace().
Get(
fmt.Sprintf(
"https://kubernetes.io/docs/reference/generated/kubernetes-api/v%s.%s/#%sspec-%s-%s",
k.ServerVersion.Major,
k.ServerVersion.Minor,
strings.ToLower(k.Kind),
splitApiVersion[1],
splitApiVersion[0],
),
)
if err != nil {
fmt.Printf("%w", err)
}

fieldDoc := ""
isFound := false
for _, line := range strings.Split(strings.TrimRight(string(resp.Body()), "\n"), "\n") {
if strings.Contains(line, field) {
tkn := html.NewTokenizer(strings.NewReader(line))
isTd := false

for {
tt := tkn.Next()

switch tt {
case html.ErrorToken:
break

case html.StartTagToken:
t := tkn.Token()
isTd = t.Data == "td"

case html.TextToken:
t := tkn.Token()

if isTd && t.Data != field {
fieldDoc = t.Data
isFound = true
}

isTd = false
}

if isFound {
break
}
}
}

if isFound {
break
}
}

return fieldDoc, nil
}
9 changes: 9 additions & 0 deletions pkg/util/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package util

import "k8s.io/apimachinery/pkg/version"

type K8sApiReference struct {
ApiVersion string
Kind string
ServerVersion *version.Info
}

0 comments on commit cf67dc2

Please sign in to comment.