Skip to content

Commit

Permalink
feat: integration refactor (#684)
Browse files Browse the repository at this point in the history
* feat: more significant refactor

Signed-off-by: Alex Jones <[email protected]>

* feat: more significant refactor

Signed-off-by: Alex Jones <[email protected]>

* feat: reworked the integration activate/deactivation

Signed-off-by: Alex Jones <[email protected]>

* chore: updated schema for list integrations

Signed-off-by: Alex Jones <[email protected]>

* fix: error with incorrect error being swallowed

Signed-off-by: Alex Jones <[email protected]>

* feat: added namespace check

Signed-off-by: Alex Jones <[email protected]>

* chore: fixed issue with namespace and skip install validation

Signed-off-by: Alex Jones <[email protected]>

---------

Signed-off-by: Alex Jones <[email protected]>
  • Loading branch information
AlexsJones authored Sep 28, 2023
1 parent ddeff9f commit 69fe2db
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 53 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
__debug*
.DS_Store
k8sgpt*
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ require (
require github.com/adrg/xdg v0.4.0

require (
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230919114723-34e017906403.1
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.31.0-20230919114723-34e017906403.1
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230927080702-a2be8a73637d.1
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.31.0-20230927080702-a2be8a73637d.1
github.com/aws/aws-sdk-go v1.45.16
github.com/cohere-ai/cohere-go v0.2.0
)
Expand Down
10 changes: 5 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230919114723-34e017906403.1 h1:OMpJ48yTsJ12DDJlhpNXTZOfNEfkrcAwGqgSvL1vg7U=
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230919114723-34e017906403.1/go.mod h1:cc42fuhIhL3qTsCrT4dK0kZ5u6hm02WJraREmSVZHmA=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230919114723-34e017906403.4/go.mod h1:i/s4ALHwKvjA1oGNKpoHg0FpEOTbufoOm/NdTE6YQAE=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.31.0-20230919114723-34e017906403.1 h1:rn//G20ZMgHwnfl7shj5zmpDgzS8aZsoVkeJ7+fMkfo=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.31.0-20230919114723-34e017906403.1/go.mod h1:gtnk2yAUexdY5nTuUg0SH5WCCGvpKzr7pd3Xbi7MWjE=
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230927080702-a2be8a73637d.1 h1:uXlT8FiRD+JL0qzZJ0m5Zmw5HpKyDFs204y27zuT7RA=
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230927080702-a2be8a73637d.1/go.mod h1:p9CUiOwgt2bvcr0goNK7NgMfButIVGhKnv8cyWW7FOM=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230927080702-a2be8a73637d.4/go.mod h1:i/s4ALHwKvjA1oGNKpoHg0FpEOTbufoOm/NdTE6YQAE=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.31.0-20230927080702-a2be8a73637d.1 h1:Snnz9mUZNxMFpd+l5m1zaVdIVAplVmdFxYVn5/f4UoI=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.31.0-20230927080702-a2be8a73637d.1/go.mod h1:gtnk2yAUexdY5nTuUg0SH5WCCGvpKzr7pd3Xbi7MWjE=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
Expand Down
9 changes: 5 additions & 4 deletions pkg/cache/cache.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package cache

import (
"errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/spf13/viper"
)
Expand Down Expand Up @@ -63,17 +64,17 @@ func RemoveRemoteCache(bucketName string) error {
var cacheInfo CacheProvider
err := viper.UnmarshalKey("cache", &cacheInfo)
if err != nil {
return err
return status.Error(codes.Internal, "cache unmarshal")
}
if cacheInfo.BucketName == "" {
return errors.New("Error: no cache is configured")
return status.Error(codes.Internal, "no cache configured")
}

cacheInfo = CacheProvider{}
viper.Set("cache", cacheInfo)
err = viper.WriteConfig()
if err != nil {
return err
return status.Error(codes.Internal, "unable to write config")
}

return nil
Expand Down
3 changes: 2 additions & 1 deletion pkg/integration/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ type IIntegration interface {
AddAnalyzer(*map[string]common.IAnalyzer)

GetAnalyzerName() []string
// An integration must keep record of its deployed namespace (if not using --no-install)
GetNamespace() (string, error)

OwnsAnalyzer(string) bool

Expand Down Expand Up @@ -86,7 +88,6 @@ func (*Integration) Activate(name string, namespace string, activeFilters []stri
return err
}
}

mergedFilters := activeFilters
mergedFilters = append(mergedFilters, integrations[name].GetAnalyzerName()...)
uniqueFilters, _ := util.RemoveDuplicates(mergedFilters)
Expand Down
17 changes: 16 additions & 1 deletion pkg/integration/trivy/trivy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package trivy
import (
"context"
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/k8sgpt-ai/k8sgpt/pkg/common"
helmclient "github.com/mittwald/go-helm-client"
Expand Down Expand Up @@ -51,6 +53,20 @@ func (t *Trivy) GetAnalyzerName() []string {
}
}

// This doesnt work
func (t *Trivy) GetNamespace() (string, error) {
releases, err := t.helm.ListDeployedReleases()
if err != nil {
return "", err
}
for _, rel := range releases {
if rel.Name == ReleaseName {
return rel.Namespace, nil
}
}
return "", status.Error(codes.NotFound, "trivy release not found")
}

func (t *Trivy) OwnsAnalyzer(analyzer string) bool {

for _, a := range t.GetAnalyzerName() {
Expand All @@ -67,7 +83,6 @@ func (t *Trivy) Deploy(namespace string) error {
Name: RepoShortName,
URL: Repo,
}

// Add a chart-repository to the client.
if err := t.helm.AddOrUpdateChartRepo(chartRepo); err != nil {
panic(err)
Expand Down
6 changes: 5 additions & 1 deletion pkg/server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ grpcurl -plaintext -d '{"namespace": "k8sgpt", "explain" : "true"}' localhost:80
```

```
grpcurl -plaintext localhost:8080 schema.v1.ServerService/ListIntegrations
grpcurl -plaintext localhost:8080 schema.v1.ServerService/ListIntegrations
{
"integrations": [
"trivy"
]
}
```

```
grpcurl -plaintext -d '{"integrations":{"trivy":{"enabled":"true","namespace":"default","skipInstall":"false"}}}' localhost:8080 schema.v1.ServerService/AddConfig
```
47 changes: 14 additions & 33 deletions pkg/server/config.go
Original file line number Diff line number Diff line change
@@ -1,64 +1,45 @@
package server

import (
"context"
"errors"

schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1"
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
"context"
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
"github.com/k8sgpt-ai/k8sgpt/pkg/integration"
"github.com/spf13/viper"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func (h *handler) AddConfig(ctx context.Context, i *schemav1.AddConfigRequest) (*schemav1.AddConfigResponse, error,
) {

if i.Integrations != nil {
coreFilters, _, _ := analyzer.ListFilters()
// Update filters
activeFilters := viper.GetStringSlice("active_filters")
if len(activeFilters) == 0 {
activeFilters = coreFilters
}
integration := integration.NewIntegration()

if i.Integrations.Trivy != nil {
// Enable/Disable Trivy
var err = integration.Activate("trivy", i.Integrations.Trivy.Namespace,
activeFilters, i.Integrations.Trivy.SkipInstall)
return &schemav1.AddConfigResponse{
Status: "",
}, err
}
resp, err := h.syncIntegration(ctx, i)
if err != nil {
return resp, err
}

if i.Cache != nil {
// Remote cache
if i.Cache.BucketName == "" || i.Cache.Region == "" {
return &schemav1.AddConfigResponse{}, errors.New("BucketName & Region are required")
return resp, status.Error(codes.InvalidArgument, "cache arguments")
}

err := cache.AddRemoteCache(i.Cache.BucketName, i.Cache.Region)
if err != nil {
return &schemav1.AddConfigResponse{
Status: err.Error(),
}, err
return resp, err
}
}
return &schemav1.AddConfigResponse{
Status: "Configuration updated.",
}, nil
return resp, nil
}

func (h *handler) RemoveConfig(ctx context.Context, i *schemav1.RemoveConfigRequest) (*schemav1.RemoveConfigResponse, error,
) {
err := cache.RemoveRemoteCache(i.Cache.BucketName)
if err != nil {
return &schemav1.RemoveConfigResponse{
Status: err.Error(),
}, err
return &schemav1.RemoveConfigResponse{}, err
}

// Remove any integrations is a TBD as it would be nice to make this more granular
// Currently integrations can be removed in the AddConfig sync

return &schemav1.RemoveConfigResponse{
Status: "Successfully removed the remote cache",
}, nil
Expand Down
132 changes: 126 additions & 6 deletions pkg/server/integration.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,144 @@
package server

import (
"context"

schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1"
"context"
"fmt"
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
"github.com/k8sgpt-ai/k8sgpt/pkg/integration"
"github.com/spf13/viper"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

const (
trivyName = "trivy"
)

// syncIntegration is aware of the following events
// A new integration added
// An integration removed from the Integration block
func (h *handler) syncIntegration(ctx context.Context,
i *schemav1.AddConfigRequest) (*schemav1.AddConfigResponse, error,
) {
response := &schemav1.AddConfigResponse{}
integrationProvider := integration.NewIntegration()
if i.Integrations == nil {
// If there are locally activate integrations, disable them
err := h.deactivateAllIntegrations(integrationProvider)
if err != nil {
return response, status.Error(codes.NotFound, "deactivation error")
}
return response, nil
}
coreFilters, _, _ := analyzer.ListFilters()
// Update filters
activeFilters := viper.GetStringSlice("active_filters")
if len(activeFilters) == 0 {
activeFilters = coreFilters
}
var err error = status.Error(codes.OK, "")
deactivateFunc := func(integrationRef integration.IIntegration) error {
namespace, err := integrationRef.GetNamespace()
if err != nil {
return err
}
err = integrationProvider.Deactivate(trivyName, namespace)
if err != nil {
return status.Error(codes.NotFound, "integration already deactivated")
}
return nil
}
integrationRef, err := integrationProvider.Get(trivyName)
if err != nil {
return response, status.Error(codes.NotFound, "provider get failure")
}
if i.Integrations.Trivy != nil {
switch i.Integrations.Trivy.Enabled {
case true:
if b, err := integrationProvider.IsActivate(trivyName); err != nil {
return response, status.Error(codes.Internal, "integration activation error")
} else {
if !b {
err := integrationProvider.Activate(trivyName, i.Integrations.Trivy.Namespace,
activeFilters, i.Integrations.Trivy.SkipInstall)
if err != nil {
return nil, err
}
} else {
return response, status.Error(codes.AlreadyExists, "integration already active")
}
}
case false:
err = deactivateFunc(integrationRef)
if err != nil {
return nil, err
}
// This break is included purely for static analysis to pass
}
} else {
// If Trivy has been removed, disable it
err = deactivateFunc(integrationRef)
if err != nil {
return nil, err
}
}

return response, err
}

func (*handler) ListIntegrations(ctx context.Context, req *schemav1.ListIntegrationsRequest) (*schemav1.ListIntegrationsResponse, error) {

integrationProvider := integration.NewIntegration()
integrations := integrationProvider.List()
// Update the requester with the status of Trivy
trivy, err := integrationProvider.Get(trivyName)
active := trivy.IsActivate()
var skipInstall bool
var namespace string = ""
if active {
namespace, err = trivy.GetNamespace()
if err != nil {
return nil, status.Error(codes.NotFound, "namespace not found")
}
if namespace == "" {
skipInstall = true
}
}

if err != nil {
return nil, status.Error(codes.NotFound, "trivy integration")
}
resp := &schemav1.ListIntegrationsResponse{
Integrations: make([]string, 0),
Trivy: &schemav1.Trivy{
Enabled: active,
Namespace: namespace,
SkipInstall: skipInstall,
},
}

return resp, nil
}

func (*handler) deactivateAllIntegrations(integrationProvider *integration.Integration) error {
integrations := integrationProvider.List()
for _, i := range integrations {
b, _ := integrationProvider.IsActivate(i)
if b {
resp.Integrations = append(resp.Integrations, i)
in, err := integrationProvider.Get(i)
namespace, err := in.GetNamespace()
if err != nil {
return err
}
if err == nil {
if namespace != "" {
integrationProvider.Deactivate(i, namespace)
} else {
fmt.Printf("Skipping deactivation of %s, not installed\n", i)
}
} else {
return err
}
}
}
return resp, nil
return nil
}

0 comments on commit 69fe2db

Please sign in to comment.