Skip to content

Commit 5830eb3

Browse files
authored
Merge pull request #74 from replicatedhq/analyze-spec
Analyze spec
2 parents 25ec38b + 8a1bb8a commit 5830eb3

File tree

12 files changed

+242
-55
lines changed

12 files changed

+242
-55
lines changed

Makefile

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ manager: generate fmt vet
2222
support-bundle: generate fmt vet
2323
go build -o bin/support-bundle github.com/replicatedhq/troubleshoot/cmd/troubleshoot
2424

25-
.PHONY: collector
26-
collector: generate fmt vet
27-
go build -o bin/collector github.com/replicatedhq/troubleshoot/cmd/collector
28-
2925
.PHONY: preflight
3026
preflight: generate fmt vet
3127
go build -o bin/preflight github.com/replicatedhq/troubleshoot/cmd/preflight
3228

29+
.PHONY: analyze
30+
analyze: generate fmt vet
31+
go build -o bin/analyze github.com/replicatedhq/troubleshoot/cmd/analyze
32+
3333
.PHONY: run
3434
run: generate fmt vet
3535
TROUBLESHOOT_EXTERNAL_MANAGER=1 go run ./cmd/manager/main.go
@@ -103,14 +103,12 @@ local-release:
103103

104104
.PHONY: run-preflight
105105
run-preflight: preflight
106-
./bin/preflight \
107-
--image=localhost:32000/troubleshoot:alpha \
108-
--pullpolicy=Always \
109-
./examples/preflight/sample-preflight.yaml
106+
./bin/preflight ./examples/preflight/sample-preflight.yaml
110107

111108
.PHONY: run-troubleshoot
112109
run-troubleshoot: support-bundle
113-
./bin/support-bundle \
114-
--image=localhost:32000/troubleshoot:alpha \
115-
--pullpolicy=Always \
116-
./examples/troubleshoot/sample-troubleshoot.yaml
110+
./bin/support-bundle ./examples/troubleshoot/sample-troubleshoot.yaml
111+
112+
.PHONY: run-analyze
113+
run-analyze: analyze
114+
./bin/analyze --analyzers ./examples/troubleshoot/sample-analyzers.yaml ./support-bundle.tar.gz

cmd/analyze/cli/root.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
8+
"github.com/replicatedhq/troubleshoot/pkg/logger"
9+
"github.com/spf13/cobra"
10+
"github.com/spf13/viper"
11+
"k8s.io/cli-runtime/pkg/genericclioptions"
12+
)
13+
14+
var (
15+
KubernetesConfigFlags *genericclioptions.ConfigFlags
16+
)
17+
18+
func RootCmd() *cobra.Command {
19+
cmd := &cobra.Command{
20+
Use: "analyze [url]",
21+
Args: cobra.MinimumNArgs(1),
22+
Short: "Analyze a support bundle",
23+
Long: `Run a series of analyzers on a support bundle archive`,
24+
PreRun: func(cmd *cobra.Command, args []string) {
25+
viper.BindPFlags(cmd.Flags())
26+
},
27+
RunE: func(cmd *cobra.Command, args []string) error {
28+
v := viper.GetViper()
29+
30+
logger.SetQuiet(v.GetBool("quiet"))
31+
32+
return runAnalyzers(v, args[0])
33+
},
34+
}
35+
36+
cobra.OnInitialize(initConfig)
37+
38+
cmd.Flags().String("analyzers", "", "filename or url of the analyzers to use")
39+
40+
viper.BindPFlags(cmd.Flags())
41+
42+
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
43+
44+
KubernetesConfigFlags = genericclioptions.NewConfigFlags(false)
45+
KubernetesConfigFlags.AddFlags(cmd.Flags())
46+
47+
return cmd
48+
}
49+
50+
func InitAndExecute() {
51+
if err := RootCmd().Execute(); err != nil {
52+
fmt.Println(err)
53+
os.Exit(1)
54+
}
55+
}
56+
57+
func initConfig() {
58+
viper.SetEnvPrefix("TROUBLESHOOT")
59+
viper.AutomaticEnv()
60+
}

