diff --git a/api/v1alpha1/k8sgpt_types.go b/api/v1alpha1/k8sgpt_types.go index b720c357..441012f2 100644 --- a/api/v1alpha1/k8sgpt_types.go +++ b/api/v1alpha1/k8sgpt_types.go @@ -68,6 +68,15 @@ type AISpec struct { Language string `json:"language,omitempty"` } +type Trivy struct { + Enabled bool `json:"enabled,omitempty"` + SkipInstall bool `json:"skipInstall,omitempty"` + Namespace string `json:"namespace,omitempty"` +} +type Integrations struct { + Trivy *Trivy `json:"trivy,omitempty"` +} + // K8sGPTSpec defines the desired state of K8sGPT type K8sGPTSpec struct { Version string `json:"version,omitempty"` @@ -77,6 +86,7 @@ type K8sGPTSpec struct { Sink *WebhookRef `json:"sink,omitempty"` AI *AISpec `json:"ai,omitempty"` RemoteCache *RemoteCacheRef `json:"remoteCache,omitempty"` + Integrations *Integrations `json:"integrations,omitempty"` } const ( diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index c131490b..3ef00f24 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -115,6 +115,26 @@ func (in *Failure) DeepCopy() *Failure { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Integrations) DeepCopyInto(out *Integrations) { + *out = *in + if in.Trivy != nil { + in, out := &in.Trivy, &out.Trivy + *out = new(Trivy) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Integrations. +func (in *Integrations) DeepCopy() *Integrations { + if in == nil { + return nil + } + out := new(Integrations) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *K8sGPT) DeepCopyInto(out *K8sGPT) { *out = *in @@ -202,6 +222,11 @@ func (in *K8sGPTSpec) DeepCopyInto(out *K8sGPTSpec) { *out = new(RemoteCacheRef) (*in).DeepCopyInto(*out) } + if in.Integrations != nil { + in, out := &in.Integrations, &out.Integrations + *out = new(Integrations) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new K8sGPTSpec. @@ -375,6 +400,21 @@ func (in *Sensitive) DeepCopy() *Sensitive { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Trivy) DeepCopyInto(out *Trivy) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Trivy. +func (in *Trivy) DeepCopy() *Trivy { + if in == nil { + return nil + } + out := new(Trivy) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WebhookRef) DeepCopyInto(out *WebhookRef) { *out = *in diff --git a/config/crd/bases/core.k8sgpt.ai_k8sgpts.yaml b/config/crd/bases/core.k8sgpt.ai_k8sgpts.yaml index d071c423..9a536326 100644 --- a/config/crd/bases/core.k8sgpt.ai_k8sgpts.yaml +++ b/config/crd/bases/core.k8sgpt.ai_k8sgpts.yaml @@ -81,6 +81,18 @@ spec: items: type: string type: array + integrations: + properties: + trivy: + properties: + enabled: + type: boolean + namespace: + type: string + skipInstall: + type: boolean + type: object + type: object noCache: type: boolean remoteCache: diff --git a/controllers/k8sgpt_controller.go b/controllers/k8sgpt_controller.go index a939a428..669d37b7 100644 --- a/controllers/k8sgpt_controller.go +++ b/controllers/k8sgpt_controller.go @@ -178,6 +178,13 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr return r.finishReconcile(err, false) } } + if k8sgptConfig.Spec.Integrations != nil { + err = k8sgptClient.AddIntegration(k8sgptConfig) + if err != nil { + k8sgptReconcileErrorCount.Inc() + return r.finishReconcile(err, false) + } + } response, err := k8sgptClient.ProcessAnalysis(deployment, k8sgptConfig) if err != nil { diff --git a/go.mod b/go.mod index 71fabd31..2974523d 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/k8sgpt-ai/k8sgpt-operator go 1.19 require ( - buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230620082254-6f80f9533908.1 - buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.31.0-20230828112343-a9fd9ad20848.1 + 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 github.com/onsi/ginkgo/v2 v2.12.0 github.com/onsi/gomega v1.27.10 github.com/prometheus/client_golang v1.16.0 @@ -26,6 +26,7 @@ require ( ) require ( + buf.build/gen/go/k8sgpt-ai/k8sgpt/connectrpc/go v1.11.1-20230919114723-34e017906403.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect diff --git a/go.sum b/go.sum index f3735f7b..5daa2b71 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,19 @@ +buf.build/gen/go/k8sgpt-ai/k8sgpt/connectrpc/go v1.11.1-20230830164712-dc062a152c20.1 h1:Q936ek1+X3/Ud3o1ajG1eL52W5nsTZFYErLWiUt01A4= +buf.build/gen/go/k8sgpt-ai/k8sgpt/connectrpc/go v1.11.1-20230830164712-dc062a152c20.1/go.mod h1:hlKBEoYi1fvrRhi75lnznnXKH9VVBf9u6bY/lkj58oA= +buf.build/gen/go/k8sgpt-ai/k8sgpt/connectrpc/go v1.11.1-20230919114723-34e017906403.1 h1:4ffb19hBiaHhWaJN5F7Kg08lIHDK7SkHsWh+gGrjmoc= +buf.build/gen/go/k8sgpt-ai/k8sgpt/connectrpc/go v1.11.1-20230919114723-34e017906403.1/go.mod h1:H26axo1Ku8cV8oAhejdNaiFAUduB82WuTB6HNM6f4uQ= buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230620082254-6f80f9533908.1 h1:Z0zeGzAumjLyAb/24aiBNyAheT+SDBhlxPfcUy12nPI= buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230620082254-6f80f9533908.1/go.mod h1:ydXSuYyk0CN76EA+cjFemhpz87XtuU310GdmkmXUUY8= +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-20230620082254-6f80f9533908.4/go.mod h1:i/s4ALHwKvjA1oGNKpoHg0FpEOTbufoOm/NdTE6YQAE= +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-20230828112343-a9fd9ad20848.1 h1:fScSW5Gzu1OzUYylwpvQwgXX5J9YPKkOQpbkc5c8Q+8= buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.31.0-20230828112343-a9fd9ad20848.1/go.mod h1:gtnk2yAUexdY5nTuUg0SH5WCCGvpKzr7pd3Xbi7MWjE= +buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.31.0-20230830164712-dc062a152c20.1 h1:oD5YCdsVnQgVLSHxium66FFfuxjjvn5u65mnQo6vAyc= +buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.31.0-20230830164712-dc062a152c20.1/go.mod h1:gtnk2yAUexdY5nTuUg0SH5WCCGvpKzr7pd3Xbi7MWjE= +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= 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= diff --git a/pkg/client/integration.go b/pkg/client/integration.go new file mode 100644 index 00000000..90b18a93 --- /dev/null +++ b/pkg/client/integration.go @@ -0,0 +1,55 @@ +package client + +import ( + "context" + "errors" + "fmt" + + rpc "buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go/schema/v1/schemav1grpc" + schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1" + "github.com/k8sgpt-ai/k8sgpt-operator/api/v1alpha1" +) + +func (c *Client) AddIntegration(config *v1alpha1.K8sGPT) error { + + // Check if the integration is active already + client := rpc.NewServerServiceClient(c.conn) + + req := &schemav1.ListIntegrationsRequest{} + + resp, err := client.ListIntegrations(context.Background(), + req) + if err != nil { + return err + } + + if config.Spec.Integrations.Trivy == nil { + return errors.New("integrations: only Trivy is currently supported") + } + + // Check for active integrations + for _, active := range resp.Integrations { + switch active { + case "trivy": + // Integration is active, nothing to do + return nil + } + } + // If the integration is inactive, make it active + // TODO: Currently this only support trivy + configUpdatereq := &schemav1.AddConfigRequest{ + Integrations: &schemav1.Integrations{ + Trivy: &schemav1.Trivy{ + Enabled: true, + SkipInstall: config.Spec.Integrations.Trivy.SkipInstall, + Namespace: config.Spec.Integrations.Trivy.Namespace, + }, + }, + } + _, err = client.AddConfig(context.Background(), configUpdatereq) + if err != nil { + return fmt.Errorf("failed to call AddConfig RPC: %v", err) + } + fmt.Println("Activated integration") + return nil +}