Compare commits

...

47 Commits

Author SHA1 Message Date
github-actions[bot]
9c0efe6f5c chore(main): release 0.3.6 (#467)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-31 17:49:44 +01:00
golgoth31
f9621af7e4 feat: get official field doc (#457)
* fix(deps): update module github.com/aws/aws-sdk-go to v1.44.267 (#451)

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* feat: get official field doc

Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* feat: use schema from server

Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* feat: add configuration api route (#459)

* feat: add configuration api route

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

* feat: rename cache methods

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

---------

Signed-off-by: Matthis Holleville <matthish29@gmail.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* fix(deps): update module github.com/aws/aws-sdk-go to v1.44.269 (#458)

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* fix: updated list.go to handle k8sgpt cache list crashing issue (#455)

* Update list.go

Signed-off-by: Krishna Dutt Panchagnula <krishnadutt123@gmail.com>

* fix: updated list.go to handle k8sgpt cache list crashing issue

Signed-off-by: Krishna Dutt Panchagnula <krishnadutt123@gmail.com>

---------

Signed-off-by: Krishna Dutt Panchagnula <krishnadutt123@gmail.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* chore(main): release 0.3.5 (#452)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* chore(deps): update google-github-actions/release-please-action digest to 51ee8ae (#464)

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* fix: name of sa reference in deployment (#468)

Signed-off-by: Johannes Kleinlercher <johannes@kleinlercher.at>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* fix(deps): update module github.com/aws/aws-sdk-go to v1.44.270 (#465)

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* fix: typo (#463)

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>
Co-authored-by: Thomas Schuetz <38893055+thschue@users.noreply.github.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* fix(deps): update module github.com/aws/aws-sdk-go to v1.44.271 (#469)

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* fix(deps): update module github.com/aws/aws-sdk-go to v1.44.269 (#458)

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update module github.com/aws/aws-sdk-go to v1.44.270 (#465)

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* fix(deps): update module github.com/aws/aws-sdk-go to v1.44.271 (#469)

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* feat: Add with-doc flag to enable/disable kubernetes doc

Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* use fmt.Sprintf in apireference.go

Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

* add --with-doc to readme

Signed-off-by: David Sabatie <david.sabatie@notrenet.com>

---------

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Signed-off-by: David Sabatie <david.sabatie@notrenet.com>
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
Signed-off-by: Krishna Dutt Panchagnula <krishnadutt123@gmail.com>
Signed-off-by: Johannes Kleinlercher <johannes@kleinlercher.at>
Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>
Signed-off-by: golgoth31 <golgoth31@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Matthis <99146727+matthisholleville@users.noreply.github.com>
Co-authored-by: Krishna Dutt Panchagnula <krishnadutt123@gmail.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Johannes Kleinlercher <johannes@kleinlercher.at>
Co-authored-by: Rakshit Gondwal <98955085+rakshitgondwal@users.noreply.github.com>
Co-authored-by: Thomas Schuetz <38893055+thschue@users.noreply.github.com>
2023-05-31 10:36:41 +01:00
renovate[bot]
6052a5b4d7 fix(deps): update module github.com/spf13/viper to v1.16.0 (#472)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-31 10:25:39 +01:00
renovate[bot]
42437f77d1 fix(deps): update module github.com/stretchr/testify to v1.8.4 (#471)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-31 10:23:57 +01:00
renovate[bot]
523362765f fix(deps): update module github.com/aws/aws-sdk-go to v1.44.272 (#473)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-31 09:19:31 +01:00
renovate[bot]
1459dd4b8e fix(deps): update module github.com/aws/aws-sdk-go to v1.44.271 (#469)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-27 07:59:45 +03:00
Rakshit Gondwal
1b86a6fc89 fix: typo (#463)
Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>
Co-authored-by: Thomas Schuetz <38893055+thschue@users.noreply.github.com>
2023-05-26 18:49:29 +00:00
renovate[bot]
5cf4fc52da fix(deps): update module github.com/aws/aws-sdk-go to v1.44.270 (#465)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-26 18:48:38 +00:00
Johannes Kleinlercher
cd049c9b4b fix: name of sa reference in deployment (#468)
Signed-off-by: Johannes Kleinlercher <johannes@kleinlercher.at>
2023-05-26 21:48:01 +03:00
renovate[bot]
86ebc23de7 chore(deps): update google-github-actions/release-please-action digest to 51ee8ae (#464)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-26 14:22:27 +03:00
github-actions[bot]
a236cc4f28 chore(main): release 0.3.5 (#452)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-25 12:23:54 +01:00
Krishna Dutt Panchagnula
6eac58d4b0 fix: updated list.go to handle k8sgpt cache list crashing issue (#455)
* Update list.go

Signed-off-by: Krishna Dutt Panchagnula <krishnadutt123@gmail.com>

* fix: updated list.go to handle k8sgpt cache list crashing issue

Signed-off-by: Krishna Dutt Panchagnula <krishnadutt123@gmail.com>

---------

Signed-off-by: Krishna Dutt Panchagnula <krishnadutt123@gmail.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2023-05-25 11:21:06 +01:00
renovate[bot]
2994c1c5a7 fix(deps): update module github.com/aws/aws-sdk-go to v1.44.269 (#458)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-25 11:08:57 +01:00
Matthis
fa4a0757b8 feat: add configuration api route (#459)
* feat: add configuration api route

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

* feat: rename cache methods

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

---------

Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-05-25 10:42:49 +01:00
renovate[bot]
49e120c28e fix(deps): update module github.com/aws/aws-sdk-go to v1.44.267 (#451)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-23 06:44:27 +02:00
github-actions[bot]
6479cbaf91 chore(main): release 0.3.4 (#448)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-22 06:48:23 +01:00
Peter Pan
36995fd4ed chore: add more filter releavent UT in analysis_test.go (#435)
Signed-off-by: Peter Pan <Peter.Pan@daocloud.io>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2023-05-22 06:40:36 +01:00
renovate[bot]
fe450eb69d fix(deps): update module github.com/stretchr/testify to v1.8.3 (#442)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-22 06:38:39 +01:00
renovate[bot]
edda743fa2 fix(deps): update module github.com/aws/aws-sdk-go to v1.44.266 (#446)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-22 06:27:59 +01:00
github-actions[bot]
57281df53c chore(main): release 0.3.3 (#433)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-20 20:39:03 +01:00
Alex Jones
1f767ebd2e fix: docker version (#444)
* feat: added the ability to set a user default AI provider

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* feat: added the ability to set a user default AI provider

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* feat: s3 based caching

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* fix: missing version info and improvements

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* chore: fixing local build

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

---------

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2023-05-20 20:33:46 +01:00
Matthis
b7dc384547 fix: append coreAnalyzer if active_filter is empty and integration is added (#441)
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-05-19 11:14:39 +02:00
renovate[bot]
c588e963de fix(deps): update module github.com/aws/aws-sdk-go to v1.44.265 (#445)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-19 09:59:48 +01:00
renovate[bot]
d13b91301c fix(deps): update kubernetes packages to v0.27.2 (#436)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-19 09:49:37 +01:00
Alex Jones
948dae5e28 feat: caching (#439)
* feat: added the ability to set a user default AI provider

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* feat: added the ability to set a user default AI provider

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* feat: s3 based caching

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* feat: s3 based caching

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* updated README.md

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* update README.md

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* updated README.md

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* chore: region is a must have

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* chore: clarified remove command

* updated remove.go

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* chore: test fmt causing issues will open another pr

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

---------

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2023-05-19 09:32:01 +01:00
Matthis
c659a875fc feat: rework auth commands (#438)
* feat: rename "auth new" to "auth add"

This change allows to be more consistent with the rest of the code

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

* feat: rework "auth remove" to be more consistent with other remove commands like "filters remove"

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

* feat: update documentation

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

---------

Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-05-18 16:50:29 +02:00
Matthis
f0d3f36f6d fix: use coreAnalyzer if there are no filters selected and no active_filters (#432)
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-05-17 09:36:47 +01:00
github-actions[bot]
940a50e851 chore(main): release 0.3.2 (#426)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-16 21:07:02 +01:00
Camilo Giraldo
06542b4bf1 fix: improve default_prompt (#406)
* fix: improve default_prompt

Signed-off-by: Camilo Giraldo <camigira@gmail.com>

* fix: specific instructions for prompt output

Signed-off-by: Camilo Giraldo <camigira@gmail.com>

---------

Signed-off-by: Camilo Giraldo <camigira@gmail.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2023-05-16 20:03:33 +00:00
Matthis
af826d500f fix: missing validation for backend option in remove command (#429)
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-05-16 12:54:53 +01:00
Alex Jones
cbe2fb4a4c feat: added the ability to set a user default AI provider (#427)
* feat: added the ability to set a user default AI provider

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* feat: added the ability to set a user default AI provider

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* chore: added provider to json output

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

---------

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
2023-05-16 13:31:19 +02:00
renovate[bot]
032576c728 chore(deps): update reviewdog/action-golangci-lint digest to 79d32f1 (#425)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-16 09:48:09 +01:00
dependabot[bot]
3099909113 chore(deps): bump github.com/docker/distribution (#428)
Bumps [github.com/docker/distribution](https://github.com/docker/distribution) from 2.8.1+incompatible to 2.8.2+incompatible.
- [Release notes](https://github.com/docker/distribution/releases)
- [Commits](https://github.com/docker/distribution/compare/v2.8.1...v2.8.2)

---
updated-dependencies:
- dependency-name: github.com/docker/distribution
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 09:40:11 +01:00
renovate[bot]
097c7912b0 chore(deps): update actions/setup-go digest to fac708d (#422)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-16 07:27:20 +01:00
github-actions[bot]
493c684eb7 chore(main): release 0.3.1 (#391)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-15 12:08:40 +01:00
renovate[bot]
a1f98ad78e fix(deps): update module buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go to v1.3.0-20230515081240-6b5b845c638e.1 (#397)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-15 11:45:25 +01:00
Peter Pan
e66de8c4ce chore: gofmt fix and enable in CI (#414)
* gofmt the files

Signed-off-by: Peter Pan <Peter.Pan@daocloud.io>

* add UT and goFMT to PR Gate (Github Action for PR)

Signed-off-by: Peter Pan <Peter.Pan@daocloud.io>

---------

Signed-off-by: Peter Pan <Peter.Pan@daocloud.io>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2023-05-15 06:53:59 +01:00
Aris Boutselis
aafe669739 fix: update engine's cmd flag to match the new cli layout (#400)
Signed-off-by: Aris Boutselis <arisboutselis08@gmail.com>
Co-authored-by: Aris Boutselis <arisboutselis08@gmail.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2023-05-15 06:46:06 +01:00
Matthis
e5e613acee feat: filters api (#407)
* fix: stop execution after matching condition in RunAnalysis()

The commit fixes the issue where the RunAnalysis() function continues execution even after matching a condition. The fix ensures that the execution stops at the end of the corresponding if statement, improving the control flow and preventing unnecessary processing.

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

* feat: include filters parameter in AnalyzeRequest initialization

The commit introduces a new feature where the filters parameter is included in the initialization of the AnalyzeRequest. This enhancement allows for more specific analysis by specifying filters during the analysis process.

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

---------

Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-05-14 10:07:43 +01:00
Peter Pan
ed73485d92 chore: make go-lint happy (#405)
Signed-off-by: Peter Pan <Peter.Pan@daocloud.io>
2023-05-12 12:24:30 +01:00
renovate[bot]
50916f2c93 fix(deps): update module buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go to v1.28.1-20230510140658-54288a50e81c.4 (#398)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-11 08:54:46 +01:00
renovate[bot]
c1410d1699 fix(deps): update module helm.sh/helm/v3 to v3.12.0 (#396)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
2023-05-11 08:09:28 +01:00
Matthis
c5b72eee16 feat: add remove command to remove a backend AI provider (#395)
* feat: add remove command to remove a backend AI provider

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

* Update cmd/auth/remove.go

Co-authored-by: Alex Jones <alex@k8sgpt.ai>
Signed-off-by: Matthis <99146727+matthisholleville@users.noreply.github.com>

* feat: update Long remove command

Signed-off-by: Matthis Holleville <matthish29@gmail.com>

---------

Signed-off-by: Matthis Holleville <matthish29@gmail.com>
Signed-off-by: Matthis <99146727+matthisholleville@users.noreply.github.com>
Co-authored-by: Alex Jones <alex@k8sgpt.ai>
2023-05-11 08:05:25 +01:00
renovate[bot]
8cfb717dc1 fix(deps): update module google.golang.org/grpc to v1.55.0 (#389)
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-09 21:17:38 +01:00
Matthis
639aa12931 feat: add error message if analyze request fail (#393)
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-05-09 18:08:39 +02:00
Matthis
123b8a66ee fix: clusterole name (#392)
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-05-09 14:28:09 +01:00
Matthis
5d4e591f11 feat: use correct port to metrics (#390)
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
2023-05-09 11:08:18 +02:00
64 changed files with 1584 additions and 332 deletions

View File

@@ -12,7 +12,7 @@ jobs:
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
- name: golangci-lint
uses: reviewdog/action-golangci-lint@f5d85915708b6e687c44764987a6912d390b17f6 # v2
uses: reviewdog/action-golangci-lint@79d32f10b2ea0d4cebb755d849b048c4b40c3d50 # v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-pr-check

View File

@@ -25,7 +25,7 @@ jobs:
- name: Checkout
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
- uses: google-github-actions/release-please-action@c078ea33917ab8cfa5300e48f4b7e6b16606aede # v3
- uses: google-github-actions/release-please-action@51ee8ae2605bd5ce1cfdcc5938684908f1cd9f69 # v3
id: release
with:
command: manifest
@@ -45,7 +45,7 @@ jobs:
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4
with:
go-version: '1.20'
- name: Download Syft

View File

@@ -19,9 +19,13 @@ jobs:
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
- name: Set up Go
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4
uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4
with:
go-version: ${{ env.GO_VERSION }}
- name: Test
run: go test -v ./...
- name: Unit Test
run: make test
# - name: Fmt Test
# run: fmtFiles=$(make fmt); if [ "$fmtFiles" != "" ];then exit 1; fi

View File

@@ -15,6 +15,8 @@ builds:
- darwin
ldflags:
- -s -w -X main.version={{.Version}}
- -s -w -X main.commit={{.ShortCommit}}
- -s -w -X main.Date={{.CommitDate}}
nfpms:
- file_name_template: '{{ .ProjectName }}_{{ .Arch }}'

View File

@@ -1 +1 @@
{".":"0.3.0"}
{".":"0.3.6"}

View File

@@ -1,5 +1,118 @@
# Changelog
## [0.3.6](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.5...v0.3.6) (2023-05-31)
### Features
* get official field doc ([#457](https://github.com/k8sgpt-ai/k8sgpt/issues/457)) ([f9621af](https://github.com/k8sgpt-ai/k8sgpt/commit/f9621af7e480f490710020b931cbb08fb9824740))
### Bug Fixes
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.270 ([#465](https://github.com/k8sgpt-ai/k8sgpt/issues/465)) ([5cf4fc5](https://github.com/k8sgpt-ai/k8sgpt/commit/5cf4fc52da4542a8bae98764d2fa7e337d95e5bd))
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.271 ([#469](https://github.com/k8sgpt-ai/k8sgpt/issues/469)) ([1459dd4](https://github.com/k8sgpt-ai/k8sgpt/commit/1459dd4b8eca937e95ebe9b727311dc8b023e304))
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.272 ([#473](https://github.com/k8sgpt-ai/k8sgpt/issues/473)) ([5233627](https://github.com/k8sgpt-ai/k8sgpt/commit/523362765f4c064c02798bb9e6f31e2bcc856e5f))
* **deps:** update module github.com/spf13/viper to v1.16.0 ([#472](https://github.com/k8sgpt-ai/k8sgpt/issues/472)) ([6052a5b](https://github.com/k8sgpt-ai/k8sgpt/commit/6052a5b4d77902e1882e3121b678671c89b57af8))
* **deps:** update module github.com/stretchr/testify to v1.8.4 ([#471](https://github.com/k8sgpt-ai/k8sgpt/issues/471)) ([42437f7](https://github.com/k8sgpt-ai/k8sgpt/commit/42437f77d1e0735a8f38a62ddbefb4d1f4e61c0e))
* name of sa reference in deployment ([#468](https://github.com/k8sgpt-ai/k8sgpt/issues/468)) ([cd049c9](https://github.com/k8sgpt-ai/k8sgpt/commit/cd049c9b4b188f702608d989fb32ae62f333dac5))
* typo ([#463](https://github.com/k8sgpt-ai/k8sgpt/issues/463)) ([1b86a6f](https://github.com/k8sgpt-ai/k8sgpt/commit/1b86a6fc89f90d29fdf2fab87a517f0da225ec96))
### Other
* **deps:** update google-github-actions/release-please-action digest to 51ee8ae ([#464](https://github.com/k8sgpt-ai/k8sgpt/issues/464)) ([86ebc23](https://github.com/k8sgpt-ai/k8sgpt/commit/86ebc23de762583b5904605f5651bbc83760aa95))
## [0.3.5](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.4...v0.3.5) (2023-05-25)
### Features
* add configuration api route ([#459](https://github.com/k8sgpt-ai/k8sgpt/issues/459)) ([fa4a075](https://github.com/k8sgpt-ai/k8sgpt/commit/fa4a0757b83f8ec00df951d49316f10961daa0e0))
### Bug Fixes
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.267 ([#451](https://github.com/k8sgpt-ai/k8sgpt/issues/451)) ([49e120c](https://github.com/k8sgpt-ai/k8sgpt/commit/49e120c28e8b5ce5a8f7255ebc0f1b1b5c423f95))
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.269 ([#458](https://github.com/k8sgpt-ai/k8sgpt/issues/458)) ([2994c1c](https://github.com/k8sgpt-ai/k8sgpt/commit/2994c1c5a77ce6ebe6e59d6edc9647c02f06f261))
* updated list.go to handle k8sgpt cache list crashing issue ([#455](https://github.com/k8sgpt-ai/k8sgpt/issues/455)) ([6eac58d](https://github.com/k8sgpt-ai/k8sgpt/commit/6eac58d4b03169356d3f06674ef206472e149fde))
## [0.3.4](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.3...v0.3.4) (2023-05-22)
### Bug Fixes
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.266 ([#446](https://github.com/k8sgpt-ai/k8sgpt/issues/446)) ([edda743](https://github.com/k8sgpt-ai/k8sgpt/commit/edda743fa2bf4b5ae2551c981447a5912a459bb4))
* **deps:** update module github.com/stretchr/testify to v1.8.3 ([#442](https://github.com/k8sgpt-ai/k8sgpt/issues/442)) ([fe450eb](https://github.com/k8sgpt-ai/k8sgpt/commit/fe450eb69da0645328e60e2d7b0852ffdb996dee))
### Other
* add more filter releavent UT in analysis_test.go ([#435](https://github.com/k8sgpt-ai/k8sgpt/issues/435)) ([36995fd](https://github.com/k8sgpt-ai/k8sgpt/commit/36995fd4ed41c8c83ebc308f8ec2a4bfe530f7dc))
## [0.3.3](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.2...v0.3.3) (2023-05-20)
### Features
* caching ([#439](https://github.com/k8sgpt-ai/k8sgpt/issues/439)) ([948dae5](https://github.com/k8sgpt-ai/k8sgpt/commit/948dae5e288ec3bb0165eb3ce32171b12003f9c7))
* rework auth commands ([#438](https://github.com/k8sgpt-ai/k8sgpt/issues/438)) ([c659a87](https://github.com/k8sgpt-ai/k8sgpt/commit/c659a875fc296849a3703bfd7f0c4796f44bdf5a))
### Bug Fixes
* append coreAnalyzer if active_filter is empty and integration is added ([#441](https://github.com/k8sgpt-ai/k8sgpt/issues/441)) ([b7dc384](https://github.com/k8sgpt-ai/k8sgpt/commit/b7dc3845476759bedb3a55f77c8779e4a9f460dd))
* **deps:** update kubernetes packages to v0.27.2 ([#436](https://github.com/k8sgpt-ai/k8sgpt/issues/436)) ([d13b913](https://github.com/k8sgpt-ai/k8sgpt/commit/d13b91301cab5e05349b68716cd506fa1705f36f))
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.265 ([#445](https://github.com/k8sgpt-ai/k8sgpt/issues/445)) ([c588e96](https://github.com/k8sgpt-ai/k8sgpt/commit/c588e963de3f238f07200d6cf09fe6f9781484f5))
* docker version ([#444](https://github.com/k8sgpt-ai/k8sgpt/issues/444)) ([1f767eb](https://github.com/k8sgpt-ai/k8sgpt/commit/1f767ebd2e31e61decab36218b1b85f2b3b6207d))
* use coreAnalyzer if there are no filters selected and no active_filters ([#432](https://github.com/k8sgpt-ai/k8sgpt/issues/432)) ([f0d3f36](https://github.com/k8sgpt-ai/k8sgpt/commit/f0d3f36f6d56bd76248590c0b841dffb7769a2ee))
## [0.3.2](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.1...v0.3.2) (2023-05-16)
### Features
* added the ability to set a user default AI provider ([#427](https://github.com/k8sgpt-ai/k8sgpt/issues/427)) ([cbe2fb4](https://github.com/k8sgpt-ai/k8sgpt/commit/cbe2fb4a4c160a0a24b3fb4602cae8e5eebd6aa0))
### Bug Fixes
* improve default_prompt ([#406](https://github.com/k8sgpt-ai/k8sgpt/issues/406)) ([06542b4](https://github.com/k8sgpt-ai/k8sgpt/commit/06542b4bf1aec193f11a40526a1b60be01972e66))
* missing validation for backend option in remove command ([#429](https://github.com/k8sgpt-ai/k8sgpt/issues/429)) ([af826d5](https://github.com/k8sgpt-ai/k8sgpt/commit/af826d500fef0469b958250161b0827aa4ab2933))
### Other
* **deps:** bump github.com/docker/distribution ([#428](https://github.com/k8sgpt-ai/k8sgpt/issues/428)) ([3099909](https://github.com/k8sgpt-ai/k8sgpt/commit/30999091136c64173e5c15b789036c85f8b855f3))
* **deps:** update actions/setup-go digest to fac708d ([#422](https://github.com/k8sgpt-ai/k8sgpt/issues/422)) ([097c791](https://github.com/k8sgpt-ai/k8sgpt/commit/097c7912b0572d0461f08af12e9f21c6618c13e4))
* **deps:** update reviewdog/action-golangci-lint digest to 79d32f1 ([#425](https://github.com/k8sgpt-ai/k8sgpt/issues/425)) ([032576c](https://github.com/k8sgpt-ai/k8sgpt/commit/032576c728751522fe6cd8f255366cc3d5c0f23c))
## [0.3.1](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.0...v0.3.1) (2023-05-15)
### Features
* add error message if analyze request fail ([#393](https://github.com/k8sgpt-ai/k8sgpt/issues/393)) ([639aa12](https://github.com/k8sgpt-ai/k8sgpt/commit/639aa12931b3fc9f99a4b34f33f583b9f427f40c))
* add remove command to remove a backend AI provider ([#395](https://github.com/k8sgpt-ai/k8sgpt/issues/395)) ([c5b72ee](https://github.com/k8sgpt-ai/k8sgpt/commit/c5b72eee165a29d4ed59b0ec2f19e9f58267840d))
* filters api ([#407](https://github.com/k8sgpt-ai/k8sgpt/issues/407)) ([e5e613a](https://github.com/k8sgpt-ai/k8sgpt/commit/e5e613acee0a99f108dd90affc55a18dee42ad9c))
* use correct port to metrics ([#390](https://github.com/k8sgpt-ai/k8sgpt/issues/390)) ([5d4e591](https://github.com/k8sgpt-ai/k8sgpt/commit/5d4e591f11e555cac851205fff158ef22f702c33))
### Bug Fixes
* clusterole name ([#392](https://github.com/k8sgpt-ai/k8sgpt/issues/392)) ([123b8a6](https://github.com/k8sgpt-ai/k8sgpt/commit/123b8a66eed1af41b7bd4e558ba4f0f8ef947e98))
* **deps:** update module buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go to v1.3.0-20230515081240-6b5b845c638e.1 ([#397](https://github.com/k8sgpt-ai/k8sgpt/issues/397)) ([a1f98ad](https://github.com/k8sgpt-ai/k8sgpt/commit/a1f98ad78ecd9a84d26e7a59c340e5410524e561))
* **deps:** update module buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go to v1.28.1-20230510140658-54288a50e81c.4 ([#398](https://github.com/k8sgpt-ai/k8sgpt/issues/398)) ([50916f2](https://github.com/k8sgpt-ai/k8sgpt/commit/50916f2c93fb19b935f835eda1ba78b7c0465fe6))
* **deps:** update module google.golang.org/grpc to v1.55.0 ([#389](https://github.com/k8sgpt-ai/k8sgpt/issues/389)) ([8cfb717](https://github.com/k8sgpt-ai/k8sgpt/commit/8cfb717dc15a6af489a16282d38d3495518bc919))
* **deps:** update module helm.sh/helm/v3 to v3.12.0 ([#396](https://github.com/k8sgpt-ai/k8sgpt/issues/396)) ([c1410d1](https://github.com/k8sgpt-ai/k8sgpt/commit/c1410d169945341e9a635e12c2adcc87a08f8a09))
* update engine's cmd flag to match the new cli layout ([#400](https://github.com/k8sgpt-ai/k8sgpt/issues/400)) ([aafe669](https://github.com/k8sgpt-ai/k8sgpt/commit/aafe669739aa8c38611d13deb08706096c7893e0))
### Other
* gofmt fix and enable in CI ([#414](https://github.com/k8sgpt-ai/k8sgpt/issues/414)) ([e66de8c](https://github.com/k8sgpt-ai/k8sgpt/commit/e66de8c4cea1213cda1db609f07cbb0c8f6591c3))
* make go-lint happy ([#405](https://github.com/k8sgpt-ai/k8sgpt/issues/405)) ([ed73485](https://github.com/k8sgpt-ai/k8sgpt/commit/ed73485d92af0329915633d51c7eccdbce9b37cc))
## [0.3.0](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.2.9...v0.3.0) (2023-05-09)

View File

@@ -54,7 +54,7 @@ all: tidy add-copyright lint cover build
build:
@echo "$(shell go version)"
@echo "===========> Building binary $(BUILDAPP) *[Git Info]: $(VERSION)-$(GIT_COMMIT)"
@export CGO_ENABLED=0 && go build -o $(BUILDAPP) -ldflags '-s -w' $(BUILDFILE)
@export CGO_ENABLED=0 && go build -o $(BUILDAPP) -ldflags "-s -w -X main.version=dev -X main.commit=$$(git rev-parse --short HEAD) -X main.date=$$(date +%FT%TZ)" $(BUILDFILE)
## tidy: tidy go.mod
.PHONY: tidy

161
README.md
View File

@@ -16,6 +16,8 @@ It has SRE experience codified into its analyzers and helps to pull out the most
<a href="https://www.producthunt.com/posts/k8sgpt?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-k8sgpt" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=389489&theme=light" alt="K8sGPT - K8sGPT&#0032;gives&#0032;Kubernetes&#0032;Superpowers&#0032;to&#0032;everyone | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<img src="images/demo4.gif" width=650px; />
# CLI Installation
@@ -32,7 +34,7 @@ brew install k8sgpt
**32 bit:**
<!---x-release-please-start-version-->
```
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.0/k8sgpt_386.rpm
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.6/k8sgpt_386.rpm
sudo rpm -ivh k8sgpt_386.rpm
```
<!---x-release-please-end-->
@@ -41,7 +43,7 @@ brew install k8sgpt
<!---x-release-please-start-version-->
```
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.0/k8sgpt_amd64.rpm
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.6/k8sgpt_amd64.rpm
sudo rpm -ivh -i k8sgpt_amd64.rpm
```
<!---x-release-please-end-->
@@ -53,7 +55,7 @@ brew install k8sgpt
**32 bit:**
<!---x-release-please-start-version-->
```
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.0/k8sgpt_386.deb
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.6/k8sgpt_386.deb
sudo dpkg -i k8sgpt_386.deb
```
<!---x-release-please-end-->
@@ -61,7 +63,7 @@ brew install k8sgpt
<!---x-release-please-start-version-->
```
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.0/k8sgpt_amd64.deb
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.6/k8sgpt_amd64.deb
sudo dpkg -i k8sgpt_amd64.deb
```
<!---x-release-please-end-->
@@ -74,14 +76,14 @@ brew install k8sgpt
**32 bit:**
<!---x-release-please-start-version-->
```
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.0/k8sgpt_386.apk
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.6/k8sgpt_386.apk
apk add k8sgpt_386.apk
```
<!---x-release-please-end-->
**64 bit:**
<!---x-release-please-start-version-->
```
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.0/k8sgpt_amd64.apk
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.6/k8sgpt_amd64.apk
apk add k8sgpt_amd64.apk
```
<!---x-release-please-end-->x
@@ -121,13 +123,12 @@ _This mode of operation is ideal for continuous monitoring of your cluster and c
* Currently the default AI provider is OpenAI, you will need to generate an API key from [OpenAI](https://openai.com)
* You can do this by running `k8sgpt generate` to open a browser link to generate it
* Run `k8sgpt auth new` to set it in k8sgpt.
* Run `k8sgpt auth add` to set it in k8sgpt.
* You can provide the password directly using the `--password` flag.
* Run `k8sgpt filters` to manage the active filters used by the analyzer. By default, all filters are executed during analysis.
* Run `k8sgpt analyze` to run a scan.
* And use `k8sgpt analyze --explain` to get a more detailed explanation of the issues.
<img src="images/demo4.gif" width=650px; />
* You also run `k8sgpt analyze --with-doc` (with or without the explain flag) to get the official documention from kubernetes.
## Analyzers
@@ -161,8 +162,9 @@ _Run a scan with the default analyzers_
```
k8sgpt generate
k8sgpt auth new
k8sgpt auth add
k8sgpt analyze --explain
k8sgpt analyze --explain --with-doc
```
_Filter on resource_
@@ -188,8 +190,8 @@ _Anonymize during explain_
k8sgpt analyze --explain --filter=Service --output=json --anonymize
```
### Using filters
<details>
<summary> Using filters </summary>
_List filters_
@@ -221,17 +223,21 @@ k8sgpt filters remove [filter(s)]
</details>
### Additional commands
<details>
<summary> Additional commands </summary>
_List configured backends_
```
k8sgpt auth list
```
_Remove configured backends_
```
k8sgpt auth remove $MY_BACKEND1,$MY_BACKEND2..
```
_List integrations_
```
@@ -269,33 +275,14 @@ curl -X GET "http://localhost:8080/analyze?namespace=k8sgpt&explain=false"
```
</details>
## Additional AI providers
### Azure OpenAI
<em>Prerequisites:</em> an Azure OpenAI deployment is needed, please visit MS official [documentation](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource) to create your own.
To authenticate with k8sgpt, you will need the Azure OpenAI endpoint of your tenant `"https://your Azure OpenAI Endpoint"`, the api key to access your deployment, the deployment name of your model and the model name itself.
<details>
### Run k8sgpt
To run k8sgpt, run `k8sgpt auth` with the `azureopenai` backend:
```
k8sgpt auth --backend azureopenai --baseurl https://<your Azure OpenAI endpoint> --engine <deployment_name> --model <model_name>
```
Lastly, enter your Azure API key, after the prompt.
Now you are ready to analyze with the azure openai backend:
```
k8sgpt analyze --explain --backend azureopenai
```
</details>
### Running local models
To run local models, it is possible to use OpenAI compatible APIs, for instance [LocalAI](https://github.com/go-skynet/LocalAI) which uses [llama.cpp](https://github.com/ggerganov/llama.cpp) and [ggml](https://github.com/ggerganov/ggml) to run inference on consumer-grade hardware. Models supported by LocalAI for instance are Vicuna, Alpaca, LLaMA, Cerebras, GPT4ALL, GPT4ALL-J and koala.
## Key Features
<details>
<summary> LocalAI provider </summary>
To run local models, it is possible to use OpenAI compatible APIs, for instance [LocalAI](https://github.com/go-skynet/LocalAI) which uses [llama.cpp](https://github.com/ggerganov/llama.cpp) and [ggml](https://github.com/ggerganov/ggml) to run inference on consumer-grade hardware. Models supported by LocalAI for instance are Vicuna, Alpaca, LLaMA, Cerebras, GPT4ALL, GPT4ALL-J and koala.
To run local inference, you need to download the models first, for instance you can find `ggml` compatible models in [huggingface.com](https://huggingface.co/models?search=ggml) (for example vicuna, alpaca and koala).
@@ -317,14 +304,69 @@ Now you can analyze with the `localai` backend:
k8sgpt analyze --explain --backend localai
```
</details>
</details>
## How does anonymization work?
<details>
<summary> AzureOpenAI provider </summary>
<em>Prerequisites:</em> an Azure OpenAI deployment is needed, please visit MS official [documentation](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource) to create your own.
To authenticate with k8sgpt, you will need the Azure OpenAI endpoint of your tenant `"https://your Azure OpenAI Endpoint"`, the api key to access your deployment, the deployment name of your model and the model name itself.
To run k8sgpt, run `k8sgpt auth` with the `azureopenai` backend:
```
k8sgpt auth add --backend azureopenai --baseurl https://<your Azure OpenAI endpoint> --engine <deployment_name> --model <model_name>
```
Lastly, enter your Azure API key, after the prompt.
Now you are ready to analyze with the azure openai backend:
```
k8sgpt analyze --explain --backend azureopenai
```
</details>
<details>
<summary>Setting a new default AI provider</summary>
There may be scenarios where you wish to have K8sGPT plugged into several default AI providers. In this case you may wish to use one as a new default, other than OpenAI which is the project default.
_To view available providers_
```
k8sgpt auth list
Default:
> openai
Active:
> openai
> azureopenai
Unused:
> localai
> noopai
```
_To set a new default provider_
```
k8sgpt auth default -p azureopenai
Default provider set to azureopenai
```
</details>
With this option, the data is anonymized before being sent to the AI Backend. During the analysis execution, `k8sgpt` retrieves sensitive data (Kubernetes object names, labels, etc.). This data is masked when sent to the AI backend and replaced by a key that can be used to de-anonymize the data when the solution is returned to the user.
<details>
With this option, the data is anonymized before being sent to the AI Backend. During the analysis execution, `k8sgpt` retrieves sensitive data (Kubernetes object names, labels, etc.). This data is masked when sent to the AI backend and replaced by a key that can be used to de-anonymize the data when the solution is returned to the user.
<summary> Anonymization </summary>
1. Error reported during analysis:
```bash
Error: HorizontalPodAutoscaler uses StatefulSet/fake-deployment as ScaleTargetRef which does not exist.
@@ -349,19 +391,50 @@ The Kubernetes system is trying to scale a StatefulSet named fake-deployment usi
</details>
## Configuration
<details>
<summary> Configuration management</summary>
`k8sgpt` stores config data in the `$XDG_CONFIG_HOME/k8sgpt/k8sgpt.yaml` file. The data is stored in plain text, including your OpenAI key.
Config file locations:
| OS | Path |
|---------|--------------------------------------------------|
| ------- | ------------------------------------------------ |
| MacOS | ~/Library/Application Support/k8sgpt/k8sgpt.yaml |
| Linux | ~/.config/k8sgpt/k8sgpt.yaml |
| Windows | %LOCALAPPDATA%/k8sgpt/k8sgpt.yaml |
</details>
<details>
There may be scenarios where caching remotely is prefered.
In these scenarios K8sGPT supports AWS S3 Integration.
<summary> Remote caching </summary>
_As a prerequisite `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` are required as environmental variables._
_Adding a remote cache_
Note: this will create the bucket if it does not exist
```
k8sgpt cache add --region <aws region> --bucket <name>
```
_Listing cache items_
```
k8sgpt cache list
```
_Removing the remote cache_
Note: this will not delete the bucket
```
k8sgpt cache remove --bucket <name>
```
</details>
## Documentation
Find our official documentation available [here](https://docs.k8sgpt.ai)
## Contributing
Please read our [contributing guide](./CONTRIBUTING.md).

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: v0.2.4 #x-release-please-version
appVersion: v0.3.0 #x-release-please-version
description: A Helm chart for K8SGPT
name: k8sgpt
type: application

View File

@@ -21,7 +21,7 @@ spec:
app.kubernetes.io/name: {{ include "k8sgpt.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
serviceAccountName: k8sgpt
serviceAccountName: {{ template "k8sgpt.fullname" . }}
containers:
- name: k8sgpt-container
imagePullPolicy: {{ .Values.deployment.imagePullPolicy }}

View File

@@ -11,5 +11,5 @@ subjects:
namespace: {{ .Release.Namespace | quote }}
roleRef:
kind: ClusterRole
name: k8sgpt-cluster-role-all
name: {{ template "k8sgpt.fullname" . }}
apiGroup: rbac.authorization.k8s.io

View File

@@ -16,4 +16,7 @@ spec:
- name: http
port: 8080
targetPort: 8080
- name: metrics
port: 8081
targetPort: 8081
type: {{ .Values.service.type }}

View File

@@ -13,7 +13,7 @@ spec:
endpoints:
- honorLabels: true
path: /metrics
port: http
port: metrics
selector:
matchLabels:
app.kubernetes.io/name: {{ include "k8sgpt.name" . }}

View File

@@ -32,6 +32,7 @@ var (
namespace string
anonymize bool
maxConcurrency int
withDoc bool
)
// AnalyzeCmd represents the problems command
@@ -45,7 +46,7 @@ var AnalyzeCmd = &cobra.Command{
// AnalysisResult configuration
config, err := analysis.NewAnalysis(backend,
language, filters, namespace, nocache, explain, maxConcurrency)
language, filters, namespace, nocache, explain, maxConcurrency, withDoc)
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
@@ -91,4 +92,6 @@ func init() {
AnalyzeCmd.Flags().StringVarP(&language, "language", "l", "english", "Languages to use for AI (e.g. 'English', 'Spanish', 'French', 'German', 'Italian', 'Portuguese', 'Dutch', 'Russian', 'Chinese', 'Japanese', 'Korean')")
// add max concurrency
AnalyzeCmd.Flags().IntVarP(&maxConcurrency, "max-concurrency", "m", 10, "Maximum number of concurrent requests to the Kubernetes API server")
// kubernetes doc flag
AnalyzeCmd.Flags().BoolVarP(&withDoc, "with-doc", "d", false, "Give me the official documentation of the involved field")
}

View File

@@ -26,15 +26,15 @@ import (
"golang.org/x/term"
)
var newCmd = &cobra.Command{
Use: "new",
var addCmd = &cobra.Command{
Use: "add",
Short: "Configure new provider",
Long: "The new command allows to configure a new backend AI provider",
PreRun: func(cmd *cobra.Command, args []string) {
backend, _ := cmd.Flags().GetString("backend")
if strings.ToLower(backend) == "azureopenai" {
cmd.MarkFlagRequired("engine")
cmd.MarkFlagRequired("baseurl")
_ = cmd.MarkFlagRequired("engine")
_ = cmd.MarkFlagRequired("baseurl")
}
},
Run: func(cmd *cobra.Command, args []string) {
@@ -107,20 +107,20 @@ var newCmd = &cobra.Command{
color.Green("%s added to the AI backend provider list", backend)
} else {
// provider with same name exists, update provider info
color.Yellow("Provider with same name already exists, use update command to modify an existing provider configuration")
color.Yellow("Provider with same name already exists.")
}
},
}
func init() {
// add flag for backend
newCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
addCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
// add flag for model
newCmd.Flags().StringVarP(&model, "model", "m", "gpt-3.5-turbo", "Backend AI model")
addCmd.Flags().StringVarP(&model, "model", "m", "gpt-3.5-turbo", "Backend AI model")
// add flag for password
newCmd.Flags().StringVarP(&password, "password", "p", "", "Backend AI password")
addCmd.Flags().StringVarP(&password, "password", "p", "", "Backend AI password")
// add flag for url
newCmd.Flags().StringVarP(&baseURL, "baseurl", "u", "", "URL AI provider, (e.g `http://localhost:8080/v1`)")
addCmd.Flags().StringVarP(&baseURL, "baseurl", "u", "", "URL AI provider, (e.g `http://localhost:8080/v1`)")
// add flag for azure open ai engine/deployment name
AuthCmd.Flags().StringVarP(&engine, "engine", "e", "", "Azure AI deployment name")
addCmd.Flags().StringVarP(&engine, "engine", "e", "", "Azure AI deployment name")
}

View File

@@ -35,7 +35,7 @@ var AuthCmd = &cobra.Command{
Long: `Provide the necessary credentials to authenticate with your chosen backend.`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
cmd.Help()
_ = cmd.Help()
return
}
},
@@ -45,5 +45,9 @@ func init() {
// add subcommand to list backends
AuthCmd.AddCommand(listCmd)
// add subcommand to create new backend provider
AuthCmd.AddCommand(newCmd)
AuthCmd.AddCommand(addCmd)
// add subcommand to remove new backend provider
AuthCmd.AddCommand(removeCmd)
// add subcommand to set default backend provider
AuthCmd.AddCommand(defaultCmd)
}

79
cmd/auth/default.go Normal file
View File

@@ -0,0 +1,79 @@
/*
Copyright 2023 The K8sGPT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package auth
import (
"os"
"strings"
"github.com/fatih/color"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
providerName string
)
var defaultCmd = &cobra.Command{
Use: "default",
Short: "Set your default AI backend provider",
Long: "The command to set your new default AI backend provider (default is openai)",
Run: func(cmd *cobra.Command, args []string) {
err := viper.UnmarshalKey("ai", &configAI)
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
if providerName == "" {
if configAI.DefaultProvider != "" {
color.Yellow("Your default provider is %s", configAI.DefaultProvider)
} else {
color.Yellow("Your default provider is openai")
}
os.Exit(0)
}
// lowercase the provider name
providerName = strings.ToLower(providerName)
// Check if the provider is in the provider list
providerExists := false
for _, provider := range configAI.Providers {
if provider.Name == providerName {
providerExists = true
}
}
if !providerExists {
color.Red("Error: Provider %s does not exist", providerName)
os.Exit(1)
}
// Set the default provider
configAI.DefaultProvider = providerName
viper.Set("ai", configAI)
// Viper write config
err = viper.WriteConfig()
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
// Print acknowledgement
color.Green("Default provider set to %s", providerName)
},
}
func init() {
// provider name flag
defaultCmd.Flags().StringVarP(&providerName, "provider", "p", "", "The name of the provider to set as default")
}

View File

@@ -18,6 +18,7 @@ import (
"os"
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@@ -35,12 +36,37 @@ var listCmd = &cobra.Command{
os.Exit(1)
}
// iterate over the provider list and prints each provider name
for _, provider := range configAI.Providers {
if len(configAI.Providers) == 0 {
color.Red("Provider list is currently empty.")
} else {
fmt.Printf("> %s\n", provider.Name)
// Print the default if it is set
fmt.Print(color.YellowString("Default: \n"))
if configAI.DefaultProvider != "" {
fmt.Printf("> %s\n", color.BlueString(configAI.DefaultProvider))
} else {
fmt.Printf("> %s\n", color.BlueString("openai"))
}
// Get list of all AI Backends and only print htem if they are not in the provider list
fmt.Print(color.YellowString("Active: \n"))
for _, aiBackend := range ai.Backends {
providerExists := false
for _, provider := range configAI.Providers {
if provider.Name == aiBackend {
providerExists = true
}
}
if providerExists {
fmt.Printf("> %s\n", color.GreenString(aiBackend))
}
}
fmt.Print(color.YellowString("Unused: \n"))
for _, aiBackend := range ai.Backends {
providerExists := false
for _, provider := range configAI.Providers {
if provider.Name == aiBackend {
providerExists = true
}
}
if !providerExists {
fmt.Printf("> %s\n", color.RedString(aiBackend))
}
}
},

71
cmd/auth/remove.go Normal file
View File

@@ -0,0 +1,71 @@
/*
Copyright 2023 The K8sGPT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package auth
import (
"os"
"strings"
"github.com/fatih/color"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var removeCmd = &cobra.Command{
Use: "remove [backend(s)]",
Short: "Remove a provider",
Long: "The command to remove an AI backend provider",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
inputBackends := strings.Split(args[0], ",")
err := viper.UnmarshalKey("ai", &configAI)
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
if len(inputBackends) == 0 {
color.Red("Error: backend must be set.")
os.Exit(1)
}
for _, b := range inputBackends {
foundBackend := false
for i, provider := range configAI.Providers {
if b == provider.Name {
foundBackend = true
configAI.Providers = append(configAI.Providers[:i], configAI.Providers[i+1:]...)
color.Green("%s deleted to the AI backend provider list", b)
break
}
}
if !foundBackend {
color.Red("Error: %s does not exist in configuration file. Please use k8sgpt auth new.", backend)
os.Exit(1)
}
}
viper.Set("ai", configAI)
if err := viper.WriteConfig(); err != nil {
color.Red("Error writing config file: %s", err.Error())
os.Exit(1)
}
},
}
func init() {
}

54
cmd/cache/add.go vendored Normal file
View File

@@ -0,0 +1,54 @@
/*
Copyright 2023 The K8sGPT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cache
import (
"fmt"
"os"
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
"github.com/spf13/cobra"
)
var (
region string
)
// addCmd represents the add command
var addCmd = &cobra.Command{
Use: "add",
Short: "Add a remote cache",
Long: `This command allows you to add a remote cache to store the results of an analysis.
The supported cache types are:
- S3`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(color.YellowString("Adding remote S3 based cache"))
err := cache.AddRemoteCache(bucketname, region)
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
},
}
func init() {
CacheCmd.AddCommand(addCmd)
addCmd.Flags().StringVarP(&region, "region", "r", "", "The region to use for the cache")
addCmd.Flags().StringVarP(&bucketname, "bucket", "b", "", "The name of the bucket to use for the cache")
addCmd.MarkFlagRequired("bucket")
addCmd.MarkFlagRequired("region")
}

36
cmd/cache/cache.go vendored Normal file
View File

@@ -0,0 +1,36 @@
/*
Copyright 2023 The K8sGPT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cache
import (
"github.com/spf13/cobra"
)
var (
bucketname string
)
// cacheCmd represents the cache command
var CacheCmd = &cobra.Command{
Use: "cache",
Short: "For working with the cache the results of an analysis",
Long: `Cache commands allow you to add a remote cache, list the contents of the cache, and remove items from the cache.`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
func init() {
}

55
cmd/cache/list.go vendored Normal file
View File

@@ -0,0 +1,55 @@
/*
Copyright 2023 The K8sGPT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cache
import (
"os"
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
"github.com/spf13/cobra"
)
// listCmd represents the list command
var listCmd = &cobra.Command{
Use: "list",
Short: "List the contents of the cache",
Long: `This command allows you to list the contents of the cache.`,
Run: func(cmd *cobra.Command, args []string) {
// load remote cache if it is configured
remoteCacheEnabled, err := cache.RemoteCacheEnabled()
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
c := cache.New(false, remoteCacheEnabled)
// list the contents of the cache
names, err := c.List()
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
for _, name := range names {
println(name)
}
},
}
func init() {
CacheCmd.AddCommand(listCmd)
}

43
cmd/cache/remove.go vendored Normal file
View File

@@ -0,0 +1,43 @@
/*
Copyright 2023 The K8sGPT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cache
import (
"os"
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
"github.com/spf13/cobra"
)
// removeCmd represents the remove command
var removeCmd = &cobra.Command{
Use: "remove",
Short: "Remove the remote cache",
Long: `This command allows you to remove the remote cache and use the default filecache.`,
Run: func(cmd *cobra.Command, args []string) {
err := cache.RemoveRemoteCache(bucketname)
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
color.Green("Successfully removed the remote cache")
},
}
func init() {
CacheCmd.AddCommand(removeCmd)
}

View File

@@ -25,7 +25,7 @@ var FiltersCmd = &cobra.Command{
You can list available filters to analyze resources.`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
cmd.Help()
_ = cmd.Help()
return
}
},

View File

@@ -37,7 +37,7 @@ var listCmd = &cobra.Command{
activeFilters = coreFilters
}
inactiveFilters := util.SliceDiff(availableFilters, activeFilters)
fmt.Printf(color.YellowString("Active: \n"))
fmt.Print(color.YellowString("Active: \n"))
for _, filter := range activeFilters {
// if the filter is an integration, mark this differently
@@ -50,7 +50,7 @@ var listCmd = &cobra.Command{
// display inactive filters
if len(inactiveFilters) != 0 {
fmt.Printf(color.YellowString("Unused: \n"))
fmt.Print(color.YellowString("Unused: \n"))
for _, filter := range inactiveFilters {
// if the filter is an integration, mark this differently
if util.SliceContainsString(integrationFilters, filter) {

View File

@@ -15,8 +15,10 @@ package integration
import (
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
"github.com/k8sgpt-ai/k8sgpt/pkg/integration"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// activateCmd represents the activate command
@@ -27,10 +29,17 @@ var activateCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
integrationName := args[0]
coreFilters, _, _ := analyzer.ListFilters()
// Update filters
activeFilters := viper.GetStringSlice("active_filters")
if len(activeFilters) == 0 {
activeFilters = coreFilters
}
integration := integration.NewIntegration()
// Check if the integation exists
err := integration.Activate(integrationName, namespace)
err := integration.Activate(integrationName, namespace, activeFilters)
if err != nil {
color.Red("Error: %v", err)
return

View File

@@ -32,7 +32,7 @@ var IntegrationCmd = &cobra.Command{
This would allow you to deploy trivy into your cluster and use a K8sGPT analyzer to parse trivy results.`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
_ = cmd.Help()
},
}

View File

@@ -20,6 +20,7 @@ import (
"github.com/adrg/xdg"
"github.com/k8sgpt-ai/k8sgpt/cmd/analyze"
"github.com/k8sgpt-ai/k8sgpt/cmd/auth"
"github.com/k8sgpt-ai/k8sgpt/cmd/cache"
"github.com/k8sgpt-ai/k8sgpt/cmd/filters"
"github.com/k8sgpt-ai/k8sgpt/cmd/generate"
"github.com/k8sgpt-ai/k8sgpt/cmd/integration"
@@ -33,7 +34,9 @@ var (
cfgFile string
kubecontext string
kubeconfig string
version string
Version string
Commit string
Date string
)
// rootCmd represents the base command when called without any subcommands
@@ -48,8 +51,10 @@ var rootCmd = &cobra.Command{
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute(v string) {
version = v
func Execute(v string, c string, d string) {
Version = v
Commit = c
Date = d
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
@@ -67,6 +72,7 @@ func init() {
rootCmd.AddCommand(generate.GenerateCmd)
rootCmd.AddCommand(integration.IntegrationCmd)
rootCmd.AddCommand(serve.ServeCmd)
rootCmd.AddCommand(cache.CacheCmd)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.k8sgpt.yaml)")
rootCmd.PersistentFlags().StringVar(&kubecontext, "kubecontext", "", "Kubernetes context to use. Only required if out-of-cluster.")
rootCmd.PersistentFlags().StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
@@ -85,7 +91,7 @@ func initConfig() {
viper.SetConfigType("yaml")
viper.SetConfigName("k8sgpt")
viper.SafeWriteConfig()
_ = viper.SafeWriteConfig()
}
viper.Set("kubecontext", kubecontext)
@@ -96,6 +102,7 @@ func initConfig() {
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
_ = 1
// fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
}
}

View File

@@ -14,6 +14,9 @@ limitations under the License.
package cmd
import (
"fmt"
"runtime/debug"
"github.com/spf13/cobra"
)
@@ -23,7 +26,21 @@ var versionCmd = &cobra.Command{
Short: "Print the version number of k8sgpt",
Long: `All software has versions. This is k8sgpt's`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Printf("k8sgpt version %s\n", version)
if Version == "dev" {
details, ok := debug.ReadBuildInfo()
if ok && details.Main.Version != "" && details.Main.Version != "(devel)" {
Version = details.Main.Version
for _, i := range details.Settings {
if i.Key == "vcs.time" {
Date = i.Value
}
if i.Key == "vcs.revision" {
Commit = i.Value
}
}
}
}
fmt.Printf("k8sgpt: %s (%s), built at: %s\n", Version, Commit, Date)
},
}

View File

@@ -12,7 +12,9 @@
FROM golang:1.20.4-alpine3.16 AS builder
ENV CGO_ENABLED=0
ARG VERSION
ARG COMMIT
ARG DATE
WORKDIR /workspace
COPY go.mod go.sum ./
@@ -20,7 +22,7 @@ RUN go mod download
COPY ./ ./
RUN go build -o /workspace/k8sgpt ./
RUN go build -o /workspace/k8sgpt -ldflags "-X main.version=${VERSION} -X main.commit=${COMMIT} -X main.date=${DATE}" ./
FROM gcr.io/distroless/static AS production

53
go.mod
View File

@@ -10,24 +10,27 @@ require (
github.com/sashabaranov/go-openai v1.9.3
github.com/schollz/progressbar/v3 v3.13.1
github.com/spf13/cobra v1.7.0
github.com/spf13/viper v1.15.0
github.com/stretchr/testify v1.8.2
github.com/spf13/viper v1.16.0
github.com/stretchr/testify v1.8.4
golang.org/x/term v0.8.0
helm.sh/helm/v3 v3.11.3
k8s.io/api v0.26.3
k8s.io/apimachinery v0.26.3
k8s.io/client-go v0.26.3
k8s.io/kubectl v0.26.3
helm.sh/helm/v3 v3.12.0
k8s.io/api v0.27.2
k8s.io/apimachinery v0.27.2
k8s.io/client-go v0.27.2
k8s.io/kubectl v0.27.2
)
require github.com/adrg/xdg v0.4.0
require (
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230506120742-576a6b5d0a86.1
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230506120742-576a6b5d0a86.4
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230524215339-41d88e13ab7e.1
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230524215339-41d88e13ab7e.1
github.com/aws/aws-sdk-go v1.44.272
)
require github.com/jmespath/go-jmespath v0.4.0 // indirect
require (
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
@@ -51,7 +54,7 @@ require (
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/cli v23.0.1+incompatible // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker v23.0.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-connections v0.4.0 // indirect
@@ -72,7 +75,7 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/gnostic v0.6.9
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-containerregistry v0.14.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
@@ -116,7 +119,7 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221020182949-4df8887994e8 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -133,7 +136,7 @@ require (
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spdx/tools-golang v0.5.0 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
@@ -147,34 +150,34 @@ require (
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/exp v0.0.0-20230124195608-d38c7dcee874 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/oauth2 v0.6.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/oauth2 v0.7.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
google.golang.org/grpc v1.54.0
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/grpc v1.55.0
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.26.3 // indirect
k8s.io/apiserver v0.26.3 // indirect
k8s.io/cli-runtime v0.26.3 // indirect
k8s.io/component-base v0.26.3 // indirect
k8s.io/apiextensions-apiserver v0.27.1 // indirect
k8s.io/apiserver v0.27.1 // indirect
k8s.io/cli-runtime v0.27.2 // indirect
k8s.io/component-base v0.27.2 // indirect
k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/kube-openapi v0.0.0-20230327201221-f5883ff37f0c // indirect
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 // indirect
oras.land/oras-go v1.2.2 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.12.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
sigs.k8s.io/kustomize/api v0.13.2 // indirect
sigs.k8s.io/kustomize/kyaml v0.14.1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

121
go.sum
View File

@@ -1,15 +1,8 @@
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230506115609-2cf6f3269635.1 h1:QN50zglrtchNsA7YKGVXvhFcHRvw84i86ZLagoDP6U4=
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230506115609-2cf6f3269635.1/go.mod h1:lPYoX6uv+XnBf4npolYcDpolT5+rM+IBVnzHHprO2Po=
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230506120135-8ee60a29e03a.1 h1:P40VwyJpUzF+me+Pf+9/aDb7/fAWIA1OPRBtbTA0CVA=
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230506120135-8ee60a29e03a.1/go.mod h1:hbOU1p8GDAMVEbOw5YBzpe9HGh0jMtHmYq44bgSDgDw=
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230506120742-576a6b5d0a86.1 h1:PQaEhu0fgP6BP2WciRwe9ol9ChEyO7U/lCiHYlwYxRM=
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230506120742-576a6b5d0a86.1/go.mod h1:hNUyDnPCFDSlQTEVED8xxZV0WXRcElFSM+LLLbP7zCQ=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230506115609-2cf6f3269635.4 h1:EP+wmi8br4EhVa8yhHqC2qi8RKiujuUsh1iUAwniSSo=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230506115609-2cf6f3269635.4/go.mod h1:i/s4ALHwKvjA1oGNKpoHg0FpEOTbufoOm/NdTE6YQAE=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230506120135-8ee60a29e03a.4 h1:2iaFkq6TNqUKiq0oHLHXqJoKdc2TMvXysaVZY6lwDBE=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230506120135-8ee60a29e03a.4/go.mod h1:i/s4ALHwKvjA1oGNKpoHg0FpEOTbufoOm/NdTE6YQAE=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230506120742-576a6b5d0a86.4 h1:PLlTZWSEBwnyxRYL0m6+RJH8z8c0Q8LZFw6BqNX1TEo=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230506120742-576a6b5d0a86.4/go.mod h1:i/s4ALHwKvjA1oGNKpoHg0FpEOTbufoOm/NdTE6YQAE=
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230524215339-41d88e13ab7e.1 h1:lvzkvTlk64ZKgqBlyI6wTkRcOCRwERbgvNNC739L2uw=
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230524215339-41d88e13ab7e.1/go.mod h1:gVjoI6SASls1kiAjJWFIYrT6midpN8pAT82q2EEVbGY=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230524215339-41d88e13ab7e.4/go.mod h1:i/s4ALHwKvjA1oGNKpoHg0FpEOTbufoOm/NdTE6YQAE=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230524215339-41d88e13ab7e.1 h1:Mx0Z+cXHStOU4lkemYYGhvNd40aU9g52sfS2W7D/gzA=
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230524215339-41d88e13ab7e.1/go.mod h1:karV92RruD5davytOQq20lDyAqBnai8ajNolo98nu94=
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=
@@ -457,6 +450,8 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.44.272 h1:cP7BaZCz1a4P80vOxi8OVma8ZcxZNDYyuyU5/bojU+Y=
github.com/aws/aws-sdk-go v1.44.272/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -522,8 +517,8 @@ github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aB
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM=
github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho=
github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
@@ -537,7 +532,6 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE=
github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
@@ -565,8 +559,9 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
@@ -784,6 +779,10 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
@@ -875,6 +874,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
@@ -937,8 +937,8 @@ github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 h1:DiL
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
@@ -1032,8 +1032,9 @@ github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
@@ -1046,8 +1047,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA=
github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -1063,8 +1064,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
@@ -1119,7 +1121,7 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -1145,8 +1147,8 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1245,10 +1247,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1276,8 +1279,8 @@ golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri
golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1376,6 +1379,7 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1384,6 +1388,7 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
@@ -1654,8 +1659,8 @@ google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZV
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE=
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1695,8 +1700,8 @@ google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -1745,8 +1750,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
helm.sh/helm/v3 v3.11.3 h1:n1X5yaQTP5DYywlBOZMl2gX398Gp6YwFp/IAVj6+5D4=
helm.sh/helm/v3 v3.11.3/go.mod h1:S+sOdQc3BLvt09a9rSlKKVs9x0N/yx+No0y3qFw+FQ8=
helm.sh/helm/v3 v3.12.0 h1:rOq2TPVzg5jt4q5ermAZGZFxNW2uQhKjRhBneAutMEM=
helm.sh/helm/v3 v3.12.0/go.mod h1:8K/469yxjUMu6BaD2EagCitkPjELUL/l2AgCO142G94=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -1754,26 +1759,26 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU=
k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE=
k8s.io/apiextensions-apiserver v0.26.3 h1:5PGMm3oEzdB1W/FTMgGIDmm100vn7IaUP5er36dB+YE=
k8s.io/apiextensions-apiserver v0.26.3/go.mod h1:jdA5MdjNWGP+njw1EKMZc64xAT5fIhN6VJrElV3sfpQ=
k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k=
k8s.io/apimachinery v0.26.3/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I=
k8s.io/apiserver v0.26.3 h1:blBpv+yOiozkPH2aqClhJmJY+rp53Tgfac4SKPDJnU4=
k8s.io/apiserver v0.26.3/go.mod h1:CJe/VoQNcXdhm67EvaVjYXxR3QyfwpceKPuPaeLibTA=
k8s.io/cli-runtime v0.26.3 h1:3ULe0oI28xmgeLMVXIstB+ZL5CTGvWSMVMLeHxitIuc=
k8s.io/cli-runtime v0.26.3/go.mod h1:5YEhXLV4kLt/OSy9yQwtSSNZU2Z7aTEYta1A+Jg4VC4=
k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s=
k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ=
k8s.io/component-base v0.26.3 h1:oC0WMK/ggcbGDTkdcqefI4wIZRYdK3JySx9/HADpV0g=
k8s.io/component-base v0.26.3/go.mod h1:5kj1kZYwSC6ZstHJN7oHBqcJC6yyn41eR+Sqa/mQc8E=
k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo=
k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4=
k8s.io/apiextensions-apiserver v0.27.1 h1:Hp7B3KxKHBZ/FxmVFVpaDiXI6CCSr49P1OJjxKO6o4g=
k8s.io/apiextensions-apiserver v0.27.1/go.mod h1:8jEvRDtKjVtWmdkhOqE84EcNWJt/uwF8PC4627UZghY=
k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg=
k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
k8s.io/apiserver v0.27.1 h1:phY+BtXjjzd+ta3a4kYbomC81azQSLa1K8jo9RBw7Lg=
k8s.io/apiserver v0.27.1/go.mod h1:UGrOjLY2KsieA9Fw6lLiTObxTb8Z1xEba4uqSuMY0WU=
k8s.io/cli-runtime v0.27.2 h1:9HI8gfReNujKXt16tGOAnb8b4NZ5E+e0mQQHKhFGwYw=
k8s.io/cli-runtime v0.27.2/go.mod h1:9UecpyPDTkhiYY4d9htzRqN+rKomJgyb4wi0OfrmCjw=
k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE=
k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ=
k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo=
k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo=
k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20230327201221-f5883ff37f0c h1:EFfsozyzZ/pggw5qNx7ftTVZdp7WZl+3ih89GEjYEK8=
k8s.io/kube-openapi v0.0.0-20230327201221-f5883ff37f0c/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
k8s.io/kubectl v0.26.3 h1:bZ5SgFyeEXw6XTc1Qji0iNdtqAC76lmeIIQULg2wNXM=
k8s.io/kubectl v0.26.3/go.mod h1:02+gv7Qn4dupzN3fi/9OvqqdW+uG/4Zi56vc4Zmsp1g=
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
k8s.io/kubectl v0.27.2 h1:sSBM2j94MHBFRWfHIWtEXWCicViQzZsb177rNsKBhZg=
k8s.io/kubectl v0.27.2/go.mod h1:GCOODtxPcrjh+EC611MqREkU8RjYBh10ldQCQ6zpFKw=
k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 h1:xMMXJlJbsU8w3V5N2FLDQ8YgU8s1EoULdbQBcAeNJkY=
k8s.io/utils v0.0.0-20230313181309-38a27ef9d749/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
oras.land/oras-go v1.2.3 h1:v8PJl+gEAntI1pJ/LCrDgsuk+1PKVavVEPsYIHFE5uY=
@@ -1783,10 +1788,10 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=
sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4=
sigs.k8s.io/kustomize/api v0.13.2 h1:kejWfLeJhUsTGioDoFNJET5LQe/ajzXhJGYoU+pJsiA=
sigs.k8s.io/kustomize/api v0.13.2/go.mod h1:DUp325VVMFVcQSq+ZxyDisA8wtldwHxLZbr1g94UHsw=
sigs.k8s.io/kustomize/kyaml v0.14.1 h1:c8iibius7l24G2wVAGZn/Va2wNys03GXLjYVIcFVxKA=
sigs.k8s.io/kustomize/kyaml v0.14.1/go.mod h1:AN1/IpawKilWD7V+YvQwRGUvuUOOWpjsHu6uHwonSF4=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=

View File

@@ -15,8 +15,12 @@ package main
import "github.com/k8sgpt-ai/k8sgpt/cmd"
var version = "dev"
var (
version = "dev"
commit = "HEAD"
date = "unknown"
)
func main() {
cmd.Execute(version)
cmd.Execute(version, commit, date)
}

View File

@@ -59,7 +59,8 @@ func NewClient(provider string) IAI {
}
type AIConfiguration struct {
Providers []AIProvider `mapstructure:"providers"`
Providers []AIProvider `mapstructure:"providers"`
DefaultProvider string `mapstructure:"defaultprovider"`
}
type AIProvider struct {

View File

@@ -57,7 +57,7 @@ func (a *NoOpAIClient) Parse(ctx context.Context, prompt []string, cache cache.I
return "", err
}
err = cache.Store(cacheKey, base64.StdEncoding.EncodeToString([]byte(response)))
err = cache.Store(cacheKey, base64.StdEncoding.EncodeToString([]byte(response)))
if err != nil {
color.Red("error storing value to cache: %v", err)

View File

@@ -1,5 +1,9 @@
package ai
const (
default_prompt = "Simplify the following Kubernetes error message and provide a solution in %s: %s"
default_prompt = `Simplify the following Kubernetes error message delimited by triple dashes written in --- %s --- language; --- %s ---.
Provide the most possible solution in a step by step style in no more than 280 characters. Write the output in the following format:
Error: {Explain error here}
Solution: {Step by step solution here}
`
)

View File

@@ -23,6 +23,7 @@ import (
"sync"
"github.com/fatih/color"
openapi_v2 "github.com/google/gnostic/openapiv2"
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
@@ -34,16 +35,18 @@ import (
)
type Analysis struct {
Context context.Context
Filters []string
Client *kubernetes.Client
AIClient ai.IAI
Results []common.Result
Errors []string
Namespace string
Cache cache.ICache
Explain bool
MaxConcurrency int
Context context.Context
Filters []string
Client *kubernetes.Client
AIClient ai.IAI
Results []common.Result
Errors []string
Namespace string
Cache cache.ICache
Explain bool
MaxConcurrency int
AnalysisAIProvider string // The name of the AI Provider used for this analysis
WithDoc bool
}
type AnalysisStatus string
@@ -55,13 +58,14 @@ const (
)
type JsonOutput struct {
Provider string `json:"provider"`
Errors AnalysisErrors `json:"errors"`
Status AnalysisStatus `json:"status"`
Problems int `json:"problems"`
Results []common.Result `json:"results"`
}
func NewAnalysis(backend string, language string, filters []string, namespace string, noCache bool, explain bool, maxConcurrency int) (*Analysis, error) {
func NewAnalysis(backend string, language string, filters []string, namespace string, noCache bool, explain bool, maxConcurrency int, withDoc bool) (*Analysis, error) {
var configAI ai.AIConfiguration
err := viper.UnmarshalKey("ai", &configAI)
if err != nil {
@@ -74,6 +78,12 @@ func NewAnalysis(backend string, language string, filters []string, namespace st
os.Exit(1)
}
// Backend string will have high priority than a default provider
// Backend as "openai" represents the default CLI argument passed through
if configAI.DefaultProvider != "" && backend == "openai" {
backend = configAI.DefaultProvider
}
var aiProvider ai.AIProvider
for _, provider := range configAI.Providers {
if backend == provider.Name {
@@ -104,36 +114,56 @@ func NewAnalysis(backend string, language string, filters []string, namespace st
return nil, err
}
// load remote cache if it is configured
remoteCacheEnabled, err := cache.RemoteCacheEnabled()
if err != nil {
return nil, err
}
return &Analysis{
Context: ctx,
Filters: filters,
Client: client,
AIClient: aiClient,
Namespace: namespace,
Cache: cache.New(noCache),
Explain: explain,
MaxConcurrency: maxConcurrency,
Context: ctx,
Filters: filters,
Client: client,
AIClient: aiClient,
Namespace: namespace,
Cache: cache.New(noCache, remoteCacheEnabled),
Explain: explain,
MaxConcurrency: maxConcurrency,
AnalysisAIProvider: backend,
WithDoc: withDoc,
}, nil
}
func (a *Analysis) RunAnalysis() {
activeFilters := viper.GetStringSlice("active_filters")
analyzerMap := analyzer.GetAnalyzerMap()
coreAnalyzerMap, analyzerMap := analyzer.GetAnalyzerMap()
// we get the openapi schema from the server only if required by the flag "with-doc"
openapiSchema := &openapi_v2.Document{}
if a.WithDoc {
var openApiErr error
openapiSchema, openApiErr = a.Client.Client.Discovery().OpenAPISchema()
if openApiErr != nil {
a.Errors = append(a.Errors, fmt.Sprintf("[KubernetesDoc] %s", openApiErr))
}
}
analyzerConfig := common.Analyzer{
Client: a.Client,
Context: a.Context,
Namespace: a.Namespace,
AIClient: a.AIClient,
Client: a.Client,
Context: a.Context,
Namespace: a.Namespace,
AIClient: a.AIClient,
OpenapiSchema: openapiSchema,
}
semaphore := make(chan struct{}, a.MaxConcurrency)
// if there are no filters selected and no active_filters then run all of them
// if there are no filters selected and no active_filters then run coreAnalyzer
if len(a.Filters) == 0 && len(activeFilters) == 0 {
var wg sync.WaitGroup
var mutex sync.Mutex
for _, analyzer := range analyzerMap {
for _, analyzer := range coreAnalyzerMap {
wg.Add(1)
semaphore <- struct{}{}
go func(analyzer common.IAnalyzer, wg *sync.WaitGroup, semaphore chan struct{}) {
@@ -141,7 +171,7 @@ func (a *Analysis) RunAnalysis() {
results, err := analyzer.Analyze(analyzerConfig)
if err != nil {
mutex.Lock()
a.Errors = append(a.Errors, fmt.Sprintf(fmt.Sprintf("[%s] %s", reflect.TypeOf(analyzer).Name(), err)))
a.Errors = append(a.Errors, fmt.Sprintf("[%s] %s", reflect.TypeOf(analyzer).Name(), err))
mutex.Unlock()
}
mutex.Lock()
@@ -152,6 +182,7 @@ func (a *Analysis) RunAnalysis() {
}
wg.Wait()
return
}
semaphore = make(chan struct{}, a.MaxConcurrency)
// if the filters flag is specified
@@ -167,7 +198,7 @@ func (a *Analysis) RunAnalysis() {
results, err := analyzer.Analyze(analyzerConfig)
if err != nil {
mutex.Lock()
a.Errors = append(a.Errors, fmt.Sprintf(fmt.Sprintf("[%s] %s", filter, err)))
a.Errors = append(a.Errors, fmt.Sprintf("[%s] %s", filter, err))
mutex.Unlock()
}
mutex.Lock()
@@ -176,10 +207,11 @@ func (a *Analysis) RunAnalysis() {
<-semaphore
}(analyzer, filter)
} else {
a.Errors = append(a.Errors, fmt.Sprintf(fmt.Sprintf("\"%s\" filter does not exist. Please run k8sgpt filters list.", filter)))
a.Errors = append(a.Errors, fmt.Sprintf("\"%s\" filter does not exist. Please run k8sgpt filters list.", filter))
}
}
wg.Wait()
return
}
var wg sync.WaitGroup
@@ -234,7 +266,7 @@ func (a *Analysis) GetAIResults(output string, anonymize bool) error {
// FIXME: can we avoid checking if output is json multiple times?
// maybe implement the progress bar better?
if output != "json" {
bar.Exit()
_ = bar.Exit()
}
// Check for exhaustion
@@ -255,7 +287,7 @@ func (a *Analysis) GetAIResults(output string, anonymize bool) error {
analysis.Details = parsedText
if output != "json" {
bar.Add(1)
_ = bar.Add(1)
}
a.Results[index] = analysis
}

View File

@@ -14,14 +14,127 @@ limitations under the License.
package analysis
import (
"context"
"encoding/json"
"fmt"
"testing"
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/magiconair/properties/assert"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
v1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"strings"
"testing"
)
// sub-function
func analysis_RunAnalysisFilterTester(t *testing.T, filterFlag string) []common.Result {
clientset := fake.NewSimpleClientset(
&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "default",
},
Status: v1.PodStatus{
Phase: v1.PodPending,
Conditions: []v1.PodCondition{
{
Type: v1.PodScheduled,
Reason: "Unschedulable",
Message: "0/1 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate.",
},
},
},
},
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "default",
Annotations: map[string]string{},
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "default",
Annotations: map[string]string{},
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app": "example",
},
},
},
&networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "default",
Annotations: map[string]string{},
},
},
)
analysis := Analysis{
Context: context.Background(),
Results: []common.Result{},
Namespace: "default",
MaxConcurrency: 1,
Client: &kubernetes.Client{
Client: clientset,
},
}
if len(filterFlag) > 0 {
// `--filter` is explicitly given
analysis.Filters = strings.Split(filterFlag, ",")
}
analysis.RunAnalysis()
return analysis.Results
}
// Test: Filter logic with running different Analyzers
func TestAnalysis_RunAnalysisWithFilter(t *testing.T) {
var results []common.Result
var filterFlag string
//1. Neither --filter flag Nor active filter is specified, only the "core analyzers"
results = analysis_RunAnalysisFilterTester(t, "")
assert.Equal(t, len(results), 3) // all built-in resource will be analyzed
//2. When the --filter flag is specified
filterFlag = "Pod" // --filter=Pod
results = analysis_RunAnalysisFilterTester(t, filterFlag)
assert.Equal(t, len(results), 1)
assert.Equal(t, results[0].Kind, filterFlag)
filterFlag = "Ingress,Pod" // --filter=Ingress,Pod
results = analysis_RunAnalysisFilterTester(t, filterFlag)
assert.Equal(t, len(results), 2)
}
// Test: Filter logic with Active Filter
func TestAnalysis_RunAnalysisActiveFilter(t *testing.T) {
//When the --filter flag is not specified but has actived filter in config
var results []common.Result
viper.SetDefault("active_filters", "Ingress")
results = analysis_RunAnalysisFilterTester(t, "")
assert.Equal(t, len(results), 1)
viper.SetDefault("active_filters", []string{"Ingress", "Service"})
results = analysis_RunAnalysisFilterTester(t, "")
assert.Equal(t, len(results), 2)
viper.SetDefault("active_filters", []string{"Ingress", "Service", "Pod"})
results = analysis_RunAnalysisFilterTester(t, "")
assert.Equal(t, len(results), 3)
}
func TestAnalysis_NoProblemJsonOutput(t *testing.T) {
analysis := Analysis{
@@ -50,6 +163,7 @@ func TestAnalysis_NoProblemJsonOutput(t *testing.T) {
fmt.Println(expected)
require.Equal(t, got, expected)
}
func TestAnalysis_ProblemJsonOutput(t *testing.T) {

View File

@@ -42,6 +42,7 @@ func (a *Analysis) jsonOutput() ([]byte, error) {
}
result := JsonOutput{
Provider: a.AnalysisAIProvider,
Problems: problems,
Results: a.Results,
Errors: a.Errors,
@@ -56,6 +57,10 @@ func (a *Analysis) jsonOutput() ([]byte, error) {
func (a *Analysis) textOutput() ([]byte, error) {
var output strings.Builder
// Print the AI provider used for this analysis
output.WriteString(fmt.Sprintf("AI Provider: %s\n", color.YellowString(a.AnalysisAIProvider)))
if len(a.Errors) != 0 {
output.WriteString("\n")
output.WriteString(color.YellowString("Warnings : \n"))
@@ -73,6 +78,9 @@ func (a *Analysis) textOutput() ([]byte, error) {
color.YellowString(result.Name), color.CyanString(result.ParentObject)))
for _, err := range result.Error {
output.WriteString(fmt.Sprintf("- %s %s\n", color.RedString("Error:"), color.RedString(err.Text)))
if err.KubernetesDoc != "" {
output.WriteString(fmt.Sprintf(" %s %s\n", color.RedString("Kubernetes Doc:"), color.RedString(err.KubernetesDoc)))
}
}
output.WriteString(color.GreenString(result.Details + "\n"))
}

View File

@@ -78,18 +78,20 @@ func ListFilters() ([]string, []string, []string) {
return coreKeys, additionalKeys, integrationAnalyzers
}
func GetAnalyzerMap() map[string]common.IAnalyzer {
func GetAnalyzerMap() (map[string]common.IAnalyzer, map[string]common.IAnalyzer) {
mergedMap := make(map[string]common.IAnalyzer)
coreAnalyzer := make(map[string]common.IAnalyzer)
mergedAnalyzerMap := make(map[string]common.IAnalyzer)
// add core analyzer
for key, value := range coreAnalyzerMap {
mergedMap[key] = value
coreAnalyzer[key] = value
mergedAnalyzerMap[key] = value
}
// add additional analyzer
for key, value := range additionalAnalyzerMap {
mergedMap[key] = value
mergedAnalyzerMap[key] = value
}
integrationProvider := integration.NewIntegration()
@@ -106,9 +108,9 @@ func GetAnalyzerMap() map[string]common.IAnalyzer {
fmt.Println(color.RedString(err.Error()))
os.Exit(1)
}
in.AddAnalyzer(&mergedMap)
in.AddAnalyzer(&mergedAnalyzerMap)
}
}
return mergedMap
return coreAnalyzer, mergedAnalyzerMap
}

View File

@@ -18,9 +18,11 @@ import (
"time"
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
cron "github.com/robfig/cron/v3"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type CronJobAnalyzer struct{}
@@ -28,6 +30,14 @@ type CronJobAnalyzer struct{}
func (analyzer CronJobAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
kind := "CronJob"
apiDoc := kubernetes.K8sApiReference{
Kind: kind,
ApiVersion: schema.GroupVersion{
Group: "batch",
Version: "v1",
},
OpenapiSchema: a.OpenapiSchema,
}
AnalyzerErrorsMetric.DeletePartialMatch(map[string]string{
"analyzer_name": kind,
@@ -43,8 +53,11 @@ func (analyzer CronJobAnalyzer) Analyze(a common.Analyzer) ([]common.Result, err
for _, cronJob := range cronJobList.Items {
var failures []common.Failure
if cronJob.Spec.Suspend != nil && *cronJob.Spec.Suspend {
doc := apiDoc.GetApiDocV2("spec.suspend")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("CronJob %s is suspended", cronJob.Name),
Text: fmt.Sprintf("CronJob %s is suspended", cronJob.Name),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: cronJob.Namespace,
@@ -59,8 +72,11 @@ func (analyzer CronJobAnalyzer) Analyze(a common.Analyzer) ([]common.Result, err
} else {
// check the schedule format
if _, err := CheckCronScheduleIsValid(cronJob.Spec.Schedule); err != nil {
doc := apiDoc.GetApiDocV2("spec.schedule")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("CronJob %s has an invalid schedule: %s", cronJob.Name, err.Error()),
Text: fmt.Sprintf("CronJob %s has an invalid schedule: %s", cronJob.Name, err.Error()),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: cronJob.Namespace,
@@ -78,9 +94,11 @@ func (analyzer CronJobAnalyzer) Analyze(a common.Analyzer) ([]common.Result, err
if cronJob.Spec.StartingDeadlineSeconds != nil {
deadline := time.Duration(*cronJob.Spec.StartingDeadlineSeconds) * time.Second
if deadline < 0 {
doc := apiDoc.GetApiDocV2("spec.startingDeadlineSeconds")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("CronJob %s has a negative starting deadline", cronJob.Name),
Text: fmt.Sprintf("CronJob %s has a negative starting deadline", cronJob.Name),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: cronJob.Namespace,

View File

@@ -18,8 +18,10 @@ import (
"fmt"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
)
@@ -31,6 +33,14 @@ type DeploymentAnalyzer struct {
func (d DeploymentAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
kind := "Deployment"
apiDoc := kubernetes.K8sApiReference{
Kind: kind,
ApiVersion: schema.GroupVersion{
Group: "apps",
Version: "v1",
},
OpenapiSchema: a.OpenapiSchema,
}
AnalyzerErrorsMetric.DeletePartialMatch(map[string]string{
"analyzer_name": kind,
@@ -45,8 +55,11 @@ func (d DeploymentAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error)
for _, deployment := range deployments.Items {
var failures []common.Failure
if *deployment.Spec.Replicas != deployment.Status.Replicas {
doc := apiDoc.GetApiDocV2("spec.replicas")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("Deployment %s/%s has %d replicas but %d are available", deployment.Namespace, deployment.Name, *deployment.Spec.Replicas, deployment.Status.Replicas),
Text: fmt.Sprintf("Deployment %s/%s has %d replicas but %d are available", deployment.Namespace, deployment.Name, *deployment.Spec.Replicas, deployment.Status.Replicas),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: deployment.Namespace,

View File

@@ -17,10 +17,12 @@ import (
"fmt"
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type HpaAnalyzer struct{}
@@ -28,6 +30,14 @@ type HpaAnalyzer struct{}
func (HpaAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
kind := "HorizontalPodAutoscaler"
apiDoc := kubernetes.K8sApiReference{
Kind: kind,
ApiVersion: schema.GroupVersion{
Group: "autoscaling",
Version: "v1",
},
OpenapiSchema: a.OpenapiSchema,
}
AnalyzerErrorsMetric.DeletePartialMatch(map[string]string{
"analyzer_name": kind,
@@ -76,8 +86,11 @@ func (HpaAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
}
if podInfo == nil {
doc := apiDoc.GetApiDocV2("spec.scaleTargetRef")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("HorizontalPodAutoscaler uses %s/%s as ScaleTargetRef which does not exist.", scaleTargetRef.Kind, scaleTargetRef.Name),
Text: fmt.Sprintf("HorizontalPodAutoscaler uses %s/%s as ScaleTargetRef which does not exist.", scaleTargetRef.Kind, scaleTargetRef.Name),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: scaleTargetRef.Name,
@@ -94,8 +107,11 @@ func (HpaAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
}
if containers <= 0 {
doc := apiDoc.GetApiDocV2("spec.scaleTargetRef.kind")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("%s %s/%s does not have resource configured.", scaleTargetRef.Kind, a.Namespace, scaleTargetRef.Name),
Text: fmt.Sprintf("%s %s/%s does not have resource configured.", scaleTargetRef.Kind, a.Namespace, scaleTargetRef.Name),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: scaleTargetRef.Name,

View File

@@ -205,15 +205,15 @@ func TestHPAAnalyzerWithExistingScaleTargetRefAsDeployment(t *testing.T) {
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "example",
Name: "example",
Image: "nginx",
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"cpu": resource.MustParse("100m"),
"cpu": resource.MustParse("100m"),
"memory": resource.MustParse("128Mi"),
},
Limits: corev1.ResourceList{
"cpu": resource.MustParse("200m"),
"cpu": resource.MustParse("200m"),
"memory": resource.MustParse("256Mi"),
},
},
@@ -269,15 +269,15 @@ func TestHPAAnalyzerWithExistingScaleTargetRefAsReplicationController(t *testing
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "example",
Name: "example",
Image: "nginx",
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"cpu": resource.MustParse("100m"),
"cpu": resource.MustParse("100m"),
"memory": resource.MustParse("128Mi"),
},
Limits: corev1.ResourceList{
"cpu": resource.MustParse("200m"),
"cpu": resource.MustParse("200m"),
"memory": resource.MustParse("256Mi"),
},
},
@@ -333,15 +333,15 @@ func TestHPAAnalyzerWithExistingScaleTargetRefAsReplicaSet(t *testing.T) {
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "example",
Name: "example",
Image: "nginx",
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"cpu": resource.MustParse("100m"),
"cpu": resource.MustParse("100m"),
"memory": resource.MustParse("128Mi"),
},
Limits: corev1.ResourceList{
"cpu": resource.MustParse("200m"),
"cpu": resource.MustParse("200m"),
"memory": resource.MustParse("256Mi"),
},
},
@@ -397,15 +397,15 @@ func TestHPAAnalyzerWithExistingScaleTargetRefAsStatefulSet(t *testing.T) {
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "example",
Name: "example",
Image: "nginx",
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"cpu": resource.MustParse("100m"),
"cpu": resource.MustParse("100m"),
"memory": resource.MustParse("128Mi"),
},
Limits: corev1.ResourceList{
"cpu": resource.MustParse("200m"),
"cpu": resource.MustParse("200m"),
"memory": resource.MustParse("256Mi"),
},
},
@@ -461,7 +461,7 @@ func TestHPAAnalyzerWithExistingScaleTargetRefWithoutSpecifyingResources(t *test
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "example",
Name: "example",
Image: "nginx",
},
},
@@ -487,7 +487,7 @@ func TestHPAAnalyzerWithExistingScaleTargetRefWithoutSpecifyingResources(t *test
var errorFound bool
for _, analysis := range analysisResults {
for _, err := range analysis.Error {
if strings.Contains(err.Text, "does not have resource configured."){
if strings.Contains(err.Text, "does not have resource configured.") {
errorFound = true
break
}

View File

@@ -17,8 +17,10 @@ import (
"fmt"
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type IngressAnalyzer struct{}
@@ -26,6 +28,14 @@ type IngressAnalyzer struct{}
func (IngressAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
kind := "Ingress"
apiDoc := kubernetes.K8sApiReference{
Kind: kind,
ApiVersion: schema.GroupVersion{
Group: "networking",
Version: "v1",
},
OpenapiSchema: a.OpenapiSchema,
}
AnalyzerErrorsMetric.DeletePartialMatch(map[string]string{
"analyzer_name": kind,
@@ -46,8 +56,11 @@ func (IngressAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
if ingressClassName == nil {
ingClassValue := ing.Annotations["kubernetes.io/ingress.class"]
if ingClassValue == "" {
doc := apiDoc.GetApiDocV2("spec.ingressClassName")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("Ingress %s/%s does not specify an Ingress class.", ing.Namespace, ing.Name),
Text: fmt.Sprintf("Ingress %s/%s does not specify an Ingress class.", ing.Namespace, ing.Name),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: ing.Namespace,
@@ -68,8 +81,11 @@ func (IngressAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
if ingressClassName != nil {
_, err := a.Client.GetClient().NetworkingV1().IngressClasses().Get(a.Context, *ingressClassName, metav1.GetOptions{})
if err != nil {
doc := apiDoc.GetApiDocV2("spec.ingressClassName")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("Ingress uses the ingress class %s which does not exist.", *ingressClassName),
Text: fmt.Sprintf("Ingress uses the ingress class %s which does not exist.", *ingressClassName),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: *ingressClassName,
@@ -86,8 +102,11 @@ func (IngressAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
for _, path := range rule.HTTP.Paths {
_, err := a.Client.GetClient().CoreV1().Services(ing.Namespace).Get(a.Context, path.Backend.Service.Name, metav1.GetOptions{})
if err != nil {
doc := apiDoc.GetApiDocV2("spec.rules.http.paths.backend.service")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("Ingress uses the service %s/%s which does not exist.", ing.Namespace, path.Backend.Service.Name),
Text: fmt.Sprintf("Ingress uses the service %s/%s which does not exist.", ing.Namespace, path.Backend.Service.Name),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: ing.Namespace,
@@ -106,8 +125,11 @@ func (IngressAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
for _, tls := range ing.Spec.TLS {
_, err := a.Client.GetClient().CoreV1().Secrets(ing.Namespace).Get(a.Context, tls.SecretName, metav1.GetOptions{})
if err != nil {
doc := apiDoc.GetApiDocV2("spec.tls.secretName")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("Ingress uses the secret %s/%s as a TLS certificate which does not exist.", ing.Namespace, tls.SecretName),
Text: fmt.Sprintf("Ingress uses the secret %s/%s as a TLS certificate which does not exist.", ing.Namespace, tls.SecretName),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: ing.Namespace,

View File

@@ -17,8 +17,10 @@ import (
"fmt"
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type NetworkPolicyAnalyzer struct{}
@@ -26,6 +28,14 @@ type NetworkPolicyAnalyzer struct{}
func (NetworkPolicyAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
kind := "NetworkPolicy"
apiDoc := kubernetes.K8sApiReference{
Kind: kind,
ApiVersion: schema.GroupVersion{
Group: "networking",
Version: "v1",
},
OpenapiSchema: a.OpenapiSchema,
}
AnalyzerErrorsMetric.DeletePartialMatch(map[string]string{
"analyzer_name": kind,
@@ -45,8 +55,11 @@ func (NetworkPolicyAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error)
// Check if policy allows traffic to all pods in the namespace
if len(policy.Spec.PodSelector.MatchLabels) == 0 {
doc := apiDoc.GetApiDocV2("spec.podSelector.matchLabels")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("Network policy allows traffic to all pods: %s", policy.Name),
Text: fmt.Sprintf("Network policy allows traffic to all pods: %s", policy.Name),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: policy.Name,

View File

@@ -58,7 +58,7 @@ func (NodeAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
}
if len(failures) > 0 {
preAnalysis[fmt.Sprintf("%s", node.Name)] = common.PreAnalysis{
preAnalysis[node.Name] = common.PreAnalysis{
Node: node,
FailureDetails: failures,
}

View File

@@ -17,8 +17,10 @@ import (
"fmt"
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type PdbAnalyzer struct{}
@@ -26,6 +28,14 @@ type PdbAnalyzer struct{}
func (PdbAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
kind := "PodDisruptionBudget"
apiDoc := kubernetes.K8sApiReference{
Kind: kind,
ApiVersion: schema.GroupVersion{
Group: "policy",
Version: "v1",
},
OpenapiSchema: a.OpenapiSchema,
}
AnalyzerErrorsMetric.DeletePartialMatch(map[string]string{
"analyzer_name": kind,
@@ -49,8 +59,11 @@ func (PdbAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
if evt.Reason == "NoPods" && evt.Message != "" {
if pdb.Spec.Selector != nil {
for k, v := range pdb.Spec.Selector.MatchLabels {
doc := apiDoc.GetApiDocV2("spec.selector.matchLabels")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("%s, expected label %s=%s", evt.Message, k, v),
Text: fmt.Sprintf("%s, expected label %s=%s", evt.Message, k, v),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: k,
@@ -64,15 +77,21 @@ func (PdbAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
})
}
for _, v := range pdb.Spec.Selector.MatchExpressions {
doc := apiDoc.GetApiDocV2("spec.selector.matchExpressions")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("%s, expected expression %s", evt.Message, v),
Sensitive: []common.Sensitive{},
Text: fmt.Sprintf("%s, expected expression %s", evt.Message, v),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{},
})
}
} else {
doc := apiDoc.GetApiDocV2("spec.selector")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("%s, selector is nil", evt.Message),
Sensitive: []common.Sensitive{},
Text: fmt.Sprintf("%s, selector is nil", evt.Message),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{},
})
}
}

View File

@@ -85,7 +85,7 @@ func (PodAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
}
} else {
// when pod is Running but its ReadinessProbe fails
if containerStatus.Ready == false && pod.Status.Phase == "Running" {
if !containerStatus.Ready && pod.Status.Phase == "Running" {
// parse the event log and append details
evt, err := FetchLatestEvent(a.Context, a.Client, pod.Namespace, pod.Name)
if err != nil || evt == nil {

View File

@@ -18,8 +18,10 @@ import (
"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type ServiceAnalyzer struct{}
@@ -27,6 +29,14 @@ type ServiceAnalyzer struct{}
func (ServiceAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
kind := "Service"
apiDoc := kubernetes.K8sApiReference{
Kind: kind,
ApiVersion: schema.GroupVersion{
Group: "",
Version: "v1",
},
OpenapiSchema: a.OpenapiSchema,
}
AnalyzerErrorsMetric.DeletePartialMatch(map[string]string{
"analyzer_name": kind,
@@ -52,8 +62,11 @@ func (ServiceAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
}
for k, v := range svc.Spec.Selector {
doc := apiDoc.GetApiDocV2("spec.selector")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("Service has no endpoints, expected label %s=%s", k, v),
Text: fmt.Sprintf("Service has no endpoints, expected label %s=%s", k, v),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: k,
@@ -72,14 +85,20 @@ func (ServiceAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
// Check through container status to check for crashes
for _, epSubset := range ep.Subsets {
apiDoc.Kind = "Endpoints"
if len(epSubset.NotReadyAddresses) > 0 {
for _, addresses := range epSubset.NotReadyAddresses {
count++
pods = append(pods, addresses.TargetRef.Kind+"/"+addresses.TargetRef.Name)
}
doc := apiDoc.GetApiDocV2("subsets.notReadyAddresses")
failures = append(failures, common.Failure{
Text: fmt.Sprintf("Service has not ready endpoints, pods: %s, expected %d", pods, count),
Sensitive: []common.Sensitive{},
Text: fmt.Sprintf("Service has not ready endpoints, pods: %s, expected %d", pods, count),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{},
})
}
}

View File

@@ -17,8 +17,10 @@ import (
"fmt"
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type StatefulSetAnalyzer struct{}
@@ -26,6 +28,14 @@ type StatefulSetAnalyzer struct{}
func (StatefulSetAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
kind := "StatefulSet"
apiDoc := kubernetes.K8sApiReference{
Kind: kind,
ApiVersion: schema.GroupVersion{
Group: "apps",
Version: "v1",
},
OpenapiSchema: a.OpenapiSchema,
}
AnalyzerErrorsMetric.DeletePartialMatch(map[string]string{
"analyzer_name": kind,
@@ -44,8 +54,15 @@ 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.GetApiDocV2("spec.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.",
sts.Namespace,
serviceName,
),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{
{
Unmasked: sts.Namespace,

71
pkg/cache/cache.go vendored
View File

@@ -1,14 +1,83 @@
package cache
import (
"errors"
"github.com/spf13/viper"
)
type ICache interface {
Store(key string, data string) error
Load(key string) (string, error)
List() ([]string, error)
Exists(key string) bool
IsCacheDisabled() bool
}
func New(noCache bool) ICache {
func New(noCache bool, remoteCache bool) ICache {
if remoteCache {
return NewS3Cache(noCache)
}
return &FileBasedCache{
noCache: noCache,
}
}
// CacheProvider is the configuration for the cache provider when using a remote cache
type CacheProvider struct {
BucketName string `mapstructure:"bucketname"`
Region string `mapstructure:"region"`
}
func RemoteCacheEnabled() (bool, error) {
// load remote cache if it is configured
var cache CacheProvider
err := viper.UnmarshalKey("cache", &cache)
if err != nil {
return false, err
}
if cache.BucketName != "" && cache.Region != "" {
return true, nil
}
return false, nil
}
func AddRemoteCache(bucketName string, region string) error {
var cacheInfo CacheProvider
err := viper.UnmarshalKey("cache", &cacheInfo)
if err != nil {
return err
}
if cacheInfo.BucketName != "" {
return errors.New("Error: a cache is already configured, please remove it first")
}
cacheInfo.BucketName = bucketName
cacheInfo.Region = region
viper.Set("cache", cacheInfo)
err = viper.WriteConfig()
if err != nil {
return err
}
return nil
}
func RemoveRemoteCache(bucketName string) error {
var cacheInfo CacheProvider
err := viper.UnmarshalKey("cache", &cacheInfo)
if err != nil {
return err
}
if cacheInfo.BucketName == "" {
return errors.New("Error: no cache is configured")
}
cacheInfo = CacheProvider{}
viper.Set("cache", cacheInfo)
err = viper.WriteConfig()
if err != nil {
return err
}
return nil
}

View File

@@ -19,6 +19,25 @@ func (f *FileBasedCache) IsCacheDisabled() bool {
return f.noCache
}
func (*FileBasedCache) List() ([]string, error) {
path, err := xdg.CacheFile("k8sgpt")
if err != nil {
return nil, err
}
files, err := os.ReadDir(path)
if err != nil {
return nil, err
}
var result []string
for _, file := range files {
result = append(result, file.Name())
}
return result, nil
}
func (*FileBasedCache) Exists(key string) bool {
path, err := xdg.CacheFile(filepath.Join("k8sgpt", key))

118
pkg/cache/s3_based.go vendored Normal file
View File

@@ -0,0 +1,118 @@
package cache
import (
"bytes"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/spf13/viper"
)
// Generate ICache implementation
type S3Cache struct {
noCache bool
bucketName string
session *s3.S3
}
func (s *S3Cache) Store(key string, data string) error {
// Store the object as a new file in the bucket with data as the content
_, err := s.session.PutObject(&s3.PutObjectInput{
Body: aws.ReadSeekCloser(bytes.NewReader([]byte(data))),
Bucket: aws.String(s.bucketName),
Key: aws.String(key),
})
return err
}
func (s *S3Cache) Load(key string) (string, error) {
// Retrieve the object from the bucket and load it into a string
result, err := s.session.GetObject(&s3.GetObjectInput{
Bucket: aws.String(s.bucketName),
Key: aws.String(key),
})
if err != nil {
return "", err
}
buf := new(bytes.Buffer)
buf.ReadFrom(result.Body)
result.Body.Close()
return buf.String(), nil
}
func (s *S3Cache) List() ([]string, error) {
// List the files in the bucket
result, err := s.session.ListObjectsV2(&s3.ListObjectsV2Input{Bucket: aws.String(s.bucketName)})
if err != nil {
return nil, err
}
var keys []string
for _, item := range result.Contents {
keys = append(keys, *item.Key)
}
return keys, nil
}
func (s *S3Cache) Exists(key string) bool {
// Check if the object exists in the bucket
_, err := s.session.HeadObject(&s3.HeadObjectInput{
Bucket: aws.String(s.bucketName),
Key: aws.String(key),
})
return err == nil
}
func (s *S3Cache) IsCacheDisabled() bool {
return s.noCache
}
func NewS3Cache(nocache bool) ICache {
var cache CacheProvider
err := viper.UnmarshalKey("cache", &cache)
if err != nil {
panic(err)
}
if cache.BucketName == "" {
panic("Bucket name not configured")
}
if cache.Region == "" {
panic("Region not configured")
}
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
Config: aws.Config{
Region: aws.String(cache.Region),
},
}))
s := s3.New(sess)
// Check if the bucket exists, if not create it
_, err = s.HeadBucket(&s3.HeadBucketInput{
Bucket: aws.String(cache.BucketName),
})
if err != nil {
_, err = s.CreateBucket(&s3.CreateBucketInput{
Bucket: aws.String(cache.BucketName),
})
if err != nil {
panic(err)
}
}
return &S3Cache{
noCache: nocache,
session: s,
bucketName: cache.BucketName,
}
}

View File

@@ -17,6 +17,7 @@ import (
"context"
trivy "github.com/aquasecurity/trivy-operator/pkg/apis/aquasecurity/v1alpha1"
openapi_v2 "github.com/google/gnostic/openapiv2"
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
appsv1 "k8s.io/api/apps/v1"
@@ -31,12 +32,13 @@ type IAnalyzer interface {
}
type Analyzer struct {
Client *kubernetes.Client
Context context.Context
Namespace string
AIClient ai.IAI
PreAnalysis map[string]PreAnalysis
Results []Result
Client *kubernetes.Client
Context context.Context
Namespace string
AIClient ai.IAI
PreAnalysis map[string]PreAnalysis
Results []Result
OpenapiSchema *openapi_v2.Document
}
type PreAnalysis struct {
@@ -65,8 +67,9 @@ type Result struct {
}
type Failure struct {
Text string
Sensitive []Sensitive
Text string
KubernetesDoc string
Sensitive []Sensitive
}
type Sensitive struct {

View File

@@ -66,14 +66,11 @@ func (*Integration) Get(name string) (IIntegration, error) {
return integrations[name], nil
}
func (*Integration) Activate(name string, namespace string) error {
func (*Integration) Activate(name string, namespace string, activeFilters []string) error {
if _, ok := integrations[name]; !ok {
return errors.New("integration not found")
}
// Update filters
activeFilters := viper.GetStringSlice("active_filters")
mergedFilters := append(activeFilters, integrations[name].GetAnalyzerName())
uniqueFilters, dupplicatedFilters := util.RemoveDuplicates(mergedFilters)

View File

@@ -0,0 +1,70 @@
package kubernetes
import (
"fmt"
"strings"
openapi_v2 "github.com/google/gnostic/openapiv2"
)
func (k *K8sApiReference) GetApiDocV2(field string) string {
startPoint := ""
// the path must be formated like "path1.path2.path3"
paths := strings.Split(field, ".")
group := strings.Split(k.ApiVersion.Group, ".")
definitions := k.OpenapiSchema.GetDefinitions().GetAdditionalProperties()
// extract the startpoint by searching the highest leaf corresponding to the requested group qnd kind
for _, prop := range definitions {
if strings.HasSuffix(prop.GetName(), fmt.Sprintf("%s.%s.%s", group[0], k.ApiVersion.Version, k.Kind)) {
startPoint = prop.GetName()
break
}
}
// recursively parse the definitions to find the description of the latest part of the given path
description := k.recursePath(definitions, startPoint, paths)
return description
}
func (k *K8sApiReference) recursePath(definitions []*openapi_v2.NamedSchema, leaf string, paths []string) string {
description := ""
for _, prop := range definitions {
// search the requested leaf
if prop.GetName() == leaf {
for _, addProp := range prop.GetValue().GetProperties().GetAdditionalProperties() {
// search the additional property of the leaf corresponding the current path
if addProp.GetName() == paths[0] {
// the last path or the path is string, we get the description and we go out
if len(paths) == 1 || addProp.GetValue().GetType().String() == "value:\"string\"" {
// extract the path description as we are at the end of the paths
description = addProp.GetValue().Description
} else {
// the path is an object, we extract the xref
if addProp.GetValue().GetXRef() != "" {
splitRef := strings.Split(addProp.GetValue().GetXRef(), "/")
reducedPaths := paths[1:]
description = k.recursePath(definitions, splitRef[len(splitRef)-1], reducedPaths)
}
// the path is an array, we take the first xref from the items
if len(addProp.GetValue().GetItems().GetSchema()) == 1 {
splitRef := strings.Split(addProp.GetValue().GetItems().GetSchema()[0].GetXRef(), "/")
reducedPaths := paths[1:]
description = k.recursePath(definitions, splitRef[len(splitRef)-1], reducedPaths)
}
}
break
}
}
break
}
}
return description
}

View File

@@ -22,12 +22,6 @@ import (
"k8s.io/kubectl/pkg/scheme"
)
type Client struct {
Client kubernetes.Interface
RestClient rest.Interface
Config *rest.Config
}
func (c *Client) GetConfig() *rest.Config {
return c.Config
}
@@ -74,9 +68,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
}

22
pkg/kubernetes/types.go Normal file
View File

@@ -0,0 +1,22 @@
package kubernetes
import (
openapi_v2 "github.com/google/gnostic/openapiv2"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
type Client struct {
Client kubernetes.Interface
RestClient rest.Interface
Config *rest.Config
ServerVersion *version.Info
}
type K8sApiReference struct {
ApiVersion schema.GroupVersion
Kind string
OpenapiSchema *openapi_v2.Document
}

61
pkg/server/analyze.go Normal file
View File

@@ -0,0 +1,61 @@
package server
import (
"context"
json "encoding/json"
schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1"
"github.com/k8sgpt-ai/k8sgpt/pkg/analysis"
)
func (h *handler) Analyze(ctx context.Context, i *schemav1.AnalyzeRequest) (
*schemav1.AnalyzeResponse,
error,
) {
if i.Output == "" {
i.Output = "json"
}
if i.Backend == "" {
i.Backend = "openai"
}
if int(i.MaxConcurrency) == 0 {
i.MaxConcurrency = 10
}
config, err := analysis.NewAnalysis(
i.Backend,
i.Language,
i.Filters,
i.Namespace,
i.Nocache,
i.Explain,
int(i.MaxConcurrency),
false, // Kubernetes Doc disabled in server mode
)
if err != nil {
return &schemav1.AnalyzeResponse{}, err
}
config.RunAnalysis()
if i.Explain {
err := config.GetAIResults(i.Output, i.Anonymize)
if err != nil {
return &schemav1.AnalyzeResponse{}, err
}
}
out, err := config.PrintOutput(i.Output)
if err != nil {
return &schemav1.AnalyzeResponse{}, err
}
var obj schemav1.AnalyzeResponse
err = json.Unmarshal(out, &obj)
if err != nil {
return &schemav1.AnalyzeResponse{}, err
}
return &obj, nil
}

37
pkg/server/config.go Normal file
View File

@@ -0,0 +1,37 @@
package server
import (
"context"
"errors"
schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1"
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
)
func (h *handler) AddConfig(ctx context.Context, i *schemav1.AddConfigRequest) (*schemav1.AddConfigResponse, error,
) {
if i.Cache.BucketName == "" || i.Cache.Region == "" {
return nil, errors.New("BucketName & Region are required")
}
err := cache.AddRemoteCache(i.Cache.BucketName, i.Cache.Region)
if err != nil {
return &schemav1.AddConfigResponse{}, err
}
return &schemav1.AddConfigResponse{
Status: "Configuration updated.",
}, 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{}, err
}
return &schemav1.RemoveConfigResponse{
Status: "Successfully removed the remote cache",
}, nil
}

View File

@@ -1,65 +1,9 @@
package server
import (
"context"
json "encoding/json"
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/pkg/analysis"
)
type handler struct {
rpc.UnimplementedServerServer
}
func (h *handler) Analyze(ctx context.Context, i *schemav1.AnalyzeRequest) (
*schemav1.AnalyzeResponse,
error,
) {
if i.Output == "" {
i.Output = "json"
}
if i.Backend == "" {
i.Backend = "openai"
}
if int(i.MaxConcurrency) == 0 {
i.MaxConcurrency = 10
}
config, err := analysis.NewAnalysis(
i.Backend,
i.Language,
[]string{},
i.Namespace,
i.Nocache,
i.Explain,
int(i.MaxConcurrency),
)
if err != nil {
return &schemav1.AnalyzeResponse{}, err
}
config.RunAnalysis()
if i.Explain {
err := config.GetAIResults(i.Output, i.Anonymize)
if err != nil {
return &schemav1.AnalyzeResponse{}, err
}
}
out, err := config.PrintOutput(i.Output)
if err != nil {
return &schemav1.AnalyzeResponse{}, err
}
var obj schemav1.AnalyzeResponse
err = json.Unmarshal(out, &obj)
if err != nil {
return &schemav1.AnalyzeResponse{}, err
}
return &obj, nil
rpc.UnimplementedServerServiceServer
}

View File

@@ -2,6 +2,7 @@ package server
import (
"context"
"fmt"
"time"
"go.uber.org/zap"
@@ -34,7 +35,7 @@ func logInterceptor(logger *zap.Logger) grpc.UnaryServerInterceptor {
}
message := "request completed"
if err != nil {
message = "request failed"
message = fmt.Sprintf("request failed. %s", err.Error())
}
logRequest(logger, fields, int(status.Code(err)), message)

View File

@@ -69,7 +69,7 @@ func (s *Config) Serve() error {
grpcServerUnaryInterceptor := grpc.UnaryInterceptor(logInterceptor(s.Logger))
grpcServer := grpc.NewServer(grpcServerUnaryInterceptor)
reflection.Register(grpcServer)
rpc.RegisterServerServer(grpcServer, s.Handler)
rpc.RegisterServerServiceServer(grpcServer, s.Handler)
if err := grpcServer.Serve(
lis,
); err != nil && !errors.Is(err, http.ErrServerClosed) {
@@ -107,7 +107,7 @@ func (s *Config) healthzHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, string(js))
fmt.Fprint(w, string(js))
}
func getBoolParam(param string) bool {