cmd/analyze/cli/run.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"net/http"
7+
"net/url"
8+
"os"
9+
10+
"github.com/pkg/errors"
11+
analyzer "github.com/replicatedhq/troubleshoot/pkg/analyze"
12+
"github.com/spf13/viper"
13+
)
14+
15+
func runAnalyzers(v *viper.Viper, bundlePath string) error {
16+
specPath := v.GetString("analyzers")
17+
18+
specContent := ""
19+
if !isURL(specPath) {
20+
if _, err := os.Stat(specPath); os.IsNotExist(err) {
21+
return fmt.Errorf("%s was not found", specPath)
22+
}
23+
24+
b, err := ioutil.ReadFile(specPath)
25+
if err != nil {
26+
return err
27+
}
28+
29+
specContent = string(b)
30+
} else {
31+
req, err := http.NewRequest("GET", specPath, nil)
32+
if err != nil {
33+
return err
34+
}
35+
req.Header.Set("User-Agent", "Replicated_Analyzer/v1beta1")
36+
resp, err := http.DefaultClient.Do(req)
37+
if err != nil {
38+
return err
39+
}
40+
defer resp.Body.Close()
41+
42+
body, err := ioutil.ReadAll(resp.Body)
43+
if err != nil {
44+
return err
45+
}
46+
47+
specContent = string(body)
48+
}
49+
50+
analyzeResults, err := analyzer.DownloadAndAnalyze(specContent, bundlePath)
51+
if err != nil {
52+
return errors.Wrap(err, "failed to download and analyze bundle")
53+
}
54+
55+
for _, analyzeResult := range analyzeResults {
56+
if analyzeResult.IsPass {
57+
fmt.Printf("Pass: %s\n %s\n", analyzeResult.Title, analyzeResult.Message)
58+
} else if analyzeResult.IsWarn {
59+
fmt.Printf("Warn: %s\n %s\n", analyzeResult.Title, analyzeResult.Message)
60+
} else if analyzeResult.IsFail {
61+
fmt.Printf("Fail: %s\n %s\n", analyzeResult.Title, analyzeResult.Message)
62+
}
63+
}
64+
65+
return nil
66+
}
67+
68+
func isURL(str string) bool {
69+
parsed, err := url.ParseRequestURI(str)
70+
if err != nil {
71+
return false
72+
}
73+
74+
return parsed.Scheme != ""
75+
}

cmd/analyze/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import (
4+
"github.com/replicatedhq/troubleshoot/cmd/analyze/cli"
5+
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
6+
)
7+
8+
func main() {
9+
cli.InitAndExecute()
10+
}

cmd/preflight/cli/util.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ func homeDir() string {
1717
}
1818

1919
func isURL(str string) bool {
20-
_, err := url.ParseRequestURI(str)
20+
parsed, err := url.ParseRequestURI(str)
2121
if err != nil {
2222
return false
2323
}
2424

25-
return true
25+
return parsed.Scheme != ""
2626
}
2727

