mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2026-03-18 19:17:25 +00:00
Compare commits
150 Commits
chore/cont
...
v0.1.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f95c1e1d8c | ||
|
|
3fc0d45823 | ||
|
|
cf633b606d | ||
|
|
ab63bd0dd1 | ||
|
|
3e05eb2af2 | ||
|
|
548039ebe6 | ||
|
|
0d5b8ad027 | ||
|
|
0f910e497a | ||
|
|
172c2df6c5 | ||
|
|
2eab0c544f | ||
|
|
f4765bed1b | ||
|
|
14ba8d5550 | ||
|
|
bf49a51c62 | ||
|
|
86c7e81e18 | ||
|
|
cdc7bb1272 | ||
|
|
fe683b71b8 | ||
|
|
cad2b38d03 | ||
|
|
01b2826475 | ||
|
|
4f24368758 | ||
|
|
27b8916f29 | ||
|
|
fe73633273 | ||
|
|
a9d7bd42c2 | ||
|
|
2d481b8563 | ||
|
|
b78ab3d9b5 | ||
|
|
c8b92aaa0e | ||
|
|
65a568e937 | ||
|
|
cb4932c39d | ||
|
|
323a8b23ec | ||
|
|
be5fb62bb7 | ||
|
|
e912a8ded0 | ||
|
|
a46416dce0 | ||
|
|
4d5566b4df | ||
|
|
dbd305f901 | ||
|
|
11c227b82e | ||
|
|
05abe975dd | ||
|
|
3bfb278f81 | ||
|
|
b4865ff233 | ||
|
|
95dfc62c4d | ||
|
|
b3efdf8525 | ||
|
|
5890e3a79c | ||
|
|
d0e4684e82 | ||
|
|
6f90386fc9 | ||
|
|
2f699a9929 | ||
|
|
93b947f261 | ||
|
|
54143ea0ee | ||
|
|
2cb1c9c150 | ||
|
|
02f5f921e2 | ||
|
|
e0141d1cf5 | ||
|
|
d48ff1a942 | ||
|
|
14f076a095 | ||
|
|
829ff566c0 | ||
|
|
0ecf248c3f | ||
|
|
c5c6162df1 | ||
|
|
a270f7c89f | ||
|
|
ff0b67b5a9 | ||
|
|
f9c7daf3dc | ||
|
|
a49cec98c0 | ||
|
|
39c0444fac | ||
|
|
0a0c88719e | ||
|
|
202e8e2977 | ||
|
|
254dbcc4e3 | ||
|
|
9983205ed6 | ||
|
|
57cb563038 | ||
|
|
f602fb59fc | ||
|
|
4bbe583a97 | ||
|
|
1c653ecc51 | ||
|
|
0c231d635e | ||
|
|
931f072e0a | ||
|
|
c3008c5e75 | ||
|
|
bb2db5ca79 | ||
|
|
9c5523f045 | ||
|
|
e113bf7a21 | ||
|
|
009f47c8e8 | ||
|
|
f01f87759a | ||
|
|
06fb8073dc | ||
|
|
7227e441f0 | ||
|
|
a194d4a509 | ||
|
|
0852c658de | ||
|
|
1bc839c48b | ||
|
|
aa77a309e0 | ||
|
|
dc2bfa918c | ||
|
|
abe6394150 | ||
|
|
726d5d45de | ||
|
|
73369240b4 | ||
|
|
d554bba384 | ||
|
|
653b04fcb5 | ||
|
|
aa8203261f | ||
|
|
c1d2863d7c | ||
|
|
88d49ae21c | ||
|
|
deebec629e | ||
|
|
14e85b08ff | ||
|
|
a1093dcfe4 | ||
|
|
961fb6c555 | ||
|
|
9c7d55955b | ||
|
|
b29c6e4582 | ||
|
|
36217667ce | ||
|
|
979f13f043 | ||
|
|
90a30f38bd | ||
|
|
0181c0aeb5 | ||
|
|
51aa59aea8 | ||
|
|
90b3c0898c | ||
|
|
ad594c7cb2 | ||
|
|
cc562a0380 | ||
|
|
80a99757f9 | ||
|
|
c7e8f00458 | ||
|
|
8171ddd15c | ||
|
|
08ba7e1566 | ||
|
|
46d72e38fa | ||
|
|
bfba381471 | ||
|
|
be67fd03b5 | ||
|
|
9fecc1ea6d | ||
|
|
00e8ec0c88 | ||
|
|
8da8945d1b | ||
|
|
9a093fa1fb | ||
|
|
c8385531e6 | ||
|
|
1a486d4532 | ||
|
|
bdb2e739d4 | ||
|
|
ca8ce8188a | ||
|
|
f3b2171e51 | ||
|
|
23da1170f5 | ||
|
|
249c95490b | ||
|
|
a5846b08ba | ||
|
|
2537376eea | ||
|
|
ca5e0fab21 | ||
|
|
2dd18c3ba1 | ||
|
|
5359d8ccfb | ||
|
|
d8dbd91d72 | ||
|
|
dcc0c6781a | ||
|
|
de9f6f29f6 | ||
|
|
13b7d58e59 | ||
|
|
a60da0b1ee | ||
|
|
aef7256dc3 | ||
|
|
cd386ff473 | ||
|
|
08f2c3112e | ||
|
|
addc01f700 | ||
|
|
0d9b9f5e95 | ||
|
|
6dbcde94e9 | ||
|
|
489da42ac0 | ||
|
|
171e58b511 | ||
|
|
5bdfb65d49 | ||
|
|
279af92dd6 | ||
|
|
d2f8afd686 | ||
|
|
9955d75450 | ||
|
|
7f7726d59a | ||
|
|
a0a3e45dce | ||
|
|
2992c4e5c8 | ||
|
|
05a787d53d | ||
|
|
26449e10ef | ||
|
|
c69d1ba696 | ||
|
|
9ab7f58762 |
12
.github/CODEOWNERS
vendored
Normal file
12
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# CODEOWNERS file indicates code owners for certain files
|
||||
#
|
||||
# Code owners will automatically be added as a reviewer for PRs that touch
|
||||
# the owned files.
|
||||
#
|
||||
|
||||
# Default owners for everything in the repo
|
||||
#
|
||||
# Unless a later match takes precedence, these owners will be requested for
|
||||
# review when someone opens a pull request.
|
||||
|
||||
* @k8sgpt-ai/maintainers
|
||||
35
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
35
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
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
Normal file
50
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
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. -->
|
||||
6
.github/workflows/build_container.yaml
vendored
6
.github/workflows/build_container.yaml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3
|
||||
|
||||
- name: Extract branch name
|
||||
id: extract_branch
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
RELEASE_REGISTRY: "localhost:5000/k8sgpt"
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
@@ -115,7 +115,7 @@ jobs:
|
||||
contents: read # Needed for checking out the repository
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2
|
||||
|
||||
10
.github/workflows/release.yaml
vendored
10
.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@24cb9080177205b6e8c946b17badbe402adc938f # v3
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3
|
||||
|
||||
- uses: google-github-actions/release-please-action@e0b9d1885d92e9a93d5ce8656de60e3b806e542c # v3
|
||||
- uses: google-github-actions/release-please-action@ee9822ec2c397e8a364d634464339ac43a06e042 # v3
|
||||
id: release
|
||||
with:
|
||||
command: manifest
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Go
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
version: latest
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.K8SGPT_BOT_SECRET }}
|
||||
|
||||
build-container:
|
||||
if: needs.release-please.outputs.releases_created == 'true'
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
IMAGE_TAG: ghcr.io/k8sgpt-ai/k8sgpt:${{ needs.release-please.outputs.tag_name }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
56
.github/workflows/semantic_pr.yaml
vendored
Normal file
56
.github/workflows/semantic_pr.yaml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: Semantic PR Validation
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: read # Needed for checking out the repository
|
||||
pull-requests: read # Needed for reading prs
|
||||
steps:
|
||||
- name: Validate Pull Request
|
||||
uses: amannn/action-semantic-pull-request@c3cd5d1ea3580753008872425915e343e351ab54 # v5.2.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
# Configure which types are allowed.
|
||||
# Default: https://github.com/commitizen/conventional-commit-types
|
||||
types: |
|
||||
feat
|
||||
fix
|
||||
build
|
||||
chore
|
||||
ci
|
||||
docs
|
||||
perf
|
||||
refactor
|
||||
revert
|
||||
style
|
||||
test
|
||||
deps
|
||||
scopes: |
|
||||
deps
|
||||
# Configure that a scope must always be provided.
|
||||
requireScope: false
|
||||
# When using "Squash and merge" on a PR with only one commit, GitHub
|
||||
# will suggest using that commit message instead of the PR title for the
|
||||
# merge commit, and it's easy to commit this by mistake. Enable this option
|
||||
# to also validate the commit message for one commit PRs.
|
||||
validateSingleCommit: true
|
||||
# Configure additional validation for the subject based on a regex.
|
||||
# This ensures the subject doesn't start with an uppercase character.
|
||||
subjectPattern: ^(?![A-Z]).+$
|
||||
# If `subjectPattern` is configured, you can use this property to override
|
||||
# the default error message that is shown when the pattern doesn't match.
|
||||
# The variables `subject` and `title` can be used within the message.
|
||||
subjectPatternError: |
|
||||
The subject "{subject}" found in the pull request title "{title}"
|
||||
didn't match the configured pattern. Please ensure that the subject
|
||||
doesn't start with an uppercase character.
|
||||
@@ -13,6 +13,8 @@ builds:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
ldflags:
|
||||
- -s -w -X main.version={{.Version}}
|
||||
|
||||
archives:
|
||||
- format: tar.gz
|
||||
@@ -29,6 +31,13 @@ archives:
|
||||
- goos: windows
|
||||
format: zip
|
||||
|
||||
brews:
|
||||
- name: k8sgpt
|
||||
homepage: https://k8sgpt.ai
|
||||
tap:
|
||||
owner: k8sgpt-ai
|
||||
name: homebrew-k8sgpt
|
||||
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
{".":"0.0.3"}
|
||||
{".":"0.1.3"}
|
||||
348
CHANGELOG.md
348
CHANGELOG.md
@@ -1,5 +1,353 @@
|
||||
# Changelog
|
||||
|
||||
## [0.1.3](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.1.2...v0.1.3) (2023-03-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add secret validation to ingress analyzer ([#141](https://github.com/k8sgpt-ai/k8sgpt/issues/141)) ([86c7e81](https://github.com/k8sgpt-ai/k8sgpt/commit/86c7e81e18db02ebcbfe35d470682c982871375f))
|
||||
* bugfix for output ([2eab0c5](https://github.com/k8sgpt-ai/k8sgpt/commit/2eab0c544fbb6026f6aea79b08d8f29c061acf2e))
|
||||
* CODE_OF_CONDUCT.md ([#129](https://github.com/k8sgpt-ai/k8sgpt/issues/129)) ([fe73633](https://github.com/k8sgpt-ai/k8sgpt/commit/fe73633273c5c1f4188bca48471283535967d5aa))
|
||||
* create-security.md ([27b8916](https://github.com/k8sgpt-ai/k8sgpt/commit/27b8916f297570907437686c6d958636fb249d50))
|
||||
* improvement to analysis speed ([548039e](https://github.com/k8sgpt-ai/k8sgpt/commit/548039ebe62bb609c1aa288e5e49845850fd2dd8))
|
||||
* init ingress analyzer ([#138](https://github.com/k8sgpt-ai/k8sgpt/issues/138)) ([fe683b7](https://github.com/k8sgpt-ai/k8sgpt/commit/fe683b71b84fe82459b0ffe366b4dcfa1c978cfe))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add Ingress in GetParent switch case ([14ba8d5](https://github.com/k8sgpt-ai/k8sgpt/commit/14ba8d555005f31fc2201cb8b61653093c19b8a7))
|
||||
* bugfix for output ([#148](https://github.com/k8sgpt-ai/k8sgpt/issues/148)) ([172c2df](https://github.com/k8sgpt-ai/k8sgpt/commit/172c2df6c55f5fddbfec7f8526be5f2323d1b900))
|
||||
* Change ObjectMeta value in Ingress analyser. ([bf49a51](https://github.com/k8sgpt-ai/k8sgpt/commit/bf49a51c62af450cff51a590547ef30989bd2e93))
|
||||
* typo in description of the filter flag in analyze command ([#147](https://github.com/k8sgpt-ai/k8sgpt/issues/147)) ([f4765be](https://github.com/k8sgpt-ai/k8sgpt/commit/f4765bed1b1ad121a81b35878fdb866354b5e34a))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* **deps:** update google-github-actions/release-please-action digest to ee9822e ([#132](https://github.com/k8sgpt-ai/k8sgpt/issues/132)) ([01b2826](https://github.com/k8sgpt-ai/k8sgpt/commit/01b282647512a4eaebd42ab5847b5534de148d14))
|
||||
|
||||
|
||||
### Docs
|
||||
|
||||
* add new slack link ([#134](https://github.com/k8sgpt-ai/k8sgpt/issues/134)) ([#135](https://github.com/k8sgpt-ai/k8sgpt/issues/135)) ([cad2b38](https://github.com/k8sgpt-ai/k8sgpt/commit/cad2b38d037658495024ec0166ebd3e936f65c2e))
|
||||
|
||||
## [0.1.2](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.1.1...v0.1.2) (2023-03-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* added namespace filter ([#127](https://github.com/k8sgpt-ai/k8sgpt/issues/127)) ([b78ab3d](https://github.com/k8sgpt-ai/k8sgpt/commit/b78ab3d9b503a256bf6ccf18276e20140ae17d1c))
|
||||
* prefix templates ([#125](https://github.com/k8sgpt-ai/k8sgpt/issues/125)) ([65a568e](https://github.com/k8sgpt-ai/k8sgpt/commit/65a568e937a8fdacc179f5e8b1a021a0178c04f0))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* readme code blocks ([#126](https://github.com/k8sgpt-ai/k8sgpt/issues/126)) ([c8b92aa](https://github.com/k8sgpt-ai/k8sgpt/commit/c8b92aaa0e2795aa8d65f84277c8adfe0f1d14e3))
|
||||
* update README.md ([#119](https://github.com/k8sgpt-ai/k8sgpt/issues/119)) ([05abe97](https://github.com/k8sgpt-ai/k8sgpt/commit/05abe975dd859cd85096a1a7182f17b0437ad20f))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* added default issue template ([#96](https://github.com/k8sgpt-ai/k8sgpt/issues/96)) ([#121](https://github.com/k8sgpt-ai/k8sgpt/issues/121)) ([11c227b](https://github.com/k8sgpt-ai/k8sgpt/commit/11c227b82e16dac8b46cbd03bb04d9cc1c2b5ac3))
|
||||
|
||||
|
||||
### Docs
|
||||
|
||||
* add new issue templates ([dbd305f](https://github.com/k8sgpt-ai/k8sgpt/commit/dbd305f901cca09b7148254c3aa7a7435504d6cc))
|
||||
* add WSL gcc instructions ([4d5566b](https://github.com/k8sgpt-ai/k8sgpt/commit/4d5566b4df7aedf43edbeeb03130f0ba77dbed1a))
|
||||
* added Windows and Linux instalation steps in README ([#116](https://github.com/k8sgpt-ai/k8sgpt/issues/116)) ([3bfb278](https://github.com/k8sgpt-ai/k8sgpt/commit/3bfb278f81a9c550ee37a88c0cb0377331802542))
|
||||
* fix indentations ([a46416d](https://github.com/k8sgpt-ai/k8sgpt/commit/a46416dce0f5cee2d42b27525023b04af1a8e3c0))
|
||||
* rename ISSUE_TEMPLATE ([#124](https://github.com/k8sgpt-ai/k8sgpt/issues/124)) ([cb4932c](https://github.com/k8sgpt-ai/k8sgpt/commit/cb4932c39df4903a4b48ae5f0428860027f76fd2))
|
||||
|
||||
## [0.1.1](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.1.0...v0.1.1) (2023-03-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* this stops service exiting the program ([6f90386](https://github.com/k8sgpt-ai/k8sgpt/commit/6f90386fc93b2e39e59832468922e8ba7210b8e5))
|
||||
* updated readme ([e0141d1](https://github.com/k8sgpt-ai/k8sgpt/commit/e0141d1cf54b5b37b25a5caeb9d5c940b9410ea7))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* short term solution for exhaustion ([5890e3a](https://github.com/k8sgpt-ai/k8sgpt/commit/5890e3a79c80a2973af2feb7d50e7f9c57c563c2))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* update README.md ([93b947f](https://github.com/k8sgpt-ai/k8sgpt/commit/93b947f261e401c10dde6dc1854e6e22187437d6))
|
||||
* update root.go path ([2cb1c9c](https://github.com/k8sgpt-ai/k8sgpt/commit/2cb1c9c150d052bb3942d9f62ded9d54b0e1873e))
|
||||
|
||||
## [0.1.0](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.9...v0.1.0) (2023-03-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* added british alias ([39c0444](https://github.com/k8sgpt-ai/k8sgpt/commit/39c0444fac9b46d0faa347b45df779b97019e5b6)), closes [#93](https://github.com/k8sgpt-ai/k8sgpt/issues/93)
|
||||
* enables overwriting of cache ([#95](https://github.com/k8sgpt-ai/k8sgpt/issues/95)) ([a270f7c](https://github.com/k8sgpt-ai/k8sgpt/commit/a270f7c89fb8bec35984715c5e4d160a2307e678))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* add CODEOWNERS ([c5c6162](https://github.com/k8sgpt-ai/k8sgpt/commit/c5c6162df1f3701659e47bce6e9fc6e3c569e539))
|
||||
* add codeowners file ([#102](https://github.com/k8sgpt-ai/k8sgpt/issues/102)) ([829ff56](https://github.com/k8sgpt-ai/k8sgpt/commit/829ff566c0a964250d3d8d45306d410e1b9d9d35))
|
||||
* release 0.1.0 ([f9c7daf](https://github.com/k8sgpt-ai/k8sgpt/commit/f9c7daf3dcd06dcd9cea5603108b8a42ee273348))
|
||||
|
||||
## [0.0.9](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.8...v0.0.9) (2023-03-28)
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* small update ([202e8e2](https://github.com/k8sgpt-ai/k8sgpt/commit/202e8e2977422b2b4506a80dc9b76a392c5457eb))
|
||||
|
||||
## [0.0.8](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.7...v0.0.8) (2023-03-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add generation of api-keys to cli ([#87](https://github.com/k8sgpt-ai/k8sgpt/issues/87)) ([1c653ec](https://github.com/k8sgpt-ai/k8sgpt/commit/1c653ecc51b74a2f51ce7240ffaee0fe75f2e8dd))
|
||||
* add generation of api-keys to cli ([#87](https://github.com/k8sgpt-ai/k8sgpt/issues/87)) ([bb2db5c](https://github.com/k8sgpt-ai/k8sgpt/commit/bb2db5ca7923e2049308d1674bb59ae8154e415c))
|
||||
* addition of simple language support ([c3008c5](https://github.com/k8sgpt-ai/k8sgpt/commit/c3008c5e75acbb35d864135199ca9c034f59e35f))
|
||||
* version ([0c231d6](https://github.com/k8sgpt-ai/k8sgpt/commit/0c231d635e7ad71609bb80abac5e0ade15ffb860))
|
||||
* version ([931f072](https://github.com/k8sgpt-ai/k8sgpt/commit/931f072e0ab0cfd77f261b0b719cf0819f85b951))
|
||||
|
||||
## [0.0.7](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.6...v0.0.7) (2023-03-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* wip fixing missing details ([0852c65](https://github.com/k8sgpt-ai/k8sgpt/commit/0852c658ded33b91e1d323bd8cba6ac6935cb525))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* moved code ([a194d4a](https://github.com/k8sgpt-ai/k8sgpt/commit/a194d4a509329cbc5a00724b0a19c75726c2a0d3))
|
||||
* return success on no issues ([009f47c](https://github.com/k8sgpt-ai/k8sgpt/commit/009f47c8e8ee6d3ce9b36110c36edae97690c949))
|
||||
* updated readme ([06fb807](https://github.com/k8sgpt-ai/k8sgpt/commit/06fb8073dc5b0b5bd9f8d115d9ec206ab238d68f))
|
||||
|
||||
## [0.0.6](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.6...v0.0.6) (2023-03-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add service analysis ([961fb6c](https://github.com/k8sgpt-ai/k8sgpt/commit/961fb6c555f59f1276531f462739b76b1508830e))
|
||||
* added analysis for pvcs ([88d49ae](https://github.com/k8sgpt-ai/k8sgpt/commit/88d49ae21c7d889d59361de157360f80503683be))
|
||||
* also fixes bug if the events feed is empty ([#73](https://github.com/k8sgpt-ai/k8sgpt/issues/73)) ([a1093dc](https://github.com/k8sgpt-ai/k8sgpt/commit/a1093dcfe468a7671c9e543372f73780fb38418e))
|
||||
* build container ([260640f](https://github.com/k8sgpt-ai/k8sgpt/commit/260640f865baefba8ac256f800d4992f25ca15fd))
|
||||
* find parent objects ([b29c6e4](https://github.com/k8sgpt-ai/k8sgpt/commit/b29c6e45825807d07dd6fdb954457772f40b1b0e))
|
||||
* find parent objects and add information about them ([#72](https://github.com/k8sgpt-ai/k8sgpt/issues/72)) ([14e85b0](https://github.com/k8sgpt-ai/k8sgpt/commit/14e85b08ff7d9a571796905260db7f1056b6e838))
|
||||
* find replicaset errors ([8ac56e0](https://github.com/k8sgpt-ai/k8sgpt/commit/8ac56e062baef2a0cf7c7ce2b4c97753f079f157))
|
||||
* initial json implementation ([#68](https://github.com/k8sgpt-ai/k8sgpt/issues/68)) ([979f13f](https://github.com/k8sgpt-ai/k8sgpt/commit/979f13f043f54a5bc74d0a49fee0db2faaf0a4f8))
|
||||
* interfaced out ai clients ([90b3c08](https://github.com/k8sgpt-ai/k8sgpt/commit/90b3c0898c8ab1299ce8b60effe981f5fc9ed63b))
|
||||
* support for multi-auth ([51aa59a](https://github.com/k8sgpt-ai/k8sgpt/commit/51aa59aea8c0fd5533d2300c7a79c0b9008ef887))
|
||||
* updated readme ([7336924](https://github.com/k8sgpt-ai/k8sgpt/commit/73369240b4fc8c91dae0ae272e671f7b413e3bdc))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add permissions to read repository ([d6cc4cf](https://github.com/k8sgpt-ai/k8sgpt/commit/d6cc4cfcbffbf84f27c7e4e4159da1e42dd5d689))
|
||||
* build ([1fbed3e](https://github.com/k8sgpt-ai/k8sgpt/commit/1fbed3e44ff790fccfef502ddafae92e34629c21))
|
||||
* container naming ([115276e](https://github.com/k8sgpt-ai/k8sgpt/commit/115276e01a38fc1692d6b66ab56a33f1e1793974))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.5.5 ([105fe44](https://github.com/k8sgpt-ai/k8sgpt/commit/105fe44680e5a987d4a65ff9c58b5b2211808c5e))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.5.6 ([37a1d3f](https://github.com/k8sgpt-ai/k8sgpt/commit/37a1d3f47e07caddb168f228627973870a9d867e))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.5.7 ([7f7726d](https://github.com/k8sgpt-ai/k8sgpt/commit/7f7726d59a63baeaf8ff110e00b30a20ec7f1df5))
|
||||
* minor adaptions ([ef17b84](https://github.com/k8sgpt-ai/k8sgpt/commit/ef17b845ba3c65c16ed5dcc417e3e3d3d40dd04e))
|
||||
* missing parent when explain is used ([9c7d559](https://github.com/k8sgpt-ai/k8sgpt/commit/9c7d55955b777ad201307cb946e0fc81cf9c4b99))
|
||||
* release please config ([c402c7b](https://github.com/k8sgpt-ai/k8sgpt/commit/c402c7bab7baababbbc7c82965d8337de7d50d35))
|
||||
* remove sboms from goreleaser ([addc01f](https://github.com/k8sgpt-ai/k8sgpt/commit/addc01f700dd2ea31ec24dcf4995bb7ed4a4785e))
|
||||
* semantic commit token permission ([#69](https://github.com/k8sgpt-ai/k8sgpt/issues/69)) ([0181c0a](https://github.com/k8sgpt-ai/k8sgpt/commit/0181c0aeb56ad82fd232ce1c7788c43b7bd03bf2))
|
||||
|
||||
|
||||
### Docs
|
||||
|
||||
* add some important information to contributing ([9ab7f58](https://github.com/k8sgpt-ai/k8sgpt/commit/9ab7f587620d69e4e8fc98faabce6417c35f7497))
|
||||
* update CONTRIBUTING ([05a787d](https://github.com/k8sgpt-ai/k8sgpt/commit/05a787d53dfe5e625c6449ac1e21ec36e66ddd28))
|
||||
* update CONTRIBUTING ([26449e1](https://github.com/k8sgpt-ai/k8sgpt/commit/26449e10efd8926cccd4a2eaa4e9dc3afa8bd01a))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* add bot secret to goreleaser ([171e58b](https://github.com/k8sgpt-ai/k8sgpt/commit/171e58b51107f75717694e35c4e249ee41f0409a))
|
||||
* add brew tap generation on release ([2992c4e](https://github.com/k8sgpt-ai/k8sgpt/commit/2992c4e5c8abad50c90ed85523c732f19ab1f31c))
|
||||
* add initial renovate config ([e37dbc7](https://github.com/k8sgpt-ai/k8sgpt/commit/e37dbc7909f1c520c4c6660c25b45de5847ea581))
|
||||
* add pull request template ([a6d5132](https://github.com/k8sgpt-ai/k8sgpt/commit/a6d5132b8c2ff077680e2edfd8361a93008197fd))
|
||||
* add release-please ([da7b409](https://github.com/k8sgpt-ai/k8sgpt/commit/da7b40978d55a6afed4c3a1ca83a756238feaca8))
|
||||
* add semantic pr validation ([#66](https://github.com/k8sgpt-ai/k8sgpt/issues/66)) ([ad594c7](https://github.com/k8sgpt-ai/k8sgpt/commit/ad594c7cb2105e0eff72d1767b2ddcc4dc0e3d38))
|
||||
* change module repo ([a307c13](https://github.com/k8sgpt-ai/k8sgpt/commit/a307c132b3464ff2e949c8a5588e01d344de91a0))
|
||||
* **deps:** pin amannn/action-semantic-pull-request action to c3cd5d1 ([3621766](https://github.com/k8sgpt-ai/k8sgpt/commit/36217667ceb87d9b97b44dc91e0ff6e7a1b86e14))
|
||||
* **deps:** pin dependencies ([f6072f5](https://github.com/k8sgpt-ai/k8sgpt/commit/f6072f56cbe2c073b7b7ebef6c12fa98120e54e2))
|
||||
* **deps:** pin dependencies ([5b360de](https://github.com/k8sgpt-ai/k8sgpt/commit/5b360de2ae6094cf850a4ae973a22855c21a9040))
|
||||
* **deps:** pin dependencies ([7fea7d1](https://github.com/k8sgpt-ai/k8sgpt/commit/7fea7d14a572fe0fd05f5f241b98e93655fb1965))
|
||||
* **deps:** update actions/checkout digest to 8f4b7f8 ([9955d75](https://github.com/k8sgpt-ai/k8sgpt/commit/9955d754505b60f28d17397132a1d02e95ffe303))
|
||||
* **main:** release 0.0.3 ([53c9947](https://github.com/k8sgpt-ai/k8sgpt/commit/53c994725ea2c2c54898ffe5307d9df40e9c1fe5))
|
||||
* **main:** release 0.0.3 ([f5d8609](https://github.com/k8sgpt-ai/k8sgpt/commit/f5d86092f49faef8d71cb950986d76c3f92daf46))
|
||||
* **main:** release 0.0.3 ([22873a6](https://github.com/k8sgpt-ai/k8sgpt/commit/22873a67163e58484d2a0ad343b4ba3c83e51d8f))
|
||||
* **main:** release 0.0.4 ([13b7d58](https://github.com/k8sgpt-ai/k8sgpt/commit/13b7d58e590078f086a0af2f9d1800e0e65a28bb))
|
||||
* **main:** release 0.0.4 ([aef7256](https://github.com/k8sgpt-ai/k8sgpt/commit/aef7256dc3a85817573744f8b4a54f834368bac7))
|
||||
* **main:** release 0.0.4 ([6dbcde9](https://github.com/k8sgpt-ai/k8sgpt/commit/6dbcde94e961a6e5a1fc0559d2a1da5567a659de))
|
||||
* **main:** release 0.0.5 ([9fecc1e](https://github.com/k8sgpt-ai/k8sgpt/commit/9fecc1ea6df4104412fc1230372de6f26aa1ade2))
|
||||
* **main:** release 0.0.6 ([d554bba](https://github.com/k8sgpt-ai/k8sgpt/commit/d554bba38494745f83b5a8931f665429af35a31a))
|
||||
* release 0.0.3 ([4840aa0](https://github.com/k8sgpt-ai/k8sgpt/commit/4840aa081e3aa4a7a01fd3fd5f837fa6f0c3c02c))
|
||||
* release 0.0.3 ([de02795](https://github.com/k8sgpt-ai/k8sgpt/commit/de027955ea18a751c5f991e7ff0f60b90ae704b0))
|
||||
* release 0.0.3 ([a927c32](https://github.com/k8sgpt-ai/k8sgpt/commit/a927c32def806bb8b99e1cfcd4ee3dcdeca6ae5d))
|
||||
* release 0.0.4 ([08f2c31](https://github.com/k8sgpt-ai/k8sgpt/commit/08f2c3112e2cc16b49b9cf8fdbd97368acecc754))
|
||||
* release 0.0.5 ([8da8945](https://github.com/k8sgpt-ai/k8sgpt/commit/8da8945d1b8d898440be235f88bdb2c08b0f9f84))
|
||||
* release 0.0.6 ([dc2bfa9](https://github.com/k8sgpt-ai/k8sgpt/commit/dc2bfa918c080a6c1b2e5ef66d699d9e08e28e10))
|
||||
|
||||
## [0.0.6](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.5...v0.0.6) (2023-03-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add service analysis ([961fb6c](https://github.com/k8sgpt-ai/k8sgpt/commit/961fb6c555f59f1276531f462739b76b1508830e))
|
||||
* added analysis for pvcs ([88d49ae](https://github.com/k8sgpt-ai/k8sgpt/commit/88d49ae21c7d889d59361de157360f80503683be))
|
||||
* also fixes bug if the events feed is empty ([#73](https://github.com/k8sgpt-ai/k8sgpt/issues/73)) ([a1093dc](https://github.com/k8sgpt-ai/k8sgpt/commit/a1093dcfe468a7671c9e543372f73780fb38418e))
|
||||
* find parent objects ([b29c6e4](https://github.com/k8sgpt-ai/k8sgpt/commit/b29c6e45825807d07dd6fdb954457772f40b1b0e))
|
||||
* find parent objects and add information about them ([#72](https://github.com/k8sgpt-ai/k8sgpt/issues/72)) ([14e85b0](https://github.com/k8sgpt-ai/k8sgpt/commit/14e85b08ff7d9a571796905260db7f1056b6e838))
|
||||
* initial json implementation ([#68](https://github.com/k8sgpt-ai/k8sgpt/issues/68)) ([979f13f](https://github.com/k8sgpt-ai/k8sgpt/commit/979f13f043f54a5bc74d0a49fee0db2faaf0a4f8))
|
||||
* interfaced out ai clients ([90b3c08](https://github.com/k8sgpt-ai/k8sgpt/commit/90b3c0898c8ab1299ce8b60effe981f5fc9ed63b))
|
||||
* support for multi-auth ([51aa59a](https://github.com/k8sgpt-ai/k8sgpt/commit/51aa59aea8c0fd5533d2300c7a79c0b9008ef887))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* missing parent when explain is used ([9c7d559](https://github.com/k8sgpt-ai/k8sgpt/commit/9c7d55955b777ad201307cb946e0fc81cf9c4b99))
|
||||
* semantic commit token permission ([#69](https://github.com/k8sgpt-ai/k8sgpt/issues/69)) ([0181c0a](https://github.com/k8sgpt-ai/k8sgpt/commit/0181c0aeb56ad82fd232ce1c7788c43b7bd03bf2))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* add semantic pr validation ([#66](https://github.com/k8sgpt-ai/k8sgpt/issues/66)) ([ad594c7](https://github.com/k8sgpt-ai/k8sgpt/commit/ad594c7cb2105e0eff72d1767b2ddcc4dc0e3d38))
|
||||
* **deps:** pin amannn/action-semantic-pull-request action to c3cd5d1 ([3621766](https://github.com/k8sgpt-ai/k8sgpt/commit/36217667ceb87d9b97b44dc91e0ff6e7a1b86e14))
|
||||
|
||||
## [0.0.5](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.4...v0.0.5) (2023-03-24)
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* release 0.0.5 ([8da8945](https://github.com/k8sgpt-ai/k8sgpt/commit/8da8945d1b8d898440be235f88bdb2c08b0f9f84))
|
||||
|
||||
## [0.0.4](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.4...v0.0.4) (2023-03-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* build container ([260640f](https://github.com/k8sgpt-ai/k8sgpt/commit/260640f865baefba8ac256f800d4992f25ca15fd))
|
||||
* find replicaset errors ([8ac56e0](https://github.com/k8sgpt-ai/k8sgpt/commit/8ac56e062baef2a0cf7c7ce2b4c97753f079f157))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add permissions to read repository ([d6cc4cf](https://github.com/k8sgpt-ai/k8sgpt/commit/d6cc4cfcbffbf84f27c7e4e4159da1e42dd5d689))
|
||||
* build ([1fbed3e](https://github.com/k8sgpt-ai/k8sgpt/commit/1fbed3e44ff790fccfef502ddafae92e34629c21))
|
||||
* container naming ([115276e](https://github.com/k8sgpt-ai/k8sgpt/commit/115276e01a38fc1692d6b66ab56a33f1e1793974))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.5.5 ([105fe44](https://github.com/k8sgpt-ai/k8sgpt/commit/105fe44680e5a987d4a65ff9c58b5b2211808c5e))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.5.6 ([37a1d3f](https://github.com/k8sgpt-ai/k8sgpt/commit/37a1d3f47e07caddb168f228627973870a9d867e))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.5.7 ([7f7726d](https://github.com/k8sgpt-ai/k8sgpt/commit/7f7726d59a63baeaf8ff110e00b30a20ec7f1df5))
|
||||
* minor adaptions ([ef17b84](https://github.com/k8sgpt-ai/k8sgpt/commit/ef17b845ba3c65c16ed5dcc417e3e3d3d40dd04e))
|
||||
* release please config ([c402c7b](https://github.com/k8sgpt-ai/k8sgpt/commit/c402c7bab7baababbbc7c82965d8337de7d50d35))
|
||||
* remove sboms from goreleaser ([addc01f](https://github.com/k8sgpt-ai/k8sgpt/commit/addc01f700dd2ea31ec24dcf4995bb7ed4a4785e))
|
||||
|
||||
|
||||
### Docs
|
||||
|
||||
* add some important information to contributing ([9ab7f58](https://github.com/k8sgpt-ai/k8sgpt/commit/9ab7f587620d69e4e8fc98faabce6417c35f7497))
|
||||
* update CONTRIBUTING ([05a787d](https://github.com/k8sgpt-ai/k8sgpt/commit/05a787d53dfe5e625c6449ac1e21ec36e66ddd28))
|
||||
* update CONTRIBUTING ([26449e1](https://github.com/k8sgpt-ai/k8sgpt/commit/26449e10efd8926cccd4a2eaa4e9dc3afa8bd01a))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* add bot secret to goreleaser ([171e58b](https://github.com/k8sgpt-ai/k8sgpt/commit/171e58b51107f75717694e35c4e249ee41f0409a))
|
||||
* add brew tap generation on release ([2992c4e](https://github.com/k8sgpt-ai/k8sgpt/commit/2992c4e5c8abad50c90ed85523c732f19ab1f31c))
|
||||
* add initial renovate config ([e37dbc7](https://github.com/k8sgpt-ai/k8sgpt/commit/e37dbc7909f1c520c4c6660c25b45de5847ea581))
|
||||
* add pull request template ([a6d5132](https://github.com/k8sgpt-ai/k8sgpt/commit/a6d5132b8c2ff077680e2edfd8361a93008197fd))
|
||||
* add release-please ([da7b409](https://github.com/k8sgpt-ai/k8sgpt/commit/da7b40978d55a6afed4c3a1ca83a756238feaca8))
|
||||
* change module repo ([a307c13](https://github.com/k8sgpt-ai/k8sgpt/commit/a307c132b3464ff2e949c8a5588e01d344de91a0))
|
||||
* **deps:** pin dependencies ([f6072f5](https://github.com/k8sgpt-ai/k8sgpt/commit/f6072f56cbe2c073b7b7ebef6c12fa98120e54e2))
|
||||
* **deps:** pin dependencies ([5b360de](https://github.com/k8sgpt-ai/k8sgpt/commit/5b360de2ae6094cf850a4ae973a22855c21a9040))
|
||||
* **deps:** pin dependencies ([7fea7d1](https://github.com/k8sgpt-ai/k8sgpt/commit/7fea7d14a572fe0fd05f5f241b98e93655fb1965))
|
||||
* **deps:** update actions/checkout digest to 8f4b7f8 ([9955d75](https://github.com/k8sgpt-ai/k8sgpt/commit/9955d754505b60f28d17397132a1d02e95ffe303))
|
||||
* **main:** release 0.0.3 ([53c9947](https://github.com/k8sgpt-ai/k8sgpt/commit/53c994725ea2c2c54898ffe5307d9df40e9c1fe5))
|
||||
* **main:** release 0.0.3 ([f5d8609](https://github.com/k8sgpt-ai/k8sgpt/commit/f5d86092f49faef8d71cb950986d76c3f92daf46))
|
||||
* **main:** release 0.0.3 ([22873a6](https://github.com/k8sgpt-ai/k8sgpt/commit/22873a67163e58484d2a0ad343b4ba3c83e51d8f))
|
||||
* **main:** release 0.0.4 ([aef7256](https://github.com/k8sgpt-ai/k8sgpt/commit/aef7256dc3a85817573744f8b4a54f834368bac7))
|
||||
* **main:** release 0.0.4 ([6dbcde9](https://github.com/k8sgpt-ai/k8sgpt/commit/6dbcde94e961a6e5a1fc0559d2a1da5567a659de))
|
||||
* release 0.0.3 ([4840aa0](https://github.com/k8sgpt-ai/k8sgpt/commit/4840aa081e3aa4a7a01fd3fd5f837fa6f0c3c02c))
|
||||
* release 0.0.3 ([de02795](https://github.com/k8sgpt-ai/k8sgpt/commit/de027955ea18a751c5f991e7ff0f60b90ae704b0))
|
||||
* release 0.0.3 ([a927c32](https://github.com/k8sgpt-ai/k8sgpt/commit/a927c32def806bb8b99e1cfcd4ee3dcdeca6ae5d))
|
||||
* release 0.0.4 ([08f2c31](https://github.com/k8sgpt-ai/k8sgpt/commit/08f2c3112e2cc16b49b9cf8fdbd97368acecc754))
|
||||
|
||||
## [0.0.4](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.4...v0.0.4) (2023-03-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* build container ([260640f](https://github.com/k8sgpt-ai/k8sgpt/commit/260640f865baefba8ac256f800d4992f25ca15fd))
|
||||
* find replicaset errors ([8ac56e0](https://github.com/k8sgpt-ai/k8sgpt/commit/8ac56e062baef2a0cf7c7ce2b4c97753f079f157))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add permissions to read repository ([d6cc4cf](https://github.com/k8sgpt-ai/k8sgpt/commit/d6cc4cfcbffbf84f27c7e4e4159da1e42dd5d689))
|
||||
* build ([1fbed3e](https://github.com/k8sgpt-ai/k8sgpt/commit/1fbed3e44ff790fccfef502ddafae92e34629c21))
|
||||
* container naming ([115276e](https://github.com/k8sgpt-ai/k8sgpt/commit/115276e01a38fc1692d6b66ab56a33f1e1793974))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.5.5 ([105fe44](https://github.com/k8sgpt-ai/k8sgpt/commit/105fe44680e5a987d4a65ff9c58b5b2211808c5e))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.5.6 ([37a1d3f](https://github.com/k8sgpt-ai/k8sgpt/commit/37a1d3f47e07caddb168f228627973870a9d867e))
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.5.7 ([7f7726d](https://github.com/k8sgpt-ai/k8sgpt/commit/7f7726d59a63baeaf8ff110e00b30a20ec7f1df5))
|
||||
* minor adaptions ([ef17b84](https://github.com/k8sgpt-ai/k8sgpt/commit/ef17b845ba3c65c16ed5dcc417e3e3d3d40dd04e))
|
||||
* release please config ([c402c7b](https://github.com/k8sgpt-ai/k8sgpt/commit/c402c7bab7baababbbc7c82965d8337de7d50d35))
|
||||
* remove sboms from goreleaser ([addc01f](https://github.com/k8sgpt-ai/k8sgpt/commit/addc01f700dd2ea31ec24dcf4995bb7ed4a4785e))
|
||||
|
||||
|
||||
### Docs
|
||||
|
||||
* add some important information to contributing ([9ab7f58](https://github.com/k8sgpt-ai/k8sgpt/commit/9ab7f587620d69e4e8fc98faabce6417c35f7497))
|
||||
* update CONTRIBUTING ([05a787d](https://github.com/k8sgpt-ai/k8sgpt/commit/05a787d53dfe5e625c6449ac1e21ec36e66ddd28))
|
||||
* update CONTRIBUTING ([26449e1](https://github.com/k8sgpt-ai/k8sgpt/commit/26449e10efd8926cccd4a2eaa4e9dc3afa8bd01a))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* add bot secret to goreleaser ([171e58b](https://github.com/k8sgpt-ai/k8sgpt/commit/171e58b51107f75717694e35c4e249ee41f0409a))
|
||||
* add brew tap generation on release ([2992c4e](https://github.com/k8sgpt-ai/k8sgpt/commit/2992c4e5c8abad50c90ed85523c732f19ab1f31c))
|
||||
* add initial renovate config ([e37dbc7](https://github.com/k8sgpt-ai/k8sgpt/commit/e37dbc7909f1c520c4c6660c25b45de5847ea581))
|
||||
* add pull request template ([a6d5132](https://github.com/k8sgpt-ai/k8sgpt/commit/a6d5132b8c2ff077680e2edfd8361a93008197fd))
|
||||
* add release-please ([da7b409](https://github.com/k8sgpt-ai/k8sgpt/commit/da7b40978d55a6afed4c3a1ca83a756238feaca8))
|
||||
* change module repo ([a307c13](https://github.com/k8sgpt-ai/k8sgpt/commit/a307c132b3464ff2e949c8a5588e01d344de91a0))
|
||||
* **deps:** pin dependencies ([f6072f5](https://github.com/k8sgpt-ai/k8sgpt/commit/f6072f56cbe2c073b7b7ebef6c12fa98120e54e2))
|
||||
* **deps:** pin dependencies ([5b360de](https://github.com/k8sgpt-ai/k8sgpt/commit/5b360de2ae6094cf850a4ae973a22855c21a9040))
|
||||
* **deps:** pin dependencies ([7fea7d1](https://github.com/k8sgpt-ai/k8sgpt/commit/7fea7d14a572fe0fd05f5f241b98e93655fb1965))
|
||||
* **deps:** update actions/checkout digest to 8f4b7f8 ([9955d75](https://github.com/k8sgpt-ai/k8sgpt/commit/9955d754505b60f28d17397132a1d02e95ffe303))
|
||||
* **main:** release 0.0.3 ([53c9947](https://github.com/k8sgpt-ai/k8sgpt/commit/53c994725ea2c2c54898ffe5307d9df40e9c1fe5))
|
||||
* **main:** release 0.0.3 ([f5d8609](https://github.com/k8sgpt-ai/k8sgpt/commit/f5d86092f49faef8d71cb950986d76c3f92daf46))
|
||||
* **main:** release 0.0.3 ([22873a6](https://github.com/k8sgpt-ai/k8sgpt/commit/22873a67163e58484d2a0ad343b4ba3c83e51d8f))
|
||||
* **main:** release 0.0.4 ([6dbcde9](https://github.com/k8sgpt-ai/k8sgpt/commit/6dbcde94e961a6e5a1fc0559d2a1da5567a659de))
|
||||
* release 0.0.3 ([4840aa0](https://github.com/k8sgpt-ai/k8sgpt/commit/4840aa081e3aa4a7a01fd3fd5f837fa6f0c3c02c))
|
||||
* release 0.0.3 ([de02795](https://github.com/k8sgpt-ai/k8sgpt/commit/de027955ea18a751c5f991e7ff0f60b90ae704b0))
|
||||
* release 0.0.3 ([a927c32](https://github.com/k8sgpt-ai/k8sgpt/commit/a927c32def806bb8b99e1cfcd4ee3dcdeca6ae5d))
|
||||
* release 0.0.4 ([08f2c31](https://github.com/k8sgpt-ai/k8sgpt/commit/08f2c3112e2cc16b49b9cf8fdbd97368acecc754))
|
||||
|
||||
## [0.0.4](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.3...v0.0.4) (2023-03-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update module github.com/sashabaranov/go-openai to v1.5.7 ([7f7726d](https://github.com/k8sgpt-ai/k8sgpt/commit/7f7726d59a63baeaf8ff110e00b30a20ec7f1df5))
|
||||
|
||||
|
||||
### Docs
|
||||
|
||||
* add some important information to contributing ([9ab7f58](https://github.com/k8sgpt-ai/k8sgpt/commit/9ab7f587620d69e4e8fc98faabce6417c35f7497))
|
||||
* update CONTRIBUTING ([05a787d](https://github.com/k8sgpt-ai/k8sgpt/commit/05a787d53dfe5e625c6449ac1e21ec36e66ddd28))
|
||||
* update CONTRIBUTING ([26449e1](https://github.com/k8sgpt-ai/k8sgpt/commit/26449e10efd8926cccd4a2eaa4e9dc3afa8bd01a))
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* add bot secret to goreleaser ([171e58b](https://github.com/k8sgpt-ai/k8sgpt/commit/171e58b51107f75717694e35c4e249ee41f0409a))
|
||||
* add brew tap generation on release ([2992c4e](https://github.com/k8sgpt-ai/k8sgpt/commit/2992c4e5c8abad50c90ed85523c732f19ab1f31c))
|
||||
* **deps:** update actions/checkout digest to 8f4b7f8 ([9955d75](https://github.com/k8sgpt-ai/k8sgpt/commit/9955d754505b60f28d17397132a1d02e95ffe303))
|
||||
|
||||
## [0.0.3](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.0.3...v0.0.3) (2023-03-23)
|
||||
|
||||
|
||||
|
||||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
contact@k8sgpt.ai.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
110
CONTRIBUTING.md
110
CONTRIBUTING.md
@@ -1,5 +1,113 @@
|
||||
# Contributing
|
||||
We're happy that you want to contribute to this project. Please read the sections to make the process as smooth as possible.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Golang `1.20`
|
||||
- An OpenAI API key
|
||||
* OpenAI API keys can be obtained from [OpenAI](https://platform.openai.com/account/api-keys)
|
||||
* You can set the API key for k8sgpt using `./k8sgpt auth key`
|
||||
- If you want to build the container image, you need to have a container engine (docker, podman, rancher, etc.) installed
|
||||
|
||||
## Getting Started
|
||||
|
||||
**Where should I start?**
|
||||
- If you are new to the project, please check out the [good first issue](https://github.com/k8sgpt-ai/k8sgpt/labels/good%20first%20issue) label.
|
||||
- If you are looking for something to work on, check out our [open issues](https://github.com/k8sgpt-ai/k8sgpt/issues).
|
||||
- If you have an idea for a new feature, please open an issue, and we can discuss it.
|
||||
- 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)
|
||||
* Introduce yourself on the slack channel or open an issue to let us know that you are interested in contributing
|
||||
|
||||
**Discuss issues**
|
||||
* Before you start working on something, propose and discuss your solution on the issue
|
||||
* If you are unsure about something, ask the community
|
||||
|
||||
**How do I contribute?**
|
||||
- Fork the repository and clone it locally
|
||||
- Create a new branch and follow [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) guidelines for work undertaken
|
||||
- Assign yourself to the issue, if you are working on it (if you are not a member of the organization, please leave a comment on the issue)
|
||||
- Make your changes
|
||||
- Keep pull requests small and focused, if you have multiple changes, please open multiple PRs
|
||||
- Create a pull request back to the upstream repository and follow follow the [pull request template](.github/pull_request_template.md) guidelines.
|
||||
- Wait for a review and address any comments
|
||||
|
||||
**Opening PRs**
|
||||
- As long as you are working on your PR, please mark it as a draft
|
||||
- Please make sure that your PR is up-to-date with the latest changes in `main`
|
||||
- Fill out the PR template
|
||||
- Mention the issue that your PR is addressing (closes: #<id>)
|
||||
- Make sure that your PR passes all checks
|
||||
|
||||
**Reviewing PRs**
|
||||
- Be respectful and constructive
|
||||
- Assign yourself to the PR
|
||||
- Check if all checks are passing
|
||||
- Suggest changes instead of simply commenting on found issues
|
||||
- If you are unsure about something, ask the author
|
||||
- If you are not sure if the changes work, try them out
|
||||
- Reach out to other reviewers if you are unsure about something
|
||||
- If you are happy with the changes, approve the PR
|
||||
- Merge the PR once it has all approvals and the checks are passing
|
||||
|
||||
## DCO
|
||||
We have a DCO check which runs on every PR to verify that the commit has been signed off.
|
||||
|
||||
To sign off the last commit you made, you can use
|
||||
|
||||
```
|
||||
git commit --amend --signoff
|
||||
```
|
||||
|
||||
You can also automate signing off your commits by adding the following to your `.zshrc` or `.bashrc`:
|
||||
|
||||
```
|
||||
git() {
|
||||
if [ $# -gt 0 ] && [[ "$1" == "commit" ]] ; then
|
||||
shift
|
||||
command git commit --signoff "$@"
|
||||
else
|
||||
command git "$@"
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
## Semantic commits
|
||||
We use [Semantic Commits](https://www.conventionalcommits.org/en/v1.0.0/) to make it easier to understand what a commit does and to build pretty changelogs. Please use the following prefixes for your commits:
|
||||
- `feat`: A new feature
|
||||
- `fix`: A bug fix
|
||||
- `docs`: Documentation changes
|
||||
- `chores`: Changes to the build process or auxiliary tools and libraries such as documentation generation
|
||||
- `refactor`: A code change that neither fixes a bug nor adds a feature
|
||||
- `test`: Adding missing tests or correcting existing tests
|
||||
- `ci`: Changes to our CI configuration files and scripts
|
||||
|
||||
An example for this could be:
|
||||
```
|
||||
git commit -m "docs: add a new section to the README"
|
||||
```
|
||||
|
||||
## Building
|
||||
Building the binary is as simple as running `go build .` in the root of the repository. If you want to build the container image, you can run `docker build -t k8sgpt -f container/Dockerfile .` in the root of the repository.
|
||||
|
||||
## Releasing
|
||||
Releases of k8sgpt are done using [Release Please](https://github.com/googleapis/release-please) and [GoReleaser](https://goreleaser.com/). The workflow looks like this:
|
||||
|
||||
* A PR is merged to the `main` branch:
|
||||
* Release please is triggered, creates or updates a new release PR
|
||||
* This is done with every merge to main, the current release PR is updated every time
|
||||
|
||||
* Merging the 'release please' PR to `main`:
|
||||
* Release please is triggered, creates a new release and updates the changelog based on the commit messages
|
||||
* GoReleaser is triggered, builds the binaries and attaches them to the release
|
||||
* Containers are created and pushed to the container registry
|
||||
|
||||
> With the next relevant merge, a new release PR will be created and the process starts again
|
||||
|
||||
### Manually setting the version
|
||||
If you want to manually set the version, you can create a PR with an empty commit message that contains the version number in the commit message. For example:
|
||||
|
||||
Such a commit can get produced as follows: `git commit --allow-empty -m "chore: release 0.0.3" -m "Release-As: 0.0.3`
|
||||
|
||||
|
||||
|
||||
134
README.md
134
README.md
@@ -1,34 +1,142 @@
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./images/logo-white.png" width="100px;">
|
||||
<img alt="Text changing depending on mode. Light: 'So light!' Dark: 'So dark!'" src="./images/logo-black.png" width="100px;">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./images/banner-white.png" width="600px;">
|
||||
<img alt="Text changing depending on mode. Light: 'So light!' Dark: 'So dark!'" src="./images/banner-black.png" width="600px;">
|
||||
</picture>
|
||||
|
||||
`k8sgpt` is a tool for scanning your kubernetes clusters, diagnosing and triaging issues in simple english.
|
||||
|
||||
It has SRE experience codified into it's analyzers and helps to pull out the most relevent information to enrich it with AI.
|
||||
|
||||
<img src="images/demo2.gif" width=650px; />
|
||||
## Installation
|
||||
|
||||
### Linux/Mac via brew
|
||||
|
||||
```
|
||||
brew tap k8sgpt-ai/k8sgpt
|
||||
brew install k8sgpt
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Failing Installation on WSL or Linux (missing gcc)</summary>
|
||||
When installing Homebrew on WSL or Linux, you may encounter the following error:
|
||||
|
||||
```
|
||||
==> Installing k8sgpt from k8sgpt-ai/k8sgpt Error: The following formula cannot be installed from bottle and must be
|
||||
built from source. k8sgpt Install Clang or run brew install gcc.
|
||||
```
|
||||
|
||||
If you install gcc as suggested, the problem will persist. Therefore, you need to install the build-essential package.
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential
|
||||
```
|
||||
</details>
|
||||
|
||||
### 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
|
||||
|
||||
### Verify installation
|
||||
|
||||
* Run `k8sgpt version`
|
||||
|
||||
## 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 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; />
|
||||
|
||||
## Analyzers
|
||||
|
||||
K8sGPT uses analyzers to triage and diagnose issues in your cluster. It has a set of analyzers that are built in, but
|
||||
you will be able to write your own analyzers.
|
||||
|
||||
### Built in analyzers
|
||||
|
||||
- [x] podAnalyzer
|
||||
- [x] pvcAnalyzer
|
||||
- [x] rsAnalyzer
|
||||
- [x] serviceAnalyzer
|
||||
- [x] eventAnalyzer
|
||||
- [x] ingressAnalyzer
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
# Ensure KUBECONFIG env is set to an active Kubernetes cluster
|
||||
k8sgpt auth key <Your OpenAI key>
|
||||
Usage:
|
||||
k8sgpt [command]
|
||||
|
||||
k8sgpt find problems --explain
|
||||
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
|
||||
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.
|
||||
```
|
||||
|
||||
### What about kubectl-ai?
|
||||
_Run a scan with the default analyzers_
|
||||
|
||||
The 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 generate
|
||||
k8sgpt auth
|
||||
k8sgpt analyze --explain
|
||||
```
|
||||
|
||||
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.
|
||||
_Filter on resource_
|
||||
|
||||
```
|
||||
k8sgpt analyze --explain --filter=Service
|
||||
```
|
||||
|
||||
_Filter by namespace_
|
||||
```
|
||||
k8sgpt analyze --explain --filter=Pod --namespace=default
|
||||
```
|
||||
|
||||
_Output to JSON_
|
||||
|
||||
```
|
||||
k8sgpt analyze --explain --filter=Service --output=json
|
||||
```
|
||||
|
||||
## 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
|
||||
## Configuration
|
||||
|
||||
`k8sgpt` stores config data in `~/.k8sgpt` the data is stored in plain text, including your OpenAI key.
|
||||
`k8sgpt` stores config data in `~/.k8sgpt.yaml` the data is stored in plain text, including your OpenAI key.
|
||||
|
||||
### Community
|
||||
* Find us on [Slack](https://cloud-native.slack.com/channels/k8sgpt-ai)
|
||||
## Contributing
|
||||
|
||||
Please read our [contributing guide](./CONTRIBUTING.md).
|
||||
## Community
|
||||
* Find us on [Slack](https://k8sgpt.slack.com/)
|
||||
|
||||
11
SECURITY.md
Normal file
11
SECURITY.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We currently support the latest release for security patching and will deploy forward releases.
|
||||
|
||||
For example if there is a vulnerability in release `0.1.0` we will fix that release in version `0.1.1-fix` or `0.1.1`
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you are aware of a vulnverability please feel free to disclose it responsibly to contact@k8sgpt.ai or to one of our maintainers in our Slack community.
|
||||
157
cmd/analyze/analyze.go
Normal file
157
cmd/analyze/analyze.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package analyze
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/schollz/progressbar/v3"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
explain bool
|
||||
backend string
|
||||
output string
|
||||
filters []string
|
||||
language string
|
||||
nocache bool
|
||||
namespace string
|
||||
)
|
||||
|
||||
// AnalyzeCmd represents the problems command
|
||||
var AnalyzeCmd = &cobra.Command{
|
||||
Use: "analyze",
|
||||
Aliases: []string{"analyse"},
|
||||
Short: "This command will find problems within your Kubernetes cluster",
|
||||
Long: `This command will find problems within your Kubernetes cluster and
|
||||
provide you with a list of issues that need to be resolved`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// get backend from file
|
||||
backendType := viper.GetString("backend_type")
|
||||
if backendType == "" {
|
||||
color.Red("No backend set. Please run k8sgpt auth")
|
||||
os.Exit(1)
|
||||
}
|
||||
// override the default backend if a flag is provided
|
||||
if backend != "" {
|
||||
backendType = backend
|
||||
}
|
||||
// get the token with viper
|
||||
token := viper.GetString(fmt.Sprintf("%s_key", backendType))
|
||||
// check if nil
|
||||
if token == "" {
|
||||
color.Red("No %s key set. Please run k8sgpt auth", backendType)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var aiClient ai.IAI
|
||||
switch backendType {
|
||||
case "openai":
|
||||
aiClient = &ai.OpenAIClient{}
|
||||
if err := aiClient.Configure(token, language); err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
default:
|
||||
color.Red("Backend not supported")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
// Get kubernetes client from viper
|
||||
client := viper.Get("kubernetesClient").(*kubernetes.Client)
|
||||
// Analysis configuration
|
||||
config := &analyzer.AnalysisConfiguration{
|
||||
Namespace: namespace,
|
||||
NoCache: nocache,
|
||||
Explain: explain,
|
||||
}
|
||||
|
||||
var analysisResults *[]analyzer.Analysis = &[]analyzer.Analysis{}
|
||||
if err := analyzer.RunAnalysis(ctx, filters, config, client,
|
||||
aiClient, analysisResults); err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var bar *progressbar.ProgressBar
|
||||
if len(*analysisResults) > 0 {
|
||||
bar = progressbar.Default(int64(len(*analysisResults)))
|
||||
} else {
|
||||
color.Green("{ \"status\": \"OK\" }")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// This variable is used to store the results that will be printed
|
||||
// It's necessary because the heap memory is lost when the function returns
|
||||
var printOutput []analyzer.Analysis
|
||||
|
||||
for _, analysis := range *analysisResults {
|
||||
|
||||
if explain {
|
||||
parsedText, err := analyzer.ParseViaAI(ctx, config, aiClient, analysis.Error)
|
||||
if err != nil {
|
||||
// Check for exhaustion
|
||||
if strings.Contains(err.Error(), "status code: 429") {
|
||||
color.Red("Exhausted API quota. Please try again later")
|
||||
os.Exit(1)
|
||||
}
|
||||
color.Red("Error: %v", err)
|
||||
continue
|
||||
}
|
||||
analysis.Details = parsedText
|
||||
bar.Add(1)
|
||||
}
|
||||
printOutput = append(printOutput, analysis)
|
||||
}
|
||||
|
||||
// print results
|
||||
for n, analysis := range printOutput {
|
||||
|
||||
switch output {
|
||||
case "json":
|
||||
analysis.Error = analysis.Error[0:]
|
||||
j, err := json.Marshal(analysis)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(string(j))
|
||||
default:
|
||||
fmt.Printf("%s %s(%s)\n", color.CyanString("%d", n),
|
||||
color.YellowString(analysis.Name), color.CyanString(analysis.ParentObject))
|
||||
for _, err := range analysis.Error {
|
||||
fmt.Printf("- %s %s\n", color.RedString("Error:"), color.RedString(err))
|
||||
}
|
||||
color.GreenString(analysis.Details)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
// namespace flag
|
||||
AnalyzeCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Namespace to analyze")
|
||||
// no cache flag
|
||||
AnalyzeCmd.Flags().BoolVarP(&nocache, "no-cache", "c", false, "Do not use cached data")
|
||||
// array of strings flag
|
||||
AnalyzeCmd.Flags().StringSliceVarP(&filters, "filter", "f", []string{}, "Filter for these analyzers (e.g. Pod, PersistentVolumeClaim, Service, ReplicaSet)")
|
||||
// explain flag
|
||||
AnalyzeCmd.Flags().BoolVarP(&explain, "explain", "e", false, "Explain the problem to me")
|
||||
// add flag for backend
|
||||
AnalyzeCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
|
||||
// output as json
|
||||
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')")
|
||||
}
|
||||
@@ -1,29 +1,61 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE alexsimonjones@gmail.com
|
||||
*/
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
var (
|
||||
backend string
|
||||
)
|
||||
|
||||
// authCmd represents the auth command
|
||||
var AuthCmd = &cobra.Command{
|
||||
Use: "auth",
|
||||
Short: "A brief description of your command",
|
||||
Long: `A longer description that spans multiple lines and likely contains examples
|
||||
and usage of using your command. For example:
|
||||
|
||||
Cobra is a CLI library for Go that empowers applications.
|
||||
This application is a tool to generate the needed files
|
||||
to quickly create a Cobra application.`,
|
||||
Short: "Authenticate with your chosen backend",
|
||||
Long: `Provide the necessary credentials to authenticate with your chosen backend.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("auth called")
|
||||
|
||||
backendType := viper.GetString("backend_type")
|
||||
if backendType == "" {
|
||||
// Set the default backend
|
||||
viper.Set("backend_type", "openai")
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
color.Red("Error writing config file: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
// override the default backend if a flag is provided
|
||||
if backend != "" {
|
||||
backendType = backend
|
||||
}
|
||||
|
||||
fmt.Printf("Enter %s Key: ", backendType)
|
||||
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
color.Red("Error reading %s Key from stdin: %s", backendType,
|
||||
err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
password := strings.TrimSpace(string(bytePassword))
|
||||
|
||||
viper.Set(fmt.Sprintf("%s_key", backendType), password)
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE alexsimonjones@gmail.com
|
||||
*/
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
// keyCmd represents the key command
|
||||
var keyCmd = &cobra.Command{
|
||||
Use: "key",
|
||||
Short: "Add a key to OpenAI",
|
||||
Long: `This command will add a key from OpenAI to enable you to interact with the API`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
fmt.Print("Enter OpenAI API Key: ")
|
||||
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
color.Red("Error reading OpenAI API Key from stdin: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
password := strings.TrimSpace(string(bytePassword))
|
||||
|
||||
viper.Set("openai_api_key", password)
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
color.Red("Error writing config file: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
color.Green("key added")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AuthCmd.AddCommand(keyCmd)
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE alexsimonjones@gmail.com
|
||||
*/
|
||||
package find
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// findCmd represents the find command
|
||||
var FindCmd = &cobra.Command{
|
||||
Use: "find",
|
||||
Short: "Find issues within your Kubernetes cluster",
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.Help()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package find
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analyzer"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var explain bool
|
||||
|
||||
// problemsCmd represents the problems command
|
||||
var problemsCmd = &cobra.Command{
|
||||
Use: "problems",
|
||||
Short: "This command will find problems within your Kubernetes cluster",
|
||||
Long: `This command will find problems within your Kubernetes cluster and
|
||||
provide you with a list of issues that need to be resolved`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// Initialise the openAI client
|
||||
openAIClient, err := ai.NewClient()
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
// Get kubernetes client from viper
|
||||
client := viper.Get("kubernetesClient").(*kubernetes.Client)
|
||||
|
||||
if err := analyzer.RunAnalysis(ctx, client, openAIClient, explain); err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
problemsCmd.Flags().BoolVarP(&explain, "explain", "e", false, "Explain the problem to me")
|
||||
|
||||
FindCmd.AddCommand(problemsCmd)
|
||||
|
||||
}
|
||||
62
cmd/generate/generate.go
Normal file
62
cmd/generate/generate.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
backend string
|
||||
)
|
||||
|
||||
// generateCmd represents the auth command
|
||||
var GenerateCmd = &cobra.Command{
|
||||
Use: "generate",
|
||||
Short: "Generate Key for your chosen backend (opens browser)",
|
||||
Long: `Opens your browser to generate a key for your chosen backend.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
backendType := viper.GetString("backend_type")
|
||||
if backendType == "" {
|
||||
// Set the default backend
|
||||
backend = "openai"
|
||||
}
|
||||
// override the default backend if a flag is provided
|
||||
if backend != "" {
|
||||
backendType = backend
|
||||
}
|
||||
fmt.Println("")
|
||||
color.Green("Opening: https://beta.openai.com/account/api-keys to generate a key for %s", backendType)
|
||||
color.Green("Please copy the generated key and run `k8sgpt auth` to add it to your config file")
|
||||
fmt.Println("")
|
||||
time.Sleep(5 * time.Second)
|
||||
openbrowser("https://beta.openai.com/account/api-keys")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// add flag for backend
|
||||
GenerateCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
|
||||
}
|
||||
|
||||
func openbrowser(url string) {
|
||||
var err error
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
err = exec.Command("xdg-open", url).Start()
|
||||
case "windows":
|
||||
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
|
||||
case "darwin":
|
||||
err = exec.Command("open", url).Start()
|
||||
default:
|
||||
err = fmt.Errorf("unsupported platform")
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
17
cmd/root.go
17
cmd/root.go
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/k8sgpt-ai/k8sgpt/cmd/generate"
|
||||
"os"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/cmd/analyze"
|
||||
"github.com/k8sgpt-ai/k8sgpt/cmd/auth"
|
||||
"github.com/k8sgpt-ai/k8sgpt/cmd/find"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -18,6 +16,7 @@ var (
|
||||
cfgFile string
|
||||
masterURL string
|
||||
kubeconfig string
|
||||
version string
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
@@ -32,7 +31,8 @@ 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() {
|
||||
func Execute(v string) {
|
||||
version = v
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
@@ -46,9 +46,9 @@ func init() {
|
||||
// Cobra supports persistent flags, which, if defined here,
|
||||
// will be global for your application.
|
||||
rootCmd.AddCommand(auth.AuthCmd)
|
||||
rootCmd.AddCommand(find.FindCmd)
|
||||
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.k8sgpt.git.yaml)")
|
||||
rootCmd.AddCommand(analyze.AnalyzeCmd)
|
||||
rootCmd.AddCommand(generate.GenerateCmd)
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.k8sgpt.yaml)")
|
||||
rootCmd.PersistentFlags().StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
|
||||
rootCmd.PersistentFlags().StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
|
||||
// Cobra also supports local flags, which will only run
|
||||
@@ -62,6 +62,7 @@ func init() {
|
||||
}
|
||||
|
||||
viper.Set("kubernetesClient", kubernetesClient)
|
||||
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
|
||||
19
cmd/version.go
Normal file
19
cmd/version.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// versionCmd represents the version command
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
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", version)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
}
|
||||
13
go.mod
13
go.mod
@@ -3,12 +3,13 @@ module github.com/k8sgpt-ai/k8sgpt
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/briandowns/spinner v1.23.0
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/sashabaranov/go-openai v1.5.6
|
||||
github.com/sashabaranov/go-openai v1.5.7
|
||||
github.com/schollz/progressbar/v3 v3.13.1
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/viper v1.15.0
|
||||
golang.org/x/term v0.6.0
|
||||
k8s.io/api v0.26.3
|
||||
k8s.io/apimachinery v0.26.3
|
||||
k8s.io/client-go v0.26.3
|
||||
)
|
||||
@@ -35,20 +36,23 @@ require (
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/spf13/afero v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.5.0 // 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
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/time v0.1.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
@@ -56,7 +60,6 @@ require (
|
||||
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/api v0.26.3 // indirect
|
||||
k8s.io/klog/v2 v2.80.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
|
||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
|
||||
|
||||
28
go.sum
28
go.sum
@@ -38,8 +38,6 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A=
|
||||
github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
@@ -164,6 +162,7 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
@@ -185,6 +184,10 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -205,15 +208,16 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sashabaranov/go-openai v1.5.4 h1:I2K7JMIx/EC/mwT2fbypBzJ3OtwKNxaFg4jf3KOvXuc=
|
||||
github.com/sashabaranov/go-openai v1.5.4/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/sashabaranov/go-openai v1.5.5 h1:VYdzEGVk4zV04ZNqNb1DT8w7JCzWM77h3h6pBH27B1k=
|
||||
github.com/sashabaranov/go-openai v1.5.5/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/sashabaranov/go-openai v1.5.6 h1:i/DI9y1kzlPqKA0KeTYezJJSy01sqpOdUIm2BV7vgtA=
|
||||
github.com/sashabaranov/go-openai v1.5.6/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/sashabaranov/go-openai v1.5.7 h1:8DGgRG+P7yWixte5j720y6yiXgY3Hlgcd0gcpHdltfo=
|
||||
github.com/sashabaranov/go-openai v1.5.7/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE=
|
||||
github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ=
|
||||
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
|
||||
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
@@ -323,8 +327,8 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -393,8 +397,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
||||
BIN
images/banner-black.png
Normal file
BIN
images/banner-black.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
BIN
images/banner-white.png
Normal file
BIN
images/banner-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
BIN
images/demo3.png
Normal file
BIN
images/demo3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 352 KiB |
BIN
images/demo4.gif
Normal file
BIN
images/demo4.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 215 KiB |
BIN
images/image.png
Normal file
BIN
images/image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 308 KiB |
BIN
images/landing.png
Normal file
BIN
images/landing.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 403 KiB |
4
main.go
4
main.go
@@ -5,6 +5,8 @@ package main
|
||||
|
||||
import "github.com/k8sgpt-ai/k8sgpt/cmd"
|
||||
|
||||
var version = "dev"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
cmd.Execute(version)
|
||||
}
|
||||
|
||||
41
pkg/ai/ai.go
41
pkg/ai/ai.go
@@ -2,43 +2,42 @@ package ai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/sashabaranov/go-openai"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
client *openai.Client
|
||||
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?"
|
||||
)
|
||||
|
||||
type OpenAIClient struct {
|
||||
client *openai.Client
|
||||
language string
|
||||
}
|
||||
|
||||
func (c *Client) GetClient() *openai.Client {
|
||||
return c.client
|
||||
}
|
||||
|
||||
func NewClient() (*Client, error) {
|
||||
|
||||
// get the token with viper
|
||||
token := viper.GetString("openai_api_key")
|
||||
// check if nil
|
||||
if token == "" {
|
||||
return nil, fmt.Errorf("no OpenAI API Key found")
|
||||
}
|
||||
|
||||
func (c *OpenAIClient) Configure(token string, language string) error {
|
||||
client := openai.NewClient(token)
|
||||
return &Client{
|
||||
client: client,
|
||||
}, nil
|
||||
if client == nil {
|
||||
return errors.New("error creating OpenAI client")
|
||||
}
|
||||
c.language = language
|
||||
c.client = client
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) GetCompletion(ctx context.Context, prompt string) (string, error) {
|
||||
func (c *OpenAIClient) GetCompletion(ctx context.Context, prompt string) (string, error) {
|
||||
// Create a completion request
|
||||
resp, err := c.client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
|
||||
Model: openai.GPT3Dot5Turbo,
|
||||
Messages: []openai.ChatCompletionMessage{
|
||||
{
|
||||
Role: "user",
|
||||
Content: "Simplify the following Kubernetes error message and provide a solution: " + prompt,
|
||||
Content: fmt.Sprintf(default_prompt, c.language, prompt),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
8
pkg/ai/iai.go
Normal file
8
pkg/ai/iai.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package ai
|
||||
|
||||
import "context"
|
||||
|
||||
type IAI interface {
|
||||
Configure(token string, language string) error
|
||||
GetCompletion(ctx context.Context, prompt string) (string, error)
|
||||
}
|
||||
30
pkg/analyzer/analysis.go
Normal file
30
pkg/analyzer/analysis.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
)
|
||||
|
||||
type AnalysisConfiguration struct {
|
||||
Namespace string
|
||||
NoCache bool
|
||||
Explain bool
|
||||
}
|
||||
|
||||
type PreAnalysis struct {
|
||||
Pod v1.Pod
|
||||
FailureDetails []string
|
||||
ReplicaSet appsv1.ReplicaSet
|
||||
PersistentVolumeClaim v1.PersistentVolumeClaim
|
||||
Endpoint v1.Endpoints
|
||||
Ingress networkingv1.Ingress
|
||||
}
|
||||
|
||||
type Analysis struct {
|
||||
Kind string `json:"kind"`
|
||||
Name string `json:"name"`
|
||||
Error []string `json:"error"`
|
||||
Details string `json:"details"`
|
||||
ParentObject string `json:"parentObject"`
|
||||
}
|
||||
@@ -2,19 +2,82 @@ package analyzer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func RunAnalysis(ctx context.Context, client *kubernetes.Client, aiClient *ai.Client, explain bool) error {
|
||||
err := AnalyzePod(ctx, client, aiClient, explain)
|
||||
if err != nil {
|
||||
return err
|
||||
var analyzerMap = map[string]func(ctx context.Context, config *AnalysisConfiguration,
|
||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error{
|
||||
"Pod": AnalyzePod,
|
||||
"ReplicaSet": AnalyzeReplicaSet,
|
||||
"PersistentVolumeClaim": AnalyzePersistentVolumeClaim,
|
||||
"Service": AnalyzeEndpoints,
|
||||
"Ingress": AnalyzeIngress,
|
||||
}
|
||||
|
||||
func RunAnalysis(ctx context.Context, filters []string, config *AnalysisConfiguration,
|
||||
client *kubernetes.Client,
|
||||
aiClient ai.IAI, analysisResults *[]Analysis) error {
|
||||
|
||||
// if there are no filters selected then run all of them
|
||||
if len(filters) == 0 {
|
||||
for _, analyzer := range analyzerMap {
|
||||
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
err = AnalyzeReplicaSet(ctx, client, aiClient, explain)
|
||||
if err != nil {
|
||||
return err
|
||||
for _, filter := range filters {
|
||||
if analyzer, ok := analyzerMap[filter]; ok {
|
||||
if err := analyzer(ctx, config, client, aiClient, analysisResults); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseViaAI(ctx context.Context, config *AnalysisConfiguration,
|
||||
aiClient ai.IAI, prompt []string) (string, error) {
|
||||
// parse the text with the AI backend
|
||||
inputKey := strings.Join(prompt, " ")
|
||||
// Check for cached data
|
||||
sEnc := base64.StdEncoding.EncodeToString([]byte(inputKey))
|
||||
// find in viper cache
|
||||
if viper.IsSet(sEnc) && !config.NoCache {
|
||||
// retrieve data from cache
|
||||
response := viper.GetString(sEnc)
|
||||
if response == "" {
|
||||
color.Red("error retrieving cached data")
|
||||
return "", nil
|
||||
}
|
||||
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 := aiClient.GetCompletion(ctx, inputKey)
|
||||
if err != nil {
|
||||
color.Red("error getting completion: %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !viper.IsSet(sEnc) {
|
||||
viper.Set(sEnc, base64.StdEncoding.EncodeToString([]byte(response)))
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
color.Red("error writing config: %v", err)
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
@@ -31,3 +31,27 @@ func FetchLatestPodEvent(ctx context.Context, kubernetesClient *kubernetes.Clien
|
||||
}
|
||||
return latestEvent, nil
|
||||
}
|
||||
|
||||
func FetchLatestPvcEvent(ctx context.Context, kubernetesClient *kubernetes.Client, pvc *v1.PersistentVolumeClaim) (*v1.Event, error) {
|
||||
|
||||
// get the list of events
|
||||
events, err := kubernetesClient.GetClient().CoreV1().Events(pvc.Namespace).List(ctx,
|
||||
metav1.ListOptions{
|
||||
FieldSelector: "involvedObject.name=" + pvc.Name,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// find most recent event
|
||||
var latestEvent *v1.Event
|
||||
for _, event := range events.Items {
|
||||
if latestEvent == nil {
|
||||
latestEvent = &event
|
||||
}
|
||||
if event.LastTimestamp.After(latestEvent.LastTimestamp.Time) {
|
||||
latestEvent = &event
|
||||
}
|
||||
}
|
||||
return latestEvent, nil
|
||||
}
|
||||
|
||||
64
pkg/analyzer/ingressAnalyzer.go
Normal file
64
pkg/analyzer/ingressAnalyzer.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func AnalyzeIngress(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI,
|
||||
analysisResults *[]Analysis) error {
|
||||
|
||||
list, err := client.GetClient().NetworkingV1().Ingresses(config.Namespace).List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
|
||||
for _, ing := range list.Items {
|
||||
var failures []string
|
||||
// loop over rules
|
||||
for _, rule := range ing.Spec.Rules {
|
||||
// loop over paths
|
||||
for _, path := range rule.HTTP.Paths {
|
||||
_, err := client.GetClient().CoreV1().Services(ing.Namespace).Get(ctx, path.Backend.Service.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
failures = append(failures, fmt.Sprintf("Ingress uses the service %s/%s which does not exist.", ing.Namespace, path.Backend.Service.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, tls := range ing.Spec.TLS {
|
||||
_, err := client.GetClient().CoreV1().Secrets(ing.Namespace).Get(ctx, tls.SecretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
failures = append(failures, fmt.Sprintf("Ingress uses the secret %s/%s as a TLS certificate which does not exist.", ing.Namespace, tls.SecretName))
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
preAnalysis[fmt.Sprintf("%s/%s", ing.Namespace, ing.Name)] = PreAnalysis{
|
||||
Ingress: ing,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
Kind: "Ingress",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.Ingress.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -2,116 +2,79 @@ package analyzer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/briandowns/spinner"
|
||||
"github.com/fatih/color"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func AnalyzePod(ctx context.Context, client *kubernetes.Client, aiClient *ai.Client, explain bool) error {
|
||||
func AnalyzePod(ctx context.Context, config *AnalysisConfiguration,
|
||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error {
|
||||
|
||||
// search all namespaces for pods that are not running
|
||||
list, err := client.GetClient().CoreV1().Pods("").List(ctx, metav1.ListOptions{})
|
||||
list, err := client.GetClient().CoreV1().Pods(config.Namespace).List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var brokenPods = map[string][]string{}
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
|
||||
for _, pod := range list.Items {
|
||||
|
||||
var failures []string
|
||||
// Check for pending pods
|
||||
if pod.Status.Phase == "Pending" {
|
||||
|
||||
// Check through container status to check for crashes
|
||||
for _, containerStatus := range pod.Status.Conditions {
|
||||
if containerStatus.Type == "PodScheduled" && containerStatus.Reason == "Unschedulable" {
|
||||
brokenPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = []string{containerStatus.Message}
|
||||
if containerStatus.Message != "" {
|
||||
failures = []string{containerStatus.Message}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check through container status to check for crashes
|
||||
var failureDetails = []string{}
|
||||
for _, containerStatus := range pod.Status.ContainerStatuses {
|
||||
if containerStatus.State.Waiting != nil {
|
||||
if containerStatus.State.Waiting.Reason == "CrashLoopBackOff" || containerStatus.State.Waiting.Reason == "ImagePullBackOff" {
|
||||
|
||||
failureDetails = append(failureDetails, containerStatus.State.Waiting.Message)
|
||||
brokenPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = failureDetails
|
||||
if containerStatus.State.Waiting.Message != "" {
|
||||
failures = append(failures, containerStatus.State.Waiting.Message)
|
||||
}
|
||||
}
|
||||
// This represents a container that is still being created or blocked due to conditions such as OOMKilled
|
||||
if containerStatus.State.Waiting.Reason == "ContainerCreating" && pod.Status.Phase == "Pending" {
|
||||
|
||||
// parse the event log and append details
|
||||
evt, err := FetchLatestPodEvent(ctx, client, &pod)
|
||||
if err != nil {
|
||||
if err != nil || evt == nil {
|
||||
continue
|
||||
}
|
||||
if evt.Reason == "FailedCreatePodSandBox" {
|
||||
failureDetails = append(failureDetails, evt.Message)
|
||||
brokenPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = failureDetails
|
||||
if evt.Reason == "FailedCreatePodSandBox" && evt.Message != "" {
|
||||
failures = append(failures, evt.Message)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if len(failures) > 0 {
|
||||
preAnalysis[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = PreAnalysis{
|
||||
Pod: pod,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count := 0
|
||||
for key, value := range brokenPods {
|
||||
fmt.Printf("%s: %s: %s\n", color.CyanString("%d", count), color.YellowString(key), color.RedString(value[0]))
|
||||
count++
|
||||
if explain {
|
||||
s := spinner.New(spinner.CharSets[35], 100*time.Millisecond) // Build our new spinner
|
||||
s.Start()
|
||||
|
||||
inputValue := strings.Join(value, " ")
|
||||
|
||||
// Check for cached data
|
||||
sEnc := base64.StdEncoding.EncodeToString([]byte(inputValue))
|
||||
// find in viper cache
|
||||
if viper.IsSet(sEnc) {
|
||||
s.Stop()
|
||||
// retrieve data from cache
|
||||
response := viper.GetString(sEnc)
|
||||
if response == "" {
|
||||
color.Red("error retrieving cached data")
|
||||
continue
|
||||
}
|
||||
output, err := base64.StdEncoding.DecodeString(response)
|
||||
if err != nil {
|
||||
color.Red("error decoding cached data: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
color.Green(string(output))
|
||||
continue
|
||||
}
|
||||
|
||||
response, err := aiClient.GetCompletion(ctx, inputValue)
|
||||
s.Stop()
|
||||
if err != nil {
|
||||
color.Red("error getting completion: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !viper.IsSet(sEnc) {
|
||||
viper.Set(sEnc, base64.StdEncoding.EncodeToString([]byte(response)))
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
color.Green(response)
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
Kind: "Pod",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.Pod.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
59
pkg/analyzer/pvcAnalyzer.go
Normal file
59
pkg/analyzer/pvcAnalyzer.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func AnalyzePersistentVolumeClaim(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error {
|
||||
|
||||
// search all namespaces for pods that are not running
|
||||
list, err := client.GetClient().CoreV1().PersistentVolumeClaims(config.Namespace).List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
|
||||
for _, pvc := range list.Items {
|
||||
var failures []string
|
||||
|
||||
// Check for empty rs
|
||||
if pvc.Status.Phase == "Pending" {
|
||||
|
||||
// parse the event log and append details
|
||||
evt, err := FetchLatestPvcEvent(ctx, client, &pvc)
|
||||
if err != nil || evt == nil {
|
||||
continue
|
||||
}
|
||||
if evt.Reason == "ProvisioningFailed" && evt.Message != "" {
|
||||
failures = append(failures, evt.Message)
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
preAnalysis[fmt.Sprintf("%s/%s", pvc.Namespace, pvc.Name)] = PreAnalysis{
|
||||
PersistentVolumeClaim: pvc,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
Kind: "PersistentVolumeClaim",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.PersistentVolumeClaim.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -2,29 +2,27 @@ package analyzer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/briandowns/spinner"
|
||||
"github.com/fatih/color"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func AnalyzeReplicaSet(ctx context.Context, client *kubernetes.Client, aiClient *ai.Client, explain bool) error {
|
||||
func AnalyzeReplicaSet(ctx context.Context, config *AnalysisConfiguration,
|
||||
client *kubernetes.Client, aiClient ai.IAI, analysisResults *[]Analysis) error {
|
||||
|
||||
// search all namespaces for pods that are not running
|
||||
list, err := client.GetClient().AppsV1().ReplicaSets("").List(ctx, metav1.ListOptions{})
|
||||
list, err := client.GetClient().AppsV1().ReplicaSets(config.Namespace).List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var brokenRS = map[string][]string{}
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
|
||||
for _, rs := range list.Items {
|
||||
var failures []string
|
||||
|
||||
// Check for empty rs
|
||||
if rs.Status.Replicas == 0 {
|
||||
@@ -32,57 +30,28 @@ func AnalyzeReplicaSet(ctx context.Context, client *kubernetes.Client, aiClient
|
||||
// Check through container status to check for crashes
|
||||
for _, rsStatus := range rs.Status.Conditions {
|
||||
if rsStatus.Type == "ReplicaFailure" && rsStatus.Reason == "FailedCreate" {
|
||||
brokenRS[fmt.Sprintf("%s/%s", rs.Namespace, rs.Name)] = []string{rsStatus.Message}
|
||||
failures = []string{rsStatus.Message}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
preAnalysis[fmt.Sprintf("%s/%s", rs.Namespace, rs.Name)] = PreAnalysis{
|
||||
ReplicaSet: rs,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count := 0
|
||||
for key, value := range brokenRS {
|
||||
fmt.Printf("%s: %s: %s\n", color.CyanString("%d", count), color.YellowString(key), color.RedString(value[0]))
|
||||
count++
|
||||
if explain {
|
||||
s := spinner.New(spinner.CharSets[35], 100*time.Millisecond) // Build our new spinner
|
||||
s.Start()
|
||||
|
||||
inputValue := strings.Join(value, " ")
|
||||
|
||||
// Check for cached data
|
||||
sEnc := base64.StdEncoding.EncodeToString([]byte(inputValue))
|
||||
// find in viper cache
|
||||
if viper.IsSet(sEnc) {
|
||||
s.Stop()
|
||||
// retrieve data from cache
|
||||
response := viper.GetString(sEnc)
|
||||
if response == "" {
|
||||
color.Red("error retrieving cached data")
|
||||
continue
|
||||
}
|
||||
output, err := base64.StdEncoding.DecodeString(response)
|
||||
if err != nil {
|
||||
color.Red("error decoding cached data: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
color.Green(string(output))
|
||||
continue
|
||||
}
|
||||
|
||||
response, err := aiClient.GetCompletion(ctx, inputValue)
|
||||
s.Stop()
|
||||
if err != nil {
|
||||
color.Red("error getting completion: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !viper.IsSet(sEnc) {
|
||||
viper.Set(sEnc, base64.StdEncoding.EncodeToString([]byte(response)))
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
Kind: "ReplicaSet",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.ReplicaSet.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
75
pkg/analyzer/serviceAnalyzer.go
Normal file
75
pkg/analyzer/serviceAnalyzer.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func AnalyzeEndpoints(ctx context.Context, config *AnalysisConfiguration, client *kubernetes.Client, aiClient ai.IAI,
|
||||
analysisResults *[]Analysis) error {
|
||||
|
||||
// search all namespaces for pods that are not running
|
||||
list, err := client.GetClient().CoreV1().Endpoints(config.Namespace).List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var preAnalysis = map[string]PreAnalysis{}
|
||||
|
||||
for _, ep := range list.Items {
|
||||
var failures []string
|
||||
|
||||
// Check for empty service
|
||||
if len(ep.Subsets) == 0 {
|
||||
svc, err := client.GetClient().CoreV1().Services(ep.Namespace).Get(ctx, ep.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
color.Yellow("Service %s/%s does not exist", ep.Namespace, ep.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
for k, v := range svc.Spec.Selector {
|
||||
failures = append(failures, fmt.Sprintf("Service has no endpoints, expected label %s=%s", k, v))
|
||||
}
|
||||
} else {
|
||||
count := 0
|
||||
pods := []string{}
|
||||
|
||||
// Check through container status to check for crashes
|
||||
for _, epSubset := range ep.Subsets {
|
||||
if len(epSubset.NotReadyAddresses) > 0 {
|
||||
for _, addresses := range epSubset.NotReadyAddresses {
|
||||
count++
|
||||
pods = append(pods, addresses.TargetRef.Kind+"/"+addresses.TargetRef.Name)
|
||||
}
|
||||
failures = append(failures, fmt.Sprintf("Service has not ready endpoints, pods: %s, expected %d", pods, count))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(failures) > 0 {
|
||||
preAnalysis[fmt.Sprintf("%s/%s", ep.Namespace, ep.Name)] = PreAnalysis{
|
||||
Endpoint: ep,
|
||||
FailureDetails: failures,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for key, value := range preAnalysis {
|
||||
var currentAnalysis = Analysis{
|
||||
Kind: "Service",
|
||||
Name: key,
|
||||
Error: value.FailureDetails,
|
||||
}
|
||||
|
||||
parent, _ := util.GetParent(client, value.Endpoint.ObjectMeta)
|
||||
currentAnalysis.ParentObject = parent
|
||||
*analysisResults = append(*analysisResults, currentAnalysis)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
67
pkg/util/util.go
Normal file
67
pkg/util/util.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func GetParent(client *kubernetes.Client, meta metav1.ObjectMeta) (string, bool) {
|
||||
if meta.OwnerReferences != nil {
|
||||
for _, owner := range meta.OwnerReferences {
|
||||
switch owner.Kind {
|
||||
case "ReplicaSet":
|
||||
rs, err := client.GetClient().AppsV1().ReplicaSets(meta.Namespace).Get(context.Background(), owner.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
if rs.OwnerReferences != nil {
|
||||
return GetParent(client, rs.ObjectMeta)
|
||||
}
|
||||
return "ReplicaSet/" + rs.Name, false
|
||||
|
||||
case "Deployment":
|
||||
dep, err := client.GetClient().AppsV1().Deployments(meta.Namespace).Get(context.Background(), owner.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
if dep.OwnerReferences != nil {
|
||||
return GetParent(client, dep.ObjectMeta)
|
||||
}
|
||||
return "Deployment/" + dep.Name, false
|
||||
|
||||
case "StatefulSet":
|
||||
sts, err := client.GetClient().AppsV1().StatefulSets(meta.Namespace).Get(context.Background(), owner.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
if sts.OwnerReferences != nil {
|
||||
return GetParent(client, sts.ObjectMeta)
|
||||
}
|
||||
return "StatefulSet/" + sts.Name, false
|
||||
|
||||
case "DaemonSet":
|
||||
ds, err := client.GetClient().AppsV1().DaemonSets(meta.Namespace).Get(context.Background(), owner.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
if ds.OwnerReferences != nil {
|
||||
return GetParent(client, ds.ObjectMeta)
|
||||
}
|
||||
return "DaemonSet/" + ds.Name, false
|
||||
|
||||
case "Ingress":
|
||||
ds, err := client.GetClient().NetworkingV1().Ingresses(meta.Namespace).Get(context.Background(), owner.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
if ds.OwnerReferences != nil {
|
||||
return GetParent(client, ds.ObjectMeta)
|
||||
}
|
||||
return "Ingress/" + ds.Name, false
|
||||
}
|
||||
}
|
||||
}
|
||||
return meta.Name, false
|
||||
}
|
||||
Reference in New Issue
Block a user