mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-09-03 00:47:17 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51c07b42c3 | ||
|
|
bd7bae6302 | ||
|
|
9d41460d33 | ||
|
|
fb0f81d076 | ||
|
|
78bbea18ac | ||
|
|
224d55b076 | ||
|
|
db967d2896 | ||
|
|
088f0321e7 | ||
|
|
aeaac7a70f | ||
|
|
6b368f2221 | ||
|
|
cb5db1733a | ||
|
|
c2f72ecd0c | ||
|
|
f3bad5f409 | ||
|
|
f438467003 | ||
|
|
a374b0a3ab | ||
|
|
6aaba59ebd | ||
|
|
f18b5d754e | ||
|
|
2ede46ed58 | ||
|
|
07d1747d81 | ||
|
|
db871e6889 | ||
|
|
dc4403811b | ||
|
|
6f7acec7b3 | ||
|
|
123d17ab4a | ||
|
|
867c70619c | ||
|
|
c9830de736 | ||
|
|
ca5ff88964 | ||
|
|
e6aff48f1b | ||
|
|
76c52d2b93 | ||
|
|
bece801ba8 | ||
|
|
72701fa4d2 | ||
|
|
7eae0fe687 | ||
|
|
6f839b389d | ||
|
|
ebe98ff2f1 | ||
|
|
59624e88fd | ||
|
|
15446996f9 | ||
|
|
c4237b6c40 | ||
|
|
d0685ea81a | ||
|
|
742e92f1ee | ||
|
|
553d709043 | ||
|
|
29435b1c15 | ||
|
|
a9b889e033 | ||
|
|
4a84e26f21 | ||
|
|
2eb3aa9883 | ||
|
|
ffd357c1e8 | ||
|
|
09287f624f | ||
|
|
cd7f2dc74d | ||
|
|
8132936e3e | ||
|
|
b49d1050c9 | ||
|
|
27f867bd4e | ||
|
|
f4d2cfb749 | ||
|
|
8620e001d7 | ||
|
|
bb9a2931a1 | ||
|
|
7c6788c0c5 | ||
|
|
e24ca642aa | ||
|
|
7dc9d6dfe4 | ||
|
|
118b2edc0a | ||
|
|
84d51481da | ||
|
|
fad7a26156 | ||
|
|
772d867093 | ||
|
|
5daf6d6c89 | ||
|
|
8b491b5702 | ||
|
|
18efea6616 | ||
|
|
48fc8b2e84 | ||
|
|
e2adfa3774 | ||
|
|
41134ca621 | ||
|
|
05a852d68c | ||
|
|
90d04b1f7d | ||
|
|
de0a2c631c |
+5
-1
@@ -14,4 +14,8 @@
|
||||
## RULES
|
||||
|
||||
* @replicatedhq/troubleshoot
|
||||
*.md @replicatedhq/cre
|
||||
*.md @replicatedhq/cre
|
||||
go.mod
|
||||
go.sum
|
||||
/examples/sdk/helm-template/go.mod
|
||||
/examples/sdk/helm-template/go.sum
|
||||
|
||||
+21
-3
@@ -10,10 +10,28 @@ updates:
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "go"
|
||||
- "type::chore"
|
||||
- "type::security"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
groups:
|
||||
security:
|
||||
update-types:
|
||||
- "patch"
|
||||
- "minor"
|
||||
- package-ecosystem: "gomod" # See documentation for possible values
|
||||
directory: "/examples/sdk/helm-template" # Location of package manifests
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "go"
|
||||
- "type::security"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
security:
|
||||
update-types:
|
||||
- "patch"
|
||||
- "minor"
|
||||
|
||||
# Maintain dependencies for GitHub Actions
|
||||
- package-ecosystem: "github-actions"
|
||||
# Workflow files stored in the
|
||||
@@ -22,6 +40,6 @@ updates:
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "github-actions"
|
||||
- "type::chore"
|
||||
- "type::security"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
name: Automated PRs Manager
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 */6 * * *" # every 6 hours
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
list-prs:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
prs: ${{ steps.list-prs.outputs.prs }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.REPLICATED_GH_PAT }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: List PRs
|
||||
id: list-prs
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# list prs that are less than 24h old and exclude prs from forks
|
||||
|
||||
dependabot_prs=$(
|
||||
gh pr list \
|
||||
--author 'dependabot[bot]' \
|
||||
--json url,createdAt,headRefName,headRepository,headRepositoryOwner \
|
||||
-q '.[] | select((.createdAt | fromdateiso8601 > now - 24*60*60) and .headRepositoryOwner.login == "replicatedhq" and .headRepository.name == "troubleshoot")'
|
||||
)
|
||||
|
||||
prs=$(echo "$dependabot_prs" | jq -sc '. | unique')
|
||||
echo "prs=$prs" >> "$GITHUB_OUTPUT"
|
||||
|
||||
process-prs:
|
||||
needs: list-prs
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.list-prs.outputs.prs != '[]'
|
||||
strategy:
|
||||
matrix:
|
||||
pr: ${{ fromJson(needs.list-prs.outputs.prs) }}
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.REPLICATED_GH_PAT }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ matrix.pr.headRefName }}
|
||||
|
||||
- name: Process PR
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
echo "Ensuring required labels..."
|
||||
gh pr edit "${{ matrix.pr.url }}" --add-label "type::security"
|
||||
|
||||
echo "Checking status of tests..."
|
||||
run_id=$(gh run list --branch "${{ matrix.pr.headRefName }}" --workflow build-test-deploy --limit 1 --json databaseId -q '.[0].databaseId')
|
||||
|
||||
# If there are still pending jobs, skip.
|
||||
|
||||
num_of_pending_jobs=$(gh run view "$run_id" --json jobs -q '.jobs[] | select(.conclusion == "") | .name' | wc -l)
|
||||
if [ "$num_of_pending_jobs" -gt 0 ]; then
|
||||
echo "There are still pending jobs. Skipping."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If all checks passed, approve and merge.
|
||||
if gh run view "$run_id" --json jobs -q '.jobs[] | select(.name == "validate-success") | .conclusion' | grep -q "success"; then
|
||||
if gh pr checks "${{ matrix.pr.url }}"; then
|
||||
echo "All tests passed. Approving and merging."
|
||||
echo -e "LGTM :thumbsup: \n\nThis PR was automatically approved and merged by the [automated-prs-manager](https://github.com/replicatedhq/troubleshoot/blob/main/.github/workflows/automated-prs-manager.yaml) GitHub action" > body.txt
|
||||
gh pr review --approve "${{ matrix.pr.url }}" --body-file body.txt
|
||||
sleep 10
|
||||
gh pr merge --auto --squash "${{ matrix.pr.url }}"
|
||||
exit 0
|
||||
else
|
||||
echo "Some checks did not pass. Skipping."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# If more than half of the jobs are successful, re-run the failed jobs.
|
||||
|
||||
num_of_jobs=$(gh run view "$run_id" --json jobs -q '.jobs[].name ' | wc -l)
|
||||
num_of_successful_jobs=$(gh run view "$run_id" --json jobs -q '.jobs[] | select(.conclusion == "success") | .name' | wc -l)
|
||||
|
||||
if [ "$num_of_successful_jobs" -gt $((num_of_jobs / 2)) ]; then
|
||||
echo "More than half of the jobs are successful. Re-running failed jobs."
|
||||
gh run rerun "$run_id" --failed
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Less than half of the jobs are successful. Skipping."
|
||||
@@ -1,3 +1,5 @@
|
||||
name: build-test-deploy
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
@@ -348,3 +350,40 @@ jobs:
|
||||
uses: rajatjindal/krew-release-bot@v0.0.46
|
||||
with:
|
||||
krew_template_file: deploy/krew/support-bundle.yaml
|
||||
|
||||
|
||||
# summary jobs, these jobs will only run if all the other jobs have succeeded
|
||||
validate-pr-tests:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- test
|
||||
- test-integration
|
||||
- run-examples
|
||||
- compile-collect
|
||||
- validate-preflight
|
||||
- validate-preflight-e2e
|
||||
- validate-supportbundle
|
||||
- validate-supportbundle-e2e
|
||||
- validate-supportbundle-e2e-go-test
|
||||
- ensure-schemas-are-generated
|
||||
steps:
|
||||
- run: echo "All PR tests passed"
|
||||
|
||||
|
||||
# this job will validate that the validation did not fail and that all pr-tests succeed
|
||||
# it is used for the github branch protection rule
|
||||
validate-success:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- validate-pr-tests
|
||||
if: always()
|
||||
steps:
|
||||
# https://docs.github.com/en/actions/learn-github-actions/contexts#needs-context
|
||||
# if the validate-pr-tests job was not successful, this job will fail
|
||||
- name: fail if validate-pr-tests job was not successful
|
||||
if: needs.validate-pr-tests.result != 'success'
|
||||
run: exit 1
|
||||
# if the validate-pr-tests job was successful, this job will succeed
|
||||
- name: succeed if validate-pr-tests job succeeded
|
||||
if: needs.validate-pr-tests.result == 'success'
|
||||
run: echo "Validation succeeded"
|
||||
@@ -40,7 +40,7 @@ E2EPATHS = ./test/e2e/...
|
||||
TESTFLAGS ?= -v -coverprofile cover.out
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
all: build test
|
||||
all: clean build test
|
||||
|
||||
.PHONY: ffi
|
||||
ffi: fmt vet
|
||||
@@ -80,6 +80,8 @@ support-bundle-e2e-go-test:
|
||||
go test ${BUILDFLAGS} ${E2EPATHS} -v; \
|
||||
fi
|
||||
|
||||
rebuild: clean build
|
||||
|
||||
# Build all binaries in parallel ( -j )
|
||||
build: tidy
|
||||
@echo "Build cli binaries"
|
||||
@@ -160,13 +162,13 @@ bin/docsgen:
|
||||
go build ${LDFLAGS} -o bin/docsgen github.com/replicatedhq/troubleshoot/cmd/docsgen
|
||||
|
||||
controller-gen:
|
||||
go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.2
|
||||
go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0
|
||||
CONTROLLER_GEN=$(shell which controller-gen)
|
||||
|
||||
.PHONY: client-gen
|
||||
client-gen:
|
||||
go install k8s.io/code-generator/cmd/client-gen@v0.28.2
|
||||
CLIENT_GEN=$(shell go env GOPATH)/bin/client-gen
|
||||
go install k8s.io/code-generator/cmd/client-gen@v0.28.8
|
||||
CLIENT_GEN=$(shell which client-gen)
|
||||
|
||||
.PHONY: release
|
||||
release: export GITHUB_TOKEN = $(shell echo ${GITHUB_TOKEN_TROUBLESHOOT})
|
||||
|
||||
+53
-29
@@ -106,6 +106,22 @@ func runTroubleshoot(v *viper.Viper, args []string) error {
|
||||
})
|
||||
}
|
||||
|
||||
if interactive {
|
||||
c := color.New()
|
||||
c.Println(fmt.Sprintf("\r%s\r", cursor.ClearEntireLine()))
|
||||
}
|
||||
|
||||
if interactive {
|
||||
if len(mainBundle.Spec.HostCollectors) > 0 && !util.IsRunningAsRoot() {
|
||||
fmt.Print(cursor.Show())
|
||||
if util.PromptYesNo(util.HOST_COLLECTORS_RUN_AS_ROOT_PROMPT) {
|
||||
fmt.Println("Exiting...")
|
||||
return nil
|
||||
}
|
||||
fmt.Print(cursor.Hide())
|
||||
}
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
collectorCB := func(c chan interface{}, msg string) { c <- msg }
|
||||
progressChan := make(chan interface{})
|
||||
@@ -174,11 +190,6 @@ func runTroubleshoot(v *viper.Viper, args []string) error {
|
||||
|
||||
nonInteractiveOutput := analysisOutput{}
|
||||
|
||||
if interactive {
|
||||
c := color.New()
|
||||
c.Println(fmt.Sprintf("\r%s\r", cursor.ClearEntireLine()))
|
||||
}
|
||||
|
||||
response, err := supportbundle.CollectSupportBundleFromSpec(&mainBundle.Spec, additionalRedactors, createOpts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to run collect and analyze process")
|
||||
@@ -234,35 +245,42 @@ the %s Admin Console to begin analysis.`
|
||||
|
||||
// loadSupportBundleSpecsFromURIs loads support bundle specs from URIs
|
||||
func loadSupportBundleSpecsFromURIs(ctx context.Context, kinds *loader.TroubleshootKinds) error {
|
||||
remoteRawSpecs := []string{}
|
||||
moreKinds := loader.NewTroubleshootKinds()
|
||||
|
||||
// iterate through original kinds and replace any support bundle spec with provided uri spec
|
||||
for _, s := range kinds.SupportBundlesV1Beta2 {
|
||||
if s.Spec.Uri != "" && util.IsURL(s.Spec.Uri) {
|
||||
// We are using LoadSupportBundleSpec function here since it handles prompting
|
||||
// users to accept insecure connections
|
||||
// There is an opportunity to refactor this code in favour of the Loader APIs
|
||||
// TODO: Pass ctx to LoadSupportBundleSpec
|
||||
rawSpec, err := supportbundle.LoadSupportBundleSpec(s.Spec.Uri)
|
||||
if err != nil {
|
||||
// In the event a spec can't be loaded, we'll just skip it and print a warning
|
||||
klog.Warningf("unable to load support bundle from URI: %q: %v", s.Spec.Uri, err)
|
||||
continue
|
||||
}
|
||||
remoteRawSpecs = append(remoteRawSpecs, string(rawSpec))
|
||||
if s.Spec.Uri == "" || !util.IsURL(s.Spec.Uri) {
|
||||
moreKinds.SupportBundlesV1Beta2 = append(moreKinds.SupportBundlesV1Beta2, s)
|
||||
continue
|
||||
}
|
||||
|
||||
// We are using LoadSupportBundleSpec function here since it handles prompting
|
||||
// users to accept insecure connections
|
||||
// There is an opportunity to refactor this code in favour of the Loader APIs
|
||||
// TODO: Pass ctx to LoadSupportBundleSpec
|
||||
rawSpec, err := supportbundle.LoadSupportBundleSpec(s.Spec.Uri)
|
||||
if err != nil {
|
||||
// add back original spec
|
||||
moreKinds.SupportBundlesV1Beta2 = append(moreKinds.SupportBundlesV1Beta2, s)
|
||||
// In the event a spec can't be loaded, we'll just skip it and print a warning
|
||||
klog.Warningf("unable to load support bundle from URI: %q: %v", s.Spec.Uri, err)
|
||||
continue
|
||||
}
|
||||
k, err := loader.LoadSpecs(ctx, loader.LoadOptions{RawSpec: string(rawSpec)})
|
||||
if err != nil {
|
||||
// add back original spec
|
||||
moreKinds.SupportBundlesV1Beta2 = append(moreKinds.SupportBundlesV1Beta2, s)
|
||||
klog.Warningf("unable to load spec: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// finally append the uri spec
|
||||
moreKinds.SupportBundlesV1Beta2 = append(moreKinds.SupportBundlesV1Beta2, k.SupportBundlesV1Beta2...)
|
||||
|
||||
}
|
||||
|
||||
if len(remoteRawSpecs) == 0 {
|
||||
return nil
|
||||
}
|
||||
kinds.SupportBundlesV1Beta2 = moreKinds.SupportBundlesV1Beta2
|
||||
|
||||
moreKinds, err := loader.LoadSpecs(ctx, loader.LoadOptions{
|
||||
RawSpecs: remoteRawSpecs,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kinds.Add(moreKinds)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -344,6 +362,12 @@ func loadSpecs(ctx context.Context, args []string, client kubernetes.Interface)
|
||||
additionalRedactors.Spec.Redactors = util.Append(additionalRedactors.Spec.Redactors, r.Spec.Redactors)
|
||||
}
|
||||
|
||||
// dedupe specs
|
||||
mainBundle.Spec.Collectors = util.Dedup(mainBundle.Spec.Collectors)
|
||||
mainBundle.Spec.Analyzers = util.Dedup(mainBundle.Spec.Analyzers)
|
||||
mainBundle.Spec.HostCollectors = util.Dedup(mainBundle.Spec.HostCollectors)
|
||||
mainBundle.Spec.HostAnalyzers = util.Dedup(mainBundle.Spec.HostAnalyzers)
|
||||
|
||||
return mainBundle, additionalRedactors, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ import (
|
||||
testclient "k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
var orig = `
|
||||
func templSpec() string {
|
||||
return `
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
@@ -30,6 +31,7 @@ spec:
|
||||
name: kube-root-ca.crt
|
||||
namespace: default
|
||||
`
|
||||
}
|
||||
|
||||
func Test_loadSupportBundleSpecsFromURIs(t *testing.T) {
|
||||
// Run a webserver to serve the spec
|
||||
@@ -45,7 +47,7 @@ spec:
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
orig := strings.ReplaceAll(orig, "$MY_URI", srv.URL)
|
||||
orig := strings.ReplaceAll(templSpec(), "$MY_URI", srv.URL)
|
||||
|
||||
ctx := context.Background()
|
||||
kinds, err := loader.LoadSpecs(ctx, loader.LoadOptions{RawSpec: orig})
|
||||
@@ -57,8 +59,73 @@ spec:
|
||||
err = loadSupportBundleSpecsFromURIs(ctx, kinds)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, kinds.SupportBundlesV1Beta2, 2)
|
||||
assert.NotNil(t, kinds.SupportBundlesV1Beta2[1].Spec.Collectors[0].ClusterInfo)
|
||||
require.Len(t, kinds.SupportBundlesV1Beta2, 1)
|
||||
assert.NotNil(t, kinds.SupportBundlesV1Beta2[0].Spec.Collectors[0].ClusterInfo)
|
||||
}
|
||||
|
||||
func Test_loadMultipleSupportBundleSpecsWithNoURIs(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
client := testclient.NewSimpleClientset()
|
||||
specs := []string{testutils.ServeFromFilePath(t, `
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
name: sb-1
|
||||
spec:
|
||||
collectors:
|
||||
- clusterInfo:{}`), testutils.ServeFromFilePath(t, `
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
name: sb-2
|
||||
spec:
|
||||
collectors:
|
||||
- clusterInfo: {}`)}
|
||||
|
||||
sb, _, err := loadSpecs(ctx, specs, client)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, sb.Spec.Collectors, 2)
|
||||
}
|
||||
|
||||
func Test_loadMultipleSupportBundleSpecsWithURIs(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
client := testclient.NewSimpleClientset()
|
||||
|
||||
specFile := testutils.ServeFromFilePath(t, `
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
name: sb-file
|
||||
spec:
|
||||
collectors:
|
||||
- logs:
|
||||
name: podlogs/kotsadm
|
||||
selector:
|
||||
- app=kotsadm
|
||||
`)
|
||||
|
||||
// Run a webserver to serve the spec
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(`
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
name: sb-uri
|
||||
spec:
|
||||
collectors:
|
||||
- clusterInfo: {}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
orig := strings.ReplaceAll(templSpec(), "$MY_URI", srv.URL)
|
||||
specUri := testutils.ServeFromFilePath(t, orig)
|
||||
specs := []string{specFile, specUri}
|
||||
|
||||
sb, _, err := loadSpecs(ctx, specs, client)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, sb.Spec.Collectors[0].Logs)
|
||||
assert.Nil(t, sb.Spec.Collectors[1].ConfigMap) // original spec gone
|
||||
assert.NotNil(t, sb.Spec.Collectors[1].ClusterInfo) // new spec from URI
|
||||
}
|
||||
|
||||
func Test_loadSupportBundleSpecsFromURIs_TimeoutError(t *testing.T) {
|
||||
@@ -69,7 +136,7 @@ func Test_loadSupportBundleSpecsFromURIs_TimeoutError(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
kinds, err := loader.LoadSpecs(ctx, loader.LoadOptions{
|
||||
RawSpec: strings.ReplaceAll(orig, "$MY_URI", srv.URL),
|
||||
RawSpec: strings.ReplaceAll(templSpec(), "$MY_URI", srv.URL),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -276,3 +343,31 @@ spec:
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_loadDuplicatedBundleSpecs(t *testing.T) {
|
||||
spec := testutils.ServeFromFilePath(t, `
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
name: sb
|
||||
spec:
|
||||
collectors:
|
||||
- helm: {}
|
||||
analyzers:
|
||||
- clusterVersion: {}
|
||||
hostCollectors:
|
||||
- cpu: {}
|
||||
hostAnalyzers:
|
||||
- cpu: {}
|
||||
`)
|
||||
args := []string{spec, spec}
|
||||
|
||||
ctx := context.Background()
|
||||
client := testclient.NewSimpleClientset()
|
||||
sb, _, err := loadSpecs(ctx, args, client)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, sb.Spec.Collectors, 1+2) // default clusterInfo + clusterResources
|
||||
assert.Len(t, sb.Spec.Analyzers, 1)
|
||||
assert.Len(t, sb.Spec.HostCollectors, 1)
|
||||
assert.Len(t, sb.Spec.HostAnalyzers, 1)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.2
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
name: analyzers.troubleshoot.replicated.com
|
||||
spec:
|
||||
group: troubleshoot.replicated.com
|
||||
@@ -21,14 +20,19 @@ spec:
|
||||
description: Analyzer is the Schema for the analyzers API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
|
||||
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.2
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
name: collectors.troubleshoot.replicated.com
|
||||
spec:
|
||||
group: troubleshoot.replicated.com
|
||||
@@ -21,14 +20,19 @@ spec:
|
||||
description: Collector is the Schema for the collectors API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
@@ -164,10 +168,10 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: A Duration represents the elapsed time
|
||||
between two instants as an int64 nanosecond count.
|
||||
The representation limits the largest representable
|
||||
duration to approximately 290 years.
|
||||
description: |-
|
||||
A Duration represents the elapsed time between two instants
|
||||
as an int64 nanosecond count. The representation limits the
|
||||
largest representable duration to approximately 290 years.
|
||||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
@@ -188,10 +192,10 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: A Duration represents the elapsed time
|
||||
between two instants as an int64 nanosecond count.
|
||||
The representation limits the largest representable
|
||||
duration to approximately 290 years.
|
||||
description: |-
|
||||
A Duration represents the elapsed time between two instants
|
||||
as an int64 nanosecond count. The representation limits the
|
||||
largest representable duration to approximately 290 years.
|
||||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
@@ -210,10 +214,10 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: A Duration represents the elapsed time
|
||||
between two instants as an int64 nanosecond count.
|
||||
The representation limits the largest representable
|
||||
duration to approximately 290 years.
|
||||
description: |-
|
||||
A Duration represents the elapsed time between two instants
|
||||
as an int64 nanosecond count. The representation limits the
|
||||
largest representable duration to approximately 290 years.
|
||||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
|
||||
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.2
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
name: preflights.troubleshoot.replicated.com
|
||||
spec:
|
||||
group: troubleshoot.replicated.com
|
||||
@@ -21,14 +20,19 @@ spec:
|
||||
description: Preflight is the Schema for the preflights API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
@@ -836,10 +840,10 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: A Duration represents the elapsed time
|
||||
between two instants as an int64 nanosecond count.
|
||||
The representation limits the largest representable
|
||||
duration to approximately 290 years.
|
||||
description: |-
|
||||
A Duration represents the elapsed time between two instants
|
||||
as an int64 nanosecond count. The representation limits the
|
||||
largest representable duration to approximately 290 years.
|
||||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
@@ -860,10 +864,10 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: A Duration represents the elapsed time
|
||||
between two instants as an int64 nanosecond count.
|
||||
The representation limits the largest representable
|
||||
duration to approximately 290 years.
|
||||
description: |-
|
||||
A Duration represents the elapsed time between two instants
|
||||
as an int64 nanosecond count. The representation limits the
|
||||
largest representable duration to approximately 290 years.
|
||||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
@@ -882,10 +886,10 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: A Duration represents the elapsed time
|
||||
between two instants as an int64 nanosecond count.
|
||||
The representation limits the largest representable
|
||||
duration to approximately 290 years.
|
||||
description: |-
|
||||
A Duration represents the elapsed time between two instants
|
||||
as an int64 nanosecond count. The representation limits the
|
||||
largest representable duration to approximately 290 years.
|
||||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
|
||||
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.2
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
name: redactors.troubleshoot.replicated.com
|
||||
spec:
|
||||
group: troubleshoot.replicated.com
|
||||
@@ -21,14 +20,19 @@ spec:
|
||||
description: Redactor is the Schema for the redaction API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
|
||||
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.2
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
name: supportbundles.troubleshoot.replicated.com
|
||||
spec:
|
||||
group: troubleshoot.replicated.com
|
||||
@@ -21,14 +20,19 @@ spec:
|
||||
description: SupportBundle is the Schema for the SupportBundles API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
@@ -867,10 +871,10 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: A Duration represents the elapsed time
|
||||
between two instants as an int64 nanosecond count.
|
||||
The representation limits the largest representable
|
||||
duration to approximately 290 years.
|
||||
description: |-
|
||||
A Duration represents the elapsed time between two instants
|
||||
as an int64 nanosecond count. The representation limits the
|
||||
largest representable duration to approximately 290 years.
|
||||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
@@ -891,10 +895,10 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: A Duration represents the elapsed time
|
||||
between two instants as an int64 nanosecond count.
|
||||
The representation limits the largest representable
|
||||
duration to approximately 290 years.
|
||||
description: |-
|
||||
A Duration represents the elapsed time between two instants
|
||||
as an int64 nanosecond count. The representation limits the
|
||||
largest representable duration to approximately 290 years.
|
||||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
@@ -913,10 +917,10 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: A Duration represents the elapsed time
|
||||
between two instants as an int64 nanosecond count.
|
||||
The representation limits the largest representable
|
||||
duration to approximately 290 years.
|
||||
description: |-
|
||||
A Duration represents the elapsed time between two instants
|
||||
as an int64 nanosecond count. The representation limits the
|
||||
largest representable duration to approximately 290 years.
|
||||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
|
||||
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.2
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
name: analyzers.troubleshoot.sh
|
||||
spec:
|
||||
group: troubleshoot.sh
|
||||
@@ -21,14 +20,19 @@ spec:
|
||||
description: Analyzer is the Schema for the analyzers API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
@@ -559,6 +563,65 @@ spec:
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
event:
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: BoolString
|
||||
kind:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
fail:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
when:
|
||||
type: string
|
||||
type: object
|
||||
pass:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
when:
|
||||
type: string
|
||||
type: object
|
||||
warn:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
when:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
reason:
|
||||
type: string
|
||||
regex:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
- reason
|
||||
type: object
|
||||
goldpinger:
|
||||
properties:
|
||||
annotations:
|
||||
@@ -982,6 +1045,66 @@ spec:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
nodeMetrics:
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: BoolString
|
||||
filters:
|
||||
properties:
|
||||
pvc:
|
||||
properties:
|
||||
nameRegex:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
fail:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
when:
|
||||
type: string
|
||||
type: object
|
||||
pass:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
when:
|
||||
type: string
|
||||
type: object
|
||||
warn:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
when:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
nodeResources:
|
||||
properties:
|
||||
annotations:
|
||||
|
||||
+11807
-4181
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.2
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
name: hostcollectors.troubleshoot.sh
|
||||
spec:
|
||||
group: troubleshoot.sh
|
||||
@@ -21,14 +20,19 @@ spec:
|
||||
description: HostCollector is the Schema for the collectors API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
@@ -1155,9 +1159,9 @@ spec:
|
||||
- path
|
||||
type: object
|
||||
filesystemPerformance:
|
||||
description: FilesystemPerformance benchmarks sequential write
|
||||
latency on a single file. The optional background IOPS feature
|
||||
attempts to mimic real-world conditions by running read and
|
||||
description: |-
|
||||
FilesystemPerformance benchmarks sequential write latency on a single file.
|
||||
The optional background IOPS feature attempts to mimic real-world conditions by running read and
|
||||
write workloads prior to and during benchmark execution.
|
||||
properties:
|
||||
backgroundIOPSWarmupSeconds:
|
||||
@@ -1165,34 +1169,33 @@ spec:
|
||||
write workloads prior to starting the benchmarks.
|
||||
type: integer
|
||||
backgroundReadIOPS:
|
||||
description: The target read IOPS to run while benchmarking.
|
||||
This is a limit and there is no guarantee it will be reached.
|
||||
This is the total IOPS for all background read jobs.
|
||||
description: |-
|
||||
The target read IOPS to run while benchmarking. This is a limit and there is no guarantee
|
||||
it will be reached. This is the total IOPS for all background read jobs.
|
||||
type: integer
|
||||
backgroundReadIOPSJobs:
|
||||
description: Number of threads to use for background read
|
||||
IOPS. This should be set high enough to reach the target
|
||||
specified in BackgrounReadIOPS.
|
||||
description: |-
|
||||
Number of threads to use for background read IOPS. This should be set high enough to reach
|
||||
the target specified in BackgrounReadIOPS.
|
||||
type: integer
|
||||
backgroundWriteIOPS:
|
||||
description: The target write IOPS to run while benchmarking.
|
||||
This is a limit and there is no guarantee it will be reached.
|
||||
This is the total IOPS for all background write jobs.
|
||||
description: |-
|
||||
The target write IOPS to run while benchmarking. This is a limit and there is no guarantee
|
||||
it will be reached. This is the total IOPS for all background write jobs.
|
||||
type: integer
|
||||
backgroundWriteIOPSJobs:
|
||||
description: 'Number of threads to use for background write
|
||||
IOPS. This should be set high enough to reach the target
|
||||
specified in BackgroundWriteIOPS. Example: If BackgroundWriteIOPS
|
||||
is 100 and write latency is 10ms then a single job would
|
||||
barely be able to reach 100 IOPS so this should be at
|
||||
least 2.'
|
||||
description: |-
|
||||
Number of threads to use for background write IOPS. This should be set high enough to reach
|
||||
the target specified in BackgroundWriteIOPS.
|
||||
Example: If BackgroundWriteIOPS is 100 and write latency is 10ms then a single job would
|
||||
barely be able to reach 100 IOPS so this should be at least 2.
|
||||
type: integer
|
||||
collectorName:
|
||||
type: string
|
||||
datasync:
|
||||
description: Whether to call datasync on the file after
|
||||
each write. Skipped if Sync is also true. Does not apply
|
||||
to background IOPS task.
|
||||
description: |-
|
||||
Whether to call datasync on the file after each write. Skipped if Sync is also true. Does not
|
||||
apply to background IOPS task.
|
||||
type: boolean
|
||||
directory:
|
||||
description: The directory where the benchmark will create
|
||||
@@ -1204,16 +1207,14 @@ spec:
|
||||
exclude:
|
||||
type: BoolString
|
||||
fileSize:
|
||||
description: The size of the file used in the benchmark.
|
||||
The number of IO operations for the benchmark will be
|
||||
FileSize / OperationSizeBytes. Accepts valid Kubernetes
|
||||
resource units such as Mi.
|
||||
description: |-
|
||||
The size of the file used in the benchmark. The number of IO operations for the benchmark
|
||||
will be FileSize / OperationSizeBytes. Accepts valid Kubernetes resource units such as Mi.
|
||||
type: string
|
||||
operationSize:
|
||||
description: The size of each write operation performed
|
||||
while benchmarking. This does not apply to the background
|
||||
IOPS feature if enabled, since those must be fixed at
|
||||
4096.
|
||||
description: |-
|
||||
The size of each write operation performed while benchmarking. This does not apply to the
|
||||
background IOPS feature if enabled, since those must be fixed at 4096.
|
||||
format: int64
|
||||
type: integer
|
||||
sync:
|
||||
@@ -1261,9 +1262,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
@@ -1281,9 +1282,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
@@ -1301,9 +1302,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
|
||||
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.2
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
name: hostpreflights.troubleshoot.sh
|
||||
spec:
|
||||
group: troubleshoot.sh
|
||||
@@ -21,14 +20,19 @@ spec:
|
||||
description: HostPreflight is the Schema for the hostpreflights API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
@@ -1155,9 +1159,9 @@ spec:
|
||||
- path
|
||||
type: object
|
||||
filesystemPerformance:
|
||||
description: FilesystemPerformance benchmarks sequential write
|
||||
latency on a single file. The optional background IOPS feature
|
||||
attempts to mimic real-world conditions by running read and
|
||||
description: |-
|
||||
FilesystemPerformance benchmarks sequential write latency on a single file.
|
||||
The optional background IOPS feature attempts to mimic real-world conditions by running read and
|
||||
write workloads prior to and during benchmark execution.
|
||||
properties:
|
||||
backgroundIOPSWarmupSeconds:
|
||||
@@ -1165,34 +1169,33 @@ spec:
|
||||
write workloads prior to starting the benchmarks.
|
||||
type: integer
|
||||
backgroundReadIOPS:
|
||||
description: The target read IOPS to run while benchmarking.
|
||||
This is a limit and there is no guarantee it will be reached.
|
||||
This is the total IOPS for all background read jobs.
|
||||
description: |-
|
||||
The target read IOPS to run while benchmarking. This is a limit and there is no guarantee
|
||||
it will be reached. This is the total IOPS for all background read jobs.
|
||||
type: integer
|
||||
backgroundReadIOPSJobs:
|
||||
description: Number of threads to use for background read
|
||||
IOPS. This should be set high enough to reach the target
|
||||
specified in BackgrounReadIOPS.
|
||||
description: |-
|
||||
Number of threads to use for background read IOPS. This should be set high enough to reach
|
||||
the target specified in BackgrounReadIOPS.
|
||||
type: integer
|
||||
backgroundWriteIOPS:
|
||||
description: The target write IOPS to run while benchmarking.
|
||||
This is a limit and there is no guarantee it will be reached.
|
||||
This is the total IOPS for all background write jobs.
|
||||
description: |-
|
||||
The target write IOPS to run while benchmarking. This is a limit and there is no guarantee
|
||||
it will be reached. This is the total IOPS for all background write jobs.
|
||||
type: integer
|
||||
backgroundWriteIOPSJobs:
|
||||
description: 'Number of threads to use for background write
|
||||
IOPS. This should be set high enough to reach the target
|
||||
specified in BackgroundWriteIOPS. Example: If BackgroundWriteIOPS
|
||||
is 100 and write latency is 10ms then a single job would
|
||||
barely be able to reach 100 IOPS so this should be at
|
||||
least 2.'
|
||||
description: |-
|
||||
Number of threads to use for background write IOPS. This should be set high enough to reach
|
||||
the target specified in BackgroundWriteIOPS.
|
||||
Example: If BackgroundWriteIOPS is 100 and write latency is 10ms then a single job would
|
||||
barely be able to reach 100 IOPS so this should be at least 2.
|
||||
type: integer
|
||||
collectorName:
|
||||
type: string
|
||||
datasync:
|
||||
description: Whether to call datasync on the file after
|
||||
each write. Skipped if Sync is also true. Does not apply
|
||||
to background IOPS task.
|
||||
description: |-
|
||||
Whether to call datasync on the file after each write. Skipped if Sync is also true. Does not
|
||||
apply to background IOPS task.
|
||||
type: boolean
|
||||
directory:
|
||||
description: The directory where the benchmark will create
|
||||
@@ -1204,16 +1207,14 @@ spec:
|
||||
exclude:
|
||||
type: BoolString
|
||||
fileSize:
|
||||
description: The size of the file used in the benchmark.
|
||||
The number of IO operations for the benchmark will be
|
||||
FileSize / OperationSizeBytes. Accepts valid Kubernetes
|
||||
resource units such as Mi.
|
||||
description: |-
|
||||
The size of the file used in the benchmark. The number of IO operations for the benchmark
|
||||
will be FileSize / OperationSizeBytes. Accepts valid Kubernetes resource units such as Mi.
|
||||
type: string
|
||||
operationSize:
|
||||
description: The size of each write operation performed
|
||||
while benchmarking. This does not apply to the background
|
||||
IOPS feature if enabled, since those must be fixed at
|
||||
4096.
|
||||
description: |-
|
||||
The size of each write operation performed while benchmarking. This does not apply to the
|
||||
background IOPS feature if enabled, since those must be fixed at 4096.
|
||||
format: int64
|
||||
type: integer
|
||||
sync:
|
||||
@@ -1261,9 +1262,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
@@ -1281,9 +1282,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
@@ -1301,9 +1302,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
@@ -1604,44 +1605,43 @@ spec:
|
||||
- path
|
||||
type: object
|
||||
filesystemPerformance:
|
||||
description: RemoteFilesystemPerformance benchmarks sequential
|
||||
write latency on a single file. The optional background IOPS
|
||||
feature attempts to mimic real-world conditions by running
|
||||
read and write workloads prior to and during benchmark execution.
|
||||
description: |-
|
||||
RemoteFilesystemPerformance benchmarks sequential write latency on a single file.
|
||||
The optional background IOPS feature attempts to mimic real-world conditions by running read and
|
||||
write workloads prior to and during benchmark execution.
|
||||
properties:
|
||||
backgroundIOPSWarmupSeconds:
|
||||
description: How long to run the background IOPS read and
|
||||
write workloads prior to starting the benchmarks.
|
||||
type: integer
|
||||
backgroundReadIOPS:
|
||||
description: The target read IOPS to run while benchmarking.
|
||||
This is a limit and there is no guarantee it will be reached.
|
||||
This is the total IOPS for all background read jobs.
|
||||
description: |-
|
||||
The target read IOPS to run while benchmarking. This is a limit and there is no guarantee
|
||||
it will be reached. This is the total IOPS for all background read jobs.
|
||||
type: integer
|
||||
backgroundReadIOPSJobs:
|
||||
description: Number of threads to use for background read
|
||||
IOPS. This should be set high enough to reach the target
|
||||
specified in BackgrounReadIOPS.
|
||||
description: |-
|
||||
Number of threads to use for background read IOPS. This should be set high enough to reach
|
||||
the target specified in BackgrounReadIOPS.
|
||||
type: integer
|
||||
backgroundWriteIOPS:
|
||||
description: The target write IOPS to run while benchmarking.
|
||||
This is a limit and there is no guarantee it will be reached.
|
||||
This is the total IOPS for all background write jobs.
|
||||
description: |-
|
||||
The target write IOPS to run while benchmarking. This is a limit and there is no guarantee
|
||||
it will be reached. This is the total IOPS for all background write jobs.
|
||||
type: integer
|
||||
backgroundWriteIOPSJobs:
|
||||
description: 'Number of threads to use for background write
|
||||
IOPS. This should be set high enough to reach the target
|
||||
specified in BackgroundWriteIOPS. Example: If BackgroundWriteIOPS
|
||||
is 100 and write latency is 10ms then a single job would
|
||||
barely be able to reach 100 IOPS so this should be at
|
||||
least 2.'
|
||||
description: |-
|
||||
Number of threads to use for background write IOPS. This should be set high enough to reach
|
||||
the target specified in BackgroundWriteIOPS.
|
||||
Example: If BackgroundWriteIOPS is 100 and write latency is 10ms then a single job would
|
||||
barely be able to reach 100 IOPS so this should be at least 2.
|
||||
type: integer
|
||||
collectorName:
|
||||
type: string
|
||||
datasync:
|
||||
description: Whether to call datasync on the file after
|
||||
each write. Skipped if Sync is also true. Does not apply
|
||||
to background IOPS task.
|
||||
description: |-
|
||||
Whether to call datasync on the file after each write. Skipped if Sync is also true. Does not
|
||||
apply to background IOPS task.
|
||||
type: boolean
|
||||
directory:
|
||||
description: The directory where the benchmark will create
|
||||
@@ -1653,16 +1653,14 @@ spec:
|
||||
exclude:
|
||||
type: BoolString
|
||||
fileSize:
|
||||
description: The size of the file used in the benchmark.
|
||||
The number of IO operations for the benchmark will be
|
||||
FileSize / OperationSizeBytes. Accepts valid Kubernetes
|
||||
resource units such as Mi.
|
||||
description: |-
|
||||
The size of the file used in the benchmark. The number of IO operations for the benchmark
|
||||
will be FileSize / OperationSizeBytes. Accepts valid Kubernetes resource units such as Mi.
|
||||
type: string
|
||||
operationSize:
|
||||
description: The size of each write operation performed
|
||||
while benchmarking. This does not apply to the background
|
||||
IOPS feature if enabled, since those must be fixed at
|
||||
4096.
|
||||
description: |-
|
||||
The size of each write operation performed while benchmarking. This does not apply to the
|
||||
background IOPS feature if enabled, since those must be fixed at 4096.
|
||||
format: int64
|
||||
type: integer
|
||||
sync:
|
||||
@@ -1703,9 +1701,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
@@ -1723,9 +1721,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
@@ -1743,9 +1741,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
|
||||
+11962
-4220
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.2
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
name: redactors.troubleshoot.sh
|
||||
spec:
|
||||
group: troubleshoot.sh
|
||||
@@ -21,14 +20,19 @@ spec:
|
||||
description: Redactor is the Schema for the redaction API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
|
||||
@@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.2
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
name: remotecollectors.troubleshoot.sh
|
||||
spec:
|
||||
group: troubleshoot.sh
|
||||
@@ -21,14 +20,19 @@ spec:
|
||||
description: RemoteCollector is the Schema for the remote collectors API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
@@ -109,44 +113,43 @@ spec:
|
||||
- path
|
||||
type: object
|
||||
filesystemPerformance:
|
||||
description: RemoteFilesystemPerformance benchmarks sequential
|
||||
write latency on a single file. The optional background IOPS
|
||||
feature attempts to mimic real-world conditions by running
|
||||
read and write workloads prior to and during benchmark execution.
|
||||
description: |-
|
||||
RemoteFilesystemPerformance benchmarks sequential write latency on a single file.
|
||||
The optional background IOPS feature attempts to mimic real-world conditions by running read and
|
||||
write workloads prior to and during benchmark execution.
|
||||
properties:
|
||||
backgroundIOPSWarmupSeconds:
|
||||
description: How long to run the background IOPS read and
|
||||
write workloads prior to starting the benchmarks.
|
||||
type: integer
|
||||
backgroundReadIOPS:
|
||||
description: The target read IOPS to run while benchmarking.
|
||||
This is a limit and there is no guarantee it will be reached.
|
||||
This is the total IOPS for all background read jobs.
|
||||
description: |-
|
||||
The target read IOPS to run while benchmarking. This is a limit and there is no guarantee
|
||||
it will be reached. This is the total IOPS for all background read jobs.
|
||||
type: integer
|
||||
backgroundReadIOPSJobs:
|
||||
description: Number of threads to use for background read
|
||||
IOPS. This should be set high enough to reach the target
|
||||
specified in BackgrounReadIOPS.
|
||||
description: |-
|
||||
Number of threads to use for background read IOPS. This should be set high enough to reach
|
||||
the target specified in BackgrounReadIOPS.
|
||||
type: integer
|
||||
backgroundWriteIOPS:
|
||||
description: The target write IOPS to run while benchmarking.
|
||||
This is a limit and there is no guarantee it will be reached.
|
||||
This is the total IOPS for all background write jobs.
|
||||
description: |-
|
||||
The target write IOPS to run while benchmarking. This is a limit and there is no guarantee
|
||||
it will be reached. This is the total IOPS for all background write jobs.
|
||||
type: integer
|
||||
backgroundWriteIOPSJobs:
|
||||
description: 'Number of threads to use for background write
|
||||
IOPS. This should be set high enough to reach the target
|
||||
specified in BackgroundWriteIOPS. Example: If BackgroundWriteIOPS
|
||||
is 100 and write latency is 10ms then a single job would
|
||||
barely be able to reach 100 IOPS so this should be at
|
||||
least 2.'
|
||||
description: |-
|
||||
Number of threads to use for background write IOPS. This should be set high enough to reach
|
||||
the target specified in BackgroundWriteIOPS.
|
||||
Example: If BackgroundWriteIOPS is 100 and write latency is 10ms then a single job would
|
||||
barely be able to reach 100 IOPS so this should be at least 2.
|
||||
type: integer
|
||||
collectorName:
|
||||
type: string
|
||||
datasync:
|
||||
description: Whether to call datasync on the file after
|
||||
each write. Skipped if Sync is also true. Does not apply
|
||||
to background IOPS task.
|
||||
description: |-
|
||||
Whether to call datasync on the file after each write. Skipped if Sync is also true. Does not
|
||||
apply to background IOPS task.
|
||||
type: boolean
|
||||
directory:
|
||||
description: The directory where the benchmark will create
|
||||
@@ -158,16 +161,14 @@ spec:
|
||||
exclude:
|
||||
type: BoolString
|
||||
fileSize:
|
||||
description: The size of the file used in the benchmark.
|
||||
The number of IO operations for the benchmark will be
|
||||
FileSize / OperationSizeBytes. Accepts valid Kubernetes
|
||||
resource units such as Mi.
|
||||
description: |-
|
||||
The size of the file used in the benchmark. The number of IO operations for the benchmark
|
||||
will be FileSize / OperationSizeBytes. Accepts valid Kubernetes resource units such as Mi.
|
||||
type: string
|
||||
operationSize:
|
||||
description: The size of each write operation performed
|
||||
while benchmarking. This does not apply to the background
|
||||
IOPS feature if enabled, since those must be fixed at
|
||||
4096.
|
||||
description: |-
|
||||
The size of each write operation performed while benchmarking. This does not apply to the
|
||||
background IOPS feature if enabled, since those must be fixed at 4096.
|
||||
format: int64
|
||||
type: integer
|
||||
sync:
|
||||
@@ -208,9 +209,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
@@ -228,9 +229,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
@@ -248,9 +249,9 @@ spec:
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout is the time to wait for a server's
|
||||
response. Its a duration e.g 15s, 2h30m. Missing value
|
||||
or empty string or means no timeout.
|
||||
description: |-
|
||||
Timeout is the time to wait for a server's response. Its a duration e.g 15s, 2h30m.
|
||||
Missing value or empty string or means no timeout.
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
|
||||
+11961
-4219
File diff suppressed because it is too large
Load Diff
@@ -42,7 +42,7 @@ An initially unintended benefit of using the Aggregation Layer is that any HostC
|
||||
* [microk8s implementation](https://github.com/canonical/microk8s/blob/master/build-scripts/patches/0000-Kubelite-integration.patch) - bundles slightly modified binaries
|
||||
* [k0s uses upstream binaries statically compiled](https://docs.k0sproject.io/v1.23.8+k0s.0/architecture/) - bundles statically compiled binaries that self extract and uses a process monitor to run them
|
||||
|
||||
2. Can you in fact push metadat like "Status" into an api-server or do we have to write directly to etcd?
|
||||
2. Can you in fact push metadata like "Status" into an api-server or do we have to write directly to etcd?
|
||||
|
||||
* If we can't push to the api-server is just writing the information directly into etcd something we can do and have a reasonable expectation of compatibility?
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@ spec:
|
||||
- pass:
|
||||
when: "== oke"
|
||||
message: OKE is a supported distribution
|
||||
- pass:
|
||||
when: "== kind"
|
||||
message: Kind is a supported distribution
|
||||
- warn:
|
||||
message: Unable to determine the distribution of Kubernetes
|
||||
- nodeResources:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module helm-template
|
||||
|
||||
go 1.20
|
||||
go 1.22.0
|
||||
|
||||
// Always use the local version of troubleshoot so as to build using
|
||||
// the latest version of the library. This will ensure the example
|
||||
@@ -9,8 +9,8 @@ replace github.com/replicatedhq/troubleshoot v0.0.0 => ../../../
|
||||
|
||||
require (
|
||||
github.com/replicatedhq/troubleshoot v0.0.0
|
||||
helm.sh/helm/v3 v3.12.3
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
helm.sh/helm/v3 v3.15.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -20,18 +20,17 @@ require (
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.10.2 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/go-openapi/swag v0.22.10 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/imdario/mergo v0.3.15 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
@@ -44,30 +43,30 @@ require (
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/net v0.18.0 // indirect
|
||||
golang.org/x/oauth2 v0.14.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/oauth2 v0.18.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/term v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.28.2 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.28.1 // indirect
|
||||
k8s.io/apimachinery v0.28.2 // indirect
|
||||
k8s.io/client-go v0.28.2 // indirect
|
||||
k8s.io/klog/v2 v2.100.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
|
||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.16.2 // indirect
|
||||
k8s.io/api v0.30.0 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.30.0 // indirect
|
||||
k8s.io/apimachinery v0.30.0 // indirect
|
||||
k8s.io/client-go v0.30.0 // indirect
|
||||
k8s.io/klog/v2 v2.120.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||
sigs.k8s.io/controller-runtime v0.18.2 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
|
||||
)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
@@ -15,41 +14,45 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE=
|
||||
github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.10 h1:4y86NVn7Z2yYd6pfS4Z+Nyh3aAUL3Nul+LMbhFKy0gA=
|
||||
github.com/go-openapi/swag v0.22.10/go.mod h1:Cnn8BYtRlx6BNE3DPN86f/xkapGIcLWzh3CLEb4C1jI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
|
||||
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
@@ -64,6 +67,7 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -83,20 +87,25 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
|
||||
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
|
||||
github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
|
||||
github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
@@ -106,7 +115,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
@@ -122,25 +132,22 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
|
||||
golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
|
||||
golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
||||
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -153,40 +160,39 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
||||
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
@@ -200,27 +206,27 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
helm.sh/helm/v3 v3.12.3 h1:5y1+Sbty12t48T/t/CGNYUIME5BJ0WKfmW/sobYqkFg=
|
||||
helm.sh/helm/v3 v3.12.3/go.mod h1:KPKQiX9IP5HX7o5YnnhViMnNuKiL/lJBVQ47GHe1R0k=
|
||||
k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw=
|
||||
k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg=
|
||||
k8s.io/apiextensions-apiserver v0.28.1 h1:l2ThkBRjrWpw4f24uq0Da2HaEgqJZ7pcgiEUTKSmQZw=
|
||||
k8s.io/apiextensions-apiserver v0.28.1/go.mod h1:sVvrI+P4vxh2YBBcm8n2ThjNyzU4BQGilCQ/JAY5kGs=
|
||||
k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ=
|
||||
k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU=
|
||||
k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY=
|
||||
k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY=
|
||||
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
||||
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ=
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
|
||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
|
||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQVuIPU=
|
||||
sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU=
|
||||
helm.sh/helm/v3 v3.15.0 h1:gcLxHeFp0Hfo7lYi6KIZ84ZyvlAnfFRSJ8lTL3zvG5U=
|
||||
helm.sh/helm/v3 v3.15.0/go.mod h1:fvfoRcB8UKRUV5jrIfOTaN/pG1TPhuqSb56fjYdTKXg=
|
||||
k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA=
|
||||
k8s.io/api v0.30.0/go.mod h1:OPlaYhoHs8EQ1ql0R/TsUgaRPhpKNxIMrKQfWUp8QSE=
|
||||
k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs=
|
||||
k8s.io/apiextensions-apiserver v0.30.0/go.mod h1:N9ogQFGcrbWqAY9p2mUAL5mGxsLqwgtUce127VtRX5Y=
|
||||
k8s.io/apimachinery v0.30.0 h1:qxVPsyDM5XS96NIh9Oj6LavoVFYff/Pon9cZeDIkHHA=
|
||||
k8s.io/apimachinery v0.30.0/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
|
||||
k8s.io/client-go v0.30.0 h1:sB1AGGlhY/o7KCyCEQ0bPWzYDL0pwOZO4vAtTSh/gJQ=
|
||||
k8s.io/client-go v0.30.0/go.mod h1:g7li5O5256qe6TYdAMyX/otJqMhIiGgTapdLchhmOaY=
|
||||
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
||||
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/controller-runtime v0.18.2 h1:RqVW6Kpeaji67CY5nPEfRz6ZfFMk0lWQlNrLqlNpx+Q=
|
||||
sigs.k8s.io/controller-runtime v0.18.2/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|
||||
@@ -1,64 +1,63 @@
|
||||
module github.com/replicatedhq/troubleshoot
|
||||
|
||||
go 1.21
|
||||
|
||||
toolchain go1.21.5
|
||||
go 1.22.0
|
||||
|
||||
require (
|
||||
github.com/ahmetalpbalkan/go-cursor v0.0.0-20131010032410-8136607ea412
|
||||
github.com/apparentlymart/go-cidr v1.1.0
|
||||
github.com/blang/semver/v4 v4.0.0
|
||||
github.com/containers/image/v5 v5.29.0
|
||||
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/containers/image/v5 v5.30.1
|
||||
github.com/distribution/distribution/v3 v3.0.0-alpha.1
|
||||
github.com/fatih/color v1.17.0
|
||||
github.com/go-logr/logr v1.4.1
|
||||
github.com/go-redis/redis/v7 v7.4.1
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/godbus/dbus/v5 v5.1.0
|
||||
github.com/google/gofuzz v1.2.0
|
||||
github.com/google/uuid v1.4.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/handlers v1.5.2
|
||||
github.com/hashicorp/go-getter v1.7.3
|
||||
github.com/hashicorp/go-getter v1.7.4
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/jackc/pgx/v5 v5.5.2
|
||||
github.com/jackc/pgx/v5 v5.5.5
|
||||
github.com/longhorn/go-iscsi-helper v0.0.0-20210330030558-49a327fb024e
|
||||
github.com/manifoldco/promptui v0.9.0
|
||||
github.com/mattn/go-isatty v0.0.19
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/microsoft/go-mssqldb v1.6.0
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5
|
||||
github.com/microsoft/go-mssqldb v1.7.1
|
||||
github.com/opencontainers/image-spec v1.1.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/replicatedhq/termui/v3 v3.1.1-0.20200811145416-f40076d26851
|
||||
github.com/segmentio/ksuid v1.0.4
|
||||
github.com/shirou/gopsutil/v3 v3.23.12
|
||||
github.com/shirou/gopsutil/v3 v3.24.4
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.18.2
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/tj/go-spin v1.1.0
|
||||
github.com/vmware-tanzu/velero v1.13.0
|
||||
go.opentelemetry.io/otel v1.19.0
|
||||
go.opentelemetry.io/otel/sdk v1.19.0
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
|
||||
golang.org/x/mod v0.14.0
|
||||
golang.org/x/sync v0.5.0
|
||||
github.com/vmware-tanzu/velero v1.13.2
|
||||
go.opentelemetry.io/otel v1.26.0
|
||||
go.opentelemetry.io/otel/sdk v1.26.0
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
|
||||
golang.org/x/mod v0.17.0
|
||||
golang.org/x/sync v0.7.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
k8s.io/api v0.29.1
|
||||
k8s.io/apiextensions-apiserver v0.29.0
|
||||
k8s.io/apimachinery v0.29.1
|
||||
k8s.io/apiserver v0.29.0
|
||||
k8s.io/cli-runtime v0.29.1
|
||||
k8s.io/client-go v0.29.1
|
||||
k8s.io/klog/v2 v2.110.1
|
||||
oras.land/oras-go v1.2.4
|
||||
sigs.k8s.io/controller-runtime v0.17.0
|
||||
k8s.io/api v0.30.1
|
||||
k8s.io/apiextensions-apiserver v0.30.1
|
||||
k8s.io/apimachinery v0.30.1
|
||||
k8s.io/apiserver v0.30.1
|
||||
k8s.io/cli-runtime v0.30.1
|
||||
k8s.io/client-go v0.30.1
|
||||
k8s.io/klog/v2 v2.120.1
|
||||
oras.land/oras-go v1.2.5
|
||||
sigs.k8s.io/controller-runtime v0.18.2
|
||||
sigs.k8s.io/e2e-framework v0.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
@@ -68,19 +67,20 @@ require (
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/containerd/cgroups/v3 v3.0.2 // indirect
|
||||
github.com/containerd/errdefs v0.1.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/distribution/reference v0.5.0 // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.8.0 // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-containerregistry v0.16.1 // indirect
|
||||
github.com/google/go-containerregistry v0.19.0 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
@@ -97,6 +97,7 @@ require (
|
||||
github.com/mistifyio/go-zfs/v3 v3.0.1 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/sys/user v0.1.0 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/rubenv/sql-migrate v1.5.2 // indirect
|
||||
@@ -107,21 +108,21 @@ require (
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/sylabs/sif/v2 v2.15.0 // indirect
|
||||
github.com/sylabs/sif/v2 v2.15.1 // indirect
|
||||
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
|
||||
github.com/vladimirvivien/gexe v0.2.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.19.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.26.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.26.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/tools v0.16.1 // indirect
|
||||
golang.org/x/tools v0.18.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
|
||||
k8s.io/component-base v0.29.0 // indirect
|
||||
k8s.io/kubectl v0.29.0 // indirect
|
||||
k8s.io/component-base v0.30.1 // indirect
|
||||
k8s.io/kubectl v0.30.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -132,9 +133,9 @@ require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.0-rc.1 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.0-rc.3 // indirect
|
||||
github.com/andybalholm/brotli v1.0.1 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.253 // indirect
|
||||
github.com/aws/aws-sdk-go v1.48.10 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/c9s/goprocinfo v0.0.0-20170724085704-0010a05ce49f // indirect
|
||||
@@ -144,34 +145,34 @@ require (
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
|
||||
github.com/containers/ocicrypt v1.1.9 // indirect
|
||||
github.com/containers/storage v1.51.0 // indirect
|
||||
github.com/containers/storage v1.53.0 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/docker/cli v24.0.7+incompatible // indirect
|
||||
github.com/docker/docker v24.0.7+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.0 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/cli v25.0.3+incompatible // indirect
|
||||
github.com/docker/docker v25.0.5+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.1 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/go-openapi/swag v0.22.10 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-intervals v0.0.2 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
@@ -183,7 +184,7 @@ require (
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.3 // indirect
|
||||
github.com/klauspost/compress v1.17.7 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
@@ -202,13 +203,11 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d // indirect
|
||||
github.com/nwaples/rardecode v1.1.2 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/runc v1.1.12 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.0 // indirect
|
||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||
github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
@@ -230,28 +229,29 @@ require (
|
||||
github.com/vbatts/tar-split v0.11.5 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/net v0.19.0
|
||||
golang.org/x/oauth2 v0.15.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/net v0.25.0
|
||||
golang.org/x/oauth2 v0.18.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/term v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/api v0.153.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
helm.sh/helm/v3 v3.13.3
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
|
||||
k8s.io/metrics v0.29.0
|
||||
helm.sh/helm/v3 v3.15.0
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
||||
k8s.io/kubelet v0.30.1
|
||||
k8s.io/metrics v0.30.1
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
|
||||
periph.io/x/host/v3 v3.8.2
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
|
||||
@@ -187,31 +187,33 @@ cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoIS
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774 h1:SCbEWT58NSt7d2mcFdvxC9uyrdcTfvBbPLThhkDmXzg=
|
||||
github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774/go.mod h1:6/0dYRLLXyJjbkIPeeGyoJ/eKOSI0eU6eTlCBYibgd0=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/Azure/azure-sdk-for-go v67.2.0+incompatible h1:Uu/Ww6ernvPTrpq31kITVTIm/I5jlJ1wjtEH/bmSB2k=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh5k7k1LGIWLQfCjaneSj7Fc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
|
||||
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
@@ -225,11 +227,9 @@ github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8
|
||||
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/hcsshim v0.12.0-rc.1 h1:Hy+xzYujv7urO5wrgcG58SPMOXNLrj4WCJbySs2XX/A=
|
||||
github.com/Microsoft/hcsshim v0.12.0-rc.1/go.mod h1:Y1a1S0QlYp1mBpyvGiuEdOfZqnao+0uX5AWHXQ5NhZU=
|
||||
github.com/Microsoft/hcsshim v0.12.0-rc.3 h1:5GNGrobGs/sN/0nFO21W9k4lFn+iXXZAE8fCZbmdRak=
|
||||
github.com/Microsoft/hcsshim v0.12.0-rc.3/go.mod h1:WuNfcaYNaw+KpCEsZCIM6HCEmu0c5HfXpi+dDSmveP0=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
||||
github.com/ahmetalpbalkan/go-cursor v0.0.0-20131010032410-8136607ea412 h1:vOVO0ypMfTt6tZacyI0kp+iCZb1XSNiYDqnzBWYgfe4=
|
||||
github.com/ahmetalpbalkan/go-cursor v0.0.0-20131010032410-8136607ea412/go.mod h1:AI9hp1tkp10pAlK5TCwL+7yWbRgtDm9jhToq6qij2xs=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@@ -244,8 +244,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go v1.44.253 h1:iqDd0okcH4ShfFexz2zzf4VmeDFf6NOMm07pHnEb8iY=
|
||||
github.com/aws/aws-sdk-go v1.44.253/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.48.10 h1:0LIFG3wp2Dt6PsxKWCg1Y1xRrn2vZnW5/gWdgaBalKg=
|
||||
github.com/aws/aws-sdk-go v1.48.10/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -256,14 +256,10 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
|
||||
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
||||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng=
|
||||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
github.com/c9s/goprocinfo v0.0.0-20170724085704-0010a05ce49f h1:tRk+aBit+q3oqnj/1mF5HHhP2yxJM2lSa0afOJxQ3nE=
|
||||
github.com/c9s/goprocinfo v0.0.0-20170724085704-0010a05ce49f/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
@@ -297,18 +293,22 @@ github.com/containerd/containerd v1.7.13 h1:wPYKIeGMN8vaggSKuV1X0wZulpMz4CrgEsZd
|
||||
github.com/containerd/containerd v1.7.13/go.mod h1:zT3up6yTRfEUa6+GsITYIJNgSVL9NQ4x4h1RPzk0Wu4=
|
||||
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
||||
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||
github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
|
||||
github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
|
||||
github.com/containers/image/v5 v5.29.0 h1:9+nhS/ZM7c4Kuzu5tJ0NMpxrgoryOJ2HAYTgG8Ny7j4=
|
||||
github.com/containers/image/v5 v5.29.0/go.mod h1:kQ7qcDsps424ZAz24thD+x7+dJw1vgur3A9tTDsj97E=
|
||||
github.com/containers/image/v5 v5.30.1 h1:AKrQMgOKI1oKx5FW5eoU2xoNyzACajHGx1O3qxobvFM=
|
||||
github.com/containers/image/v5 v5.30.1/go.mod h1:gSD8MVOyqBspc0ynLsuiMR9qmt8UQ4jpVImjmK0uXfk=
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
||||
github.com/containers/ocicrypt v1.1.9 h1:2Csfba4jse85Raxk5HIyEk8OwZNjRvfkhEGijOjIdEM=
|
||||
github.com/containers/ocicrypt v1.1.9/go.mod h1:dTKx1918d8TDkxXvarscpNVY+lyPakPNFN4jwA9GBys=
|
||||
github.com/containers/storage v1.51.0 h1:AowbcpiWXzAjHosKz7MKvPEqpyX+ryZA/ZurytRrFNA=
|
||||
github.com/containers/storage v1.51.0/go.mod h1:ybl8a3j1PPtpyaEi/5A6TOFs+5TrEyObeKJzVtkUlfc=
|
||||
github.com/containers/storage v1.53.0 h1:VSES3C/u1pxjTJIXvLrSmyP7OBtDky04oGu07UvdTEA=
|
||||
github.com/containers/storage v1.53.0/go.mod h1:pujcoOSc+upx15Jirdkebhtd8uJiLwbSd/mYT6zDJK8=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@@ -320,20 +320,22 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/distribution/distribution/v3 v3.0.0-alpha.1 h1:jn7I1gvjOvmLztH1+1cLiUFud7aeJCIQcgzugtwjyJo=
|
||||
github.com/distribution/distribution/v3 v3.0.0-alpha.1/go.mod h1:LCp4JZp1ZalYg0W/TN05jarCQu+h4w7xc7ZfQF4Y/cY=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg=
|
||||
github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v25.0.3+incompatible h1:KLeNs7zws74oFuVhgZQ5ONGZiXUUdgsdy6/EsX/6284=
|
||||
github.com/docker/cli v25.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
|
||||
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
|
||||
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE=
|
||||
github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
|
||||
github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
||||
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||
@@ -357,17 +359,17 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro=
|
||||
github.com/evanphx/json-patch/v5 v5.8.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
|
||||
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
|
||||
github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
@@ -387,7 +389,6 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
@@ -401,13 +402,13 @@ github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaL
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.10 h1:4y86NVn7Z2yYd6pfS4Z+Nyh3aAUL3Nul+LMbhFKy0gA=
|
||||
github.com/go-openapi/swag v0.22.10/go.mod h1:Cnn8BYtRlx6BNE3DPN86f/xkapGIcLWzh3CLEb4C1jI=
|
||||
github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI=
|
||||
github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
@@ -424,8 +425,8 @@ github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||
@@ -462,14 +463,12 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
|
||||
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
@@ -493,8 +492,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ=
|
||||
github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
|
||||
github.com/google/go-containerregistry v0.19.0 h1:uIsMRBV7m/HDkDxE/nXMnv1q+lOOSPlQ/ywc5JbB8Ic=
|
||||
github.com/google/go-containerregistry v0.19.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
|
||||
github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
|
||||
github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -531,8 +530,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||
@@ -552,8 +551,8 @@ github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qK
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
@@ -561,14 +560,17 @@ github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
|
||||
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-getter v1.7.3 h1:bN2+Fw9XPFvOCjB0UOevFIMICZ7G2XSQHzfvLUyOM5E=
|
||||
github.com/hashicorp/go-getter v1.7.3/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
|
||||
github.com/hashicorp/go-getter v1.7.4 h1:3yQjWuxICvSpYwqSayAdKRFcvBl1y/vogCxczWSmix0=
|
||||
github.com/hashicorp/go-getter v1.7.4/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||
@@ -578,7 +580,10 @@ github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
|
||||
github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
@@ -596,8 +601,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.5.2 h1:iLlpgp4Cp/gC9Xuscl7lFL1PhhW+ZLtXZcrfCt4C3tA=
|
||||
github.com/jackc/pgx/v5 v5.5.2/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
@@ -622,8 +627,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
|
||||
github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
|
||||
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
@@ -671,8 +676,8 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
@@ -680,15 +685,15 @@ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
|
||||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI=
|
||||
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
|
||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
|
||||
github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU=
|
||||
github.com/microsoft/go-mssqldb v1.7.1 h1:KU/g8aWeM3Hx7IMOFpiwYiUkU+9zeISb4+tx3ScVfsM=
|
||||
github.com/microsoft/go-mssqldb v1.7.1/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
|
||||
github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg=
|
||||
github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/mistifyio/go-zfs/v3 v3.0.1 h1:YaoXgBePoMA12+S1u/ddkv+QqxcfiZK4prI6HPnkFiU=
|
||||
@@ -714,6 +719,8 @@ github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
|
||||
github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
||||
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
|
||||
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -743,19 +750,17 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY=
|
||||
github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw=
|
||||
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
|
||||
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
|
||||
github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
|
||||
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
|
||||
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
|
||||
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
|
||||
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||
github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f h1:/UDgs8FGMqwnHagNDPGOlts35QkhAZ8by3DR7nMih7M=
|
||||
@@ -770,8 +775,8 @@ github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1H
|
||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
|
||||
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -802,6 +807,12 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho=
|
||||
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U=
|
||||
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc=
|
||||
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ=
|
||||
github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY=
|
||||
github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c=
|
||||
github.com/replicatedhq/termui/v3 v3.1.1-0.20200811145416-f40076d26851 h1:eRlNDHxGfVkPCRXbA4BfQJvt5DHjFiTtWy3R/t4djyY=
|
||||
github.com/replicatedhq/termui/v3 v3.1.1-0.20200811145416-f40076d26851/go.mod h1:JDxG6+uubnk9/BZ2yUsyAJJwlptjrnmB2MPF5d2Xe/8=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
@@ -823,10 +834,10 @@ github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624
|
||||
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
||||
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
|
||||
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
|
||||
github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU=
|
||||
github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
@@ -855,8 +866,9 @@ github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMV
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@@ -866,12 +878,13 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/sylabs/sif/v2 v2.15.0 h1:Nv0tzksFnoQiQ2eUwpAis9nVqEu4c3RcNSxX8P3Cecw=
|
||||
github.com/sylabs/sif/v2 v2.15.0/go.mod h1:X1H7eaPz6BAxA84POMESXoXfTqgAnLQkujyF/CQFWTc=
|
||||
github.com/sylabs/sif/v2 v2.15.1 h1:75BcunPOY11fVhe02/WHuNLTfDd3OHH0ex0MuuNMYX0=
|
||||
github.com/sylabs/sif/v2 v2.15.1/go.mod h1:YiwCUdZOhiohnPbyxuxvCZa+03HwAaiC+vfAKZPR8nQ=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
|
||||
@@ -891,8 +904,8 @@ github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinC
|
||||
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
|
||||
github.com/vladimirvivien/gexe v0.2.0 h1:nbdAQ6vbZ+ZNsolCgSVb9Fno60kzSuvtzVh6Ytqi/xY=
|
||||
github.com/vladimirvivien/gexe v0.2.0/go.mod h1:LHQL00w/7gDUKIak24n801ABp8C+ni6eBht9vGVst8w=
|
||||
github.com/vmware-tanzu/velero v1.13.0 h1:8lqFM1orSnaCZ52UMOhi9AkgJWGnI46AYxup5CCskz4=
|
||||
github.com/vmware-tanzu/velero v1.13.0/go.mod h1:87DH9gnd/uTRmsjLk7wc2JWsK+RjIqX4VEt6z5qkAfA=
|
||||
github.com/vmware-tanzu/velero v1.13.2 h1:72Rw+11HJB6XUYfH9/M/jle6duSLyGhMisMMYFr/1qs=
|
||||
github.com/vmware-tanzu/velero v1.13.2/go.mod h1:yHFPyr+iwpKRf66xJ88MriAHiX58tTnKmQXY2FQZClM=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
@@ -910,14 +923,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
|
||||
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
|
||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@@ -927,17 +934,39 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q=
|
||||
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
|
||||
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
|
||||
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
|
||||
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
|
||||
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
|
||||
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
|
||||
go.opentelemetry.io/contrib/exporters/autoexport v0.46.1 h1:ysCfPZB9AjUlMa1UHYup3c9dAOCMQX/6sxSfPBUoxHw=
|
||||
go.opentelemetry.io/contrib/exporters/autoexport v0.46.1/go.mod h1:ha0aiYm+DOPsLHjh0zoQ8W8sLT+LJ58J3j47lGpSLrU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
|
||||
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
|
||||
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 h1:bflGWrfYyuulcdxf14V6n9+CoQcu5SAAdHmDPAJnlps=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0/go.mod h1:qcTO4xHAxZLaLxPd60TdE88rxtItPHgHWqOhOGRr0as=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.44.0 h1:08qeJgaPC0YEBu2PQMbqU3rogTlyzpjhCI2b58Yn00w=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.44.0/go.mod h1:ERL2uIeBtg4TxZdojHUwzZfIFlUIjZtxubT5p4h1Gjg=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.44.0 h1:dEZWPjVN22urgYCza3PXRUGEyCB++y1sAqm6guWFesk=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.44.0/go.mod h1:sTt30Evb7hJB/gEk27qLb1+l9n4Tb8HvHkR0Wx3S6CU=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYfrPk5SOryw1e9LDDTZCbIPFrho0ec=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E=
|
||||
go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
|
||||
go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
|
||||
go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8=
|
||||
go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q=
|
||||
go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
|
||||
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -952,8 +981,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -964,8 +993,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -992,8 +1021,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1046,8 +1075,8 @@ golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfS
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
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=
|
||||
@@ -1073,8 +1102,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri
|
||||
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
|
||||
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
|
||||
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
|
||||
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
||||
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -1089,8 +1118,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1170,16 +1199,16 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1191,8 +1220,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
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=
|
||||
@@ -1252,8 +1281,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
|
||||
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
||||
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1482,8 +1511,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -1513,10 +1542,10 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
|
||||
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
helm.sh/helm/v3 v3.13.3 h1:0zPEdGqHcubehJHP9emCtzRmu8oYsJFRrlVF3TFj8xY=
|
||||
helm.sh/helm/v3 v3.13.3/go.mod h1:3OKO33yI3p4YEXtTITN2+4oScsHeQe71KuzhlZ+aPfg=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
helm.sh/helm/v3 v3.15.0 h1:gcLxHeFp0Hfo7lYi6KIZ84ZyvlAnfFRSJ8lTL3zvG5U=
|
||||
helm.sh/helm/v3 v3.15.0/go.mod h1:fvfoRcB8UKRUV5jrIfOTaN/pG1TPhuqSb56fjYdTKXg=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -1524,39 +1553,41 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw=
|
||||
k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ=
|
||||
k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0=
|
||||
k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc=
|
||||
k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc=
|
||||
k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU=
|
||||
k8s.io/apiserver v0.29.0 h1:Y1xEMjJkP+BIi0GSEv1BBrf1jLU9UPfAnnGGbbDdp7o=
|
||||
k8s.io/apiserver v0.29.0/go.mod h1:31n78PsRKPmfpee7/l9NYEv67u6hOL6AfcE761HapDM=
|
||||
k8s.io/cli-runtime v0.29.1 h1:By3WVOlEWYfyxhGko0f/IuAOLQcbBSMzwSaDren2JUs=
|
||||
k8s.io/cli-runtime v0.29.1/go.mod h1:vjEY9slFp8j8UoMhV5AlO8uulX9xk6ogfIesHobyBDU=
|
||||
k8s.io/client-go v0.29.1 h1:19B/+2NGEwnFLzt0uB5kNJnfTsbV8w6TgQRz9l7ti7A=
|
||||
k8s.io/client-go v0.29.1/go.mod h1:TDG/psL9hdet0TI9mGyHJSgRkW3H9JZk2dNEUS7bRks=
|
||||
k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s=
|
||||
k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M=
|
||||
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
|
||||
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
|
||||
k8s.io/kubectl v0.29.0 h1:Oqi48gXjikDhrBF67AYuZRTcJV4lg2l42GmvsP7FmYI=
|
||||
k8s.io/kubectl v0.29.0/go.mod h1:0jMjGWIcMIQzmUaMgAzhSELv5WtHo2a8pq67DtviAJs=
|
||||
k8s.io/metrics v0.29.0 h1:a6dWcNM+EEowMzMZ8trka6wZtSRIfEA/9oLjuhBksGc=
|
||||
k8s.io/metrics v0.29.0/go.mod h1:UCuTT4dC/x/x6ODSk87IWIZQnuAfcwxOjb1gjWJdjMA=
|
||||
k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY=
|
||||
k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM=
|
||||
k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws=
|
||||
k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4=
|
||||
k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U=
|
||||
k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
|
||||
k8s.io/apiserver v0.30.1 h1:BEWEe8bzS12nMtDKXzCF5Q5ovp6LjjYkSp8qOPk8LZ8=
|
||||
k8s.io/apiserver v0.30.1/go.mod h1:i87ZnQ+/PGAmSbD/iEKM68bm1D5reX8fO4Ito4B01mo=
|
||||
k8s.io/cli-runtime v0.30.1 h1:kSBBpfrJGS6lllc24KeniI9JN7ckOOJKnmFYH1RpTOw=
|
||||
k8s.io/cli-runtime v0.30.1/go.mod h1:zhHgbqI4J00pxb6gM3gJPVf2ysDjhQmQtnTxnMScab8=
|
||||
k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q=
|
||||
k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc=
|
||||
k8s.io/component-base v0.30.1 h1:bvAtlPh1UrdaZL20D9+sWxsJljMi0QZ3Lmw+kmZAaxQ=
|
||||
k8s.io/component-base v0.30.1/go.mod h1:e/X9kDiOebwlI41AvBHuWdqFriSRrX50CdwA9TFaHLI=
|
||||
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
||||
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
||||
k8s.io/kubectl v0.30.0 h1:xbPvzagbJ6RNYVMVuiHArC1grrV5vSmmIcSZuCdzRyk=
|
||||
k8s.io/kubectl v0.30.0/go.mod h1:zgolRw2MQXLPwmic2l/+iHs239L49fhSeICuMhQQXTI=
|
||||
k8s.io/kubelet v0.30.1 h1:6gS1gWjrefUGfC/9n0ITOzxnKyt89FfkIhom70Bola4=
|
||||
k8s.io/kubelet v0.30.1/go.mod h1:5IUeAt3YlIfLNdT/YfRuCCONfEefm7qfcqz81b002Z8=
|
||||
k8s.io/metrics v0.30.1 h1:PeA9cP0kxVtaC8Wkzp4sTkr7YSkd9R0UYP6cCHOOY1M=
|
||||
k8s.io/metrics v0.30.1/go.mod h1:gVAhTTgfNKsn9D1kB7Nmb1T31relBuXzzGUE7klyOkM=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY=
|
||||
oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324=
|
||||
oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo=
|
||||
oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo=
|
||||
periph.io/x/host/v3 v3.8.2 h1:ayKUDzgUCN0g8+/xM9GTkWaOBhSLVcVHGTfjAOi8OsQ=
|
||||
periph.io/x/host/v3 v3.8.2/go.mod h1:yFL76AesNHR68PboofSWYaQTKmvPXsQH2Apvp/ls/K4=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/controller-runtime v0.17.0 h1:fjJQf8Ukya+VjogLO6/bNX9HE6Y2xpsO5+fyS26ur/s=
|
||||
sigs.k8s.io/controller-runtime v0.17.0/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s=
|
||||
sigs.k8s.io/controller-runtime v0.18.2 h1:RqVW6Kpeaji67CY5nPEfRz6ZfFMk0lWQlNrLqlNpx+Q=
|
||||
sigs.k8s.io/controller-runtime v0.18.2/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw=
|
||||
sigs.k8s.io/e2e-framework v0.3.0 h1:eqQALBtPCth8+ulTs6lcPK7ytV5rZSSHJzQHZph4O7U=
|
||||
sigs.k8s.io/e2e-framework v0.3.0/go.mod h1:C+ef37/D90Dc7Xq1jQnNbJYscrUGpxrWog9bx2KIa+c=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/user"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
@@ -11,6 +15,8 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
const HOST_COLLECTORS_RUN_AS_ROOT_PROMPT = "Some host collectors need to be run as root.\nDo you want to exit and rerun the command using sudo?"
|
||||
|
||||
func HomeDir() string {
|
||||
if h := os.Getenv("HOME"); h != "" {
|
||||
return h
|
||||
@@ -105,3 +111,61 @@ func RenderTemplate(tpl string, data interface{}) (string, error) {
|
||||
// Return the string representation of the buffer
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func IsRunningAsRoot() bool {
|
||||
currentUser, err := user.Current()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the user ID is 0 (root's UID)
|
||||
return currentUser.Uid == "0"
|
||||
}
|
||||
|
||||
func PromptYesNo(question string) bool {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
for {
|
||||
fmt.Printf("%s (yes/no): ", question)
|
||||
|
||||
response, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Println("Error reading response:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
response = strings.TrimSpace(response)
|
||||
response = strings.ToLower(response)
|
||||
|
||||
if response == "yes" || response == "y" {
|
||||
return true
|
||||
} else if response == "no" || response == "n" {
|
||||
return false
|
||||
} else {
|
||||
fmt.Println("Please type 'yes' or 'no'.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Dedup[T any](objs []T) []T {
|
||||
seen := make(map[string]bool)
|
||||
out := []T{}
|
||||
|
||||
if len(objs) == 0 {
|
||||
return objs
|
||||
}
|
||||
|
||||
for _, o := range objs {
|
||||
data, err := json.Marshal(o)
|
||||
if err != nil {
|
||||
out = append(out, o)
|
||||
continue
|
||||
}
|
||||
key := string(data)
|
||||
if _, ok := seen[key]; !ok {
|
||||
out = append(out, o)
|
||||
seen[key] = true
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -246,6 +246,10 @@ func getAnalyzer(analyzer *troubleshootv1beta2.Analyze) Analyzer {
|
||||
return &AnalyzeCertificates{analyzer: analyzer.Certificates}
|
||||
case analyzer.Goldpinger != nil:
|
||||
return &AnalyzeGoldpinger{analyzer: analyzer.Goldpinger}
|
||||
case analyzer.Event != nil:
|
||||
return &AnalyzeEvent{analyzer: analyzer.Event}
|
||||
case analyzer.NodeMetrics != nil:
|
||||
return &AnalyzeNodeMetrics{analyzer: analyzer.NodeMetrics}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package analyzer
|
||||
|
||||
import "fmt"
|
||||
|
||||
type ComparisonOperator int
|
||||
|
||||
const (
|
||||
Unknown ComparisonOperator = iota
|
||||
Equal
|
||||
NotEqual
|
||||
GreaterThan
|
||||
GreaterThanOrEqual
|
||||
LessThan
|
||||
LessThanOrEqual
|
||||
)
|
||||
|
||||
func ParseComparisonOperator(s string) (ComparisonOperator, error) {
|
||||
switch s {
|
||||
case "=", "==", "===":
|
||||
return Equal, nil
|
||||
case "!=", "!==":
|
||||
return NotEqual, nil
|
||||
case "<":
|
||||
return LessThan, nil
|
||||
case ">":
|
||||
return GreaterThan, nil
|
||||
case "<=":
|
||||
return LessThanOrEqual, nil
|
||||
case ">=":
|
||||
return GreaterThanOrEqual, nil
|
||||
}
|
||||
|
||||
return Unknown, fmt.Errorf("unknown operator: %s", s)
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseComparisonOperator(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want ComparisonOperator
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "equal",
|
||||
input: "=",
|
||||
want: Equal,
|
||||
},
|
||||
{
|
||||
name: "equal",
|
||||
input: "==",
|
||||
want: Equal,
|
||||
},
|
||||
{
|
||||
name: "equal",
|
||||
input: "===",
|
||||
want: Equal,
|
||||
},
|
||||
{
|
||||
name: "not equal",
|
||||
input: "!=",
|
||||
want: NotEqual,
|
||||
},
|
||||
{
|
||||
name: "not equal",
|
||||
input: "!==",
|
||||
want: NotEqual,
|
||||
},
|
||||
{
|
||||
name: "less than",
|
||||
input: "<",
|
||||
want: LessThan,
|
||||
},
|
||||
{
|
||||
name: "greater than",
|
||||
input: ">",
|
||||
want: GreaterThan,
|
||||
},
|
||||
{
|
||||
name: "less than or equal",
|
||||
input: "<=",
|
||||
want: LessThanOrEqual,
|
||||
},
|
||||
{
|
||||
name: "greater than or equal",
|
||||
input: ">=",
|
||||
want: GreaterThanOrEqual,
|
||||
},
|
||||
{
|
||||
name: "invalid operator 1",
|
||||
input: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid operator 2",
|
||||
input: "gibberish",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ParseComparisonOperator(tt.input)
|
||||
assert.Equal(t, tt.want, got, "ParseOperator() = %v, want %v", got, tt.want)
|
||||
assert.Equalf(t, tt.wantErr, err != nil, "ParseOperator() error = %v, wantErr %v", err, tt.wantErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
+65
-29
@@ -13,40 +13,46 @@ import (
|
||||
)
|
||||
|
||||
type providers struct {
|
||||
microk8s bool
|
||||
dockerDesktop bool
|
||||
eks bool
|
||||
gke bool
|
||||
digitalOcean bool
|
||||
openShift bool
|
||||
tanzu bool
|
||||
kurl bool
|
||||
aks bool
|
||||
ibm bool
|
||||
minikube bool
|
||||
rke2 bool
|
||||
k3s bool
|
||||
oke bool
|
||||
microk8s bool
|
||||
dockerDesktop bool
|
||||
eks bool
|
||||
gke bool
|
||||
digitalOcean bool
|
||||
openShift bool
|
||||
tanzu bool
|
||||
kurl bool
|
||||
aks bool
|
||||
ibm bool
|
||||
minikube bool
|
||||
rke2 bool
|
||||
k3s bool
|
||||
oke bool
|
||||
kind bool
|
||||
k0s bool
|
||||
embeddedCluster bool
|
||||
}
|
||||
|
||||
type Provider int
|
||||
|
||||
const (
|
||||
unknown Provider = iota
|
||||
microk8s Provider = iota
|
||||
dockerDesktop Provider = iota
|
||||
eks Provider = iota
|
||||
gke Provider = iota
|
||||
digitalOcean Provider = iota
|
||||
openShift Provider = iota
|
||||
tanzu Provider = iota
|
||||
kurl Provider = iota
|
||||
aks Provider = iota
|
||||
ibm Provider = iota
|
||||
minikube Provider = iota
|
||||
rke2 Provider = iota
|
||||
k3s Provider = iota
|
||||
oke Provider = iota
|
||||
unknown Provider = iota
|
||||
microk8s Provider = iota
|
||||
dockerDesktop Provider = iota
|
||||
eks Provider = iota
|
||||
gke Provider = iota
|
||||
digitalOcean Provider = iota
|
||||
openShift Provider = iota
|
||||
tanzu Provider = iota
|
||||
kurl Provider = iota
|
||||
aks Provider = iota
|
||||
ibm Provider = iota
|
||||
minikube Provider = iota
|
||||
rke2 Provider = iota
|
||||
k3s Provider = iota
|
||||
oke Provider = iota
|
||||
kind Provider = iota
|
||||
k0s Provider = iota
|
||||
embeddedCluster Provider = iota
|
||||
)
|
||||
|
||||
type AnalyzeDistribution struct {
|
||||
@@ -132,6 +138,15 @@ func ParseNodesForProviders(nodes []corev1.Node) (providers, string) {
|
||||
foundProviders.oke = true
|
||||
stringProvider = "oke"
|
||||
}
|
||||
if k == "node.k0sproject.io/role" {
|
||||
foundProviders.k0s = true
|
||||
stringProvider = "k0s"
|
||||
}
|
||||
|
||||
if k == "kots.io/embedded-cluster-role" {
|
||||
foundProviders.embeddedCluster = true
|
||||
stringProvider = "embedded-cluster"
|
||||
}
|
||||
}
|
||||
|
||||
for k := range node.ObjectMeta.Annotations {
|
||||
@@ -162,6 +177,10 @@ func ParseNodesForProviders(nodes []corev1.Node) (providers, string) {
|
||||
foundProviders.ibm = true
|
||||
stringProvider = "ibm"
|
||||
}
|
||||
if strings.HasPrefix(node.Spec.ProviderID, "kind:") {
|
||||
foundProviders.kind = true
|
||||
stringProvider = "kind"
|
||||
}
|
||||
}
|
||||
|
||||
if foundMaster {
|
||||
@@ -172,6 +191,11 @@ func ParseNodesForProviders(nodes []corev1.Node) (providers, string) {
|
||||
}
|
||||
}
|
||||
|
||||
// If k0s and embedded-cluster are both found, prefer embedded-cluster
|
||||
if foundProviders.k0s && foundProviders.embeddedCluster {
|
||||
stringProvider = "embedded-cluster"
|
||||
}
|
||||
|
||||
return foundProviders, stringProvider
|
||||
}
|
||||
|
||||
@@ -335,6 +359,12 @@ func compareDistributionConditionalToActual(conditional string, actual providers
|
||||
isMatch = actual.k3s
|
||||
case oke:
|
||||
isMatch = actual.oke
|
||||
case kind:
|
||||
isMatch = actual.kind
|
||||
case k0s:
|
||||
isMatch = actual.k0s
|
||||
case embeddedCluster:
|
||||
isMatch = actual.embeddedCluster
|
||||
}
|
||||
|
||||
switch parts[0] {
|
||||
@@ -377,6 +407,12 @@ func mustNormalizeDistributionName(raw string) Provider {
|
||||
return k3s
|
||||
case "oke":
|
||||
return oke
|
||||
case "kind":
|
||||
return kind
|
||||
case "k0s":
|
||||
return k0s
|
||||
case "embeddedcluster":
|
||||
return embeddedCluster
|
||||
}
|
||||
|
||||
return unknown
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func Test_compareDistributionConditionalToActual(t *testing.T) {
|
||||
@@ -39,6 +41,30 @@ func Test_compareDistributionConditionalToActual(t *testing.T) {
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "== kind when kind is found",
|
||||
conditional: "== kind",
|
||||
input: providers{
|
||||
kind: true,
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "== k0s when k0s is found",
|
||||
conditional: "== k0s",
|
||||
input: providers{
|
||||
k0s: true,
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "== embedded-cluster when embedded-cluster is found",
|
||||
conditional: "== embedded-cluster",
|
||||
input: providers{
|
||||
embeddedCluster: true,
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -73,6 +99,66 @@ func Test_mustNormalizeDistributionName(t *testing.T) {
|
||||
raw: "Docker-Desktop",
|
||||
expected: dockerDesktop,
|
||||
},
|
||||
{
|
||||
raw: "embedded-cluster",
|
||||
expected: embeddedCluster,
|
||||
},
|
||||
{
|
||||
raw: "k0s",
|
||||
expected: k0s,
|
||||
},
|
||||
{
|
||||
raw: "kind",
|
||||
expected: kind,
|
||||
},
|
||||
{
|
||||
raw: "k3s",
|
||||
expected: k3s,
|
||||
},
|
||||
{
|
||||
raw: "ibm",
|
||||
expected: ibm,
|
||||
},
|
||||
{
|
||||
raw: "ibmcloud",
|
||||
expected: ibm,
|
||||
},
|
||||
{
|
||||
raw: "ibm cloud",
|
||||
expected: ibm,
|
||||
},
|
||||
{
|
||||
raw: "gke",
|
||||
expected: gke,
|
||||
},
|
||||
{
|
||||
raw: "aks",
|
||||
expected: aks,
|
||||
},
|
||||
{
|
||||
raw: "eks",
|
||||
expected: eks,
|
||||
},
|
||||
{
|
||||
raw: "oke",
|
||||
expected: oke,
|
||||
},
|
||||
{
|
||||
raw: "rke2",
|
||||
expected: rke2,
|
||||
},
|
||||
{
|
||||
raw: "dockerdesktop",
|
||||
expected: dockerDesktop,
|
||||
},
|
||||
{
|
||||
raw: "docker desktop",
|
||||
expected: dockerDesktop,
|
||||
},
|
||||
{
|
||||
raw: "docker-desktop",
|
||||
expected: dockerDesktop,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -83,3 +169,48 @@ func Test_mustNormalizeDistributionName(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNodesForProviders(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
nodes []corev1.Node
|
||||
wantProviders providers
|
||||
wantProviderString string
|
||||
}{
|
||||
{
|
||||
name: "embedded-cluster",
|
||||
nodes: []corev1.Node{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "embedded-cluster",
|
||||
Labels: map[string]string{
|
||||
"beta.kubernetes.io/arch": "amd64",
|
||||
"beta.kubernetes.io/os": "linux",
|
||||
"kots.io/embedded-cluster-role": "total-1",
|
||||
"kots.io/embedded-cluster-role-0": "management",
|
||||
"kubernetes.io/arch": "amd64",
|
||||
"kubernetes.io/hostname": "evans-vm1",
|
||||
"kubernetes.io/os": "linux",
|
||||
"management": "true",
|
||||
"node-role.kubernetes.io/control-plane": "true",
|
||||
"node.k0sproject.io/role": "control-plane",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantProviders: providers{embeddedCluster: true, k0s: true},
|
||||
wantProviderString: "embedded-cluster",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
providers, stringProvider := ParseNodesForProviders(tt.nodes)
|
||||
assert.Equalf(t, tt.wantProviders, providers,
|
||||
"ParseNodesForProviders() gotProviders = %v, providers %v", providers, tt.wantProviders,
|
||||
)
|
||||
assert.Equalf(t, tt.wantProviderString, stringProvider,
|
||||
"ParseNodesForProviders() gotStringProvider = %v, stringProvider %v", stringProvider, tt.wantProviderString,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/constants"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
type AnalyzeEvent struct {
|
||||
analyzer *troubleshootv1beta2.EventAnalyze
|
||||
}
|
||||
|
||||
type eventFilter struct {
|
||||
kind string
|
||||
reason string
|
||||
msgRegex string
|
||||
}
|
||||
|
||||
func (a *AnalyzeEvent) Title() string {
|
||||
if a.analyzer.CheckName != "" {
|
||||
return a.analyzer.CheckName
|
||||
}
|
||||
if a.analyzer.CollectorName != "" {
|
||||
return a.analyzer.CollectorName
|
||||
}
|
||||
return "Event"
|
||||
}
|
||||
|
||||
func (a *AnalyzeEvent) IsExcluded() (bool, error) {
|
||||
return isExcluded(a.analyzer.Exclude)
|
||||
}
|
||||
|
||||
func (a *AnalyzeEvent) Analyze(getFile getCollectedFileContents, findFiles getChildCollectedFileContents) ([]*AnalyzeResult, error) {
|
||||
// required check
|
||||
if a.analyzer.Reason == "" {
|
||||
return nil, errors.New("reason is required")
|
||||
}
|
||||
|
||||
// read collected events based on namespace
|
||||
namespace := getNamespace(a.analyzer.Namespace)
|
||||
fullPath := path.Join(constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_EVENTS, namespace)
|
||||
fullPath = fmt.Sprintf("%s.json", fullPath)
|
||||
fileContent, err := getFile(fullPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to read collected events for namespace: %s", namespace)
|
||||
}
|
||||
|
||||
events, err := convertToEventList(fileContent)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read collected events")
|
||||
}
|
||||
|
||||
// filter if there's single event matched with the given criteria
|
||||
// match: Reason && Kind (optional) && MessageRegex (optional)
|
||||
// e.g. Reason: Unhealthy. Kind: Pod. Message: Readiness probe failed:...
|
||||
event := getEvent(events, eventFilter{
|
||||
kind: a.analyzer.Kind,
|
||||
reason: a.analyzer.Reason,
|
||||
msgRegex: a.analyzer.RegexPattern,
|
||||
})
|
||||
|
||||
return analyzeEventResult(event, a.analyzer.Outcomes, a.Title())
|
||||
|
||||
}
|
||||
|
||||
func getNamespace(namespace string) string {
|
||||
if namespace == "" {
|
||||
return corev1.NamespaceDefault
|
||||
}
|
||||
return namespace
|
||||
}
|
||||
|
||||
func convertToEventList(data []byte) (*corev1.EventList, error) {
|
||||
var eventList corev1.EventList
|
||||
err := json.Unmarshal(data, &eventList)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert []byte to corev1.EventList: %w", err)
|
||||
}
|
||||
return &eventList, nil
|
||||
}
|
||||
|
||||
func getEvent(events *corev1.EventList, filter eventFilter) *corev1.Event {
|
||||
var (
|
||||
re *regexp.Regexp
|
||||
errParseRegex error
|
||||
)
|
||||
|
||||
if filter.msgRegex != "" {
|
||||
re, errParseRegex = regexp.Compile(filter.msgRegex)
|
||||
if errParseRegex != nil {
|
||||
klog.V(2).Infof("failed to read message regex: %v", errParseRegex)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
for _, event := range events.Items {
|
||||
if !matchReason(event.Reason, filter.reason) {
|
||||
continue
|
||||
}
|
||||
if !matchKind(event.InvolvedObject.Kind, filter.kind) {
|
||||
continue
|
||||
}
|
||||
if re == nil || re.MatchString(event.Message) {
|
||||
klog.V(2).Infof("event matched: %v for reason: %s kind: %s messageRegex: %s ", event, filter.reason, filter.kind, filter.msgRegex)
|
||||
return &event
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func matchReason(actual, expected string) bool {
|
||||
// not possible to have empty reason
|
||||
if expected == "" {
|
||||
return false
|
||||
}
|
||||
return strings.EqualFold(actual, expected)
|
||||
}
|
||||
|
||||
func matchKind(actual, expected string) bool {
|
||||
// kind is optional
|
||||
if expected == "" {
|
||||
return true
|
||||
}
|
||||
return strings.EqualFold(actual, expected)
|
||||
}
|
||||
|
||||
func analyzeEventResult(event *corev1.Event, outcomes []*troubleshootv1beta2.Outcome, checkName string) ([]*AnalyzeResult, error) {
|
||||
|
||||
results := []*AnalyzeResult{}
|
||||
|
||||
// for now, only support single outcome
|
||||
// we will return when there's a matched event
|
||||
willReturn := event != nil
|
||||
|
||||
result := &AnalyzeResult{
|
||||
Title: checkName,
|
||||
IconKey: "kubernetes_event",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/kubernetes.svg?w=16&h=16",
|
||||
}
|
||||
|
||||
for _, o := range outcomes {
|
||||
if o.Fail != nil {
|
||||
toReturn, err := strconv.ParseBool(o.Fail.When)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse when condition: %s", o.Fail.When)
|
||||
}
|
||||
if toReturn == willReturn {
|
||||
result.IsFail = true
|
||||
result.Message = decorateMessage(o.Fail.Message, event)
|
||||
result.URI = o.Fail.URI
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if o.Warn != nil {
|
||||
toReturn, err := strconv.ParseBool(o.Warn.When)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse when condition: %s", o.Warn.When)
|
||||
}
|
||||
if toReturn == willReturn {
|
||||
result.IsWarn = true
|
||||
result.Message = decorateMessage(o.Warn.Message, event)
|
||||
result.URI = o.Warn.URI
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if o.Pass != nil {
|
||||
toReturn, err := strconv.ParseBool(o.Pass.When)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse when condition: %s", o.Pass.When)
|
||||
}
|
||||
if toReturn == willReturn {
|
||||
result.IsPass = true
|
||||
result.Message = decorateMessage(o.Pass.Message, event)
|
||||
result.URI = o.Pass.URI
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
results = append(results, result)
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func decorateMessage(message string, event *corev1.Event) string {
|
||||
if event == nil {
|
||||
return message
|
||||
}
|
||||
out := fmt.Sprintf("Event matched. Reason: %s Name: %s Message: %s", event.Reason, event.InvolvedObject.Name, event.Message)
|
||||
|
||||
tmpl := template.New("event")
|
||||
msgTmpl, err := tmpl.Parse(message)
|
||||
if err != nil {
|
||||
klog.V(2).Infof("failed to parse message template: %v", err)
|
||||
return out
|
||||
}
|
||||
|
||||
var m bytes.Buffer
|
||||
err = msgTmpl.Execute(&m, event)
|
||||
if err != nil {
|
||||
klog.V(2).Infof("failed to render message template: %v", err)
|
||||
return out
|
||||
}
|
||||
|
||||
return strings.TrimSpace(m.String())
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func TestAnalyzeEvent(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
analyzer troubleshootv1beta2.EventAnalyze
|
||||
expectResult []AnalyzeResult
|
||||
files map[string][]byte
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "reason is required",
|
||||
analyzer: troubleshootv1beta2.EventAnalyze{
|
||||
CollectorName: "event-collector-0",
|
||||
Kind: "Pod",
|
||||
Namespace: "default",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "true",
|
||||
Message: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
err: errors.New("reason is required"),
|
||||
files: map[string][]byte{
|
||||
"cluster-resources/events/default.json": []byte(`
|
||||
{
|
||||
"kind": "EventList",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"resourceVersion": "722"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"kind": "Event",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "nginx-rc",
|
||||
"namespace": "default",
|
||||
"creationTimestamp": "2022-01-01T00:00:00Z"
|
||||
},
|
||||
"involvedObject": {
|
||||
"kind": "Pod",
|
||||
"name": "nginx-rc-12345",
|
||||
"namespace": "default"
|
||||
},
|
||||
"reason": "OOMKilled",
|
||||
"message": "The container was killed due to an out-of-memory condition.",
|
||||
"type": "Warning"
|
||||
}
|
||||
]
|
||||
}
|
||||
`),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fail when OOMKilled event is present",
|
||||
analyzer: troubleshootv1beta2.EventAnalyze{
|
||||
CollectorName: "event-collector-1",
|
||||
Kind: "Pod",
|
||||
Namespace: "default",
|
||||
Reason: "OOMKilled",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "true",
|
||||
Message: "Detect OOMKilled event with {{ .InvolvedObject.Kind }}-{{ .InvolvedObject.Name }} with message {{ .Message }}",
|
||||
},
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "false",
|
||||
Message: "No OOMKilled event detected",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectResult: []AnalyzeResult{
|
||||
{
|
||||
Title: "event-collector-1",
|
||||
IconKey: "kubernetes_event",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/kubernetes.svg?w=16&h=16",
|
||||
IsFail: true,
|
||||
IsWarn: false,
|
||||
IsPass: false,
|
||||
Message: "Detect OOMKilled event with Pod-nginx-rc-12345 with message The container was killed due to an out-of-memory condition.",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"cluster-resources/events/default.json": []byte(`
|
||||
{
|
||||
"kind": "EventList",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"resourceVersion": "722"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"kind": "Event",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "nginx-rc",
|
||||
"namespace": "default",
|
||||
"creationTimestamp": "2022-01-01T00:00:00Z"
|
||||
},
|
||||
"involvedObject": {
|
||||
"kind": "Pod",
|
||||
"name": "nginx-rc-12345",
|
||||
"namespace": "default"
|
||||
},
|
||||
"reason": "OOMKilled",
|
||||
"message": "The container was killed due to an out-of-memory condition.",
|
||||
"type": "Warning"
|
||||
}
|
||||
]
|
||||
}
|
||||
`),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pass when no FailedMount event is present",
|
||||
analyzer: troubleshootv1beta2.EventAnalyze{
|
||||
CollectorName: "event-collector-2",
|
||||
Kind: "Pod",
|
||||
Namespace: "default",
|
||||
Reason: "FailedMount",
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "false",
|
||||
Message: "No FailedMount event detected",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectResult: []AnalyzeResult{
|
||||
{
|
||||
Title: "event-collector-2",
|
||||
IconKey: "kubernetes_event",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/kubernetes.svg?w=16&h=16",
|
||||
IsFail: false,
|
||||
IsWarn: false,
|
||||
IsPass: true,
|
||||
Message: "No FailedMount event detected",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"cluster-resources/events/default.json": []byte(`
|
||||
{
|
||||
"kind": "EventList",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"resourceVersion": "722"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"kind": "Event",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "nginx-rc-1",
|
||||
"namespace": "default",
|
||||
"creationTimestamp": "2022-01-01T00:00:00Z"
|
||||
},
|
||||
"involvedObject": {
|
||||
"kind": "Pod",
|
||||
"name": "nginx-rc-12345",
|
||||
"namespace": "default"
|
||||
},
|
||||
"reason": "Created",
|
||||
"message": "Created container",
|
||||
"type": "Normal"
|
||||
},
|
||||
{
|
||||
"kind": "Event",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "nginx-rc-2",
|
||||
"namespace": "default",
|
||||
"creationTimestamp": "2022-01-01T00:00:00Z"
|
||||
},
|
||||
"involvedObject": {
|
||||
"kind": "Pod",
|
||||
"name": "nginx-rc-67890",
|
||||
"namespace": "default"
|
||||
},
|
||||
"reason": "Started",
|
||||
"message": "Started container",
|
||||
"type": "Normal"
|
||||
}
|
||||
]
|
||||
}
|
||||
`),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
|
||||
getFile := func(n string) ([]byte, error) {
|
||||
if b, ok := test.files[n]; ok {
|
||||
return b, nil
|
||||
}
|
||||
return nil, errors.New("file not found")
|
||||
}
|
||||
|
||||
findFiles := func(n string, _ []string) (map[string][]byte, error) {
|
||||
return nil, errors.New("method not implemented")
|
||||
}
|
||||
|
||||
a := &AnalyzeEvent{
|
||||
analyzer: &test.analyzer,
|
||||
}
|
||||
actual, err := a.Analyze(getFile, findFiles)
|
||||
if test.err != nil {
|
||||
req.EqualError(err, test.err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
req.NoError(err)
|
||||
unPointered := []AnalyzeResult{}
|
||||
for _, v := range actual {
|
||||
unPointered = append(unPointered, *v)
|
||||
}
|
||||
req.ElementsMatch(test.expectResult, unPointered)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnalyzeEventResult(t *testing.T) {
|
||||
event := &corev1.Event{
|
||||
InvolvedObject: corev1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Name: "foo-pod",
|
||||
},
|
||||
Reason: "Unhealthy",
|
||||
Message: "foo-message",
|
||||
Type: "Warning",
|
||||
}
|
||||
|
||||
outcomes := []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "true",
|
||||
Message: "No unhealthy pods allowed",
|
||||
},
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "false",
|
||||
Message: "No unhealthy pod detected",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
checkName := "Test Event"
|
||||
|
||||
expectedResults := []*AnalyzeResult{
|
||||
{
|
||||
Title: "Test Event",
|
||||
IconKey: "kubernetes_event",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/kubernetes.svg?w=16&h=16",
|
||||
IsFail: true,
|
||||
IsWarn: false,
|
||||
IsPass: false,
|
||||
Message: "No unhealthy pods allowed",
|
||||
},
|
||||
}
|
||||
|
||||
results, err := analyzeEventResult(event, outcomes, checkName)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if len(results) != len(expectedResults) {
|
||||
t.Fatalf("unexpected number of results, got %d, want %d", len(results), len(expectedResults))
|
||||
}
|
||||
|
||||
for i, result := range results {
|
||||
expectedResult := expectedResults[i]
|
||||
|
||||
if result.Title != expectedResult.Title {
|
||||
t.Errorf("unexpected title, got %s, want %s", result.Title, expectedResult.Title)
|
||||
}
|
||||
|
||||
if result.IsFail != expectedResult.IsFail {
|
||||
t.Errorf("unexpected IsFail value, got %v, want %v", result.IsFail, expectedResult.IsFail)
|
||||
}
|
||||
|
||||
if result.IsWarn != expectedResult.IsWarn {
|
||||
t.Errorf("unexpected IsWarn value, got %v, want %v", result.IsWarn, expectedResult.IsWarn)
|
||||
}
|
||||
|
||||
if result.IsPass != expectedResult.IsPass {
|
||||
t.Errorf("unexpected IsPass value, got %v, want %v", result.IsPass, expectedResult.IsPass)
|
||||
}
|
||||
|
||||
if result.Message != expectedResult.Message {
|
||||
t.Errorf("unexpected message, got %s, want %s", result.Message, expectedResult.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"kind": "ConfigMapList",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"resourceVersion": "4825753"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"kind": "ConfigMap",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "kube-root-ca.crt",
|
||||
"namespace": "kube-public",
|
||||
"uid": "37a912b2-a666-480f-a1a8-05ab012432e4",
|
||||
"resourceVersion": "332",
|
||||
"creationTimestamp": "2023-05-29T23:33:07Z",
|
||||
"annotations": {
|
||||
"kubernetes.io/description": "Contains a CA bundle that can be used to verify the kube-apiserver when using internal endpoints such as the internal service IP or kubernetes.default.svc. No other usage is guaranteed across distributions of Kubernetes clusters."
|
||||
},
|
||||
"managedFields": [
|
||||
{
|
||||
"manager": "kube-controller-manager",
|
||||
"operation": "Update",
|
||||
"apiVersion": "v1",
|
||||
"time": "2023-05-29T23:33:07Z",
|
||||
"fieldsType": "FieldsV1",
|
||||
"fieldsV1": {
|
||||
"f:data": {
|
||||
".": {},
|
||||
"f:ca.crt": {}
|
||||
},
|
||||
"f:metadata": {
|
||||
"f:annotations": {
|
||||
".": {},
|
||||
"f:kubernetes.io/description": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"ca.crt": "-----BEGIN CERTIFICATE-----\nMIIDBjCCAe6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwptaW5p\na3ViZUNBMB4XDTIzMDUyODIzMzIzOVoXDTMzMDUyNjIzMzIzOVowFTETMBEGA1UE\nAxMKbWluaWt1YmVDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOpU\nswd15tD+QCelgYlu5MRB260+Ke63gEDTkXIyAr+mR+TjW/v9TPPIP9iidvTUg+jq\nryrf1PwURVx3EUSZWtd9NpAEDT1ov/ggx16xxj2El7KLen0SXQutSF28zjCFXxYG\nMkPxXu+qYsn2mLJX5i1kaCZNffyToCJ0n2bxxx83rOS+fgz11JntAwcgC8V3Mtq6\nIv+2Xb9PSxPs38ef7r15j5KSTOrmWCR5texPFz/WU/YbZ3W42pj9T/EiuGwamfmI\ngevuwv7AxlfjKutp5UQEth5GhY6V4kJyVIUExN3ddEsTPLQD9zvdsP4DlkGpZmiR\n/Ip3rXY/ldxeeGZ0HUUCAwEAAaNhMF8wDgYDVR0PAQH/BAQDAgKkMB0GA1UdJQQW\nMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW\nBBS0XUXhCu/DOH8/0W5L0n4BOw9b6zANBgkqhkiG9w0BAQsFAAOCAQEAHrXOxKdy\n+DvPtvgfzzV3qqmIvTuuFyW0BdZdXV8yo1tZajkEO0B0HvLUyn8ljKgoK5YtCQcr\nzSj6QEewgP+JCBTsWCKzbOhMcDKw1pa6bSeLcQWwMxox+1Zcj7edMPlPcQ3SVLxZ\n6y7fD7BArTKRBKCr8Uwudwox5Vm0URWLRAvb+8jPv9BDuC/uMPJ4UrexL/Q2QQs8\nQkyWYeSk4mBCM3qAahQhYc0WSHbk+a/5iua/y+VUaa208CUbm5glBoAroHDk5eTN\nYstOSLUQAlzTdr4kCEVi+a3+NgmuvzYXWubAdy/PT860aFBJlmVNuDhy8V/bGpnS\nKxmG7B3yJmbmzg==\n-----END CERTIFICATE-----\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"k8s.io/klog/v2"
|
||||
kubeletv1alpha1 "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
|
||||
)
|
||||
|
||||
type AnalyzeNodeMetrics struct {
|
||||
analyzer *troubleshootv1beta2.NodeMetricsAnalyze
|
||||
}
|
||||
|
||||
type nodeMetricsComparisonResults struct {
|
||||
PVC pvcTemplateData
|
||||
}
|
||||
|
||||
type pvcTemplateData struct {
|
||||
UsedPercentage float64
|
||||
ConcatenatedNames string
|
||||
Names []string
|
||||
}
|
||||
|
||||
type pvcUsageStats struct {
|
||||
PvcName string
|
||||
Used float64
|
||||
}
|
||||
|
||||
func (a *AnalyzeNodeMetrics) Title() string {
|
||||
title := a.analyzer.CheckName
|
||||
if title == "" {
|
||||
title = a.analyzer.CollectorName
|
||||
}
|
||||
if title == "" {
|
||||
title = "Node Metrics"
|
||||
}
|
||||
|
||||
return title
|
||||
}
|
||||
|
||||
func (a *AnalyzeNodeMetrics) IsExcluded() (bool, error) {
|
||||
return isExcluded(a.analyzer.Exclude)
|
||||
}
|
||||
|
||||
func (a *AnalyzeNodeMetrics) Analyze(getFile getCollectedFileContents, findFiles getChildCollectedFileContents) ([]*AnalyzeResult, error) {
|
||||
// Gather all collected node-metrics files
|
||||
collected, err := findFiles(filepath.Join("node-metrics", "*.json"), nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read collected pods")
|
||||
}
|
||||
|
||||
// Unmarshal all collected node-metrics files
|
||||
summaries := []kubeletv1alpha1.Summary{}
|
||||
for _, fileContent := range collected {
|
||||
summary := kubeletv1alpha1.Summary{}
|
||||
if err := json.Unmarshal(fileContent, &summary); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal node metrics")
|
||||
}
|
||||
|
||||
summaries = append(summaries, summary)
|
||||
}
|
||||
|
||||
// Run through all outcomes to generate results
|
||||
result, err := a.compareCollectedMetricsWithOutcomes(summaries)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compare node metrics with outcomes")
|
||||
}
|
||||
if result == nil {
|
||||
return []*AnalyzeResult{}, nil
|
||||
}
|
||||
result.Strict = a.analyzer.Strict.BoolOrDefaultFalse()
|
||||
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
|
||||
func (a *AnalyzeNodeMetrics) compareCollectedMetricsWithOutcomes(summaries []kubeletv1alpha1.Summary) (*AnalyzeResult, error) {
|
||||
for _, outcome := range a.analyzer.Outcomes {
|
||||
result := &AnalyzeResult{
|
||||
Title: a.Title(),
|
||||
}
|
||||
|
||||
if outcome.Fail != nil {
|
||||
if outcome.Fail.When == "" {
|
||||
result.IsFail = true
|
||||
result.Message = outcome.Fail.Message
|
||||
result.URI = outcome.Fail.URI
|
||||
|
||||
return result, nil
|
||||
} else {
|
||||
isMatch, out, err := a.compareNodeMetricConditionalsToStats(outcome.Fail.When, summaries)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compare node metrics conditional with summary stats")
|
||||
}
|
||||
|
||||
if isMatch {
|
||||
result.IsFail = true
|
||||
result.Message = renderTemplate(outcome.Fail.Message, out)
|
||||
result.URI = outcome.Fail.URI
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
} else if outcome.Warn != nil {
|
||||
if outcome.Warn.When == "" {
|
||||
result.IsWarn = true
|
||||
result.Message = outcome.Warn.Message
|
||||
result.URI = outcome.Warn.URI
|
||||
|
||||
return result, nil
|
||||
} else {
|
||||
isMatch, out, err := a.compareNodeMetricConditionalsToStats(outcome.Warn.When, summaries)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compare node metrics conditional with summary stats")
|
||||
}
|
||||
|
||||
if isMatch {
|
||||
result.IsWarn = true
|
||||
result.Message = renderTemplate(outcome.Warn.Message, out)
|
||||
result.URI = outcome.Warn.URI
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
} else if outcome.Pass != nil {
|
||||
if outcome.Pass.When == "" {
|
||||
result.IsPass = true
|
||||
result.Message = outcome.Pass.Message
|
||||
result.URI = outcome.Pass.URI
|
||||
|
||||
return result, nil
|
||||
} else {
|
||||
isMatch, out, err := a.compareNodeMetricConditionalsToStats(outcome.Pass.When, summaries)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compare node metrics conditional with summary stats")
|
||||
}
|
||||
|
||||
if isMatch {
|
||||
result.IsPass = true
|
||||
result.Message = renderTemplate(outcome.Pass.Message, out)
|
||||
result.URI = outcome.Pass.URI
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (a *AnalyzeNodeMetrics) findPVCUsageStats(summaries []kubeletv1alpha1.Summary) ([]pvcUsageStats, error) {
|
||||
// We just collect usage percentages for now. If other stats are needed, we can add them.
|
||||
stats := []pvcUsageStats{}
|
||||
var nameRegex *regexp.Regexp
|
||||
var ns string
|
||||
var err error
|
||||
|
||||
pvcFilter := a.analyzer.Filters.PVC
|
||||
if pvcFilter != nil {
|
||||
if pvcFilter.NameRegex != "" {
|
||||
nameRegex, err = regexp.Compile(pvcFilter.NameRegex)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compile PVC name regex")
|
||||
}
|
||||
}
|
||||
|
||||
ns = pvcFilter.Namespace
|
||||
}
|
||||
|
||||
// Analyze PVCs
|
||||
for _, summary := range summaries {
|
||||
for i := range summary.Pods {
|
||||
pod := summary.Pods[i]
|
||||
if ns != "" && ns != pod.PodRef.Namespace {
|
||||
klog.V(2).Infof("Skipping pvcs in %s/%s pod due to namespace filter", pod.PodRef.Namespace, pod.PodRef.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
for j := range pod.VolumeStats {
|
||||
volume := pod.VolumeStats[j]
|
||||
|
||||
// This is a persistent volume
|
||||
if volume.PVCRef != nil {
|
||||
if nameRegex != nil && !nameRegex.MatchString(volume.PVCRef.Name) {
|
||||
klog.V(2).Infof("Skipping pvc %s/%s due to name regex filter", volume.PVCRef.Namespace, volume.PVCRef.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
// Calculate the usage
|
||||
pvcName := fmt.Sprintf("%s/%s", volume.PVCRef.Namespace, volume.PVCRef.Name)
|
||||
|
||||
used := volume.UsedBytes
|
||||
capacity := volume.CapacityBytes
|
||||
if used != nil && capacity != nil {
|
||||
pvcUsedPercentage := float64(*used) / float64(*capacity) * 100
|
||||
stats = append(stats, pvcUsageStats{
|
||||
PvcName: pvcName,
|
||||
Used: pvcUsedPercentage,
|
||||
})
|
||||
klog.V(2).Infof("PVC usage for %s: %0.2f%%", pvcName, pvcUsedPercentage)
|
||||
} else {
|
||||
klog.V(2).Infof("Missing capacity or used bytes for PVC %s", pvcName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// compareNodeMetricConditionalsToStats compares the conditional with the collected node metrics
|
||||
// and returns true if the conditional is met. At the moment we only support comparing PVC usage
|
||||
func (a *AnalyzeNodeMetrics) compareNodeMetricConditionalsToStats(conditional string, summaries []kubeletv1alpha1.Summary) (bool, nodeMetricsComparisonResults, error) {
|
||||
klog.V(2).Infof("Comparing node metrics with conditional: %s", conditional)
|
||||
parts := strings.Split(strings.TrimSpace(conditional), " ")
|
||||
out := nodeMetricsComparisonResults{}
|
||||
|
||||
if len(parts) != 3 {
|
||||
return false, out, errors.New("unable to parse conditional")
|
||||
}
|
||||
|
||||
switch parts[0] {
|
||||
case "pvcUsedPercentage":
|
||||
// e.g pvcUsedPercentage >= 50.4
|
||||
|
||||
klog.V(2).Infof("Analyzing volume usage stats for PVCs")
|
||||
|
||||
op, err := ParseComparisonOperator(parts[1])
|
||||
if err != nil {
|
||||
return false, out, errors.Wrap(err, "failed to parse comparison operator")
|
||||
}
|
||||
|
||||
expected, err := strconv.ParseFloat(parts[2], 64)
|
||||
if err != nil {
|
||||
return false, out, errors.Wrap(err, "failed to parse bool")
|
||||
}
|
||||
|
||||
// Pick all PVCs from all summaries. Filters will be applied here
|
||||
pvcUsageStats, err := a.findPVCUsageStats(summaries)
|
||||
if err != nil {
|
||||
return false, out, errors.Wrap(err, "failed to find PVC usage stats")
|
||||
}
|
||||
matchedPVCs := []string{}
|
||||
|
||||
for _, pvcUsage := range pvcUsageStats {
|
||||
value := pvcUsage.Used
|
||||
switch op {
|
||||
case Equal:
|
||||
if value == expected {
|
||||
matchedPVCs = append(matchedPVCs, pvcUsage.PvcName)
|
||||
}
|
||||
case NotEqual:
|
||||
if value != expected {
|
||||
matchedPVCs = append(matchedPVCs, pvcUsage.PvcName)
|
||||
}
|
||||
case LessThan:
|
||||
if value < expected {
|
||||
matchedPVCs = append(matchedPVCs, pvcUsage.PvcName)
|
||||
}
|
||||
case GreaterThan:
|
||||
if value > expected {
|
||||
matchedPVCs = append(matchedPVCs, pvcUsage.PvcName)
|
||||
}
|
||||
case LessThanOrEqual:
|
||||
if value <= expected {
|
||||
matchedPVCs = append(matchedPVCs, pvcUsage.PvcName)
|
||||
}
|
||||
case GreaterThanOrEqual:
|
||||
if value >= expected {
|
||||
matchedPVCs = append(matchedPVCs, pvcUsage.PvcName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Concatenate all matched PVC names
|
||||
out.PVC = pvcTemplateData{
|
||||
Names: matchedPVCs,
|
||||
ConcatenatedNames: strings.Join(matchedPVCs, ", "),
|
||||
}
|
||||
return len(matchedPVCs) > 0, out, nil
|
||||
}
|
||||
|
||||
return false, out, errors.New("unknown node metric conditional")
|
||||
}
|
||||
|
||||
func renderTemplate(tmpMsg string, data any) string {
|
||||
if data == nil {
|
||||
return tmpMsg
|
||||
}
|
||||
|
||||
t, err := template.New("msg").Parse(tmpMsg)
|
||||
if err != nil {
|
||||
klog.V(2).Infof("Failed to parse template: %s", err)
|
||||
return tmpMsg
|
||||
}
|
||||
|
||||
var m bytes.Buffer
|
||||
err = t.Execute(&m, data)
|
||||
if err != nil {
|
||||
klog.V(2).Infof("Failed to execute template: %s", err)
|
||||
return tmpMsg
|
||||
}
|
||||
|
||||
return m.String()
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
kubeletv1alpha1 "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
|
||||
utilptr "k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
func TestAnalyzeNodeMetrics_findPVCUsageStats(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
analyzer troubleshootv1beta2.NodeMetricsAnalyze
|
||||
summaries []kubeletv1alpha1.Summary
|
||||
want []pvcUsageStats
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "no summaries",
|
||||
summaries: []kubeletv1alpha1.Summary{},
|
||||
want: []pvcUsageStats{},
|
||||
},
|
||||
{
|
||||
name: "one summary",
|
||||
summaries: []kubeletv1alpha1.Summary{
|
||||
{
|
||||
Pods: []kubeletv1alpha1.PodStats{
|
||||
{
|
||||
PodRef: kubeletv1alpha1.PodReference{
|
||||
Namespace: "default",
|
||||
Name: "my-pod",
|
||||
},
|
||||
VolumeStats: []kubeletv1alpha1.VolumeStats{
|
||||
{
|
||||
Name: "volume-1",
|
||||
PVCRef: &kubeletv1alpha1.PVCReference{
|
||||
Namespace: "default",
|
||||
Name: "my-pvc",
|
||||
},
|
||||
FsStats: kubeletv1alpha1.FsStats{
|
||||
AvailableBytes: utilptr.To(uint64(20)),
|
||||
UsedBytes: utilptr.To(uint64(80)),
|
||||
CapacityBytes: utilptr.To(uint64(100)),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []pvcUsageStats{
|
||||
{
|
||||
Used: 80,
|
||||
PvcName: "default/my-pvc",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "one summary with namespace filter",
|
||||
analyzer: troubleshootv1beta2.NodeMetricsAnalyze{
|
||||
Filters: troubleshootv1beta2.NodeMetricsAnalyzeFilters{
|
||||
PVC: &troubleshootv1beta2.PVCRef{
|
||||
Namespace: "another-namespace",
|
||||
},
|
||||
},
|
||||
},
|
||||
summaries: []kubeletv1alpha1.Summary{
|
||||
{
|
||||
Pods: []kubeletv1alpha1.PodStats{
|
||||
{
|
||||
PodRef: kubeletv1alpha1.PodReference{
|
||||
Namespace: "default",
|
||||
Name: "my-pod",
|
||||
},
|
||||
VolumeStats: []kubeletv1alpha1.VolumeStats{
|
||||
{
|
||||
Name: "volume-1",
|
||||
PVCRef: &kubeletv1alpha1.PVCReference{
|
||||
Namespace: "default",
|
||||
Name: "my-pvc",
|
||||
},
|
||||
FsStats: kubeletv1alpha1.FsStats{
|
||||
AvailableBytes: utilptr.To(uint64(20)),
|
||||
UsedBytes: utilptr.To(uint64(80)),
|
||||
CapacityBytes: utilptr.To(uint64(100)),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []pvcUsageStats{},
|
||||
},
|
||||
{
|
||||
name: "one summary with name regex filter",
|
||||
analyzer: troubleshootv1beta2.NodeMetricsAnalyze{
|
||||
Filters: troubleshootv1beta2.NodeMetricsAnalyzeFilters{
|
||||
PVC: &troubleshootv1beta2.PVCRef{
|
||||
NameRegex: ".*other.*",
|
||||
},
|
||||
},
|
||||
},
|
||||
summaries: []kubeletv1alpha1.Summary{
|
||||
{
|
||||
Pods: []kubeletv1alpha1.PodStats{
|
||||
{
|
||||
PodRef: kubeletv1alpha1.PodReference{
|
||||
Namespace: "default",
|
||||
Name: "my-pod",
|
||||
},
|
||||
VolumeStats: []kubeletv1alpha1.VolumeStats{
|
||||
{
|
||||
Name: "volume-1",
|
||||
PVCRef: &kubeletv1alpha1.PVCReference{
|
||||
Namespace: "default",
|
||||
Name: "my-pvc",
|
||||
},
|
||||
FsStats: kubeletv1alpha1.FsStats{
|
||||
AvailableBytes: utilptr.To(uint64(20)),
|
||||
UsedBytes: utilptr.To(uint64(80)),
|
||||
CapacityBytes: utilptr.To(uint64(100)),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "volume-1",
|
||||
PVCRef: &kubeletv1alpha1.PVCReference{
|
||||
Namespace: "default",
|
||||
Name: "my-other-pvc",
|
||||
},
|
||||
FsStats: kubeletv1alpha1.FsStats{
|
||||
AvailableBytes: utilptr.To(uint64(25)),
|
||||
UsedBytes: utilptr.To(uint64(75)),
|
||||
CapacityBytes: utilptr.To(uint64(100)),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []pvcUsageStats{
|
||||
{
|
||||
Used: 75,
|
||||
PvcName: "default/my-other-pvc",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &AnalyzeNodeMetrics{
|
||||
analyzer: &tt.analyzer,
|
||||
}
|
||||
got, err := a.findPVCUsageStats(tt.summaries)
|
||||
assert.Equalf(t, tt.wantErr, err != nil, "AnalyzeNodeMetrics.findPVCUsageStats() error = %v, wantErr %v", err, tt.wantErr)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnalyzeNodeMetrics_Analyze(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
analyzer troubleshootv1beta2.NodeMetricsAnalyze
|
||||
nodeMetrics string
|
||||
want []*AnalyzeResult
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "no node metrics",
|
||||
analyzer: troubleshootv1beta2.NodeMetricsAnalyze{
|
||||
Filters: troubleshootv1beta2.NodeMetricsAnalyzeFilters{},
|
||||
},
|
||||
nodeMetrics: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid node metrics",
|
||||
analyzer: troubleshootv1beta2.NodeMetricsAnalyze{
|
||||
Filters: troubleshootv1beta2.NodeMetricsAnalyzeFilters{},
|
||||
},
|
||||
nodeMetrics: "invalid",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "no summaries",
|
||||
analyzer: troubleshootv1beta2.NodeMetricsAnalyze{
|
||||
Filters: troubleshootv1beta2.NodeMetricsAnalyzeFilters{},
|
||||
},
|
||||
nodeMetrics: "{}",
|
||||
want: []*AnalyzeResult{},
|
||||
},
|
||||
{
|
||||
name: "one summary with name regex filter",
|
||||
analyzer: troubleshootv1beta2.NodeMetricsAnalyze{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "pvcUsedPercentage >= 75",
|
||||
Message: "PVC space usage is too high for pvcs [{{ .PVC.ConcatenatedNames }}]",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "No PVCs are using more than 80% of storage",
|
||||
},
|
||||
},
|
||||
},
|
||||
Filters: troubleshootv1beta2.NodeMetricsAnalyzeFilters{
|
||||
PVC: &troubleshootv1beta2.PVCRef{
|
||||
NameRegex: ".*other.*",
|
||||
},
|
||||
},
|
||||
},
|
||||
nodeMetrics: `{
|
||||
"pods": [
|
||||
{
|
||||
"podRef": {
|
||||
"name": "my-pod",
|
||||
"namespace": "my-namespace"
|
||||
},
|
||||
"volume": [
|
||||
{
|
||||
"capacityBytes": 100,
|
||||
"usedBytes": 80,
|
||||
"pvcRef": {
|
||||
"name": "backup-pvc",
|
||||
"namespace": "my-namespace"
|
||||
}
|
||||
},
|
||||
{
|
||||
"capacityBytes": 100,
|
||||
"usedBytes": 75,
|
||||
"pvcRef": {
|
||||
"name": "another-pvc",
|
||||
"namespace": "my-namespace"
|
||||
}
|
||||
},
|
||||
{
|
||||
"capacityBytes": 100,
|
||||
"usedBytes": 80,
|
||||
"pvcRef": {
|
||||
"name": "the-other-pvc",
|
||||
"namespace": "my-namespace"
|
||||
}
|
||||
},
|
||||
{
|
||||
"capacityBytes": 100,
|
||||
"usedBytes": 65,
|
||||
"pvcRef": {
|
||||
"name": "to-other-pvc",
|
||||
"namespace": "my-namespace"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
want: []*AnalyzeResult{
|
||||
{
|
||||
Title: "Node Metrics",
|
||||
IsFail: true,
|
||||
Message: "PVC space usage is too high for pvcs [my-namespace/another-pvc, my-namespace/the-other-pvc]",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &AnalyzeNodeMetrics{
|
||||
analyzer: &tt.analyzer,
|
||||
}
|
||||
filesFn := func(string, []string) (map[string][]byte, error) {
|
||||
return map[string][]byte{
|
||||
"node-metrics.json": []byte(tt.nodeMetrics),
|
||||
}, nil
|
||||
}
|
||||
|
||||
got, err := a.Analyze(nil, filesFn)
|
||||
assert.Equalf(t, tt.wantErr, err != nil, "AnalyzeNodeMetrics.Analyze() error = %v, wantErr %v", err, tt.wantErr)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -17,22 +17,23 @@ import (
|
||||
)
|
||||
|
||||
var Filemap = map[string]string{
|
||||
"Deployment": constants.CLUSTER_RESOURCES_DEPLOYMENTS,
|
||||
"StatefulSet": constants.CLUSTER_RESOURCES_STATEFULSETS,
|
||||
"NetworkPolicy": constants.CLUSTER_RESOURCES_NETWORK_POLICY,
|
||||
"Pod": constants.CLUSTER_RESOURCES_PODS,
|
||||
"Ingress": constants.CLUSTER_RESOURCES_INGRESS,
|
||||
"Service": constants.CLUSTER_RESOURCES_SERVICES,
|
||||
"ResourceQuota": constants.CLUSTER_RESOURCES_RESOURCE_QUOTA,
|
||||
"Job": constants.CLUSTER_RESOURCES_JOBS,
|
||||
"PersistentVolumeClaim": constants.CLUSTER_RESOURCES_PVCS,
|
||||
"deployment": constants.CLUSTER_RESOURCES_DEPLOYMENTS,
|
||||
"statefulset": constants.CLUSTER_RESOURCES_STATEFULSETS,
|
||||
"networkpolicy": constants.CLUSTER_RESOURCES_NETWORK_POLICY,
|
||||
"pod": constants.CLUSTER_RESOURCES_PODS,
|
||||
"ingress": constants.CLUSTER_RESOURCES_INGRESS,
|
||||
"service": constants.CLUSTER_RESOURCES_SERVICES,
|
||||
"resourcequota": constants.CLUSTER_RESOURCES_RESOURCE_QUOTA,
|
||||
"job": constants.CLUSTER_RESOURCES_JOBS,
|
||||
"persistentvolumeclaim": constants.CLUSTER_RESOURCES_PVCS,
|
||||
"pvc": constants.CLUSTER_RESOURCES_PVCS,
|
||||
"ReplicaSet": constants.CLUSTER_RESOURCES_REPLICASETS,
|
||||
"Namespace": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_NAMESPACES),
|
||||
"PersistentVolume": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_PVS),
|
||||
"replicaset": constants.CLUSTER_RESOURCES_REPLICASETS,
|
||||
"configmap": constants.CLUSTER_RESOURCES_CONFIGMAPS,
|
||||
"namespace": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_NAMESPACES),
|
||||
"persistentvolume": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_PVS),
|
||||
"pv": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_PVS),
|
||||
"Node": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_NODES),
|
||||
"StorageClass": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_STORAGE_CLASS),
|
||||
"node": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_NODES),
|
||||
"storageclass": fmt.Sprintf("%s.json", constants.CLUSTER_RESOURCES_STORAGE_CLASS),
|
||||
}
|
||||
|
||||
type AnalyzeClusterResource struct {
|
||||
@@ -66,6 +67,9 @@ func FindResource(kind string, clusterScoped bool, namespace string, name string
|
||||
|
||||
var datapath string
|
||||
|
||||
// lowercase the kind to avoid case sensitivity
|
||||
kind = strings.ToLower(kind)
|
||||
|
||||
resourceLocation, ok := Filemap[kind]
|
||||
|
||||
if !ok {
|
||||
|
||||
@@ -21,13 +21,13 @@ func Test_findResource(t *testing.T) {
|
||||
resourceExists: true,
|
||||
analyzer: troubleshootv1beta2.ClusterResource{
|
||||
CollectorName: "Check namespaced resource",
|
||||
Kind: "Deployment",
|
||||
Kind: "deployment",
|
||||
Namespace: "kube-system",
|
||||
Name: "coredns",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "check default fallthrough",
|
||||
name: "check default fallthrough with case insensitivity",
|
||||
resourceExists: true,
|
||||
analyzer: troubleshootv1beta2.ClusterResource{
|
||||
CollectorName: "Check namespaced resource",
|
||||
@@ -40,7 +40,7 @@ func Test_findResource(t *testing.T) {
|
||||
resourceExists: true,
|
||||
analyzer: troubleshootv1beta2.ClusterResource{
|
||||
CollectorName: "Check namespaced resource",
|
||||
Kind: "Node",
|
||||
Kind: "node",
|
||||
ClusterScoped: true,
|
||||
Name: "repldev-marc",
|
||||
},
|
||||
@@ -50,11 +50,21 @@ func Test_findResource(t *testing.T) {
|
||||
resourceExists: false,
|
||||
analyzer: troubleshootv1beta2.ClusterResource{
|
||||
CollectorName: "Check namespaced resource",
|
||||
Kind: "Node",
|
||||
Kind: "node",
|
||||
ClusterScoped: true,
|
||||
Name: "resource-does-not-exist",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "configmap does exist",
|
||||
resourceExists: true,
|
||||
analyzer: troubleshootv1beta2.ClusterResource{
|
||||
CollectorName: "Check namespaced resource",
|
||||
Kind: "configmap",
|
||||
Namespace: "kube-public",
|
||||
Name: "kube-root-ca.crt",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -101,6 +101,10 @@ func analyzeOneReplicaSetStatus(analyzer *troubleshootv1beta2.ReplicaSetStatus,
|
||||
}
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
|
||||
|
||||
+15
-12
@@ -361,11 +361,9 @@ func analyzeBackups(backups []*velerov1.Backup) []*AnalyzeResult {
|
||||
results := []*AnalyzeResult{}
|
||||
|
||||
failedPhases := map[velerov1.BackupPhase]bool{
|
||||
velerov1.BackupPhaseFailed: true,
|
||||
velerov1.BackupPhasePartiallyFailed: true,
|
||||
velerov1.BackupPhaseFailedValidation: true,
|
||||
velerov1.BackupPhaseFinalizingPartiallyFailed: true,
|
||||
velerov1.BackupPhaseWaitingForPluginOperationsPartiallyFailed: true,
|
||||
velerov1.BackupPhaseFailed: true,
|
||||
velerov1.BackupPhasePartiallyFailed: true,
|
||||
velerov1.BackupPhaseFailedValidation: true,
|
||||
}
|
||||
|
||||
for _, backup := range backups {
|
||||
@@ -510,10 +508,9 @@ func analyzeRestores(restores []*velerov1.Restore) []*AnalyzeResult {
|
||||
if len(restores) > 0 {
|
||||
|
||||
failedPhases := map[velerov1.RestorePhase]bool{
|
||||
velerov1.RestorePhaseFailed: true,
|
||||
velerov1.RestorePhasePartiallyFailed: true,
|
||||
velerov1.RestorePhaseFailedValidation: true,
|
||||
velerov1.RestorePhaseWaitingForPluginOperationsPartiallyFailed: true,
|
||||
velerov1.RestorePhaseFailed: true,
|
||||
velerov1.RestorePhasePartiallyFailed: true,
|
||||
velerov1.RestorePhaseFailedValidation: true,
|
||||
}
|
||||
|
||||
for _, restore := range restores {
|
||||
@@ -658,17 +655,23 @@ func getVeleroVersion(excludedFiles []string, findFiles getChildCollectedFileCon
|
||||
veleroDeploymentGlob := filepath.Join(veleroDeploymentDir, "velero.json")
|
||||
veleroDeploymentJson, err := findFiles(veleroDeploymentGlob, excludedFiles)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to find velero deployment file under %s", veleroDeploymentDir)
|
||||
return "", errors.Wrapf(err, "failed to find Velero deployment")
|
||||
}
|
||||
if len(veleroDeploymentJson) == 0 {
|
||||
return "", errors.Errorf("could not find Velero deployment in %s", veleroDeploymentDir)
|
||||
}
|
||||
var deploymentList *appsV1.DeploymentList
|
||||
// should run only once
|
||||
for key, veleroDeploymentJsonBytes := range veleroDeploymentJson {
|
||||
err := json.Unmarshal(veleroDeploymentJsonBytes, &deploymentList)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to unmarshal velero deployment json from %s", key)
|
||||
return "", errors.Wrapf(err, "failed to unmarshal Velero deployment json from %s", key)
|
||||
}
|
||||
break
|
||||
}
|
||||
if deploymentList == nil {
|
||||
return "", errors.Errorf("could not find Velero deployment")
|
||||
}
|
||||
for _, deployment := range deploymentList.Items {
|
||||
for _, container := range deployment.Spec.Template.Spec.Containers {
|
||||
if container.Name == "velero" {
|
||||
@@ -679,7 +682,7 @@ func getVeleroVersion(excludedFiles []string, findFiles getChildCollectedFileCon
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.Errorf("Unable to get velero version. Could not find velero container in deployment!")
|
||||
return "", errors.Errorf("could not find Velero container in deployment")
|
||||
}
|
||||
|
||||
func GetVeleroBackupsDirectory() string {
|
||||
|
||||
@@ -626,32 +626,6 @@ func TestAnalyzeVelero_Restores(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "restores - failures",
|
||||
args: args{
|
||||
restores: []*velerov1.Restore{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "observability-backup-20210308150016",
|
||||
Namespace: "velero",
|
||||
},
|
||||
Spec: velerov1.RestoreSpec{
|
||||
BackupName: "observability-backup",
|
||||
},
|
||||
Status: velerov1.RestoreStatus{
|
||||
Phase: velerov1.RestorePhaseWaitingForPluginOperationsPartiallyFailed,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []*AnalyzeResult{
|
||||
{
|
||||
Title: "Restore observability-backup-20210308150016",
|
||||
Message: "Restore observability-backup-20210308150016 phase is WaitingForPluginOperationsPartiallyFailed",
|
||||
IsFail: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
@@ -232,6 +232,32 @@ type GoldpingerAnalyze struct {
|
||||
FilePath string `json:"filePath,omitempty" yaml:"filePath,omitempty"`
|
||||
}
|
||||
|
||||
type EventAnalyze struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
CollectorName string `json:"collectorName" yaml:"collectorName"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
Reason string `json:"reason" yaml:"reason"`
|
||||
RegexPattern string `json:"regex,omitempty" yaml:"regex,omitempty"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
}
|
||||
|
||||
type NodeMetricsAnalyze struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
CollectorName string `json:"collectorName" yaml:"collectorName"`
|
||||
Filters NodeMetricsAnalyzeFilters `json:"filters,omitempty" yaml:"filters,omitempty"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
}
|
||||
|
||||
type NodeMetricsAnalyzeFilters struct {
|
||||
PVC *PVCRef `json:"pvc,omitempty" yaml:"pvc,omitempty"`
|
||||
}
|
||||
|
||||
type PVCRef struct {
|
||||
NameRegex string `json:"nameRegex,omitempty" yaml:"nameRegex,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
type Analyze struct {
|
||||
ClusterVersion *ClusterVersion `json:"clusterVersion,omitempty" yaml:"clusterVersion,omitempty"`
|
||||
StorageClass *StorageClass `json:"storageClass,omitempty" yaml:"storageClass,omitempty"`
|
||||
@@ -264,4 +290,6 @@ type Analyze struct {
|
||||
ClusterResource *ClusterResource `json:"clusterResource,omitempty" yaml:"clusterResource,omitempty"`
|
||||
Certificates *CertificatesAnalyze `json:"certificates,omitempty" yaml:"certificates,omitempty"`
|
||||
Goldpinger *GoldpingerAnalyze `json:"goldpinger,omitempty" yaml:"goldpinger,omitempty"`
|
||||
Event *EventAnalyze `json:"event,omitempty" yaml:"event,omitempty"`
|
||||
NodeMetrics *NodeMetricsAnalyze `json:"nodeMetrics,omitempty" yaml:"nodeMetrics,omitempty"`
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ type CustomMetrics struct {
|
||||
MetricRequests []MetricRequest `json:"metricRequests,omitempty" yaml:"metricRequests,omitempty"`
|
||||
}
|
||||
|
||||
type NodeMetrics struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
NodeNames []string `json:"nodeNames,omitempty" yaml:"nodeNames,omitempty"`
|
||||
Selector []string `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
}
|
||||
|
||||
type Secret struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
@@ -107,6 +113,15 @@ type RunPod struct {
|
||||
PodSpec corev1.PodSpec `json:"podSpec,omitempty" yaml:"podSpec,omitempty"`
|
||||
}
|
||||
|
||||
type RunDaemonSet struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
ImagePullSecret *ImagePullSecrets `json:"imagePullSecret,omitempty" yaml:"imagePullSecret,omitempty"`
|
||||
PodSpec corev1.PodSpec `json:"podSpec,omitempty" yaml:"podSpec,omitempty"`
|
||||
}
|
||||
|
||||
type ImagePullSecrets struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Data map[string]string `json:"data,omitempty" yaml:"data,omitempty"`
|
||||
@@ -273,6 +288,16 @@ type PodLaunchOptions struct {
|
||||
ServiceAccountName string `json:"serviceAccountName,omitempty" yaml:"serviceAccountName,omitempty"`
|
||||
}
|
||||
|
||||
type Sonobuoy struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
type DNS struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
type Collect struct {
|
||||
ClusterInfo *ClusterInfo `json:"clusterInfo,omitempty" yaml:"clusterInfo,omitempty"`
|
||||
ClusterResources *ClusterResources `json:"clusterResources,omitempty" yaml:"clusterResources,omitempty"`
|
||||
@@ -282,6 +307,7 @@ type Collect struct {
|
||||
Logs *Logs `json:"logs,omitempty" yaml:"logs,omitempty"`
|
||||
Run *Run `json:"run,omitempty" yaml:"run,omitempty"`
|
||||
RunPod *RunPod `json:"runPod,omitempty" yaml:"runPod,omitempty"`
|
||||
RunDaemonSet *RunDaemonSet `json:"runDaemonSet,omitempty" yaml:"runDaemonSet,omitempty"`
|
||||
Exec *Exec `json:"exec,omitempty" yaml:"exec,omitempty"`
|
||||
Data *Data `json:"data,omitempty" yaml:"data,omitempty"`
|
||||
Copy *Copy `json:"copy,omitempty" yaml:"copy,omitempty"`
|
||||
@@ -299,6 +325,9 @@ type Collect struct {
|
||||
Certificates *Certificates `json:"certificates,omitempty" yaml:"certificates,omitempty"`
|
||||
Helm *Helm `json:"helm,omitempty" yaml:"helm,omitempty"`
|
||||
Goldpinger *Goldpinger `json:"goldpinger,omitempty" yaml:"goldpinger,omitempty"`
|
||||
Sonobuoy *Sonobuoy `json:"sonobuoy,omitempty" yaml:"sonobuoy,omitempty"`
|
||||
NodeMetrics *NodeMetrics `json:"nodeMetrics,omitempty" yaml:"nodeMetrics,omitempty"`
|
||||
DNS *DNS `json:"dns,omitempty" yaml:"dns,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSubjectAccessReviewSpec {
|
||||
@@ -432,6 +461,19 @@ func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSub
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
} else if c.RunDaemonSet != nil {
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: pickNamespaceOrDefault(c.RunDaemonSet.Namespace, overrideNS),
|
||||
Verb: "create",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "pods",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
} else if c.Exec != nil {
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
@@ -542,6 +584,10 @@ func (c *Collect) GetName() string {
|
||||
collector = "run-pod"
|
||||
name = c.RunPod.CollectorName
|
||||
}
|
||||
if c.RunDaemonSet != nil {
|
||||
collector = "run-daemonset"
|
||||
name = c.RunDaemonSet.CollectorName
|
||||
}
|
||||
if c.Exec != nil {
|
||||
collector = "exec"
|
||||
name = c.Exec.CollectorName
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
@@ -209,6 +208,16 @@ func (in *Analyze) DeepCopyInto(out *Analyze) {
|
||||
*out = new(GoldpingerAnalyze)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Event != nil {
|
||||
in, out := &in.Event, &out.Event
|
||||
*out = new(EventAnalyze)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.NodeMetrics != nil {
|
||||
in, out := &in.NodeMetrics, &out.NodeMetrics
|
||||
*out = new(NodeMetricsAnalyze)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Analyze.
|
||||
@@ -817,6 +826,11 @@ func (in *Collect) DeepCopyInto(out *Collect) {
|
||||
*out = new(RunPod)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.RunDaemonSet != nil {
|
||||
in, out := &in.RunDaemonSet, &out.RunDaemonSet
|
||||
*out = new(RunDaemonSet)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Exec != nil {
|
||||
in, out := &in.Exec, &out.Exec
|
||||
*out = new(Exec)
|
||||
@@ -902,6 +916,21 @@ func (in *Collect) DeepCopyInto(out *Collect) {
|
||||
*out = new(Goldpinger)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Sonobuoy != nil {
|
||||
in, out := &in.Sonobuoy, &out.Sonobuoy
|
||||
*out = new(Sonobuoy)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.NodeMetrics != nil {
|
||||
in, out := &in.NodeMetrics, &out.NodeMetrics
|
||||
*out = new(NodeMetrics)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.DNS != nil {
|
||||
in, out := &in.DNS, &out.DNS
|
||||
*out = new(DNS)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Collect.
|
||||
@@ -1231,6 +1260,22 @@ func (in *CustomResourceDefinition) DeepCopy() *CustomResourceDefinition {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DNS) DeepCopyInto(out *DNS) {
|
||||
*out = *in
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNS.
|
||||
func (in *DNS) DeepCopy() *DNS {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DNS)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Data) DeepCopyInto(out *Data) {
|
||||
*out = *in
|
||||
@@ -1402,6 +1447,33 @@ func (in *Distribution) DeepCopy() *Distribution {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *EventAnalyze) DeepCopyInto(out *EventAnalyze) {
|
||||
*out = *in
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Outcome)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventAnalyze.
|
||||
func (in *EventAnalyze) DeepCopy() *EventAnalyze {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(EventAnalyze)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Exec) DeepCopyInto(out *Exec) {
|
||||
*out = *in
|
||||
@@ -2943,6 +3015,80 @@ func (in *MetricRequest) DeepCopy() *MetricRequest {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeMetrics) DeepCopyInto(out *NodeMetrics) {
|
||||
*out = *in
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.NodeNames != nil {
|
||||
in, out := &in.NodeNames, &out.NodeNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeMetrics.
|
||||
func (in *NodeMetrics) DeepCopy() *NodeMetrics {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NodeMetrics)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeMetricsAnalyze) DeepCopyInto(out *NodeMetricsAnalyze) {
|
||||
*out = *in
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
in.Filters.DeepCopyInto(&out.Filters)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Outcome)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeMetricsAnalyze.
|
||||
func (in *NodeMetricsAnalyze) DeepCopy() *NodeMetricsAnalyze {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NodeMetricsAnalyze)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeMetricsAnalyzeFilters) DeepCopyInto(out *NodeMetricsAnalyzeFilters) {
|
||||
*out = *in
|
||||
if in.PVC != nil {
|
||||
in, out := &in.PVC, &out.PVC
|
||||
*out = new(PVCRef)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeMetricsAnalyzeFilters.
|
||||
func (in *NodeMetricsAnalyzeFilters) DeepCopy() *NodeMetricsAnalyzeFilters {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NodeMetricsAnalyzeFilters)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeResourceFilters) DeepCopyInto(out *NodeResourceFilters) {
|
||||
*out = *in
|
||||
@@ -3047,6 +3193,21 @@ func (in *Outcome) DeepCopy() *Outcome {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PVCRef) DeepCopyInto(out *PVCRef) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PVCRef.
|
||||
func (in *PVCRef) DeepCopy() *PVCRef {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PVCRef)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PodLaunchOptions) DeepCopyInto(out *PodLaunchOptions) {
|
||||
*out = *in
|
||||
@@ -4078,6 +4239,28 @@ func (in *Run) DeepCopy() *Run {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RunDaemonSet) DeepCopyInto(out *RunDaemonSet) {
|
||||
*out = *in
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.ImagePullSecret != nil {
|
||||
in, out := &in.ImagePullSecret, &out.ImagePullSecret
|
||||
*out = new(ImagePullSecrets)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
in.PodSpec.DeepCopyInto(&out.PodSpec)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunDaemonSet.
|
||||
func (in *RunDaemonSet) DeepCopy() *RunDaemonSet {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RunDaemonSet)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RunPod) DeepCopyInto(out *RunPod) {
|
||||
*out = *in
|
||||
@@ -4136,6 +4319,22 @@ func (in *SingleOutcome) DeepCopy() *SingleOutcome {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Sonobuoy) DeepCopyInto(out *Sonobuoy) {
|
||||
*out = *in
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Sonobuoy.
|
||||
func (in *Sonobuoy) DeepCopy() *Sonobuoy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Sonobuoy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StatefulsetStatus) DeepCopyInto(out *StatefulsetStatus) {
|
||||
*out = *in
|
||||
|
||||
@@ -91,25 +91,23 @@ vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||
+OkuE6N36B9K
|
||||
-----END CERTIFICATE-----`,
|
||||
"validCert": `-----BEGIN CERTIFICATE-----
|
||||
MIIDejCCAmKgAwIBAgIEAZaq0DANBgkqhkiG9w0BAQsFADAuMRgwFgYDVQQDEw9Q
|
||||
cm9qZWN0IENvbnRvdXIxEjAQBgNVBAUTCTYxNTkyOTg5MTAeFw0yMzAyMjQwNDI3
|
||||
MThaFw0yNDAyMjUwNDI3MTZaMBAxDjAMBgNVBAMTBWVudm95MIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqsNmmxb1ICso6Ay25lapcRyvLxAX/5u422uV
|
||||
eiNn5jseCVXfg1jJr2Symrgou2dgMtIpZoVKT7w0el8sNpD+az5oMOWUNfTGEpYI
|
||||
5zNAhtiedxCWcX15gfezOZ/DECL7HP8U37JFVdazm0CjvlQWI+8rFGvFQJJFDLYJ
|
||||
h0fHGfbX6L/ST6cANtkXZyIU6CYFSgniuuDjHmQnQr6CC8lkisJxY5QVS7MZ02RR
|
||||
nU/dK14ABY+mo/0ZeBKR5si04hr4i18nJJnk4DnHN+jQ/WWWSO1yLqr9kAOj37dA
|
||||
nRAeKuzkx/VbU8DC/3sh0otcazoWO470D+irOy1is0whDArLNwIDAQABo4G9MIG6
|
||||
MA4GA1UdDwEB/wQEAwIE8DAdBgNVHQ4EFgQUbAavOY+vIXgc44k8GvLHH6mdzzYw
|
||||
HwYDVR0jBBgwFoAUb+S3Mu7cbwZiqZaEHTEMyUhLyH4waAYDVR0RBGEwX4IFZW52
|
||||
b3mCFGVudm95LnByb2plY3Rjb250b3VyghhlbnZveS5wcm9qZWN0Y29udG91ci5z
|
||||
dmOCJmVudm95LnByb2plY3Rjb250b3VyLnN2Yy5jbHVzdGVyLmxvY2FsMA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQBIKpBD1T9tugzJF7lajbdulXTb9qGibwQALqauskX9Sq57
|
||||
po/R2TjyxywLn4DgM7BAzzu9qfHWf+S4eQjRUHQshPbUEX9CEsSd5tCu8ZHVbBds
|
||||
6qFagl2+YQ9ng0Xwta9ezvctM3T6Dy9Kkf5OOe9ysMEsBX7s8NFxe68Qku+cExr3
|
||||
78oERlIoNOlT0cNbFLAlH2svNv1uB4qOThRDha52L+mlUdZfTMYZAwNDJWm52t/M
|
||||
NCIm5NJ5jAJpcJmoEb+JMP3j0x6wydHDXFtGm3WRggZRcrjasyodSKK6szbf96+9
|
||||
6syzAwvg9xxNtFxwbhRqqplMEz2sDWaggTrxCQzd
|
||||
MIIDEjCCAfqgAwIBAgIUWG+wobb7huLDKQ4bUn80QKsbVSQwDQYJKoZIhvcNAQEL
|
||||
BQAwGDEWMBQGA1UEAwwNRXhhbXBsZVNlcnZlcjAeFw0yNDAyMjYyMjA5MjdaFw0y
|
||||
OTAyMjQyMjA5MjdaMBgxFjAUBgNVBAMMDUV4YW1wbGVTZXJ2ZXIwggEiMA0GCSqG
|
||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsb9MSNERE7l4b/vxzkRnL6qvkjodbY3yQ
|
||||
DDCbG29jJ71wSwYoz0v4n/Q/tDaJDBUcSjSPIa+L6Gn1BGLNUD2LFec5H5XlwcDq
|
||||
A0D8qzvPLMYaIw4p04M/2Wvkqme79yQta8jXaCnPxTkgysno/FuQR+nDMqXoyW01
|
||||
wMmj8JAYFs9MVPbmP97RqbVHnn7cydzvQvi4+dfBuII9L+TvTQY2o42bbCqCcmov
|
||||
16m0uXp98j4CFfv/8KhCmQcqS0uyvp+J/iJZzEow+1NP72pozPEPv9JhXsYDb+vH
|
||||
KxX5k44fYXVYVQHxYQllLjDDRcbz2DJh2DQXMZTiTLE63tC0m2RjAgMBAAGjVDBS
|
||||
MDEGA1UdEQQqMCiCCGV4YW1wbGUxgghleGFtcGxlMoIIZXhhbXBsZTOCCGV4YW1w
|
||||
bGU0MB0GA1UdDgQWBBTEkowqyNS1ez5XJ0shro/18UQlqTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEANhnxV81NZmt8FcgrcRt73WdKDCE0hQbci65ZkAbcTVOCAs6Rw+aEC04L
|
||||
0gKJT4Zmx3kR3fUwcDQRhjoXIrhmvP59k/8SN0N+Ua50oEYikaetsxEDr8oikwP2
|
||||
eHDKU451jZZfcyII2Jx8XjgtiExcNZL3N9ZtSstp3I9n9BSmMdQHDIvPxNeGdJri
|
||||
l4YGTm+sJLs+c5efSNaEPw1Dr6bhAPamNQwvIspuASJlCTcMCLw2+F3dEolAFUuM
|
||||
E5wI9498c+P3pvl85UfiQISTu95jOl7YmZOYl8xBpu9yhQ7kjWhVRdVAnhl9Ts9F
|
||||
3TD68rCMXegJYyg5VbiwVdSPkcw3eQ==
|
||||
-----END CERTIFICATE-----`,
|
||||
"nonCert": `-----BEGIN CERTIFICATE-----
|
||||
Oy1is0whDArLNwIDAQABo4G9MIG6
|
||||
@@ -248,16 +246,16 @@ func TestCertParser(t *testing.T) {
|
||||
CertificateChain: []ParsedCertificate{
|
||||
{
|
||||
CertName: "tls.crt",
|
||||
Subject: "CN=envoy",
|
||||
Subject: "CN=ExampleServer",
|
||||
SubjectAlternativeNames: []string{
|
||||
"envoy",
|
||||
"envoy.projectcontour",
|
||||
"envoy.projectcontour.svc",
|
||||
"envoy.projectcontour.svc.cluster.local",
|
||||
"example1",
|
||||
"example2",
|
||||
"example3",
|
||||
"example4",
|
||||
},
|
||||
Issuer: "SERIALNUMBER=615929891,CN=Project Contour",
|
||||
NotAfter: time.Date(2024, time.February, 25, 4, 27, 16, 0, time.UTC),
|
||||
NotBefore: time.Date(2023, time.February, 24, 4, 27, 18, 0, time.UTC),
|
||||
Issuer: "CN=ExampleServer",
|
||||
NotAfter: time.Date(2029, time.February, 24, 22, 9, 27, 0, time.UTC),
|
||||
NotBefore: time.Date(2024, time.February, 26, 22, 9, 27, 0, time.UTC),
|
||||
IsValid: true,
|
||||
IsCA: false,
|
||||
},
|
||||
|
||||
@@ -506,7 +506,7 @@ func pods(ctx context.Context, client *kubernetes.Clientset, namespaces []string
|
||||
}
|
||||
|
||||
func getPodDisruptionBudgets(ctx context.Context, client *kubernetes.Clientset, namespaces []string) (map[string][]byte, map[string]string) {
|
||||
ok, err := discovery.HasResource(client, "policy.k8s.io/v1", "PodDisruptionBudgets")
|
||||
ok, err := discovery.HasResource(client, "policy/v1", "PodDisruptionBudgets")
|
||||
if err != nil {
|
||||
return nil, map[string]string{"": err.Error()}
|
||||
}
|
||||
@@ -801,7 +801,7 @@ func jobs(ctx context.Context, client *kubernetes.Clientset, namespaces []string
|
||||
}
|
||||
|
||||
func cronJobs(ctx context.Context, client *kubernetes.Clientset, namespaces []string) (map[string][]byte, map[string]string) {
|
||||
ok, err := discovery.HasResource(client, "batch.k8s.io/v1", "CronJobs")
|
||||
ok, err := discovery.HasResource(client, "batch/v1", "CronJobs")
|
||||
if err != nil {
|
||||
return nil, map[string]string{"": err.Error()}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,8 @@ func GetCollector(collector *troubleshootv1beta2.Collect, bundlePath string, nam
|
||||
return &CollectRun{collector.Run, bundlePath, namespace, clientConfig, client, ctx, RBACErrors}, true
|
||||
case collector.RunPod != nil:
|
||||
return &CollectRunPod{collector.RunPod, bundlePath, namespace, clientConfig, client, ctx, RBACErrors}, true
|
||||
case collector.RunDaemonSet != nil:
|
||||
return &CollectRunDaemonSet{collector.RunDaemonSet, bundlePath, namespace, clientConfig, client, ctx, RBACErrors}, true
|
||||
case collector.Exec != nil:
|
||||
return &CollectExec{collector.Exec, bundlePath, namespace, clientConfig, client, ctx, RBACErrors}, true
|
||||
case collector.Data != nil:
|
||||
@@ -118,6 +120,12 @@ func GetCollector(collector *troubleshootv1beta2.Collect, bundlePath string, nam
|
||||
return &CollectHelm{collector.Helm, bundlePath, namespace, clientConfig, client, ctx, RBACErrors}, true
|
||||
case collector.Goldpinger != nil:
|
||||
return &CollectGoldpinger{collector.Goldpinger, bundlePath, namespace, clientConfig, client, ctx, RBACErrors}, true
|
||||
case collector.Sonobuoy != nil:
|
||||
return &CollectSonobuoyResults{collector.Sonobuoy, bundlePath, namespace, clientConfig, client, ctx, RBACErrors}, true
|
||||
case collector.NodeMetrics != nil:
|
||||
return &CollectNodeMetrics{collector.NodeMetrics, bundlePath, clientConfig, client, ctx, RBACErrors}, true
|
||||
case collector.DNS != nil:
|
||||
return &CollectDNS{collector.DNS, bundlePath, namespace, clientConfig, client, ctx, RBACErrors}, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -152,6 +160,9 @@ func getCollectorName(c interface{}) string {
|
||||
case *CollectRunPod:
|
||||
collector = "run-pod"
|
||||
name = v.Collector.CollectorName
|
||||
case *CollectRunDaemonSet:
|
||||
collector = "run-daemonset"
|
||||
name = v.Collector.CollectorName
|
||||
case *CollectExec:
|
||||
collector = "exec"
|
||||
name = v.Collector.CollectorName
|
||||
@@ -202,6 +213,12 @@ func getCollectorName(c interface{}) string {
|
||||
collector = "helm"
|
||||
case *CollectGoldpinger:
|
||||
collector = "goldpinger"
|
||||
case *CollectSonobuoyResults:
|
||||
collector = "sonobuoy"
|
||||
case *CollectNodeMetrics:
|
||||
collector = "node-metrics"
|
||||
case *CollectDNS:
|
||||
collector = "dns"
|
||||
default:
|
||||
collector = "<none>"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
dnsUtilsImage = "registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3"
|
||||
)
|
||||
|
||||
type CollectDNS struct {
|
||||
Collector *troubleshootv1beta2.DNS
|
||||
BundlePath string
|
||||
Namespace string
|
||||
ClientConfig *rest.Config
|
||||
Client kubernetes.Interface
|
||||
Context context.Context
|
||||
RBACErrors
|
||||
}
|
||||
|
||||
func (c *CollectDNS) Title() string {
|
||||
return getCollectorName(c)
|
||||
}
|
||||
|
||||
func (c *CollectDNS) IsExcluded() (bool, error) {
|
||||
return isExcluded(c.Collector.Exclude)
|
||||
}
|
||||
|
||||
func (c *CollectDNS) Collect(progressChan chan<- interface{}) (CollectorResult, error) {
|
||||
|
||||
ctx, cancel := context.WithTimeout(c.Context, time.Duration(60*time.Second))
|
||||
defer cancel()
|
||||
|
||||
sb := strings.Builder{}
|
||||
|
||||
// get kubernetes Cluster IP
|
||||
clusterIP, err := getKubernetesClusterIP(c.Client, ctx)
|
||||
if err == nil {
|
||||
sb.WriteString(fmt.Sprintf("=== Kubernetes Cluster IP from API Server: %s\n", clusterIP))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("=== Failed to detect Kubernetes Cluster IP: %v\n", err))
|
||||
}
|
||||
|
||||
// run a pod and perform DNS lookup
|
||||
podLog, err := troubleshootDNSFromPod(c.Client, ctx)
|
||||
if err == nil {
|
||||
sb.WriteString(fmt.Sprintf("=== Test DNS resolution in pod %s: \n", dnsUtilsImage))
|
||||
sb.WriteString(podLog)
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("=== Failed to run commands from pod: %v\n", err))
|
||||
}
|
||||
|
||||
// is DNS pods running?
|
||||
sb.WriteString(fmt.Sprintf("=== Running kube-dns pods: %s\n", getRunningKubeDNSPodNames(c.Client, ctx)))
|
||||
|
||||
// is DNS service up?
|
||||
sb.WriteString(fmt.Sprintf("=== Running kube-dns service: %s\n", getKubeDNSServiceClusterIP(c.Client, ctx)))
|
||||
|
||||
// are DNS endpoints exposed?
|
||||
sb.WriteString(fmt.Sprintf("=== kube-dns endpoints: %s\n", getKubeDNSEndpoints(c.Client, ctx)))
|
||||
|
||||
// get DNS server config
|
||||
coreDNSConfig, err := getCoreDNSConfig(c.Client, ctx)
|
||||
if err == nil {
|
||||
sb.WriteString("=== CoreDNS config: \n")
|
||||
sb.WriteString(coreDNSConfig)
|
||||
}
|
||||
kubeDNSConfig, err := getKubeDNSConfig(c.Client, ctx)
|
||||
if err == nil {
|
||||
sb.WriteString("=== KubeDNS config: \n")
|
||||
sb.WriteString(kubeDNSConfig)
|
||||
}
|
||||
|
||||
data := sb.String()
|
||||
output := NewResult()
|
||||
output.SaveResult(c.BundlePath, filepath.Join("dns", c.Collector.CollectorName), bytes.NewBuffer([]byte(data)))
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func getKubernetesClusterIP(client kubernetes.Interface, ctx context.Context) (string, error) {
|
||||
service, err := client.CoreV1().Services("default").Get(ctx, "kubernetes", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
klog.V(2).Infof("Failed to detect Kubernetes Cluster IP: %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return service.Spec.ClusterIP, nil
|
||||
}
|
||||
|
||||
func troubleshootDNSFromPod(client kubernetes.Interface, ctx context.Context) (string, error) {
|
||||
namespace := "default"
|
||||
command := []string{"/bin/sh", "-c", `
|
||||
set -x
|
||||
cat /etc/resolv.conf
|
||||
nslookup -debug kubernetes
|
||||
exit 0
|
||||
`}
|
||||
|
||||
// TODO: image pull secret?
|
||||
podLabels := map[string]string{
|
||||
"troubleshoot-role": "dns-collector",
|
||||
}
|
||||
pod := &corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: "troubleshoot-dns-",
|
||||
Namespace: namespace,
|
||||
Labels: podLabels,
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "troubleshoot-dns",
|
||||
Image: dnsUtilsImage,
|
||||
Command: command,
|
||||
},
|
||||
},
|
||||
RestartPolicy: corev1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
created, err := client.CoreV1().Pods(namespace).Create(ctx, pod, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to run troubleshoot DNS pod")
|
||||
}
|
||||
klog.V(2).Infof("Pod with prefix %s has been created", created.GenerateName)
|
||||
|
||||
defer func() {
|
||||
if created == nil {
|
||||
return
|
||||
}
|
||||
err := client.CoreV1().Pods(namespace).Delete(ctx, created.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to delete troubleshoot DNS pod %s: %v", created.Name, err)
|
||||
}
|
||||
klog.V(2).Infof("Deleted pod %s", created.Name)
|
||||
}()
|
||||
|
||||
// wait for pod to be completed
|
||||
watcher, err := client.CoreV1().Pods(namespace).Watch(ctx, metav1.ListOptions{
|
||||
LabelSelector: "troubleshoot-role=dns-collector",
|
||||
})
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to watch pod")
|
||||
}
|
||||
defer func() {
|
||||
if watcher != nil {
|
||||
watcher.Stop()
|
||||
}
|
||||
}()
|
||||
|
||||
for event := range watcher.ResultChan() {
|
||||
pod, ok := event.Object.(*corev1.Pod)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if pod.Status.Phase == corev1.PodSucceeded {
|
||||
break
|
||||
}
|
||||
if pod.Status.Phase == corev1.PodFailed {
|
||||
return "", errors.New("troubleshoot DNS pod failed")
|
||||
}
|
||||
}
|
||||
|
||||
// get pod logs
|
||||
podLogOpts := corev1.PodLogOptions{}
|
||||
req := client.CoreV1().Pods(namespace).GetLogs(created.Name, &podLogOpts)
|
||||
podLogs, err := req.Stream(ctx)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to get pod logs")
|
||||
}
|
||||
defer podLogs.Close()
|
||||
|
||||
bytes, err := io.ReadAll(podLogs)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to read troubleshoot DNS pod logs")
|
||||
}
|
||||
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
func getCoreDNSConfig(client kubernetes.Interface, ctx context.Context) (string, error) {
|
||||
configMap, err := client.CoreV1().ConfigMaps("kube-system").Get(ctx, "coredns", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
klog.V(2).Infof("Failed to detect CoreDNS config: %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return configMap.Data["Corefile"], nil
|
||||
}
|
||||
|
||||
func getKubeDNSConfig(client kubernetes.Interface, ctx context.Context) (string, error) {
|
||||
configMap, err := client.CoreV1().ConfigMaps("kube-system").Get(ctx, "kube-dns", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
klog.V(2).Infof("Failed to detect KubeDNS config: %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if configMap.Data == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
dataBytes, err := json.Marshal(configMap.Data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(dataBytes), nil
|
||||
}
|
||||
|
||||
func getRunningKubeDNSPodNames(client kubernetes.Interface, ctx context.Context) string {
|
||||
pods, err := client.CoreV1().Pods("kube-system").List(ctx, metav1.ListOptions{
|
||||
LabelSelector: "k8s-app=kube-dns",
|
||||
})
|
||||
if err != nil {
|
||||
klog.V(2).Infof("failed to list kube-dns pods: %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
var podNames []string
|
||||
for _, pod := range pods.Items {
|
||||
if pod.Status.Phase == corev1.PodRunning {
|
||||
podNames = append(podNames, pod.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(podNames, ", ")
|
||||
}
|
||||
|
||||
func getKubeDNSServiceClusterIP(client kubernetes.Interface, ctx context.Context) string {
|
||||
service, err := client.CoreV1().Services("kube-system").Get(ctx, "kube-dns", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
klog.V(2).Infof("failed to get kube-dns service: %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return service.Spec.ClusterIP
|
||||
}
|
||||
|
||||
func getKubeDNSEndpoints(client kubernetes.Interface, ctx context.Context) string {
|
||||
endpoints, err := client.CoreV1().Endpoints("kube-system").Get(ctx, "kube-dns", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
klog.V(2).Infof("failed to get kube-dns endpoints: %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
var endpointStrings []string
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, address := range subset.Addresses {
|
||||
if len(subset.Ports) > 0 {
|
||||
endpointStrings = append(endpointStrings, fmt.Sprintf("%s:%d", address.IP, subset.Ports[0].Port))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(endpointStrings, ", ")
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
func TestGetKubernetesClusterIP(t *testing.T) {
|
||||
k8sSvcIp := "10.0.0.1"
|
||||
client := fake.NewSimpleClientset()
|
||||
service := &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "kubernetes",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
ClusterIP: k8sSvcIp,
|
||||
},
|
||||
}
|
||||
|
||||
// Add the service to the fake clientset
|
||||
_, err := client.CoreV1().Services("default").Create(context.TODO(), service, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("error injecting service into fake clientset: %v", err)
|
||||
}
|
||||
|
||||
// Call the function
|
||||
clusterIP, err := getKubernetesClusterIP(client, context.TODO())
|
||||
if err != nil {
|
||||
t.Fatalf("error getting cluster IP: %v", err)
|
||||
}
|
||||
|
||||
// Check the result
|
||||
if clusterIP != k8sSvcIp {
|
||||
t.Errorf("expected %s, got %s", k8sSvcIp, clusterIP)
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -105,6 +105,9 @@ func helmReleaseHistoryCollector(releaseName string, namespace string, collectVa
|
||||
return nil, []error{err}
|
||||
}
|
||||
versionInfo, err := getVersionInfo(actionConfig, r.Name, r.Namespace, collectValues)
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
results = append(results, ReleaseInfo{
|
||||
ReleaseName: r.Name,
|
||||
Chart: r.Chart.Metadata.Name,
|
||||
@@ -113,7 +116,7 @@ func helmReleaseHistoryCollector(releaseName string, namespace string, collectVa
|
||||
Namespace: r.Namespace,
|
||||
VersionInfo: versionInfo,
|
||||
})
|
||||
return results, []error{err}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// If releaseName is not specified, get the history of all releases
|
||||
|
||||
@@ -24,16 +24,16 @@ func Test_HostCertParser(t *testing.T) {
|
||||
CertificatePath: path,
|
||||
CertificateChain: []ParsedCertificate{
|
||||
{
|
||||
Subject: "CN=envoy",
|
||||
Subject: "CN=ExampleServer",
|
||||
SubjectAlternativeNames: []string{
|
||||
"envoy",
|
||||
"envoy.projectcontour",
|
||||
"envoy.projectcontour.svc",
|
||||
"envoy.projectcontour.svc.cluster.local",
|
||||
"example1",
|
||||
"example2",
|
||||
"example3",
|
||||
"example4",
|
||||
},
|
||||
Issuer: "SERIALNUMBER=615929891,CN=Project Contour",
|
||||
NotAfter: time.Date(2024, time.February, 25, 4, 27, 16, 0, time.UTC),
|
||||
NotBefore: time.Date(2023, time.February, 24, 4, 27, 18, 0, time.UTC),
|
||||
Issuer: "CN=ExampleServer",
|
||||
NotAfter: time.Date(2029, time.February, 24, 22, 9, 27, 0, time.UTC),
|
||||
NotBefore: time.Date(2024, time.February, 26, 22, 9, 27, 0, time.UTC),
|
||||
IsValid: true,
|
||||
IsCA: false,
|
||||
},
|
||||
|
||||
@@ -60,7 +60,7 @@ func isValidLoadBalancerAddress(address string) bool {
|
||||
|
||||
// Check for isValidIP
|
||||
|
||||
test := validation.IsValidIP(hostAddress)
|
||||
test := validation.IsValidIP(nil, hostAddress)
|
||||
return len(test) == 0
|
||||
|
||||
}
|
||||
|
||||
@@ -14,12 +14,14 @@ import (
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
type HTTPResponse struct {
|
||||
Status int `json:"status"`
|
||||
Body string `json:"body"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
RawJSON json.RawMessage `json:"raw_json,omitempty"`
|
||||
}
|
||||
|
||||
type HTTPError struct {
|
||||
@@ -127,10 +129,17 @@ func responseToOutput(response *http.Response, err error) ([]byte, error) {
|
||||
headers[k] = strings.Join(v, ",")
|
||||
}
|
||||
|
||||
var rawJSON json.RawMessage
|
||||
if err := json.Unmarshal(body, &rawJSON); err != nil {
|
||||
klog.Infof("failed to unmarshal response body as JSON: %v", err)
|
||||
rawJSON = json.RawMessage{}
|
||||
}
|
||||
|
||||
output["response"] = HTTPResponse{
|
||||
Status: response.StatusCode,
|
||||
Body: string(body),
|
||||
Headers: headers,
|
||||
RawJSON: rawJSON,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
@@ -376,3 +378,64 @@ func Test_parseTimeout(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_responseToOutput(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
response *http.Response
|
||||
err error
|
||||
want []byte
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid JSON response",
|
||||
response: &http.Response{
|
||||
Body: io.NopCloser(bytes.NewBufferString(`{"ok": false, "error": "invalid_auth"}`)),
|
||||
Header: http.Header{"Content-Type": []string{"application/json; charset=utf-8"}},
|
||||
StatusCode: http.StatusOK,
|
||||
},
|
||||
err: nil,
|
||||
want: []byte(`
|
||||
{
|
||||
"response":
|
||||
{
|
||||
"status":200,
|
||||
"body":"{\"ok\": false, \"error\": \"invalid_auth\"}",
|
||||
"headers":{"Content-Type":"application/json; charset=utf-8"},
|
||||
"raw_json":{"ok":false,"error":"invalid_auth"}
|
||||
}
|
||||
}`),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid JSON response",
|
||||
response: &http.Response{
|
||||
Body: io.NopCloser(bytes.NewBufferString(`foobar`)),
|
||||
Header: http.Header{"Content-Type": []string{"text/html; charset=utf-8"}},
|
||||
StatusCode: http.StatusOK,
|
||||
},
|
||||
err: nil,
|
||||
want: []byte(`
|
||||
{
|
||||
"response":
|
||||
{
|
||||
"status":200,
|
||||
"body":"foobar",
|
||||
"headers":{"Content-Type":"text/html; charset=utf-8"}
|
||||
}
|
||||
}`),
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := responseToOutput(tt.response, tt.err)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(t, string(got), string(tt.want))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
summaryUrlTemplate = "/api/v1/nodes/%s/proxy/stats/summary"
|
||||
)
|
||||
|
||||
type CollectNodeMetrics struct {
|
||||
Collector *troubleshootv1beta2.NodeMetrics
|
||||
BundlePath string
|
||||
ClientConfig *rest.Config
|
||||
Client kubernetes.Interface
|
||||
Context context.Context
|
||||
RBACErrors
|
||||
}
|
||||
|
||||
func (c *CollectNodeMetrics) Title() string {
|
||||
return getCollectorName(c)
|
||||
}
|
||||
|
||||
func (c *CollectNodeMetrics) IsExcluded() (bool, error) {
|
||||
return isExcluded(c.Collector.Exclude)
|
||||
}
|
||||
|
||||
func (c *CollectNodeMetrics) Collect(progressChan chan<- interface{}) (CollectorResult, error) {
|
||||
output := NewResult()
|
||||
nodesMap := c.constructNodesMap()
|
||||
if len(nodesMap) == 0 {
|
||||
klog.V(2).Info("no nodes found to collect metrics for")
|
||||
return output, nil
|
||||
}
|
||||
|
||||
nodeNames := make([]string, 0, len(nodesMap))
|
||||
for nodeName := range nodesMap {
|
||||
nodeNames = append(nodeNames, nodeName)
|
||||
}
|
||||
|
||||
klog.V(2).Infof("collecting node metrics for [%s] nodes", strings.Join(nodeNames, ", "))
|
||||
|
||||
for nodeName, endpoint := range nodesMap {
|
||||
// Equivalent to `kubectl get --raw "/api/v1/nodes/<nodeName>/proxy/stats/summary"`
|
||||
klog.V(2).Infof("querying: %+v\n", endpoint)
|
||||
response, err := c.Client.CoreV1().RESTClient().Get().AbsPath(endpoint).DoRaw(c.Context)
|
||||
if err != nil {
|
||||
return output, errors.Wrapf(err, "could not query endpoint %s", endpoint)
|
||||
}
|
||||
err = output.SaveResult(c.BundlePath, fmt.Sprintf("node-metrics/%s.json", nodeName), bytes.NewBuffer(response))
|
||||
if err != nil {
|
||||
klog.Errorf("failed to save node metrics for %s: %v", nodeName, err)
|
||||
}
|
||||
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (c *CollectNodeMetrics) constructNodesMap() map[string]string {
|
||||
nodesMap := map[string]string{}
|
||||
|
||||
if c.Collector.NodeNames == nil && c.Collector.Selector == nil {
|
||||
// If no node names or selectors are provided, collect all nodes
|
||||
nodes, err := c.Client.CoreV1().Nodes().List(c.Context, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
klog.Errorf("failed to list nodes: %v", err)
|
||||
}
|
||||
for _, node := range nodes.Items {
|
||||
nodesMap[node.Name] = fmt.Sprintf(summaryUrlTemplate, node.Name)
|
||||
}
|
||||
return nodesMap
|
||||
}
|
||||
|
||||
for _, nodeName := range c.Collector.NodeNames {
|
||||
nodesMap[nodeName] = fmt.Sprintf(summaryUrlTemplate, nodeName)
|
||||
}
|
||||
|
||||
// Find nodes by label selector
|
||||
if c.Collector.Selector != nil {
|
||||
nodes, err := c.Client.CoreV1().Nodes().List(c.Context, metav1.ListOptions{
|
||||
LabelSelector: strings.Join(c.Collector.Selector, ","),
|
||||
})
|
||||
if err != nil {
|
||||
klog.Errorf("failed to list nodes by label selector: %v", err)
|
||||
}
|
||||
for _, node := range nodes.Items {
|
||||
nodesMap[node.Name] = fmt.Sprintf(summaryUrlTemplate, node.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nodesMap
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
testclient "k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
func TestCollectNodeMetrics_constructNodesMap(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
objectMetas []metav1.ObjectMeta
|
||||
collector troubleshootv1beta2.NodeMetrics
|
||||
want map[string]string
|
||||
}{
|
||||
{
|
||||
name: "default collector no nodes",
|
||||
want: map[string]string{},
|
||||
},
|
||||
{
|
||||
name: "default collector one node",
|
||||
objectMetas: []metav1.ObjectMeta{
|
||||
{
|
||||
Name: "node1",
|
||||
},
|
||||
},
|
||||
want: map[string]string{
|
||||
"node1": "/api/v1/nodes/node1/proxy/stats/summary",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "collector with node list picking one node",
|
||||
objectMetas: []metav1.ObjectMeta{
|
||||
{
|
||||
Name: "node1",
|
||||
},
|
||||
{
|
||||
Name: "node2",
|
||||
},
|
||||
},
|
||||
collector: troubleshootv1beta2.NodeMetrics{
|
||||
NodeNames: []string{"node2"},
|
||||
},
|
||||
want: map[string]string{
|
||||
"node2": "/api/v1/nodes/node2/proxy/stats/summary",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "collector with selector picking one node",
|
||||
objectMetas: []metav1.ObjectMeta{
|
||||
{
|
||||
Name: "node1",
|
||||
Labels: map[string]string{
|
||||
"hostname": "node1.example.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "node2",
|
||||
},
|
||||
},
|
||||
collector: troubleshootv1beta2.NodeMetrics{
|
||||
Selector: []string{"hostname=node1.example.com"},
|
||||
},
|
||||
want: map[string]string{
|
||||
"node1": "/api/v1/nodes/node1/proxy/stats/summary",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := testclient.NewSimpleClientset()
|
||||
ctx := context.Background()
|
||||
collector := tt.collector
|
||||
c := &CollectNodeMetrics{
|
||||
Collector: &collector,
|
||||
Client: client,
|
||||
Context: ctx,
|
||||
}
|
||||
|
||||
for _, objectMeta := range tt.objectMetas {
|
||||
_, err := client.CoreV1().Nodes().Create(ctx, &v1.Node{
|
||||
ObjectMeta: objectMeta,
|
||||
}, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
got := c.constructNodesMap()
|
||||
assert.Equalf(t, tt.want, got, "constructNodesMap() = %v, want %v", got, tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -71,9 +71,9 @@ func RedactResult(bundlePath string, input CollectorResult, additionalRedactors
|
||||
errorCh <- errors.Wrap(err, "failed to get relative path")
|
||||
return
|
||||
}
|
||||
klog.V(2).Infof("Redacting %s (symlink => %s)\n", file, symlink)
|
||||
klog.V(4).Infof("Redacting %s (symlink => %s)\n", file, symlink)
|
||||
} else {
|
||||
klog.V(2).Infof("Redacting %s\n", file)
|
||||
klog.V(4).Infof("Redacting %s\n", file)
|
||||
}
|
||||
r, err := input.GetReader(bundlePath, file)
|
||||
if err != nil {
|
||||
|
||||
@@ -25,7 +25,7 @@ func NewResult() CollectorResult {
|
||||
// is empty, no symlink is created. The relativeLinkPath is always saved in the result map.
|
||||
func (r CollectorResult) SymLinkResult(bundlePath, relativeLinkPath, relativeFilePath string) error {
|
||||
// We should have saved the result this symlink is pointing to prior to creating it
|
||||
klog.V(2).Info("Creating symlink ", relativeLinkPath, " -> ", relativeFilePath)
|
||||
klog.V(4).Info("Creating symlink ", relativeLinkPath, " -> ", relativeFilePath)
|
||||
data, ok := r[relativeFilePath]
|
||||
if !ok {
|
||||
return errors.Errorf("cannot create symlink, result in %q not found", relativeFilePath)
|
||||
@@ -75,7 +75,7 @@ func (r CollectorResult) SymLinkResult(bundlePath, relativeLinkPath, relativeFil
|
||||
return errors.Wrap(err, "failed to create symlink")
|
||||
}
|
||||
|
||||
klog.V(2).Infof("Added %q symlink of %q in bundle output", relativeLinkPath, relativeFilePath)
|
||||
klog.V(4).Infof("Added %q symlink of %q in bundle output", relativeLinkPath, relativeFilePath)
|
||||
// store the file name referencing the symlink to have archived
|
||||
r[relativeLinkPath] = nil
|
||||
|
||||
@@ -105,7 +105,7 @@ func (r CollectorResult) SaveResult(bundlePath string, relativePath string, read
|
||||
return errors.Wrap(err, "failed to read data")
|
||||
}
|
||||
// Memory only bundle
|
||||
klog.V(2).Infof("Added %q to bundle output", relativePath)
|
||||
klog.V(4).Infof("Added %q to bundle output", relativePath)
|
||||
r[relativePath] = data
|
||||
return nil
|
||||
}
|
||||
@@ -135,7 +135,7 @@ func (r CollectorResult) SaveResult(bundlePath string, relativePath string, read
|
||||
return errors.Wrap(err, "failed to stat file")
|
||||
}
|
||||
|
||||
klog.V(2).Infof("Added %q (%d KB) to bundle output", relativePath, fileInfo.Size()/(1024))
|
||||
klog.V(4).Infof("Added %q (%d KB) to bundle output", relativePath, fileInfo.Size()/(1024))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -340,7 +340,7 @@ func (r CollectorResult) ArchiveSupportBundle(bundlePath string, outputFilename
|
||||
if fileMode.Type() == os.ModeSymlink {
|
||||
// Don't copy the symlink, just write the header which
|
||||
// will create a symlink in the tarball
|
||||
klog.V(2).Infof("Added %q symlink to bundle archive", hdr.Linkname)
|
||||
klog.V(4).Infof("Added %q symlink to bundle archive", hdr.Linkname)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func (r CollectorResult) ArchiveSupportBundle(bundlePath string, outputFilename
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to copy file into archive")
|
||||
}
|
||||
klog.V(2).Infof("Added %q file to bundle archive", hdr.Name)
|
||||
klog.V(4).Infof("Added %q file to bundle archive", hdr.Name)
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTimeout = time.Duration(60 * time.Second)
|
||||
)
|
||||
|
||||
type CollectRunDaemonSet struct {
|
||||
Collector *troubleshootv1beta2.RunDaemonSet
|
||||
BundlePath string
|
||||
Namespace string
|
||||
ClientConfig *rest.Config
|
||||
Client kubernetes.Interface
|
||||
Context context.Context
|
||||
RBACErrors
|
||||
}
|
||||
|
||||
func (c *CollectRunDaemonSet) Title() string {
|
||||
return getCollectorName(c)
|
||||
}
|
||||
|
||||
func (c *CollectRunDaemonSet) IsExcluded() (bool, error) {
|
||||
return isExcluded(c.Collector.Exclude)
|
||||
}
|
||||
|
||||
func (c *CollectRunDaemonSet) Collect(progressChan chan<- interface{}) (CollectorResult, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := kubernetes.NewForConfig(c.ClientConfig)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create client from config")
|
||||
}
|
||||
|
||||
// create DaemonSet Spec
|
||||
dsSpec, err := createDaemonSetSpec(c.Collector)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create DaemonSet spec")
|
||||
}
|
||||
|
||||
// create ImagePullSecret
|
||||
var secretName string
|
||||
if c.Collector.ImagePullSecret != nil && c.Collector.ImagePullSecret.Data != nil {
|
||||
secretName, err = createSecret(ctx, client, dsSpec.ObjectMeta.Namespace, c.Collector.ImagePullSecret)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create ImagePullSecret")
|
||||
}
|
||||
dsSpec.Spec.Template.Spec.ImagePullSecrets = append(dsSpec.Spec.Template.Spec.ImagePullSecrets, corev1.LocalObjectReference{Name: secretName})
|
||||
}
|
||||
|
||||
// run DaemonSet
|
||||
ds, err := client.AppsV1().DaemonSets(dsSpec.ObjectMeta.Namespace).Create(ctx, dsSpec, metav1.CreateOptions{})
|
||||
klog.V(2).Infof("DaemonSet %s has been created", ds.Name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create DaemonSet")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// delete DaemonSet
|
||||
err := client.AppsV1().DaemonSets(ds.ObjectMeta.Namespace).Delete(ctx, ds.ObjectMeta.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to delete DaemonSet %s: %v", ds.Name, err)
|
||||
}
|
||||
// delete ImagePullSecret
|
||||
if secretName != "" {
|
||||
err := client.CoreV1().Secrets(ds.ObjectMeta.Namespace).Delete(ctx, secretName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to delete Secret %s: %v", secretName, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// set custom timeout if any
|
||||
var (
|
||||
timeout time.Duration
|
||||
errInvalidDuration error
|
||||
)
|
||||
if c.Collector.Timeout != "" {
|
||||
timeout, errInvalidDuration = time.ParseDuration(c.Collector.Timeout)
|
||||
if errInvalidDuration != nil {
|
||||
return nil, errors.Wrapf(errInvalidDuration, "failed to parse timeout %q", c.Collector.Timeout)
|
||||
}
|
||||
}
|
||||
if timeout <= time.Duration(0) {
|
||||
timeout = defaultTimeout
|
||||
}
|
||||
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
// block till DaemonSet has right number of scheduled Pods
|
||||
err = waitForDaemonSetPods(timeoutCtx, client, ds)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to wait for DaemonSet pods")
|
||||
}
|
||||
klog.V(2).Infof("DaemonSet %s has desired number of pods", ds.Name)
|
||||
|
||||
// get all Pods in DaemonSet
|
||||
pods, err := client.CoreV1().Pods(ds.ObjectMeta.Namespace).List(ctx, metav1.ListOptions{
|
||||
LabelSelector: getLabelSelector(ds),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to list pods")
|
||||
}
|
||||
|
||||
results := NewResult()
|
||||
|
||||
// collect logs from all Pods
|
||||
// or save error message if failed to get logs
|
||||
wg := &sync.WaitGroup{}
|
||||
mtx := &sync.Mutex{}
|
||||
for _, pod := range pods.Items {
|
||||
wg.Add(1)
|
||||
go func(pod corev1.Pod) {
|
||||
defer wg.Done()
|
||||
|
||||
select {
|
||||
case <-timeoutCtx.Done():
|
||||
klog.Errorf("Timeout reached while waiting for pod %s", pod.Name)
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
var logs []byte
|
||||
|
||||
nodeName, err := getPodNodeAtCompletion(timeoutCtx, client.CoreV1(), pod)
|
||||
if err != nil {
|
||||
nodeName = fmt.Sprintf("unknown-node-%s", pod.Name)
|
||||
errString := fmt.Sprintf("Failed to get node name/wait for pod %s to complete: %v", pod.Name, err)
|
||||
klog.Error(errString)
|
||||
logs = []byte(errString)
|
||||
} else {
|
||||
logs, err = getPodLog(timeoutCtx, client.CoreV1(), pod)
|
||||
if err != nil {
|
||||
errString := fmt.Sprintf("Failed to get log from pod %s: %v", pod.Name, err)
|
||||
klog.Error(errString)
|
||||
logs = []byte(errString)
|
||||
}
|
||||
}
|
||||
|
||||
mtx.Lock()
|
||||
defer mtx.Unlock()
|
||||
results[nodeName] = logs
|
||||
klog.V(2).Infof("Collected logs for pod %s", pod.Name)
|
||||
|
||||
}(pod)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
output := NewResult()
|
||||
for k, v := range results {
|
||||
filename := k + ".log"
|
||||
err := output.SaveResult(c.BundlePath, filepath.Join(c.Collector.Name, filename), bytes.NewBuffer(v))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return output, nil
|
||||
|
||||
}
|
||||
|
||||
func createDaemonSetSpec(c *troubleshootv1beta2.RunDaemonSet) (*appsv1.DaemonSet, error) {
|
||||
ds := &appsv1.DaemonSet{}
|
||||
|
||||
labels := make(map[string]string)
|
||||
labels["troubleshoot-role"] = "run-daemonset-collector"
|
||||
|
||||
namespace := "default"
|
||||
if c.Namespace != "" {
|
||||
namespace = c.Namespace
|
||||
}
|
||||
ds.ObjectMeta = metav1.ObjectMeta{
|
||||
GenerateName: fmt.Sprintf("run-daemonset-%s-", c.Name),
|
||||
Namespace: namespace,
|
||||
Labels: labels,
|
||||
}
|
||||
|
||||
ds.Spec = appsv1.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: labels,
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: c.PodSpec,
|
||||
},
|
||||
}
|
||||
|
||||
return ds, nil
|
||||
}
|
||||
|
||||
func getLabelSelector(ds *appsv1.DaemonSet) string {
|
||||
labelSelector := ""
|
||||
for k, v := range ds.Spec.Template.ObjectMeta.Labels {
|
||||
labelSelector += k + "=" + v + ","
|
||||
}
|
||||
return strings.TrimSuffix(labelSelector, ",")
|
||||
}
|
||||
|
||||
func getPodLog(ctx context.Context, client v1.CoreV1Interface, pod corev1.Pod) ([]byte, error) {
|
||||
podLogOpts := corev1.PodLogOptions{
|
||||
Container: pod.Spec.Containers[0].Name,
|
||||
}
|
||||
req := client.Pods(pod.Namespace).GetLogs(pod.Name, &podLogOpts)
|
||||
logs, err := req.Stream(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get log stream")
|
||||
}
|
||||
defer logs.Close()
|
||||
|
||||
return io.ReadAll(logs)
|
||||
}
|
||||
|
||||
// getPodNodeAtCompletion waits for the Pod to complete and returns the node name
|
||||
func getPodNodeAtCompletion(ctx context.Context, client v1.CoreV1Interface, pod corev1.Pod) (string, error) {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return "", ctx.Err()
|
||||
case <-ticker.C:
|
||||
pod, err := client.Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to get pod")
|
||||
}
|
||||
|
||||
if pod.Status.Phase == corev1.PodFailed || pod.Status.Phase == corev1.PodSucceeded {
|
||||
return pod.Spec.NodeName, nil
|
||||
}
|
||||
|
||||
// we assume a container restart means the Pod has completed before
|
||||
if len(pod.Status.ContainerStatuses) > 0 && pod.Status.ContainerStatuses[0].RestartCount > 0 {
|
||||
return pod.Spec.NodeName, nil
|
||||
}
|
||||
|
||||
if pod.Status.Phase == corev1.PodPending {
|
||||
for _, v := range pod.Status.ContainerStatuses {
|
||||
if v.State.Waiting != nil && v.State.Waiting.Reason == "ImagePullBackOff" {
|
||||
return "", errors.New("wait for pod aborted after getting pod status 'ImagePullBackOff'")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// waitForDaemonSetPods waits for the DaemonSet to have the desired number of pods scheduled
|
||||
func waitForDaemonSetPods(ctx context.Context, client kubernetes.Interface, ds *appsv1.DaemonSet) error {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-ticker.C:
|
||||
ds, err := client.AppsV1().DaemonSets(ds.ObjectMeta.Namespace).Get(ctx, ds.ObjectMeta.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get DaemonSet")
|
||||
}
|
||||
|
||||
// we return as soon as the desired number of pods are scheduled
|
||||
if ds.Status.DesiredNumberScheduled == ds.Status.CurrentNumberScheduled {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
func TestWaitForDaemonSetPods(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
client := fake.NewSimpleClientset()
|
||||
|
||||
ds := &appsv1.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
Name: "connectivity",
|
||||
},
|
||||
Status: appsv1.DaemonSetStatus{
|
||||
DesiredNumberScheduled: 2,
|
||||
CurrentNumberScheduled: 2,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := client.AppsV1().DaemonSets("default").Create(ctx, ds, metav1.CreateOptions{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = waitForDaemonSetPods(ctx, client, ds)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
func TestGetPodNodeAtCompletion(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
client := fake.NewSimpleClientset()
|
||||
|
||||
pod := corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
Name: "test-pod",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
NodeName: "foo-node",
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "connectivity",
|
||||
Image: "curlimages/curl",
|
||||
Args: []string{"-IsL", "https://docs.replicated.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: corev1.PodStatus{
|
||||
Phase: corev1.PodSucceeded,
|
||||
ContainerStatuses: []corev1.ContainerStatus{
|
||||
{
|
||||
Name: "connectivity",
|
||||
RestartCount: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err := client.CoreV1().Pods("default").Create(ctx, &pod, metav1.CreateOptions{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
nodeName, err := getPodNodeAtCompletion(ctx, client.CoreV1(), pod)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "foo-node", nodeName)
|
||||
}
|
||||
@@ -72,6 +72,9 @@ func (c *CollectRunPod) Collect(progressChan chan<- interface{}) (result Collect
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
result, err = savePodDetails(ctx, client, result, c.BundlePath, c.ClientConfig, pod, c.Collector)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to save pod details: %v", err)
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultSonobuoyNamespace = "sonobuoy"
|
||||
DefaultSonobuoyAggregatorPodName = "sonobuoy"
|
||||
DefaultSonobuoyAggregatorContainerName = "kube-sonobuoy"
|
||||
DefaultSonobuoyAggregatorResultsPath = "/tmp/sonobuoy"
|
||||
)
|
||||
|
||||
type CollectSonobuoyResults struct {
|
||||
Collector *troubleshootv1beta2.Sonobuoy
|
||||
BundlePath string
|
||||
Namespace string // this is not used
|
||||
ClientConfig *rest.Config
|
||||
Client kubernetes.Interface
|
||||
Context context.Context
|
||||
RBACErrors
|
||||
}
|
||||
|
||||
func (c *CollectSonobuoyResults) Title() string {
|
||||
return getCollectorName(c)
|
||||
}
|
||||
|
||||
func (c *CollectSonobuoyResults) IsExcluded() (bool, error) {
|
||||
return isExcluded(c.Collector.Exclude)
|
||||
}
|
||||
|
||||
func (c *CollectSonobuoyResults) Collect(progressChan chan<- interface{}) (CollectorResult, error) {
|
||||
namespace := DefaultSonobuoyNamespace
|
||||
if c.Collector.Namespace != "" {
|
||||
namespace = c.Collector.Namespace
|
||||
}
|
||||
|
||||
podName := DefaultSonobuoyAggregatorPodName
|
||||
resultsPath := DefaultSonobuoyAggregatorResultsPath
|
||||
containerName := DefaultSonobuoyAggregatorContainerName
|
||||
|
||||
_, err := c.Client.CoreV1().Pods(namespace).Get(c.Context, podName, metav1.GetOptions{})
|
||||
if kerrors.IsNotFound(err) {
|
||||
return nil, fmt.Errorf("sonobuoy pod %s in namespace %s not found", podName, namespace)
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("failed to get sonobuoy pod %s in namespace %s: %v", podName, namespace, err)
|
||||
}
|
||||
|
||||
reader, ec, err := sonobuoyRetrieveResults(c.Context, c.Client, c.ClientConfig, namespace, podName, containerName, resultsPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve sonobuoy results: %v", err)
|
||||
}
|
||||
|
||||
output := NewResult()
|
||||
|
||||
ec2 := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
defer close(ec2)
|
||||
|
||||
gz, err := gzip.NewReader(reader)
|
||||
if err != nil {
|
||||
ec2 <- errors.Wrap(err, "failed to create gzip reader")
|
||||
return
|
||||
}
|
||||
defer gz.Close()
|
||||
|
||||
tr := tar.NewReader(gz)
|
||||
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
return
|
||||
} else if err != nil {
|
||||
ec2 <- errors.Wrap(err, "failed to read tar header")
|
||||
return
|
||||
}
|
||||
if header.Typeflag != tar.TypeReg {
|
||||
continue
|
||||
}
|
||||
filename := filepath.Clean(header.Name) // sanitize the filename
|
||||
klog.V(2).Infof("Sonobuoy collector found file: %s", filename)
|
||||
err = output.SaveResult(c.BundlePath, filepath.Join("sonobuoy", filename), tr)
|
||||
if err != nil {
|
||||
ec2 <- errors.Wrapf(err, "failed to save result for %s", filename)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = <-ec2
|
||||
if err != nil {
|
||||
_, _ = io.Copy(io.Discard, reader) // ensure the stream is closed
|
||||
return nil, fmt.Errorf("failed to write sonobuoy results: %v", err)
|
||||
}
|
||||
|
||||
err = <-ec
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve sonobuoy results: %v", err)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// sonobuoyRetrieveResults copies results from a sonobuoy run into a Reader in tar format.
|
||||
// It also returns a channel of errors, where any errors encountered when writing results
|
||||
// will be sent, and an error in the case where the config validation fails.
|
||||
func sonobuoyRetrieveResults(
|
||||
ctx context.Context, client kubernetes.Interface, restConfig *rest.Config, namespace, podName, containerName, path string,
|
||||
) (io.Reader, <-chan error, error) {
|
||||
ec := make(chan error, 1)
|
||||
|
||||
cmd := sonobuoyTarCmd(path)
|
||||
|
||||
klog.V(2).Infof(
|
||||
"Sonobuoy collector runing command: kubectl exec -n %s %s -c %s -- %s",
|
||||
namespace, podName, containerName, strings.Join(cmd, " "),
|
||||
)
|
||||
restClient := client.CoreV1().RESTClient()
|
||||
req := restClient.Post().
|
||||
Resource("pods").
|
||||
Name(podName).
|
||||
Namespace(namespace).
|
||||
SubResource("exec").
|
||||
Param("container", containerName)
|
||||
req.VersionedParams(&corev1.PodExecOptions{
|
||||
Container: containerName,
|
||||
Command: cmd,
|
||||
Stdin: false,
|
||||
Stdout: true,
|
||||
Stderr: false,
|
||||
}, scheme.ParameterCodec)
|
||||
executor, err := remotecommand.NewSPDYExecutor(restConfig, "POST", req.URL())
|
||||
if err != nil {
|
||||
return nil, ec, err
|
||||
}
|
||||
reader, writer := io.Pipe()
|
||||
go func(writer *io.PipeWriter, ec chan error) {
|
||||
defer writer.Close()
|
||||
defer close(ec)
|
||||
err = executor.StreamWithContext(ctx, remotecommand.StreamOptions{
|
||||
Stdout: writer,
|
||||
Tty: false,
|
||||
})
|
||||
if err != nil {
|
||||
ec <- err
|
||||
}
|
||||
}(writer, ec)
|
||||
|
||||
return reader, ec, nil
|
||||
}
|
||||
|
||||
func sonobuoyTarCmd(path string) []string {
|
||||
return []string{
|
||||
"/sonobuoy",
|
||||
"splat",
|
||||
path,
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,7 @@ const (
|
||||
|
||||
// Troubleshoot spec constants
|
||||
Troubleshootv1beta2Kind = "troubleshoot.sh/v1beta2"
|
||||
Troubleshootv1beta1Kind = "troubleshoot.replicated.com/v1beta1"
|
||||
|
||||
// TermUI Display Constants
|
||||
MESSAGE_TEXT_PADDING = 4
|
||||
|
||||
@@ -196,7 +196,7 @@ func (l *specLoader) loadFromStrings(rawSpecs ...string) (*TroubleshootKinds, er
|
||||
default:
|
||||
return nil, types.NewExitCodeError(constants.EXIT_CODE_SPEC_ISSUES, errors.Errorf("%T type is not a Secret or ConfigMap", v))
|
||||
}
|
||||
} else if parsed.APIVersion == constants.Troubleshootv1beta2Kind {
|
||||
} else if parsed.APIVersion == constants.Troubleshootv1beta2Kind || parsed.APIVersion == constants.Troubleshootv1beta1Kind {
|
||||
// If it's not a configmap or secret, just append it to the splitdocs
|
||||
splitdocs = append(splitdocs, rawDoc)
|
||||
} else {
|
||||
|
||||
@@ -371,6 +371,38 @@ func TestLoadingMultidocsWithTroubleshootSpecs(t *testing.T) {
|
||||
}, kinds.SupportBundlesV1Beta2)
|
||||
}
|
||||
|
||||
func TestLoadingV1Beta1CollectorSpec(t *testing.T) {
|
||||
kinds, err := LoadSpecs(context.Background(), LoadOptions{RawSpec: `kind: Collector
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
metadata:
|
||||
name: collector-sample
|
||||
spec:
|
||||
collectors:
|
||||
- clusterInfo: {}
|
||||
`})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, kinds)
|
||||
|
||||
assert.Equal(t, []troubleshootv1beta2.Collector{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Collector",
|
||||
APIVersion: "troubleshoot.sh/v1beta2",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "collector-sample",
|
||||
},
|
||||
Spec: troubleshootv1beta2.CollectorSpec{
|
||||
Collectors: []*troubleshootv1beta2.Collect{
|
||||
{
|
||||
ClusterInfo: &troubleshootv1beta2.ClusterInfo{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, kinds.CollectorsV1Beta2)
|
||||
}
|
||||
|
||||
func TestLoadingConfigMapWithMultipleSpecs_PreflightSupportBundleAndRedactorDataKeys(t *testing.T) {
|
||||
s := testutils.GetTestFixture(t, "yamldocs/multidoc-spec-2.yaml")
|
||||
l := specLoader{}
|
||||
|
||||
+11
-11
@@ -2,7 +2,7 @@ package preflight
|
||||
|
||||
import (
|
||||
flag "github.com/spf13/pflag"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
utilpointer "k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -35,16 +35,16 @@ var preflightFlags *PreflightFlags
|
||||
|
||||
func NewPreflightFlags() *PreflightFlags {
|
||||
return &PreflightFlags{
|
||||
Interactive: utilpointer.Bool(true),
|
||||
Format: utilpointer.String("human"),
|
||||
CollectorImage: utilpointer.String(""),
|
||||
CollectorPullPolicy: utilpointer.String(""),
|
||||
CollectWithoutPermissions: utilpointer.Bool(true),
|
||||
Selector: utilpointer.String(""),
|
||||
SinceTime: utilpointer.String(""),
|
||||
Since: utilpointer.String(""),
|
||||
Output: utilpointer.String("o"),
|
||||
Debug: utilpointer.Bool(false),
|
||||
Interactive: utilpointer.To(true),
|
||||
Format: utilpointer.To("human"),
|
||||
CollectorImage: utilpointer.To(""),
|
||||
CollectorPullPolicy: utilpointer.To(""),
|
||||
CollectWithoutPermissions: utilpointer.To(true),
|
||||
Selector: utilpointer.To(""),
|
||||
SinceTime: utilpointer.To(""),
|
||||
Since: utilpointer.To(""),
|
||||
Output: utilpointer.To("o"),
|
||||
Debug: utilpointer.To(false),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
cursor "github.com/ahmetalpbalkan/go-cursor"
|
||||
"github.com/fatih/color"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/replicatedhq/troubleshoot/internal/util"
|
||||
analyzer "github.com/replicatedhq/troubleshoot/pkg/analyze"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/constants"
|
||||
@@ -46,6 +47,17 @@ func RunPreflights(interactive bool, output string, format string, args []string
|
||||
return types.NewExitCodeError(constants.EXIT_CODE_SPEC_ISSUES, err)
|
||||
}
|
||||
|
||||
if interactive {
|
||||
if len(specs.HostPreflightsV1Beta2) > 0 && !util.IsRunningAsRoot() {
|
||||
fmt.Print(cursor.Show())
|
||||
if util.PromptYesNo(util.HOST_COLLECTORS_RUN_AS_ROOT_PROMPT) {
|
||||
fmt.Println("Exiting...")
|
||||
return nil
|
||||
}
|
||||
fmt.Print(cursor.Hide())
|
||||
}
|
||||
}
|
||||
|
||||
warning := validatePreflight(specs)
|
||||
if warning != nil {
|
||||
fmt.Println(warning.Warning())
|
||||
|
||||
@@ -456,7 +456,7 @@ func getRedactors(path string) ([]Redactor, error) {
|
||||
|
||||
uniqueCRs := map[string]bool{}
|
||||
for _, cr := range customResources {
|
||||
fileglob := fmt.Sprintf("%s/%s/%s/*", constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_CUSTOM_RESOURCES, cr.resource)
|
||||
fileglob := fmt.Sprintf("%s/%s/%s/*.yaml", constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_CUSTOM_RESOURCES, cr.resource)
|
||||
redactors = append(redactors, NewYamlRedactor(cr.yamlPath, fileglob, ""))
|
||||
|
||||
// redact kubectl last applied annotation once for each resource since it contains copies of
|
||||
|
||||
+1
-4
@@ -4,7 +4,6 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -50,7 +49,7 @@ func (r *YamlRedactor) Redact(input io.Reader, path string) io.Reader {
|
||||
reader := bufio.NewReader(input)
|
||||
|
||||
var doc []byte
|
||||
doc, err = ioutil.ReadAll(reader)
|
||||
doc, err = io.ReadAll(reader)
|
||||
var yamlInterface interface{}
|
||||
err = yaml.Unmarshal(doc, &yamlInterface)
|
||||
if err != nil {
|
||||
@@ -84,8 +83,6 @@ func (r *YamlRedactor) Redact(input io.Reader, path string) io.Reader {
|
||||
File: path,
|
||||
IsDefaultRedactor: r.isDefault,
|
||||
})
|
||||
|
||||
return
|
||||
}()
|
||||
return reader
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
@@ -824,6 +824,96 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"event": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"collectorName",
|
||||
"outcomes",
|
||||
"reason"
|
||||
],
|
||||
"properties": {
|
||||
"annotations": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"checkName": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectorName": {
|
||||
"type": "string"
|
||||
},
|
||||
"exclude": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fail": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"when": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pass": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"when": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"when": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"regex": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"goldpinger": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -1475,6 +1565,99 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"nodeMetrics": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"collectorName",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
"annotations": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"checkName": {
|
||||
"type": "string"
|
||||
},
|
||||
"collectorName": {
|
||||
"type": "string"
|
||||
},
|
||||
"exclude": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
},
|
||||
"filters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pvc": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"nameRegex": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fail": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"when": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pass": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"when": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"warn": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"when": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"nodeResources": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
@@ -214,7 +214,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.",
|
||||
"description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
@@ -245,7 +245,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.",
|
||||
"description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
@@ -273,7 +273,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.",
|
||||
"description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,11 +3,11 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
@@ -1255,7 +1255,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.",
|
||||
"description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
@@ -1286,7 +1286,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.",
|
||||
"description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
@@ -1314,7 +1314,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.",
|
||||
"description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,11 +3,11 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
@@ -1301,7 +1301,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.",
|
||||
"description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
@@ -1332,7 +1332,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.",
|
||||
"description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
@@ -1360,7 +1360,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.",
|
||||
"description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,11 +10,16 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/replicatedhq/troubleshoot/internal/testutils"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/convert"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/e2e-framework/klient/k8s/resources"
|
||||
"sigs.k8s.io/e2e-framework/klient/wait"
|
||||
"sigs.k8s.io/e2e-framework/klient/wait/conditions"
|
||||
"sigs.k8s.io/e2e-framework/pkg/envconf"
|
||||
"sigs.k8s.io/e2e-framework/pkg/features"
|
||||
"sigs.k8s.io/e2e-framework/third_party/helm"
|
||||
@@ -27,6 +32,10 @@ metadata:
|
||||
name: goldpinger
|
||||
spec:
|
||||
collectors:
|
||||
- clusterResources:
|
||||
exclude: true
|
||||
- clusterInfo:
|
||||
exclude: true
|
||||
- goldpinger:
|
||||
namespace: $NAMESPACE
|
||||
analyzers:
|
||||
@@ -45,7 +54,23 @@ func Test_GoldpingerCollector(t *testing.T) {
|
||||
helm.WithNamespace(c.Namespace()),
|
||||
helm.WithChart(testutils.TestFixtureFilePath(t, "charts/goldpinger-6.0.1.tgz")),
|
||||
helm.WithWait(),
|
||||
helm.WithTimeout("1m"),
|
||||
helm.WithTimeout("2m"),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
client, err := c.NewClient()
|
||||
require.NoError(t, err)
|
||||
pods := &v1.PodList{}
|
||||
|
||||
// Lets wait for the goldpinger pods to be running
|
||||
err = client.Resources().WithNamespace(c.Namespace()).List(ctx, pods,
|
||||
resources.WithLabelSelector("app.kubernetes.io/name=goldpinger"),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, pods.Items, 1)
|
||||
|
||||
err = wait.For(
|
||||
conditions.New(client.Resources()).PodRunning(&pods.Items[0]),
|
||||
wait.WithTimeout(time.Second*30),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
return ctx
|
||||
@@ -81,12 +106,16 @@ func Test_GoldpingerCollector(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check that we analysed collected goldpinger results.
|
||||
// There won't be any ping results because goldpinger would not have run yet.
|
||||
// The test is fine since this checks that we query the goldpinger results correctly
|
||||
// and the analyser is working.
|
||||
require.Equal(t, 1, len(analysisResults))
|
||||
// We should expect a single analysis result for goldpinger.
|
||||
assert.Equal(t, 1, len(analysisResults))
|
||||
assert.True(t, strings.HasPrefix(analysisResults[0].Name, "missing.ping.results.for.goldpinger."))
|
||||
assert.Equal(t, convert.SeverityWarn, analysisResults[0].Severity)
|
||||
if t.Failed() {
|
||||
t.Logf("Analysis results: %s\n", analysisJSON)
|
||||
t.Logf("Stdout: %s\n", out.String())
|
||||
t.Logf("Stderr: %s\n", stdErr.String())
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
return ctx
|
||||
}).
|
||||
Teardown(func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/e2e-framework/pkg/env"
|
||||
"sigs.k8s.io/e2e-framework/pkg/envconf"
|
||||
"sigs.k8s.io/e2e-framework/pkg/envfuncs"
|
||||
@@ -23,6 +25,12 @@ var testenv env.Environment
|
||||
const ClusterName = "kind-cluster"
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// enable klog
|
||||
klog.InitFlags(nil)
|
||||
if os.Getenv("E2E_VERBOSE") == "1" {
|
||||
_ = flag.Set("v", "10")
|
||||
}
|
||||
|
||||
testenv = env.New()
|
||||
namespace := envconf.RandomName("default", 16)
|
||||
testenv.Setup(
|
||||
@@ -37,13 +45,13 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
|
||||
func getClusterFromContext(t *testing.T, ctx context.Context, clusterName string) *kind.Cluster {
|
||||
provider, ok := envfuncs.GetClusterFromContext(ctx, ClusterName)
|
||||
provider, ok := envfuncs.GetClusterFromContext(ctx, clusterName)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to extract kind cluster %s from context", ClusterName)
|
||||
t.Fatalf("Failed to extract kind cluster %s from context", clusterName)
|
||||
}
|
||||
cluster, ok := provider.(*kind.Cluster)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to cast kind cluster %s from provider", ClusterName)
|
||||
t.Fatalf("Failed to cast kind cluster %s from provider", clusterName)
|
||||
}
|
||||
|
||||
return cluster
|
||||
@@ -77,7 +85,10 @@ func readFilesAndFoldersFromTar(tarPath, targetFolder string) ([]string, []strin
|
||||
}
|
||||
|
||||
if strings.HasPrefix(header.Name, targetFolder) {
|
||||
relativePath := strings.TrimPrefix(header.Name, targetFolder)
|
||||
relativePath, err := filepath.Rel(targetFolder, header.Name)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Error getting relative path: %w", err)
|
||||
}
|
||||
if relativePath != "" {
|
||||
relativeDir := filepath.Dir(relativePath)
|
||||
if relativeDir != "." {
|
||||
@@ -132,4 +143,4 @@ func readFileFromTar(tarPath, targetFile string) ([]byte, error) {
|
||||
|
||||
func sbBinary() string {
|
||||
return "../../../bin/support-bundle"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"sigs.k8s.io/e2e-framework/pkg/envconf"
|
||||
"sigs.k8s.io/e2e-framework/pkg/features"
|
||||
)
|
||||
|
||||
type sonobuoyContextKey string
|
||||
|
||||
func Test_SonobuoyCollector(t *testing.T) {
|
||||
|
||||
feature := features.New("Collector Sonobuoy Results").
|
||||
Setup(func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context {
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
cluster := getClusterFromContext(t, ctx, ClusterName)
|
||||
|
||||
// download sonobuoy
|
||||
resp, err := http.Get(fmt.Sprintf(
|
||||
"https://github.com/vmware-tanzu/sonobuoy/releases/download/v0.57.1/sonobuoy_0.57.1_%s_%s.tar.gz",
|
||||
runtime.GOOS, runtime.GOARCH,
|
||||
))
|
||||
require.NoError(t, err, "failed to download sonobuoy")
|
||||
defer resp.Body.Close()
|
||||
f, err := os.Create(filepath.Join(tmpdir, "sonobuoy.tar.gz"))
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
_, err = io.Copy(f, resp.Body)
|
||||
require.NoError(t, err)
|
||||
err = exec.Command("tar", "-xvf", filepath.Join(tmpdir, "sonobuoy.tar.gz"), "-C", tmpdir).Run()
|
||||
require.NoError(t, err, "failed to extract sonobuoy.tar.gz")
|
||||
sonobuoy := filepath.Join(tmpdir, "sonobuoy")
|
||||
ctx = context.WithValue(ctx, sonobuoyContextKey("sonobuoy"), sonobuoy)
|
||||
|
||||
// run sonobuoy
|
||||
_ = exec.Command(sonobuoy, "delete", "--kubeconfig", cluster.GetKubeconfig(), "--wait").Run()
|
||||
out, err := exec.Command(sonobuoy, "run", "--kubeconfig", cluster.GetKubeconfig(), "--mode", "quick", "--wait").CombinedOutput()
|
||||
require.NoError(t, err, "failed to run sonobuoy: %s", string(out))
|
||||
|
||||
return ctx
|
||||
}).
|
||||
Assess("check support bundle catch helm release", func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context {
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
tarPath := filepath.Join(tmpdir, "bundle.tar.gz")
|
||||
targetFolder := "bundle/sonobuoy"
|
||||
// 202402130428_sonobuoy_92a8ac6c-b5ed-4af5-bfc6-8bb454ceb0f0.tar.gz
|
||||
targetFileMatch := regexp.MustCompile(".*_sonobuoy_.*.tar.gz")
|
||||
|
||||
cmd := exec.CommandContext(ctx, sbBinary(), "spec/sonobuoy.yaml", "--interactive=false", fmt.Sprintf("-o=%s", tarPath))
|
||||
out, err := cmd.CombinedOutput()
|
||||
t.Log(string(out))
|
||||
require.NoError(t, err, "failed to run support-bundle")
|
||||
|
||||
// validate the tarball
|
||||
files, _, err := readFilesAndFoldersFromTar(tarPath, targetFolder)
|
||||
require.NoError(t, err, "failed to read files and folders from tarball")
|
||||
|
||||
found := false
|
||||
for _, file := range files {
|
||||
if targetFileMatch.MatchString(file) {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
require.True(t, found, "sonobuoy tarball not found in support bundle")
|
||||
|
||||
return ctx
|
||||
}).
|
||||
Teardown(func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context {
|
||||
sonobuoy := ctx.Value(sonobuoyContextKey("sonobuoy")).(string)
|
||||
|
||||
cluster := getClusterFromContext(t, ctx, ClusterName)
|
||||
|
||||
out, err := exec.Command(sonobuoy, "delete", "--kubeconfig", cluster.GetKubeconfig(), "--wait").CombinedOutput()
|
||||
if err != nil {
|
||||
t.Logf("Error deleting sonobuoy: %s", string(out))
|
||||
}
|
||||
|
||||
return ctx
|
||||
}).
|
||||
Feature()
|
||||
testenv.Test(t, feature)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
name: sonobuoy
|
||||
spec:
|
||||
collectors:
|
||||
- sonobuoy: {}
|
||||
Reference in New Issue
Block a user