mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-09-03 00:47:17 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e74fd209e | ||
|
|
a00a1892d9 | ||
|
|
474a874f82 | ||
|
|
463ba62ffa | ||
|
|
46194fccb7 | ||
|
|
badedf34ee | ||
|
|
af2f49cb07 | ||
|
|
88a6d3f715 | ||
|
|
5a1321da02 | ||
|
|
014a716949 | ||
|
|
ad4893bec5 | ||
|
|
989093394c | ||
|
|
f1868d0ba8 | ||
|
|
3cbdb41c8f | ||
|
|
d2f6594c0c | ||
|
|
56408fab01 | ||
|
|
f0d9418e21 | ||
|
|
1ba3840ad9 | ||
|
|
a3d667298e | ||
|
|
5cf4ae2157 | ||
|
|
dede187841 | ||
|
|
7dc6e22d8d | ||
|
|
f3af73b6e3 | ||
|
|
4e047b2372 | ||
|
|
7f190e3cce | ||
|
|
2436a0c163 | ||
|
|
883abacaf8 | ||
|
|
7186b75f7e | ||
|
|
e16eabd531 | ||
|
|
3ff91a3b92 | ||
|
|
2020049cb7 | ||
|
|
d94954e6dd | ||
|
|
06817c1682 | ||
|
|
0554c2ac0f | ||
|
|
1087eb65d2 | ||
|
|
09dc6b5862 | ||
|
|
3d301f4307 | ||
|
|
446b1d5552 | ||
|
|
63c8422e63 | ||
|
|
616f6e73a5 | ||
|
|
213b52477f | ||
|
|
e9ba73d87f | ||
|
|
6e86cdc803 | ||
|
|
c023a81966 | ||
|
|
7d0bb1a5d7 | ||
|
|
3cf679260e | ||
|
|
53bd30755d | ||
|
|
7fe7216b29 | ||
|
|
2da1f518d3 | ||
|
|
8a30f2ddce | ||
|
|
0ea4e1d52f | ||
|
|
74c9ff2432 | ||
|
|
bfa50c9643 | ||
|
|
74a7e5f19c | ||
|
|
e3c954f460 | ||
|
|
16d3ff372f | ||
|
|
437357f099 | ||
|
|
955e08c35a | ||
|
|
58261cdaf2 | ||
|
|
545313aa06 | ||
|
|
1ceab64b6f | ||
|
|
eb0f692aa0 | ||
|
|
2ae1b9b678 | ||
|
|
2f2501ac3b | ||
|
|
a57894962d | ||
|
|
3f48574071 | ||
|
|
00bbfc0414 | ||
|
|
c4d4af6890 | ||
|
|
4149e4d6ed | ||
|
|
b2cb3bf43b | ||
|
|
e232cc0f34 | ||
|
|
f68e0dbae0 | ||
|
|
0126fb7d7a | ||
|
|
d2bc571a18 | ||
|
|
1f0842484c | ||
|
|
8c31054331 | ||
|
|
4b2e7e153e | ||
|
|
2289e00558 | ||
|
|
949f0f2213 | ||
|
|
703219119e | ||
|
|
5522b0623c | ||
|
|
8b1ae0194e | ||
|
|
a0ce85ae1e | ||
|
|
b1e251ed03 | ||
|
|
f7e4103d9b | ||
|
|
442c97f138 | ||
|
|
6862f0f6c1 | ||
|
|
6ad9103f86 | ||
|
|
016d6e4f18 | ||
|
|
97db83b270 | ||
|
|
20e82be101 | ||
|
|
4e08ce4d93 | ||
|
|
e8dc5ae1b8 | ||
|
|
0e667e9685 | ||
|
|
99f5e2d896 | ||
|
|
407b80daf5 | ||
|
|
c84dc6de45 | ||
|
|
a686e47fa2 | ||
|
|
56e58c0849 | ||
|
|
3b8e53bf90 | ||
|
|
cc9d3aedec | ||
|
|
a70843cd69 | ||
|
|
08c52770a9 | ||
|
|
52e385ffce | ||
|
|
d63321bc43 | ||
|
|
37ae457aa1 | ||
|
|
4b1852c3e1 | ||
|
|
dc80733397 | ||
|
|
78e328be86 | ||
|
|
ea43d4d9b6 | ||
|
|
8ce751f989 | ||
|
|
f55b9b6ae4 | ||
|
|
086f85845a | ||
|
|
eb90b6d935 | ||
|
|
13df9a0f87 | ||
|
|
89b4979cbc | ||
|
|
6e874483b6 | ||
|
|
afd2ee95ca | ||
|
|
e66d12dab2 | ||
|
|
d98172eb9f | ||
|
|
b070b4009c | ||
|
|
890cbb1378 | ||
|
|
0f1f8b511e | ||
|
|
19fb95e99b | ||
|
|
a22e2e25df | ||
|
|
8d991e1f9e | ||
|
|
91e856d6d5 | ||
|
|
65f957db81 | ||
|
|
a561254756 | ||
|
|
53626bb025 | ||
|
|
54d8d7585d | ||
|
|
4021a6c176 | ||
|
|
8c9734c19c | ||
|
|
b6ac6e4702 | ||
|
|
f256bdb653 | ||
|
|
1c3496e2f7 | ||
|
|
f5d737f2c5 | ||
|
|
619c4550bc | ||
|
|
6f42f85705 | ||
|
|
661d7fcfc4 | ||
|
|
47e715a350 | ||
|
|
b9c3ad2635 | ||
|
|
2787cf385c | ||
|
|
f03916cfd2 | ||
|
|
252b29fb0a | ||
|
|
553718eada | ||
|
|
171c440f27 | ||
|
|
869a9eafd3 | ||
|
|
6c61040f74 | ||
|
|
079765b558 | ||
|
|
45ccd7be5b | ||
|
|
2bc9938a2a | ||
|
|
5050f46b1e | ||
|
|
222a93162d |
@@ -11,6 +11,11 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-18.04
|
||||
container:
|
||||
image: replicated/troubleshoot-builder:18.04
|
||||
credentials:
|
||||
username: repldeploy2
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
steps:
|
||||
- uses: actions/setup-go@v1
|
||||
with:
|
||||
@@ -23,11 +28,15 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- run: make
|
||||
- run: make
|
||||
|
||||
compile-preflight:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-18.04
|
||||
container:
|
||||
image: replicated/troubleshoot-builder:18.04
|
||||
credentials:
|
||||
username: repldeploy2
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/setup-go@v1
|
||||
@@ -46,7 +55,7 @@ jobs:
|
||||
path: bin/preflight
|
||||
|
||||
validate-preflight:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-18.04
|
||||
needs: compile-preflight
|
||||
steps:
|
||||
- name: Download preflight binary
|
||||
@@ -54,12 +63,57 @@ jobs:
|
||||
with:
|
||||
name: preflight
|
||||
path: bin/
|
||||
- uses: engineerd/setup-kind@v0.2.0
|
||||
- uses: engineerd/setup-kind@v0.4.0
|
||||
- run: chmod +x bin/preflight
|
||||
- run: bin/preflight --interactive=false --format=json https://preflight.replicated.com
|
||||
- run: ./bin/preflight --interactive=false --format=json https://preflight.replicated.com
|
||||
|
||||
compile-supportbundle:
|
||||
runs-on: ubuntu-18.04
|
||||
container:
|
||||
image: replicated/troubleshoot-builder:18.04
|
||||
credentials:
|
||||
username: repldeploy2
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '1.14'
|
||||
- name: setup env
|
||||
run: |
|
||||
echo "::set-env name=GOPATH::$(go env GOPATH)"
|
||||
echo "::add-path::$(go env GOPATH)/bin"
|
||||
shell: bash
|
||||
- uses: actions/checkout@master
|
||||
- run: make support-bundle
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: support-bundle
|
||||
path: bin/support-bundle
|
||||
|
||||
validate-supportbundle:
|
||||
runs-on: ubuntu-18.04
|
||||
needs: compile-supportbundle
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Download support-bundle binary
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: support-bundle
|
||||
path: bin/
|
||||
- uses: engineerd/setup-kind@v0.4.0
|
||||
- run: chmod +x bin/support-bundle
|
||||
- run: ./bin/support-bundle ./examples/support-bundle/sample-collectors.yaml
|
||||
- run: ./bin/support-bundle ./examples/support-bundle/sample-supportbundle.yaml
|
||||
- run: ./bin/support-bundle https://kots.io
|
||||
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-18.04
|
||||
container:
|
||||
image: replicated/troubleshoot-builder:18.04
|
||||
credentials:
|
||||
username: repldeploy2
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
needs:
|
||||
- validate-preflight
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
@@ -74,7 +128,7 @@ jobs:
|
||||
|
||||
- name: Unshallow
|
||||
run: git fetch --prune --unshallow
|
||||
|
||||
|
||||
- uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: "1.14"
|
||||
|
||||
@@ -29,6 +29,8 @@ endif
|
||||
|
||||
define LDFLAGS
|
||||
-ldflags "\
|
||||
-s -w \
|
||||
-extldflags \"-static\" \
|
||||
-X ${VERSION_PACKAGE}.version=${VERSION} \
|
||||
-X ${VERSION_PACKAGE}.gitSHA=${GIT_SHA} \
|
||||
-X ${VERSION_PACKAGE}.buildTime=${DATE} \
|
||||
@@ -47,15 +49,15 @@ test: generate fmt vet
|
||||
|
||||
.PHONY: support-bundle
|
||||
support-bundle: generate fmt vet
|
||||
go build ${LDFLAGS} -o bin/support-bundle github.com/replicatedhq/troubleshoot/cmd/troubleshoot
|
||||
go build -tags netgo ${LDFLAGS} -o bin/support-bundle github.com/replicatedhq/troubleshoot/cmd/troubleshoot
|
||||
|
||||
.PHONY: preflight
|
||||
preflight: generate fmt vet
|
||||
go build ${LDFLAGS} -o bin/preflight github.com/replicatedhq/troubleshoot/cmd/preflight
|
||||
go build -tags netgo ${LDFLAGS} -o bin/preflight github.com/replicatedhq/troubleshoot/cmd/preflight
|
||||
|
||||
.PHONY: analyze
|
||||
analyze: generate fmt vet
|
||||
go build ${LDFLAGS} -o bin/analyze github.com/replicatedhq/troubleshoot/cmd/analyze
|
||||
go build -tags netgo ${LDFLAGS} -o bin/analyze github.com/replicatedhq/troubleshoot/cmd/analyze
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
@@ -67,37 +69,39 @@ vet:
|
||||
|
||||
.PHONY: generate
|
||||
generate: controller-gen client-gen
|
||||
$(shell go env GOPATH)/bin/controller-gen object:headerFile=./hack/boilerplate.go.txt paths=./pkg/apis/...
|
||||
$(shell go env GOPATH)/bin/client-gen \
|
||||
$(CONTROLLER_GEN) \
|
||||
object:headerFile=./hack/boilerplate.go.txt paths=./pkg/apis/...
|
||||
$(CLIENT_GEN) \
|
||||
--output-package=github.com/replicatedhq/troubleshoot/pkg/client \
|
||||
--clientset-name troubleshootclientset \
|
||||
--input-base github.com/replicatedhq/troubleshoot/pkg/apis \
|
||||
--input troubleshoot/v1beta1 \
|
||||
--input troubleshoot/v1beta2 \
|
||||
-h ./hack/boilerplate.go.txt
|
||||
|
||||
.PHONY: openapischema
|
||||
openapischema: controller-gen
|
||||
controller-gen crd +output:dir=./config/crds paths=./pkg/apis/troubleshoot/v1beta1
|
||||
controller-gen crd +output:dir=./config/crds paths=./pkg/apis/troubleshoot/v1beta2
|
||||
|
||||
.PHONY: schemas
|
||||
schemas: fmt vet openapischema
|
||||
go build ${LDFLAGS} -o bin/schemagen github.com/replicatedhq/troubleshoot/cmd/schemagen
|
||||
./bin/schemagen --output-dir ./schemas
|
||||
|
||||
# find or download controller-gen
|
||||
# download controller-gen if necessary
|
||||
.PHONY: contoller-gen
|
||||
controller-gen:
|
||||
ifeq (, $(shell which controller-gen))
|
||||
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.8
|
||||
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.3.0
|
||||
CONTROLLER_GEN=$(shell go env GOPATH)/bin/controller-gen
|
||||
else
|
||||
CONTROLLER_GEN=$(shell which controller-gen)
|
||||
endif
|
||||
|
||||
# find or download client-gen
|
||||
.PHONY: client-gen
|
||||
client-gen:
|
||||
ifeq (, $(shell which client-gen))
|
||||
go get k8s.io/code-generator/cmd/client-gen@kubernetes-1.16.4
|
||||
go get k8s.io/code-generator/cmd/client-gen@kubernetes-1.18.0
|
||||
CLIENT_GEN=$(shell go env GOPATH)/bin/client-gen
|
||||
else
|
||||
CLIENT_GEN=$(shell which client-gen)
|
||||
@@ -116,7 +120,7 @@ snapshot-release:
|
||||
|
||||
.PHONY: local-release
|
||||
local-release:
|
||||
curl -sL https://git.io/goreleaser | bash -s -- --rm-dist --snapshot --config deploy/.goreleaser.local.yml
|
||||
curl -sL https://git.io/goreleaser | bash -s -- --rm-dist --snapshot --config deploy/.goreleaser.yaml
|
||||
docker tag replicated/troubleshoot:alpha localhost:32000/troubleshoot:alpha
|
||||
docker tag replicated/preflight:alpha localhost:32000/preflight:alpha
|
||||
docker push localhost:32000/troubleshoot:alpha
|
||||
@@ -128,8 +132,8 @@ run-preflight: preflight
|
||||
|
||||
.PHONY: run-troubleshoot
|
||||
run-troubleshoot: support-bundle
|
||||
./bin/support-bundle ./examples/troubleshoot/sample-troubleshoot.yaml
|
||||
./bin/support-bundle ./examples/support-bundle/sample-supportbundle.yaml
|
||||
|
||||
.PHONY: run-analyze
|
||||
run-analyze: analyze
|
||||
./bin/analyze --analyzers ./examples/troubleshoot/sample-analyzers.yaml ./support-bundle.tar.gz
|
||||
./bin/analyze --analyzers ./examples/support-bundle/sample-analyzers.yaml ./support-bundle.tar.gz
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Replicated Troubleshoot
|
||||
|
||||
Replicated Troubleshoot is a framework for collecting, redacting and analyzing highly customizable diagnostic information about a Kubernetes cluster. Troubleshoot specs are created by 3rd-party application developers/maintainers and run by cluster operators in the initial and ongoing operation of those applications.
|
||||
Replicated Troubleshoot is a framework for collecting, redacting, and analyzing highly customizable diagnostic information about a Kubernetes cluster. Troubleshoot specs are created by 3rd-party application developers/maintainers and run by cluster operators in the initial and ongoing operation of those applications.
|
||||
|
||||
Troubleshoot provides two CLI tools as kubectl plugins (using [Krew](https://krew.dev)) `kubectl preflight` and `kubectl support-bundle`. Preflight provides pre-installation cluster conformance testing and validation (preflight checks) and support-bundle provides post-installation troubleshooting and diagnostics (support bundles).
|
||||
Troubleshoot provides two CLI tools as kubectl plugins (using [Krew](https://krew.dev)): `kubectl preflight` and `kubectl support-bundle`. Preflight provides pre-installation cluster conformance testing and validation (preflight checks) and support-bundle provides post-installation troubleshooting and diagnostics (support bundles).
|
||||
|
||||
## Preflight Checks
|
||||
Preflight checks are an easy-to-run set of conformance tests that can be written to verify that specific requirements in a cluster are met.
|
||||
@@ -18,11 +18,11 @@ curl https://krew.sh/preflight | bash
|
||||
kubectl preflight https://preflight.replicated.com
|
||||
```
|
||||
|
||||
For a details on creating the custom resource files that drive preflight checks, visit [creating preflight checks](https://troubleshoot.sh/docs/preflight/creating/).
|
||||
For a details on creating the custom resource files that drive preflight checks, visit [creating preflight checks](https://troubleshoot.sh/docs/preflight/introduction/).
|
||||
|
||||
|
||||
## Support Bundle
|
||||
A support bundle is an archive that's created in-cluster, by collecting logs, cluster information and executing specified commands (including redaction of sensitive information). After creating a support bundle, the cluster operator will normally deliver it to the 3rd-party application vendor for analysis and disconnected debugging. Another Replicated project, [Kotsadm](https://github.com/replicatedhq/kotsadm), provides cluster operators with in-cluster UI for processing support bundles and viewing analyzers (as well as support bundle collection).
|
||||
A support bundle is an archive that's created in-cluster, by collecting logs and cluster information, and executing specified commands (including redaction of sensitive information). After creating a support bundle, the cluster operator will normally deliver it to the 3rd-party application vendor for analysis and disconnected debugging. Another Replicated project, [Kotsadm](https://github.com/replicatedhq/kotsadm), provides cluster operators with an in-cluster UI for processing support bundles and viewing analyzers (as well as support bundle collection).
|
||||
|
||||
To collect a sample support bundle, install the troubleshoot kubectl plugin:
|
||||
|
||||
@@ -32,11 +32,27 @@ curl https://krew.sh/support-bundle | bash
|
||||
and run:
|
||||
|
||||
```shell
|
||||
kubectl support-bundle https://troubleshoot.replicated.com
|
||||
kubectl support-bundle https://support-bundle.replicated.com
|
||||
```
|
||||
For details on creating the custom resource files that drive support-bundle collection [creating collectors](https://troubleshoot.sh/reference/collectors/overview/) and for analyzers [creating analyzers](https://troubleshoot.sh/reference/analyzers/overview/).
|
||||
For details on creating the custom resource files that drive support-bundle collection, visit [creating collectors](https://troubleshoot.sh/docs/collect/) and [creating analyzers](https://troubleshoot.sh/docs/analyze/).
|
||||
|
||||
# Community
|
||||
|
||||
For questions about using Troubleshoot, there's a [Replicated Community](https://help.replicated.com/community) forum, and a [#app-troubleshoot channel in Kubernetes Slack](https://kubernetes.slack.com/channels/app-troubleshoot).
|
||||
|
||||
# Building
|
||||
|
||||
The following packages are required for building the project from source code:
|
||||
|
||||
pkg-config
|
||||
librrd-dev
|
||||
libglib2.0-dev
|
||||
libcairo2-dev
|
||||
libpango1.0-dev
|
||||
libpixman-1-dev
|
||||
libpng-dev
|
||||
libsdl-pango-dev
|
||||
libthai-dev
|
||||
libpcre3-dev
|
||||
|
||||
There are known issues with libc6 2.27-3ubuntu1.2 on Ubuntu 18. Upgrading to 2.27-3ubuntu1.3 (apt-get install libc6) resolves these.
|
||||
@@ -4,14 +4,10 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/logger"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
)
|
||||
|
||||
var (
|
||||
KubernetesConfigFlags *genericclioptions.ConfigFlags
|
||||
)
|
||||
|
||||
func RootCmd() *cobra.Command {
|
||||
@@ -41,8 +37,7 @@ func RootCmd() *cobra.Command {
|
||||
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||
|
||||
KubernetesConfigFlags = genericclioptions.NewConfigFlags(false)
|
||||
KubernetesConfigFlags.AddFlags(cmd.Flags())
|
||||
k8sutil.AddFlags(cmd.Flags())
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/cmd/analyze/cli"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -5,18 +5,18 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ui "github.com/gizak/termui/v3"
|
||||
"github.com/gizak/termui/v3/widgets"
|
||||
"github.com/pkg/errors"
|
||||
ui "github.com/replicatedhq/termui/v3"
|
||||
"github.com/replicatedhq/termui/v3/widgets"
|
||||
"github.com/replicatedhq/troubleshoot/cmd/util"
|
||||
analyzerunner "github.com/replicatedhq/troubleshoot/pkg/analyze"
|
||||
)
|
||||
|
||||
var (
|
||||
selectedResult = 0
|
||||
table = widgets.NewTable()
|
||||
isShowingSaved = false
|
||||
)
|
||||
|
||||
@@ -64,7 +64,9 @@ func showInteractiveResults(preflightName string, analyzeResults []*analyzerunne
|
||||
selectedResult++
|
||||
} else {
|
||||
selectedResult = 0
|
||||
table.SelectedRow = 0
|
||||
}
|
||||
table.ScrollDown()
|
||||
ui.Clear()
|
||||
drawUI(preflightName, analyzeResults)
|
||||
case "<Up>":
|
||||
@@ -72,7 +74,9 @@ func showInteractiveResults(preflightName string, analyzeResults []*analyzerunne
|
||||
selectedResult--
|
||||
} else {
|
||||
selectedResult = len(analyzeResults) - 1
|
||||
table.SelectedRow = len(analyzeResults)
|
||||
}
|
||||
table.ScrollUp()
|
||||
ui.Clear()
|
||||
drawUI(preflightName, analyzeResults)
|
||||
}
|
||||
@@ -95,7 +99,7 @@ func drawHeader(preflightName string) {
|
||||
termWidth, _ := ui.TerminalDimensions()
|
||||
|
||||
title := widgets.NewParagraph()
|
||||
title.Text = fmt.Sprintf("%s Preflight Checks", appName(preflightName))
|
||||
title.Text = fmt.Sprintf("%s Preflight Checks", util.AppName(preflightName))
|
||||
title.TextStyle.Fg = ui.ColorWhite
|
||||
title.TextStyle.Bg = ui.ColorClear
|
||||
title.TextStyle.Modifier = ui.ModifierBold
|
||||
@@ -127,7 +131,6 @@ func drawFooter() {
|
||||
func drawPreflightTable(analyzeResults []*analyzerunner.AnalyzeResult) {
|
||||
termWidth, termHeight := ui.TerminalDimensions()
|
||||
|
||||
table := widgets.NewTable()
|
||||
table.SetRect(0, 3, termWidth/2, termHeight-6)
|
||||
table.FillRow = true
|
||||
table.Border = true
|
||||
@@ -221,7 +224,7 @@ func save(preflightName string, analyzeResults []*analyzerunner.AnalyzeResult) (
|
||||
os.Remove(filename)
|
||||
}
|
||||
|
||||
results := fmt.Sprintf("%s Preflight Checks\n\n", appName(preflightName))
|
||||
results := fmt.Sprintf("%s Preflight Checks\n\n", util.AppName(preflightName))
|
||||
for _, analyzeResult := range analyzeResults {
|
||||
result := ""
|
||||
|
||||
@@ -270,19 +273,3 @@ func showSaved(filename string) {
|
||||
|
||||
isShowingSaved = true
|
||||
}
|
||||
|
||||
func appName(preflightName string) string {
|
||||
words := strings.Split(strings.Title(strings.Replace(preflightName, "-", " ", -1)), " ")
|
||||
casedWords := []string{}
|
||||
for i, word := range words {
|
||||
if strings.ToLower(word) == "ai" {
|
||||
casedWords = append(casedWords, "AI")
|
||||
} else if strings.ToLower(word) == "io" && i > 0 {
|
||||
casedWords[i-1] += ".io"
|
||||
} else {
|
||||
casedWords = append(casedWords, word)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(casedWords, " ")
|
||||
}
|
||||
|
||||
@@ -4,13 +4,9 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
)
|
||||
|
||||
var (
|
||||
KubernetesConfigFlags *genericclioptions.ConfigFlags
|
||||
)
|
||||
|
||||
func RootCmd() *cobra.Command {
|
||||
@@ -36,19 +32,15 @@ that a cluster meets the requirements to run an application.`,
|
||||
|
||||
cmd.Flags().Bool("interactive", true, "interactive preflights")
|
||||
cmd.Flags().String("format", "human", "output format, one of human, json, yaml. only used when interactive is set to false")
|
||||
cmd.Flags().String("preflight", "", "name of the preflight to use")
|
||||
cmd.Flags().String("image", "", "the full name of the preflight image to use")
|
||||
cmd.Flags().String("pullpolicy", "", "the pull policy of the preflight image")
|
||||
cmd.Flags().String("collector-image", "", "the full name of the collector image to use")
|
||||
cmd.Flags().String("collector-pullpolicy", "", "the pull policy of the collector image")
|
||||
cmd.Flags().Bool("collect-without-permissions", false, "always run preflight checks even if some require permissions that preflight does not have")
|
||||
|
||||
cmd.Flags().String("serviceaccount", "", "name of the service account to use. if not provided, one will be created")
|
||||
cmd.Flags().String("since-time", "", "force pod logs collectors to return logs after a specific date (RFC3339)")
|
||||
cmd.Flags().String("since", "", "force pod logs collectors to return logs newer than a relative duration like 5s, 2m, or 3h.")
|
||||
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||
|
||||
KubernetesConfigFlags = genericclioptions.NewConfigFlags(false)
|
||||
KubernetesConfigFlags.AddFlags(cmd.Flags())
|
||||
k8sutil.AddFlags(cmd.Flags())
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -5,17 +5,22 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
cursor "github.com/ahmetalpbalkan/go-cursor"
|
||||
"github.com/fatih/color"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/replicatedhq/troubleshoot/cmd/util"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
troubleshootclientsetscheme "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/docrewrite"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/preflight"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/specs"
|
||||
"github.com/spf13/viper"
|
||||
spin "github.com/tj/go-spin"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
@@ -23,15 +28,28 @@ func runPreflights(v *viper.Viper, arg string) error {
|
||||
fmt.Print(cursor.Hide())
|
||||
defer fmt.Print(cursor.Show())
|
||||
|
||||
preflightContent := ""
|
||||
var preflightContent []byte
|
||||
var err error
|
||||
if _, err = os.Stat(arg); err == nil {
|
||||
if strings.HasPrefix(arg, "secret/") {
|
||||
// format secret/namespace-name/secret-name
|
||||
pathParts := strings.Split(arg, "/")
|
||||
if len(pathParts) != 3 {
|
||||
return errors.Errorf("path %s must have 3 components", arg)
|
||||
}
|
||||
|
||||
spec, err := specs.LoadFromSecret(pathParts[1], pathParts[2], "preflight-spec")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get spec from secret")
|
||||
}
|
||||
|
||||
preflightContent = spec
|
||||
} else if _, err = os.Stat(arg); err == nil {
|
||||
b, err := ioutil.ReadFile(arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
preflightContent = string(b)
|
||||
preflightContent = b
|
||||
} else {
|
||||
if !util.IsURL(arg) {
|
||||
return fmt.Errorf("%s is not a URL and was not found (err %s)", arg, err)
|
||||
@@ -41,7 +59,7 @@ func runPreflights(v *viper.Viper, arg string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("User-Agent", "Replicated_Preflight/v1beta1")
|
||||
req.Header.Set("User-Agent", "Replicated_Preflight/v1beta2")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -53,7 +71,12 @@ func runPreflights(v *viper.Viper, arg string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
preflightContent = string(body)
|
||||
preflightContent = body
|
||||
}
|
||||
|
||||
preflightContent, err = docrewrite.ConvertToV1Beta2(preflightContent)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to convert to v1beta2")
|
||||
}
|
||||
|
||||
troubleshootclientsetscheme.AddToScheme(scheme.Scheme)
|
||||
@@ -63,7 +86,7 @@ func runPreflights(v *viper.Viper, arg string) error {
|
||||
return errors.Wrapf(err, "failed to parse %s", arg)
|
||||
}
|
||||
|
||||
preflightSpec := obj.(*troubleshootv1beta1.Preflight)
|
||||
preflightSpec := obj.(*troubleshootv1beta2.Preflight)
|
||||
|
||||
s := spin.New()
|
||||
finishedCh := make(chan bool, 1)
|
||||
@@ -95,7 +118,7 @@ func runPreflights(v *viper.Viper, arg string) error {
|
||||
close(finishedCh)
|
||||
}()
|
||||
|
||||
restConfig, err := KubernetesConfigFlags.ToRESTConfig()
|
||||
restConfig, err := k8sutil.GetRESTConfig()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to convert kube flags to rest config")
|
||||
}
|
||||
@@ -107,6 +130,13 @@ func runPreflights(v *viper.Viper, arg string) error {
|
||||
KubernetesRestConfig: restConfig,
|
||||
}
|
||||
|
||||
if v.GetString("since") != "" || v.GetString("since-time") != "" {
|
||||
err := parseTimeFlags(v, progressChan, preflightSpec.Spec.Collectors)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
collectResults, err := preflight.Collect(collectOpts, preflightSpec)
|
||||
if err != nil {
|
||||
if !collectResults.IsRBACAllowed {
|
||||
@@ -139,3 +169,35 @@ func runPreflights(v *viper.Viper, arg string) error {
|
||||
|
||||
return showStdoutResults(v.GetString("format"), preflightSpec.Name, analyzeResults)
|
||||
}
|
||||
|
||||
func parseTimeFlags(v *viper.Viper, progressChan chan interface{}, collectors []*troubleshootv1beta2.Collect) error {
|
||||
var (
|
||||
sinceTime time.Time
|
||||
err error
|
||||
)
|
||||
if v.GetString("since-time") != "" {
|
||||
if v.GetString("since") != "" {
|
||||
return errors.Errorf("at most one of `sinceTime` or `since` may be specified")
|
||||
}
|
||||
sinceTime, err = time.Parse(time.RFC3339, v.GetString("since-time"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to parse --since-time flag")
|
||||
}
|
||||
} else {
|
||||
parsedDuration, err := time.ParseDuration(v.GetString("since"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to parse --since flag")
|
||||
}
|
||||
now := time.Now()
|
||||
sinceTime = now.Add(0 - parsedDuration)
|
||||
}
|
||||
for _, collector := range collectors {
|
||||
if collector.Logs != nil {
|
||||
if collector.Logs.Limits == nil {
|
||||
collector.Logs.Limits = new(troubleshootv1beta2.LogLimits)
|
||||
}
|
||||
collector.Logs.Limits.SinceTime = metav1.NewTime(sinceTime)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
kuberneteserrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
func createServiceAccount(preflight troubleshootv1beta1.Preflight, namespace string, clientset *kubernetes.Clientset) (string, error) {
|
||||
name := fmt.Sprintf("preflight-%s", preflight.Name)
|
||||
|
||||
serviceAccount := corev1.ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ServiceAccount",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Secrets: []corev1.ObjectReference{
|
||||
{
|
||||
APIVersion: "v1",
|
||||
Kind: "Secret",
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
_, err := clientset.CoreV1().ServiceAccounts(namespace).Get(serviceAccount.Name, metav1.GetOptions{})
|
||||
if err != nil && !kuberneteserrors.IsNotFound(err) {
|
||||
return "", errors.Wrap(err, "failed to get existing service account")
|
||||
}
|
||||
if kuberneteserrors.IsNotFound(err) {
|
||||
_, err := clientset.CoreV1().ServiceAccounts(namespace).Create(&serviceAccount)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to create service account")
|
||||
}
|
||||
}
|
||||
|
||||
role := rbacv1.ClusterRole{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ClusterRole",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Rules: []rbacv1.PolicyRule{
|
||||
{
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{
|
||||
"namespaces",
|
||||
"pods",
|
||||
"services",
|
||||
"secrets",
|
||||
},
|
||||
Verbs: metav1.Verbs{"list"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{"apps"},
|
||||
Resources: []string{"deployments"},
|
||||
Verbs: metav1.Verbs{"list"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{"extensions"},
|
||||
Resources: []string{"ingresses"},
|
||||
Verbs: metav1.Verbs{"list"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{"storage.k8s.io"},
|
||||
Resources: []string{"storageclasses"},
|
||||
Verbs: metav1.Verbs{"list"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{"apiextensions.k8s.io"},
|
||||
Resources: []string{"customresourcedefinitions"},
|
||||
Verbs: metav1.Verbs{"list"},
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err = clientset.RbacV1().ClusterRoles().Get(role.Name, metav1.GetOptions{})
|
||||
if err != nil && !kuberneteserrors.IsNotFound(err) {
|
||||
return "", errors.Wrap(err, "failed to get eisting cluster role")
|
||||
}
|
||||
if kuberneteserrors.IsNotFound(err) {
|
||||
_, err = clientset.RbacV1().ClusterRoles().Create(&role)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to create cluster role")
|
||||
}
|
||||
}
|
||||
|
||||
roleBinding := rbacv1.ClusterRoleBinding{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ClusterRoleBinding",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Subjects: []rbacv1.Subject{
|
||||
{
|
||||
Kind: "ServiceAccount",
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
APIGroup: "rbac.authorization.k8s.io",
|
||||
Kind: "ClusterRole",
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
_, err = clientset.RbacV1().ClusterRoleBindings().Get(roleBinding.Name, metav1.GetOptions{})
|
||||
if err != nil && !kuberneteserrors.IsNotFound(err) {
|
||||
return "", errors.Wrap(err, "failed to get existing cluster role binding")
|
||||
}
|
||||
if kuberneteserrors.IsNotFound(err) {
|
||||
_, err = clientset.RbacV1().ClusterRoleBindings().Create(&roleBinding)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to create cluster role binding")
|
||||
}
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func removeServiceAccount(name string, namespace string, clientset *kubernetes.Clientset) error {
|
||||
if err := clientset.RbacV1().ClusterRoleBindings().Delete(name, &metav1.DeleteOptions{}); err != nil {
|
||||
return errors.Wrap(err, "failed to delete cluster role binding")
|
||||
}
|
||||
|
||||
if err := clientset.RbacV1().ClusterRoles().Delete(name, &metav1.DeleteOptions{}); err != nil {
|
||||
return errors.Wrap(err, "failed to delete cluster role")
|
||||
}
|
||||
|
||||
if err := clientset.CoreV1().ServiceAccounts(namespace).Delete(name, &metav1.DeleteOptions{}); err != nil {
|
||||
return errors.Wrap(err, "failed to delete service account")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
troubleshootclientv1beta1 "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/typed/troubleshoot/v1beta1"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
)
|
||||
|
||||
func createTroubleshootK8sClient(configFlags *genericclioptions.ConfigFlags) (*troubleshootclientv1beta1.TroubleshootV1beta1Client, error) {
|
||||
config, err := configFlags.ToRESTConfig()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert kube flags to rest config")
|
||||
}
|
||||
|
||||
troubleshootClient, err := troubleshootclientv1beta1.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create troubleshoot client")
|
||||
}
|
||||
|
||||
return troubleshootClient, nil
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/cmd/preflight/cli"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
+52
-20
@@ -62,28 +62,60 @@ func generateSchemas(v *viper.Viper) error {
|
||||
return errors.Wrap(err, "failed to get workdir")
|
||||
}
|
||||
|
||||
preflightContents, err := ioutil.ReadFile(filepath.Join(workdir, "config", "crds", "troubleshoot.replicated.com_preflights.yaml"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to read preflight crd")
|
||||
}
|
||||
if err := generateSchemaFromCRD(preflightContents, filepath.Join(workdir, v.GetString("output-dir"), "preflight-troubleshoot-v1beta1.json")); err != nil {
|
||||
return errors.Wrap(err, "failed to write preflight schema")
|
||||
files := []struct {
|
||||
inFilename string
|
||||
outFilename string
|
||||
}{
|
||||
{
|
||||
"troubleshoot.replicated.com_preflights.yaml",
|
||||
"preflight-troubleshoot-v1beta1.json",
|
||||
},
|
||||
{
|
||||
"troubleshoot.replicated.com_analyzers.yaml",
|
||||
"analyzer-troubleshoot-v1beta1.json",
|
||||
},
|
||||
{
|
||||
"troubleshoot.replicated.com_collectors.yaml",
|
||||
"collector-troubleshoot-v1beta1.json",
|
||||
},
|
||||
{
|
||||
"troubleshoot.replicated.com_redactors.yaml",
|
||||
"redactor-troubleshoot-v1beta1.json",
|
||||
},
|
||||
{
|
||||
"troubleshoot.replicated.com_supportbundles.yaml",
|
||||
"supportbundle-troubleshoot-v1beta1.json",
|
||||
},
|
||||
{
|
||||
"troubleshoot.sh_analyzers.yaml",
|
||||
"analyzer-troubleshoot-v1beta2.json",
|
||||
},
|
||||
{
|
||||
"troubleshoot.sh_collectors.yaml",
|
||||
"collector-troubleshoot-v1beta2.json",
|
||||
},
|
||||
{
|
||||
"troubleshoot.sh_preflights.yaml",
|
||||
"preflight-troubleshoot-v1beta2.json",
|
||||
},
|
||||
{
|
||||
"troubleshoot.sh_redactors.yaml",
|
||||
"redactor-troubleshoot-v1beta2.json",
|
||||
},
|
||||
{
|
||||
"troubleshoot.sh_supportbundles.yaml",
|
||||
"supportbundle-troubleshoot-v1beta2.json",
|
||||
},
|
||||
}
|
||||
|
||||
analyzersContents, err := ioutil.ReadFile(filepath.Join(workdir, "config", "crds", "troubleshoot.replicated.com_analyzers.yaml"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to read analyzers crd")
|
||||
}
|
||||
if err := generateSchemaFromCRD(analyzersContents, filepath.Join(workdir, v.GetString("output-dir"), "analyzer-troubleshoot-v1beta1.json")); err != nil {
|
||||
return errors.Wrap(err, "failed to write analyzers schema")
|
||||
}
|
||||
|
||||
collectorsContents, err := ioutil.ReadFile(filepath.Join(workdir, "config", "crds", "troubleshoot.replicated.com_collectors.yaml"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to read collectors crd")
|
||||
}
|
||||
if err := generateSchemaFromCRD(collectorsContents, filepath.Join(workdir, v.GetString("output-dir"), "collector-troubleshoot-v1beta1.json")); err != nil {
|
||||
return errors.Wrap(err, "failed to write collectors schema")
|
||||
for _, file := range files {
|
||||
contents, err := ioutil.ReadFile(filepath.Join(workdir, "config", "crds", file.inFilename))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to read crd from %s", file.inFilename)
|
||||
}
|
||||
if err := generateSchemaFromCRD(contents, filepath.Join(workdir, v.GetString("output-dir"), file.outFilename)); err != nil {
|
||||
return errors.Wrapf(err, "failed to write crd schema to %s", file.outFilename)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ui "github.com/replicatedhq/termui/v3"
|
||||
"github.com/replicatedhq/termui/v3/widgets"
|
||||
"github.com/replicatedhq/troubleshoot/cmd/util"
|
||||
analyzerunner "github.com/replicatedhq/troubleshoot/pkg/analyze"
|
||||
)
|
||||
|
||||
var (
|
||||
selectedResult = 0
|
||||
table = widgets.NewTable()
|
||||
isShowingSaved = false
|
||||
)
|
||||
|
||||
func showInteractiveResults(supportBundleName string, analyzeResults []*analyzerunner.AnalyzeResult) error {
|
||||
if err := ui.Init(); err != nil {
|
||||
return errors.Wrap(err, "failed to create terminal ui")
|
||||
}
|
||||
defer ui.Close()
|
||||
drawUI(supportBundleName, analyzeResults)
|
||||
|
||||
uiEvents := ui.PollEvents()
|
||||
for {
|
||||
select {
|
||||
case e := <-uiEvents:
|
||||
switch e.ID {
|
||||
case "<C-c>":
|
||||
return nil
|
||||
case "q":
|
||||
if isShowingSaved == true {
|
||||
isShowingSaved = false
|
||||
ui.Clear()
|
||||
drawUI(supportBundleName, analyzeResults)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
case "s":
|
||||
filename, err := save(analyzeResults)
|
||||
if err != nil {
|
||||
// show
|
||||
} else {
|
||||
showSaved(filename)
|
||||
go func() {
|
||||
time.Sleep(time.Second * 5)
|
||||
isShowingSaved = false
|
||||
ui.Clear()
|
||||
drawUI(supportBundleName, analyzeResults)
|
||||
}()
|
||||
}
|
||||
case "<Resize>":
|
||||
ui.Clear()
|
||||
drawUI(supportBundleName, analyzeResults)
|
||||
case "<Down>":
|
||||
if selectedResult < len(analyzeResults)-1 {
|
||||
selectedResult++
|
||||
} else {
|
||||
selectedResult = 0
|
||||
table.SelectedRow = 0
|
||||
}
|
||||
table.ScrollDown()
|
||||
ui.Clear()
|
||||
drawUI(supportBundleName, analyzeResults)
|
||||
case "<Up>":
|
||||
if selectedResult > 0 {
|
||||
selectedResult--
|
||||
} else {
|
||||
selectedResult = len(analyzeResults) - 1
|
||||
table.SelectedRow = len(analyzeResults)
|
||||
}
|
||||
table.ScrollUp()
|
||||
ui.Clear()
|
||||
drawUI(supportBundleName, analyzeResults)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func drawUI(supportBundleName string, analyzeResults []*analyzerunner.AnalyzeResult) {
|
||||
drawGrid(analyzeResults)
|
||||
drawHeader(supportBundleName)
|
||||
drawFooter()
|
||||
}
|
||||
|
||||
func drawGrid(analyzeResults []*analyzerunner.AnalyzeResult) {
|
||||
drawAnalyzersTable(analyzeResults)
|
||||
drawDetails(analyzeResults[selectedResult])
|
||||
}
|
||||
|
||||
func drawHeader(supportBundleName string) {
|
||||
termWidth, _ := ui.TerminalDimensions()
|
||||
|
||||
title := widgets.NewParagraph()
|
||||
title.Text = fmt.Sprintf("%s Support Bundle Analysis", util.AppName(supportBundleName))
|
||||
title.TextStyle.Fg = ui.ColorWhite
|
||||
title.TextStyle.Bg = ui.ColorClear
|
||||
title.TextStyle.Modifier = ui.ModifierBold
|
||||
title.Border = false
|
||||
|
||||
left := termWidth/2 - 2*len(title.Text)/3
|
||||
right := termWidth/2 + (termWidth/2 - left)
|
||||
|
||||
title.SetRect(left, 0, right, 1)
|
||||
ui.Render(title)
|
||||
}
|
||||
|
||||
func drawFooter() {
|
||||
termWidth, termHeight := ui.TerminalDimensions()
|
||||
|
||||
instructions := widgets.NewParagraph()
|
||||
instructions.Text = "[q] quit [s] save [↑][↓] scroll"
|
||||
instructions.Border = false
|
||||
|
||||
left := 0
|
||||
right := termWidth
|
||||
top := termHeight - 1
|
||||
bottom := termHeight
|
||||
|
||||
instructions.SetRect(left, top, right, bottom)
|
||||
ui.Render(instructions)
|
||||
}
|
||||
|
||||
func drawAnalyzersTable(analyzeResults []*analyzerunner.AnalyzeResult) {
|
||||
termWidth, termHeight := ui.TerminalDimensions()
|
||||
|
||||
table.SetRect(0, 3, termWidth/2, termHeight-6)
|
||||
table.FillRow = true
|
||||
table.Border = true
|
||||
table.Rows = [][]string{}
|
||||
table.ColumnWidths = []int{termWidth}
|
||||
|
||||
for i, analyzeResult := range analyzeResults {
|
||||
title := analyzeResult.Title
|
||||
if analyzeResult.IsPass {
|
||||
title = fmt.Sprintf("✔ %s", title)
|
||||
} else if analyzeResult.IsWarn {
|
||||
title = fmt.Sprintf("⚠️ %s", title)
|
||||
} else if analyzeResult.IsFail {
|
||||
title = fmt.Sprintf("✘ %s", title)
|
||||
}
|
||||
table.Rows = append(table.Rows, []string{
|
||||
title,
|
||||
})
|
||||
|
||||
if analyzeResult.IsPass {
|
||||
if i == selectedResult {
|
||||
table.RowStyles[i] = ui.NewStyle(ui.ColorGreen, ui.ColorClear, ui.ModifierReverse)
|
||||
} else {
|
||||
table.RowStyles[i] = ui.NewStyle(ui.ColorGreen, ui.ColorClear)
|
||||
}
|
||||
} else if analyzeResult.IsWarn {
|
||||
if i == selectedResult {
|
||||
table.RowStyles[i] = ui.NewStyle(ui.ColorYellow, ui.ColorClear, ui.ModifierReverse)
|
||||
} else {
|
||||
table.RowStyles[i] = ui.NewStyle(ui.ColorYellow, ui.ColorClear)
|
||||
}
|
||||
} else if analyzeResult.IsFail {
|
||||
if i == selectedResult {
|
||||
table.RowStyles[i] = ui.NewStyle(ui.ColorRed, ui.ColorClear, ui.ModifierReverse)
|
||||
} else {
|
||||
table.RowStyles[i] = ui.NewStyle(ui.ColorRed, ui.ColorClear)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui.Render(table)
|
||||
}
|
||||
|
||||
func drawDetails(analysisResult *analyzerunner.AnalyzeResult) {
|
||||
termWidth, _ := ui.TerminalDimensions()
|
||||
|
||||
currentTop := 4
|
||||
title := widgets.NewParagraph()
|
||||
title.Text = analysisResult.Title
|
||||
title.Border = false
|
||||
if analysisResult.IsPass {
|
||||
title.TextStyle = ui.NewStyle(ui.ColorGreen, ui.ColorClear, ui.ModifierBold)
|
||||
} else if analysisResult.IsWarn {
|
||||
title.TextStyle = ui.NewStyle(ui.ColorYellow, ui.ColorClear, ui.ModifierBold)
|
||||
} else if analysisResult.IsFail {
|
||||
title.TextStyle = ui.NewStyle(ui.ColorRed, ui.ColorClear, ui.ModifierBold)
|
||||
}
|
||||
height := estimateNumberOfLines(title.Text, termWidth/2)
|
||||
title.SetRect(termWidth/2, currentTop, termWidth, currentTop+height)
|
||||
ui.Render(title)
|
||||
currentTop = currentTop + height + 1
|
||||
|
||||
message := widgets.NewParagraph()
|
||||
message.Text = analysisResult.Message
|
||||
message.Border = false
|
||||
height = estimateNumberOfLines(message.Text, termWidth/2) + 2
|
||||
message.SetRect(termWidth/2, currentTop, termWidth, currentTop+height)
|
||||
ui.Render(message)
|
||||
currentTop = currentTop + height + 1
|
||||
|
||||
if analysisResult.URI != "" {
|
||||
uri := widgets.NewParagraph()
|
||||
uri.Text = fmt.Sprintf("For more information: %s", analysisResult.URI)
|
||||
uri.Border = false
|
||||
height = estimateNumberOfLines(uri.Text, termWidth/2)
|
||||
uri.SetRect(termWidth/2, currentTop, termWidth, currentTop+height)
|
||||
ui.Render(uri)
|
||||
currentTop = currentTop + height + 1
|
||||
}
|
||||
}
|
||||
|
||||
func estimateNumberOfLines(text string, width int) int {
|
||||
lines := len(text)/width + 1
|
||||
return lines
|
||||
}
|
||||
|
||||
func showSaved(filename string) {
|
||||
termWidth, termHeight := ui.TerminalDimensions()
|
||||
|
||||
savedMessage := widgets.NewParagraph()
|
||||
savedMessage.Text = fmt.Sprintf("Support Bundle analysis results saved to\n\n%s", filename)
|
||||
savedMessage.WrapText = true
|
||||
savedMessage.Border = true
|
||||
|
||||
left := termWidth/2 - 20
|
||||
right := termWidth/2 + 20
|
||||
top := termHeight/2 - 4
|
||||
bottom := termHeight/2 + 4
|
||||
|
||||
savedMessage.SetRect(left, top, right, bottom)
|
||||
ui.Render(savedMessage)
|
||||
|
||||
isShowingSaved = true
|
||||
}
|
||||
|
||||
func save(analyzeResults []*analyzerunner.AnalyzeResult) (string, error) {
|
||||
filename := path.Join(util.HomeDir(), fmt.Sprintf("%s-results.txt", "support-bundle"))
|
||||
_, err := os.Stat(filename)
|
||||
if err == nil {
|
||||
os.Remove(filename)
|
||||
}
|
||||
|
||||
results := ""
|
||||
for _, analyzeResult := range analyzeResults {
|
||||
result := ""
|
||||
|
||||
if analyzeResult.IsPass {
|
||||
result = "Check PASS\n"
|
||||
} else if analyzeResult.IsWarn {
|
||||
result = "Check WARN\n"
|
||||
} else if analyzeResult.IsFail {
|
||||
result = "Check FAIL\n"
|
||||
}
|
||||
|
||||
result = result + fmt.Sprintf("Title: %s\n", analyzeResult.Title)
|
||||
result = result + fmt.Sprintf("Message: %s\n", analyzeResult.Message)
|
||||
|
||||
if analyzeResult.URI != "" {
|
||||
result = result + fmt.Sprintf("URI: %s\n", analyzeResult.URI)
|
||||
}
|
||||
|
||||
result = result + "\n------------\n"
|
||||
|
||||
results = results + result
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filename, []byte(results), 0644); err != nil {
|
||||
return "", errors.Wrap(err, "failed to save preflight results")
|
||||
}
|
||||
|
||||
return filename, nil
|
||||
}
|
||||
@@ -5,24 +5,20 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/logger"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
)
|
||||
|
||||
var (
|
||||
KubernetesConfigFlags *genericclioptions.ConfigFlags
|
||||
)
|
||||
|
||||
func RootCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "troubleshoot [url]",
|
||||
Use: "support-bundle [url]",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Short: "Generate and manage support bundles",
|
||||
Short: "Generate a support bundle",
|
||||
Long: `A support bundle is an archive of files, output, metrics and state
|
||||
from a server that can be used to assist when troubleshooting a server.`,
|
||||
from a server that can be used to assist when troubleshooting a Kubernetes cluster.`,
|
||||
SilenceUsage: true,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
viper.BindPFlags(cmd.Flags())
|
||||
@@ -40,24 +36,21 @@ from a server that can be used to assist when troubleshooting a server.`,
|
||||
cmd.AddCommand(Analyze())
|
||||
cmd.AddCommand(VersionCmd())
|
||||
|
||||
cmd.Flags().String("collectors", "", "name of the collectors to use")
|
||||
cmd.Flags().String("image", "", "the full name of the collector image to use")
|
||||
cmd.Flags().String("pullpolicy", "", "the pull policy of the collector image")
|
||||
cmd.Flags().StringSlice("redactors", []string{}, "names of the additional redactors to use")
|
||||
cmd.Flags().Bool("redact", true, "enable/disable default redactions")
|
||||
cmd.Flags().Bool("collect-without-permissions", false, "always run troubleshoot collectors even if some require permissions that troubleshoot does not have")
|
||||
cmd.Flags().Bool("collect-without-permissions", false, "always generate a support bundle, even if it some require additional permissions")
|
||||
cmd.Flags().String("since-time", "", "force pod logs collectors to return logs after a specific date (RFC3339)")
|
||||
cmd.Flags().String("since", "", "force pod logs collectors to return logs newer than a relative duration like 5s, 2m, or 3h.")
|
||||
|
||||
// hidden in favor of the `insecure-skip-tls-verify` flag
|
||||
cmd.Flags().Bool("allow-insecure-connections", false, "don't verify TLS certs when retrieving spec and reporting results")
|
||||
cmd.Flags().Bool("allow-insecure-connections", false, "when set, do not verify TLS certs when retrieving spec and reporting results")
|
||||
cmd.Flags().MarkHidden("allow-insecure-connections")
|
||||
|
||||
cmd.Flags().String("serviceaccount", "", "name of the service account to use. if not provided, one will be created")
|
||||
viper.BindPFlags(cmd.Flags())
|
||||
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||
|
||||
KubernetesConfigFlags = genericclioptions.NewConfigFlags(false)
|
||||
KubernetesConfigFlags.AddFlags(cmd.Flags())
|
||||
k8sutil.AddFlags(cmd.Flags())
|
||||
|
||||
return cmd
|
||||
}
|
||||
@@ -73,7 +66,7 @@ func initConfig() {
|
||||
viper.AutomaticEnv()
|
||||
}
|
||||
|
||||
func ensureCollectorInList(list []*troubleshootv1beta1.Collect, collector troubleshootv1beta1.Collect) []*troubleshootv1beta1.Collect {
|
||||
func ensureCollectorInList(list []*troubleshootv1beta2.Collect, collector troubleshootv1beta2.Collect) []*troubleshootv1beta2.Collect {
|
||||
for _, inList := range list {
|
||||
if collector.ClusterResources != nil && inList.ClusterResources != nil {
|
||||
return list
|
||||
|
||||
+442
-130
@@ -1,15 +1,20 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -17,16 +22,21 @@ import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/mholt/archiver"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/replicatedhq/troubleshoot/cmd/util"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
analyzer "github.com/replicatedhq/troubleshoot/pkg/analyze"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme"
|
||||
troubleshootclientsetscheme "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/convert"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/docrewrite"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/redact"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/specs"
|
||||
"github.com/spf13/viper"
|
||||
spin "github.com/tj/go-spin"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -50,42 +60,53 @@ func runTroubleshoot(v *viper.Viper, arg string) error {
|
||||
return errors.Wrap(err, "failed to load collector spec")
|
||||
}
|
||||
|
||||
multidocs := strings.Split(string(collectorContent), "---")
|
||||
multidocs := strings.Split(string(collectorContent), "\n---\n")
|
||||
|
||||
// we suppory both raw collector kinds and supportbundle kinds here
|
||||
supportBundleSpec, err := parseSupportBundleFromDoc([]byte(multidocs[0]))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse collector")
|
||||
}
|
||||
|
||||
troubleshootclientsetscheme.AddToScheme(scheme.Scheme)
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
obj, _, err := decode([]byte(multidocs[0]), nil, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse %s", arg)
|
||||
}
|
||||
|
||||
collector := obj.(*troubleshootv1beta1.Collector)
|
||||
|
||||
additionalRedactors := &troubleshootv1beta1.Redactor{}
|
||||
additionalRedactors := &troubleshootv1beta2.Redactor{}
|
||||
for idx, redactor := range v.GetStringSlice("redactors") {
|
||||
redactorContent, err := loadSpec(v, redactor)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to load redactor spec #%d", idx)
|
||||
}
|
||||
redactorContent, err = docrewrite.ConvertToV1Beta2(redactorContent)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to convert to v1beta2")
|
||||
}
|
||||
obj, _, err := decode([]byte(redactorContent), nil, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse redactors %s", redactor)
|
||||
}
|
||||
loopRedactors, ok := obj.(*troubleshootv1beta1.Redactor)
|
||||
loopRedactors, ok := obj.(*troubleshootv1beta2.Redactor)
|
||||
if !ok {
|
||||
return fmt.Errorf("%s is not a troubleshootv1beta1 redactor type", redactor)
|
||||
return fmt.Errorf("%s is not a troubleshootv1beta2 redactor type", redactor)
|
||||
}
|
||||
if loopRedactors != nil {
|
||||
additionalRedactors.Spec.Redactors = append(additionalRedactors.Spec.Redactors, loopRedactors.Spec.Redactors...)
|
||||
}
|
||||
}
|
||||
|
||||
for i, additionalDoc := range multidocs[1:] {
|
||||
obj, _, err := decode([]byte(additionalDoc), nil, nil)
|
||||
for i, additionalDoc := range multidocs {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
additionalDoc, err := docrewrite.ConvertToV1Beta2([]byte(additionalDoc))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to convert to v1beta2")
|
||||
}
|
||||
obj, _, err := decode(additionalDoc, nil, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse additional doc %d", i)
|
||||
}
|
||||
multidocRedactors, ok := obj.(*troubleshootv1beta1.Redactor)
|
||||
multidocRedactors, ok := obj.(*troubleshootv1beta2.Redactor)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@@ -95,6 +116,7 @@ func runTroubleshoot(v *viper.Viper, arg string) error {
|
||||
s := spin.New()
|
||||
finishedCh := make(chan bool, 1)
|
||||
progressChan := make(chan interface{}, 0) // non-zero buffer can result in missed messages
|
||||
isFinishedChClosed := false
|
||||
go func() {
|
||||
currentDir := ""
|
||||
for {
|
||||
@@ -120,19 +142,90 @@ func runTroubleshoot(v *viper.Viper, arg string) error {
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
close(finishedCh)
|
||||
if !isFinishedChClosed {
|
||||
close(finishedCh)
|
||||
}
|
||||
}()
|
||||
|
||||
archivePath, err := runCollectors(v, *collector, additionalRedactors, progressChan)
|
||||
archivePath, err := runCollectors(v, supportBundleSpec.Spec.Collectors, additionalRedactors, progressChan)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "run collectors")
|
||||
}
|
||||
|
||||
fmt.Printf("\r%s\r", cursor.ClearEntireLine())
|
||||
|
||||
if len(collector.Spec.AfterCollection) == 0 {
|
||||
// upload if needed
|
||||
fileUploaded := false
|
||||
if len(supportBundleSpec.Spec.AfterCollection) > 0 {
|
||||
for _, ac := range supportBundleSpec.Spec.AfterCollection {
|
||||
if ac.UploadResultsTo != nil {
|
||||
if err := uploadSupportBundle(ac.UploadResultsTo, archivePath); err != nil {
|
||||
c := color.New(color.FgHiRed)
|
||||
c.Printf("%s\r * Failed to upload support bundle: %v\n", cursor.ClearEntireLine(), err)
|
||||
} else {
|
||||
fileUploaded = true
|
||||
}
|
||||
} else if ac.Callback != nil {
|
||||
if err := callbackSupportBundleAPI(ac.Callback, archivePath); err != nil {
|
||||
c := color.New(color.FgHiRed)
|
||||
c.Printf("%s\r * Failed to notify API that support bundle has been uploaded: %v\n", cursor.ClearEntireLine(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// perform analysis, if possible
|
||||
if len(supportBundleSpec.Spec.Analyzers) > 0 {
|
||||
tmpDir, err := ioutil.TempDir("", "troubleshoot")
|
||||
if err != nil {
|
||||
c := color.New(color.FgHiRed)
|
||||
c.Printf("%s\r * Failed to make directory for analysis: %v\n", cursor.ClearEntireLine(), err)
|
||||
}
|
||||
|
||||
f, err := os.Open(archivePath)
|
||||
if err != nil {
|
||||
c := color.New(color.FgHiRed)
|
||||
c.Printf("%s\r * Failed to open support bundle for analysis: %v\n", cursor.ClearEntireLine(), err)
|
||||
|
||||
}
|
||||
if err := analyzer.ExtractTroubleshootBundle(f, tmpDir); err != nil {
|
||||
c := color.New(color.FgHiRed)
|
||||
c.Printf("%s\r * Failed to extract support bundle for analysis: %v\n", cursor.ClearEntireLine(), err)
|
||||
}
|
||||
|
||||
analyzeResults, err := analyzer.AnalyzeLocal(tmpDir, supportBundleSpec.Spec.Analyzers)
|
||||
if err != nil {
|
||||
c := color.New(color.FgHiRed)
|
||||
c.Printf("%s\r * Failed to analyze support bundle: %v\n", cursor.ClearEntireLine(), err)
|
||||
}
|
||||
|
||||
interactive := isatty.IsTerminal(os.Stdout.Fd())
|
||||
|
||||
if interactive {
|
||||
close(finishedCh) // this removes the spinner
|
||||
isFinishedChClosed = true
|
||||
|
||||
if err := showInteractiveResults(supportBundleSpec.Name, analyzeResults); err != nil {
|
||||
interactive = false
|
||||
}
|
||||
}
|
||||
|
||||
if !interactive {
|
||||
data := convert.FromAnalyzerResult(analyzeResults)
|
||||
formatted, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
c := color.New(color.FgHiRed)
|
||||
c.Printf("%s\r * Failed to format analysis: %v\n", cursor.ClearEntireLine(), err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s", formatted)
|
||||
}
|
||||
}
|
||||
|
||||
if !fileUploaded {
|
||||
msg := archivePath
|
||||
if appName := collector.Labels["applicationName"]; appName != "" {
|
||||
if appName := supportBundleSpec.Labels["applicationName"]; appName != "" {
|
||||
f := `A support bundle for %s has been created in this directory
|
||||
named %s. Please upload it on the Troubleshoot page of
|
||||
the %s Admin Console to begin analysis.`
|
||||
@@ -144,23 +237,6 @@ the %s Admin Console to begin analysis.`
|
||||
return nil
|
||||
}
|
||||
|
||||
fileUploaded := false
|
||||
for _, ac := range collector.Spec.AfterCollection {
|
||||
if ac.UploadResultsTo != nil {
|
||||
if err := uploadSupportBundle(ac.UploadResultsTo, archivePath); err != nil {
|
||||
c := color.New(color.FgHiRed)
|
||||
c.Printf("%s\r * Failed to upload support bundle: %v\n", cursor.ClearEntireLine(), err)
|
||||
} else {
|
||||
fileUploaded = true
|
||||
}
|
||||
} else if ac.Callback != nil {
|
||||
if err := callbackSupportBundleAPI(ac.Callback, archivePath); err != nil {
|
||||
c := color.New(color.FgHiRed)
|
||||
c.Printf("%s\r * Failed to notify API that support bundle has been uploaded: %v\n", cursor.ClearEntireLine(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("\r%s\r", cursor.ClearEntireLine())
|
||||
if fileUploaded {
|
||||
fmt.Printf("A support bundle has been created and uploaded to your cluster for analysis. Please visit the Troubleshoot page to continue.\n")
|
||||
@@ -173,6 +249,21 @@ the %s Admin Console to begin analysis.`
|
||||
|
||||
func loadSpec(v *viper.Viper, arg string) ([]byte, error) {
|
||||
var err error
|
||||
if strings.HasPrefix(arg, "secret/") {
|
||||
// format secret/namespace-name/secret-name
|
||||
pathParts := strings.Split(arg, "/")
|
||||
if len(pathParts) != 3 {
|
||||
return nil, errors.Errorf("path %s must have 3 components", arg)
|
||||
}
|
||||
|
||||
spec, err := specs.LoadFromSecret(pathParts[1], pathParts[2], "support-bundle-spec")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get spec from secret")
|
||||
}
|
||||
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
if _, err = os.Stat(arg); err == nil {
|
||||
b, err := ioutil.ReadFile(arg)
|
||||
if err != nil {
|
||||
@@ -184,6 +275,14 @@ func loadSpec(v *viper.Viper, arg string) ([]byte, error) {
|
||||
return nil, fmt.Errorf("%s is not a URL and was not found (err %s)", arg, err)
|
||||
}
|
||||
|
||||
spec, err := loadSpecFromURL(v, arg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get spec from URL")
|
||||
}
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
func loadSpecFromURL(v *viper.Viper, arg string) ([]byte, error) {
|
||||
for {
|
||||
req, err := http.NewRequest("GET", arg, nil)
|
||||
if err != nil {
|
||||
@@ -193,10 +292,7 @@ func loadSpec(v *viper.Viper, arg string) ([]byte, error) {
|
||||
req.Header.Set("Bundle-Upload-Host", fmt.Sprintf("%s://%s", req.URL.Scheme, req.URL.Host))
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "x509") && httpClient == http.DefaultClient && canTryInsecure(v) {
|
||||
httpClient = &http.Client{Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}}
|
||||
if shouldRetryRequest(err) {
|
||||
continue
|
||||
}
|
||||
return nil, errors.Wrap(err, "execute request")
|
||||
@@ -212,7 +308,57 @@ func loadSpec(v *viper.Viper, arg string) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func canTryInsecure(v *viper.Viper) bool {
|
||||
func parseSupportBundleFromDoc(doc []byte) (*troubleshootv1beta2.SupportBundle, error) {
|
||||
doc, err := docrewrite.ConvertToV1Beta2(doc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert to v1beta2")
|
||||
}
|
||||
|
||||
troubleshootclientsetscheme.AddToScheme(scheme.Scheme)
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
|
||||
obj, _, err := decode(doc, nil, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse document")
|
||||
}
|
||||
|
||||
collector, ok := obj.(*troubleshootv1beta2.Collector)
|
||||
if ok {
|
||||
supportBundle := troubleshootv1beta2.SupportBundle{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "troubleshoot.sh/v1beta2",
|
||||
Kind: "SupportBundle",
|
||||
},
|
||||
ObjectMeta: collector.ObjectMeta,
|
||||
Spec: troubleshootv1beta2.SupportBundleSpec{
|
||||
Collectors: collector.Spec.Collectors,
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{},
|
||||
AfterCollection: collector.Spec.AfterCollection,
|
||||
},
|
||||
}
|
||||
|
||||
return &supportBundle, nil
|
||||
}
|
||||
|
||||
supportBundle, ok := obj.(*troubleshootv1beta2.SupportBundle)
|
||||
if ok {
|
||||
return supportBundle, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("spec was not parseable as a troubleshoot kind")
|
||||
}
|
||||
|
||||
func shouldRetryRequest(err error) bool {
|
||||
if strings.Contains(err.Error(), "x509") && httpClient == http.DefaultClient && canTryInsecure() {
|
||||
httpClient = &http.Client{Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func canTryInsecure() bool {
|
||||
if !isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
return false
|
||||
}
|
||||
@@ -229,44 +375,55 @@ func canTryInsecure(v *viper.Viper) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, additionalRedactors *troubleshootv1beta1.Redactor, progressChan chan interface{}) (string, error) {
|
||||
bundlePath, err := ioutil.TempDir("", "troubleshoot")
|
||||
func runCollectors(v *viper.Viper, collectors []*troubleshootv1beta2.Collect, additionalRedactors *troubleshootv1beta2.Redactor, progressChan chan interface{}) (string, error) {
|
||||
tmpDir, err := ioutil.TempDir("", "troubleshoot")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "create temp dir")
|
||||
}
|
||||
defer os.RemoveAll(bundlePath)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
filename, err := findFileName("support-bundle-"+time.Now().Format("2006-01-02T15_04_05"), "tar.gz")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "find file name")
|
||||
}
|
||||
|
||||
bundlePath := filepath.Join(tmpDir, strings.TrimSuffix(filename, ".tar.gz"))
|
||||
if err := os.MkdirAll(bundlePath, 0777); err != nil {
|
||||
return "", errors.Wrap(err, "create bundle dir")
|
||||
}
|
||||
|
||||
if err = writeVersionFile(bundlePath); err != nil {
|
||||
return "", errors.Wrap(err, "write version file")
|
||||
}
|
||||
|
||||
collectSpecs := make([]*troubleshootv1beta1.Collect, 0, 0)
|
||||
collectSpecs = append(collectSpecs, collector.Spec.Collectors...)
|
||||
collectSpecs = ensureCollectorInList(collectSpecs, troubleshootv1beta1.Collect{ClusterInfo: &troubleshootv1beta1.ClusterInfo{}})
|
||||
collectSpecs = ensureCollectorInList(collectSpecs, troubleshootv1beta1.Collect{ClusterResources: &troubleshootv1beta1.ClusterResources{}})
|
||||
collectSpecs := make([]*troubleshootv1beta2.Collect, 0, 0)
|
||||
collectSpecs = append(collectSpecs, collectors...)
|
||||
collectSpecs = ensureCollectorInList(collectSpecs, troubleshootv1beta2.Collect{ClusterInfo: &troubleshootv1beta2.ClusterInfo{}})
|
||||
collectSpecs = ensureCollectorInList(collectSpecs, troubleshootv1beta2.Collect{ClusterResources: &troubleshootv1beta2.ClusterResources{}})
|
||||
|
||||
config, err := KubernetesConfigFlags.ToRESTConfig()
|
||||
config, err := k8sutil.GetRESTConfig()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to convert kube flags to rest config")
|
||||
}
|
||||
|
||||
var collectors collect.Collectors
|
||||
var cleanedCollectors collect.Collectors
|
||||
for _, desiredCollector := range collectSpecs {
|
||||
collector := collect.Collector{
|
||||
Redact: true,
|
||||
Collect: desiredCollector,
|
||||
ClientConfig: config,
|
||||
Namespace: v.GetString("namespace"),
|
||||
PathPrefix: filepath.Base(bundlePath),
|
||||
}
|
||||
collectors = append(collectors, &collector)
|
||||
cleanedCollectors = append(cleanedCollectors, &collector)
|
||||
}
|
||||
|
||||
if err := collectors.CheckRBAC(); err != nil {
|
||||
if err := cleanedCollectors.CheckRBAC(context.Background()); err != nil {
|
||||
return "", errors.Wrap(err, "failed to check RBAC for collectors")
|
||||
}
|
||||
|
||||
foundForbidden := false
|
||||
for _, c := range collectors {
|
||||
for _, c := range cleanedCollectors {
|
||||
for _, e := range c.RBACErrors {
|
||||
foundForbidden = true
|
||||
progressChan <- e
|
||||
@@ -277,13 +434,19 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, addi
|
||||
return "", errors.New("insufficient permissions to run all collectors")
|
||||
}
|
||||
|
||||
globalRedactors := []*troubleshootv1beta1.Redact{}
|
||||
globalRedactors := []*troubleshootv1beta2.Redact{}
|
||||
if additionalRedactors != nil {
|
||||
globalRedactors = additionalRedactors.Spec.Redactors
|
||||
}
|
||||
if v.GetString("since-time") != "" || v.GetString("since") != "" {
|
||||
err := parseTimeFlags(v, progressChan, &cleanedCollectors)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// Run preflights collectors synchronously
|
||||
for _, collector := range collectors {
|
||||
for _, collector := range cleanedCollectors {
|
||||
if len(collector.RBACErrors) > 0 {
|
||||
// don't skip clusterResources collector due to RBAC issues
|
||||
if collector.Collect.ClusterResources == nil {
|
||||
@@ -301,7 +464,8 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, addi
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
err = saveCollectorOutput(result, bundlePath)
|
||||
// results already contain the bundle dir name in their paths
|
||||
err = saveCollectorOutput(result, filepath.Dir(bundlePath), collector)
|
||||
if err != nil {
|
||||
progressChan <- fmt.Errorf("failed to parse collector spec %q: %v", collector.GetDisplayName(), err)
|
||||
continue
|
||||
@@ -309,11 +473,6 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, addi
|
||||
}
|
||||
}
|
||||
|
||||
filename, err := findFileName("support-bundle", "tar.gz")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "find file name")
|
||||
}
|
||||
|
||||
if err := tarSupportBundleDir(bundlePath, filename); err != nil {
|
||||
return "", errors.Wrap(err, "create bundle file")
|
||||
}
|
||||
@@ -321,8 +480,15 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, addi
|
||||
return filename, nil
|
||||
}
|
||||
|
||||
func saveCollectorOutput(output map[string][]byte, bundlePath string) error {
|
||||
func saveCollectorOutput(output map[string][]byte, bundlePath string, c *collect.Collector) error {
|
||||
for filename, maybeContents := range output {
|
||||
if c.Collect.Copy != nil {
|
||||
err := untarAndSave(maybeContents, filepath.Join(bundlePath, filepath.Dir(filename)))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "extract copied files")
|
||||
}
|
||||
continue
|
||||
}
|
||||
fileDir, fileName := filepath.Split(filename)
|
||||
outPath := filepath.Join(bundlePath, fileDir)
|
||||
|
||||
@@ -338,39 +504,99 @@ func saveCollectorOutput(output map[string][]byte, bundlePath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func uploadSupportBundle(r *troubleshootv1beta1.ResultRequest, archivePath string) error {
|
||||
func untarAndSave(tarFile []byte, bundlePath string) error {
|
||||
keys := make([]string, 0)
|
||||
dirs := make(map[string]*tar.Header)
|
||||
files := make(map[string][]byte)
|
||||
fileHeaders := make(map[string]*tar.Header)
|
||||
tarReader := tar.NewReader(bytes.NewBuffer(tarFile))
|
||||
//Extract and separate tar contentes in file and folders, keeping header info from each one.
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
dirs[header.Name] = header
|
||||
case tar.TypeReg:
|
||||
file := new(bytes.Buffer)
|
||||
_, err = io.Copy(file, tarReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
files[header.Name] = file.Bytes()
|
||||
fileHeaders[header.Name] = header
|
||||
default:
|
||||
return fmt.Errorf("Tar file entry %s contained unsupported file type %v", header.Name, header.FileInfo().Mode())
|
||||
}
|
||||
}
|
||||
//Create directories from base path: <namespace>/<pod name>/containerPath
|
||||
if err := os.MkdirAll(filepath.Join(bundlePath), 0777); err != nil {
|
||||
return errors.Wrap(err, "create output file")
|
||||
}
|
||||
//Order folders stored in variable keys to start always by parent folder. That way folder info is preserved.
|
||||
for k := range dirs {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
//Orderly create folders.
|
||||
for _, k := range keys {
|
||||
if err := os.Mkdir(filepath.Join(bundlePath, k), dirs[k].FileInfo().Mode().Perm()); err != nil {
|
||||
return errors.Wrap(err, "create output file")
|
||||
}
|
||||
}
|
||||
//Populate folders with respective files and its permissions stored in the header.
|
||||
for k, v := range files {
|
||||
if err := ioutil.WriteFile(filepath.Join(bundlePath, k), v, fileHeaders[k].FileInfo().Mode().Perm()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func uploadSupportBundle(r *troubleshootv1beta2.ResultRequest, archivePath string) error {
|
||||
contentType := getExpectedContentType(r.URI)
|
||||
if contentType != "" && contentType != "application/tar+gzip" {
|
||||
return fmt.Errorf("cannot upload content type %s", contentType)
|
||||
}
|
||||
|
||||
f, err := os.Open(archivePath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "open file")
|
||||
}
|
||||
defer f.Close()
|
||||
for {
|
||||
f, err := os.Open(archivePath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "open file")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fileStat, err := f.Stat()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "stat file")
|
||||
}
|
||||
fileStat, err := f.Stat()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "stat file")
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(r.Method, r.URI, f)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create request")
|
||||
}
|
||||
req.ContentLength = fileStat.Size()
|
||||
if contentType != "" {
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
}
|
||||
req, err := http.NewRequest(r.Method, r.URI, f)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create request")
|
||||
}
|
||||
req.ContentLength = fileStat.Size()
|
||||
if contentType != "" {
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
}
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "execute request")
|
||||
}
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
if shouldRetryRequest(err) {
|
||||
continue
|
||||
}
|
||||
return errors.Wrap(err, "execute request")
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("unexpected status code %d", resp.StatusCode)
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("unexpected status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
// send redaction report
|
||||
@@ -384,19 +610,26 @@ func uploadSupportBundle(r *troubleshootv1beta1.ResultRequest, archivePath strin
|
||||
return errors.Wrap(err, "get redaction report")
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("PUT", r.RedactURI, bytes.NewReader(redactBytes))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create redaction report request")
|
||||
}
|
||||
req.ContentLength = int64(len(redactBytes))
|
||||
for {
|
||||
req, err := http.NewRequest("PUT", r.RedactURI, bytes.NewReader(redactBytes))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create redaction report request")
|
||||
}
|
||||
req.ContentLength = int64(len(redactBytes))
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "execute redaction request")
|
||||
}
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
if shouldRetryRequest(err) {
|
||||
continue
|
||||
}
|
||||
return errors.Wrap(err, "execute redaction request")
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("unexpected redaction status code %d", resp.StatusCode)
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("unexpected redaction status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,54 +644,133 @@ func getExpectedContentType(uploadURL string) string {
|
||||
return parsedURL.Query().Get("Content-Type")
|
||||
}
|
||||
|
||||
func callbackSupportBundleAPI(r *troubleshootv1beta1.ResultRequest, archivePath string) error {
|
||||
req, err := http.NewRequest(r.Method, r.URI, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create request")
|
||||
}
|
||||
func callbackSupportBundleAPI(r *troubleshootv1beta2.ResultRequest, archivePath string) error {
|
||||
for {
|
||||
req, err := http.NewRequest(r.Method, r.URI, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create request")
|
||||
}
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "execute request")
|
||||
}
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
if shouldRetryRequest(err) {
|
||||
continue
|
||||
}
|
||||
return errors.Wrap(err, "execute request")
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("unexpected status code %d", resp.StatusCode)
|
||||
}
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("unexpected status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tarSupportBundleDir(inputDir, outputFilename string) error {
|
||||
tarGz := archiver.TarGz{
|
||||
Tar: &archiver.Tar{
|
||||
ImplicitTopLevelFolder: false,
|
||||
},
|
||||
}
|
||||
|
||||
paths := []string{
|
||||
filepath.Join(inputDir, VersionFilename), // version file should be first in tar archive for quick extraction
|
||||
}
|
||||
|
||||
topLevelFiles, err := ioutil.ReadDir(inputDir)
|
||||
fileWriter, err := os.Create(outputFilename)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "list bundle directory contents")
|
||||
}
|
||||
for _, f := range topLevelFiles {
|
||||
if f.Name() == VersionFilename {
|
||||
continue
|
||||
}
|
||||
paths = append(paths, filepath.Join(inputDir, f.Name()))
|
||||
return errors.Wrap(err, "failed to create output file")
|
||||
}
|
||||
defer fileWriter.Close()
|
||||
|
||||
if err := tarGz.Archive(paths, outputFilename); err != nil {
|
||||
return errors.Wrap(err, "create archive")
|
||||
gzipWriter := gzip.NewWriter(fileWriter)
|
||||
defer gzipWriter.Close()
|
||||
|
||||
tarWriter := tar.NewWriter(gzipWriter)
|
||||
defer tarWriter.Close()
|
||||
|
||||
err = filepath.Walk(inputDir, func(filename string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fileMode := info.Mode()
|
||||
if !fileMode.IsRegular() { // support bundle can have only files
|
||||
return nil
|
||||
}
|
||||
|
||||
nameInArchive, err := filepath.Rel(inputDir, filename)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create relative file name")
|
||||
}
|
||||
|
||||
// tar.FileInfoHeader call causes a crash in static builds
|
||||
// https://github.com/golang/go/issues/24787
|
||||
hdr := &tar.Header{
|
||||
Name: nameInArchive,
|
||||
ModTime: info.ModTime(),
|
||||
Mode: int64(fileMode.Perm()),
|
||||
Typeflag: tar.TypeReg,
|
||||
Size: info.Size(),
|
||||
}
|
||||
|
||||
err = tarWriter.WriteHeader(hdr)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write tar header")
|
||||
}
|
||||
|
||||
err = func() error {
|
||||
fileReader, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to open source file")
|
||||
}
|
||||
defer fileReader.Close()
|
||||
|
||||
_, err = io.Copy(tarWriter, fileReader)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to copy file into archive")
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to walk source dir")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type CollectorFailure struct {
|
||||
Collector *troubleshootv1beta1.Collect
|
||||
Collector *troubleshootv1beta2.Collect
|
||||
Failure string
|
||||
}
|
||||
|
||||
func parseTimeFlags(v *viper.Viper, progressChan chan interface{}, collectors *collect.Collectors) error {
|
||||
var (
|
||||
sinceTime time.Time
|
||||
err error
|
||||
)
|
||||
if v.GetString("since-time") != "" {
|
||||
if v.GetString("since") != "" {
|
||||
return errors.Errorf("at most one of `sinceTime` or `since` may be specified")
|
||||
}
|
||||
sinceTime, err = time.Parse(time.RFC3339, v.GetString("since-time"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to parse --since-time flag")
|
||||
}
|
||||
} else {
|
||||
parsedDuration, err := time.ParseDuration(v.GetString("since"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to parse --since flag")
|
||||
}
|
||||
now := time.Now()
|
||||
sinceTime = now.Add(0 - parsedDuration)
|
||||
}
|
||||
for _, collector := range *collectors {
|
||||
if collector.Collect.Logs != nil {
|
||||
if collector.Collect.Logs.Limits == nil {
|
||||
collector.Collect.Logs.Limits = new(troubleshootv1beta2.LogLimits)
|
||||
}
|
||||
collector.Collect.Logs.Limits.SinceTime = metav1.NewTime(sinceTime)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
func createServiceAccount(collector troubleshootv1beta1.Collector, namespace string, clientset *kubernetes.Clientset) (string, error) {
|
||||
name := fmt.Sprintf("troubleshoot-%s", collector.Name)
|
||||
|
||||
serviceAccount := corev1.ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ServiceAccount",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
}
|
||||
_, err := clientset.CoreV1().ServiceAccounts(namespace).Create(&serviceAccount)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
role := rbacv1.ClusterRole{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ClusterRole",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Rules: []rbacv1.PolicyRule{
|
||||
{
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{
|
||||
"namespaces",
|
||||
"pods",
|
||||
"services",
|
||||
"secrets",
|
||||
},
|
||||
Verbs: metav1.Verbs{"list"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{"apps"},
|
||||
Resources: []string{"deployments"},
|
||||
Verbs: metav1.Verbs{"list"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{"extensions"},
|
||||
Resources: []string{"ingresses"},
|
||||
Verbs: metav1.Verbs{"list"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{"storage.k8s.io"},
|
||||
Resources: []string{"storageclasses"},
|
||||
Verbs: metav1.Verbs{"list"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{"apiextensions.k8s.io"},
|
||||
Resources: []string{"customresourcedefinitions"},
|
||||
Verbs: metav1.Verbs{"list"},
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err = clientset.RbacV1().ClusterRoles().Create(&role)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
roleBinding := rbacv1.ClusterRoleBinding{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ClusterRoleBinding",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Subjects: []rbacv1.Subject{
|
||||
{
|
||||
Kind: "ServiceAccount",
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
APIGroup: "rbac.authorization.k8s.io",
|
||||
Kind: "ClusterRole",
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
_, err = clientset.RbacV1().ClusterRoleBindings().Create(&roleBinding)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func removeServiceAccount(name string, namespace string, clientset *kubernetes.Clientset) error {
|
||||
if err := clientset.RbacV1().ClusterRoleBindings().Delete(name, &metav1.DeleteOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := clientset.RbacV1().ClusterRoles().Delete(name, &metav1.DeleteOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := clientset.CoreV1().ServiceAccounts(namespace).Delete(name, &metav1.DeleteOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -5,24 +5,8 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootclientv1beta1 "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/typed/troubleshoot/v1beta1"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
)
|
||||
|
||||
func createTroubleshootK8sClient(configFlags *genericclioptions.ConfigFlags) (*troubleshootclientv1beta1.TroubleshootV1beta1Client, error) {
|
||||
config, err := configFlags.ToRESTConfig()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert kube flags to rest config")
|
||||
}
|
||||
|
||||
troubleshootClient, err := troubleshootclientv1beta1.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create troubleshoot client")
|
||||
}
|
||||
|
||||
return troubleshootClient, nil
|
||||
}
|
||||
|
||||
func findFileName(basename, extension string) (string, error) {
|
||||
n := 1
|
||||
name := basename
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/version"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -29,10 +29,10 @@ func VersionCmd() *cobra.Command {
|
||||
const VersionFilename = "version.yaml"
|
||||
|
||||
func writeVersionFile(path string) error {
|
||||
version := troubleshootv1beta1.SupportBundleVersion{
|
||||
ApiVersion: "troubleshoot.replicated.com/v1beta1",
|
||||
version := troubleshootv1beta2.SupportBundleVersion{
|
||||
ApiVersion: "troubleshoot.sh/v1beta2",
|
||||
Kind: "SupportBundle",
|
||||
Spec: troubleshootv1beta1.SupportBundleVersionSpec{
|
||||
Spec: troubleshootv1beta2.SupportBundleVersionSpec{
|
||||
VersionNumber: version.Version(),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/cmd/troubleshoot/cli"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -3,6 +3,7 @@ package util
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func HomeDir() string {
|
||||
@@ -20,3 +21,19 @@ func IsURL(str string) bool {
|
||||
|
||||
return parsed.Scheme != ""
|
||||
}
|
||||
|
||||
func AppName(name string) string {
|
||||
words := strings.Split(strings.Title(strings.Replace(name, "-", " ", -1)), " ")
|
||||
casedWords := []string{}
|
||||
for i, word := range words {
|
||||
if strings.ToLower(word) == "ai" {
|
||||
casedWords = append(casedWords, "AI")
|
||||
} else if strings.ToLower(word) == "io" && i > 0 {
|
||||
casedWords[i-1] += ".io"
|
||||
} else {
|
||||
casedWords = append(casedWords, word)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(casedWords, " ")
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.4
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: analyzers.troubleshoot.replicated.com
|
||||
spec:
|
||||
@@ -42,7 +42,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -83,7 +88,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -126,7 +136,12 @@ spec:
|
||||
customResourceDefinitionName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -168,7 +183,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -215,7 +235,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -256,7 +281,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -300,7 +330,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
ingressName:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -342,12 +377,68 @@ spec:
|
||||
- namespace
|
||||
- outcomes
|
||||
type: object
|
||||
mysql:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
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
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
nodeResources:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
filters:
|
||||
properties:
|
||||
cpuAllocatable:
|
||||
@@ -366,6 +457,13 @@ spec:
|
||||
type: string
|
||||
podCapacity:
|
||||
type: string
|
||||
selector:
|
||||
properties:
|
||||
matchLabel:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
outcomes:
|
||||
items:
|
||||
@@ -402,12 +500,119 @@ spec:
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
postgres:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
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
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
redis:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
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
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
secret:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
key:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -456,7 +661,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -503,7 +713,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -549,7 +764,12 @@ spec:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
type: string
|
||||
outcomes:
|
||||
|
||||
@@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.4
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: collectors.troubleshoot.replicated.com
|
||||
spec:
|
||||
@@ -41,20 +41,26 @@ spec:
|
||||
properties:
|
||||
method:
|
||||
type: string
|
||||
redactUri:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- method
|
||||
- redactUri
|
||||
- uri
|
||||
type: object
|
||||
uploadResultsTo:
|
||||
properties:
|
||||
method:
|
||||
type: string
|
||||
redactUri:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- method
|
||||
- redactUri
|
||||
- uri
|
||||
type: object
|
||||
type: object
|
||||
@@ -67,14 +73,24 @@ spec:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
type: object
|
||||
clusterResources:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
type: object
|
||||
copy:
|
||||
properties:
|
||||
@@ -85,7 +101,12 @@ spec:
|
||||
containerPath:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -106,7 +127,12 @@ spec:
|
||||
data:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
@@ -127,7 +153,12 @@ spec:
|
||||
containerName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -147,7 +178,12 @@ spec:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
get:
|
||||
properties:
|
||||
headers:
|
||||
@@ -203,7 +239,12 @@ spec:
|
||||
type: string
|
||||
type: array
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
limits:
|
||||
properties:
|
||||
maxAge:
|
||||
@@ -223,6 +264,54 @@ spec:
|
||||
required:
|
||||
- selector
|
||||
type: object
|
||||
mysql:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- uri
|
||||
type: object
|
||||
postgres:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- uri
|
||||
type: object
|
||||
redis:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- uri
|
||||
type: object
|
||||
run:
|
||||
properties:
|
||||
args:
|
||||
@@ -236,7 +325,12 @@ spec:
|
||||
type: string
|
||||
type: array
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
image:
|
||||
type: string
|
||||
imagePullPolicy:
|
||||
@@ -256,7 +350,12 @@ spec:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
includeValue:
|
||||
type: boolean
|
||||
key:
|
||||
|
||||
@@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.4
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: preflights.troubleshoot.replicated.com
|
||||
spec:
|
||||
@@ -42,7 +42,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -83,7 +88,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -126,7 +136,12 @@ spec:
|
||||
customResourceDefinitionName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -168,7 +183,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -215,7 +235,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -256,7 +281,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -300,7 +330,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
ingressName:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -342,12 +377,68 @@ spec:
|
||||
- namespace
|
||||
- outcomes
|
||||
type: object
|
||||
mysql:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
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
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
nodeResources:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
filters:
|
||||
properties:
|
||||
cpuAllocatable:
|
||||
@@ -366,6 +457,13 @@ spec:
|
||||
type: string
|
||||
podCapacity:
|
||||
type: string
|
||||
selector:
|
||||
properties:
|
||||
matchLabel:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
outcomes:
|
||||
items:
|
||||
@@ -402,12 +500,119 @@ spec:
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
postgres:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
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
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
redis:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
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
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
secret:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
key:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -456,7 +661,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -503,7 +713,12 @@ spec:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
outcomes:
|
||||
items:
|
||||
properties:
|
||||
@@ -549,7 +764,12 @@ spec:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
type: string
|
||||
outcomes:
|
||||
@@ -601,14 +821,24 @@ spec:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
type: object
|
||||
clusterResources:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
type: object
|
||||
copy:
|
||||
properties:
|
||||
@@ -619,7 +849,12 @@ spec:
|
||||
containerPath:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -640,7 +875,12 @@ spec:
|
||||
data:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
@@ -661,7 +901,12 @@ spec:
|
||||
containerName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
@@ -681,7 +926,12 @@ spec:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
get:
|
||||
properties:
|
||||
headers:
|
||||
@@ -737,7 +987,12 @@ spec:
|
||||
type: string
|
||||
type: array
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
limits:
|
||||
properties:
|
||||
maxAge:
|
||||
@@ -757,6 +1012,54 @@ spec:
|
||||
required:
|
||||
- selector
|
||||
type: object
|
||||
mysql:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- uri
|
||||
type: object
|
||||
postgres:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- uri
|
||||
type: object
|
||||
redis:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- uri
|
||||
type: object
|
||||
run:
|
||||
properties:
|
||||
args:
|
||||
@@ -770,7 +1073,12 @@ spec:
|
||||
type: string
|
||||
type: array
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
image:
|
||||
type: string
|
||||
imagePullPolicy:
|
||||
@@ -790,7 +1098,12 @@ spec:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
type: boolean
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
includeValue:
|
||||
type: boolean
|
||||
key:
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: redactors.troubleshoot.replicated.com
|
||||
spec:
|
||||
group: troubleshoot.replicated.com
|
||||
names:
|
||||
kind: Redactor
|
||||
listKind: RedactorList
|
||||
plural: redactors
|
||||
singular: redactor
|
||||
scope: Namespaced
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
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'
|
||||
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'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: RedactorSpec defines the desired state of Redactor
|
||||
properties:
|
||||
redactors:
|
||||
items:
|
||||
properties:
|
||||
fileSelector:
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
files:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
name:
|
||||
type: string
|
||||
removals:
|
||||
properties:
|
||||
regex:
|
||||
items:
|
||||
properties:
|
||||
redactor:
|
||||
type: string
|
||||
selector:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
values:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
yamlPath:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
status:
|
||||
description: RedactorStatus defines the observed state of Redactor
|
||||
type: object
|
||||
type: object
|
||||
version: v1beta1
|
||||
versions:
|
||||
- name: v1beta1
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,831 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: analyzers.troubleshoot.sh
|
||||
spec:
|
||||
group: troubleshoot.sh
|
||||
names:
|
||||
kind: Analyzer
|
||||
listKind: AnalyzerList
|
||||
plural: analyzers
|
||||
singular: analyzer
|
||||
scope: Namespaced
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
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'
|
||||
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'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: AnalyzerSpec defines the desired state of Analyzer
|
||||
properties:
|
||||
analyzers:
|
||||
items:
|
||||
properties:
|
||||
clusterVersion:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
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
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
containerRuntime:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
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
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
customResourceDefinition:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
customResourceDefinitionName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
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
|
||||
required:
|
||||
- customResourceDefinitionName
|
||||
- outcomes
|
||||
type: object
|
||||
deploymentStatus:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
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
|
||||
required:
|
||||
- name
|
||||
- namespace
|
||||
- outcomes
|
||||
type: object
|
||||
distribution:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
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
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
imagePullSecret:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
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
|
||||
registryName:
|
||||
type: string
|
||||
required:
|
||||
- outcomes
|
||||
- registryName
|
||||
type: object
|
||||
ingress:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
ingressName:
|
||||
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
|
||||
required:
|
||||
- ingressName
|
||||
- namespace
|
||||
- outcomes
|
||||
type: object
|
||||
mysql:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
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
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
nodeResources:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
filters:
|
||||
properties:
|
||||
cpuAllocatable:
|
||||
type: string
|
||||
cpuCapacity:
|
||||
type: string
|
||||
ephemeralStorageAllocatable:
|
||||
type: string
|
||||
ephemeralStorageCapacity:
|
||||
type: string
|
||||
memoryAllocatable:
|
||||
type: string
|
||||
memoryCapacity:
|
||||
type: string
|
||||
podAllocatable:
|
||||
type: string
|
||||
podCapacity:
|
||||
type: string
|
||||
selector:
|
||||
properties:
|
||||
matchLabel:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
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
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
postgres:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
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
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
redis:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
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
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
type: object
|
||||
secret:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
key:
|
||||
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
|
||||
secretName:
|
||||
type: string
|
||||
required:
|
||||
- namespace
|
||||
- outcomes
|
||||
- secretName
|
||||
type: object
|
||||
statefulsetStatus:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
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
|
||||
required:
|
||||
- name
|
||||
- namespace
|
||||
- outcomes
|
||||
type: object
|
||||
storageClass:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
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
|
||||
storageClassName:
|
||||
type: string
|
||||
required:
|
||||
- outcomes
|
||||
- storageClassName
|
||||
type: object
|
||||
textAnalyze:
|
||||
properties:
|
||||
checkName:
|
||||
type: string
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
fileName:
|
||||
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
|
||||
regex:
|
||||
type: string
|
||||
regexGroups:
|
||||
type: string
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
status:
|
||||
description: AnalyzerStatus defines the observed state of Analyzer
|
||||
type: object
|
||||
type: object
|
||||
version: v1beta2
|
||||
versions:
|
||||
- name: v1beta2
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
@@ -0,0 +1,387 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: collectors.troubleshoot.sh
|
||||
spec:
|
||||
group: troubleshoot.sh
|
||||
names:
|
||||
kind: Collector
|
||||
listKind: CollectorList
|
||||
plural: collectors
|
||||
singular: collector
|
||||
scope: Namespaced
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
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'
|
||||
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'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: CollectorSpec defines the desired state of Collector
|
||||
properties:
|
||||
afterCollection:
|
||||
items:
|
||||
properties:
|
||||
callback:
|
||||
properties:
|
||||
method:
|
||||
type: string
|
||||
redactUri:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- method
|
||||
- redactUri
|
||||
- uri
|
||||
type: object
|
||||
uploadResultsTo:
|
||||
properties:
|
||||
method:
|
||||
type: string
|
||||
redactUri:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- method
|
||||
- redactUri
|
||||
- uri
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
collectors:
|
||||
items:
|
||||
properties:
|
||||
clusterInfo:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
type: object
|
||||
clusterResources:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
type: object
|
||||
copy:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
containerName:
|
||||
type: string
|
||||
containerPath:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
selector:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- containerPath
|
||||
- namespace
|
||||
- selector
|
||||
type: object
|
||||
data:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
data:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- data
|
||||
type: object
|
||||
exec:
|
||||
properties:
|
||||
args:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
collectorName:
|
||||
type: string
|
||||
command:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
containerName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
selector:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
required:
|
||||
- namespace
|
||||
- selector
|
||||
type: object
|
||||
http:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
get:
|
||||
properties:
|
||||
headers:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
url:
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
type: object
|
||||
name:
|
||||
type: string
|
||||
post:
|
||||
properties:
|
||||
body:
|
||||
type: string
|
||||
headers:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
url:
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
type: object
|
||||
put:
|
||||
properties:
|
||||
body:
|
||||
type: string
|
||||
headers:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
url:
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
type: object
|
||||
type: object
|
||||
logs:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
containerNames:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
limits:
|
||||
properties:
|
||||
maxAge:
|
||||
type: string
|
||||
maxLines:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
selector:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- selector
|
||||
type: object
|
||||
mysql:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- uri
|
||||
type: object
|
||||
postgres:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- uri
|
||||
type: object
|
||||
redis:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- uri
|
||||
type: object
|
||||
run:
|
||||
properties:
|
||||
args:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
collectorName:
|
||||
type: string
|
||||
command:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
image:
|
||||
type: string
|
||||
imagePullPolicy:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
timeout:
|
||||
type: string
|
||||
required:
|
||||
- image
|
||||
- namespace
|
||||
type: object
|
||||
secret:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
exclude:
|
||||
description: BoolOrString is a type that can hold an bool
|
||||
or a string. When used in JSON or YAML marshalling and
|
||||
unmarshalling, it produces or consumes the inner type. This
|
||||
allows you to have, for example, a JSON field that can accept
|
||||
a booolean string or raw bool.
|
||||
type: BoolString
|
||||
includeValue:
|
||||
type: boolean
|
||||
key:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
status:
|
||||
description: CollectorStatus defines the observed state of Collector
|
||||
type: object
|
||||
type: object
|
||||
version: v1beta2
|
||||
versions:
|
||||
- name: v1beta2
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: redactors.troubleshoot.sh
|
||||
spec:
|
||||
group: troubleshoot.sh
|
||||
names:
|
||||
kind: Redactor
|
||||
listKind: RedactorList
|
||||
plural: redactors
|
||||
singular: redactor
|
||||
scope: Namespaced
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
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'
|
||||
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'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: RedactorSpec defines the desired state of Redactor
|
||||
properties:
|
||||
redactors:
|
||||
items:
|
||||
properties:
|
||||
fileSelector:
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
files:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
name:
|
||||
type: string
|
||||
removals:
|
||||
properties:
|
||||
regex:
|
||||
items:
|
||||
properties:
|
||||
redactor:
|
||||
type: string
|
||||
selector:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
values:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
yamlPath:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
status:
|
||||
description: RedactorStatus defines the observed state of Redactor
|
||||
type: object
|
||||
type: object
|
||||
version: v1beta2
|
||||
versions:
|
||||
- name: v1beta2
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,4 +1,4 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Analyzer
|
||||
metadata:
|
||||
labels:
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Collector
|
||||
metadata:
|
||||
name: collector-sample
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Preflight
|
||||
metadata:
|
||||
name: support-io
|
||||
+36
-4
@@ -19,10 +19,25 @@ builds:
|
||||
- id: preflight
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
main: cmd/preflight/main.go
|
||||
ldflags: -s -w
|
||||
-X github.com/replicatedhq/troubleshoot/pkg/version.version={{.Version}}
|
||||
-X github.com/replicatedhq/troubleshoot/pkg/version.gitSHA={{.Commit}}
|
||||
-X github.com/replicatedhq/troubleshoot/pkg/version.buildTime={{.Date}}
|
||||
-extldflags "-static"
|
||||
flags: -tags netgo -installsuffix netgo
|
||||
binary: preflight
|
||||
hooks: {}
|
||||
- id: preflight-darwin
|
||||
goos:
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
main: cmd/preflight/main.go
|
||||
@@ -37,10 +52,25 @@ builds:
|
||||
- id: support-bundle
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
main: cmd/troubleshoot/main.go
|
||||
ldflags: -s -w
|
||||
-X github.com/replicatedhq/troubleshoot/pkg/version.version={{.Version}}
|
||||
-X github.com/replicatedhq/troubleshoot/pkg/version.gitSHA={{.Commit}}
|
||||
-X github.com/replicatedhq/troubleshoot/pkg/version.buildTime={{.Date}}
|
||||
-extldflags "-static"
|
||||
flags: -tags netgo -installsuffix netgo
|
||||
binary: support-bundle
|
||||
hooks: {}
|
||||
- id: support-bundle-darwin
|
||||
goos:
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
main: cmd/troubleshoot/main.go
|
||||
@@ -61,11 +91,12 @@ archives:
|
||||
- id: preflight
|
||||
builds:
|
||||
- preflight
|
||||
- preflight-darwin
|
||||
format: tar.gz
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
name_template: '{{ .Binary }}_{{ .Os }}_{{ .Arch }}'
|
||||
name_template: 'preflight_{{ .Os }}_{{ .Arch }}'
|
||||
files:
|
||||
- licence*
|
||||
- LICENCE*
|
||||
@@ -78,11 +109,12 @@ archives:
|
||||
- id: support-bundle
|
||||
builds:
|
||||
- support-bundle
|
||||
- support-bundle-darwin
|
||||
format: tar.gz
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
name_template: '{{ .Binary }}_{{ .Os }}_{{ .Arch }}'
|
||||
name_template: 'support-bundle_{{ .Os }}_{{ .Arch }}'
|
||||
files:
|
||||
- licence*
|
||||
- LICENCE*
|
||||
|
||||
+18
-19
@@ -31,7 +31,7 @@ spec:
|
||||
matchLabels:
|
||||
os: windows
|
||||
arch: amd64
|
||||
{{addURIAndSha "https://github.com/replicatedhq/troubleshoot/releases/download/{{ .TagName }}/preflight.exe_windows_amd64.zip" .TagName }}
|
||||
{{addURIAndSha "https://github.com/replicatedhq/troubleshoot/releases/download/{{ .TagName }}/preflight_windows_amd64.zip" .TagName }}
|
||||
files:
|
||||
- from: preflight.exe
|
||||
to: .
|
||||
@@ -40,7 +40,23 @@ spec:
|
||||
bin: preflight.exe
|
||||
shortDescription: Executes application preflight tests in a cluster
|
||||
homepage: https://github.com/replicatedhq/troubleshoot
|
||||
caveats: |
|
||||
description: |
|
||||
This plugin executes application-specific preflight checks and conformance
|
||||
tests against a cluster, prior to installation of an application.
|
||||
|
||||
Application developers can create and host a Preflight manifest that
|
||||
defines the minimum and desired Kubernetes environment for an application.
|
||||
Before installing the application, a cluster admin can use this plugin to
|
||||
execute the application preflight checksto identify any missing
|
||||
components, configuration or incompatibilities between the cluster and the
|
||||
desired environment.
|
||||
|
||||
When executing Preflight tests, the test results will be displayed in a
|
||||
terminal-based UI on the workstation that executed the command.
|
||||
|
||||
For information on creating a Preflight manifest, view the documentation
|
||||
at https://help.replicated.com/docs/troubleshoot/kubernetes/analysis/
|
||||
|
||||
Usage:
|
||||
$ kubectl preflight <uri/path>
|
||||
|
||||
@@ -59,20 +75,3 @@ spec:
|
||||
|
||||
For application developers writing collectors and analyzers:
|
||||
https://help.replicated.com/docs/troubleshoot/kubernetes/collectors/defining-collectors/
|
||||
|
||||
description: |
|
||||
This plugin executes application-specific preflight checks and conformance
|
||||
tests against a cluster, prior to installation of an application.
|
||||
|
||||
Application developers can create and host a Preflight manifest that
|
||||
defines the minimum and desired Kubernetes environment for an application.
|
||||
Before installing the application, a cluster admin can use this plugin to
|
||||
execute the application preflight checksto identify any missing
|
||||
components, configuration or incompatibilities between the cluster and the
|
||||
desired environment.
|
||||
|
||||
When executing Preflight tests, the test results will be displayed in a
|
||||
terminal-based UI on the workstation that executed the command.
|
||||
|
||||
For information on creating a Preflight manifest, view the documentation
|
||||
at https://help.replicated.com/docs/troubleshoot/kubernetes/analysis/
|
||||
|
||||
@@ -31,7 +31,7 @@ spec:
|
||||
matchLabels:
|
||||
os: windows
|
||||
arch: amd64
|
||||
{{addURIAndSha "https://github.com/replicatedhq/troubleshoot/releases/download/{{ .TagName }}/support-bundle.exe_windows_amd64.zip" .TagName }}
|
||||
{{addURIAndSha "https://github.com/replicatedhq/troubleshoot/releases/download/{{ .TagName }}/support-bundle_windows_amd64.zip" .TagName }}
|
||||
files:
|
||||
- from: support-bundle.exe
|
||||
to: .
|
||||
@@ -40,7 +40,20 @@ spec:
|
||||
bin: support-bundle.exe
|
||||
shortDescription: Creates support bundles for off-cluster analysis
|
||||
homepage: https://github.com/replicatedhq/troubleshoot
|
||||
caveats: |
|
||||
description: |
|
||||
This plugin collects information about the cluster, and automatically
|
||||
redacts sensitive data from being collected. This can optionally include
|
||||
application-specific data. The plugin writes the collected files into a
|
||||
single archive named support-bundle.tar.gz. This archive can be manually
|
||||
inspected or uploaded to https://vendor.replicated.com for automated
|
||||
analysis.
|
||||
|
||||
Application developers can create and host a Collector manifest that
|
||||
defines information to be collected.
|
||||
|
||||
For information on creating a Collector manifest, view the documentation
|
||||
at https://help.replicated.com/docs/troubleshoot/kubernetes/collectors/defining-collectors/
|
||||
|
||||
Usage:
|
||||
$ kubectl support-bundle <uri>
|
||||
|
||||
@@ -59,17 +72,3 @@ spec:
|
||||
|
||||
For application developers writing collectors and analyzers:
|
||||
https://help.replicated.com/docs/troubleshoot/kubernetes/collectors/defining-collectors/
|
||||
|
||||
description: |
|
||||
This plugin collects information about the cluster, and automatically
|
||||
redacts sensitive data from being collected. This can optionally include
|
||||
application-specific data. The plugin writes the collected files into a
|
||||
single archive named support-bundle.tar.gz. This archive can be manually
|
||||
inspected or uploaded to https://vendor.replicated.com for automated
|
||||
analysis.
|
||||
|
||||
Application developers can create and host a Collector manifest that
|
||||
defines information to be collected.
|
||||
|
||||
For information on creating a Collector manifest, view the documentation
|
||||
at https://help.replicated.com/docs/troubleshoot/kubernetes/collectors/defining-collectors/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Preflight
|
||||
metadata:
|
||||
name: sample
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Preflight
|
||||
metadata:
|
||||
name: sample
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Preflight
|
||||
metadata:
|
||||
name: sample
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Preflight
|
||||
metadata:
|
||||
name: example-preflight-checks
|
||||
name: example
|
||||
spec:
|
||||
collectors:
|
||||
- secret:
|
||||
name: myapp-postgres
|
||||
namespace: default
|
||||
key: uri
|
||||
includeValue: false
|
||||
analyzers:
|
||||
- clusterVersion:
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "< 1.13.0"
|
||||
message: The application requires at Kubernetes 1.13.0 or later, and recommends 1.15.0.
|
||||
message: This application requires at least Kubernetes 1.13.0 or later, and recommends 1.15.0.
|
||||
uri: https://www.kubernetes.io
|
||||
- warn:
|
||||
when: "< 1.15.0"
|
||||
@@ -24,32 +18,102 @@ spec:
|
||||
when: ">= 1.15.0"
|
||||
message: Your cluster meets the recommended and required versions of Kubernetes.
|
||||
- customResourceDefinition:
|
||||
customResourceDefinitionName: constrainttemplates.templates.gatekeeper.sh
|
||||
checkName: Gatekeeper policy runtime
|
||||
checkName: Ingress
|
||||
customResourceDefinitionName: ingressroutes.contour.heptio.com
|
||||
outcomes:
|
||||
- fail:
|
||||
message: Gatekeeper is required for the application, but not found in the cluster.
|
||||
uri: https://enterprise.support.io/installing/gatekeeper
|
||||
message: Contour ingress not found!
|
||||
- pass:
|
||||
message: Found a supported version of Gatekeeper installed and running in the cluster.
|
||||
- imagePullSecret:
|
||||
checkName: Registry credentials for Quay.io
|
||||
registryName: quay.io
|
||||
message: Contour ingress found!
|
||||
- containerRuntime:
|
||||
outcomes:
|
||||
- pass:
|
||||
when: "== docker"
|
||||
message: Docker container runtime was found.
|
||||
- fail:
|
||||
message: Did not find Docker container runtime.
|
||||
- storageClass:
|
||||
checkName: Required storage classes
|
||||
storageClassName: "default"
|
||||
outcomes:
|
||||
- fail:
|
||||
message: |
|
||||
Cannot pull from quay.io. An image pull secret should be deployed to the cluster that has credentials to pull the images. To obtain this secret, please contact your support rep.
|
||||
uri: https://enterprise.support.io/installing/registry-credentials
|
||||
message: Could not find a storage class called default.
|
||||
- pass:
|
||||
message: Found credentials to pull from quay.io
|
||||
- secret:
|
||||
checkName: Postgres connection string
|
||||
secretName: myapp-postgres
|
||||
namespace: default
|
||||
key: uri
|
||||
message: All good on storage classes
|
||||
- distribution:
|
||||
outcomes:
|
||||
- fail:
|
||||
message: A secret named "myapp-postgres" must be deployed with a "uri" key
|
||||
uri: https://enterprise.support.io/installing/postgres
|
||||
when: "== docker-desktop"
|
||||
message: The application does not support Docker Desktop Clusters
|
||||
- fail:
|
||||
when: "== microk8s"
|
||||
message: The application does not support Microk8s Clusters
|
||||
- fail:
|
||||
when: "== minikube"
|
||||
message: The application does not support Minikube Clusters
|
||||
- pass:
|
||||
message: Found a valid postgres connection string
|
||||
when: "== eks"
|
||||
message: EKS is a supported distribution
|
||||
- pass:
|
||||
when: "== gke"
|
||||
message: GKE is a supported distribution
|
||||
- pass:
|
||||
when: "== aks"
|
||||
message: AKS is a supported distribution
|
||||
# Will be supported in the future
|
||||
- pass:
|
||||
when: "== kurl"
|
||||
message: KURL is a supported distribution
|
||||
- pass:
|
||||
when: "== digitalocean"
|
||||
message: DigitalOcean is a supported distribution
|
||||
- warn:
|
||||
message: Unable to determine the distribution of Kubernetes
|
||||
- nodeResources:
|
||||
checkName: Must have at least 3 nodes in the cluster, with 5 recommended
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "count() < 3"
|
||||
message: This application requires at least 3 nodes.
|
||||
uri: https://kurl.sh/docs/install-with-kurl/adding-nodes
|
||||
- warn:
|
||||
when: "count() < 5"
|
||||
message: This application recommends at last 5 nodes.
|
||||
uri: https://kurl.sh/docs/install-with-kurl/adding-nodes
|
||||
- pass:
|
||||
message: This cluster has enough nodes.
|
||||
- nodeResources:
|
||||
checkName: Every node in the cluster must have at least 10 GB of memory, with 32 GB recommended
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "min(memoryCapacity) < 10Gi"
|
||||
message: All nodes must have at least 10 GB of memory.
|
||||
uri: https://kurl.sh/docs/install-with-kurl/system-requirements
|
||||
- warn:
|
||||
when: "min(memoryCapacity) < 32Gi"
|
||||
message: All nodes are recommended to have at least 32 GB of memory.
|
||||
uri: https://kurl.sh/docs/install-with-kurl/system-requirements
|
||||
- pass:
|
||||
message: All nodes have at least 32 GB of memory.
|
||||
- nodeResources:
|
||||
checkName: Total CPU Cores in the cluster is 4 or greater
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "sum(cpuCapacity) < 4"
|
||||
message: The cluster must contain at least 4 cores
|
||||
uri: https://kurl.sh/docs/install-with-kurl/system-requirements
|
||||
- pass:
|
||||
message: There are at least 4 cores in the cluster
|
||||
- nodeResources:
|
||||
checkName: Every node in the cluster must have at least 40 GB of ephemeral storage, with 100 GB recommended
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "min(ephemeralStorageCapacity) < 40Gi"
|
||||
message: All nodes must have at least 40 GB of ephemeral storage.
|
||||
uri: https://kurl.sh/docs/install-with-kurl/system-requirements
|
||||
- warn:
|
||||
when: "min(ephemeralStorageCapacity) < 100Gi"
|
||||
message: All nodes are recommended to have at least 100 GB of ephemeral storage.
|
||||
uri: https://kurl.sh/docs/install-with-kurl/system-requirements
|
||||
- pass:
|
||||
message: All nodes have at least 100 GB of ephemeral storage.
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Preflight
|
||||
metadata:
|
||||
name: example-preflight-checks
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Analyzer
|
||||
metadata:
|
||||
name: a
|
||||
spec:
|
||||
analyzers:
|
||||
- distribution:
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "= dockerdesktop"
|
||||
message: "docker for desktop is not allowed"
|
||||
# - fail:
|
||||
# when: "microk8s"
|
||||
# message: "mickrk8s is not prod"
|
||||
- fail:
|
||||
when: "!= openshift"
|
||||
message: "this should fail on anything other than openshift"
|
||||
- warn:
|
||||
when: "!= eks"
|
||||
message: "YMMV on not eks"
|
||||
- pass:
|
||||
message: "good work"
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Collector
|
||||
metadata:
|
||||
name: collector-sample
|
||||
spec:
|
||||
collectors: []
|
||||
@@ -0,0 +1,101 @@
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
name: example
|
||||
spec:
|
||||
collectors:
|
||||
- logs:
|
||||
selector:
|
||||
- app=example
|
||||
- component=nginx
|
||||
namespace: repl{{ Namespace }}
|
||||
limits:
|
||||
maxAge: 30d
|
||||
maxLines: 10000
|
||||
analyzers:
|
||||
- clusterVersion:
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "< 1.16.0"
|
||||
message: The application requires at least Kubernetes 1.16.0 or later
|
||||
uri: https://kubernetes.io
|
||||
- warn:
|
||||
when: "< 1.17.0"
|
||||
message: Your cluster meets the minimum version of Kubernetes, but we recommend you update to 1.17.0 or later.
|
||||
uri: https://kubernetes.io
|
||||
- pass:
|
||||
message: Your cluster meets the recommended and required versions of Kubernetes.
|
||||
- customResourceDefinition:
|
||||
customResourceDefinitionName: rook
|
||||
outcomes:
|
||||
- fail:
|
||||
message: The Rook CRD was not found in the cluster.
|
||||
- pass:
|
||||
message: Rook is installed and available.
|
||||
- containerRuntime:
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "== docker"
|
||||
message: The application does not support docker
|
||||
- pass:
|
||||
message: A supported container runtime was found
|
||||
- storageClass:
|
||||
checkName: Required storage classes
|
||||
storageClassName: "microk8s-hostpath"
|
||||
outcomes:
|
||||
- fail:
|
||||
message: The microk8s storage class thing was not found
|
||||
- pass:
|
||||
message: All good on storage classes
|
||||
- nodeResources:
|
||||
checkName: Must have at least 3 nodes in the cluster
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "count() < 3"
|
||||
message: This application requires at least 3 nodes
|
||||
- warn:
|
||||
when: "count() < 5"
|
||||
message: This application recommends at last 5 nodes.
|
||||
- pass:
|
||||
message: This cluster has enough nodes.
|
||||
- nodeResources:
|
||||
checkName: Total CPU Cores in the cluster is 4 or greater
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "sum(cpuCapacity) < 4"
|
||||
message: The cluster must contain at least 4 cores
|
||||
- pass:
|
||||
message: There are at least 4 cores in the cluster
|
||||
- nodeResources:
|
||||
checkName: Each node must have at least 40 GB of ephemeral storage
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "min(ephemeralStorageCapacity) < 40Gi"
|
||||
message: Noees in this cluster do not have at least 40 GB of ephemeral storage.
|
||||
uri: https://kurl.sh/docs/install-with-kurl/system-requirements
|
||||
- warn:
|
||||
when: "min(ephemeralStorageCapacity) < 100Gi"
|
||||
message: Nodes in this cluster are recommended to have at least 100 GB of ephemeral storage.
|
||||
uri: https://kurl.sh/docs/install-with-kurl/system-requirements
|
||||
- pass:
|
||||
message: The nodes in this cluster have enough ephemeral storage.
|
||||
- ingress:
|
||||
namespace: default
|
||||
ingressName: connect-to-me
|
||||
outcomes:
|
||||
- fail:
|
||||
message: The ingress isn't ingressing
|
||||
- pass:
|
||||
message: All systems ok on ingress
|
||||
- deploymentStatus:
|
||||
name: api
|
||||
namespace: default
|
||||
outcomes:
|
||||
- fail:
|
||||
when: "< 1"
|
||||
message: The API deployment does not have any ready replicas.
|
||||
- warn:
|
||||
when: "= 1"
|
||||
message: The API deployment has only a single ready replica.
|
||||
- pass:
|
||||
message: There are multiple replicas of the API deployment ready.
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Analyzer
|
||||
metadata:
|
||||
name: a
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Collector
|
||||
metadata:
|
||||
name: collector-sample
|
||||
|
||||
@@ -8,17 +8,14 @@ require (
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/chzyer/logex v1.1.11-0.20160617073814-96a4d311aa9b // indirect
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect
|
||||
github.com/dsnet/compress v0.0.1 // indirect
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 // indirect
|
||||
github.com/emicklei/go-restful v2.9.6+incompatible // indirect
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/frankban/quicktest v1.7.2 // indirect
|
||||
github.com/gizak/termui/v3 v3.1.0
|
||||
github.com/go-openapi/spec v0.19.4 // indirect
|
||||
github.com/go-redis/redis/v7 v7.2.0
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/google/go-cmp v0.3.1 // indirect
|
||||
github.com/google/gofuzz v1.1.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/hashicorp/go-getter v1.3.1-0.20190627223108-da0323b9545e
|
||||
@@ -28,22 +25,19 @@ require (
|
||||
github.com/manifoldco/promptui v0.3.2
|
||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.9
|
||||
github.com/mholt/archiver v3.1.1+incompatible
|
||||
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
|
||||
github.com/nicksnyder/go-i18n v1.10.1 // indirect
|
||||
github.com/nwaples/rardecode v1.0.0 // indirect
|
||||
github.com/onsi/ginkgo v1.11.0 // indirect
|
||||
github.com/onsi/gomega v1.9.0 // indirect
|
||||
github.com/pierrec/lz4 v2.2.6+incompatible // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/procfs v0.0.5 // indirect
|
||||
github.com/replicatedhq/termui/v3 v3.1.1-0.20200811145416-f40076d26851
|
||||
github.com/segmentio/ksuid v1.0.3
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.4.0
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/tj/go-spin v1.1.0
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/ulikunitz/xz v0.5.6 // indirect
|
||||
go.opencensus.io v0.22.0 // indirect
|
||||
go.undefinedlabs.com/scopeagent v0.1.7
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
|
||||
@@ -51,14 +45,10 @@ require (
|
||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff // indirect
|
||||
gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20191105091915-95d230a53780 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
k8s.io/api v0.17.4
|
||||
k8s.io/apiextensions-apiserver v0.15.12-beta.0
|
||||
k8s.io/apimachinery v0.17.4
|
||||
k8s.io/cli-runtime v0.17.4
|
||||
k8s.io/client-go v0.17.4
|
||||
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c // indirect
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.4.0
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
k8s.io/api v0.18.3
|
||||
k8s.io/apiextensions-apiserver v0.18.2
|
||||
k8s.io/apimachinery v0.18.3
|
||||
k8s.io/cli-runtime v0.18.0
|
||||
k8s.io/client-go v0.18.2
|
||||
sigs.k8s.io/controller-runtime v0.5.1-0.20200402191424-df180accb901
|
||||
)
|
||||
|
||||
|
||||
@@ -10,18 +10,21 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||
github.com/Azure/go-autorest/autorest/date v0.1.0 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM=
|
||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0 h1:Ww5g4zThfD/6cLb4z6xxgeyDa7QDkizMkJKe0ysZXp0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
|
||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
@@ -31,6 +34,7 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
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/gometalinter v2.0.11+incompatible h1:ENdXMllZNSVDTJUUVIzBW9CSEpntTrQa76iRsEFLX/M=
|
||||
@@ -38,6 +42,7 @@ github.com/alecthomas/gometalinter v2.0.11+incompatible/go.mod h1:qfIpQGGz3d+Nmg
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
@@ -52,6 +57,7 @@ github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
@@ -68,41 +74,37 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWs
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-oidc v0.0.0-20180117170138-065b426bd416/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.0.0-20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s=
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
||||
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8=
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
|
||||
@@ -113,23 +115,17 @@ github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1
|
||||
github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk=
|
||||
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc=
|
||||
github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
@@ -144,57 +140,52 @@ github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54=
|
||||
github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
|
||||
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
|
||||
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
|
||||
github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
|
||||
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
|
||||
github.com/go-openapi/runtime v0.17.2/go.mod h1:QO936ZXeisByFmZEO1IS1Dqhtf4QV1sYYFtIq6Ld86Q=
|
||||
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
|
||||
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
|
||||
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
|
||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
|
||||
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
|
||||
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
||||
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
|
||||
github.com/go-redis/redis/v7 v7.2.0 h1:CrCexy/jYWZjW0AyVoHlcJUeZN19VWlbepTh1Vq6dJs=
|
||||
github.com/go-redis/redis/v7 v7.2.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
@@ -202,17 +193,13 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
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 v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
@@ -221,14 +208,10 @@ github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:tluoj9z5200j
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
@@ -238,9 +221,6 @@ github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -259,25 +239,24 @@ github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE0
|
||||
github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
|
||||
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
|
||||
github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
|
||||
github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o=
|
||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc h1:cJlkeAx1QYgO5N80aF5xRGstVsRQwgLR7uA2FnP1ZjY=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
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/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170330212424-2500245aa611/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
@@ -307,10 +286,7 @@ github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.0.0-20141017032234-72f9bd7c4e0c/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
||||
@@ -322,8 +298,6 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
@@ -354,7 +328,6 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
@@ -363,8 +336,6 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU=
|
||||
github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
@@ -379,37 +350,29 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/nicksnyder/go-i18n v1.10.1 h1:isfg77E/aCD7+0lD/D00ebR2MV5vgeQ276WYyDaCRQc=
|
||||
github.com/nicksnyder/go-i18n v1.10.1/go.mod h1:e4Di5xjP9oTVrC6y3C7C0HoSYXjSbhh/dU0eUV32nB4=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||
github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
|
||||
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.4.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
|
||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo=
|
||||
@@ -422,51 +385,42 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pierrec/lz4 v2.2.6+incompatible h1:6aCX4/YZ9v8q69hTyiR7dNLnTA3fgtKHVVW5BCd5Znw=
|
||||
github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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 v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||
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/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/segmentio/ksuid v1.0.3 h1:FoResxvleQwYiPAVKe1tMUlEirodZqlqglIuFsdDntY=
|
||||
github.com/segmentio/ksuid v1.0.3/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
@@ -492,7 +446,6 @@ github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYED
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
@@ -502,7 +455,7 @@ github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
@@ -518,14 +471,13 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y
|
||||
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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
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 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=
|
||||
github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
@@ -539,28 +491,27 @@ github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
|
||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/undefinedlabs/go-mpatch v0.0.0-20200122175732-0044123dbb98 h1:Z/megzdoMbuZ0H/oLmfTw92PAEfyTi1DkvAr8AUzFgw=
|
||||
github.com/undefinedlabs/go-mpatch v0.0.0-20200122175732-0044123dbb98/go.mod h1:TyJZDQ/5AgyN7FSLiBJ8RO9u2c6wbtRvK827b6AVqY4=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.undefinedlabs.com/scopeagent v0.1.7 h1:TPALQQNkPah8NgVjPKKhaBNZL2hg+hY2GRPfRMSt48c=
|
||||
@@ -568,28 +519,23 @@ go.undefinedlabs.com/scopeagent v0.1.7/go.mod h1:XCD8wnuBZ+eskhynYNP+uvBiFan9cFr
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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=
|
||||
@@ -597,7 +543,6 @@ golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -609,12 +554,10 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -622,7 +565,6 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/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-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
@@ -633,7 +575,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
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/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180117170059-2c42eef0765b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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=
|
||||
@@ -646,28 +587,23 @@ golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/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.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
@@ -680,25 +616,20 @@ golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181122213734-04b5d21e00f1/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac h1:MQEvx39qSf8vyrx3XRaOe+j1UDIzKwkYOVObRgGPVqI=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff h1:XdBG6es/oFDr1HwaxkxgVve7NB281QhxgK/i4voubFs=
|
||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
|
||||
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
@@ -708,11 +639,9 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
@@ -721,19 +650,16 @@ google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
@@ -743,27 +669,22 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0-20150622162204-20b71e5b60d7/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=
|
||||
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.0.0/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@@ -773,69 +694,49 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh
|
||||
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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48=
|
||||
k8s.io/api v0.15.12-beta.0/go.mod h1:SeTuJQed4C1QTmlWawryIM+feNPRReglVrvv+KsbpGk=
|
||||
k8s.io/api v0.17.4 h1:HbwOhDapkguO8lTAE8OX3hdF2qp8GtpC9CW/MQATXXo=
|
||||
k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA=
|
||||
k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783 h1:V6ndwCPoao1yZ52agqOKaUAl7DYWVGiXjV7ePA2i610=
|
||||
k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY=
|
||||
k8s.io/apiextensions-apiserver v0.15.12-beta.0 h1:6+6t58za7f5ZwtuCz3zQAkCtn5pKYaSTbPTb3PO3vJA=
|
||||
k8s.io/apiextensions-apiserver v0.15.12-beta.0/go.mod h1:8Rm/f9mZoGC5Voo4UJjDjsjIoMLAIOVnp2aQ/WCbZiA=
|
||||
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4=
|
||||
k8s.io/apimachinery v0.15.12-beta.0/go.mod h1:ZRw+v83FjgEqlzqaBkxL3XB21MSLYdzjsY9Bgxclhdw=
|
||||
k8s.io/apimachinery v0.17.4 h1:UzM+38cPUJnzqSQ+E1PY4YxMHIzQyCg29LOoGfo79Zw=
|
||||
k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
|
||||
k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg=
|
||||
k8s.io/apiserver v0.15.12-beta.0/go.mod h1:8jB/rq3MrxjXmRNKxH5Uo+TmUndNG+fF91H8wIw2SKs=
|
||||
k8s.io/cli-runtime v0.17.4 h1:ZIJdxpBEszZqUhydrCoiI5rLXS2J/1AF5xFok2QJ9bc=
|
||||
k8s.io/cli-runtime v0.17.4/go.mod h1:IVW4zrKKx/8gBgNNkhiUIc7nZbVVNhc1+HcQh+PiNHc=
|
||||
k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk=
|
||||
k8s.io/client-go v0.15.12-beta.0/go.mod h1:ytfQFnpRiHki2QY+iyAYxMbq+Cc/aj6VVmPMDYzleQE=
|
||||
k8s.io/client-go v0.17.4 h1:VVdVbpTY70jiNHS1eiFkUt7ZIJX3txd29nDxxXH4en8=
|
||||
k8s.io/client-go v0.17.4/go.mod h1:ouF6o5pz3is8qU0/qYL2RnoxOPqgfuidYLowytyLJmc=
|
||||
k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE=
|
||||
k8s.io/code-generator v0.15.12-beta.0/go.mod h1:G8bQwmHm2eafm5bgtX67XDZQ8CWKSGu9DekI+yN4Y5I=
|
||||
k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090/go.mod h1:933PBGtQFJky3TEwYx4aEPZ4IxqhWh3R6DCmzqIn1hA=
|
||||
k8s.io/component-base v0.15.12-beta.0/go.mod h1:jRj5HNzJOrJYcmdWD76c3tlTJXuBMzz5vWHVSqm5e3s=
|
||||
k8s.io/gengo v0.0.0-20190116091435-f8a0810f38af/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8=
|
||||
k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78=
|
||||
k8s.io/api v0.18.3 h1:2AJaUQdgUZLoDZHrun21PW2Nx9+ll6cUzvn3IKhSIn0=
|
||||
k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA=
|
||||
k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo=
|
||||
k8s.io/apiextensions-apiserver v0.18.2 h1:I4v3/jAuQC+89L3Z7dDgAiN4EOjN6sbm6iBqQwHTah8=
|
||||
k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY=
|
||||
k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA=
|
||||
k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA=
|
||||
k8s.io/apimachinery v0.18.3 h1:pOGcbVAhxADgUYnjS08EFXs9QMl8qaH5U4fr5LGUrSk=
|
||||
k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko=
|
||||
k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw=
|
||||
k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw=
|
||||
k8s.io/cli-runtime v0.18.0 h1:jG8XpSqQ5TrV0N+EZ3PFz6+gqlCk71dkggWCCq9Mq34=
|
||||
k8s.io/cli-runtime v0.18.0/go.mod h1:1eXfmBsIJosjn9LjEBUd2WVPoPAY9XGTqTFcPMIBsUQ=
|
||||
k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8=
|
||||
k8s.io/client-go v0.18.2 h1:aLB0iaD4nmwh7arT2wIn+lMnAq7OswjaejkQ8p9bBYE=
|
||||
k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU=
|
||||
k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
|
||||
k8s.io/code-generator v0.18.2 h1:C1Nn2JiMf244CvBDKVPX0W2mZFJkVBg54T8OV7/Imso=
|
||||
k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
|
||||
k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c=
|
||||
k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/gengo v0.0.0-20190822140433-26a664648505 h1:ZY6yclUKVbZ+SdWnkfY+Je5vrMpKOxmGeKRbsXVmqYM=
|
||||
k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/gengo v0.0.0-20200114144118-36b2048a9120 h1:RPscN6KhmG54S33L+lr3GS+oD1jmchIU0ll519K6FA4=
|
||||
k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
|
||||
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM=
|
||||
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
|
||||
k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
|
||||
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY=
|
||||
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
||||
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
||||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
||||
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
|
||||
sigs.k8s.io/controller-runtime v0.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg=
|
||||
sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0=
|
||||
sigs.k8s.io/controller-runtime v0.5.1-0.20200402191424-df180accb901 h1:qwHvTyQQBjATQeKPdJ0TwcXdtScjyI6GuiAQ5CSqEvM=
|
||||
sigs.k8s.io/controller-runtime v0.5.1-0.20200402191424-df180accb901/go.mod h1:j4echH3Y/UPHRpXS65rxGXujda8iWOheMQvDh1uNgaY=
|
||||
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
||||
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190302045857-e85c7b244fd2/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca h1:6dsH6AYQWbyZmtttJNe8Gq1cXOeS1BdV3eW37zHilAQ=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
sigs.k8s.io/testing_frameworks v0.1.2 h1:vK0+tvjF0BZ/RYFeZ1E6BYBwHJJXhjuZ3TdsEKH+UQM=
|
||||
sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
|
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
|
||||
+96
-18
@@ -4,7 +4,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/multitype"
|
||||
)
|
||||
|
||||
@@ -28,6 +28,10 @@ func isExcluded(excludeVal multitype.BoolOrString) (bool, error) {
|
||||
return excludeVal.BoolVal, nil
|
||||
}
|
||||
|
||||
if excludeVal.StrVal == "" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
parsed, err := strconv.ParseBool(excludeVal.StrVal)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to parse bool string")
|
||||
@@ -36,7 +40,7 @@ func isExcluded(excludeVal multitype.BoolOrString) (bool, error) {
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileContents, findFiles getChildCollectedFileContents) (*AnalyzeResult, error) {
|
||||
func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileContents, findFiles getChildCollectedFileContents) ([]*AnalyzeResult, error) {
|
||||
if analyzer.ClusterVersion != nil {
|
||||
isExcluded, err := isExcluded(analyzer.ClusterVersion.Exclude)
|
||||
if err != nil {
|
||||
@@ -45,7 +49,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeClusterVersion(analyzer.ClusterVersion, getFile)
|
||||
result, err := analyzeClusterVersion(analyzer.ClusterVersion, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.StorageClass != nil {
|
||||
isExcluded, err := isExcluded(analyzer.StorageClass.Exclude)
|
||||
@@ -55,7 +63,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeStorageClass(analyzer.StorageClass, getFile)
|
||||
result, err := analyzeStorageClass(analyzer.StorageClass, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.CustomResourceDefinition != nil {
|
||||
isExcluded, err := isExcluded(analyzer.CustomResourceDefinition.Exclude)
|
||||
@@ -65,7 +77,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeCustomResourceDefinition(analyzer.CustomResourceDefinition, getFile)
|
||||
result, err := analyzeCustomResourceDefinition(analyzer.CustomResourceDefinition, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Ingress != nil {
|
||||
isExcluded, err := isExcluded(analyzer.Ingress.Exclude)
|
||||
@@ -75,7 +91,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeIngress(analyzer.Ingress, getFile)
|
||||
result, err := analyzeIngress(analyzer.Ingress, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Secret != nil {
|
||||
isExcluded, err := isExcluded(analyzer.Secret.Exclude)
|
||||
@@ -85,7 +105,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeSecret(analyzer.Secret, getFile)
|
||||
result, err := analyzeSecret(analyzer.Secret, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.ImagePullSecret != nil {
|
||||
isExcluded, err := isExcluded(analyzer.ImagePullSecret.Exclude)
|
||||
@@ -95,7 +119,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeImagePullSecret(analyzer.ImagePullSecret, findFiles)
|
||||
result, err := analyzeImagePullSecret(analyzer.ImagePullSecret, findFiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.DeploymentStatus != nil {
|
||||
isExcluded, err := isExcluded(analyzer.DeploymentStatus.Exclude)
|
||||
@@ -105,7 +133,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeDeploymentStatus(analyzer.DeploymentStatus, getFile)
|
||||
result, err := analyzeDeploymentStatus(analyzer.DeploymentStatus, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.StatefulsetStatus != nil {
|
||||
isExcluded, err := isExcluded(analyzer.StatefulsetStatus.Exclude)
|
||||
@@ -115,7 +147,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeStatefulsetStatus(analyzer.StatefulsetStatus, getFile)
|
||||
result, err := analyzeStatefulsetStatus(analyzer.StatefulsetStatus, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.ContainerRuntime != nil {
|
||||
isExcluded, err := isExcluded(analyzer.ContainerRuntime.Exclude)
|
||||
@@ -125,7 +161,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeContainerRuntime(analyzer.ContainerRuntime, getFile)
|
||||
result, err := analyzeContainerRuntime(analyzer.ContainerRuntime, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Distribution != nil {
|
||||
isExcluded, err := isExcluded(analyzer.Distribution.Exclude)
|
||||
@@ -135,7 +175,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeDistribution(analyzer.Distribution, getFile)
|
||||
result, err := analyzeDistribution(analyzer.Distribution, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.NodeResources != nil {
|
||||
isExcluded, err := isExcluded(analyzer.NodeResources.Exclude)
|
||||
@@ -145,7 +189,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeNodeResources(analyzer.NodeResources, getFile)
|
||||
result, err := analyzeNodeResources(analyzer.NodeResources, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.TextAnalyze != nil {
|
||||
isExcluded, err := isExcluded(analyzer.TextAnalyze.Exclude)
|
||||
@@ -155,7 +203,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeTextAnalyze(analyzer.TextAnalyze, getFile)
|
||||
multiResult, err := analyzeTextAnalyze(analyzer.TextAnalyze, findFiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return multiResult, nil
|
||||
}
|
||||
if analyzer.Postgres != nil {
|
||||
isExcluded, err := isExcluded(analyzer.Postgres.Exclude)
|
||||
@@ -165,7 +217,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzePostgres(analyzer.Postgres, getFile)
|
||||
result, err := analyzePostgres(analyzer.Postgres, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Mysql != nil {
|
||||
isExcluded, err := isExcluded(analyzer.Mysql.Exclude)
|
||||
@@ -175,7 +231,11 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeMysql(analyzer.Mysql, getFile)
|
||||
result, err := analyzeMysql(analyzer.Mysql, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Redis != nil {
|
||||
isExcluded, err := isExcluded(analyzer.Redis.Exclude)
|
||||
@@ -185,8 +245,26 @@ func Analyze(analyzer *troubleshootv1beta1.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return analyzeRedis(analyzer.Redis, getFile)
|
||||
result, err := analyzeRedis(analyzer.Redis, getFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Collectd != nil {
|
||||
isExcluded, err := isExcluded(analyzer.Collectd.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
result, err := analyzeCollectd(analyzer.Collectd, findFiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("invalid analyzer")
|
||||
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
)
|
||||
|
||||
func analyzeClusterVersion(analyzer *troubleshootv1beta1.ClusterVersion, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeClusterVersion(analyzer *troubleshootv1beta2.ClusterVersion, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
clusterInfo, err := getCollectedFileContents("cluster-info/cluster_version.json")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get contents of cluster_version.json")
|
||||
@@ -29,7 +29,7 @@ func analyzeClusterVersion(analyzer *troubleshootv1beta1.ClusterVersion, getColl
|
||||
return analyzeClusterVersionResult(k8sVersion, analyzer.Outcomes, analyzer.CheckName)
|
||||
}
|
||||
|
||||
func analyzeClusterVersionResult(k8sVersion semver.Version, outcomes []*troubleshootv1beta1.Outcome, checkName string) (*AnalyzeResult, error) {
|
||||
func analyzeClusterVersionResult(k8sVersion semver.Version, outcomes []*troubleshootv1beta2.Outcome, checkName string) (*AnalyzeResult, error) {
|
||||
for _, outcome := range outcomes {
|
||||
when := ""
|
||||
message := ""
|
||||
|
||||
@@ -5,28 +5,28 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/blang/semver"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"go.undefinedlabs.com/scopeagent"
|
||||
)
|
||||
|
||||
func Test_analyzeClusterVersionResult(t *testing.T) {
|
||||
outcomes := []*troubleshootv1beta1.Outcome{
|
||||
outcomes := []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "< 1.13.0",
|
||||
Message: "Sentry requires at Kubernetes 1.13.0 or later, and recommends 1.15.0.",
|
||||
URI: "https://www.kubernetes.io",
|
||||
},
|
||||
},
|
||||
{
|
||||
Warn: &troubleshootv1beta1.SingleOutcome{
|
||||
Warn: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "< 1.15.0",
|
||||
Message: "Your cluster meets the minimum version of Kubernetes, but we recommend you update to 1.15.0 or later.",
|
||||
URI: "https://www.kubernetes.io",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "Your cluster meets the recommended and required versions of Kubernetes.",
|
||||
},
|
||||
},
|
||||
@@ -34,7 +34,7 @@ func Test_analyzeClusterVersionResult(t *testing.T) {
|
||||
|
||||
type args struct {
|
||||
k8sVersion semver.Version
|
||||
outcomes []*troubleshootv1beta1.Outcome
|
||||
outcomes []*troubleshootv1beta2.Outcome
|
||||
checkName string
|
||||
}
|
||||
tests := []struct {
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/rrd"
|
||||
)
|
||||
|
||||
type CollectdSummary struct {
|
||||
Load float64
|
||||
}
|
||||
|
||||
func analyzeCollectd(analyzer *troubleshootv1beta2.CollectdAnalyze, getCollectedFileContents func(string) (map[string][]byte, error)) (*AnalyzeResult, error) {
|
||||
rrdArchives, err := getCollectedFileContents("/collectd/rrd/*.tar")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find rrd archives")
|
||||
}
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "rrd")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create temp rrd dir")
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
for name, data := range rrdArchives {
|
||||
destDir := filepath.Join(tmpDir, filepath.Base(name))
|
||||
if err := extractRRDFiles(data, destDir); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to extract rrd file")
|
||||
}
|
||||
}
|
||||
|
||||
loadFiles, err := findRRDLoadFiles(tmpDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find load files")
|
||||
}
|
||||
|
||||
collectdSummary := CollectdSummary{
|
||||
Load: 0,
|
||||
}
|
||||
|
||||
// load files are always present, so this loop can be used for all host metrics
|
||||
for _, loadFile := range loadFiles {
|
||||
pathParts := strings.Split(loadFile, string(filepath.Separator))
|
||||
if len(pathParts) < 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
// .../<hostname>/load/load.rrd
|
||||
hostname := pathParts[len(pathParts)-3]
|
||||
hostDir := strings.TrimSuffix(loadFile, "/load/load.rrd")
|
||||
|
||||
hostLoad, err := getHostLoad(analyzer, loadFile, hostDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to find analyze %s files", hostname)
|
||||
}
|
||||
|
||||
collectdSummary.Load = math.Max(collectdSummary.Load, hostLoad)
|
||||
}
|
||||
|
||||
result, err := getCollectdAnalyzerOutcome(analyzer, collectdSummary)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to generate outcome")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func extractRRDFiles(archiveData []byte, dst string) error {
|
||||
tarReader := tar.NewReader(bytes.NewReader(archiveData))
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return errors.Wrap(err, "failed to read rrd archive")
|
||||
}
|
||||
|
||||
if header.Typeflag != tar.TypeReg {
|
||||
continue
|
||||
}
|
||||
|
||||
dstFileName := filepath.Join(dst, header.Name)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(dstFileName), 0755); err != nil {
|
||||
return errors.Wrap(err, "failed to create dest path")
|
||||
}
|
||||
|
||||
err = func() error {
|
||||
f, err := os.Create(dstFileName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create dest file")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = io.Copy(f, tarReader)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to copy")
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write dest file")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findRRDLoadFiles(rootDir string) ([]string, error) {
|
||||
files := make([]string, 0)
|
||||
err := filepath.Walk(rootDir, func(filename string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if filepath.Base(filename) == "load.rrd" {
|
||||
files = append(files, filename)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find rrd load files")
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func getHostLoad(analyzer *troubleshootv1beta2.CollectdAnalyze, loadFile string, hostRoot string) (float64, error) {
|
||||
numberOfCPUs := 0
|
||||
err := filepath.Walk(hostRoot, func(filename string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(filepath.Base(filename), "cpu-") {
|
||||
numberOfCPUs++
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to find rrd files")
|
||||
}
|
||||
|
||||
if numberOfCPUs == 0 {
|
||||
numberOfCPUs = 1 // what else can we do here? return an error?
|
||||
}
|
||||
|
||||
fileInfo, err := rrd.Info(loadFile)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to get rrd info")
|
||||
}
|
||||
|
||||
// Query RRD data. Start and end have to be multiples of step.
|
||||
|
||||
window := 7 * 24 * time.Hour
|
||||
step := 1 * time.Hour
|
||||
lastUpdate := int64(fileInfo["last_update"].(uint))
|
||||
endSeconds := int64(lastUpdate/int64(step.Seconds())) * int64(step.Seconds())
|
||||
end := time.Unix(int64(endSeconds), 0)
|
||||
start := end.Add(-window)
|
||||
fetchResult, err := rrd.Fetch(loadFile, "MAX", start, end, step)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to fetch load data")
|
||||
}
|
||||
defer fetchResult.FreeValues()
|
||||
|
||||
values := fetchResult.Values()
|
||||
maxLoad := float64(0)
|
||||
for i := 0; i < len(values); i += 3 { // +3 because "shortterm", "midterm", "longterm"
|
||||
v := values[i+1] // midterm
|
||||
if math.IsNaN(v) {
|
||||
continue
|
||||
}
|
||||
maxLoad = math.Max(maxLoad, values[i+1])
|
||||
}
|
||||
|
||||
return maxLoad / float64(numberOfCPUs), nil
|
||||
}
|
||||
|
||||
func getCollectdAnalyzerOutcome(analyzer *troubleshootv1beta2.CollectdAnalyze, collectdSummary CollectdSummary) (*AnalyzeResult, error) {
|
||||
collectorName := analyzer.CollectorName
|
||||
if collectorName == "" {
|
||||
collectorName = "rrd"
|
||||
}
|
||||
|
||||
title := analyzer.CheckName
|
||||
if title == "" {
|
||||
title = collectorName
|
||||
}
|
||||
result := &AnalyzeResult{
|
||||
Title: title,
|
||||
IconKey: "host_load_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/rrd-analyze.svg",
|
||||
}
|
||||
|
||||
for _, outcome := range analyzer.Outcomes {
|
||||
if outcome.Fail != nil {
|
||||
if outcome.Fail.When == "" {
|
||||
result.IsFail = true
|
||||
result.Message = outcome.Fail.Message
|
||||
result.URI = outcome.Fail.URI
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
isMatch, err := compareCollectdConditionalToActual(outcome.Fail.When, collectdSummary)
|
||||
if err != nil {
|
||||
return result, errors.Wrap(err, "failed to compare rrd fail conditional")
|
||||
}
|
||||
|
||||
if isMatch {
|
||||
result.IsFail = true
|
||||
result.Message = outcome.Fail.Message
|
||||
result.URI = outcome.Fail.URI
|
||||
|
||||
return result, nil
|
||||
}
|
||||
} else if outcome.Warn != nil {
|
||||
if outcome.Pass.When == "" {
|
||||
result.IsWarn = true
|
||||
result.Message = outcome.Warn.Message
|
||||
result.URI = outcome.Warn.URI
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
isMatch, err := compareCollectdConditionalToActual(outcome.Warn.When, collectdSummary)
|
||||
if err != nil {
|
||||
return result, errors.Wrap(err, "failed to compare rrd warn conditional")
|
||||
}
|
||||
|
||||
if isMatch {
|
||||
result.IsWarn = true
|
||||
result.Message = outcome.Warn.Message
|
||||
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
|
||||
}
|
||||
|
||||
isMatch, err := compareCollectdConditionalToActual(outcome.Pass.When, collectdSummary)
|
||||
if err != nil {
|
||||
return result, errors.Wrap(err, "failed to compare rrd pass conditional")
|
||||
}
|
||||
|
||||
if isMatch {
|
||||
result.IsPass = true
|
||||
result.Message = outcome.Pass.Message
|
||||
result.URI = outcome.Pass.URI
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func compareCollectdConditionalToActual(conditional string, collectdSummary CollectdSummary) (bool, error) {
|
||||
parts := strings.Split(strings.TrimSpace(conditional), " ")
|
||||
|
||||
if len(parts) != 3 {
|
||||
return false, errors.New("unable to parse conditional")
|
||||
}
|
||||
|
||||
switch parts[0] {
|
||||
case "load":
|
||||
expected, err := strconv.ParseFloat(parts[2], 64)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to parse float")
|
||||
}
|
||||
|
||||
switch parts[1] {
|
||||
case "=", "==", "===":
|
||||
return collectdSummary.Load == expected, nil
|
||||
case "!=", "!==":
|
||||
return collectdSummary.Load != expected, nil
|
||||
case "<":
|
||||
return collectdSummary.Load < expected, nil
|
||||
|
||||
case ">":
|
||||
return collectdSummary.Load > expected, nil
|
||||
|
||||
case "<=":
|
||||
return collectdSummary.Load <= expected, nil
|
||||
|
||||
case ">=":
|
||||
return collectdSummary.Load >= expected, nil
|
||||
}
|
||||
|
||||
return false, errors.Errorf("unknown rrd comparator: %q", parts[0])
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
)
|
||||
|
||||
func commonStatus(outcomes []*troubleshootv1beta1.Outcome, title, iconKey string, iconURI string, readyReplicas int) (*AnalyzeResult, error) {
|
||||
func commonStatus(outcomes []*troubleshootv1beta2.Outcome, title, iconKey string, iconURI string, readyReplicas int) (*AnalyzeResult, error) {
|
||||
result := &AnalyzeResult{
|
||||
Title: title,
|
||||
IconKey: iconKey,
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func analyzeContainerRuntime(analyzer *troubleshootv1beta1.ContainerRuntime, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeContainerRuntime(analyzer *troubleshootv1beta2.ContainerRuntime, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
collected, err := getCollectedFileContents("cluster-resources/nodes.json")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get contents of nodes.json")
|
||||
@@ -26,8 +26,12 @@ func analyzeContainerRuntime(analyzer *troubleshootv1beta1.ContainerRuntime, get
|
||||
foundRuntimes = append(foundRuntimes, node.Status.NodeInfo.ContainerRuntimeVersion)
|
||||
}
|
||||
|
||||
title := analyzer.CheckName
|
||||
if title == "" {
|
||||
title = "Container Runtime"
|
||||
}
|
||||
result := &AnalyzeResult{
|
||||
Title: "Container Runtime",
|
||||
Title: title,
|
||||
IconKey: "kubernetes_container_runtime",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/container-runtime.svg?w=23&h=16",
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package analyzer
|
||||
import (
|
||||
"testing"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.undefinedlabs.com/scopeagent"
|
||||
@@ -72,22 +72,22 @@ func Test_compareRuntimeConditionalToActual(t *testing.T) {
|
||||
func Test_containerRuntime(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
analyzer troubleshootv1beta1.ContainerRuntime
|
||||
analyzer troubleshootv1beta2.ContainerRuntime
|
||||
expectResult AnalyzeResult
|
||||
files map[string][]byte
|
||||
}{
|
||||
{
|
||||
name: "no containerd, when it's containerd",
|
||||
analyzer: troubleshootv1beta1.ContainerRuntime{
|
||||
Outcomes: []*troubleshootv1beta1.Outcome{
|
||||
analyzer: troubleshootv1beta2.ContainerRuntime{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "!= containerd",
|
||||
Message: "pass",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "containerd detected",
|
||||
},
|
||||
},
|
||||
|
||||
+2
-2
@@ -4,11 +4,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
)
|
||||
|
||||
func analyzeCustomResourceDefinition(analyzer *troubleshootv1beta1.CustomResourceDefinition, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeCustomResourceDefinition(analyzer *troubleshootv1beta2.CustomResourceDefinition, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
crdData, err := getCollectedFileContents("cluster-resources/custom-resource-definitions.json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -35,14 +35,18 @@ func compareDatabaseConditionalToActual(conditional string, result *collect.Data
|
||||
return false, errors.New("unable to parse postgres connected analyzer")
|
||||
|
||||
case "version":
|
||||
expectedRange, err := semver.ParseRange(fmt.Sprintf("%s %s", parts[1], parts[2]))
|
||||
expected, err := semver.ParseTolerant(strings.Replace(parts[2], "x", "0", -1))
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to parse semver range")
|
||||
return false, errors.Wrap(err, "failed to parse expected version")
|
||||
}
|
||||
actual, err := semver.ParseTolerant(strings.Replace(result.Version, "x", "0", -1))
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to parse postgres db actual version")
|
||||
}
|
||||
|
||||
actual, err := semver.Parse(result.Version)
|
||||
expectedRange, err := semver.ParseRange(fmt.Sprintf("%s %s", parts[1], expected.String()))
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to parse actual psotgres version")
|
||||
return false, errors.Wrap(err, "failed to parse semver range")
|
||||
}
|
||||
|
||||
return expectedRange(actual), nil
|
||||
|
||||
@@ -3,15 +3,15 @@ package analyzer
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
)
|
||||
|
||||
func analyzeDeploymentStatus(analyzer *troubleshootv1beta1.DeploymentStatus, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
collected, err := getCollectedFileContents(path.Join("cluster-resources", "deployments", fmt.Sprintf("%s.json", analyzer.Namespace)))
|
||||
func analyzeDeploymentStatus(analyzer *troubleshootv1beta2.DeploymentStatus, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
collected, err := getCollectedFileContents(filepath.Join("cluster-resources", "deployments", fmt.Sprintf("%s.json", analyzer.Namespace)))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read collected deployments from namespace")
|
||||
}
|
||||
@@ -24,7 +24,7 @@ func analyzeDeploymentStatus(analyzer *troubleshootv1beta1.DeploymentStatus, get
|
||||
var status *appsv1.DeploymentStatus
|
||||
for _, deployment := range deployments {
|
||||
if deployment.Name == analyzer.Name {
|
||||
status = &deployment.Status
|
||||
status = deployment.Status.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package analyzer
|
||||
import (
|
||||
"testing"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.undefinedlabs.com/scopeagent"
|
||||
@@ -12,22 +12,22 @@ import (
|
||||
func Test_deploymentStatus(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
analyzer troubleshootv1beta1.DeploymentStatus
|
||||
analyzer troubleshootv1beta2.DeploymentStatus
|
||||
expectResult AnalyzeResult
|
||||
files map[string][]byte
|
||||
}{
|
||||
{
|
||||
name: "1/1, pass when = 1",
|
||||
analyzer: troubleshootv1beta1.DeploymentStatus{
|
||||
Outcomes: []*troubleshootv1beta1.Outcome{
|
||||
analyzer: troubleshootv1beta2.DeploymentStatus{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "= 1",
|
||||
Message: "pass",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
@@ -50,16 +50,16 @@ func Test_deploymentStatus(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "1/1, pass when = 2",
|
||||
analyzer: troubleshootv1beta1.DeploymentStatus{
|
||||
Outcomes: []*troubleshootv1beta1.Outcome{
|
||||
analyzer: troubleshootv1beta2.DeploymentStatus{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "= 2",
|
||||
Message: "pass",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
@@ -82,22 +82,22 @@ func Test_deploymentStatus(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "1/1, pass when >= 2, warn when = 1, fail when 0",
|
||||
analyzer: troubleshootv1beta1.DeploymentStatus{
|
||||
Outcomes: []*troubleshootv1beta1.Outcome{
|
||||
analyzer: troubleshootv1beta2.DeploymentStatus{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: ">= 2",
|
||||
Message: "pass",
|
||||
},
|
||||
},
|
||||
{
|
||||
Warn: &troubleshootv1beta1.SingleOutcome{
|
||||
Warn: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "= 1",
|
||||
Message: "warn",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2,10 +2,11 @@ package analyzer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
@@ -19,6 +20,8 @@ type providers struct {
|
||||
openShift bool
|
||||
kurl bool
|
||||
aks bool
|
||||
ibm bool
|
||||
minikube bool
|
||||
}
|
||||
|
||||
type Provider int
|
||||
@@ -33,6 +36,8 @@ const (
|
||||
openShift Provider = iota
|
||||
kurl Provider = iota
|
||||
aks Provider = iota
|
||||
ibm Provider = iota
|
||||
minikube Provider = iota
|
||||
)
|
||||
|
||||
func CheckOpenShift(foundProviders *providers, apiResources []*metav1.APIResourceList, provider string) string {
|
||||
@@ -68,6 +73,10 @@ func ParseNodesForProviders(nodes []corev1.Node) (providers, string) {
|
||||
foundProviders.aks = true
|
||||
stringProvider = "aks"
|
||||
}
|
||||
if k == "minikube.k8s.io/version" {
|
||||
foundProviders.minikube = true
|
||||
stringProvider = "minikube"
|
||||
}
|
||||
}
|
||||
|
||||
if node.Status.NodeInfo.OSImage == "Docker Desktop" {
|
||||
@@ -87,6 +96,10 @@ func ParseNodesForProviders(nodes []corev1.Node) (providers, string) {
|
||||
foundProviders.gke = true
|
||||
stringProvider = "gke"
|
||||
}
|
||||
if strings.HasPrefix(node.Spec.ProviderID, "ibm:") {
|
||||
foundProviders.ibm = true
|
||||
stringProvider = "ibm"
|
||||
}
|
||||
}
|
||||
|
||||
if foundMaster {
|
||||
@@ -100,7 +113,8 @@ func ParseNodesForProviders(nodes []corev1.Node) (providers, string) {
|
||||
return foundProviders, stringProvider
|
||||
}
|
||||
|
||||
func analyzeDistribution(analyzer *troubleshootv1beta1.Distribution, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeDistribution(analyzer *troubleshootv1beta2.Distribution, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
var unknownDistribution string
|
||||
collected, err := getCollectedFileContents("cluster-resources/nodes.json")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get contents of nodes.json")
|
||||
@@ -123,9 +137,12 @@ func analyzeDistribution(analyzer *troubleshootv1beta1.Distribution, getCollecte
|
||||
}
|
||||
_ = CheckOpenShift(&foundProviders, apiResources, "")
|
||||
}
|
||||
|
||||
title := analyzer.CheckName
|
||||
if title == "" {
|
||||
title = "Kubernetes Distribution"
|
||||
}
|
||||
result := &AnalyzeResult{
|
||||
Title: "Kubernetes Distribution",
|
||||
Title: title,
|
||||
IconKey: "kubernetes_distribution",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/distribution.svg?w=20&h=14",
|
||||
}
|
||||
@@ -141,7 +158,7 @@ func analyzeDistribution(analyzer *troubleshootv1beta1.Distribution, getCollecte
|
||||
return result, nil
|
||||
}
|
||||
|
||||
isMatch, err := compareDistributionConditionalToActual(outcome.Fail.When, foundProviders)
|
||||
isMatch, err := compareDistributionConditionalToActual(outcome.Fail.When, foundProviders, &unknownDistribution)
|
||||
if err != nil {
|
||||
return result, errors.Wrap(err, "failed to compare distribution conditional")
|
||||
}
|
||||
@@ -162,7 +179,7 @@ func analyzeDistribution(analyzer *troubleshootv1beta1.Distribution, getCollecte
|
||||
return result, nil
|
||||
}
|
||||
|
||||
isMatch, err := compareDistributionConditionalToActual(outcome.Warn.When, foundProviders)
|
||||
isMatch, err := compareDistributionConditionalToActual(outcome.Warn.When, foundProviders, &unknownDistribution)
|
||||
if err != nil {
|
||||
return result, errors.Wrap(err, "failed to compare distribution conditional")
|
||||
}
|
||||
@@ -183,7 +200,7 @@ func analyzeDistribution(analyzer *troubleshootv1beta1.Distribution, getCollecte
|
||||
return result, nil
|
||||
}
|
||||
|
||||
isMatch, err := compareDistributionConditionalToActual(outcome.Pass.When, foundProviders)
|
||||
isMatch, err := compareDistributionConditionalToActual(outcome.Pass.When, foundProviders, &unknownDistribution)
|
||||
if err != nil {
|
||||
return result, errors.Wrap(err, "failed to compare distribution conditional")
|
||||
}
|
||||
@@ -199,10 +216,17 @@ func analyzeDistribution(analyzer *troubleshootv1beta1.Distribution, getCollecte
|
||||
}
|
||||
}
|
||||
|
||||
result.IsWarn = true
|
||||
if unknownDistribution != "" {
|
||||
result.Message = unknownDistribution
|
||||
} else {
|
||||
result.Message = "None of the conditionals were met"
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func compareDistributionConditionalToActual(conditional string, actual providers) (bool, error) {
|
||||
func compareDistributionConditionalToActual(conditional string, actual providers, unknownDistribution *string) (bool, error) {
|
||||
parts := strings.Split(strings.TrimSpace(conditional), " ")
|
||||
|
||||
// we can make this a lot more flexible
|
||||
@@ -220,6 +244,7 @@ func compareDistributionConditionalToActual(conditional string, actual providers
|
||||
normalizedName := mustNormalizeDistributionName(parts[1])
|
||||
|
||||
if normalizedName == unknown {
|
||||
*unknownDistribution += fmt.Sprintf("- Unknown distribution: %s ", parts[1])
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -241,6 +266,10 @@ func compareDistributionConditionalToActual(conditional string, actual providers
|
||||
isMatch = actual.kurl
|
||||
case aks:
|
||||
isMatch = actual.aks
|
||||
case ibm:
|
||||
isMatch = actual.ibm
|
||||
case minikube:
|
||||
isMatch = actual.minikube
|
||||
}
|
||||
|
||||
switch parts[0] {
|
||||
@@ -271,6 +300,10 @@ func mustNormalizeDistributionName(raw string) Provider {
|
||||
return kurl
|
||||
case "aks":
|
||||
return aks
|
||||
case "ibm", "ibmcloud", "ibm cloud":
|
||||
return ibm
|
||||
case "minikube":
|
||||
return minikube
|
||||
}
|
||||
|
||||
return unknown
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_compareDistributionConditionalToActual(t *testing.T) {
|
||||
var unknownDistribution string
|
||||
tests := []struct {
|
||||
name string
|
||||
conditional string
|
||||
@@ -46,7 +47,7 @@ func Test_compareDistributionConditionalToActual(t *testing.T) {
|
||||
defer scopetest.End()
|
||||
req := require.New(t)
|
||||
|
||||
actual, err := compareDistributionConditionalToActual(test.conditional, test.input)
|
||||
actual, err := compareDistributionConditionalToActual(test.conditional, test.input, &unknownDistribution)
|
||||
req.NoError(err)
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
|
||||
+101
-31
@@ -10,8 +10,9 @@ import (
|
||||
|
||||
getter "github.com/hashicorp/go-getter"
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
troubleshootscheme "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/docrewrite"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/logger"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
@@ -20,6 +21,31 @@ type fileContentProvider struct {
|
||||
rootDir string
|
||||
}
|
||||
|
||||
// Analyze local will analyze a locally available (already downloaded) bundle
|
||||
func AnalyzeLocal(localBundlePath string, analyzers []*troubleshootv1beta2.Analyze) ([]*AnalyzeResult, error) {
|
||||
rootDir, err := FindBundleRootDir(localBundlePath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find root dir")
|
||||
}
|
||||
|
||||
fcp := fileContentProvider{rootDir: rootDir}
|
||||
|
||||
analyzeResults := []*AnalyzeResult{}
|
||||
for _, analyzer := range analyzers {
|
||||
analyzeResult, err := Analyze(analyzer, fcp.getFileContents, fcp.getChildFileContents)
|
||||
if err != nil {
|
||||
logger.Printf("an analyzer failed to run: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if analyzeResult != nil {
|
||||
analyzeResults = append(analyzeResults, analyzeResult...)
|
||||
}
|
||||
}
|
||||
|
||||
return analyzeResults, nil
|
||||
}
|
||||
|
||||
func DownloadAndAnalyze(bundleURL string, analyzersSpec string) ([]*AnalyzeResult, error) {
|
||||
tmpDir, err := ioutil.TempDir("", "troubleshoot-k8s")
|
||||
if err != nil {
|
||||
@@ -31,12 +57,17 @@ func DownloadAndAnalyze(bundleURL string, analyzersSpec string) ([]*AnalyzeResul
|
||||
return nil, errors.Wrap(err, "failed to download bundle")
|
||||
}
|
||||
|
||||
_, err = os.Stat(filepath.Join(tmpDir, "version.yaml"))
|
||||
rootDir, err := FindBundleRootDir(tmpDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find root dir")
|
||||
}
|
||||
|
||||
_, err = os.Stat(filepath.Join(rootDir, "version.yaml"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read version.yaml")
|
||||
}
|
||||
|
||||
analyzers := []*troubleshootv1beta1.Analyze{}
|
||||
analyzers := []*troubleshootv1beta2.Analyze{}
|
||||
|
||||
if analyzersSpec == "" {
|
||||
defaultAnalyzers, err := getDefaultAnalyzers()
|
||||
@@ -52,22 +83,7 @@ func DownloadAndAnalyze(bundleURL string, analyzersSpec string) ([]*AnalyzeResul
|
||||
analyzers = parsedAnalyzers
|
||||
}
|
||||
|
||||
fcp := fileContentProvider{rootDir: tmpDir}
|
||||
|
||||
analyzeResults := []*AnalyzeResult{}
|
||||
for _, analyzer := range analyzers {
|
||||
analyzeResult, err := Analyze(analyzer, fcp.getFileContents, fcp.getChildFileContents)
|
||||
if err != nil {
|
||||
logger.Printf("an analyzer failed to run: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if analyzeResult != nil {
|
||||
analyzeResults = append(analyzeResults, analyzeResult)
|
||||
}
|
||||
}
|
||||
|
||||
return analyzeResults, nil
|
||||
return AnalyzeLocal(rootDir, analyzers)
|
||||
}
|
||||
|
||||
func downloadTroubleshootBundle(bundleURL string, destDir string) error {
|
||||
@@ -77,7 +93,7 @@ func downloadTroubleshootBundle(bundleURL string, destDir string) error {
|
||||
return errors.Wrap(err, "failed to open support bundle")
|
||||
}
|
||||
defer f.Close()
|
||||
return extractTroubleshootBundle(f, destDir)
|
||||
return ExtractTroubleshootBundle(f, destDir)
|
||||
}
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
@@ -85,7 +101,7 @@ func downloadTroubleshootBundle(bundleURL string, destDir string) error {
|
||||
return errors.Wrap(err, "failed to get workdir")
|
||||
}
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "getter")
|
||||
tmpDir, err := ioutil.TempDir("", "troubleshoot")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create tmp dir")
|
||||
}
|
||||
@@ -107,10 +123,10 @@ func downloadTroubleshootBundle(bundleURL string, destDir string) error {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return extractTroubleshootBundle(f, destDir)
|
||||
return ExtractTroubleshootBundle(f, destDir)
|
||||
}
|
||||
|
||||
func extractTroubleshootBundle(reader io.Reader, destDir string) error {
|
||||
func ExtractTroubleshootBundle(reader io.Reader, destDir string) error {
|
||||
gzReader, err := gzip.NewReader(reader)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create gzip reader")
|
||||
@@ -134,6 +150,12 @@ func extractTroubleshootBundle(reader io.Reader, destDir string) error {
|
||||
}
|
||||
case tar.TypeReg:
|
||||
name := filepath.Join(destDir, header.Name)
|
||||
|
||||
dirName := filepath.Dir(name)
|
||||
if err := os.MkdirAll(dirName, 0755); err != nil {
|
||||
return errors.Wrapf(err, "failed to mkdir for file %s", header.Name)
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE, os.FileMode(header.Mode))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to open tar file")
|
||||
@@ -149,21 +171,26 @@ func extractTroubleshootBundle(reader io.Reader, destDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseAnalyzers(spec string) ([]*troubleshootv1beta1.Analyze, error) {
|
||||
func parseAnalyzers(spec string) ([]*troubleshootv1beta2.Analyze, error) {
|
||||
troubleshootscheme.AddToScheme(scheme.Scheme)
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
|
||||
obj, _, err := decode([]byte(spec), nil, nil)
|
||||
convertedSpec, err := docrewrite.ConvertToV1Beta2([]byte(spec))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert to v1beta2")
|
||||
}
|
||||
|
||||
obj, _, err := decode(convertedSpec, nil, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to decode analyzers")
|
||||
}
|
||||
|
||||
analyzer := obj.(*troubleshootv1beta1.Analyzer)
|
||||
analyzer := obj.(*troubleshootv1beta2.Analyzer)
|
||||
return analyzer.Spec.Analyzers, nil
|
||||
}
|
||||
|
||||
func getDefaultAnalyzers() ([]*troubleshootv1beta1.Analyze, error) {
|
||||
spec := `apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
func getDefaultAnalyzers() ([]*troubleshootv1beta2.Analyze, error) {
|
||||
spec := `apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: Analyzer
|
||||
metadata:
|
||||
name: defaultAnalyzers
|
||||
@@ -186,12 +213,55 @@ spec:
|
||||
return parseAnalyzers(spec)
|
||||
}
|
||||
|
||||
// FindBundleRootDir detects whether the bundle is stored inside a subdirectory or not.
|
||||
// returns the subdirectory path if so, otherwise, returns the path unchanged
|
||||
func FindBundleRootDir(localBundlePath string) (string, error) {
|
||||
f, err := os.Open(localBundlePath)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to open bundle dir")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
names, err := f.Readdirnames(0)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to read dirnames")
|
||||
}
|
||||
|
||||
if len(names) == 0 {
|
||||
return "", errors.New("bundle directory is empty")
|
||||
}
|
||||
|
||||
isInSubDir := true
|
||||
for _, name := range names {
|
||||
if name == "version.yaml" {
|
||||
isInSubDir = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isInSubDir {
|
||||
return filepath.Join(localBundlePath, names[0]), nil
|
||||
}
|
||||
|
||||
return localBundlePath, nil
|
||||
}
|
||||
|
||||
func (f fileContentProvider) getFileContents(fileName string) ([]byte, error) {
|
||||
return ioutil.ReadFile(filepath.Join(f.rootDir, fileName))
|
||||
}
|
||||
|
||||
func (f fileContentProvider) getChildFileContents(dirName string) (map[string][]byte, error) {
|
||||
// TODO: walk sub-dirs
|
||||
// return nil, errors.New("not implemnted")
|
||||
return map[string][]byte{}, nil
|
||||
files, err := filepath.Glob(filepath.Join(f.rootDir, dirName))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "invalid glob %q", dirName)
|
||||
}
|
||||
fileArr := map[string][]byte{}
|
||||
for _, filePath := range files {
|
||||
bytes, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "read %q", filePath)
|
||||
}
|
||||
fileArr[filePath] = bytes
|
||||
}
|
||||
return fileArr, nil
|
||||
}
|
||||
|
||||
@@ -2,34 +2,41 @@ package analyzer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
)
|
||||
|
||||
func analyzeImagePullSecret(analyzer *troubleshootv1beta1.ImagePullSecret, getChildCollectedFileContents func(string) (map[string][]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeImagePullSecret(analyzer *troubleshootv1beta2.ImagePullSecret, getChildCollectedFileContents func(string) (map[string][]byte, error)) (*AnalyzeResult, error) {
|
||||
imagePullSecrets, err := getChildCollectedFileContents("cluster-resources/image-pull-secrets")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get file contents for image pull secrets")
|
||||
}
|
||||
|
||||
var failOutcome *troubleshootv1beta1.Outcome
|
||||
var passOutcome *troubleshootv1beta1.Outcome
|
||||
var failOutcome *troubleshootv1beta2.SingleOutcome
|
||||
var passOutcome *troubleshootv1beta2.SingleOutcome
|
||||
for _, outcome := range analyzer.Outcomes {
|
||||
if outcome.Fail != nil {
|
||||
failOutcome = outcome
|
||||
failOutcome = outcome.Fail
|
||||
} else if outcome.Pass != nil {
|
||||
passOutcome = outcome
|
||||
passOutcome = outcome.Pass
|
||||
}
|
||||
}
|
||||
title := analyzer.CheckName
|
||||
if title == "" {
|
||||
title = "Image Pull Secrets"
|
||||
}
|
||||
|
||||
result := AnalyzeResult{
|
||||
Title: analyzer.CheckName,
|
||||
Title: title,
|
||||
IconKey: "kubernetes_image_pull_secret",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/image-pull-secret.svg?w=16&h=14",
|
||||
IsFail: true,
|
||||
Message: failOutcome.Fail.Message,
|
||||
URI: failOutcome.Fail.URI,
|
||||
}
|
||||
if failOutcome != nil {
|
||||
result.Message = failOutcome.Message
|
||||
result.URI = failOutcome.URI
|
||||
}
|
||||
|
||||
for _, v := range imagePullSecrets {
|
||||
@@ -42,11 +49,20 @@ func analyzeImagePullSecret(analyzer *troubleshootv1beta1.ImagePullSecret, getCh
|
||||
if registry == analyzer.RegistryName {
|
||||
result.IsPass = true
|
||||
result.IsFail = false
|
||||
result.Message = passOutcome.Pass.Message
|
||||
result.URI = passOutcome.Pass.URI
|
||||
if passOutcome != nil {
|
||||
result.Message = passOutcome.Message
|
||||
result.URI = passOutcome.URI
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if result.Message == "" {
|
||||
if result.IsPass {
|
||||
result.Message = fmt.Sprintf("Credentials to pull from: %s found", analyzer.RegistryName)
|
||||
} else {
|
||||
result.Message = fmt.Sprintf("Credentials to pull from: %s not ound", analyzer.RegistryName)
|
||||
}
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@ package analyzer
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
)
|
||||
|
||||
func analyzeIngress(analyzer *troubleshootv1beta1.Ingress, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
ingressData, err := getCollectedFileContents("cluster-resources/storage-classes.json")
|
||||
func analyzeIngress(analyzer *troubleshootv1beta2.Ingress, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
ingressData, err := getCollectedFileContents(filepath.Join("cluster-resources", "ingress", fmt.Sprintf("%s.json", analyzer.Namespace)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"path"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
)
|
||||
|
||||
func analyzeMysql(analyzer *troubleshootv1beta1.DatabaseAnalyze, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeMysql(analyzer *troubleshootv1beta2.DatabaseAnalyze, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
collectorName := analyzer.CollectorName
|
||||
if collectorName == "" {
|
||||
collectorName = "mysql"
|
||||
@@ -28,13 +28,13 @@ func analyzeMysql(analyzer *troubleshootv1beta1.DatabaseAnalyze, getCollectedFil
|
||||
return nil, errors.Wrap(err, "failed to unmarshal databased connection result")
|
||||
}
|
||||
|
||||
checkName := analyzer.CheckName
|
||||
if checkName == "" {
|
||||
checkName = collectorName
|
||||
title := analyzer.CheckName
|
||||
if title == "" {
|
||||
title = collectorName
|
||||
}
|
||||
|
||||
result := &AnalyzeResult{
|
||||
Title: checkName,
|
||||
Title: title,
|
||||
IconKey: "kubernetes_mysql_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/mysql-analyze.svg",
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
)
|
||||
|
||||
func analyzeNodeResources(analyzer *troubleshootv1beta1.NodeResources, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeNodeResources(analyzer *troubleshootv1beta2.NodeResources, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
collected, err := getCollectedFileContents("cluster-resources/nodes.json")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get contents of nodes.json")
|
||||
@@ -94,9 +94,19 @@ func analyzeNodeResources(analyzer *troubleshootv1beta1.NodeResources, getCollec
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func compareNodeResourceConditionalToActual(conditional string, matchingNodes []corev1.Node, totalNodeCount int) (bool, error) {
|
||||
func compareNodeResourceConditionalToActual(conditional string, matchingNodes []corev1.Node, totalNodeCount int) (res bool, err error) {
|
||||
res = false
|
||||
err = nil
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = errors.Errorf("failed to evaluate %q: %v", conditional, r)
|
||||
}
|
||||
}()
|
||||
|
||||
if conditional == "" {
|
||||
return true, nil
|
||||
res = true
|
||||
return
|
||||
}
|
||||
|
||||
parts := strings.Fields(strings.TrimSpace(conditional))
|
||||
@@ -106,7 +116,8 @@ func compareNodeResourceConditionalToActual(conditional string, matchingNodes []
|
||||
}
|
||||
|
||||
if len(parts) != 3 {
|
||||
return false, errors.New("unable to parse nodeResources conditional")
|
||||
err = errors.New("unable to parse nodeResources conditional")
|
||||
return
|
||||
}
|
||||
|
||||
operator := parts[1]
|
||||
@@ -117,6 +128,8 @@ func compareNodeResourceConditionalToActual(conditional string, matchingNodes []
|
||||
parsedDesiredValue, err := strconv.Atoi(parts[2])
|
||||
if err == nil {
|
||||
desiredValue = parsedDesiredValue
|
||||
} else {
|
||||
err = nil // try parsing as a resource
|
||||
}
|
||||
|
||||
reg := regexp.MustCompile(`(?P<function>.*)\((?P<property>.*)\)`)
|
||||
@@ -128,7 +141,8 @@ func compareNodeResourceConditionalToActual(conditional string, matchingNodes []
|
||||
}
|
||||
|
||||
if match == nil || len(match) != 3 {
|
||||
return false, errors.New("conditional does not match pattern of function(property?)")
|
||||
err = errors.New("conditional does not match pattern of function(property?)")
|
||||
return
|
||||
}
|
||||
|
||||
function := match[1]
|
||||
@@ -151,70 +165,86 @@ func compareNodeResourceConditionalToActual(conditional string, matchingNodes []
|
||||
case "=", "==", "===":
|
||||
if _, ok := actualValue.(int); ok {
|
||||
if _, ok := desiredValue.(int); ok {
|
||||
return actualValue.(int) == desiredValue.(int), nil
|
||||
res = actualValue.(int) == desiredValue.(int)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := desiredValue.(string); ok {
|
||||
return actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == 0, nil
|
||||
res = actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == 0
|
||||
return
|
||||
}
|
||||
|
||||
return actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == 0, nil
|
||||
res = actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == 0
|
||||
return
|
||||
|
||||
case "<":
|
||||
if _, ok := actualValue.(int); ok {
|
||||
if _, ok := desiredValue.(int); ok {
|
||||
return actualValue.(int) < desiredValue.(int), nil
|
||||
res = actualValue.(int) < desiredValue.(int)
|
||||
return
|
||||
}
|
||||
}
|
||||
if _, ok := desiredValue.(string); ok {
|
||||
return actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == -1, nil
|
||||
res = actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == -1
|
||||
return
|
||||
}
|
||||
|
||||
return actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == -1, nil
|
||||
res = actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == -1
|
||||
return
|
||||
|
||||
case ">":
|
||||
if _, ok := actualValue.(int); ok {
|
||||
if _, ok := desiredValue.(int); ok {
|
||||
return actualValue.(int) > desiredValue.(int), nil
|
||||
res = actualValue.(int) > desiredValue.(int)
|
||||
return
|
||||
}
|
||||
}
|
||||
if _, ok := desiredValue.(string); ok {
|
||||
return actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == 1, nil
|
||||
res = actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == 1
|
||||
return
|
||||
}
|
||||
|
||||
return actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == 1, nil
|
||||
res = actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == 1
|
||||
return
|
||||
|
||||
case "<=":
|
||||
if _, ok := actualValue.(int); ok {
|
||||
if _, ok := desiredValue.(int); ok {
|
||||
return actualValue.(int) <= desiredValue.(int), nil
|
||||
res = actualValue.(int) <= desiredValue.(int)
|
||||
return
|
||||
}
|
||||
}
|
||||
if _, ok := desiredValue.(string); ok {
|
||||
return actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == 0 ||
|
||||
actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == -1, nil
|
||||
res = actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == 0 ||
|
||||
actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == -1
|
||||
return
|
||||
}
|
||||
|
||||
return actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == 0 ||
|
||||
actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == -1, nil
|
||||
res = actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == 0 ||
|
||||
actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == -1
|
||||
return
|
||||
|
||||
case ">=":
|
||||
if _, ok := actualValue.(int); ok {
|
||||
if _, ok := desiredValue.(int); ok {
|
||||
return actualValue.(int) >= desiredValue.(int), nil
|
||||
res = actualValue.(int) >= desiredValue.(int)
|
||||
return
|
||||
}
|
||||
}
|
||||
if _, ok := desiredValue.(string); ok {
|
||||
return actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == 0 ||
|
||||
actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == 1, nil
|
||||
res = actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == 0 ||
|
||||
actualValue.(*resource.Quantity).Cmp(resource.MustParse(desiredValue.(string))) == 1
|
||||
return
|
||||
}
|
||||
|
||||
return actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == 0 ||
|
||||
actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == 1, nil
|
||||
res = actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == 0 ||
|
||||
actualValue.(*resource.Quantity).Cmp(resource.MustParse(strconv.Itoa(desiredValue.(int)))) == 1
|
||||
return
|
||||
}
|
||||
|
||||
return false, errors.New("unexpected conditional in nodeResources")
|
||||
err = errors.New("unexpected conditional in nodeResources")
|
||||
return
|
||||
}
|
||||
|
||||
func getQuantity(node corev1.Node, property string) *resource.Quantity {
|
||||
@@ -283,12 +313,19 @@ func findMax(nodes []corev1.Node, property string) *resource.Quantity {
|
||||
return max
|
||||
}
|
||||
|
||||
func nodeMatchesFilters(node corev1.Node, filters *troubleshootv1beta1.NodeResourceFilters) (bool, error) {
|
||||
func nodeMatchesFilters(node corev1.Node, filters *troubleshootv1beta2.NodeResourceFilters) (bool, error) {
|
||||
if filters == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// all filters must pass for this to pass
|
||||
if filters.Selector != nil {
|
||||
for k, v := range filters.Selector.MatchLabel {
|
||||
if l, found := node.Labels[k]; !found || l != v {
|
||||
return false, errors.Errorf("failed to match label %s", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if filters.CPUCapacity != "" {
|
||||
parsed, err := resource.ParseQuantity(filters.CPUCapacity)
|
||||
|
||||
@@ -3,7 +3,7 @@ package analyzer
|
||||
import (
|
||||
"testing"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -67,6 +67,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
totalNodeCount int
|
||||
matchingNodes []corev1.Node
|
||||
expected bool
|
||||
isError bool
|
||||
}{
|
||||
{
|
||||
name: "=",
|
||||
@@ -74,6 +75,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "count()",
|
||||
@@ -81,6 +83,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "<",
|
||||
@@ -88,6 +91,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "count() <",
|
||||
@@ -95,6 +99,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: ">",
|
||||
@@ -102,6 +107,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: false,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "count() >",
|
||||
@@ -109,6 +115,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "count() >= 1 (true)",
|
||||
@@ -116,6 +123,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "count() <= 2 (true)",
|
||||
@@ -123,6 +131,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "count() <= 1 (false)",
|
||||
@@ -130,6 +139,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: false,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "min(memoryCapacity) < 4Gi (true)",
|
||||
@@ -137,6 +147,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "min(memoryCapacity) >= 4Gi (false)",
|
||||
@@ -144,6 +155,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: false,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "min(memoryAllocatable) == 16Ki (true)",
|
||||
@@ -151,6 +163,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "min(cpuCapacity) == 2 (true)",
|
||||
@@ -158,6 +171,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "min(cpuAllocatable) == 1.5 (true)",
|
||||
@@ -165,6 +179,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "min(podCapacity) == 15 (true)",
|
||||
@@ -172,6 +187,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "min(podAllocatable) == 12 (true)",
|
||||
@@ -179,6 +195,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "min(ephemeralStorageCapacity) <= 20Gi (true)",
|
||||
@@ -186,6 +203,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "min(ephemeralStorageCapacity) > 20Gi (false)",
|
||||
@@ -193,6 +211,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: false,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "min(ephemeralStorageAllocatable) == 12316009748 (true)",
|
||||
@@ -200,6 +219,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "max(memoryCapacity) == 7951376Ki (true)",
|
||||
@@ -207,6 +227,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "max(memoryAllocatable) == 7848976Ki (true)",
|
||||
@@ -214,6 +235,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "max(cpuCapacity) == 12 (false)",
|
||||
@@ -221,6 +243,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: false,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "max(cpuCapacity) == 4 (true)",
|
||||
@@ -228,6 +251,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "max(cpuAllocatable) == 3 (true)",
|
||||
@@ -235,6 +259,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "max(podCapacity) == 29 (true)",
|
||||
@@ -242,6 +267,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "max(podAllocatable) == 14 (true)",
|
||||
@@ -249,6 +275,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "max(ephemeralStorageCapacity) == 20959212Ki (true)",
|
||||
@@ -256,6 +283,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "max(ephemeralStorageAllocatable) == 19316009748 (true)",
|
||||
@@ -263,6 +291,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "sum(memoryCapacity) > 7951376Ki (true)",
|
||||
@@ -270,6 +299,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "sum(memoryAllocatable) > 7848976Ki (true)",
|
||||
@@ -277,6 +307,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "sum(cpuCapacity) > 5 (true)",
|
||||
@@ -284,6 +315,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "sum(cpuAllocatable) == 4.5 (true)",
|
||||
@@ -291,6 +323,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "sum(podCapacity) == 44 (true)",
|
||||
@@ -298,6 +331,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "sum(podAllocatable) == 26 (true)",
|
||||
@@ -305,6 +339,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "sum(ephemeralStorageCapacity) > 20959212Ki (true)",
|
||||
@@ -312,6 +347,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "sum(ephemeralStorageAllocatable) > 19316009748 (true)",
|
||||
@@ -319,6 +355,15 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: true,
|
||||
isError: false,
|
||||
},
|
||||
{
|
||||
name: "sum(ephemeralStorageAllocatable) > 19316009748 (error)",
|
||||
conditional: "sum(ephemeralStorageAllocatable) > \"19316009748\"",
|
||||
matchingNodes: nodeData,
|
||||
totalNodeCount: len(nodeData),
|
||||
expected: false,
|
||||
isError: true,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -327,7 +372,11 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) {
|
||||
req := require.New(t)
|
||||
|
||||
actual, err := compareNodeResourceConditionalToActual(test.conditional, test.matchingNodes, test.totalNodeCount)
|
||||
req.NoError(err)
|
||||
if test.isError {
|
||||
req.Error(err)
|
||||
} else {
|
||||
req.NoError(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
|
||||
@@ -362,13 +411,13 @@ func Test_nodeMatchesFilters(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
node corev1.Node
|
||||
filters *troubleshootv1beta1.NodeResourceFilters
|
||||
filters *troubleshootv1beta2.NodeResourceFilters
|
||||
expectResult bool
|
||||
}{
|
||||
{
|
||||
name: "true when empty filters",
|
||||
node: node,
|
||||
filters: &troubleshootv1beta1.NodeResourceFilters{},
|
||||
filters: &troubleshootv1beta2.NodeResourceFilters{},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
@@ -379,7 +428,7 @@ func Test_nodeMatchesFilters(t *testing.T) {
|
||||
{
|
||||
name: "false when allocatable memory is too high",
|
||||
node: node,
|
||||
filters: &troubleshootv1beta1.NodeResourceFilters{
|
||||
filters: &troubleshootv1beta2.NodeResourceFilters{
|
||||
MemoryAllocatable: "16Gi",
|
||||
},
|
||||
expectResult: false,
|
||||
@@ -387,7 +436,7 @@ func Test_nodeMatchesFilters(t *testing.T) {
|
||||
{
|
||||
name: "true when allocatable memory is available",
|
||||
node: node,
|
||||
filters: &troubleshootv1beta1.NodeResourceFilters{
|
||||
filters: &troubleshootv1beta2.NodeResourceFilters{
|
||||
MemoryAllocatable: "4Gi",
|
||||
},
|
||||
expectResult: true,
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"path"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
)
|
||||
|
||||
func analyzePostgres(analyzer *troubleshootv1beta1.DatabaseAnalyze, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzePostgres(analyzer *troubleshootv1beta2.DatabaseAnalyze, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
collectorName := analyzer.CollectorName
|
||||
if collectorName == "" {
|
||||
collectorName = "postgres"
|
||||
@@ -28,13 +28,13 @@ func analyzePostgres(analyzer *troubleshootv1beta1.DatabaseAnalyze, getCollected
|
||||
return nil, errors.Wrap(err, "failed to unmarshal databased connection result")
|
||||
}
|
||||
|
||||
checkName := analyzer.CheckName
|
||||
if checkName == "" {
|
||||
checkName = collectorName
|
||||
title := analyzer.CheckName
|
||||
if title == "" {
|
||||
title = collectorName
|
||||
}
|
||||
|
||||
result := &AnalyzeResult{
|
||||
Title: checkName,
|
||||
Title: title,
|
||||
IconKey: "kubernetes_postgres_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/postgres-analyze.svg",
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"path"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
)
|
||||
|
||||
func analyzeRedis(analyzer *troubleshootv1beta1.DatabaseAnalyze, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeRedis(analyzer *troubleshootv1beta2.DatabaseAnalyze, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
collectorName := analyzer.CollectorName
|
||||
if collectorName == "" {
|
||||
collectorName = "redis"
|
||||
@@ -28,13 +28,13 @@ func analyzeRedis(analyzer *troubleshootv1beta1.DatabaseAnalyze, getCollectedFil
|
||||
return nil, errors.Wrap(err, "failed to unmarshal database connection result")
|
||||
}
|
||||
|
||||
checkName := analyzer.CheckName
|
||||
if checkName == "" {
|
||||
checkName = collectorName
|
||||
title := analyzer.CheckName
|
||||
if title == "" {
|
||||
title = collectorName
|
||||
}
|
||||
|
||||
result := &AnalyzeResult{
|
||||
Title: checkName,
|
||||
Title: title,
|
||||
IconKey: "kubernetes_redis_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/redis-analyze.svg",
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
)
|
||||
|
||||
func analyzeSecret(analyzer *troubleshootv1beta1.AnalyzeSecret, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeSecret(analyzer *troubleshootv1beta2.AnalyzeSecret, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
secretData, err := getCollectedFileContents(fmt.Sprintf("secrets/%s/%s.json", analyzer.Namespace, analyzer.SecretName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -30,7 +30,7 @@ func analyzeSecret(analyzer *troubleshootv1beta1.AnalyzeSecret, getCollectedFile
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/secret.svg?w=13&h=16",
|
||||
}
|
||||
|
||||
var failOutcome *troubleshootv1beta1.Outcome
|
||||
var failOutcome *troubleshootv1beta2.Outcome
|
||||
for _, outcome := range analyzer.Outcomes {
|
||||
if outcome.Fail != nil {
|
||||
failOutcome = outcome
|
||||
|
||||
@@ -3,15 +3,15 @@ package analyzer
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
)
|
||||
|
||||
func analyzeStatefulsetStatus(analyzer *troubleshootv1beta1.StatefulsetStatus, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
collected, err := getCollectedFileContents(path.Join("cluster-resources", "statefulsets", fmt.Sprintf("%s.json", analyzer.Namespace)))
|
||||
func analyzeStatefulsetStatus(analyzer *troubleshootv1beta2.StatefulsetStatus, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
collected, err := getCollectedFileContents(filepath.Join("cluster-resources", "statefulsets", fmt.Sprintf("%s.json", analyzer.Namespace)))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read collected statefulsets from namespace")
|
||||
}
|
||||
@@ -24,7 +24,7 @@ func analyzeStatefulsetStatus(analyzer *troubleshootv1beta1.StatefulsetStatus, g
|
||||
var status *appsv1.StatefulSetStatus
|
||||
for _, statefulset := range statefulsets {
|
||||
if statefulset.Name == analyzer.Name {
|
||||
status = &statefulset.Status
|
||||
status = statefulset.Status.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
||||
)
|
||||
|
||||
func analyzeStorageClass(analyzer *troubleshootv1beta1.StorageClass, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeStorageClass(analyzer *troubleshootv1beta2.StorageClass, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
storageClassesData, err := getCollectedFileContents("cluster-resources/storage-classes.json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -21,7 +21,11 @@ func analyzeStorageClass(analyzer *troubleshootv1beta1.StorageClass, getCollecte
|
||||
|
||||
title := analyzer.CheckName
|
||||
if title == "" {
|
||||
title = fmt.Sprintf("Storage class %s", analyzer.StorageClassName)
|
||||
if analyzer.StorageClassName != "" {
|
||||
title = fmt.Sprintf("Storage class %s", analyzer.StorageClassName)
|
||||
} else {
|
||||
title = "Default Storage Class"
|
||||
}
|
||||
}
|
||||
|
||||
result := AnalyzeResult{
|
||||
@@ -31,7 +35,8 @@ func analyzeStorageClass(analyzer *troubleshootv1beta1.StorageClass, getCollecte
|
||||
}
|
||||
|
||||
for _, storageClass := range storageClasses {
|
||||
if storageClass.Name == analyzer.StorageClassName {
|
||||
val, _ := storageClass.Annotations["storageclass.kubernetes.io/is-default-class"]
|
||||
if (storageClass.Name == analyzer.StorageClassName) || (analyzer.StorageClassName == "" && val == "true") {
|
||||
result.IsPass = true
|
||||
for _, outcome := range analyzer.Outcomes {
|
||||
if outcome.Pass != nil {
|
||||
@@ -39,6 +44,9 @@ func analyzeStorageClass(analyzer *troubleshootv1beta1.StorageClass, getCollecte
|
||||
result.URI = outcome.Pass.URI
|
||||
}
|
||||
}
|
||||
if analyzer.StorageClassName == "" && result.Message == "" {
|
||||
result.Message = "Default Storage Class found"
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
@@ -51,6 +59,9 @@ func analyzeStorageClass(analyzer *troubleshootv1beta1.StorageClass, getCollecte
|
||||
result.URI = outcome.Fail.URI
|
||||
}
|
||||
}
|
||||
if analyzer.StorageClassName == "" && result.Message == "" {
|
||||
result.Message = "No Default Storage Class found"
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
+69
-31
@@ -8,10 +8,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
)
|
||||
|
||||
func analyzeTextAnalyze(analyzer *troubleshootv1beta1.TextAnalyze, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
func analyzeTextAnalyze(analyzer *troubleshootv1beta2.TextAnalyze, getCollectedFileContents func(string) (map[string][]byte, error)) ([]*AnalyzeResult, error) {
|
||||
fullPath := filepath.Join(analyzer.CollectorName, analyzer.FileName)
|
||||
collected, err := getCollectedFileContents(fullPath)
|
||||
if err != nil {
|
||||
@@ -23,59 +23,97 @@ func analyzeTextAnalyze(analyzer *troubleshootv1beta1.TextAnalyze, getCollectedF
|
||||
checkName = analyzer.CollectorName
|
||||
}
|
||||
|
||||
if len(collected) == 0 {
|
||||
return []*AnalyzeResult{
|
||||
{
|
||||
Title: checkName,
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
IsFail: false,
|
||||
Message: "No matching files",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
results := []*AnalyzeResult{}
|
||||
|
||||
if analyzer.RegexPattern != "" {
|
||||
return analyzeRegexPattern(analyzer.RegexPattern, collected, analyzer.Outcomes, checkName)
|
||||
for _, fileContents := range collected {
|
||||
result, err := analyzeRegexPattern(analyzer.RegexPattern, fileContents, analyzer.Outcomes, checkName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result != nil {
|
||||
results = append(results, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if analyzer.RegexGroups != "" {
|
||||
return analyzeRegexGroups(analyzer.RegexGroups, collected, analyzer.Outcomes, checkName)
|
||||
for _, fileContents := range collected {
|
||||
result, err := analyzeRegexGroups(analyzer.RegexGroups, fileContents, analyzer.Outcomes, checkName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result != nil {
|
||||
results = append(results, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &AnalyzeResult{
|
||||
Title: checkName,
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
IsFail: true,
|
||||
Message: "Invalid analyzer",
|
||||
if len(results) > 0 {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
return []*AnalyzeResult{
|
||||
{
|
||||
Title: checkName,
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
IsFail: true,
|
||||
Message: "Invalid analyzer",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func analyzeRegexPattern(pattern string, collected []byte, outcomes []*troubleshootv1beta1.Outcome, checkName string) (*AnalyzeResult, error) {
|
||||
func analyzeRegexPattern(pattern string, collected []byte, outcomes []*troubleshootv1beta2.Outcome, checkName string) (*AnalyzeResult, error) {
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to compile regex: %s", pattern)
|
||||
}
|
||||
|
||||
var failOutcome *troubleshootv1beta1.Outcome
|
||||
var passOutcome *troubleshootv1beta1.Outcome
|
||||
var failOutcome *troubleshootv1beta2.SingleOutcome
|
||||
var passOutcome *troubleshootv1beta2.SingleOutcome
|
||||
for _, outcome := range outcomes {
|
||||
if outcome.Fail != nil {
|
||||
failOutcome = outcome
|
||||
failOutcome = outcome.Fail
|
||||
} else if outcome.Pass != nil {
|
||||
passOutcome = outcome
|
||||
passOutcome = outcome.Pass
|
||||
}
|
||||
}
|
||||
|
||||
if re.MatchString(string(collected)) {
|
||||
return &AnalyzeResult{
|
||||
Title: checkName,
|
||||
IsPass: true,
|
||||
Message: passOutcome.Pass.Message,
|
||||
URI: passOutcome.Pass.URI,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &AnalyzeResult{
|
||||
result := AnalyzeResult{
|
||||
Title: checkName,
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
IsFail: true,
|
||||
Message: failOutcome.Fail.Message,
|
||||
URI: failOutcome.Fail.URI,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if re.MatchString(string(collected)) {
|
||||
result.IsPass = true
|
||||
if passOutcome != nil {
|
||||
result.Message = passOutcome.Message
|
||||
result.URI = passOutcome.URI
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
result.IsFail = true
|
||||
if failOutcome != nil {
|
||||
result.Message = failOutcome.Message
|
||||
result.URI = failOutcome.URI
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func analyzeRegexGroups(pattern string, collected []byte, outcomes []*troubleshootv1beta1.Outcome, checkName string) (*AnalyzeResult, error) {
|
||||
func analyzeRegexGroups(pattern string, collected []byte, outcomes []*troubleshootv1beta2.Outcome, checkName string) (*AnalyzeResult, error) {
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to compile regex: %s", pattern)
|
||||
|
||||
@@ -2,9 +2,11 @@ package analyzer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.undefinedlabs.com/scopeagent"
|
||||
@@ -13,21 +15,21 @@ import (
|
||||
func Test_textAnalyze(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
analyzer troubleshootv1beta1.TextAnalyze
|
||||
expectResult AnalyzeResult
|
||||
analyzer troubleshootv1beta2.TextAnalyze
|
||||
expectResult []AnalyzeResult
|
||||
files map[string][]byte
|
||||
}{
|
||||
{
|
||||
name: "success case 1",
|
||||
analyzer: troubleshootv1beta1.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta1.Outcome{
|
||||
analyzer: troubleshootv1beta2.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "pass",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
@@ -36,12 +38,16 @@ func Test_textAnalyze(t *testing.T) {
|
||||
FileName: "cfile-1.txt",
|
||||
RegexPattern: "succeeded",
|
||||
},
|
||||
expectResult: AnalyzeResult{
|
||||
IsPass: true,
|
||||
IsWarn: false,
|
||||
IsFail: false,
|
||||
Title: "text-collector-1",
|
||||
Message: "pass",
|
||||
expectResult: []AnalyzeResult{
|
||||
{
|
||||
IsPass: true,
|
||||
IsWarn: false,
|
||||
IsFail: false,
|
||||
Title: "text-collector-1",
|
||||
Message: "pass",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"text-collector-1/cfile-1.txt": []byte("Yes it all succeeded"),
|
||||
@@ -49,15 +55,15 @@ func Test_textAnalyze(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "failure case 1",
|
||||
analyzer: troubleshootv1beta1.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta1.Outcome{
|
||||
analyzer: troubleshootv1beta2.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "success",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
@@ -66,14 +72,16 @@ func Test_textAnalyze(t *testing.T) {
|
||||
FileName: "cfile-2.txt",
|
||||
RegexPattern: "succeeded",
|
||||
},
|
||||
expectResult: AnalyzeResult{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-2",
|
||||
Message: "fail",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
expectResult: []AnalyzeResult{
|
||||
{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-2",
|
||||
Message: "fail",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"text-collector-2/cfile-2.txt": []byte(""),
|
||||
@@ -81,15 +89,15 @@ func Test_textAnalyze(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "success case 2",
|
||||
analyzer: troubleshootv1beta1.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta1.Outcome{
|
||||
analyzer: troubleshootv1beta2.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "success",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
@@ -98,14 +106,16 @@ func Test_textAnalyze(t *testing.T) {
|
||||
FileName: "cfile-3.txt",
|
||||
RegexPattern: "",
|
||||
},
|
||||
expectResult: AnalyzeResult{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-3",
|
||||
Message: "Invalid analyzer",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
expectResult: []AnalyzeResult{
|
||||
{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-3",
|
||||
Message: "Invalid analyzer",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"text-collector-3/cfile-3.txt": []byte("Connection to service succeeded"),
|
||||
@@ -113,15 +123,15 @@ func Test_textAnalyze(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "success case 3",
|
||||
analyzer: troubleshootv1beta1.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta1.Outcome{
|
||||
analyzer: troubleshootv1beta2.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "success",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
@@ -130,12 +140,16 @@ func Test_textAnalyze(t *testing.T) {
|
||||
FileName: "cfile-5.txt",
|
||||
RegexPattern: "([a-zA-Z0-9\\-_:*\\s])*succe([a-zA-Z0-9\\-_:*\\s!])*",
|
||||
},
|
||||
expectResult: AnalyzeResult{
|
||||
IsPass: true,
|
||||
IsWarn: false,
|
||||
IsFail: false,
|
||||
Title: "text-collector-5",
|
||||
Message: "success",
|
||||
expectResult: []AnalyzeResult{
|
||||
{
|
||||
IsPass: true,
|
||||
IsWarn: false,
|
||||
IsFail: false,
|
||||
Title: "text-collector-5",
|
||||
Message: "success",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"text-collector-5/cfile-5.txt": []byte("Connection to service succeeded!"),
|
||||
@@ -143,15 +157,15 @@ func Test_textAnalyze(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "failure case 3",
|
||||
analyzer: troubleshootv1beta1.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta1.Outcome{
|
||||
analyzer: troubleshootv1beta2.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "success",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
@@ -160,14 +174,16 @@ func Test_textAnalyze(t *testing.T) {
|
||||
FileName: "cfile-4.txt",
|
||||
RegexPattern: "succeeded",
|
||||
},
|
||||
expectResult: AnalyzeResult{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-4",
|
||||
Message: "fail",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
expectResult: []AnalyzeResult{
|
||||
{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-4",
|
||||
Message: "fail",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"text-collector-4/cfile-4.txt": []byte("A different message"),
|
||||
@@ -175,15 +191,15 @@ func Test_textAnalyze(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "failure case 4",
|
||||
analyzer: troubleshootv1beta1.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta1.Outcome{
|
||||
analyzer: troubleshootv1beta2.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta1.SingleOutcome{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "success",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta1.SingleOutcome{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
@@ -192,19 +208,102 @@ func Test_textAnalyze(t *testing.T) {
|
||||
FileName: "cfile-6.txt",
|
||||
RegexPattern: "([a-zA-Z0-9\\-_:*\\s])*succe([a-zA-Z0-9\\-_:*\\s!])*",
|
||||
},
|
||||
expectResult: AnalyzeResult{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-6",
|
||||
Message: "fail",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
expectResult: []AnalyzeResult{
|
||||
{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-6",
|
||||
Message: "fail",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"text-collector-6/cfile-6.txt": []byte("A different message"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple results case 1",
|
||||
analyzer: troubleshootv1beta2.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "pass",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
},
|
||||
CollectorName: "text-collector-1",
|
||||
FileName: "cfile",
|
||||
RegexPattern: "succeeded",
|
||||
},
|
||||
expectResult: []AnalyzeResult{
|
||||
{
|
||||
IsPass: true,
|
||||
IsWarn: false,
|
||||
IsFail: false,
|
||||
Title: "text-collector-1",
|
||||
Message: "pass",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-1",
|
||||
Message: "fail",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"text-collector-1/cfile-1.txt": []byte("Yes it all succeeded"),
|
||||
"text-collector-1/cfile-2.txt": []byte("no success here"),
|
||||
"text-collector-2/cfile-3.txt": []byte("Yes it all succeeded"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple results case 2 globbing",
|
||||
analyzer: troubleshootv1beta2.TextAnalyze{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "pass",
|
||||
},
|
||||
},
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
},
|
||||
CollectorName: "text-collector-1",
|
||||
FileName: "cfile*.log",
|
||||
RegexPattern: "succeeded",
|
||||
},
|
||||
expectResult: []AnalyzeResult{
|
||||
{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-1",
|
||||
Message: "fail",
|
||||
IconKey: "kubernetes_text_analyze",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/text-analyze.svg",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"text-collector-1/cfile-1.txt": []byte("Yes it all succeeded"),
|
||||
"text-collector-1/cfile-2.log": []byte("no success here"),
|
||||
"text-collector-2/cfile-3.txt": []byte("Yes it all succeeded"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -213,17 +312,34 @@ func Test_textAnalyze(t *testing.T) {
|
||||
defer scopetest.End()
|
||||
req := require.New(t)
|
||||
|
||||
getFiles := func(n string) ([]byte, error) {
|
||||
val, ok := test.files[n]
|
||||
if !ok {
|
||||
getFiles := func(n string) (map[string][]byte, error) {
|
||||
matching := make(map[string][]byte)
|
||||
for k, v := range test.files {
|
||||
if strings.HasPrefix(k, n) {
|
||||
matching[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range test.files {
|
||||
if ok, _ := filepath.Match(n, k); ok {
|
||||
matching[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(matching) == 0 {
|
||||
return nil, fmt.Errorf("File not found: %s", n)
|
||||
}
|
||||
return val, nil
|
||||
return matching, nil
|
||||
}
|
||||
|
||||
actual, err := analyzeTextAnalyze(&test.analyzer, getFiles)
|
||||
req.NoError(err)
|
||||
assert.Equal(t, &test.expectResult, actual)
|
||||
|
||||
unPointered := []AnalyzeResult{}
|
||||
for _, v := range actual {
|
||||
unPointered = append(unPointered, *v)
|
||||
}
|
||||
assert.ElementsMatch(t, test.expectResult, unPointered)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apis
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
|
||||
AddToSchemes = append(AddToSchemes, v1beta2.SchemeBuilder.AddToScheme)
|
||||
}
|
||||
@@ -84,14 +84,19 @@ type NodeResources struct {
|
||||
}
|
||||
|
||||
type NodeResourceFilters struct {
|
||||
CPUCapacity string `json:"cpuCapacity,omitempty" yaml:"cpuCapacity,omitempty"`
|
||||
CPUAllocatable string `json:"cpuAllocatable,omitempty" yaml:"cpuAllocatable,omitempty"`
|
||||
MemoryCapacity string `json:"memoryCapacity,omitempty" yaml:"memoryCapacity,omitempty"`
|
||||
MemoryAllocatable string `json:"memoryAllocatable,omitempty" yaml:"memoryAllocatable,omitempty"`
|
||||
PodCapacity string `json:"podCapacity,omitempty" yaml:"podCapacity,omitempty"`
|
||||
PodAllocatable string `json:"podAllocatable,omitempty" yaml:"podAllocatable,omitempty"`
|
||||
EphemeralStorageCapacity string `json:"ephemeralStorageCapacity,omitempty" yaml:"ephemeralStorageCapacity,omitempty"`
|
||||
EphemeralStorageAllocatable string `json:"ephemeralStorageAllocatable,omitempty" yaml:"ephemeralStorageAllocatable,omitempty"`
|
||||
CPUCapacity string `json:"cpuCapacity,omitempty" yaml:"cpuCapacity,omitempty"`
|
||||
CPUAllocatable string `json:"cpuAllocatable,omitempty" yaml:"cpuAllocatable,omitempty"`
|
||||
MemoryCapacity string `json:"memoryCapacity,omitempty" yaml:"memoryCapacity,omitempty"`
|
||||
MemoryAllocatable string `json:"memoryAllocatable,omitempty" yaml:"memoryAllocatable,omitempty"`
|
||||
PodCapacity string `json:"podCapacity,omitempty" yaml:"podCapacity,omitempty"`
|
||||
PodAllocatable string `json:"podAllocatable,omitempty" yaml:"podAllocatable,omitempty"`
|
||||
EphemeralStorageCapacity string `json:"ephemeralStorageCapacity,omitempty" yaml:"ephemeralStorageCapacity,omitempty"`
|
||||
EphemeralStorageAllocatable string `json:"ephemeralStorageAllocatable,omitempty" yaml:"ephemeralStorageAllocatable,omitempty"`
|
||||
Selector *NodeResourceSelectors `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
}
|
||||
|
||||
type NodeResourceSelectors struct {
|
||||
MatchLabel map[string]string `json:"matchLabel,omitempty" yaml:"matchLabel,omitempty"`
|
||||
}
|
||||
|
||||
type TextAnalyze struct {
|
||||
|
||||
@@ -52,13 +52,20 @@ type Data struct {
|
||||
|
||||
type Run struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
Image string `json:"image" yaml:"image"`
|
||||
Command []string `json:"command,omitempty" yaml:"command,omitempty"`
|
||||
Args []string `json:"args,omitempty" yaml:"args,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
Image string `json:"image" yaml:"image"`
|
||||
Command []string `json:"command,omitempty" yaml:"command,omitempty"`
|
||||
Args []string `json:"args,omitempty" yaml:"args,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"`
|
||||
ImagePullSecret *ImagePullSecrets `json:"imagePullSecret,omitempty" yaml:"imagePullSecret,omitempty"`
|
||||
}
|
||||
|
||||
type ImagePullSecrets struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Data map[string]string `json:"data,omitempty" yaml:"data,omitempty"`
|
||||
SecretType string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
}
|
||||
|
||||
type Exec struct {
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
package v1beta1
|
||||
|
||||
type MultiLine struct {
|
||||
type Regex struct {
|
||||
Selector string `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
Redactor string `json:"redactor,omitempty" yaml:"redactor,omitempty"`
|
||||
}
|
||||
|
||||
type FileSelector struct {
|
||||
File string `json:"file,omitempty" yaml:"file,omitempty"`
|
||||
Files []string `json:"files,omitempty" yaml:"files,omitempty"`
|
||||
}
|
||||
|
||||
type Removals struct {
|
||||
Values []string `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
Regex []Regex `json:"regex,omitempty" yaml:"regex,omitempty"`
|
||||
YamlPath []string `json:"yamlPath,omitempty" yaml:"yamlPath,omitempty"`
|
||||
}
|
||||
|
||||
type Redact struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
File string `json:"file,omitempty" yaml:"file,omitempty"`
|
||||
Files []string `json:"files,omitempty" yaml:"files,omitempty"`
|
||||
Values []string `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
Regex []string `json:"regex,omitempty" yaml:"regex,omitempty"`
|
||||
MultiLine []MultiLine `json:"multiLine,omitempty" yaml:"multiLine,omitempty"`
|
||||
Yaml []string `json:"yaml,omitempty" yaml:"yaml,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
FileSelector FileSelector `json:"fileSelector,omitempty" yaml:"fileSelector,omitempty"`
|
||||
Removals Removals `json:"removals,omitempty" yaml:"removals,omitempty"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// SupportBundleSpec defines the desired state of SupportBundle
|
||||
type SupportBundleSpec struct {
|
||||
AfterCollection []*AfterCollection `json:"afterCollection,omitempty" yaml:"afterCollection,omitempty"`
|
||||
Collectors []*Collect `json:"collectors,omitempty" yaml:"collectors,omitempty"`
|
||||
Analyzers []*Analyze `json:"analyzers,omitempty" yaml:"analyzers,omitempty"`
|
||||
}
|
||||
|
||||
// SupportBundleStatus defines the observed state of SupportBundle
|
||||
type SupportBundleStatus struct {
|
||||
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||
// Important: Run "make" to regenerate code after modifying this file
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// SupportBundle is the Schema for the SupportBundles API
|
||||
// +k8s:openapi-gen=true
|
||||
type SupportBundle struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
|
||||
Spec SupportBundleSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
|
||||
Status SupportBundleStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// SupportBundleList contains a list of SupportBundle
|
||||
type SupportBundleList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []SupportBundle `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&SupportBundle{}, &SupportBundleList{})
|
||||
}
|
||||
@@ -762,6 +762,26 @@ func (in *Exec) DeepCopy() *Exec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *FileSelector) DeepCopyInto(out *FileSelector) {
|
||||
*out = *in
|
||||
if in.Files != nil {
|
||||
in, out := &in.Files, &out.Files
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileSelector.
|
||||
func (in *FileSelector) DeepCopy() *FileSelector {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FileSelector)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Get) DeepCopyInto(out *Get) {
|
||||
*out = *in
|
||||
@@ -842,6 +862,28 @@ func (in *ImagePullSecret) DeepCopy() *ImagePullSecret {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ImagePullSecrets) DeepCopyInto(out *ImagePullSecrets) {
|
||||
*out = *in
|
||||
if in.Data != nil {
|
||||
in, out := &in.Data, &out.Data
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImagePullSecrets.
|
||||
func (in *ImagePullSecrets) DeepCopy() *ImagePullSecrets {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ImagePullSecrets)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Ingress) DeepCopyInto(out *Ingress) {
|
||||
*out = *in
|
||||
@@ -915,24 +957,14 @@ func (in *Logs) DeepCopy() *Logs {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MultiLine) DeepCopyInto(out *MultiLine) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MultiLine.
|
||||
func (in *MultiLine) DeepCopy() *MultiLine {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MultiLine)
|
||||
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
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = new(NodeResourceSelectors)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourceFilters.
|
||||
@@ -945,6 +977,28 @@ func (in *NodeResourceFilters) DeepCopy() *NodeResourceFilters {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeResourceSelectors) DeepCopyInto(out *NodeResourceSelectors) {
|
||||
*out = *in
|
||||
if in.MatchLabel != nil {
|
||||
in, out := &in.MatchLabel, &out.MatchLabel
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourceSelectors.
|
||||
func (in *NodeResourceSelectors) DeepCopy() *NodeResourceSelectors {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NodeResourceSelectors)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeResources) DeepCopyInto(out *NodeResources) {
|
||||
*out = *in
|
||||
@@ -963,7 +1017,7 @@ func (in *NodeResources) DeepCopyInto(out *NodeResources) {
|
||||
if in.Filters != nil {
|
||||
in, out := &in.Filters, &out.Filters
|
||||
*out = new(NodeResourceFilters)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1165,31 +1219,8 @@ func (in *Put) DeepCopy() *Put {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Redact) DeepCopyInto(out *Redact) {
|
||||
*out = *in
|
||||
if in.Files != nil {
|
||||
in, out := &in.Files, &out.Files
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Values != nil {
|
||||
in, out := &in.Values, &out.Values
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Regex != nil {
|
||||
in, out := &in.Regex, &out.Regex
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.MultiLine != nil {
|
||||
in, out := &in.MultiLine, &out.MultiLine
|
||||
*out = make([]MultiLine, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Yaml != nil {
|
||||
in, out := &in.Yaml, &out.Yaml
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
in.FileSelector.DeepCopyInto(&out.FileSelector)
|
||||
in.Removals.DeepCopyInto(&out.Removals)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Redact.
|
||||
@@ -1302,6 +1333,51 @@ func (in *RedactorStatus) DeepCopy() *RedactorStatus {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Regex) DeepCopyInto(out *Regex) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Regex.
|
||||
func (in *Regex) DeepCopy() *Regex {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Regex)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Removals) DeepCopyInto(out *Removals) {
|
||||
*out = *in
|
||||
if in.Values != nil {
|
||||
in, out := &in.Values, &out.Values
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Regex != nil {
|
||||
in, out := &in.Regex, &out.Regex
|
||||
*out = make([]Regex, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.YamlPath != nil {
|
||||
in, out := &in.YamlPath, &out.YamlPath
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Removals.
|
||||
func (in *Removals) DeepCopy() *Removals {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Removals)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResultRequest) DeepCopyInto(out *ResultRequest) {
|
||||
*out = *in
|
||||
@@ -1331,6 +1407,11 @@ func (in *Run) DeepCopyInto(out *Run) {
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.ImagePullSecret != nil {
|
||||
in, out := &in.ImagePullSecret, &out.ImagePullSecret
|
||||
*out = new(ImagePullSecrets)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Run.
|
||||
@@ -1428,6 +1509,128 @@ func (in *StorageClass) DeepCopy() *StorageClass {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SupportBundle) DeepCopyInto(out *SupportBundle) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
out.Status = in.Status
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SupportBundle.
|
||||
func (in *SupportBundle) DeepCopy() *SupportBundle {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SupportBundle)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *SupportBundle) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SupportBundleList) DeepCopyInto(out *SupportBundleList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]SupportBundle, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SupportBundleList.
|
||||
func (in *SupportBundleList) DeepCopy() *SupportBundleList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SupportBundleList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *SupportBundleList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SupportBundleSpec) DeepCopyInto(out *SupportBundleSpec) {
|
||||
*out = *in
|
||||
if in.AfterCollection != nil {
|
||||
in, out := &in.AfterCollection, &out.AfterCollection
|
||||
*out = make([]*AfterCollection, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(AfterCollection)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
if in.Collectors != nil {
|
||||
in, out := &in.Collectors, &out.Collectors
|
||||
*out = make([]*Collect, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Collect)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
if in.Analyzers != nil {
|
||||
in, out := &in.Analyzers, &out.Analyzers
|
||||
*out = make([]*Analyze, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Analyze)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SupportBundleSpec.
|
||||
func (in *SupportBundleSpec) DeepCopy() *SupportBundleSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SupportBundleSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SupportBundleStatus) DeepCopyInto(out *SupportBundleStatus) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SupportBundleStatus.
|
||||
func (in *SupportBundleStatus) DeepCopy() *SupportBundleStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SupportBundleStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SupportBundleVersion) DeepCopyInto(out *SupportBundleVersion) {
|
||||
*out = *in
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/multitype"
|
||||
)
|
||||
|
||||
type SingleOutcome struct {
|
||||
When string `json:"when,omitempty" yaml:"when,omitempty"`
|
||||
Message string `json:"message,omitempty" yaml:"message,omitempty"`
|
||||
URI string `json:"uri,omitempty" yaml:"uri,omitempty"`
|
||||
}
|
||||
|
||||
type Outcome struct {
|
||||
Fail *SingleOutcome `json:"fail,omitempty" yaml:"fail,omitempty"`
|
||||
Warn *SingleOutcome `json:"warn,omitempty" yaml:"warn,omitempty"`
|
||||
Pass *SingleOutcome `json:"pass,omitempty" yaml:"pass,omitempty"`
|
||||
}
|
||||
|
||||
type ClusterVersion struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
}
|
||||
|
||||
type StorageClass struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
StorageClassName string `json:"storageClassName" yaml:"storageClassName"`
|
||||
}
|
||||
|
||||
type CustomResourceDefinition struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
CustomResourceDefinitionName string `json:"customResourceDefinitionName" yaml:"customResourceDefinitionName"`
|
||||
}
|
||||
|
||||
type Ingress struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
IngressName string `json:"ingressName" yaml:"ingressName"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
}
|
||||
|
||||
type AnalyzeSecret struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
SecretName string `json:"secretName" yaml:"secretName"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
Key string `json:"key,omitempty" yaml:"key,omitempty"`
|
||||
}
|
||||
|
||||
type ImagePullSecret struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
RegistryName string `json:"registryName" yaml:"registryName"`
|
||||
}
|
||||
type DeploymentStatus struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
}
|
||||
|
||||
type StatefulsetStatus struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
}
|
||||
|
||||
type ContainerRuntime struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
}
|
||||
|
||||
type Distribution struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
}
|
||||
|
||||
type NodeResources struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
Filters *NodeResourceFilters `json:"filters,omitempty" yaml:"filters,omitempty"`
|
||||
}
|
||||
|
||||
type NodeResourceFilters struct {
|
||||
CPUCapacity string `json:"cpuCapacity,omitempty" yaml:"cpuCapacity,omitempty"`
|
||||
CPUAllocatable string `json:"cpuAllocatable,omitempty" yaml:"cpuAllocatable,omitempty"`
|
||||
MemoryCapacity string `json:"memoryCapacity,omitempty" yaml:"memoryCapacity,omitempty"`
|
||||
MemoryAllocatable string `json:"memoryAllocatable,omitempty" yaml:"memoryAllocatable,omitempty"`
|
||||
PodCapacity string `json:"podCapacity,omitempty" yaml:"podCapacity,omitempty"`
|
||||
PodAllocatable string `json:"podAllocatable,omitempty" yaml:"podAllocatable,omitempty"`
|
||||
EphemeralStorageCapacity string `json:"ephemeralStorageCapacity,omitempty" yaml:"ephemeralStorageCapacity,omitempty"`
|
||||
EphemeralStorageAllocatable string `json:"ephemeralStorageAllocatable,omitempty" yaml:"ephemeralStorageAllocatable,omitempty"`
|
||||
Selector *NodeResourceSelectors `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
}
|
||||
|
||||
type NodeResourceSelectors struct {
|
||||
MatchLabel map[string]string `json:"matchLabel,omitempty" yaml:"matchLabel,omitempty"`
|
||||
}
|
||||
|
||||
type TextAnalyze struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
CollectorName string `json:"collectorName,omitempty" yaml:"collectorName,omitempty"`
|
||||
FileName string `json:"fileName,omitempty" yaml:"fileName,omitempty"`
|
||||
RegexPattern string `json:"regex,omitempty" yaml:"regex,omitempty"`
|
||||
RegexGroups string `json:"regexGroups,omitempty" yaml:"regexGroups,omitempty"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
}
|
||||
|
||||
type DatabaseAnalyze struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
CollectorName string `json:"collectorName" yaml:"collectorName"`
|
||||
FileName string `json:"fileName,omitempty" yaml:"fileName,omitempty"`
|
||||
}
|
||||
|
||||
type CollectdAnalyze struct {
|
||||
AnalyzeMeta `json:",inline" yaml:",inline"`
|
||||
Outcomes []*Outcome `json:"outcomes" yaml:"outcomes"`
|
||||
CollectorName string `json:"collectorName" yaml:"collectorName"`
|
||||
}
|
||||
|
||||
type AnalyzeMeta struct {
|
||||
CheckName string `json:"checkName,omitempty" yaml:"checkName,omitempty"`
|
||||
Exclude multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
}
|
||||
|
||||
type Analyze struct {
|
||||
ClusterVersion *ClusterVersion `json:"clusterVersion,omitempty" yaml:"clusterVersion,omitempty"`
|
||||
StorageClass *StorageClass `json:"storageClass,omitempty" yaml:"storageClass,omitempty"`
|
||||
CustomResourceDefinition *CustomResourceDefinition `json:"customResourceDefinition,omitempty" yaml:"customResourceDefinition,omitempty"`
|
||||
Ingress *Ingress `json:"ingress,omitempty" yaml:"ingress,omitempty"`
|
||||
Secret *AnalyzeSecret `json:"secret,omitempty" yaml:"secret,omitempty"`
|
||||
ImagePullSecret *ImagePullSecret `json:"imagePullSecret,omitempty" yaml:"imagePullSecret,omitempty"`
|
||||
DeploymentStatus *DeploymentStatus `json:"deploymentStatus,omitempty" yaml:"deploymentStatus,omitempty"`
|
||||
StatefulsetStatus *StatefulsetStatus `json:"statefulsetStatus,omitempty" yaml:"statefulsetStatus,omitempty"`
|
||||
ContainerRuntime *ContainerRuntime `json:"containerRuntime,omitempty" yaml:"containerRuntime,omitempty"`
|
||||
Distribution *Distribution `json:"distribution,omitempty" yaml:"distribution,omitempty"`
|
||||
NodeResources *NodeResources `json:"nodeResources,omitempty" yaml:"nodeResources,omitempty"`
|
||||
TextAnalyze *TextAnalyze `json:"textAnalyze,omitempty" yaml:"textAnalyze,omitempty"`
|
||||
Postgres *DatabaseAnalyze `json:"postgres,omitempty" yaml:"postgres,omitempty"`
|
||||
Mysql *DatabaseAnalyze `json:"mysql,omitempty" yaml:"mysql,omitempty"`
|
||||
Redis *DatabaseAnalyze `json:"redis,omitempty" yaml:"redis,omitempty"`
|
||||
Collectd *CollectdAnalyze `json:"collectd,omitempty" yaml:"collectd,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// AnalyzerSpec defines the desired state of Analyzer
|
||||
type AnalyzerSpec struct {
|
||||
Analyzers []*Analyze `json:"analyzers,omitempty"`
|
||||
}
|
||||
|
||||
// AnalyzerStatus defines the observed state of Analyzer
|
||||
type AnalyzerStatus struct {
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Analyzer is the Schema for the analyzers API
|
||||
// +k8s:openapi-gen=true
|
||||
type Analyzer struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec AnalyzerSpec `json:"spec,omitempty"`
|
||||
Status AnalyzerStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// AnalyzerList contains a list of Analyzer
|
||||
type AnalyzerList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Analyzer `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Analyzer{}, &AnalyzerList{})
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/replicatedhq/troubleshoot/pkg/multitype"
|
||||
authorizationv1 "k8s.io/api/authorization/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type CollectorMeta struct {
|
||||
CollectorName string `json:"collectorName,omitempty" yaml:"collectorName,omitempty"`
|
||||
// +optional
|
||||
Exclude multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
}
|
||||
|
||||
type ClusterInfo struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
}
|
||||
|
||||
type ClusterResources struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
}
|
||||
|
||||
type Secret struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
SecretName string `json:"name" yaml:"name"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Key string `json:"key,omitempty" yaml:"key,omitempty"`
|
||||
IncludeValue bool `json:"includeValue,omitempty" yaml:"includeValue,omitempty"`
|
||||
}
|
||||
|
||||
type LogLimits struct {
|
||||
MaxAge string `json:"maxAge,omitempty" yaml:"maxAge,omitempty"`
|
||||
MaxLines int64 `json:"maxLines,omitempty" yaml:"maxLines,omitempty"`
|
||||
SinceTime metav1.Time
|
||||
}
|
||||
|
||||
type Logs struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Selector []string `json:"selector" yaml:"selector"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
ContainerNames []string `json:"containerNames,omitempty" yaml:"containerNames,omitempty"`
|
||||
Limits *LogLimits `json:"limits,omitempty" yaml:"omitempty"`
|
||||
}
|
||||
|
||||
type Data struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Data string `json:"data" yaml:"data"`
|
||||
}
|
||||
|
||||
type Run struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
Image string `json:"image" yaml:"image"`
|
||||
Command []string `json:"command,omitempty" yaml:"command,omitempty"`
|
||||
Args []string `json:"args,omitempty" yaml:"args,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"`
|
||||
ImagePullSecret *ImagePullSecrets `json:"imagePullSecret,omitempty" yaml:"imagePullSecret,omitempty"`
|
||||
}
|
||||
|
||||
type ImagePullSecrets struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Data map[string]string `json:"data,omitempty" yaml:"data,omitempty"`
|
||||
SecretType string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
}
|
||||
|
||||
type Exec struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Selector []string `json:"selector" yaml:"selector"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
ContainerName string `json:"containerName,omitempty" yaml:"containerName,omitempty"`
|
||||
Command []string `json:"command,omitempty" yaml:"command,omitempty"`
|
||||
Args []string `json:"args,omitempty" yaml:"args,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
type Copy struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Selector []string `json:"selector" yaml:"selector"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
ContainerPath string `json:"containerPath" yaml:"containerPath"`
|
||||
ContainerName string `json:"containerName,omitempty" yaml:"containerName,omitempty"`
|
||||
}
|
||||
|
||||
type HTTP struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Get *Get `json:"get,omitempty" yaml:"get,omitempty"`
|
||||
Post *Post `json:"post,omitempty" yaml:"post,omitempty"`
|
||||
Put *Put `json:"put,omitempty" yaml:"put,omitempty"`
|
||||
}
|
||||
|
||||
type Get struct {
|
||||
URL string `json:"url" yaml:"url"`
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty"`
|
||||
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
}
|
||||
|
||||
type Post struct {
|
||||
URL string `json:"url" yaml:"url"`
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty"`
|
||||
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
Body string `json:"body,omitempty" yaml:"body,omitempty"`
|
||||
}
|
||||
|
||||
type Put struct {
|
||||
URL string `json:"url" yaml:"url"`
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty"`
|
||||
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
Body string `json:"body,omitempty" yaml:"body,omitempty"`
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
URI string `json:"uri" yaml:"uri"`
|
||||
}
|
||||
|
||||
type Collectd struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
Image string `json:"image" yaml:"image"`
|
||||
ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"`
|
||||
ImagePullSecret *ImagePullSecrets `json:"imagePullSecret,omitempty" yaml:"imagePullSecret,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
HostPath string `json:"hostPath" yaml:"hostPath"`
|
||||
}
|
||||
|
||||
type Collect struct {
|
||||
ClusterInfo *ClusterInfo `json:"clusterInfo,omitempty" yaml:"clusterInfo,omitempty"`
|
||||
ClusterResources *ClusterResources `json:"clusterResources,omitempty" yaml:"clusterResources,omitempty"`
|
||||
Secret *Secret `json:"secret,omitempty" yaml:"secret,omitempty"`
|
||||
Logs *Logs `json:"logs,omitempty" yaml:"logs,omitempty"`
|
||||
Run *Run `json:"run,omitempty" yaml:"run,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"`
|
||||
HTTP *HTTP `json:"http,omitempty" yaml:"http,omitempty"`
|
||||
Postgres *Database `json:"postgres,omitempty" yaml:"postgres,omitempty"`
|
||||
Mysql *Database `json:"mysql,omitempty" yaml:"mysql,omitempty"`
|
||||
Redis *Database `json:"redis,omitempty" yaml:"redis,omitempty"`
|
||||
Collectd *Collectd `json:"collectd,omitempty" yaml:"collectd,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSubjectAccessReviewSpec {
|
||||
result := make([]authorizationv1.SelfSubjectAccessReviewSpec, 0)
|
||||
|
||||
if c.ClusterInfo != nil {
|
||||
// NOOP
|
||||
} else if c.ClusterResources != nil {
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: "",
|
||||
Verb: "list",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "Namespace",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: "",
|
||||
Verb: "list",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "Node",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: "",
|
||||
Verb: "list",
|
||||
Group: "apiextensions.k8s.io",
|
||||
Version: "",
|
||||
Resource: "CustomResourceDefinition",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: "",
|
||||
Verb: "list",
|
||||
Group: "storage.k8s.io",
|
||||
Version: "",
|
||||
Resource: "StorageClasses",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
} else if c.Secret != nil {
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: pickNamespaceOrDefault(c.Secret.Namespace, overrideNS),
|
||||
Verb: "get",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "Secret",
|
||||
Subresource: "",
|
||||
Name: c.Secret.SecretName,
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
} else if c.Logs != nil {
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: pickNamespaceOrDefault(c.Logs.Namespace, overrideNS),
|
||||
Verb: "list",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "Pod",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: pickNamespaceOrDefault(c.Logs.Namespace, overrideNS),
|
||||
Verb: "get",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "Pod",
|
||||
Subresource: "log",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
} else if c.Run != nil {
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: pickNamespaceOrDefault(c.Run.Namespace, overrideNS),
|
||||
Verb: "create",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "Pod",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
} else if c.Exec != nil {
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: pickNamespaceOrDefault(c.Exec.Namespace, overrideNS),
|
||||
Verb: "list",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "Pod",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: pickNamespaceOrDefault(c.Exec.Namespace, overrideNS),
|
||||
Verb: "get",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "Pod",
|
||||
Subresource: "exec",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
} else if c.Copy != nil {
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: pickNamespaceOrDefault(c.Copy.Namespace, overrideNS),
|
||||
Verb: "list",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "Pod",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: pickNamespaceOrDefault(c.Copy.Namespace, overrideNS),
|
||||
Verb: "get",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "Pod",
|
||||
Subresource: "exec",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
} else if c.HTTP != nil {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *Collect) GetName() string {
|
||||
var collector, name, selector string
|
||||
if c.ClusterInfo != nil {
|
||||
collector = "cluster-info"
|
||||
}
|
||||
if c.ClusterResources != nil {
|
||||
collector = "cluster-resources"
|
||||
}
|
||||
if c.Secret != nil {
|
||||
collector = "secret"
|
||||
name = c.Secret.CollectorName
|
||||
}
|
||||
if c.Logs != nil {
|
||||
collector = "logs"
|
||||
name = c.Logs.CollectorName
|
||||
selector = strings.Join(c.Logs.Selector, ",")
|
||||
}
|
||||
if c.Run != nil {
|
||||
collector = "run"
|
||||
name = c.Run.CollectorName
|
||||
}
|
||||
if c.Exec != nil {
|
||||
collector = "exec"
|
||||
name = c.Exec.CollectorName
|
||||
selector = strings.Join(c.Exec.Selector, ",")
|
||||
}
|
||||
if c.Copy != nil {
|
||||
collector = "copy"
|
||||
name = c.Copy.CollectorName
|
||||
selector = strings.Join(c.Copy.Selector, ",")
|
||||
}
|
||||
if c.HTTP != nil {
|
||||
collector = "http"
|
||||
name = c.HTTP.CollectorName
|
||||
}
|
||||
if c.Collectd != nil {
|
||||
collector = "rrd"
|
||||
name = c.Collectd.CollectorName
|
||||
}
|
||||
|
||||
if collector == "" {
|
||||
return "<none>"
|
||||
}
|
||||
if name != "" {
|
||||
return fmt.Sprintf("%s/%s", collector, name)
|
||||
}
|
||||
if selector != "" {
|
||||
return fmt.Sprintf("%s/%s", collector, selector)
|
||||
}
|
||||
return collector
|
||||
}
|
||||
|
||||
func pickNamespaceOrDefault(collectorNS string, overrideNS string) string {
|
||||
if overrideNS != "" {
|
||||
return overrideNS
|
||||
}
|
||||
if collectorNS != "" {
|
||||
return collectorNS
|
||||
}
|
||||
return "default"
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type ResultRequest struct {
|
||||
URI string `json:"uri" yaml:"uri"`
|
||||
Method string `json:"method" yaml:"method"`
|
||||
RedactURI string `json:"redactUri" yaml:"redactUri"` // the URI to POST redaction reports to
|
||||
}
|
||||
|
||||
type AfterCollection struct {
|
||||
UploadResultsTo *ResultRequest `json:"uploadResultsTo,omitempty" yaml:"uploadResultsTo,omitempty"`
|
||||
Callback *ResultRequest `json:"callback,omitempty" yaml:"callback,omitempty"`
|
||||
}
|
||||
|
||||
// CollectorSpec defines the desired state of Collector
|
||||
type CollectorSpec struct {
|
||||
Collectors []*Collect `json:"collectors,omitempty" yaml:"collectors,omitempty"`
|
||||
AfterCollection []*AfterCollection `json:"afterCollection,omitempty" yaml:"afterCollection,omitempty"`
|
||||
}
|
||||
|
||||
// CollectorStatus defines the observed state of Collector
|
||||
type CollectorStatus struct {
|
||||
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||
// Important: Run "make" to regenerate code after modifying this file
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Collector is the Schema for the collectors API
|
||||
// +k8s:openapi-gen=true
|
||||
type Collector struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
|
||||
Spec CollectorSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
|
||||
Status CollectorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CollectorList contains a list of Collector
|
||||
type CollectorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Collector `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Collector{}, &CollectorList{})
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package v1beta2 contains API Schema definitions for the troubleshoot v1beta2 API group
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +groupName=troubleshoot.sh
|
||||
package v1beta2
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// PreflightSpec defines the desired state of Preflight
|
||||
type PreflightSpec struct {
|
||||
UploadResultsTo string `json:"uploadResultsTo,omitempty" yaml:"uploadResultsTo,omitempty"`
|
||||
Collectors []*Collect `json:"collectors,omitempty" yaml:"collectors,omitempty"`
|
||||
Analyzers []*Analyze `json:"analyzers,omitempty" yaml:"analyzers,omitempty"`
|
||||
}
|
||||
|
||||
// PreflightStatus defines the observed state of Preflight
|
||||
type PreflightStatus struct {
|
||||
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||
// Important: Run "make" to regenerate code after modifying this file
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Preflight is the Schema for the preflights API
|
||||
// +k8s:openapi-gen=true
|
||||
type Preflight struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
|
||||
Spec PreflightSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
|
||||
Status PreflightStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// PreflightList contains a list of Preflight
|
||||
type PreflightList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Preflight `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Preflight{}, &PreflightList{})
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package v1beta2
|
||||
|
||||
type Regex struct {
|
||||
Selector string `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
Redactor string `json:"redactor,omitempty" yaml:"redactor,omitempty"`
|
||||
}
|
||||
|
||||
type FileSelector struct {
|
||||
File string `json:"file,omitempty" yaml:"file,omitempty"`
|
||||
Files []string `json:"files,omitempty" yaml:"files,omitempty"`
|
||||
}
|
||||
|
||||
type Removals struct {
|
||||
Values []string `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
Regex []Regex `json:"regex,omitempty" yaml:"regex,omitempty"`
|
||||
YamlPath []string `json:"yamlPath,omitempty" yaml:"yamlPath,omitempty"`
|
||||
}
|
||||
|
||||
type Redact struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
FileSelector FileSelector `json:"fileSelector,omitempty" yaml:"fileSelector,omitempty"`
|
||||
Removals Removals `json:"removals,omitempty" yaml:"removals,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// RedactorSpec defines the desired state of Redactor
|
||||
type RedactorSpec struct {
|
||||
Redactors []*Redact `json:"redactors,omitempty"`
|
||||
}
|
||||
|
||||
// RedactorStatus defines the observed state of Redactor
|
||||
type RedactorStatus struct {
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Redactor is the Schema for the redaction API
|
||||
// +k8s:openapi-gen=true
|
||||
type Redactor struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec RedactorSpec `json:"spec,omitempty"`
|
||||
Status RedactorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// RedactorList contains a list of Redactor
|
||||
type RedactorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Redactor `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Redactor{}, &RedactorList{})
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// NOTE: Boilerplate only. Ignore this file.
|
||||
|
||||
// Package v1beta2 contains API Schema definitions for the troubleshoot v1beta2 API group
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +groupName=troubleshoot.sh
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
SchemeGroupVersion = schema.GroupVersion{Group: "troubleshoot.sh", Version: "v1beta2"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
|
||||
|
||||
// AddToScheme is required by pkg/client/...
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Resource is required by pkg/client/listers/...
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// SupportBundleSpec defines the desired state of SupportBundle
|
||||
type SupportBundleSpec struct {
|
||||
AfterCollection []*AfterCollection `json:"afterCollection,omitempty" yaml:"afterCollection,omitempty"`
|
||||
Collectors []*Collect `json:"collectors,omitempty" yaml:"collectors,omitempty"`
|
||||
Analyzers []*Analyze `json:"analyzers,omitempty" yaml:"analyzers,omitempty"`
|
||||
}
|
||||
|
||||
// SupportBundleStatus defines the observed state of SupportBundle
|
||||
type SupportBundleStatus struct {
|
||||
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||
// Important: Run "make" to regenerate code after modifying this file
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// SupportBundle is the Schema for the SupportBundles API
|
||||
// +k8s:openapi-gen=true
|
||||
type SupportBundle struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
|
||||
Spec SupportBundleSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
|
||||
Status SupportBundleStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// SupportBundleList contains a list of SupportBundle
|
||||
type SupportBundleList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []SupportBundle `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&SupportBundle{}, &SupportBundleList{})
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package v1beta2
|
||||
|
||||
type SupportBundleVersionSpec struct {
|
||||
VersionNumber string `json:"versionNumber" yaml:"versionNumber"`
|
||||
}
|
||||
|
||||
type SupportBundleVersion struct {
|
||||
ApiVersion string `json:"apiVersion" yaml:"apiVersion"`
|
||||
Kind string `json:"kind" yaml:"kind"`
|
||||
Spec SupportBundleVersionSpec `json:"spec" yaml:"spec"`
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/typed/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/typed/troubleshoot/v1beta2"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
rest "k8s.io/client-go/rest"
|
||||
flowcontrol "k8s.io/client-go/util/flowcontrol"
|
||||
@@ -29,6 +30,7 @@ import (
|
||||
type Interface interface {
|
||||
Discovery() discovery.DiscoveryInterface
|
||||
TroubleshootV1beta1() troubleshootv1beta1.TroubleshootV1beta1Interface
|
||||
TroubleshootV1beta2() troubleshootv1beta2.TroubleshootV1beta2Interface
|
||||
}
|
||||
|
||||
// Clientset contains the clients for groups. Each group has exactly one
|
||||
@@ -36,6 +38,7 @@ type Interface interface {
|
||||
type Clientset struct {
|
||||
*discovery.DiscoveryClient
|
||||
troubleshootV1beta1 *troubleshootv1beta1.TroubleshootV1beta1Client
|
||||
troubleshootV1beta2 *troubleshootv1beta2.TroubleshootV1beta2Client
|
||||
}
|
||||
|
||||
// TroubleshootV1beta1 retrieves the TroubleshootV1beta1Client
|
||||
@@ -43,6 +46,11 @@ func (c *Clientset) TroubleshootV1beta1() troubleshootv1beta1.TroubleshootV1beta
|
||||
return c.troubleshootV1beta1
|
||||
}
|
||||
|
||||
// TroubleshootV1beta2 retrieves the TroubleshootV1beta2Client
|
||||
func (c *Clientset) TroubleshootV1beta2() troubleshootv1beta2.TroubleshootV1beta2Interface {
|
||||
return c.troubleshootV1beta2
|
||||
}
|
||||
|
||||
// Discovery retrieves the DiscoveryClient
|
||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||
if c == nil {
|
||||
@@ -58,7 +66,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||
configShallowCopy := *c
|
||||
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
|
||||
if configShallowCopy.Burst <= 0 {
|
||||
return nil, fmt.Errorf("Burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
|
||||
return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
|
||||
}
|
||||
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
|
||||
}
|
||||
@@ -68,6 +76,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs.troubleshootV1beta2, err = troubleshootv1beta2.NewForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
@@ -81,6 +93,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||
func NewForConfigOrDie(c *rest.Config) *Clientset {
|
||||
var cs Clientset
|
||||
cs.troubleshootV1beta1 = troubleshootv1beta1.NewForConfigOrDie(c)
|
||||
cs.troubleshootV1beta2 = troubleshootv1beta2.NewForConfigOrDie(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
|
||||
return &cs
|
||||
@@ -90,6 +103,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
|
||||
func New(c rest.Interface) *Clientset {
|
||||
var cs Clientset
|
||||
cs.troubleshootV1beta1 = troubleshootv1beta1.New(c)
|
||||
cs.troubleshootV1beta2 = troubleshootv1beta2.New(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
|
||||
return &cs
|
||||
|
||||
@@ -21,6 +21,8 @@ import (
|
||||
clientset "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/typed/troubleshoot/v1beta1"
|
||||
faketroubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/typed/troubleshoot/v1beta1/fake"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/typed/troubleshoot/v1beta2"
|
||||
faketroubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/typed/troubleshoot/v1beta2/fake"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
@@ -79,3 +81,8 @@ var _ clientset.Interface = &Clientset{}
|
||||
func (c *Clientset) TroubleshootV1beta1() troubleshootv1beta1.TroubleshootV1beta1Interface {
|
||||
return &faketroubleshootv1beta1.FakeTroubleshootV1beta1{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// TroubleshootV1beta2 retrieves the TroubleshootV1beta2Client
|
||||
func (c *Clientset) TroubleshootV1beta2() troubleshootv1beta2.TroubleshootV1beta2Interface {
|
||||
return &faketroubleshootv1beta2.FakeTroubleshootV1beta2{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package fake
|
||||
|
||||
import (
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@@ -31,6 +32,7 @@ var codecs = serializer.NewCodecFactory(scheme)
|
||||
var parameterCodec = runtime.NewParameterCodec(scheme)
|
||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
troubleshootv1beta1.AddToScheme,
|
||||
troubleshootv1beta2.AddToScheme,
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
|
||||
@@ -19,6 +19,7 @@ package scheme
|
||||
|
||||
import (
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@@ -31,6 +32,7 @@ var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
var ParameterCodec = runtime.NewParameterCodec(Scheme)
|
||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
troubleshootv1beta1.AddToScheme,
|
||||
troubleshootv1beta2.AddToScheme,
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
|
||||
@@ -18,6 +18,7 @@ limitations under the License.
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
v1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
@@ -36,15 +37,15 @@ type AnalyzersGetter interface {
|
||||
|
||||
// AnalyzerInterface has methods to work with Analyzer resources.
|
||||
type AnalyzerInterface interface {
|
||||
Create(*v1beta1.Analyzer) (*v1beta1.Analyzer, error)
|
||||
Update(*v1beta1.Analyzer) (*v1beta1.Analyzer, error)
|
||||
UpdateStatus(*v1beta1.Analyzer) (*v1beta1.Analyzer, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1beta1.Analyzer, error)
|
||||
List(opts v1.ListOptions) (*v1beta1.AnalyzerList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Analyzer, err error)
|
||||
Create(ctx context.Context, analyzer *v1beta1.Analyzer, opts v1.CreateOptions) (*v1beta1.Analyzer, error)
|
||||
Update(ctx context.Context, analyzer *v1beta1.Analyzer, opts v1.UpdateOptions) (*v1beta1.Analyzer, error)
|
||||
UpdateStatus(ctx context.Context, analyzer *v1beta1.Analyzer, opts v1.UpdateOptions) (*v1beta1.Analyzer, error)
|
||||
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.Analyzer, error)
|
||||
List(ctx context.Context, opts v1.ListOptions) (*v1beta1.AnalyzerList, error)
|
||||
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Analyzer, err error)
|
||||
AnalyzerExpansion
|
||||
}
|
||||
|
||||
@@ -63,20 +64,20 @@ func newAnalyzers(c *TroubleshootV1beta1Client, namespace string) *analyzers {
|
||||
}
|
||||
|
||||
// Get takes name of the analyzer, and returns the corresponding analyzer object, and an error if there is any.
|
||||
func (c *analyzers) Get(name string, options v1.GetOptions) (result *v1beta1.Analyzer, err error) {
|
||||
func (c *analyzers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Analyzer, err error) {
|
||||
result = &v1beta1.Analyzer{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("analyzers").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Analyzers that match those selectors.
|
||||
func (c *analyzers) List(opts v1.ListOptions) (result *v1beta1.AnalyzerList, err error) {
|
||||
func (c *analyzers) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.AnalyzerList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
@@ -87,13 +88,13 @@ func (c *analyzers) List(opts v1.ListOptions) (result *v1beta1.AnalyzerList, err
|
||||
Resource("analyzers").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested analyzers.
|
||||
func (c *analyzers) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
func (c *analyzers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
@@ -104,87 +105,90 @@ func (c *analyzers) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
Resource("analyzers").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
Watch(ctx)
|
||||
}
|
||||
|
||||
// Create takes the representation of a analyzer and creates it. Returns the server's representation of the analyzer, and an error, if there is any.
|
||||
func (c *analyzers) Create(analyzer *v1beta1.Analyzer) (result *v1beta1.Analyzer, err error) {
|
||||
func (c *analyzers) Create(ctx context.Context, analyzer *v1beta1.Analyzer, opts v1.CreateOptions) (result *v1beta1.Analyzer, err error) {
|
||||
result = &v1beta1.Analyzer{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("analyzers").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(analyzer).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a analyzer and updates it. Returns the server's representation of the analyzer, and an error, if there is any.
|
||||
func (c *analyzers) Update(analyzer *v1beta1.Analyzer) (result *v1beta1.Analyzer, err error) {
|
||||
func (c *analyzers) Update(ctx context.Context, analyzer *v1beta1.Analyzer, opts v1.UpdateOptions) (result *v1beta1.Analyzer, err error) {
|
||||
result = &v1beta1.Analyzer{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("analyzers").
|
||||
Name(analyzer.Name).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(analyzer).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
|
||||
func (c *analyzers) UpdateStatus(analyzer *v1beta1.Analyzer) (result *v1beta1.Analyzer, err error) {
|
||||
func (c *analyzers) UpdateStatus(ctx context.Context, analyzer *v1beta1.Analyzer, opts v1.UpdateOptions) (result *v1beta1.Analyzer, err error) {
|
||||
result = &v1beta1.Analyzer{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("analyzers").
|
||||
Name(analyzer.Name).
|
||||
SubResource("status").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(analyzer).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the analyzer and deletes it. Returns an error if one occurs.
|
||||
func (c *analyzers) Delete(name string, options *v1.DeleteOptions) error {
|
||||
func (c *analyzers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("analyzers").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *analyzers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
func (c *analyzers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
if listOpts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("analyzers").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
VersionedParams(&listOpts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched analyzer.
|
||||
func (c *analyzers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Analyzer, err error) {
|
||||
func (c *analyzers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Analyzer, err error) {
|
||||
result = &v1beta1.Analyzer{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("analyzers").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
SubResource(subresources...).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(data).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ limitations under the License.
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
v1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
@@ -36,15 +37,15 @@ type CollectorsGetter interface {
|
||||
|
||||
// CollectorInterface has methods to work with Collector resources.
|
||||
type CollectorInterface interface {
|
||||
Create(*v1beta1.Collector) (*v1beta1.Collector, error)
|
||||
Update(*v1beta1.Collector) (*v1beta1.Collector, error)
|
||||
UpdateStatus(*v1beta1.Collector) (*v1beta1.Collector, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1beta1.Collector, error)
|
||||
List(opts v1.ListOptions) (*v1beta1.CollectorList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Collector, err error)
|
||||
Create(ctx context.Context, collector *v1beta1.Collector, opts v1.CreateOptions) (*v1beta1.Collector, error)
|
||||
Update(ctx context.Context, collector *v1beta1.Collector, opts v1.UpdateOptions) (*v1beta1.Collector, error)
|
||||
UpdateStatus(ctx context.Context, collector *v1beta1.Collector, opts v1.UpdateOptions) (*v1beta1.Collector, error)
|
||||
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.Collector, error)
|
||||
List(ctx context.Context, opts v1.ListOptions) (*v1beta1.CollectorList, error)
|
||||
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Collector, err error)
|
||||
CollectorExpansion
|
||||
}
|
||||
|
||||
@@ -63,20 +64,20 @@ func newCollectors(c *TroubleshootV1beta1Client, namespace string) *collectors {
|
||||
}
|
||||
|
||||
// Get takes name of the collector, and returns the corresponding collector object, and an error if there is any.
|
||||
func (c *collectors) Get(name string, options v1.GetOptions) (result *v1beta1.Collector, err error) {
|
||||
func (c *collectors) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Collector, err error) {
|
||||
result = &v1beta1.Collector{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("collectors").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Collectors that match those selectors.
|
||||
func (c *collectors) List(opts v1.ListOptions) (result *v1beta1.CollectorList, err error) {
|
||||
func (c *collectors) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.CollectorList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
@@ -87,13 +88,13 @@ func (c *collectors) List(opts v1.ListOptions) (result *v1beta1.CollectorList, e
|
||||
Resource("collectors").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested collectors.
|
||||
func (c *collectors) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
func (c *collectors) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
@@ -104,87 +105,90 @@ func (c *collectors) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
Resource("collectors").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
Watch(ctx)
|
||||
}
|
||||
|
||||
// Create takes the representation of a collector and creates it. Returns the server's representation of the collector, and an error, if there is any.
|
||||
func (c *collectors) Create(collector *v1beta1.Collector) (result *v1beta1.Collector, err error) {
|
||||
func (c *collectors) Create(ctx context.Context, collector *v1beta1.Collector, opts v1.CreateOptions) (result *v1beta1.Collector, err error) {
|
||||
result = &v1beta1.Collector{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("collectors").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(collector).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a collector and updates it. Returns the server's representation of the collector, and an error, if there is any.
|
||||
func (c *collectors) Update(collector *v1beta1.Collector) (result *v1beta1.Collector, err error) {
|
||||
func (c *collectors) Update(ctx context.Context, collector *v1beta1.Collector, opts v1.UpdateOptions) (result *v1beta1.Collector, err error) {
|
||||
result = &v1beta1.Collector{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("collectors").
|
||||
Name(collector.Name).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(collector).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
|
||||
func (c *collectors) UpdateStatus(collector *v1beta1.Collector) (result *v1beta1.Collector, err error) {
|
||||
func (c *collectors) UpdateStatus(ctx context.Context, collector *v1beta1.Collector, opts v1.UpdateOptions) (result *v1beta1.Collector, err error) {
|
||||
result = &v1beta1.Collector{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("collectors").
|
||||
Name(collector.Name).
|
||||
SubResource("status").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(collector).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the collector and deletes it. Returns an error if one occurs.
|
||||
func (c *collectors) Delete(name string, options *v1.DeleteOptions) error {
|
||||
func (c *collectors) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("collectors").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *collectors) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
func (c *collectors) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
if listOpts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("collectors").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
VersionedParams(&listOpts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched collector.
|
||||
func (c *collectors) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Collector, err error) {
|
||||
func (c *collectors) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Collector, err error) {
|
||||
result = &v1beta1.Collector{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("collectors").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
SubResource(subresources...).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(data).
|
||||
Do().
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ limitations under the License.
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
@@ -38,7 +40,7 @@ var analyzersResource = schema.GroupVersionResource{Group: "troubleshoot.replica
|
||||
var analyzersKind = schema.GroupVersionKind{Group: "troubleshoot.replicated.com", Version: "v1beta1", Kind: "Analyzer"}
|
||||
|
||||
// Get takes name of the analyzer, and returns the corresponding analyzer object, and an error if there is any.
|
||||
func (c *FakeAnalyzers) Get(name string, options v1.GetOptions) (result *v1beta1.Analyzer, err error) {
|
||||
func (c *FakeAnalyzers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Analyzer, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(analyzersResource, c.ns, name), &v1beta1.Analyzer{})
|
||||
|
||||
@@ -49,7 +51,7 @@ func (c *FakeAnalyzers) Get(name string, options v1.GetOptions) (result *v1beta1
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Analyzers that match those selectors.
|
||||
func (c *FakeAnalyzers) List(opts v1.ListOptions) (result *v1beta1.AnalyzerList, err error) {
|
||||
func (c *FakeAnalyzers) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.AnalyzerList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(analyzersResource, analyzersKind, c.ns, opts), &v1beta1.AnalyzerList{})
|
||||
|
||||
@@ -71,14 +73,14 @@ func (c *FakeAnalyzers) List(opts v1.ListOptions) (result *v1beta1.AnalyzerList,
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested analyzers.
|
||||
func (c *FakeAnalyzers) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
func (c *FakeAnalyzers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(analyzersResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a analyzer and creates it. Returns the server's representation of the analyzer, and an error, if there is any.
|
||||
func (c *FakeAnalyzers) Create(analyzer *v1beta1.Analyzer) (result *v1beta1.Analyzer, err error) {
|
||||
func (c *FakeAnalyzers) Create(ctx context.Context, analyzer *v1beta1.Analyzer, opts v1.CreateOptions) (result *v1beta1.Analyzer, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(analyzersResource, c.ns, analyzer), &v1beta1.Analyzer{})
|
||||
|
||||
@@ -89,7 +91,7 @@ func (c *FakeAnalyzers) Create(analyzer *v1beta1.Analyzer) (result *v1beta1.Anal
|
||||
}
|
||||
|
||||
// Update takes the representation of a analyzer and updates it. Returns the server's representation of the analyzer, and an error, if there is any.
|
||||
func (c *FakeAnalyzers) Update(analyzer *v1beta1.Analyzer) (result *v1beta1.Analyzer, err error) {
|
||||
func (c *FakeAnalyzers) Update(ctx context.Context, analyzer *v1beta1.Analyzer, opts v1.UpdateOptions) (result *v1beta1.Analyzer, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(analyzersResource, c.ns, analyzer), &v1beta1.Analyzer{})
|
||||
|
||||
@@ -101,7 +103,7 @@ func (c *FakeAnalyzers) Update(analyzer *v1beta1.Analyzer) (result *v1beta1.Anal
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeAnalyzers) UpdateStatus(analyzer *v1beta1.Analyzer) (*v1beta1.Analyzer, error) {
|
||||
func (c *FakeAnalyzers) UpdateStatus(ctx context.Context, analyzer *v1beta1.Analyzer, opts v1.UpdateOptions) (*v1beta1.Analyzer, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(analyzersResource, "status", c.ns, analyzer), &v1beta1.Analyzer{})
|
||||
|
||||
@@ -112,7 +114,7 @@ func (c *FakeAnalyzers) UpdateStatus(analyzer *v1beta1.Analyzer) (*v1beta1.Analy
|
||||
}
|
||||
|
||||
// Delete takes name of the analyzer and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeAnalyzers) Delete(name string, options *v1.DeleteOptions) error {
|
||||
func (c *FakeAnalyzers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(analyzersResource, c.ns, name), &v1beta1.Analyzer{})
|
||||
|
||||
@@ -120,15 +122,15 @@ func (c *FakeAnalyzers) Delete(name string, options *v1.DeleteOptions) error {
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeAnalyzers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(analyzersResource, c.ns, listOptions)
|
||||
func (c *FakeAnalyzers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(analyzersResource, c.ns, listOpts)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1beta1.AnalyzerList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched analyzer.
|
||||
func (c *FakeAnalyzers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Analyzer, err error) {
|
||||
func (c *FakeAnalyzers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Analyzer, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(analyzersResource, c.ns, name, pt, data, subresources...), &v1beta1.Analyzer{})
|
||||
|
||||
|
||||
+12
-10
@@ -18,6 +18,8 @@ limitations under the License.
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
@@ -38,7 +40,7 @@ var collectorsResource = schema.GroupVersionResource{Group: "troubleshoot.replic
|
||||
var collectorsKind = schema.GroupVersionKind{Group: "troubleshoot.replicated.com", Version: "v1beta1", Kind: "Collector"}
|
||||
|
||||
// Get takes name of the collector, and returns the corresponding collector object, and an error if there is any.
|
||||
func (c *FakeCollectors) Get(name string, options v1.GetOptions) (result *v1beta1.Collector, err error) {
|
||||
func (c *FakeCollectors) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Collector, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(collectorsResource, c.ns, name), &v1beta1.Collector{})
|
||||
|
||||
@@ -49,7 +51,7 @@ func (c *FakeCollectors) Get(name string, options v1.GetOptions) (result *v1beta
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Collectors that match those selectors.
|
||||
func (c *FakeCollectors) List(opts v1.ListOptions) (result *v1beta1.CollectorList, err error) {
|
||||
func (c *FakeCollectors) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.CollectorList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(collectorsResource, collectorsKind, c.ns, opts), &v1beta1.CollectorList{})
|
||||
|
||||
@@ -71,14 +73,14 @@ func (c *FakeCollectors) List(opts v1.ListOptions) (result *v1beta1.CollectorLis
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested collectors.
|
||||
func (c *FakeCollectors) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
func (c *FakeCollectors) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(collectorsResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a collector and creates it. Returns the server's representation of the collector, and an error, if there is any.
|
||||
func (c *FakeCollectors) Create(collector *v1beta1.Collector) (result *v1beta1.Collector, err error) {
|
||||
func (c *FakeCollectors) Create(ctx context.Context, collector *v1beta1.Collector, opts v1.CreateOptions) (result *v1beta1.Collector, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(collectorsResource, c.ns, collector), &v1beta1.Collector{})
|
||||
|
||||
@@ -89,7 +91,7 @@ func (c *FakeCollectors) Create(collector *v1beta1.Collector) (result *v1beta1.C
|
||||
}
|
||||
|
||||
// Update takes the representation of a collector and updates it. Returns the server's representation of the collector, and an error, if there is any.
|
||||
func (c *FakeCollectors) Update(collector *v1beta1.Collector) (result *v1beta1.Collector, err error) {
|
||||
func (c *FakeCollectors) Update(ctx context.Context, collector *v1beta1.Collector, opts v1.UpdateOptions) (result *v1beta1.Collector, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(collectorsResource, c.ns, collector), &v1beta1.Collector{})
|
||||
|
||||
@@ -101,7 +103,7 @@ func (c *FakeCollectors) Update(collector *v1beta1.Collector) (result *v1beta1.C
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeCollectors) UpdateStatus(collector *v1beta1.Collector) (*v1beta1.Collector, error) {
|
||||
func (c *FakeCollectors) UpdateStatus(ctx context.Context, collector *v1beta1.Collector, opts v1.UpdateOptions) (*v1beta1.Collector, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(collectorsResource, "status", c.ns, collector), &v1beta1.Collector{})
|
||||
|
||||
@@ -112,7 +114,7 @@ func (c *FakeCollectors) UpdateStatus(collector *v1beta1.Collector) (*v1beta1.Co
|
||||
}
|
||||
|
||||
// Delete takes name of the collector and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeCollectors) Delete(name string, options *v1.DeleteOptions) error {
|
||||
func (c *FakeCollectors) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(collectorsResource, c.ns, name), &v1beta1.Collector{})
|
||||
|
||||
@@ -120,15 +122,15 @@ func (c *FakeCollectors) Delete(name string, options *v1.DeleteOptions) error {
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeCollectors) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(collectorsResource, c.ns, listOptions)
|
||||
func (c *FakeCollectors) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(collectorsResource, c.ns, listOpts)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1beta1.CollectorList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched collector.
|
||||
func (c *FakeCollectors) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Collector, err error) {
|
||||
func (c *FakeCollectors) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Collector, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(collectorsResource, c.ns, name, pt, data, subresources...), &v1beta1.Collector{})
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user