2828
func createTroubleshootK8sClient(configFlags *genericclioptions.ConfigFlags) (*troubleshootclientv1beta1.TroubleshootV1beta1Client, error) {

cmd/troubleshoot/cli/analyze.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cli
22

33
import (
4-
"context"
54
"encoding/json"
65
"fmt"
76

@@ -28,7 +27,7 @@ func Analyze() *cobra.Command {
2827

2928
logger.SetQuiet(v.GetBool("quiet"))
3029

31-
result, err := analyzer.DownloadAndAnalyze(context.TODO(), v.GetString("url"))
30+
result, err := analyzer.DownloadAndAnalyze("", v.GetString("url"))
3231
if err != nil {
3332
return err
3433
}

cmd/troubleshoot/cli/util.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ func homeDir() string {
1818
}
1919

2020
func isURL(str string) bool {
21-
_, err := url.ParseRequestURI(str)
21+
parsed, err := url.ParseRequestURI(str)
2222
if err != nil {
2323
return false
2424
}
2525

26-
return true
26+
return parsed.Scheme != ""
2727
}
2828

2929
func createTroubleshootK8sClient(configFlags *genericclioptions.ConfigFlags) (*troubleshootclientv1beta1.TroubleshootV1beta1Client, error) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: troubleshoot.replicated.com/v1beta1
2+
kind: Analyzer
3+
metadata:
4+
name: defaultAnalyzers
5+
spec:
6+
analyzers:
7+
- clusterVersion:
8+
outcomes:
9+
- fail:
10+
when: "< 1.13.0"
11+
message: The application requires at Kubernetes 1.13.0 or later, and recommends 1.15.0.
12+
uri: https://www.kubernetes.io
13+
- warn:
14+
when: "< 1.15.0"
15+
message: Your cluster meets the minimum version of Kubernetes, but we recommend you update to 1.15.0 or later.
16+
uri: https://kubernetes.io
17+
- pass:
18+
when: ">= 1.15.0"
19+
message: Your cluster meets the recommended and required versions of Kubernetes.

ffi/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ import (
1515
)
1616

1717
//export Analyze
18-
func Analyze(bundleURL string, outputFormat string, compatibility string) *C.char {
18+
func Analyze(bundleURL string, analyzers string, outputFormat string, compatibility string) *C.char {
1919
logger.SetQuiet(true)
2020

21-
result, err := analyzer.DownloadAndAnalyze(context.TODO(), bundleURL)
21+
result, err := analyzer.DownloadAndAnalyze(bundleURL, analyzers)
2222
if err != nil {
2323
fmt.Printf("error downloading and analyzing: %s\n", err.Error())
2424
return C.CString("")

pkg/analyze/download.go

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,24 @@ package analyzer
33
import (
44
"archive/tar"
55
"compress/gzip"
6-
"context"
7-
"fmt"
86
"io"
97
"io/ioutil"
10-
"net/http"
118
"os"
129
"path/filepath"
1310

1411
getter "github.com/hashicorp/go-getter"
1512
"github.com/pkg/errors"
1613
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
14+
troubleshootscheme "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme"
1715
"github.com/replicatedhq/troubleshoot/pkg/logger"
18-
"gopkg.in/yaml.v2"
16+
"k8s.io/client-go/kubernetes/scheme"
1917
)
2018

2119
type fileContentProvider struct {
2220
rootDir string
2321
}
2422

25-
func DownloadAndAnalyze(ctx context.Context, bundleURL string) ([]*AnalyzeResult, error) {
23+
func DownloadAndAnalyze(analyzersSpec string, bundleURL string) ([]*AnalyzeResult, error) {
2624
tmpDir, err := ioutil.TempDir("", "troubleshoot-k8s")
2725
if err != nil {
2826
return nil, errors.Wrap(err, "failed to create temp dir")
@@ -38,9 +36,20 @@ func DownloadAndAnalyze(ctx context.Context, bundleURL string) ([]*AnalyzeResult
3836
return nil, errors.Wrap(err, "failed to read version.yaml")
3937
}
4038

41-
analyzers, err := getTroubleshootAnalyzers()
42-
if err != nil {
43-
return nil, errors.Wrap(err, "failed to get analyzers")
39+
analyzers := []*troubleshootv1beta1.Analyze{}
40+
41+
if analyzersSpec == "" {
42+
defaultAnalyzers, err := getDefaultAnalyzers()
43+
if err != nil {
44+
return nil, errors.Wrap(err, "failed to get default analyzers")
45+
}
46+
analyzers = defaultAnalyzers
47+
} else {
48+
parsedAnalyzers, err := parseAnalyzers(analyzersSpec)
49+
if err != nil {
50+
return nil, errors.Wrap(err, "failed to parse analyzers")
51+
}
52+
analyzers = parsedAnalyzers
4453
}
4554

4655
fcp := fileContentProvider{rootDir: tmpDir}
@@ -138,29 +147,41 @@ func extractTroubleshootBundle(reader io.Reader, destDir string) error {
138147
return nil
139148
}
140149

141-
func getTroubleshootAnalyzers() ([]*troubleshootv1beta1.Analyze, error) {
142-
specURL := `https://troubleshoot.replicated.com/`
143-
resp, err := http.Get(specURL)
144-
if err != nil {
145-
return nil, err
146-
}
147-
defer resp.Body.Close()
148-
149-
if resp.StatusCode != http.StatusOK {
150-
return nil, fmt.Errorf("could not download analyzer spec, status code: %v", resp.StatusCode)
151-
}
150+
func parseAnalyzers(spec string) ([]*troubleshootv1beta1.Analyze, error) {
151+
troubleshootscheme.AddToScheme(scheme.Scheme)
152+
decode := scheme.Codecs.UniversalDeserializer().Decode
152153

153-
spec, err := ioutil.ReadAll(resp.Body)
154+
obj, _, err := decode([]byte(spec), nil, nil)
154155
if err != nil {
155-
return nil, err
156+
return nil, errors.Wrap(err, "failed to decode analyzers")
156157
}
157158

158-
preflight := troubleshootv1beta1.Preflight{}
159-
if err := yaml.Unmarshal([]byte(spec), &preflight); err != nil {
160-
return nil, err
161-
}
159+
analyzer := obj.(*troubleshootv1beta1.Analyzer)
160+
return analyzer.Spec.Analyzers, nil
161+
}
162162

163-
return preflight.Spec.Analyzers, nil
163+
func getDefaultAnalyzers() ([]*troubleshootv1beta1.Analyze, error) {
164+
spec := `apiVersion: troubleshoot.replicated.com/v1beta1
165+
kind: Analyzer
166+
metadata:
167+
name: defaultAnalyzers
168+
spec:
169+
analyzers:
170+
- clusterVersion:
171+
outcomes:
172+
- fail:
173+
when: "< 1.13.0"
174+
message: The application requires at Kubernetes 1.13.0 or later, and recommends 1.15.0.
175+
uri: https://www.kubernetes.io
176+
- warn:
177+
when: "< 1.15.0"
178+
message: Your cluster meets the minimum version of Kubernetes, but we recommend you update to 1.15.0 or later.
179+
uri: https://kubernetes.io
180+
- pass:
181+
when: ">= 1.15.0"
182+
message: Your cluster meets the recommended and required versions of Kubernetes.`
183+
184+
return parseAnalyzers(spec)
164185
}
165186

166187
func (f fileContentProvider) getFileContents(fileName string) ([]byte, error) {

0 commit comments

Comments
 (0)