Compare commits
178 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad112eae2e | ||
|
|
da750df16b | ||
|
|
767e4cbc41 | ||
|
|
3067fa98f4 | ||
|
|
2309b0dfe2 | ||
|
|
1f5462c80b | ||
|
|
5a983c4a0a | ||
|
|
5662d5932f | ||
|
|
367fe8f74c | ||
|
|
566f7525ee | ||
|
|
fafb69544f | ||
|
|
b7d4602cb8 | ||
|
|
d56861d4ba | ||
|
|
3146754779 | ||
|
|
57695b44b6 | ||
|
|
be52308c99 | ||
|
|
cd7807a484 | ||
|
|
0521060410 | ||
|
|
b9cf522685 | ||
|
|
06e50d57db | ||
|
|
c88fc889e4 | ||
|
|
c15a561b63 | ||
|
|
1819c3bf15 | ||
|
|
f4d7876838 | ||
|
|
d87127a309 | ||
|
|
9df75cc959 | ||
|
|
f3e0b9b56d | ||
|
|
0f03ddcf0f | ||
|
|
14e5691190 | ||
|
|
64b93c9116 | ||
|
|
4038318adc | ||
|
|
b1c6ec3c09 | ||
|
|
f6db6ce861 | ||
|
|
1bc0f42f71 | ||
|
|
01aeeb35e2 | ||
|
|
a6342c9283 | ||
|
|
98b852aabe | ||
|
|
c85203bccd | ||
|
|
ad2a5fd5fc | ||
|
|
04b4f56a66 | ||
|
|
40fbba7df1 | ||
|
|
a23276d3ff | ||
|
|
e556901b9d | ||
|
|
1ae21e6fd4 | ||
|
|
e2d5c2dee0 | ||
|
|
075066dd7c | ||
|
|
3f0aea131e | ||
|
|
92539ee05d | ||
|
|
705b54fcd3 | ||
|
|
1a81227d61 | ||
|
|
9c0efe6f5c | ||
|
|
f9621af7e4 | ||
|
|
6052a5b4d7 | ||
|
|
42437f77d1 | ||
|
|
523362765f | ||
|
|
1459dd4b8e | ||
|
|
1b86a6fc89 | ||
|
|
5cf4fc52da | ||
|
|
cd049c9b4b | ||
|
|
86ebc23de7 | ||
|
|
a236cc4f28 | ||
|
|
6eac58d4b0 | ||
|
|
2994c1c5a7 | ||
|
|
fa4a0757b8 | ||
|
|
49e120c28e | ||
|
|
6479cbaf91 | ||
|
|
36995fd4ed | ||
|
|
fe450eb69d | ||
|
|
edda743fa2 | ||
|
|
57281df53c | ||
|
|
1f767ebd2e | ||
|
|
b7dc384547 | ||
|
|
c588e963de | ||
|
|
d13b91301c | ||
|
|
948dae5e28 | ||
|
|
c659a875fc | ||
|
|
f0d3f36f6d | ||
|
|
940a50e851 | ||
|
|
06542b4bf1 | ||
|
|
af826d500f | ||
|
|
cbe2fb4a4c | ||
|
|
032576c728 | ||
|
|
3099909113 | ||
|
|
097c7912b0 | ||
|
|
493c684eb7 | ||
|
|
a1f98ad78e | ||
|
|
e66de8c4ce | ||
|
|
aafe669739 | ||
|
|
e5e613acee | ||
|
|
ed73485d92 | ||
|
|
50916f2c93 | ||
|
|
c1410d1699 | ||
|
|
c5b72eee16 | ||
|
|
8cfb717dc1 | ||
|
|
639aa12931 | ||
|
|
123b8a66ee | ||
|
|
5d4e591f11 | ||
|
|
9f494fa884 | ||
|
|
9998e7620d | ||
|
|
b6b06123db | ||
|
|
9192b26fab | ||
|
|
65fff11e58 | ||
|
|
00aaae86d8 | ||
|
|
d6bcb96105 | ||
|
|
045a06350b | ||
|
|
fbc9a3b6e1 | ||
|
|
9faa69422d | ||
|
|
8b82d59bd7 | ||
|
|
799869bcef | ||
|
|
8b49f708f3 | ||
|
|
e0200e7fa0 | ||
|
|
d8357ceb94 | ||
|
|
a89a5cfa2e | ||
|
|
4f6e833d34 | ||
|
|
6431be7771 | ||
|
|
766a15b25a | ||
|
|
4e146fb152 | ||
|
|
b8a5f3bab8 | ||
|
|
3051b1ca34 | ||
|
|
7471b76794 | ||
|
|
5af8178802 | ||
|
|
363294c310 | ||
|
|
80dddc35a4 | ||
|
|
dee423519e | ||
|
|
3af366788f | ||
|
|
cf16769a36 | ||
|
|
ee85d13d59 | ||
|
|
f8fa35cf9d | ||
|
|
14a3537ce9 | ||
|
|
0995e008fe | ||
|
|
125341bdaa | ||
|
|
aca58064c3 | ||
|
|
10f49e6146 | ||
|
|
c29860d418 | ||
|
|
947e94f353 | ||
|
|
8adde6bf87 | ||
|
|
d4dcc7a399 | ||
|
|
78ee280e73 | ||
|
|
74d9a750ca | ||
|
|
c365c53332 | ||
|
|
9f092f3928 | ||
|
|
252c734310 | ||
|
|
db4a88e409 | ||
|
|
2616220935 | ||
|
|
30de25166d | ||
|
|
3d11e12963 | ||
|
|
692cd06c38 | ||
|
|
5383d2e858 | ||
|
|
a1aaa0a2d1 | ||
|
|
5d6f3c31b9 | ||
|
|
2a27344e9c | ||
|
|
3f769bf0e0 | ||
|
|
7eddb8f4a6 | ||
|
|
c3cc413e7f | ||
|
|
2391603075 | ||
|
|
9b914fbc0b | ||
|
|
110cb54a8a | ||
|
|
e7f74db6e5 | ||
|
|
5aaeb77a48 | ||
|
|
751010f25b | ||
|
|
a65ee7fc09 | ||
|
|
ff799825cf | ||
|
|
cf797a6eb6 | ||
|
|
754bf917e1 | ||
|
|
d0f7a1105f | ||
|
|
95305438b3 | ||
|
|
ddd830cc56 | ||
|
|
0a4ed0d907 | ||
|
|
2102f06585 | ||
|
|
84a3cc05fb | ||
|
|
bd4ab0e589 | ||
|
|
7a7c6cf157 | ||
|
|
fa087ff559 | ||
|
|
3ef6156d55 | ||
|
|
d50ca29a2c | ||
|
|
df2ed4185b | ||
|
|
3c7e0bba1d | ||
|
|
0472c363a4 |
3
.github/CODEOWNERS
vendored
@@ -9,4 +9,5 @@
|
||||
# Unless a later match takes precedence, these owners will be requested for
|
||||
# review when someone opens a pull request.
|
||||
|
||||
* @k8sgpt-ai/maintainers @k8sgpt-ai/k8sgpt-approvers
|
||||
/.github/settings.yml @k8sgpt-ai/maintainers
|
||||
* @k8sgpt-ai/maintainers @k8sgpt-ai/k8sgpt-maintainers @k8sgpt-ai/k8sgpt-approvers
|
||||
|
||||
35
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,35 +0,0 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest an idea for this project
|
||||
title: 'feature: '
|
||||
labels: 'type:question'
|
||||
assignees: '@k8sgpt-ai/maintainers'
|
||||
---
|
||||
|
||||
<!--
|
||||
Thank you for initiating this feature request 🤗
|
||||
|
||||
To ensure conciseness, kindly try to adhere to the following format.
|
||||
-->
|
||||
|
||||
Checklist:
|
||||
* [ ] I've searched for similar issues and couldn't find anything matching
|
||||
* [ ] I've discussed this feature in the #k8sgpt slack channel
|
||||
|
||||
## Is this feature request related to a problem?
|
||||
* [ ] Yes
|
||||
* [ ] No
|
||||
|
||||
<!-- If yes, please provide a clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||
|
||||
## Describe the solution you'd like
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
## Benefits for the project and its users
|
||||
<!-- Describe the benefits this feature will bring to the project and its users. -->
|
||||
|
||||
## Potential drawbacks
|
||||
<!-- Describe any potential drawbacks this feature might bring to the project and its users. -->
|
||||
|
||||
## Additional context
|
||||
<!-- Add any other context about your feature request here. If applicable, add drawings to help explain. -->
|
||||
50
.github/ISSUE_TEMPLATE/question.md
vendored
@@ -1,50 +0,0 @@
|
||||
---
|
||||
name: Question / Bug Report
|
||||
about: Create a report to help us improve
|
||||
title: 'question: '
|
||||
labels: 'type:question'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
Thank you for initiating this issue request 🤗
|
||||
|
||||
To ensure conciseness, kindly try to adhere to the following format.
|
||||
-->
|
||||
|
||||
Checklist:
|
||||
|
||||
* [ ] I've searched for similar issues and couldn't find anything matching
|
||||
* [ ] I've included steps to reproduce the bug.
|
||||
* [ ] I've included the version of Kubernetes and k8sgpt.
|
||||
|
||||
### Subject of the issue
|
||||
|
||||
<!-- Describe your issue here. -->
|
||||
|
||||
### Your environment
|
||||
|
||||
<!-- Describe your environment here. -->
|
||||
|
||||
* Version of Kubernetes
|
||||
<!-- kubectl version -->
|
||||
* Host OS and its version / If windows, is it WSL?
|
||||
* Version of k8sgpt
|
||||
<!-- k8sgpt version -->
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
<!-- Tell us how to reproduce this issue. -->
|
||||
|
||||
* Step 1
|
||||
* Step 2
|
||||
|
||||
### Expected behaviour
|
||||
<!-- Tell us what should happen -->
|
||||
|
||||
### Actual behaviour
|
||||
|
||||
<!-- Tell us what happens instead -->
|
||||
|
||||
### Additional context / screenshots
|
||||
<!-- Add any other context about the problem here. If applicable, add screenshots to help explain. -->
|
||||
47
.github/settings.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
repository:
|
||||
name: "k8sgpt"
|
||||
description: "Giving Kubernetes SRE superpowers to everyone"
|
||||
homepage_url: "https://k8sgpt.ai"
|
||||
topics: kubernetes, devops, tooling, openai, sre
|
||||
|
||||
default_branch: main
|
||||
allow_squash_merge: true
|
||||
allow_merge_commit: true
|
||||
allow_rebase_merge: true
|
||||
|
||||
has_wiki: false
|
||||
|
||||
teams:
|
||||
- name: "maintainers"
|
||||
permission: "admin"
|
||||
- name: "k8sgpt-maintainers"
|
||||
permission: "maintain"
|
||||
- name: "k8sgpt-approvers"
|
||||
permission: "push"
|
||||
- name: "contributors"
|
||||
permission: "push"
|
||||
|
||||
branches:
|
||||
- name: main
|
||||
protection:
|
||||
required_pull_request_reviews:
|
||||
required_approving_review_count: 1
|
||||
dismiss_stale_reviews: true
|
||||
require_code_owner_reviews: true
|
||||
dismissal_restrictions: {}
|
||||
code_owner_approval: true
|
||||
required_conversation_resolution: true
|
||||
|
||||
required_status_checks:
|
||||
strict: true
|
||||
contexts:
|
||||
- "DCO"
|
||||
|
||||
enforce_admins: true
|
||||
|
||||
required_linear_history: true
|
||||
|
||||
restrictions:
|
||||
users: []
|
||||
apps: []
|
||||
teams: []
|
||||
16
.github/workflows/build_container.yaml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3
|
||||
|
||||
- name: Extract branch name
|
||||
id: extract_branch
|
||||
@@ -70,14 +70,14 @@ jobs:
|
||||
RELEASE_REGISTRY: "localhost:5000/k8sgpt"
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2
|
||||
uses: docker/setup-buildx-action@16c0bc4a6e6ada2cfd8afd41d22d95379cf7c32a # v2
|
||||
|
||||
- name: Build Docker Image
|
||||
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4
|
||||
uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825 # v4
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
@@ -115,10 +115,10 @@ jobs:
|
||||
contents: read # Needed for checking out the repository
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2
|
||||
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2
|
||||
with:
|
||||
registry: "ghcr.io"
|
||||
username: ${{ github.actor }}
|
||||
@@ -126,10 +126,10 @@ jobs:
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2
|
||||
uses: docker/setup-buildx-action@16c0bc4a6e6ada2cfd8afd41d22d95379cf7c32a # v2
|
||||
|
||||
- name: Build Docker Image
|
||||
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4
|
||||
uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825 # v4
|
||||
with:
|
||||
context: .
|
||||
file: ./container/Dockerfile
|
||||
|
||||
18
.github/workflows/golangci_lint.yaml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Run golangci-lint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
golangci-lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3
|
||||
|
||||
- name: golangci-lint
|
||||
uses: reviewdog/action-golangci-lint@22adb9d08853436506154413f5683c2e749d3b85 # v2
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
reporter: github-pr-check
|
||||
22
.github/workflows/release.yaml
vendored
@@ -23,9 +23,9 @@ jobs:
|
||||
# Release-please creates a PR that tracks all changes
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3
|
||||
|
||||
- uses: google-github-actions/release-please-action@c078ea33917ab8cfa5300e48f4b7e6b16606aede # v3
|
||||
- uses: google-github-actions/release-please-action@8016a6649226f2ec88ed05441c11bb5410a22d29 # v3
|
||||
id: release
|
||||
with:
|
||||
command: manifest
|
||||
@@ -41,17 +41,17 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3
|
||||
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
|
||||
uses: anchore/sbom-action/download-syft@422cb34a0f8b599678c41b21163ea6088edb2624 # v0.14.1
|
||||
uses: anchore/sbom-action/download-syft@78fc58e266e87a38d4194b2137a3d4e9bcaf7ca1 # v0.14.3
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@f82d6c1c344bcacabba2c841718984797f664a6b # v4
|
||||
uses: goreleaser/goreleaser-action@336e29918d653399e599bfca99fadc1d7ffbc9f7 # v4
|
||||
with:
|
||||
# either 'goreleaser' (default) or 'goreleaser-pro'
|
||||
distribution: goreleaser
|
||||
@@ -74,23 +74,23 @@ jobs:
|
||||
IMAGE_NAME: k8sgpt
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2
|
||||
uses: docker/setup-buildx-action@16c0bc4a6e6ada2cfd8afd41d22d95379cf7c32a # v2
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2
|
||||
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2
|
||||
with:
|
||||
registry: "ghcr.io"
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build Docker Image
|
||||
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4
|
||||
uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825 # v4
|
||||
with:
|
||||
context: .
|
||||
file: ./container/Dockerfile
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
cache-to: type=gha,scope=${{ github.ref_name }}-${{ env.IMAGE_TAG }}
|
||||
|
||||
- name: Generate SBOM
|
||||
uses: anchore/sbom-action@422cb34a0f8b599678c41b21163ea6088edb2624 # v0.14.1
|
||||
uses: anchore/sbom-action@78fc58e266e87a38d4194b2137a3d4e9bcaf7ca1 # v0.14.3
|
||||
with:
|
||||
image: ${{ env.IMAGE_TAG }}
|
||||
artifact-name: sbom-${{ env.IMAGE_NAME }}
|
||||
|
||||
12
.github/workflows/test.yaml
vendored
@@ -16,12 +16,16 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # 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
|
||||
|
||||
|
||||
4
.gitignore
vendored
@@ -1,3 +1,7 @@
|
||||
.DS_Store
|
||||
k8sgpt*
|
||||
!charts/k8sgpt
|
||||
*.vscode
|
||||
dist/
|
||||
|
||||
bin/
|
||||
|
||||
@@ -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 }}'
|
||||
|
||||
@@ -1 +1 @@
|
||||
{".":"0.2.4"}
|
||||
{".":"0.3.9"}
|
||||
341
CHANGELOG.md
@@ -1,5 +1,346 @@
|
||||
# Changelog
|
||||
|
||||
## [0.3.9](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.8...v0.3.9) (2023-07-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* details flag to list command ([#537](https://github.com/k8sgpt-ai/k8sgpt/issues/537)) ([2309b0d](https://github.com/k8sgpt-ai/k8sgpt/commit/2309b0dfe20e27b6afe283a6be21ad7a0652ac99))
|
||||
* upgrading azure client impl ([#526](https://github.com/k8sgpt-ai/k8sgpt/issues/526)) ([367fe8f](https://github.com/k8sgpt-ai/k8sgpt/commit/367fe8f74c6a9e26f0d9c3b25a86093530fb85b2))
|
||||
* upgrading the proto files to fix user issues ([#515](https://github.com/k8sgpt-ai/k8sgpt/issues/515)) ([c88fc88](https://github.com/k8sgpt-ai/k8sgpt/commit/c88fc889e4f6089e48f37d90e349d5c61ea0b952))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 'intergration' typos ([#508](https://github.com/k8sgpt-ai/k8sgpt/issues/508)) ([64b93c9](https://github.com/k8sgpt-ai/k8sgpt/commit/64b93c9116b6a7f82419f1c4fff98fa68b8c0aca))
|
||||
* add --no-install for activate command ([#536](https://github.com/k8sgpt-ai/k8sgpt/issues/536)) ([1f5462c](https://github.com/k8sgpt-ai/k8sgpt/commit/1f5462c80bd04f63c2b55889c987634251635812))
|
||||
* **deps:** update module buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go to v1.3.0-20230620082254-6f80f9533908.1 ([#516](https://github.com/k8sgpt-ai/k8sgpt/issues/516)) ([06e50d5](https://github.com/k8sgpt-ai/k8sgpt/commit/06e50d57db3aa2e5a68b093e2ba25c0e33dc6343))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.284 ([#501](https://github.com/k8sgpt-ai/k8sgpt/issues/501)) ([d87127a](https://github.com/k8sgpt-ai/k8sgpt/commit/d87127a309734847a56bf95c2e947e2270f94a88))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.286 ([#514](https://github.com/k8sgpt-ai/k8sgpt/issues/514)) ([b9cf522](https://github.com/k8sgpt-ai/k8sgpt/commit/b9cf5226853619655e98f2156bfd0b8513511bb3))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.288 ([#519](https://github.com/k8sgpt-ai/k8sgpt/issues/519)) ([57695b4](https://github.com/k8sgpt-ai/k8sgpt/commit/57695b44b6429319860a76e4e02016dafe3ed0b0))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.289 ([#524](https://github.com/k8sgpt-ai/k8sgpt/issues/524)) ([fafb695](https://github.com/k8sgpt-ai/k8sgpt/commit/fafb69544f4edda670bad6973332a20a7f0f055e))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.292 ([#530](https://github.com/k8sgpt-ai/k8sgpt/issues/530)) ([566f752](https://github.com/k8sgpt-ai/k8sgpt/commit/566f7525eef9f65dd2ab6a47bd0012bfb91e2a12))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.294 ([#535](https://github.com/k8sgpt-ai/k8sgpt/issues/535)) ([3067fa9](https://github.com/k8sgpt-ai/k8sgpt/commit/3067fa98f4a8990c9a930e53ad93f89cf35e0d62))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.295 ([#540](https://github.com/k8sgpt-ai/k8sgpt/issues/540)) ([767e4cb](https://github.com/k8sgpt-ai/k8sgpt/commit/767e4cbc4127e2017a3a9c4b182ccc833debc6a5))
|
||||
* **deps:** update module github.com/prometheus/client_golang to v1.16.0 ([#507](https://github.com/k8sgpt-ai/k8sgpt/issues/507)) ([14e5691](https://github.com/k8sgpt-ai/k8sgpt/commit/14e5691190bf772c05477cbcb811ed71bec450a3))
|
||||
* **deps:** update module google.golang.org/grpc to v1.56.0 ([#510](https://github.com/k8sgpt-ai/k8sgpt/issues/510)) ([f3e0b9b](https://github.com/k8sgpt-ai/k8sgpt/commit/f3e0b9b56d13397c79f57e76bdd6b741bb565fb4))
|
||||
* **deps:** update module google.golang.org/grpc to v1.56.1 ([#520](https://github.com/k8sgpt-ai/k8sgpt/issues/520)) ([be52308](https://github.com/k8sgpt-ai/k8sgpt/commit/be52308c99f6aed73e2c20d260823795d45876f5))
|
||||
* **deps:** update module helm.sh/helm/v3 to v3.12.1 ([#503](https://github.com/k8sgpt-ai/k8sgpt/issues/503)) ([0f03ddc](https://github.com/k8sgpt-ai/k8sgpt/commit/0f03ddcf0f5ec79bc6dbb74c654e0d8fac634a0a))
|
||||
* displaying correct yaml config location on app start ([#521](https://github.com/k8sgpt-ai/k8sgpt/issues/521)) ([b7d4602](https://github.com/k8sgpt-ai/k8sgpt/commit/b7d4602cb8aaaa0c22a0a5941d8c6edad7c58db4))
|
||||
* remove provider from default on delete ([#529](https://github.com/k8sgpt-ai/k8sgpt/issues/529)) ([5a983c4](https://github.com/k8sgpt-ai/k8sgpt/commit/5a983c4a0a511389e25cffe12999b903b85cd96d))
|
||||
* typo in add command ([#539](https://github.com/k8sgpt-ai/k8sgpt/issues/539)) ([da750df](https://github.com/k8sgpt-ai/k8sgpt/commit/da750df16bde878f7619aa58ef5e7ef7d3173b2b))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* **deps:** update anchore/sbom-action action to v0.14.3 ([#517](https://github.com/k8sgpt-ai/k8sgpt/issues/517)) ([0521060](https://github.com/k8sgpt-ai/k8sgpt/commit/05210604109a6e892bb465df11038b8c24d68076))
|
||||
* **deps:** update docker/build-push-action digest to 2eb1c19 ([#499](https://github.com/k8sgpt-ai/k8sgpt/issues/499)) ([9df75cc](https://github.com/k8sgpt-ai/k8sgpt/commit/9df75cc959f7ed23cae8e3761498ea6c56885788))
|
||||
* **deps:** update docker/login-action digest to 465a078 ([#488](https://github.com/k8sgpt-ai/k8sgpt/issues/488)) ([c15a561](https://github.com/k8sgpt-ai/k8sgpt/commit/c15a561b635dc678bb8de15c6623914942475537))
|
||||
* **deps:** update docker/setup-buildx-action digest to 16c0bc4 ([#532](https://github.com/k8sgpt-ai/k8sgpt/issues/532)) ([5662d59](https://github.com/k8sgpt-ai/k8sgpt/commit/5662d5932ff3beb8c1a31fc2088c5e703e90ec79))
|
||||
* **deps:** update docker/setup-buildx-action digest to ecf9528 ([#498](https://github.com/k8sgpt-ai/k8sgpt/issues/498)) ([f4d7876](https://github.com/k8sgpt-ai/k8sgpt/commit/f4d78768388774f62d87acd89e71689535e538f7))
|
||||
* **deps:** update google-github-actions/release-please-action digest to 8016a66 ([#523](https://github.com/k8sgpt-ai/k8sgpt/issues/523)) ([d56861d](https://github.com/k8sgpt-ai/k8sgpt/commit/d56861d4bad475da09992813fc256a0d99399eab))
|
||||
* **deps:** update reviewdog/action-golangci-lint digest to 22adb9d ([#525](https://github.com/k8sgpt-ai/k8sgpt/issues/525)) ([3146754](https://github.com/k8sgpt-ai/k8sgpt/commit/314675477917063dcfb847880fb3186f8bdf32f6))
|
||||
* **deps:** update reviewdog/action-golangci-lint digest to 994abff ([#513](https://github.com/k8sgpt-ai/k8sgpt/issues/513)) ([1819c3b](https://github.com/k8sgpt-ai/k8sgpt/commit/1819c3bf1512291cd637c115e8b82c9e0e8885a0))
|
||||
* sorting out the dependency hell ([#518](https://github.com/k8sgpt-ai/k8sgpt/issues/518)) ([cd7807a](https://github.com/k8sgpt-ai/k8sgpt/commit/cd7807a48481f298422d9b1c8066b431fad3ae5a))
|
||||
|
||||
## [0.3.8](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.7...v0.3.8) (2023-06-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* fix for s3 cache from operator ([f6db6ce](https://github.com/k8sgpt-ai/k8sgpt/commit/f6db6ce86163dcb4b5ec4bd99b8a3842dd0c60bb))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update kubernetes packages to v0.27.3 ([#504](https://github.com/k8sgpt-ai/k8sgpt/issues/504)) ([b1c6ec3](https://github.com/k8sgpt-ai/k8sgpt/commit/b1c6ec3c0919649bc551ec0047a1d9c2420f4264))
|
||||
|
||||
## [0.3.7](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.6...v0.3.7) (2023-06-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add update to auth cmd ([#450](https://github.com/k8sgpt-ai/k8sgpt/issues/450)) ([01aeeb3](https://github.com/k8sgpt-ai/k8sgpt/commit/01aeeb35e2dab957d2909cd5cffc5a4a03e19664))
|
||||
* support arbitrary uid for openshift environments ([#454](https://github.com/k8sgpt-ai/k8sgpt/issues/454)) ([92539ee](https://github.com/k8sgpt-ai/k8sgpt/commit/92539ee05d2d15e951742aaaf07f2defff3f79c5))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.274 ([#474](https://github.com/k8sgpt-ai/k8sgpt/issues/474)) ([1a81227](https://github.com/k8sgpt-ai/k8sgpt/commit/1a81227d6148be59b7b9ae4e9ae5e2d9a5b7a9ae))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.275 ([#478](https://github.com/k8sgpt-ai/k8sgpt/issues/478)) ([705b54f](https://github.com/k8sgpt-ai/k8sgpt/commit/705b54fcd308ef1fc0bc870b5a0a32baa30767df))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.276 ([#482](https://github.com/k8sgpt-ai/k8sgpt/issues/482)) ([3f0aea1](https://github.com/k8sgpt-ai/k8sgpt/commit/3f0aea131e1e62655a10f6a51bf6238316dd6598))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.277 ([#485](https://github.com/k8sgpt-ai/k8sgpt/issues/485)) ([e2d5c2d](https://github.com/k8sgpt-ai/k8sgpt/commit/e2d5c2dee00e3411fa10bcaa4ae134b5671f45ab))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.280 ([#490](https://github.com/k8sgpt-ai/k8sgpt/issues/490)) ([04b4f56](https://github.com/k8sgpt-ai/k8sgpt/commit/04b4f56a667febf77c21838a618a1cd4a7f1e371))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.281 ([#496](https://github.com/k8sgpt-ai/k8sgpt/issues/496)) ([a6342c9](https://github.com/k8sgpt-ai/k8sgpt/commit/a6342c92830451e3110a54bac80a1b693984fcc8))
|
||||
* **deps:** update module golang.org/x/term to v0.9.0 ([#497](https://github.com/k8sgpt-ai/k8sgpt/issues/497)) ([98b852a](https://github.com/k8sgpt-ai/k8sgpt/commit/98b852aabe1ff62ac64e3c9e3e70173a8ff19749))
|
||||
* use the `status` for pdb checking ([#477](https://github.com/k8sgpt-ai/k8sgpt/issues/477)) ([075066d](https://github.com/k8sgpt-ai/k8sgpt/commit/075066dd7c353c0afd36637f421229cba5a6e022)), closes [#476](https://github.com/k8sgpt-ai/k8sgpt/issues/476)
|
||||
|
||||
|
||||
### Docs
|
||||
|
||||
* fix add localai command in readme.md ([#494](https://github.com/k8sgpt-ai/k8sgpt/issues/494)) ([40fbba7](https://github.com/k8sgpt-ai/k8sgpt/commit/40fbba7df1b2ce40c99262c901c7d2a26e9bbed0))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* customized prompt template for integration plugins ([#403](https://github.com/k8sgpt-ai/k8sgpt/issues/403)) ([c85203b](https://github.com/k8sgpt-ai/k8sgpt/commit/c85203bccde094c33ef83eb728aeed2608cbc136))
|
||||
* **deps:** update actions/checkout digest to c85c95e ([#492](https://github.com/k8sgpt-ai/k8sgpt/issues/492)) ([1ae21e6](https://github.com/k8sgpt-ai/k8sgpt/commit/1ae21e6fd46b8490ea012fa8176d741af2e71e7e))
|
||||
* **deps:** update docker/build-push-action digest to 44ea916 ([#491](https://github.com/k8sgpt-ai/k8sgpt/issues/491)) ([e556901](https://github.com/k8sgpt-ai/k8sgpt/commit/e556901b9d6205f75c819e1fbde51ba1f018e97d))
|
||||
* **deps:** update docker/setup-buildx-action digest to 6a58db7 ([#489](https://github.com/k8sgpt-ai/k8sgpt/issues/489)) ([a23276d](https://github.com/k8sgpt-ai/k8sgpt/commit/a23276d3ff740abc6d3b36a4c793d90387ecee08))
|
||||
* **deps:** update goreleaser/goreleaser-action digest to 336e299 ([#495](https://github.com/k8sgpt-ai/k8sgpt/issues/495)) ([ad2a5fd](https://github.com/k8sgpt-ai/k8sgpt/commit/ad2a5fd5fce78bf1bda4a48ad4a21598abadcdf4))
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* migrate api to grpc ([#386](https://github.com/k8sgpt-ai/k8sgpt/issues/386))
|
||||
|
||||
### Features
|
||||
|
||||
* add auth commands ([#369](https://github.com/k8sgpt-ai/k8sgpt/issues/369)) ([00aaae8](https://github.com/k8sgpt-ai/k8sgpt/commit/00aaae86d88812bd6b6be290ba440ea583ccc01c))
|
||||
* migrate api to grpc ([#386](https://github.com/k8sgpt-ai/k8sgpt/issues/386)) ([9998e76](https://github.com/k8sgpt-ai/k8sgpt/commit/9998e7620d2803b82b241482649449507040add3))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.9.3 ([#378](https://github.com/k8sgpt-ai/k8sgpt/issues/378)) ([045a063](https://github.com/k8sgpt-ai/k8sgpt/commit/045a06350bf41d4177e67316978af8fcf02ff19a))
|
||||
* **deps:** update module golang.org/x/term to v0.8.0 ([#382](https://github.com/k8sgpt-ai/k8sgpt/issues/382)) ([65fff11](https://github.com/k8sgpt-ai/k8sgpt/commit/65fff11e585f8074fb77124b25339a09da313970))
|
||||
|
||||
|
||||
### Docs
|
||||
|
||||
* update README ([#383](https://github.com/k8sgpt-ai/k8sgpt/issues/383)) ([d6bcb96](https://github.com/k8sgpt-ai/k8sgpt/commit/d6bcb96105a549eb772b790704c7ec27e374eafd))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* **deps:** update anchore/sbom-action action to v0.14.2 ([#387](https://github.com/k8sgpt-ai/k8sgpt/issues/387)) ([9192b26](https://github.com/k8sgpt-ai/k8sgpt/commit/9192b26fab2ce09c8a480256a15723ae788612c3))
|
||||
* fix the logo URL ([#384](https://github.com/k8sgpt-ai/k8sgpt/issues/384)) ([b6b0612](https://github.com/k8sgpt-ai/k8sgpt/commit/b6b06123db8914cae09dfa96edd92aff83823bdf))
|
||||
|
||||
## [0.2.9](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.2.8...v0.2.9) (2023-05-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add additionalLabels to Service Monitor ([#366](https://github.com/k8sgpt-ai/k8sgpt/issues/366)) ([a89a5cf](https://github.com/k8sgpt-ai/k8sgpt/commit/a89a5cfa2efd365cfc1c501c7055a315949c5f97))
|
||||
* add azure openai provider ([#309](https://github.com/k8sgpt-ai/k8sgpt/issues/309)) ([d8357ce](https://github.com/k8sgpt-ai/k8sgpt/commit/d8357ceb949e04d9dd21276a1d1dfcb60010c37a))
|
||||
* add helm chart ([#318](https://github.com/k8sgpt-ai/k8sgpt/issues/318)) ([5af8178](https://github.com/k8sgpt-ai/k8sgpt/commit/5af817880278771cf0b25d0936b90a45c089218c))
|
||||
* improving readme ([7471b76](https://github.com/k8sgpt-ai/k8sgpt/commit/7471b7679469bc7416ee35061a13e8442bfc532c))
|
||||
* rework output format ([#368](https://github.com/k8sgpt-ai/k8sgpt/issues/368)) ([8b49f70](https://github.com/k8sgpt-ai/k8sgpt/commit/8b49f708f364569994801757cf72982291c0de82))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update module github.com/aquasecurity/trivy-operator to v0.13.2 ([#353](https://github.com/k8sgpt-ai/k8sgpt/issues/353)) ([363294c](https://github.com/k8sgpt-ai/k8sgpt/commit/363294c310ca1a6666d4d2dcba7e232387f0d41f))
|
||||
* **deps:** update module github.com/prometheus/client_golang to v1.15.1 ([#374](https://github.com/k8sgpt-ai/k8sgpt/issues/374)) ([799869b](https://github.com/k8sgpt-ai/k8sgpt/commit/799869bcef76be0d5b2169646de106bd3b441c50))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.9.1 ([#363](https://github.com/k8sgpt-ai/k8sgpt/issues/363)) ([766a15b](https://github.com/k8sgpt-ai/k8sgpt/commit/766a15b25a2669b101c717013dae0ea4f5d0daa3))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.9.2 ([#375](https://github.com/k8sgpt-ai/k8sgpt/issues/375)) ([8b82d59](https://github.com/k8sgpt-ai/k8sgpt/commit/8b82d59bd7a6837a543467f9d76c66e70f267b85))
|
||||
* update CONTRIBUTING.md Slack URL ([#373](https://github.com/k8sgpt-ai/k8sgpt/issues/373)) ([e0200e7](https://github.com/k8sgpt-ai/k8sgpt/commit/e0200e7fa05597b52c9f25fc2e9b744aea764b9a))
|
||||
|
||||
|
||||
### Docs
|
||||
|
||||
* remove issue templates to use org wide ones ([#352](https://github.com/k8sgpt-ai/k8sgpt/issues/352)) ([3051b1c](https://github.com/k8sgpt-ai/k8sgpt/commit/3051b1ca343d739e48ff05c96468040adefc929a))
|
||||
* update README.md ([#356](https://github.com/k8sgpt-ai/k8sgpt/issues/356)) ([4e146fb](https://github.com/k8sgpt-ai/k8sgpt/commit/4e146fb152b79a43f3163a94389022b4325126d4))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* added changing banners ([#367](https://github.com/k8sgpt-ai/k8sgpt/issues/367)) ([4f6e833](https://github.com/k8sgpt-ai/k8sgpt/commit/4f6e833d3427adf82438186f52eee40293c50cd0))
|
||||
* **deps:** update golang docker tag to v1.20.4 ([#370](https://github.com/k8sgpt-ai/k8sgpt/issues/370)) ([9faa694](https://github.com/k8sgpt-ai/k8sgpt/commit/9faa69422dab812ec062c10a8fffb73160a3cd21))
|
||||
* **deps:** update reviewdog/action-golangci-lint digest to f5d8591 ([#362](https://github.com/k8sgpt-ai/k8sgpt/issues/362)) ([b8a5f3b](https://github.com/k8sgpt-ai/k8sgpt/commit/b8a5f3bab85e28f83259739958fe22ca0ada211a))
|
||||
* updated logo ([#365](https://github.com/k8sgpt-ai/k8sgpt/issues/365)) ([6431be7](https://github.com/k8sgpt-ai/k8sgpt/commit/6431be7771bd7c34d6beac14470bc6918b1793c4))
|
||||
|
||||
## [0.2.8](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.2.7...v0.2.8) (2023-04-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* don't ask for password if backend is localai ([74d9a75](https://github.com/k8sgpt-ai/k8sgpt/commit/74d9a750ca01361eb81fdcc91eb5886ecff1d17c))
|
||||
* introduce linter to run on PR builds ([#333](https://github.com/k8sgpt-ai/k8sgpt/issues/333)) ([252c734](https://github.com/k8sgpt-ai/k8sgpt/commit/252c7343106bf64c86861a9452e8618efc72881c)), closes [#330](https://github.com/k8sgpt-ai/k8sgpt/issues/330)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove dead code ([c29860d](https://github.com/k8sgpt-ai/k8sgpt/commit/c29860d418faa316bc167721e443f7b64eafd970))
|
||||
* report failure if network policy doesn't match any pods ([8adde6b](https://github.com/k8sgpt-ai/k8sgpt/commit/8adde6bf873b46f365146bc14fc4c8f46d82f8dc))
|
||||
* take `KUBECONFIG` env variable into consideration ([#340](https://github.com/k8sgpt-ai/k8sgpt/issues/340)) ([ee85d13](https://github.com/k8sgpt-ai/k8sgpt/commit/ee85d13d59e045519b087adaf55520acc2c205db)), closes [#331](https://github.com/k8sgpt-ai/k8sgpt/issues/331)
|
||||
* use a cache file name with a fixed size. ([#350](https://github.com/k8sgpt-ai/k8sgpt/issues/350)) ([dee4235](https://github.com/k8sgpt-ai/k8sgpt/commit/dee423519eb35f11c3e3a6dd64981e781899fe22))
|
||||
* use correct result slice for cronjob analyzer ([947e94f](https://github.com/k8sgpt-ai/k8sgpt/commit/947e94f35379712a2fb1e2a2c90636606e0e44b6))
|
||||
|
||||
|
||||
### Docs
|
||||
|
||||
* fix README ([#345](https://github.com/k8sgpt-ai/k8sgpt/issues/345)) ([f8fa35c](https://github.com/k8sgpt-ai/k8sgpt/commit/f8fa35cf9d591691679d6881fcc203e3411d99aa))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* add settings ([#351](https://github.com/k8sgpt-ai/k8sgpt/issues/351)) ([3af3667](https://github.com/k8sgpt-ai/k8sgpt/commit/3af366788fb47ff87be0142446c027f5a90491e7))
|
||||
* **deps:** pin dependencies ([#336](https://github.com/k8sgpt-ai/k8sgpt/issues/336)) ([125341b](https://github.com/k8sgpt-ai/k8sgpt/commit/125341bdaacbc8bedbb333e498dabfb5c72a24c0))
|
||||
* logo update ([#339](https://github.com/k8sgpt-ai/k8sgpt/issues/339)) ([d4dcc7a](https://github.com/k8sgpt-ai/k8sgpt/commit/d4dcc7a3991a861923c8115c0c82759b9e83bcfa))
|
||||
* update Apache2 license ([#342](https://github.com/k8sgpt-ai/k8sgpt/issues/342)) ([aca5806](https://github.com/k8sgpt-ai/k8sgpt/commit/aca58064c36b3bc13699e055a7cca8a493320078))
|
||||
* update README.md ([#346](https://github.com/k8sgpt-ai/k8sgpt/issues/346)) ([14a3537](https://github.com/k8sgpt-ai/k8sgpt/commit/14a3537ce9bc9d581b78329be899a66bc14db648))
|
||||
* updated banner ([#343](https://github.com/k8sgpt-ai/k8sgpt/issues/343)) ([0995e00](https://github.com/k8sgpt-ai/k8sgpt/commit/0995e008fe64f5978c3a0cc9fb4c525470f00dfa))
|
||||
|
||||
## [0.2.7](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.2.6...v0.2.7) (2023-04-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove pointer to loop variable when searching the latest event to analyze ([#328](https://github.com/k8sgpt-ai/k8sgpt/issues/328)) ([2616220](https://github.com/k8sgpt-ai/k8sgpt/commit/2616220935d450030c8a9f2f2741c3607aa4b663))
|
||||
|
||||
## [0.2.6](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.2.5...v0.2.6) (2023-04-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* explicitly pass in filter to async analysis go routine ([#326](https://github.com/k8sgpt-ai/k8sgpt/issues/326)) ([692cd06](https://github.com/k8sgpt-ai/k8sgpt/commit/692cd06c385c1c6f458994f6e975a9fce2bc1c57))
|
||||
|
||||
## [0.2.5](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.2.4...v0.2.5) (2023-04-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add configuration interface to support customer providers ([84a3cc0](https://github.com/k8sgpt-ai/k8sgpt/commit/84a3cc05fb6e21b732ef777351b42db8045e1093))
|
||||
* add k8sgpt grafana dashboard ([#316](https://github.com/k8sgpt-ai/k8sgpt/issues/316)) ([ff79982](https://github.com/k8sgpt-ai/k8sgpt/commit/ff799825cfe5856bb97c8f38d939ec36b19fa30a))
|
||||
* add serve & integration to README ([a65ee7f](https://github.com/k8sgpt-ai/k8sgpt/commit/a65ee7fc0957c7ba9369bdbe12e648818ca3f841))
|
||||
* add subproject group to CODEOWNERS ([#322](https://github.com/k8sgpt-ai/k8sgpt/issues/322)) ([2391603](https://github.com/k8sgpt-ai/k8sgpt/commit/2391603075e73b91d9988d40eecddfc3e0593405))
|
||||
* allow to set a baseurl ([#310](https://github.com/k8sgpt-ai/k8sgpt/issues/310)) ([cf797a6](https://github.com/k8sgpt-ai/k8sgpt/commit/cf797a6eb67efba957704077b4b04ed3ee166c24))
|
||||
* async calls ([#311](https://github.com/k8sgpt-ai/k8sgpt/issues/311)) ([c3cc413](https://github.com/k8sgpt-ai/k8sgpt/commit/c3cc413e7fc3b06b310779dfa3cb4863ea9f3ed2))
|
||||
* modify error handling to return a list of errors to display to the user at the end of analysis without blocking it if an error is detected (e.g., version of an object is not available on user's cluster) ([fa087ff](https://github.com/k8sgpt-ai/k8sgpt/commit/fa087ff5593871d2a07d68f203dd91e66c57e40b))
|
||||
* the overall optimization and architecture design of the makefile are made ([#317](https://github.com/k8sgpt-ai/k8sgpt/issues/317)) ([754bf91](https://github.com/k8sgpt-ai/k8sgpt/commit/754bf917e1ac524699d38fb2dc59bc5d858f6d80))
|
||||
* update readme ([#314](https://github.com/k8sgpt-ai/k8sgpt/issues/314)) ([ddd830c](https://github.com/k8sgpt-ai/k8sgpt/commit/ddd830cc569278c157480c44a671c9be20c95b24))
|
||||
* use OS conform path for storing cached results ([7eddb8f](https://github.com/k8sgpt-ai/k8sgpt/commit/7eddb8f4a6dc61d5f66fc1bf56c0e8cbf9370229)), closes [#323](https://github.com/k8sgpt-ai/k8sgpt/issues/323)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update module github.com/aquasecurity/trivy-operator to v0.13.1 ([#321](https://github.com/k8sgpt-ai/k8sgpt/issues/321)) ([e7f74db](https://github.com/k8sgpt-ai/k8sgpt/commit/e7f74db6e556146b898437bb777c2b803d1bec4f))
|
||||
* **deps:** update module github.com/prometheus/client_golang to v1.15.0 ([#303](https://github.com/k8sgpt-ai/k8sgpt/issues/303)) ([df2ed41](https://github.com/k8sgpt-ai/k8sgpt/commit/df2ed4185b5a33a18e6b144c85bec3902c14d209))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.9.0 ([#298](https://github.com/k8sgpt-ai/k8sgpt/issues/298)) ([0472c36](https://github.com/k8sgpt-ai/k8sgpt/commit/0472c363a4d8a90556bc744fbf513ad63281e38b))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* add serviceMonitor in sample yaml ([#304](https://github.com/k8sgpt-ai/k8sgpt/issues/304)) ([0a4ed0d](https://github.com/k8sgpt-ai/k8sgpt/commit/0a4ed0d907c22a924dd79e8945eb9d6d10cd9ce7))
|
||||
* analyze Pod ReadinessProbe faliure ([3c7e0bb](https://github.com/k8sgpt-ai/k8sgpt/commit/3c7e0bba1d4cc8247d248756dcfef884bc406992))
|
||||
* change license to Apache-2 ([#313](https://github.com/k8sgpt-ai/k8sgpt/issues/313)) ([d0f7a11](https://github.com/k8sgpt-ai/k8sgpt/commit/d0f7a1105fe7ed317785782d3af45c83766b7d80))
|
||||
|
||||
## [0.2.4](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.2.3...v0.2.4) (2023-04-18)
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ We're happy that you want to contribute to this project. Please read the section
|
||||
- We are also happy to help you find something to work on. Just reach out to us.
|
||||
|
||||
**Getting in touch with the community**
|
||||
* Join our [#k8sgpt slack channel](https://slack.cloud-native.io/channels/k8sgpt)
|
||||
* Join our [#k8sgpt slack channel](https://join.slack.com/t/k8sgpt/shared_invite/zt-1rwe5fpzq-VNtJK8DmYbbm~iWL1H34nw)
|
||||
* Introduce yourself on the slack channel or open an issue to let us know that you are interested in contributing
|
||||
|
||||
**Discuss issues**
|
||||
|
||||
215
LICENSE
@@ -1,21 +1,202 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Alex Jones
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
1. Definitions.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
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.
|
||||
167
Makefile
@@ -1,16 +1,157 @@
|
||||
.PHONY: docker-build
|
||||
# Copyright 2023 K8sgpt AI. All rights reserved.
|
||||
# Use of this source code is governed by a MIT style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
# ==============================================================================
|
||||
# define the default goal
|
||||
#
|
||||
ROOT_PACKAGE=github.com/k8sgpt-ai/k8sgpt
|
||||
|
||||
SHELL := /bin/bash
|
||||
DIRS=$(shell ls)
|
||||
GO=go
|
||||
GOOS ?= $(shell go env GOOS)
|
||||
GOARCH ?= $(shell go env GOARCH)
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
# include the common makefile
|
||||
COMMON_SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
|
||||
# ROOT_DIR: root directory of the code base
|
||||
ifeq ($(origin ROOT_DIR),undefined)
|
||||
ROOT_DIR := $(abspath $(shell cd $(COMMON_SELF_DIR)/. && pwd -P))
|
||||
endif
|
||||
# OUTPUT_DIR: The directory where the build output is stored.
|
||||
ifeq ($(origin OUTPUT_DIR),undefined)
|
||||
OUTPUT_DIR := $(ROOT_DIR)/bin
|
||||
$(shell mkdir -p $(OUTPUT_DIR))
|
||||
endif
|
||||
|
||||
ifeq ($(origin VERSION), undefined)
|
||||
VERSION := $(shell git describe --abbrev=0 --dirty --always --tags | sed 's/-/./g')
|
||||
endif
|
||||
|
||||
# Check if the tree is dirty. default to dirty(maybe u should commit?)
|
||||
GIT_TREE_STATE:="dirty"
|
||||
ifeq (, $(shell git status --porcelain 2>/dev/null))
|
||||
GIT_TREE_STATE="clean"
|
||||
endif
|
||||
GIT_COMMIT:=$(shell git rev-parse HEAD)
|
||||
|
||||
IMG ?= ghcr.io/k8sgpt-ai/k8sgpt:latest
|
||||
|
||||
deploy:
|
||||
ifndef SECRET
|
||||
$(error SECRET environment variable is not set)
|
||||
endif
|
||||
kubectl create ns k8sgpt || true
|
||||
kubectl create secret generic ai-backend-secret --from-literal=secret-key=$(SECRET) --namespace=k8sgpt || true
|
||||
kubectl apply -f container/manifests
|
||||
undeploy:
|
||||
kubectl delete secret ai-backend-secret --namespace=k8sgpt
|
||||
kubectl delete -f container/manifests
|
||||
kubectl delete ns k8sgpt
|
||||
BUILDFILE = "./main.go"
|
||||
BUILDAPP = "$(OUTPUT_DIR)/k8sgpt"
|
||||
|
||||
.PHONY: all
|
||||
all: tidy add-copyright lint cover build
|
||||
|
||||
# ==============================================================================
|
||||
# Targets
|
||||
|
||||
## build: Build binaries by default
|
||||
.PHONY: 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 -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
|
||||
tidy:
|
||||
@$(GO) mod tidy
|
||||
|
||||
## deploy: Deploy k8sgpt
|
||||
.PHONY: deploy
|
||||
deploy: helm
|
||||
@echo "===========> Deploying k8sgpt"
|
||||
$(HELM) install k8sgpt charts/k8sgpt -n k8sgpt --create-namespace
|
||||
|
||||
## update: Update k8sgpt
|
||||
.PHONY: update
|
||||
update: helm
|
||||
@echo "===========> Updating k8sgpt"
|
||||
$(HELM) upgrade k8sgpt charts/k8sgpt -n k8sgpt
|
||||
|
||||
## undeploy: Undeploy k8sgpt
|
||||
.PHONY: undeploy
|
||||
undeploy: helm
|
||||
@echo "===========> Undeploying k8sgpt"
|
||||
$(HELM) uninstall k8sgpt -n k8sgpt
|
||||
|
||||
## docker-build: Build docker image
|
||||
.PHONY: docker-build
|
||||
docker-build:
|
||||
docker buildx build --build-arg=VERSION="$$(git describe --tags --abbrev=0)" --build-arg=COMMIT="$$(git rev-parse --short HEAD)" --build-arg DATE="$$(date +%FT%TZ)" --platform="linux/amd64,linux/arm64" -t ${IMG} -f container/Dockerfile . --push
|
||||
@echo "===========> Building docker image"
|
||||
docker buildx build --build-arg=VERSION="$$(git describe --tags --abbrev=0)" --build-arg=COMMIT="$$(git rev-parse --short HEAD)" --build-arg DATE="$$(date +%FT%TZ)" --platform="linux/amd64,linux/arm64" -t ${IMG} -f container/Dockerfile . --push
|
||||
|
||||
## fmt: Run go fmt against code.
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
@$(GO) fmt ./...
|
||||
|
||||
## vet: Run go vet against code.
|
||||
.PHONY: vet
|
||||
vet:
|
||||
@$(GO) vet ./...
|
||||
|
||||
## lint: Run go lint against code.
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@golangci-lint run -v ./...
|
||||
|
||||
## style: Code style -> fmt,vet,lint
|
||||
.PHONY: style
|
||||
style: fmt vet lint
|
||||
|
||||
## test: Run unit test
|
||||
.PHONY: test
|
||||
test:
|
||||
@echo "===========> Run unit test"
|
||||
@$(GO) test ./...
|
||||
|
||||
## cover: Run unit test with coverage
|
||||
.PHONY: cover
|
||||
cover: test
|
||||
@$(GO) test -cover
|
||||
|
||||
## go.clean: Clean all builds
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "===========> Cleaning all builds OUTPUT_DIR($(OUTPUT_DIR))"
|
||||
@-rm -vrf $(OUTPUT_DIR)
|
||||
@echo "===========> End clean..."
|
||||
|
||||
## help: Show this help info.
|
||||
.PHONY: help
|
||||
help: Makefile
|
||||
@printf "\n\033[1mUsage: make <TARGETS> ...\033[0m\n\n\\033[1mTargets:\\033[0m\n\n"
|
||||
@sed -n 's/^##//p' $< | awk -F':' '{printf "\033[36m%-28s\033[0m %s\n", $$1, $$2}' | sed -e 's/^/ /'
|
||||
|
||||
## copyright.verify: Validate boilerplate headers for assign files
|
||||
.PHONY: copyright.verify
|
||||
copyright.verify: tools.verify.addlicense
|
||||
@echo "===========> Validate boilerplate headers for assign files starting in the $(ROOT_DIR) directory"
|
||||
# @addlicense -v -check -ignore **/test/** -f $(LICENSE_TEMPLATE) $(CODE_DIRS)
|
||||
@echo "===========> End of boilerplate headers check..."
|
||||
|
||||
## copyright.add: Add the boilerplate headers for all files
|
||||
.PHONY: copyright.add
|
||||
copyright.add: tools.verify.addlicense
|
||||
@echo "===========> Adding $(LICENSE_TEMPLATE) the boilerplate headers for all files"
|
||||
# @addlicense -y $(shell date +"%Y") -v -c "K8sgpt AI." -f $(LICENSE_TEMPLATE) $(CODE_DIRS)
|
||||
@echo "===========> End the copyright is added..."
|
||||
|
||||
# =====
|
||||
# Tools
|
||||
|
||||
HELM_VERSION ?= v3.11.3
|
||||
|
||||
helm:
|
||||
if ! test -f $(OUTPUT_DIR)/helm-$(GOOS)-$(GOARCH); then \
|
||||
curl -L https://get.helm.sh/helm-$(HELM_VERSION)-$(GOOS)-$(GOARCH).tar.gz | tar xz; \
|
||||
mv $(GOOS)-$(GOARCH)/helm $(OUTPUT_DIR)/helm-$(GOOS)-$(GOARCH); \
|
||||
chmod +x $(OUTPUT_DIR)/helm-$(GOOS)-$(GOARCH); \
|
||||
rm -rf ./$(GOOS)-$(GOARCH)/; \
|
||||
fi
|
||||
HELM=$(OUTPUT_DIR)/helm-$(GOOS)-$(GOARCH)
|
||||
327
README.md
@@ -7,6 +7,8 @@
|
||||

|
||||

|
||||

|
||||
[](https://bestpractices.coreinfrastructure.org/projects/7272)
|
||||
[](https://docs.k8sgpt.ai/)
|
||||
|
||||
`k8sgpt` is a tool for scanning your Kubernetes clusters, diagnosing, and triaging issues in simple English.
|
||||
|
||||
@@ -14,10 +16,12 @@ 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 gives Kubernetes Superpowers to everyone | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
|
||||
# Installation
|
||||
<img src="images/demo4.gif" width=650px; />
|
||||
|
||||
# CLI Installation
|
||||
|
||||
|
||||
## Linux/Mac via brew
|
||||
### Linux/Mac via brew
|
||||
|
||||
```
|
||||
brew tap k8sgpt-ai/k8sgpt
|
||||
@@ -30,7 +34,7 @@ brew install k8sgpt
|
||||
**32 bit:**
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.2.4/k8sgpt_386.rpm
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.9/k8sgpt_386.rpm
|
||||
sudo rpm -ivh k8sgpt_386.rpm
|
||||
```
|
||||
<!---x-release-please-end-->
|
||||
@@ -39,7 +43,7 @@ brew install k8sgpt
|
||||
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.2.4/k8sgpt_amd64.rpm
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.9/k8sgpt_amd64.rpm
|
||||
sudo rpm -ivh -i k8sgpt_amd64.rpm
|
||||
```
|
||||
<!---x-release-please-end-->
|
||||
@@ -51,7 +55,7 @@ brew install k8sgpt
|
||||
**32 bit:**
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.2.4/k8sgpt_386.deb
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.9/k8sgpt_386.deb
|
||||
sudo dpkg -i k8sgpt_386.deb
|
||||
```
|
||||
<!---x-release-please-end-->
|
||||
@@ -59,7 +63,7 @@ brew install k8sgpt
|
||||
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.2.4/k8sgpt_amd64.deb
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.9/k8sgpt_amd64.deb
|
||||
sudo dpkg -i k8sgpt_amd64.deb
|
||||
```
|
||||
<!---x-release-please-end-->
|
||||
@@ -72,14 +76,14 @@ brew install k8sgpt
|
||||
**32 bit:**
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.2.4/k8sgpt_386.apk
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.9/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.2.4/k8sgpt_amd64.apk
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.9/k8sgpt_amd64.apk
|
||||
apk add k8sgpt_amd64.apk
|
||||
```
|
||||
<!---x-release-please-end-->x
|
||||
@@ -102,30 +106,29 @@ If you install gcc as suggested, the problem will persist. Therefore, you need t
|
||||
</details>
|
||||
|
||||
|
||||
## Windows
|
||||
### Windows
|
||||
|
||||
* Download the latest Windows binaries of **k8sgpt** from the [Release](https://github.com/k8sgpt-ai/k8sgpt/releases)
|
||||
tab based on your system architecture.
|
||||
* Extract the downloaded package to your desired location. Configure the system *path* variable with the binary location
|
||||
|
||||
## Operator Installation
|
||||
|
||||
## Verify installation
|
||||
To install within a Kubernetes cluster please use our `k8sgpt-operator` with installation instructions available [here](https://github.com/k8sgpt-ai/k8sgpt-operator)
|
||||
|
||||
* Run `k8sgpt version`
|
||||
_This mode of operation is ideal for continuous monitoring of your cluster and can integrate with your existing monitoring such as Prometheus and Alertmanager._
|
||||
|
||||
<hr>
|
||||
|
||||
## Quick Start
|
||||
|
||||
* 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` 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
|
||||
|
||||
@@ -153,67 +156,15 @@ you will be able to write your own analyzers.
|
||||
- [x] pdbAnalyzer
|
||||
- [x] networkPolicyAnalyzer
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
Usage:
|
||||
k8sgpt [command]
|
||||
|
||||
Available Commands:
|
||||
analyze This command will find problems within your Kubernetes cluster
|
||||
auth Authenticate with your chosen backend
|
||||
completion Generate the autocompletion script for the specified shell
|
||||
filters Manage filters for analyzing Kubernetes resources
|
||||
generate Generate Key for your chosen backend (opens browser)
|
||||
help Help about any command
|
||||
version Print the version number of k8sgpt
|
||||
|
||||
Flags:
|
||||
--config string config file (default is $HOME/.k8sgpt.git.yaml)
|
||||
-h, --help help for k8sgpt
|
||||
--kubeconfig string Path to a kubeconfig. Only required if out-of-cluster.
|
||||
--master string The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.
|
||||
-t, --toggle Help message for toggle
|
||||
|
||||
Use "k8sgpt [command] --help" for more information about a command.
|
||||
```
|
||||
|
||||
_Manage filters_
|
||||
|
||||
_List filters_
|
||||
|
||||
```
|
||||
k8sgpt filters list
|
||||
```
|
||||
|
||||
_Add default filters_
|
||||
|
||||
```
|
||||
k8sgpt filters add [filter(s)]
|
||||
```
|
||||
|
||||
### Examples :
|
||||
|
||||
- Simple filter : `k8sgpt filters add Service`
|
||||
- Multiple filters : `k8sgpt filters add Ingress,Pod`
|
||||
|
||||
_Add default filters_
|
||||
|
||||
```
|
||||
k8sgpt filters remove [filter(s)]
|
||||
```
|
||||
|
||||
### Examples :
|
||||
|
||||
- Simple filter : `k8sgpt filters remove Service`
|
||||
- Multiple filters : `k8sgpt filters remove Ingress,Pod`
|
||||
## Examples
|
||||
|
||||
_Run a scan with the default analyzers_
|
||||
|
||||
```
|
||||
k8sgpt generate
|
||||
k8sgpt auth
|
||||
k8sgpt auth add
|
||||
k8sgpt analyze --explain
|
||||
k8sgpt analyze --explain --with-doc
|
||||
```
|
||||
|
||||
_Filter on resource_
|
||||
@@ -239,12 +190,190 @@ _Anonymize during explain_
|
||||
k8sgpt analyze --explain --filter=Service --output=json --anonymize
|
||||
```
|
||||
|
||||
### How does anonymization work?
|
||||
<details>
|
||||
<summary> Using filters </summary>
|
||||
|
||||
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.
|
||||
_List filters_
|
||||
|
||||
```
|
||||
k8sgpt filters list
|
||||
```
|
||||
|
||||
_Add default filters_
|
||||
|
||||
```
|
||||
k8sgpt filters add [filter(s)]
|
||||
```
|
||||
|
||||
### Examples :
|
||||
|
||||
- Simple filter : `k8sgpt filters add Service`
|
||||
- Multiple filters : `k8sgpt filters add Ingress,Pod`
|
||||
|
||||
_Remove default filters_
|
||||
|
||||
```
|
||||
k8sgpt filters remove [filter(s)]
|
||||
```
|
||||
|
||||
### Examples :
|
||||
|
||||
- Simple filter : `k8sgpt filters remove Service`
|
||||
- Multiple filters : `k8sgpt filters remove Ingress,Pod`
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary> Additional commands </summary>
|
||||
|
||||
_List configured backends_
|
||||
|
||||
```
|
||||
k8sgpt auth list
|
||||
```
|
||||
|
||||
_Update configured backends_
|
||||
|
||||
```
|
||||
k8sgpt auth update $MY_BACKEND1,$MY_BACKEND2..
|
||||
```
|
||||
|
||||
_Remove configured backends_
|
||||
|
||||
```
|
||||
k8sgpt auth remove $MY_BACKEND1,$MY_BACKEND2..
|
||||
```
|
||||
|
||||
_List integrations_
|
||||
|
||||
```
|
||||
k8sgpt integrations list
|
||||
```
|
||||
|
||||
_Activate integrations_
|
||||
|
||||
```
|
||||
k8sgpt integrations activate [integration(s)]
|
||||
```
|
||||
|
||||
_Use integration_
|
||||
|
||||
```
|
||||
k8sgpt analyze --filter=[integration(s)]
|
||||
```
|
||||
|
||||
_Deactivate integrations_
|
||||
|
||||
```
|
||||
k8sgpt integrations deactivate [integration(s)]
|
||||
```
|
||||
|
||||
_Serve mode_
|
||||
|
||||
```
|
||||
k8sgpt serve
|
||||
```
|
||||
|
||||
_Analysis with serve mode_
|
||||
|
||||
```
|
||||
curl -X GET "http://localhost:8080/analyze?namespace=k8sgpt&explain=false"
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
## 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).
|
||||
|
||||
### Start the API server
|
||||
|
||||
To start the API server, follow the instruction in [LocalAI](https://github.com/go-skynet/LocalAI#example-use-gpt4all-j-model).
|
||||
|
||||
### Run k8sgpt
|
||||
|
||||
To run k8sgpt, run `k8sgpt auth add` with the `localai` backend:
|
||||
|
||||
```
|
||||
k8sgpt auth add --backend localai --model <model_name> --baseurl http://localhost:8080/v1
|
||||
```
|
||||
|
||||
Now you can analyze with the `localai` backend:
|
||||
|
||||
```
|
||||
k8sgpt analyze --explain --backend localai
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
<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.
|
||||
@@ -269,32 +398,48 @@ The Kubernetes system is trying to scale a StatefulSet named fake-deployment usi
|
||||
|
||||
</details>
|
||||
|
||||
## Upcoming major milestones
|
||||
|
||||
- [ ] Multiple AI backend support
|
||||
- [ ] Custom AI/ML model backend support
|
||||
- [ ] Custom analyzers
|
||||
|
||||
## What about kubectl-ai?
|
||||
|
||||
The kubectl-ai [project](https://github.com/sozercan/kubectl-ai) uses AI to create manifests and apply them to the
|
||||
cluster. It is not what we are trying to do here, it is focusing on writing YAML manifests.
|
||||
|
||||
K8sgpt is focused on triaging and diagnosing issues in your cluster. It is a tool for SRE, Platform & DevOps engineers
|
||||
to help them understand what is going on in their cluster. Cutting through the noise of logs and multiple tools to find
|
||||
the root cause of an issue.
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
6
charts/k8sgpt/Chart.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
appVersion: v0.3.0 #x-release-please-version
|
||||
description: A Helm chart for K8SGPT
|
||||
name: k8sgpt
|
||||
type: application
|
||||
version: 1.0.0
|
||||
44
charts/k8sgpt/templates/_helpers.tpl
Normal file
@@ -0,0 +1,44 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "k8sgpt.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "k8sgpt.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "k8sgpt.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "k8sgpt.labels" -}}
|
||||
helm.sh/chart: {{ include "k8sgpt.chart" . }}
|
||||
app.kubernetes.io/name: {{ include "k8sgpt.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
57
charts/k8sgpt/templates/deployment.yaml
Normal file
@@ -0,0 +1,57 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "k8sgpt.fullname" . }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
{{- if .Values.deployment.annotations }}
|
||||
annotations:
|
||||
{{- toYaml .Values.deployment.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "k8sgpt.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "k8sgpt.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "k8sgpt.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
serviceAccountName: {{ template "k8sgpt.fullname" . }}
|
||||
containers:
|
||||
- name: k8sgpt-container
|
||||
imagePullPolicy: {{ .Values.deployment.imagePullPolicy }}
|
||||
image: {{ .Values.deployment.image.repository }}:{{ .Values.deployment.image.tag | default .Chart.AppVersion }}
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
args: ["serve"]
|
||||
{{- if .Values.deployment.resources }}
|
||||
resources:
|
||||
{{- toYaml .Values.deployment.resources | nindent 10 }}
|
||||
{{- end }}
|
||||
env:
|
||||
- name: K8SGPT_MODEL
|
||||
value: {{ .Values.deployment.env.model }}
|
||||
- name: K8SGPT_BACKEND
|
||||
value: {{ .Values.deployment.env.backend }}
|
||||
{{- if .Values.secret.secretKey }}
|
||||
- name: K8SGPT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ai-backend-secret
|
||||
key: secret-key
|
||||
{{- end }}
|
||||
- name: XDG_CONFIG_HOME
|
||||
value: /k8sgpt-config/
|
||||
- name: XDG_CACHE_HOME
|
||||
value: /k8sgpt-config/
|
||||
volumeMounts:
|
||||
- mountPath: /k8sgpt-config
|
||||
name: config
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: config
|
||||
@@ -1,7 +1,10 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: k8sgpt-cluster-role-all
|
||||
name: {{ template "k8sgpt.fullname" . }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
labels:
|
||||
{{- include "k8sgpt.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
15
charts/k8sgpt/templates/rolebinding.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ template "k8sgpt.fullname" . }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
labels:
|
||||
{{- include "k8sgpt.labels" . | nindent 4 }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ template "k8sgpt.fullname" . }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: {{ template "k8sgpt.fullname" . }}
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
7
charts/k8sgpt/templates/sa.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ template "k8sgpt.fullname" . }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
labels:
|
||||
{{- include "k8sgpt.labels" . | nindent 4 }}
|
||||
10
charts/k8sgpt/templates/secret.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
{{- if .Values.secret.secretKey }}
|
||||
apiVersion: v1
|
||||
data:
|
||||
secret-key: {{ .Values.secret.secretKey }}
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ai-backend-secret
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
type: Opaque
|
||||
{{- end}}
|
||||
22
charts/k8sgpt/templates/service.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "k8sgpt.fullname" . }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
labels:
|
||||
{{- include "k8sgpt.labels" . | nindent 4 }}
|
||||
{{- if .Values.service.annotations }}
|
||||
annotations:
|
||||
{{- toYaml .Values.service.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "k8sgpt.name" . }}
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
- name: metrics
|
||||
port: 8081
|
||||
targetPort: 8081
|
||||
type: {{ .Values.service.type }}
|
||||
21
charts/k8sgpt/templates/serviceMonitor.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
{{- if .Values.serviceMonitor.enabled }}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "k8sgpt.fullname" . }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
labels:
|
||||
{{- include "k8sgpt.labels" . | nindent 4 }}
|
||||
{{- if .Values.serviceMonitor.additionalLabels }}
|
||||
{{- toYaml .Values.serviceMonitor.additionalLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
endpoints:
|
||||
- honorLabels: true
|
||||
path: /metrics
|
||||
port: metrics
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "k8sgpt.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
27
charts/k8sgpt/values.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
deployment:
|
||||
image:
|
||||
repository: ghcr.io/k8sgpt-ai/k8sgpt
|
||||
tag: "" # defaults to Chart.appVersion if unspecified
|
||||
imagePullPolicy: Always
|
||||
annotations: {}
|
||||
env:
|
||||
model: "gpt-3.5-turbo"
|
||||
backend: "openai" # one of: [ openai | llama ]
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: "512Mi"
|
||||
requests:
|
||||
cpu: "0.2"
|
||||
memory: "156Mi"
|
||||
|
||||
secret:
|
||||
secretKey: "" # base64 encoded OpenAI token
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
annotations: {}
|
||||
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
additionalLabels: {}
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyze
|
||||
|
||||
import (
|
||||
@@ -10,14 +23,16 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
explain bool
|
||||
backend string
|
||||
output string
|
||||
filters []string
|
||||
language string
|
||||
nocache bool
|
||||
namespace string
|
||||
anonymize bool
|
||||
explain bool
|
||||
backend string
|
||||
output string
|
||||
filters []string
|
||||
language string
|
||||
nocache bool
|
||||
namespace string
|
||||
anonymize bool
|
||||
maxConcurrency int
|
||||
withDoc bool
|
||||
)
|
||||
|
||||
// AnalyzeCmd represents the problems command
|
||||
@@ -30,17 +45,14 @@ var AnalyzeCmd = &cobra.Command{
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// AnalysisResult configuration
|
||||
config, err := analysis.NewAnalysis(backend, language, filters, namespace, nocache, explain)
|
||||
config, err := analysis.NewAnalysis(backend,
|
||||
language, filters, namespace, nocache, explain, maxConcurrency, withDoc)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = config.RunAnalysis()
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
config.RunAnalysis()
|
||||
|
||||
if explain {
|
||||
err := config.GetAIResults(output, anonymize)
|
||||
@@ -78,4 +90,8 @@ func init() {
|
||||
AnalyzeCmd.Flags().StringVarP(&output, "output", "o", "text", "Output format (text, json)")
|
||||
// add language options for output
|
||||
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")
|
||||
}
|
||||
|
||||
126
cmd/auth/add.go
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
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 (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
var addCmd = &cobra.Command{
|
||||
Use: "add",
|
||||
Short: "Add new provider",
|
||||
Long: "The add 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")
|
||||
}
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// get ai configuration
|
||||
err := viper.UnmarshalKey("ai", &configAI)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// search for provider with same name
|
||||
providerIndex := -1
|
||||
for i, provider := range configAI.Providers {
|
||||
if backend == provider.Name {
|
||||
providerIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
validBackend := func(validBackends []string, backend string) bool {
|
||||
for _, b := range validBackends {
|
||||
if b == backend {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// check if backend is not empty and a valid value
|
||||
if backend == "" || !validBackend(ai.Backends, backend) {
|
||||
color.Red("Error: Backend AI cannot be empty and accepted values are '%v'", strings.Join(ai.Backends, ", "))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// check if model is not empty
|
||||
if model == "" {
|
||||
color.Red("Error: Model cannot be empty.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if ai.NeedPassword(backend) && password == "" {
|
||||
fmt.Printf("Enter %s Key: ", backend)
|
||||
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
color.Red("Error reading %s Key from stdin: %s", backend,
|
||||
err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
password = strings.TrimSpace(string(bytePassword))
|
||||
}
|
||||
|
||||
// create new provider object
|
||||
newProvider := ai.AIProvider{
|
||||
Name: backend,
|
||||
Model: model,
|
||||
Password: password,
|
||||
BaseURL: baseURL,
|
||||
Engine: engine,
|
||||
}
|
||||
|
||||
if providerIndex == -1 {
|
||||
// provider with same name does not exist, add new provider to list
|
||||
configAI.Providers = append(configAI.Providers, newProvider)
|
||||
viper.Set("ai", configAI)
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
color.Red("Error writing config file: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
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.")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// add flag for backend
|
||||
addCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
|
||||
// add flag for model
|
||||
addCmd.Flags().StringVarP(&model, "model", "m", "gpt-3.5-turbo", "Backend AI model")
|
||||
// add flag for password
|
||||
addCmd.Flags().StringVarP(&password, "password", "p", "", "Backend AI password")
|
||||
// add flag for url
|
||||
addCmd.Flags().StringVarP(&baseURL, "baseurl", "u", "", "URL AI provider, (e.g `http://localhost:8080/v1`)")
|
||||
// add flag for azure open ai engine/deployment name
|
||||
addCmd.Flags().StringVarP(&engine, "engine", "e", "", "Azure AI deployment name")
|
||||
}
|
||||
108
cmd/auth/auth.go
@@ -1,103 +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 auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
var (
|
||||
backend string
|
||||
password string
|
||||
baseURL string
|
||||
model string
|
||||
engine string
|
||||
)
|
||||
|
||||
var configAI ai.AIConfiguration
|
||||
|
||||
// authCmd represents the auth command
|
||||
var AuthCmd = &cobra.Command{
|
||||
Use: "auth",
|
||||
Short: "Authenticate with your chosen backend",
|
||||
Long: `Provide the necessary credentials to authenticate with your chosen backend.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// get ai configuration
|
||||
var configAI ai.AIConfiguration
|
||||
err := viper.UnmarshalKey("ai", &configAI)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
if len(args) == 0 {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
|
||||
// search for provider with same name
|
||||
providerIndex := -1
|
||||
for i, provider := range configAI.Providers {
|
||||
if backend == provider.Name {
|
||||
providerIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// check if backend is not empty
|
||||
if backend == "" {
|
||||
color.Red("Error: Backend AI cannot be empty.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
color.Green("Using %s as backend AI provider", backend)
|
||||
|
||||
// check if model is not empty
|
||||
if model == "" {
|
||||
color.Red("Error: Model cannot be empty.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if password == "" {
|
||||
fmt.Printf("Enter %s Key: ", backend)
|
||||
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
color.Red("Error reading %s Key from stdin: %s", backend,
|
||||
err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
password = strings.TrimSpace(string(bytePassword))
|
||||
}
|
||||
|
||||
// create new provider object
|
||||
newProvider := ai.AIProvider{
|
||||
Name: backend,
|
||||
Model: model,
|
||||
Password: password,
|
||||
}
|
||||
|
||||
if providerIndex == -1 {
|
||||
// provider with same name does not exist, add new provider to list
|
||||
configAI.Providers = append(configAI.Providers, newProvider)
|
||||
color.Green("New provider added")
|
||||
} else {
|
||||
// provider with same name exists, update provider info
|
||||
configAI.Providers[providerIndex] = newProvider
|
||||
color.Green("Provider updated")
|
||||
}
|
||||
viper.Set("ai", configAI)
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
color.Red("Error writing config file: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
color.Green("key added")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// add flag for backend
|
||||
AuthCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
|
||||
// add flag for model
|
||||
AuthCmd.Flags().StringVarP(&model, "model", "m", "gpt-3.5-turbo", "Backend AI model")
|
||||
// add flag for password
|
||||
AuthCmd.Flags().StringVarP(&password, "password", "p", "", "Backend AI password")
|
||||
// add subcommand to list backends
|
||||
AuthCmd.AddCommand(listCmd)
|
||||
// add subcommand to create new backend provider
|
||||
AuthCmd.AddCommand(addCmd)
|
||||
// add subcommand to remove new backend provider
|
||||
AuthCmd.AddCommand(removeCmd)
|
||||
// add subcommand to set default backend provider
|
||||
AuthCmd.AddCommand(defaultCmd)
|
||||
// add subcommand to update backend provider
|
||||
AuthCmd.AddCommand(updateCmd)
|
||||
}
|
||||
|
||||
79
cmd/auth/default.go
Normal 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")
|
||||
}
|
||||
120
cmd/auth/list.go
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
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 (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var details bool
|
||||
var userInput string
|
||||
|
||||
var listCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List configured providers",
|
||||
Long: "The list command displays a list of configured providers",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// get ai configuration
|
||||
err := viper.UnmarshalKey("ai", &configAI)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if details {
|
||||
fmt.Println("Show password ? (y/n)")
|
||||
fmt.Scan(&userInput)
|
||||
}
|
||||
|
||||
// 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 them 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))
|
||||
if details {
|
||||
for _, provider := range configAI.Providers {
|
||||
if provider.Name == aiBackend {
|
||||
printDetails(provider, userInput)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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))
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
listCmd.Flags().BoolVar(&details, "details", false, "Print active provider configuration details")
|
||||
}
|
||||
|
||||
func printDetails(provider ai.AIProvider, userInput string) {
|
||||
if provider.Model != "" {
|
||||
fmt.Printf(" - Model: %s\n", provider.Model)
|
||||
}
|
||||
switch userInput {
|
||||
case "y":
|
||||
if provider.Password != "" {
|
||||
fmt.Printf(" - Password: %s\n", provider.Password)
|
||||
}
|
||||
case "n":
|
||||
if provider.Password != "" {
|
||||
nc := utf8.RuneCountInString(provider.Password)
|
||||
newStr := strings.Repeat("*", nc)
|
||||
fmt.Printf(" - Password: %s\n", newStr)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
if provider.Engine != "" {
|
||||
fmt.Printf(" - Engine: %s\n", provider.Engine)
|
||||
}
|
||||
if provider.BaseURL != "" {
|
||||
fmt.Printf(" - BaseURL: %s\n", provider.BaseURL)
|
||||
}
|
||||
}
|
||||
69
cmd/auth/remove.go
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
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:]...)
|
||||
if configAI.DefaultProvider == b {
|
||||
configAI.DefaultProvider = "openai"
|
||||
}
|
||||
color.Green("%s deleted from 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)
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
106
cmd/auth/update.go
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
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 updateCmd = &cobra.Command{
|
||||
Use: "update",
|
||||
Short: "Update a backend provider",
|
||||
Long: "The command to update an AI backend provider",
|
||||
Args: cobra.ExactArgs(1),
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
backend, _ := cmd.Flags().GetString("backend")
|
||||
if strings.ToLower(backend) == "azureopenai" {
|
||||
_ = cmd.MarkFlagRequired("engine")
|
||||
_ = cmd.MarkFlagRequired("baseurl")
|
||||
}
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// get ai configuration
|
||||
err := viper.UnmarshalKey("ai", &configAI)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
inputBackends := strings.Split(args[0], ",")
|
||||
|
||||
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
|
||||
if backend != "" {
|
||||
configAI.Providers[i].Name = backend
|
||||
color.Blue("Backend name updated successfully")
|
||||
}
|
||||
if model != "" {
|
||||
configAI.Providers[i].Model = model
|
||||
color.Blue("Model updated successfully")
|
||||
}
|
||||
if password != "" {
|
||||
configAI.Providers[i].Password = password
|
||||
color.Blue("Password updated successfully")
|
||||
}
|
||||
if baseURL != "" {
|
||||
configAI.Providers[i].BaseURL = baseURL
|
||||
color.Blue("Base URL updated successfully")
|
||||
}
|
||||
if engine != "" {
|
||||
configAI.Providers[i].Engine = engine
|
||||
}
|
||||
color.Green("%s updated in the AI backend provider list", b)
|
||||
}
|
||||
}
|
||||
if !foundBackend {
|
||||
color.Red("Error: %s does not exist in configuration file. Please use k8sgpt auth new.", args[0])
|
||||
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() {
|
||||
// update flag for backend
|
||||
updateCmd.Flags().StringVarP(&backend, "backend", "b", "", "Update backend AI provider")
|
||||
// update flag for model
|
||||
updateCmd.Flags().StringVarP(&model, "model", "m", "", "Update backend AI model")
|
||||
// update flag for password
|
||||
updateCmd.Flags().StringVarP(&password, "password", "p", "", "Update backend AI password")
|
||||
// update flag for url
|
||||
updateCmd.Flags().StringVarP(&baseURL, "baseurl", "u", "", "Update URL AI provider, (e.g `http://localhost:8080/v1`)")
|
||||
// update flag for azure open ai engine/deployment name
|
||||
updateCmd.Flags().StringVarP(&engine, "engine", "e", "", "Update Azure AI deployment name")
|
||||
}
|
||||
54
cmd/cache/add.go
vendored
Normal 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(®ion, "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
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 filters
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 filters
|
||||
|
||||
import (
|
||||
@@ -12,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
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 filters
|
||||
|
||||
import (
|
||||
@@ -24,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
|
||||
@@ -37,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) {
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 filters
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 generate
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
/*
|
||||
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 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"
|
||||
)
|
||||
|
||||
var (
|
||||
skipInstall bool
|
||||
)
|
||||
|
||||
// activateCmd represents the activate command
|
||||
@@ -14,10 +33,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, skipInstall)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
return
|
||||
@@ -29,5 +55,6 @@ var activateCmd = &cobra.Command{
|
||||
|
||||
func init() {
|
||||
IntegrationCmd.AddCommand(activateCmd)
|
||||
activateCmd.Flags().BoolVarP(&skipInstall, "no-install", "s", false, "Only activate the integration filter without installing the filter (for example, if that filter plugin is already deployed in cluster, we do not need to re-install it again)")
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||
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 integration
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 integration
|
||||
|
||||
import (
|
||||
@@ -12,14 +25,14 @@ var (
|
||||
var IntegrationCmd = &cobra.Command{
|
||||
Use: "integration",
|
||||
Aliases: []string{"integrations"},
|
||||
Short: "Intergrate another tool into K8sGPT",
|
||||
Long: `Intergrate another tool into K8sGPT. For example:
|
||||
Short: "Integrate another tool into K8sGPT",
|
||||
Long: `Integrate another tool into K8sGPT. For example:
|
||||
|
||||
k8sgpt integration activate trivy
|
||||
|
||||
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()
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 integration
|
||||
|
||||
import (
|
||||
|
||||
50
cmd/root.go
@@ -1,28 +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 cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/cmd/serve"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
"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"
|
||||
"github.com/k8sgpt-ai/k8sgpt/cmd/serve"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/client-go/util/homedir"
|
||||
)
|
||||
|
||||
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
|
||||
@@ -37,8 +52,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)
|
||||
@@ -50,19 +67,16 @@ func init() {
|
||||
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
var kubeconfigPath string
|
||||
if home := homedir.HomeDir(); home != "" {
|
||||
kubeconfigPath = filepath.Join(home, ".kube", "config")
|
||||
}
|
||||
rootCmd.AddCommand(auth.AuthCmd)
|
||||
rootCmd.AddCommand(analyze.AnalyzeCmd)
|
||||
rootCmd.AddCommand(filters.FiltersCmd)
|
||||
rootCmd.AddCommand(generate.GenerateCmd)
|
||||
rootCmd.AddCommand(integration.IntegrationCmd)
|
||||
rootCmd.AddCommand(serve.ServeCmd)
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.k8sgpt.yaml)")
|
||||
rootCmd.AddCommand(cache.CacheCmd)
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", fmt.Sprintf("Default config file (%s/k8sgpt/k8sgpt.yaml)", xdg.ConfigHome))
|
||||
rootCmd.PersistentFlags().StringVar(&kubecontext, "kubecontext", "", "Kubernetes context to use. Only required if out-of-cluster.")
|
||||
rootCmd.PersistentFlags().StringVar(&kubeconfig, "kubeconfig", kubeconfigPath, "Path to a kubeconfig. Only required if out-of-cluster.")
|
||||
rootCmd.PersistentFlags().StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
@@ -78,7 +92,7 @@ func initConfig() {
|
||||
viper.SetConfigType("yaml")
|
||||
viper.SetConfigName("k8sgpt")
|
||||
|
||||
viper.SafeWriteConfig()
|
||||
_ = viper.SafeWriteConfig()
|
||||
}
|
||||
|
||||
viper.Set("kubecontext", kubecontext)
|
||||
@@ -89,6 +103,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())
|
||||
}
|
||||
}
|
||||
@@ -107,14 +122,7 @@ func performConfigMigrationIfNeeded() {
|
||||
err = util.EnsureDirExists(configDir)
|
||||
cobra.CheckErr(err)
|
||||
|
||||
if oldConfigExists && newConfigExists {
|
||||
fmt.Fprintln(os.Stderr, color.RedString("Warning: Legacy config file at `%s` detected! This file will be ignored!", oldConfig))
|
||||
return
|
||||
}
|
||||
|
||||
if oldConfigExists && !newConfigExists {
|
||||
fmt.Fprintln(os.Stderr, color.RedString("Performing config file migration from `%s` to `%s`", oldConfig, newConfig))
|
||||
|
||||
err = os.Rename(oldConfig, newConfig)
|
||||
cobra.CheckErr(err)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 serve
|
||||
|
||||
import (
|
||||
@@ -8,12 +21,13 @@ import (
|
||||
k8sgptserver "github.com/k8sgpt-ai/k8sgpt/pkg/server"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
port string
|
||||
backend string
|
||||
token string
|
||||
port string
|
||||
metricsPort string
|
||||
backend string
|
||||
)
|
||||
|
||||
var ServeCmd = &cobra.Command{
|
||||
@@ -34,13 +48,18 @@ var ServeCmd = &cobra.Command{
|
||||
backend = os.Getenv("K8SGPT_BACKEND")
|
||||
password := os.Getenv("K8SGPT_PASSWORD")
|
||||
model := os.Getenv("K8SGPT_MODEL")
|
||||
// If the envs are set, alocate in place to the aiProvider
|
||||
baseURL := os.Getenv("K8SGPT_BASEURL")
|
||||
engine := os.Getenv("K8SGPT_ENGINE")
|
||||
// If the envs are set, allocate in place to the aiProvider
|
||||
// else exit with error
|
||||
if backend != "" || password != "" || model != "" {
|
||||
envIsSet := backend != "" || password != "" || model != ""
|
||||
if envIsSet {
|
||||
aiProvider = &ai.AIProvider{
|
||||
Name: backend,
|
||||
Password: password,
|
||||
Model: model,
|
||||
BaseURL: baseURL,
|
||||
Engine: engine,
|
||||
}
|
||||
|
||||
configAI.Providers = append(configAI.Providers, *aiProvider)
|
||||
@@ -58,7 +77,11 @@ var ServeCmd = &cobra.Command{
|
||||
if aiProvider == nil {
|
||||
for _, provider := range configAI.Providers {
|
||||
if backend == provider.Name {
|
||||
aiProvider = &provider
|
||||
// the pointer to the range variable is not really an issue here, as there
|
||||
// is a break right after, but to prevent potential future issues, a temp
|
||||
// variable is assigned
|
||||
p := provider
|
||||
aiProvider = &p
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -69,23 +92,42 @@ var ServeCmd = &cobra.Command{
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
server := k8sgptserver.Config{
|
||||
Backend: aiProvider.Name,
|
||||
Port: port,
|
||||
Token: aiProvider.Password,
|
||||
}
|
||||
|
||||
err = server.Serve()
|
||||
logger, err := zap.NewProduction()
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
color.Red("failed to create logger: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
// override the default backend if a flag is provided
|
||||
defer logger.Sync()
|
||||
|
||||
server := k8sgptserver.Config{
|
||||
Backend: aiProvider.Name,
|
||||
Port: port,
|
||||
MetricsPort: metricsPort,
|
||||
Token: aiProvider.Password,
|
||||
Logger: logger,
|
||||
}
|
||||
go func() {
|
||||
if err := server.ServeMetrics(); err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
if err := server.Serve(); err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for both servers to exit
|
||||
select {}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// add flag for backend
|
||||
ServeCmd.Flags().StringVarP(&port, "port", "p", "8080", "Port to run the server on")
|
||||
ServeCmd.Flags().StringVarP(&metricsPort, "metrics-port", "", "8081", "Port to run the metrics-server on")
|
||||
ServeCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
/*
|
||||
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 cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -10,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)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
FROM golang:1.20.3-alpine3.16 AS builder
|
||||
# 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.
|
||||
|
||||
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 ./
|
||||
@@ -9,15 +22,15 @@ 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
|
||||
|
||||
LABEL org.opencontainers.image.source="https://github.com/k8sgpt-ai/k8sgpt" \
|
||||
org.opencontainers.image.url="https://k8sgpt.ai" \
|
||||
org.opencontainers.image.title="k8sgpt" \
|
||||
org.opencontainers.image.vendor="the k8sgpt-ai maintainers" \
|
||||
org.opencontainers.image.licenses="MIT"
|
||||
org.opencontainers.image.vendor='The K8sGPT Authors' \
|
||||
org.opencontainers.image.licenses='Apache-2.0'
|
||||
|
||||
WORKDIR /
|
||||
COPY --from=builder /workspace/k8sgpt .
|
||||
|
||||
463
container/dashboards/k8sgpt-dashboard.json
Normal file
@@ -0,0 +1,463 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": {
|
||||
"limit": 100,
|
||||
"matchAny": false,
|
||||
"tags": [],
|
||||
"type": "dashboard"
|
||||
},
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "",
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": 27,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 2,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 8,
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"pluginVersion": "9.4.7",
|
||||
"transparent": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 3,
|
||||
"x": 2,
|
||||
"y": 0
|
||||
},
|
||||
"id": 10,
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "Useful links\n- [Website](https://k8sgpt.ai/)\n- [Documentation](https://docs.k8sgpt.ai/)\n- [GitHub](https://github.com/k8sgpt-ai)",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"pluginVersion": "9.4.7",
|
||||
"transparent": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "Total number of errors",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "none"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 7,
|
||||
"x": 5,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showThresholdLabels": true,
|
||||
"showThresholdMarkers": true
|
||||
},
|
||||
"pluginVersion": "9.4.7",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(analyzer_errors{namespace=~\"$namespace\"})",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Errors",
|
||||
"type": "gauge"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "Total number of errors per analyzer",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"displayName": "${__field.labels.analyzer_name}",
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "none"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"minVizHeight": 10,
|
||||
"minVizWidth": 0,
|
||||
"orientation": "horizontal",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showUnfilled": true
|
||||
},
|
||||
"pluginVersion": "9.4.7",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (analyzer_name) (analyzer_errors{namespace=~\"$namespace\"})",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Errors per analyzer",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "Total number of errors time series",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "none"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "9.4.7",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum (analyzer_errors{namespace=~\"$namespace\"})",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Errors",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "Total number of errors per analyzer time series",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineStyle": {
|
||||
"fill": "solid"
|
||||
},
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "none"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "right",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "9.4.7",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (analyzer_name) (analyzer_errors{namespace=~\"$namespace\"})",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Errors per analyzer",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"revision": 1,
|
||||
"schemaVersion": 38,
|
||||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {
|
||||
"selected": true,
|
||||
"text": [
|
||||
"All"
|
||||
],
|
||||
"value": [
|
||||
"$__all"
|
||||
]
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"definition": "label_values(analyzer_errors, namespace)",
|
||||
"hide": 0,
|
||||
"includeAll": true,
|
||||
"label": "Namespace",
|
||||
"multi": true,
|
||||
"name": "namespace",
|
||||
"options": [],
|
||||
"query": {
|
||||
"query": "label_values(analyzer_errors, namespace)",
|
||||
"refId": "StandardVariableQuery"
|
||||
},
|
||||
"refresh": 2,
|
||||
"regex": "",
|
||||
"skipUrlSync": false,
|
||||
"sort": 1,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-5m",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "K8sGPT",
|
||||
"uid": "JfxtNBP4z",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: k8sgpt-deployment
|
||||
namespace: k8sgpt
|
||||
labels:
|
||||
app: k8sgpt
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: k8sgpt
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: k8sgpt
|
||||
spec:
|
||||
serviceAccountName: k8sgpt
|
||||
containers:
|
||||
- name: k8sgpt-container
|
||||
imagePullPolicy: Always
|
||||
image: ghcr.io/k8sgpt-ai/k8sgpt:v0.2.4 #x-release-please-version
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
args: ["serve"]
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: "512Mi"
|
||||
requests:
|
||||
cpu: "0.5"
|
||||
memory: "256Mi"
|
||||
env:
|
||||
- name: K8SGPT_MODEL
|
||||
value: "gpt-3.5-turbo"
|
||||
- name: K8SGPT_BACKEND
|
||||
value: "openai"
|
||||
- name: K8SGPT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ai-backend-secret
|
||||
key: secret-key
|
||||
@@ -1,13 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: k8sgpt-rolebinding
|
||||
namespace: k8sgpt
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: k8sgpt
|
||||
namespace: k8sgpt
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: k8sgpt-cluster-role-all
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
@@ -1,5 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: k8sgpt
|
||||
namespace: k8sgpt
|
||||
@@ -1,13 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: k8sgpt-service
|
||||
namespace: k8sgpt
|
||||
spec:
|
||||
selector:
|
||||
app: k8sgpt
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
type: ClusterIP
|
||||
11
demo
@@ -1,11 +0,0 @@
|
||||
. demo-magic.sh
|
||||
clear
|
||||
|
||||
pe "k8sgpt filter list"
|
||||
pe "k8sgpt analyze --filter=Pod --explain -o json | jq ."
|
||||
pe "k8sgpt integration list"
|
||||
pe "k8sgpt integration activate trivy"
|
||||
pe "k8sgpt filter list"
|
||||
pe "k8sgpt analyze --filter=VulnerabilityReport"
|
||||
pe "./k8sgpt analyze --filter=Node --explain"
|
||||
|
||||
117
go.mod
@@ -3,25 +3,36 @@ module github.com/k8sgpt-ai/k8sgpt
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/aquasecurity/trivy-operator v0.13.0
|
||||
github.com/aquasecurity/trivy-operator v0.14.1
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/magiconair/properties v1.8.7
|
||||
github.com/mittwald/go-helm-client v0.12.1
|
||||
github.com/sashabaranov/go-openai v1.8.0
|
||||
github.com/sashabaranov/go-openai v1.12.0
|
||||
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
|
||||
golang.org/x/term v0.7.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
|
||||
github.com/spf13/viper v1.16.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
golang.org/x/term v0.9.0
|
||||
helm.sh/helm/v3 v3.12.1
|
||||
k8s.io/api v0.27.3
|
||||
k8s.io/apimachinery v0.27.3
|
||||
k8s.io/client-go v0.27.3
|
||||
k8s.io/kubectl v0.27.3
|
||||
|
||||
)
|
||||
|
||||
require github.com/adrg/xdg v0.4.0 // indirect
|
||||
require github.com/adrg/xdg v0.4.0
|
||||
|
||||
require (
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230620082254-6f80f9533908.1
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230620082254-6f80f9533908.1
|
||||
github.com/aws/aws-sdk-go v1.44.295
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect
|
||||
@@ -29,25 +40,25 @@ require (
|
||||
github.com/BurntSushi/toml v1.2.1 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/Masterminds/squirrel v1.5.3 // indirect
|
||||
github.com/aquasecurity/defsec v0.85.0 // indirect
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20230324043952-2172dc218241 // indirect
|
||||
github.com/Masterminds/squirrel v1.5.4 // indirect
|
||||
github.com/aquasecurity/defsec v0.89.0 // indirect
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20230531031752-12c25a7270cc // indirect
|
||||
github.com/aquasecurity/table v1.8.0 // indirect
|
||||
github.com/aquasecurity/tml v0.6.1 // indirect
|
||||
github.com/aquasecurity/trivy v0.39.0 // indirect
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20230116084806-4bcdf1c414d0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/aquasecurity/trivy v0.42.0 // indirect
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20230515061101-378ab9ed302c // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/containerd/containerd v1.7.0 // indirect
|
||||
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/docker v23.0.3+incompatible // indirect
|
||||
github.com/docker/cli v23.0.5+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/docker v23.0.5+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
@@ -67,9 +78,9 @@ 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/go-containerregistry v0.15.2 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
@@ -85,10 +96,10 @@ require (
|
||||
github.com/jmoiron/sqlx v1.3.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.16.0 // indirect
|
||||
github.com/klauspost/compress v1.16.5 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/lib/pq v1.10.7 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/masahiro331/go-xfs-filesystem v0.0.0-20221225060805-c02764233454 // indirect
|
||||
@@ -110,25 +121,25 @@ require (
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
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/opencontainers/image-spec v1.1.0-rc3 // 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
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.10.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/rubenv/sql-migrate v1.3.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/samber/lo v1.37.0 // indirect
|
||||
github.com/samber/lo v1.38.1 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
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
|
||||
@@ -140,36 +151,36 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
go.starlark.net v0.0.0-20221020143700-22309ac47eac // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.7.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221109205753-fc8884afc316 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/oauth2 v0.6.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/oauth2 v0.7.0 // indirect
|
||||
golang.org/x/sync v0.2.0 // indirect
|
||||
golang.org/x/sys v0.9.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.53.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
google.golang.org/grpc v1.56.1
|
||||
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/klog/v2 v2.90.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20230327201221-f5883ff37f0c // indirect
|
||||
k8s.io/apiextensions-apiserver v0.27.2 // indirect
|
||||
k8s.io/apiserver v0.27.2 // indirect
|
||||
k8s.io/cli-runtime v0.27.3 // indirect
|
||||
k8s.io/component-base v0.27.3 // indirect
|
||||
k8s.io/klog/v2 v2.100.1 // 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
|
||||
)
|
||||
@@ -177,7 +188,3 @@ require (
|
||||
// v1.2.0 is taken from github.com/open-policy-agent/opa v0.42.0
|
||||
// v1.2.0 incompatible with github.com/docker/docker v23.0.0-rc.1+incompatible
|
||||
replace oras.land/oras-go => oras.land/oras-go v1.2.3
|
||||
|
||||
// v0.3.1-0.20230104082527-d6f58551be3f is taken from github.com/moby/buildkit v0.11.0
|
||||
// spdx logic write on v0.3.0 and incompatible with v0.3.1-0.20230104082527-d6f58551be3f
|
||||
replace github.com/spdx/tools-golang => github.com/spdx/tools-golang v0.3.0
|
||||
|
||||
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 78 KiB |
10
images/banner-white.svg
Normal file
|
After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 236 KiB |
|
Before Width: | Height: | Size: 234 KiB |
20
main.go
@@ -1,12 +1,26 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||
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 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)
|
||||
}
|
||||
|
||||
103
pkg/ai/azureopenai.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package ai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
|
||||
"github.com/fatih/color"
|
||||
|
||||
"github.com/sashabaranov/go-openai"
|
||||
)
|
||||
|
||||
type AzureAIClient struct {
|
||||
client *openai.Client
|
||||
language string
|
||||
model string
|
||||
}
|
||||
|
||||
func (c *AzureAIClient) Configure(config IAIConfig, lang string) error {
|
||||
token := config.GetPassword()
|
||||
baseURL := config.GetBaseURL()
|
||||
engine := config.GetEngine()
|
||||
defaultConfig := openai.DefaultAzureConfig(token, baseURL)
|
||||
|
||||
defaultConfig.AzureModelMapperFunc = func(model string) string {
|
||||
// If you use a deployment name different from the model name, you can customize the AzureModelMapperFunc function
|
||||
azureModelMapping := map[string]string{
|
||||
model: engine,
|
||||
}
|
||||
return azureModelMapping[model]
|
||||
|
||||
}
|
||||
client := openai.NewClientWithConfig(defaultConfig)
|
||||
if client == nil {
|
||||
return errors.New("error creating Azure OpenAI client")
|
||||
}
|
||||
c.language = lang
|
||||
c.client = client
|
||||
c.model = config.GetModel()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *AzureAIClient) GetCompletion(ctx context.Context, prompt string, promptTmpl string) (string, error) {
|
||||
// Create a completion request
|
||||
resp, err := c.client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
|
||||
Model: c.model,
|
||||
Messages: []openai.ChatCompletionMessage{
|
||||
{
|
||||
Role: openai.ChatMessageRoleUser,
|
||||
Content: fmt.Sprintf(default_prompt, c.language, prompt),
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return resp.Choices[0].Message.Content, nil
|
||||
}
|
||||
|
||||
func (a *AzureAIClient) Parse(ctx context.Context, prompt []string, cache cache.ICache, promptTmpl string) (string, error) {
|
||||
inputKey := strings.Join(prompt, " ")
|
||||
// Check for cached data
|
||||
cacheKey := util.GetCacheKey(a.GetName(), a.language, inputKey)
|
||||
|
||||
if !cache.IsCacheDisabled() && cache.Exists(cacheKey) {
|
||||
response, err := cache.Load(cacheKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if response != "" {
|
||||
output, err := base64.StdEncoding.DecodeString(response)
|
||||
if err != nil {
|
||||
color.Red("error decoding cached data: %v", err)
|
||||
return "", nil
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
}
|
||||
|
||||
response, err := a.GetCompletion(ctx, inputKey, promptTmpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = cache.Store(cacheKey, base64.StdEncoding.EncodeToString([]byte(response)))
|
||||
|
||||
if err != nil {
|
||||
color.Red("error storing value to cache: %v", err)
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (a *AzureAIClient) GetName() string {
|
||||
return "azureopenai"
|
||||
}
|
||||
@@ -1,33 +1,92 @@
|
||||
/*
|
||||
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 ai
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
clients = []IAI{
|
||||
&OpenAIClient{},
|
||||
&AzureAIClient{},
|
||||
&LocalAIClient{},
|
||||
&NoOpAIClient{},
|
||||
}
|
||||
Backends = []string{
|
||||
"openai",
|
||||
"localai",
|
||||
"azureopenai",
|
||||
"noopai",
|
||||
}
|
||||
)
|
||||
|
||||
type IAI interface {
|
||||
Configure(token string, model string, language string) error
|
||||
GetCompletion(ctx context.Context, prompt string) (string, error)
|
||||
Parse(ctx context.Context, prompt []string, nocache bool) (string, error)
|
||||
Configure(config IAIConfig, language string) error
|
||||
GetCompletion(ctx context.Context, prompt string, promptTmpl string) (string, error)
|
||||
Parse(ctx context.Context, prompt []string, cache cache.ICache, promptTmpl string) (string, error)
|
||||
GetName() string
|
||||
}
|
||||
|
||||
type IAIConfig interface {
|
||||
GetPassword() string
|
||||
GetModel() string
|
||||
GetBaseURL() string
|
||||
GetEngine() string
|
||||
}
|
||||
|
||||
func NewClient(provider string) IAI {
|
||||
switch provider {
|
||||
case "openai":
|
||||
return &OpenAIClient{}
|
||||
case "noopai":
|
||||
return &NoOpAIClient{}
|
||||
default:
|
||||
return &OpenAIClient{}
|
||||
for _, c := range clients {
|
||||
if provider == c.GetName() {
|
||||
return c
|
||||
}
|
||||
}
|
||||
// default client
|
||||
return &OpenAIClient{}
|
||||
}
|
||||
|
||||
type AIConfiguration struct {
|
||||
Providers []AIProvider `mapstructure:"providers"`
|
||||
Providers []AIProvider `mapstructure:"providers"`
|
||||
DefaultProvider string `mapstructure:"defaultprovider"`
|
||||
}
|
||||
|
||||
type AIProvider struct {
|
||||
Name string `mapstructure:"name"`
|
||||
Model string `mapstructure:"model"`
|
||||
Password string `mapstructure:"password"`
|
||||
Password string `mapstructure:"password" yaml:"password,omitempty"`
|
||||
BaseURL string `mapstructure:"baseurl" yaml:"baseurl,omitempty"`
|
||||
Engine string `mapstructure:"engine" yaml:"engine,omitempty"`
|
||||
}
|
||||
|
||||
func (p *AIProvider) GetBaseURL() string {
|
||||
return p.BaseURL
|
||||
}
|
||||
|
||||
func (p *AIProvider) GetPassword() string {
|
||||
return p.Password
|
||||
}
|
||||
|
||||
func (p *AIProvider) GetModel() string {
|
||||
return p.Model
|
||||
}
|
||||
|
||||
func (p *AIProvider) GetEngine() string {
|
||||
return p.Engine
|
||||
}
|
||||
|
||||
func NeedPassword(backend string) bool {
|
||||
return backend != "localai"
|
||||
}
|
||||
|
||||
9
pkg/ai/localai.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package ai
|
||||
|
||||
type LocalAIClient struct {
|
||||
OpenAIClient
|
||||
}
|
||||
|
||||
func (a *LocalAIClient) GetName() string {
|
||||
return "localai"
|
||||
}
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 ai
|
||||
|
||||
import (
|
||||
@@ -7,8 +20,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type NoOpAIClient struct {
|
||||
@@ -17,39 +30,40 @@ type NoOpAIClient struct {
|
||||
model string
|
||||
}
|
||||
|
||||
func (c *NoOpAIClient) Configure(token string, model string, language string) error {
|
||||
func (c *NoOpAIClient) Configure(config IAIConfig, language string) error {
|
||||
token := config.GetPassword()
|
||||
c.language = language
|
||||
c.client = fmt.Sprintf("I am a noop client with the token %s ", token)
|
||||
c.model = model
|
||||
c.model = config.GetModel()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *NoOpAIClient) GetCompletion(ctx context.Context, prompt string) (string, error) {
|
||||
func (c *NoOpAIClient) GetCompletion(ctx context.Context, prompt string, promptTmpl string) (string, error) {
|
||||
// Create a completion request
|
||||
response := "I am a noop response to the prompt " + prompt
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (a *NoOpAIClient) Parse(ctx context.Context, prompt []string, nocache bool) (string, error) {
|
||||
func (a *NoOpAIClient) Parse(ctx context.Context, prompt []string, cache cache.ICache, promptTmpl string) (string, error) {
|
||||
// parse the text with the AI backend
|
||||
inputKey := strings.Join(prompt, " ")
|
||||
// Check for cached data
|
||||
sEnc := base64.StdEncoding.EncodeToString([]byte(inputKey))
|
||||
cacheKey := util.GetCacheKey(a.GetName(), a.language, sEnc)
|
||||
|
||||
response, err := a.GetCompletion(ctx, inputKey)
|
||||
response, err := a.GetCompletion(ctx, inputKey, promptTmpl)
|
||||
if err != nil {
|
||||
color.Red("error getting completion: %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !viper.IsSet(cacheKey) {
|
||||
viper.Set(cacheKey, base64.StdEncoding.EncodeToString([]byte(response)))
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
color.Red("error writing config: %v", err)
|
||||
return "", nil
|
||||
}
|
||||
err = cache.Store(cacheKey, base64.StdEncoding.EncodeToString([]byte(response)))
|
||||
|
||||
if err != nil {
|
||||
color.Red("error storing value to cache: %v", err)
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 ai
|
||||
|
||||
import (
|
||||
@@ -7,19 +20,12 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/sashabaranov/go-openai"
|
||||
)
|
||||
|
||||
const (
|
||||
default_prompt = "Simplify the following Kubernetes error message and provide a solution in %s: %s"
|
||||
prompt_a = "Read the following input %s and provide possible scenarios for remediation in %s"
|
||||
prompt_b = "Considering the following input from the Kubernetes resource %s and the error message %s, provide possible scenarios for remediation in %s"
|
||||
prompt_c = "Reading the following %s error message and it's accompanying log message %s, how would you simplify this message?"
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
type OpenAIClient struct {
|
||||
@@ -28,25 +34,36 @@ type OpenAIClient struct {
|
||||
model string
|
||||
}
|
||||
|
||||
func (c *OpenAIClient) Configure(token string, model string, language string) error {
|
||||
client := openai.NewClient(token)
|
||||
func (c *OpenAIClient) Configure(config IAIConfig, language string) error {
|
||||
token := config.GetPassword()
|
||||
defaultConfig := openai.DefaultConfig(token)
|
||||
|
||||
baseURL := config.GetBaseURL()
|
||||
if baseURL != "" {
|
||||
defaultConfig.BaseURL = baseURL
|
||||
}
|
||||
|
||||
client := openai.NewClientWithConfig(defaultConfig)
|
||||
if client == nil {
|
||||
return errors.New("error creating OpenAI client")
|
||||
}
|
||||
c.language = language
|
||||
c.client = client
|
||||
c.model = model
|
||||
c.model = config.GetModel()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OpenAIClient) GetCompletion(ctx context.Context, prompt string) (string, error) {
|
||||
func (c *OpenAIClient) GetCompletion(ctx context.Context, prompt string, promptTmpl string) (string, error) {
|
||||
// Create a completion request
|
||||
if len(promptTmpl) == 0 {
|
||||
promptTmpl = PromptMap["default"]
|
||||
}
|
||||
resp, err := c.client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
|
||||
Model: c.model,
|
||||
Messages: []openai.ChatCompletionMessage{
|
||||
{
|
||||
Role: "user",
|
||||
Content: fmt.Sprintf(default_prompt, c.language, prompt),
|
||||
Content: fmt.Sprintf(promptTmpl, c.language, prompt),
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -56,39 +73,39 @@ func (c *OpenAIClient) GetCompletion(ctx context.Context, prompt string) (string
|
||||
return resp.Choices[0].Message.Content, nil
|
||||
}
|
||||
|
||||
func (a *OpenAIClient) Parse(ctx context.Context, prompt []string, nocache bool) (string, error) {
|
||||
func (a *OpenAIClient) Parse(ctx context.Context, prompt []string, cache cache.ICache, promptTmpl string) (string, error) {
|
||||
inputKey := strings.Join(prompt, " ")
|
||||
// Check for cached data
|
||||
sEnc := base64.StdEncoding.EncodeToString([]byte(inputKey))
|
||||
cacheKey := util.GetCacheKey(a.GetName(), a.language, sEnc)
|
||||
// find in viper cache
|
||||
if viper.IsSet(cacheKey) && !nocache {
|
||||
// retrieve data from cache
|
||||
response := viper.GetString(cacheKey)
|
||||
if response == "" {
|
||||
color.Red("error retrieving cached data")
|
||||
return "", nil
|
||||
}
|
||||
output, err := base64.StdEncoding.DecodeString(response)
|
||||
cacheKey := util.GetCacheKey(a.GetName(), a.language, inputKey)
|
||||
|
||||
if !cache.IsCacheDisabled() && cache.Exists(cacheKey) {
|
||||
response, err := cache.Load(cacheKey)
|
||||
if err != nil {
|
||||
color.Red("error decoding cached data: %v", err)
|
||||
return "", nil
|
||||
return "", err
|
||||
}
|
||||
|
||||
if response != "" {
|
||||
output, err := base64.StdEncoding.DecodeString(response)
|
||||
if err != nil {
|
||||
color.Red("error decoding cached data: %v", err)
|
||||
return "", nil
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
response, err := a.GetCompletion(ctx, inputKey)
|
||||
response, err := a.GetCompletion(ctx, inputKey, promptTmpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !viper.IsSet(cacheKey) || nocache {
|
||||
viper.Set(cacheKey, base64.StdEncoding.EncodeToString([]byte(response)))
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
color.Red("error writing config: %v", err)
|
||||
return "", nil
|
||||
}
|
||||
err = cache.Store(cacheKey, base64.StdEncoding.EncodeToString([]byte(response)))
|
||||
|
||||
if err != nil {
|
||||
color.Red("error storing value to cache: %v", err)
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
|
||||
15
pkg/ai/prompts.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package ai
|
||||
|
||||
const (
|
||||
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}
|
||||
`
|
||||
trivy_prompt = "Explain the following trivy scan result and the detail risk or root cause of the CVE ID, then provide a solution. Response in %s: %s"
|
||||
)
|
||||
|
||||
var PromptMap = map[string]string{
|
||||
"default": default_prompt,
|
||||
"VulnerabilityReport": trivy_prompt, // for Trivy integration, the key should match `Result.Kind` in pkg/common/types.go
|
||||
}
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analysis
|
||||
|
||||
import (
|
||||
@@ -5,11 +18,15 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"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"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
@@ -18,17 +35,22 @@ import (
|
||||
)
|
||||
|
||||
type Analysis struct {
|
||||
Context context.Context
|
||||
Filters []string
|
||||
Client *kubernetes.Client
|
||||
AIClient ai.IAI
|
||||
Results []common.Result
|
||||
Namespace string
|
||||
NoCache bool
|
||||
Explain bool
|
||||
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
|
||||
type AnalysisErrors []string
|
||||
|
||||
const (
|
||||
StateOK AnalysisStatus = "OK"
|
||||
@@ -36,12 +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) (*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 {
|
||||
@@ -54,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 {
|
||||
@@ -68,7 +98,7 @@ func NewAnalysis(backend string, language string, filters []string, namespace st
|
||||
}
|
||||
|
||||
aiClient := ai.NewClient(aiProvider.Name)
|
||||
if err := aiClient.Configure(aiProvider.Password, aiProvider.Model, language); err != nil {
|
||||
if err := aiClient.Configure(&aiProvider, language); err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
@@ -84,68 +114,130 @@ 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,
|
||||
NoCache: noCache,
|
||||
Explain: explain,
|
||||
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() error {
|
||||
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,
|
||||
}
|
||||
|
||||
// if there are no filters selected and no active_filters then run all of them
|
||||
semaphore := make(chan struct{}, a.MaxConcurrency)
|
||||
// if there are no filters selected and no active_filters then run coreAnalyzer
|
||||
if len(a.Filters) == 0 && len(activeFilters) == 0 {
|
||||
for _, analyzer := range analyzerMap {
|
||||
results, err := analyzer.Analyze(analyzerConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Results = append(a.Results, results...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// if the filters flag is specified
|
||||
if len(a.Filters) != 0 {
|
||||
for _, filter := range a.Filters {
|
||||
if analyzer, ok := analyzerMap[filter]; ok {
|
||||
var wg sync.WaitGroup
|
||||
var mutex sync.Mutex
|
||||
for _, analyzer := range coreAnalyzerMap {
|
||||
wg.Add(1)
|
||||
semaphore <- struct{}{}
|
||||
go func(analyzer common.IAnalyzer, wg *sync.WaitGroup, semaphore chan struct{}) {
|
||||
defer wg.Done()
|
||||
results, err := analyzer.Analyze(analyzerConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
mutex.Lock()
|
||||
a.Errors = append(a.Errors, fmt.Sprintf("[%s] %s", reflect.TypeOf(analyzer).Name(), err))
|
||||
mutex.Unlock()
|
||||
}
|
||||
mutex.Lock()
|
||||
a.Results = append(a.Results, results...)
|
||||
mutex.Unlock()
|
||||
<-semaphore
|
||||
}(analyzer, &wg, semaphore)
|
||||
|
||||
}
|
||||
wg.Wait()
|
||||
return
|
||||
}
|
||||
semaphore = make(chan struct{}, a.MaxConcurrency)
|
||||
// if the filters flag is specified
|
||||
if len(a.Filters) != 0 {
|
||||
var wg sync.WaitGroup
|
||||
var mutex sync.Mutex
|
||||
for _, filter := range a.Filters {
|
||||
if analyzer, ok := analyzerMap[filter]; ok {
|
||||
semaphore <- struct{}{}
|
||||
wg.Add(1)
|
||||
go func(analyzer common.IAnalyzer, filter string) {
|
||||
defer wg.Done()
|
||||
results, err := analyzer.Analyze(analyzerConfig)
|
||||
if err != nil {
|
||||
mutex.Lock()
|
||||
a.Errors = append(a.Errors, fmt.Sprintf("[%s] %s", filter, err))
|
||||
mutex.Unlock()
|
||||
}
|
||||
mutex.Lock()
|
||||
a.Results = append(a.Results, results...)
|
||||
mutex.Unlock()
|
||||
<-semaphore
|
||||
}(analyzer, filter)
|
||||
} else {
|
||||
return errors.New(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))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
wg.Wait()
|
||||
return
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var mutex sync.Mutex
|
||||
semaphore = make(chan struct{}, a.MaxConcurrency)
|
||||
// use active_filters
|
||||
for _, filter := range activeFilters {
|
||||
if analyzer, ok := analyzerMap[filter]; ok {
|
||||
results, err := analyzer.Analyze(analyzerConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Results = append(a.Results, results...)
|
||||
semaphore <- struct{}{}
|
||||
wg.Add(1)
|
||||
go func(analyzer common.IAnalyzer, filter string) {
|
||||
defer wg.Done()
|
||||
results, err := analyzer.Analyze(analyzerConfig)
|
||||
if err != nil {
|
||||
mutex.Lock()
|
||||
a.Errors = append(a.Errors, fmt.Sprintf("[%s] %s", filter, err))
|
||||
mutex.Unlock()
|
||||
}
|
||||
mutex.Lock()
|
||||
a.Results = append(a.Results, results...)
|
||||
mutex.Unlock()
|
||||
<-semaphore
|
||||
}(analyzer, filter)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (a *Analysis) GetAIResults(output string, anonymize bool) error {
|
||||
@@ -169,12 +261,19 @@ func (a *Analysis) GetAIResults(output string, anonymize bool) error {
|
||||
}
|
||||
texts = append(texts, failure.Text)
|
||||
}
|
||||
parsedText, err := a.AIClient.Parse(a.Context, texts, a.NoCache)
|
||||
// If the resource `Kind` comes from a "integration plugin", maybe a customized prompt template will be involved.
|
||||
var promptTemplate string
|
||||
if prompt, ok := ai.PromptMap[analysis.Kind]; ok {
|
||||
promptTemplate = prompt
|
||||
} else {
|
||||
promptTemplate = ai.PromptMap["default"]
|
||||
}
|
||||
parsedText, err := a.AIClient.Parse(a.Context, texts, a.Cache, promptTemplate)
|
||||
if err != nil {
|
||||
// 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
|
||||
@@ -195,7 +294,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
|
||||
}
|
||||
|
||||
@@ -1,14 +1,140 @@
|
||||
/*
|
||||
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 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{
|
||||
@@ -37,6 +163,7 @@ func TestAnalysis_NoProblemJsonOutput(t *testing.T) {
|
||||
fmt.Println(expected)
|
||||
|
||||
require.Equal(t, got, expected)
|
||||
|
||||
}
|
||||
|
||||
func TestAnalysis_ProblemJsonOutput(t *testing.T) {
|
||||
|
||||
@@ -42,8 +42,10 @@ func (a *Analysis) jsonOutput() ([]byte, error) {
|
||||
}
|
||||
|
||||
result := JsonOutput{
|
||||
Provider: a.AnalysisAIProvider,
|
||||
Problems: problems,
|
||||
Results: a.Results,
|
||||
Errors: a.Errors,
|
||||
Status: status,
|
||||
}
|
||||
output, err := json.MarshalIndent(result, "", " ")
|
||||
@@ -55,6 +57,17 @@ 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"))
|
||||
for _, aerror := range a.Errors {
|
||||
output.WriteString(fmt.Sprintf("- %s\n", color.YellowString(aerror)))
|
||||
}
|
||||
}
|
||||
output.WriteString("\n")
|
||||
if len(a.Results) == 0 {
|
||||
output.WriteString(color.GreenString("No problems detected\n"))
|
||||
@@ -65,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"))
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
@@ -65,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()
|
||||
@@ -93,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
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
@@ -5,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{}
|
||||
@@ -15,16 +30,22 @@ 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,
|
||||
})
|
||||
|
||||
var results []common.Result
|
||||
|
||||
cronJobList, err := a.Client.GetClient().BatchV1().CronJobs(a.Namespace).List(a.Context, v1.ListOptions{})
|
||||
if err != nil {
|
||||
return results, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var preAnalysis = map[string]common.PreAnalysis{}
|
||||
@@ -32,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,
|
||||
@@ -48,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,
|
||||
@@ -67,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,
|
||||
@@ -101,7 +130,7 @@ func (analyzer CronJobAnalyzer) Analyze(a common.Analyzer) ([]common.Result, err
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
a.Results = append(results, currentAnalysis)
|
||||
a.Results = append(a.Results, currentAnalysis)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
@@ -5,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"
|
||||
)
|
||||
|
||||
@@ -18,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,
|
||||
@@ -32,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,
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
@@ -23,10 +36,14 @@ func FetchLatestEvent(ctx context.Context, kubernetesClient *kubernetes.Client,
|
||||
var latestEvent *v1.Event
|
||||
for _, event := range events.Items {
|
||||
if latestEvent == nil {
|
||||
latestEvent = &event
|
||||
// this is required, as a pointer to a loop variable would always yield the latest value in the range
|
||||
e := event
|
||||
latestEvent = &e
|
||||
}
|
||||
if event.LastTimestamp.After(latestEvent.LastTimestamp.Time) {
|
||||
latestEvent = &event
|
||||
// this is required, as a pointer to a loop variable would always yield the latest value in the range
|
||||
e := event
|
||||
latestEvent = &e
|
||||
}
|
||||
}
|
||||
return latestEvent, nil
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
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{}
|
||||
@@ -15,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,
|
||||
@@ -63,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,
|
||||
@@ -81,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,
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
@@ -192,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"),
|
||||
},
|
||||
},
|
||||
@@ -256,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"),
|
||||
},
|
||||
},
|
||||
@@ -320,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"),
|
||||
},
|
||||
},
|
||||
@@ -384,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"),
|
||||
},
|
||||
},
|
||||
@@ -448,7 +461,7 @@ func TestHPAAnalyzerWithExistingScaleTargetRefWithoutSpecifyingResources(t *test
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "example",
|
||||
Name: "example",
|
||||
Image: "nginx",
|
||||
},
|
||||
},
|
||||
@@ -474,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
|
||||
}
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
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{}
|
||||
@@ -13,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,
|
||||
@@ -33,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,
|
||||
@@ -55,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,
|
||||
@@ -73,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,
|
||||
@@ -93,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,
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
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{}
|
||||
@@ -13,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,
|
||||
@@ -32,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,
|
||||
@@ -41,23 +67,23 @@ func (NetworkPolicyAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error)
|
||||
},
|
||||
},
|
||||
})
|
||||
continue
|
||||
}
|
||||
// Check if policy is not applied to any pods
|
||||
podList, err := util.GetPodListByLabels(a.Client.GetClient(), a.Namespace, policy.Spec.PodSelector.MatchLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(podList.Items) == 0 {
|
||||
failures = append(failures, common.Failure{
|
||||
Text: fmt.Sprintf("Network policy is not applied to any pods: %s", policy.Name),
|
||||
Sensitive: []common.Sensitive{
|
||||
{
|
||||
Unmasked: policy.Name,
|
||||
Masked: util.MaskString(policy.Name),
|
||||
} else {
|
||||
// Check if policy is not applied to any pods
|
||||
podList, err := util.GetPodListByLabels(a.Client.GetClient(), a.Namespace, policy.Spec.PodSelector.MatchLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(podList.Items) == 0 {
|
||||
failures = append(failures, common.Failure{
|
||||
Text: fmt.Sprintf("Network policy is not applied to any pods: %s", policy.Name),
|
||||
Sensitive: []common.Sensitive{
|
||||
{
|
||||
Unmasked: policy.Name,
|
||||
Masked: util.MaskString(policy.Name),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if len(failures) > 0 {
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
@@ -45,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,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
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{}
|
||||
@@ -13,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,
|
||||
@@ -27,39 +50,28 @@ func (PdbAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
|
||||
|
||||
for _, pdb := range list.Items {
|
||||
var failures []common.Failure
|
||||
|
||||
evt, err := FetchLatestEvent(a.Context, a.Client, pdb.Namespace, pdb.Name)
|
||||
if err != nil || evt == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if evt.Reason == "NoPods" && evt.Message != "" {
|
||||
if pdb.Spec.Selector != nil {
|
||||
for k, v := range pdb.Spec.Selector.MatchLabels {
|
||||
failures = append(failures, common.Failure{
|
||||
Text: fmt.Sprintf("%s, expected label %s=%s", evt.Message, k, v),
|
||||
Sensitive: []common.Sensitive{
|
||||
{
|
||||
Unmasked: k,
|
||||
Masked: util.MaskString(k),
|
||||
},
|
||||
{
|
||||
Unmasked: v,
|
||||
Masked: util.MaskString(v),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
for _, v := range pdb.Spec.Selector.MatchExpressions {
|
||||
failures = append(failures, common.Failure{
|
||||
Text: fmt.Sprintf("%s, expected expression %s", evt.Message, v),
|
||||
Sensitive: []common.Sensitive{},
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if pdb.Status.Conditions[0].Type == "DisruptionAllowed" && pdb.Status.Conditions[0].Status == "False" {
|
||||
var doc string
|
||||
if pdb.Spec.MaxUnavailable != nil {
|
||||
doc = apiDoc.GetApiDocV2("spec.maxUnavailable")
|
||||
}
|
||||
if pdb.Spec.MinAvailable != nil {
|
||||
doc = apiDoc.GetApiDocV2("spec.minAvailable")
|
||||
}
|
||||
for k, v := range pdb.Spec.Selector.MatchLabels {
|
||||
failures = append(failures, common.Failure{
|
||||
Text: fmt.Sprintf("%s, selector is nil", evt.Message),
|
||||
Sensitive: []common.Sensitive{},
|
||||
Text: fmt.Sprintf("%s, expected pdb pod label %s=%s", pdb.Status.Conditions[0].Reason, k, v),
|
||||
KubernetesDoc: doc,
|
||||
Sensitive: []common.Sensitive{
|
||||
{
|
||||
Unmasked: k,
|
||||
Masked: util.MaskString(k),
|
||||
},
|
||||
{
|
||||
Unmasked: v,
|
||||
Masked: util.MaskString(v),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
@@ -44,7 +57,7 @@ func (PodAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check through container status to check for crashes
|
||||
// Check through container status to check for crashes or unready
|
||||
for _, containerStatus := range pod.Status.ContainerStatuses {
|
||||
if containerStatus.State.Waiting != nil {
|
||||
if containerStatus.State.Waiting.Reason == "CrashLoopBackOff" || containerStatus.State.Waiting.Reason == "ImagePullBackOff" {
|
||||
@@ -70,6 +83,23 @@ func (PodAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// when pod is Running but its ReadinessProbe fails
|
||||
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 {
|
||||
continue
|
||||
}
|
||||
if evt.Reason == "Unhealthy" && evt.Message != "" {
|
||||
failures = append(failures, common.Failure{
|
||||
Text: evt.Message,
|
||||
Sensitive: []common.Sensitive{},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
@@ -14,23 +27,65 @@ import (
|
||||
|
||||
func TestPodAnalyzer(t *testing.T) {
|
||||
|
||||
clientset := fake.NewSimpleClientset(&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "example",
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
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.",
|
||||
clientset := fake.NewSimpleClientset(
|
||||
&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "example",
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
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.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "example2",
|
||||
Namespace: "default",
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
Phase: v1.PodRunning,
|
||||
ContainerStatuses: []v1.ContainerStatus{
|
||||
{
|
||||
Name: "example2",
|
||||
Ready: false,
|
||||
},
|
||||
},
|
||||
Conditions: []v1.PodCondition{
|
||||
{
|
||||
Type: v1.ContainersReady,
|
||||
Reason: "ContainersNotReady",
|
||||
Message: "containers with unready status: [example2]",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// simulate event: 30s Warning Unhealthy pod/my-nginx-7fb4dbcf47-4ch4w Readiness probe failed: bash: xxxx: command not found
|
||||
&v1.Event{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: "default",
|
||||
},
|
||||
InvolvedObject: v1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Name: "example2",
|
||||
Namespace: "default",
|
||||
UID: "differentUid",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
Reason: "Unhealthy",
|
||||
Message: "readiness probe failed: the detail reason here ...",
|
||||
Source: v1.EventSource{Component: "eventTest"},
|
||||
Count: 1,
|
||||
Type: v1.EventTypeWarning,
|
||||
})
|
||||
|
||||
config := common.Analyzer{
|
||||
Client: &kubernetes.Client{
|
||||
@@ -45,7 +100,7 @@ func TestPodAnalyzer(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Equal(t, len(analysisResults), 1)
|
||||
assert.Equal(t, len(analysisResults), 2)
|
||||
}
|
||||
|
||||
func TestPodAnalyzerNamespaceFiltering(t *testing.T) {
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
@@ -5,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{}
|
||||
@@ -14,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,
|
||||
@@ -39,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,
|
||||
@@ -59,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{},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
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{}
|
||||
@@ -13,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,
|
||||
@@ -31,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,
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
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 analyzer
|
||||
|
||||
import (
|
||||
|
||||
81
pkg/cache/cache.go
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
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, 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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
83
pkg/cache/file_based.go
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
)
|
||||
|
||||
var _ (ICache) = (*FileBasedCache)(nil)
|
||||
|
||||
type FileBasedCache struct {
|
||||
noCache bool
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "warning: error while testing if cache key exists:", err)
|
||||
return false
|
||||
}
|
||||
|
||||
exists, err := util.FileExists(path)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "warning: error while testing if cache key exists:", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return exists
|
||||
}
|
||||
|
||||
func (*FileBasedCache) Load(key string) (string, error) {
|
||||
path, err := xdg.CacheFile(filepath.Join("k8sgpt", key))
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func (*FileBasedCache) Store(key string, data string) error {
|
||||
path, err := xdg.CacheFile(filepath.Join("k8sgpt", key))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(path, []byte(data), 0600)
|
||||
}
|
||||
115
pkg/cache/s3_based.go
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
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 {
|
||||
_, _ = s.CreateBucket(&s3.CreateBucketInput{
|
||||
Bucket: aws.String(cache.BucketName),
|
||||
})
|
||||
}
|
||||
|
||||
return &S3Cache{
|
||||
noCache: nocache,
|
||||
session: s,
|
||||
bucketName: cache.BucketName,
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,23 @@
|
||||
/*
|
||||
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 common
|
||||
|
||||
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"
|
||||
@@ -18,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 {
|
||||
@@ -52,8 +67,9 @@ type Result struct {
|
||||
}
|
||||
|
||||
type Failure struct {
|
||||
Text string
|
||||
Sensitive []Sensitive
|
||||
Text string
|
||||
KubernetesDoc string
|
||||
Sensitive []Sensitive
|
||||
}
|
||||
|
||||
type Sensitive struct {
|
||||
|
||||