From 074fee81f7a83f51912abc6fdcd3b534f805783e Mon Sep 17 00:00:00 2001 From: Marc Campbell Date: Mon, 29 Sep 2025 10:10:41 -0700 Subject: [PATCH] V1beta3 cleanup (#1869) * moving some files around * more cleanup * removing more unused --- CONTRIBUTING.md | 83 +------- bin/watch.js | 29 --- bin/watchrsync.js | 51 ----- cmd/analyze/cli/root.go | 75 ------- cmd/analyze/cli/run.go | 68 ------- cmd/analyze/main.go | 10 - cmd/collect/cli/chroot_darwin.go | 21 -- cmd/collect/cli/chroot_linux.go | 21 -- cmd/collect/cli/chroot_windows.go | 9 - cmd/collect/cli/root.go | 90 --------- cmd/collect/cli/run.go | 189 ------------------ cmd/collect/cli/stdout_results.go | 103 ---------- cmd/collect/main.go | 10 - cmd/docsgen/cli/root.go | 37 ---- cmd/docsgen/main.go | 10 - cmd/schemagen/cli/root.go | 174 ---------------- cmd/schemagen/main.go | 9 - Person-2-PRD.md => docs/Person-2-PRD.md | 0 .../design}/proposal-concurrent-collectors.md | 0 go.mod | 1 - go.sum | 1 - 21 files changed, 7 insertions(+), 984 deletions(-) delete mode 100755 bin/watch.js delete mode 100755 bin/watchrsync.js delete mode 100644 cmd/analyze/cli/root.go delete mode 100644 cmd/analyze/cli/run.go delete mode 100644 cmd/analyze/main.go delete mode 100644 cmd/collect/cli/chroot_darwin.go delete mode 100644 cmd/collect/cli/chroot_linux.go delete mode 100644 cmd/collect/cli/chroot_windows.go delete mode 100644 cmd/collect/cli/root.go delete mode 100644 cmd/collect/cli/run.go delete mode 100644 cmd/collect/cli/stdout_results.go delete mode 100644 cmd/collect/main.go delete mode 100644 cmd/docsgen/cli/root.go delete mode 100644 cmd/docsgen/main.go delete mode 100644 cmd/schemagen/cli/root.go delete mode 100644 cmd/schemagen/main.go rename Person-2-PRD.md => docs/Person-2-PRD.md (100%) rename {design => docs/design}/proposal-concurrent-collectors.md (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fb4ea73d..27a979f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,12 +1,10 @@ # Contributing to Troubleshoot -Thank you for your interest in Troubleshoot, we welcome your participation. Please familiarize yourself with our [Code of Conduct](https://github.com/replicatedhq/troubleshoot/blob/main/CODE_OF_CONDUCT.md) prior to contributing. There are a number of ways to participate in Troubleshoot as outlined below: +Thank you for your interest in Troubleshoot, we welcome your participation. There are a number of ways to participate in Troubleshoot as outlined below: # Community -For discussions about developing Troubleshoot, there's an [#app-troubleshoot channel in Kubernetes Slack](https://kubernetes.slack.com/channels/app-troubleshoot), plus IRC using [Libera](ircs://irc.libera.chat:6697/#troubleshoot) (#troubleshoot). - -There are [community meetings](https://calendar.google.com/calendar/u/0?cid=Y19mMGx1aGhiZGtscGllOGo5dWpicXMwNnN1a0Bncm91cC5jYWxlbmRhci5nb29nbGUuY29t) on a regular basis, with a shared calendar and [public notes](https://hackmd.io/yZbotEHdTg6TfRZBzb8Tcg) +For discussions about developing Troubleshoot, there's an [#app-troubleshoot channel in Kubernetes Slack](https://kubernetes.slack.com/channels/app-troubleshoot). ## Issues @@ -21,44 +19,15 @@ When implementing a new feature please review the [design principles](./docs/des To get started we recommend: -1. Go (v1.20 or later) -2. A Kubernetes cluster (we recommend . This requires Docker v20.10.5 or later) +1. Go (v1.24 or later) +2. For cluster-based collectors, you will need access to a Kubernetes cluster 3. Fork and clone repo 4. Run `make clean build` to generate binaries -5. Run `make run-support-bundle` to generate a support bundle with the `sample-troubleshoot.yaml` in the root of the repo +5. You can now run `./bin/preflight` and/or `./bin/support-bundle` to use the code you've been writing -> Note: recent versions of Go support easy cross-compilation. For example, to cross-compile a Linux binary from MacOS: +> Note: to cross-compile a Linux binary from MacOS: > `GOOS=linux GOARCH=amd64 make clean build` -6. Install [golangci-lint] linter and run `make lint` to execute additional code linters. - -### Build automatically on save with `watch` - -1. Install `npm` -2. Run `make watch` to build binaries automatically on saving. Note: you may still have to run `make schemas` if you've added API changes, like a new collector or analyzer type. - -### Syncing to a test cluster with `watchrsync` - -1. Install `npm` -2. Export `REMOTES=@` so that `watchrsync` knows where to sync. -3. Maybe run `export GOOS=linux` and `export GOARCH=amd64` so that you build Linux binaries. -4. run `make watchrsync` to build and sync binaries automatically on saving. - -``` -ssh-add --apple-use-keychain ~/.ssh/google_compute_engine -export REMOTES=ada@35.229.61.56 -export GOOS=linux -export GOARCH=amd64 -make watchrsync -# bin/watchrsync.js -# make support-bundle -# go build -tags "netgo containers_image_ostree_stub exclude_graphdriver_devicemapper exclude_graphdriver_btrfs containers_image_openpgp" -installsuffix netgo -ldflags " -s -w -X github.com/replicatedhq/troubleshoot/pkg/version.version=`git describe --tags --dirty` -X github.com/replicatedhq/troubleshoot/pkg/version.gitSHA=`git rev-parse HEAD` -X github.com/replicatedhq/troubleshoot/pkg/version.buildTime=`date -u +"%Y-%m-%dT%H:%M:%SZ"` " -o bin/support-bundle github.com/replicatedhq/troubleshoot/cmd/troubleshoot -# rsync bin/support-bundle ada@35.229.61.56: -# date -# Tue May 16 14:14:13 EDT 2023 -# synced -``` - ### Testing To run the tests locally run the following: @@ -104,42 +73,4 @@ More on profiling please visit https://go.dev/doc/diagnostics#profiling ## Contribution workflow -This is a rough outline of how to prepare a contribution: - -- Create a fork of this repo. -- Create a topic branch from where you want to base your work (branched from `main` is a safe choice). -- Make commits of logical units. -- When your changes are ready to merge, squash your history to 1 commit. - - For example, if you want to squash your last 3 commits and write a new commit message: - - ``` - git reset --soft HEAD~3 && - git commit - ``` - - - If you want to keep the previous commit messages and concatenate them all into a new commit, you can do something like this instead: - - ``` - git reset --soft HEAD~3 && - git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})" - ``` - -- Push your changes to a topic branch in your fork of the repository. -- Submit a pull request to the original repository. It will be reviewed in a timely manner. - -### Pull Requests - -A pull request should address a single issue, feature or bug. For example, lets say you've written code that fixes two issues. That's great! However, you should submit two small pull requests, one for each issue as opposed to combining them into a single larger pull request. In general the size of the pull request should be kept small in order to make it easy for a reviewer to understand, and to minimize risks from integrating many changes at the same time. For example, if you are working on a large feature you should break it into several smaller PRs by implementing the feature as changes to several packages and submitting a separate pull request for each one. Squash commit history when preparing your PR so it merges as 1 commit. - -Code submitted in pull requests must be properly documented, formatted and tested in order to be approved and merged. The following guidelines describe the things a reviewer will look for when they evaluate your pull request. Here's a tip. If your reviewer doesn't understand what the code is doing, they won't approve the pull request. Strive to make code clear and well documented. If possible, request a reviewer that has some context on the PR. - -### Commit messages - -Commit messages should follow the general guidelines: - -- Breaking changes should be highlighted in the heading of the commit message. -- Commits should be clear about their purpose (and a single commit per thing that changed) -- Messages should be descriptive: - - First line, 50 chars or less, as a heading/title that people can find - - Then a paragraph explaining things -- Consider a footer with links to which bugs they fix etc, bearing in mind that Github does some of this magic already +We'd love to talk before you dig into a a large feature. diff --git a/bin/watch.js b/bin/watch.js deleted file mode 100755 index b2d53566..00000000 --- a/bin/watch.js +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env node - -const gri = require('gaze-run-interrupt'); - -const commands = [ - // { - // command: 'rm', - // args: binList, - // }, - { - command: 'make', - args: ['build'], - }, -]; - -commands.push({ - command: "date", - args: [], -}); - -commands.push({ - command: "echo", - args: ["synced"], -}); - -gri([ - 'cmd/**/*.go', - 'pkg/**/*.go', -], commands); diff --git a/bin/watchrsync.js b/bin/watchrsync.js deleted file mode 100755 index a77826a3..00000000 --- a/bin/watchrsync.js +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env node - -const gri = require('gaze-run-interrupt'); - -if (!process.env.REMOTES) { - console.log("Usage: `REMOTES='user@h1.1.1.1,user@1.1.1.2' ./watchrsync.js`"); - process.exit(1); -} - -process.env.GOOS = 'linux'; -process.env.GOARCH = 'amd64'; - -const binList = [ - // 'bin/analyze', - // 'bin/preflight', - 'bin/support-bundle', - // 'bin/collect' -] - -const commands = [ - // { - // command: 'rm', - // args: binList, - // }, - { - command: 'make', - args: ['build'], - }, -]; - -process.env.REMOTES.split(",").forEach(function (remote) { - commands.push({ - command: 'rsync', - args: binList.concat(`${remote}:`), - }); -}); - -commands.push({ - command: "date", - args: [], -}); - -commands.push({ - command: "echo", - args: ["synced"], -}); - -gri([ - 'cmd/**/*.go', - 'pkg/**/*.go', -], commands); diff --git a/cmd/analyze/cli/root.go b/cmd/analyze/cli/root.go deleted file mode 100644 index a685cf8a..00000000 --- a/cmd/analyze/cli/root.go +++ /dev/null @@ -1,75 +0,0 @@ -package cli - -import ( - "os" - "strings" - - "github.com/replicatedhq/troubleshoot/cmd/internal/util" - "github.com/replicatedhq/troubleshoot/pkg/k8sutil" - "github.com/replicatedhq/troubleshoot/pkg/logger" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "k8s.io/klog/v2" -) - -func RootCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "analyze [url]", - Args: cobra.MinimumNArgs(1), - Short: "Analyze a support bundle", - Long: `Run a series of analyzers on a support bundle archive`, - SilenceUsage: true, - PreRun: func(cmd *cobra.Command, args []string) { - v := viper.GetViper() - v.BindPFlags(cmd.Flags()) - - logger.SetupLogger(v) - - if err := util.StartProfiling(); err != nil { - klog.Errorf("Failed to start profiling: %v", err) - } - }, - RunE: func(cmd *cobra.Command, args []string) error { - v := viper.GetViper() - - return runAnalyzers(v, args[0]) - }, - PostRun: func(cmd *cobra.Command, args []string) { - if err := util.StopProfiling(); err != nil { - klog.Errorf("Failed to stop profiling: %v", err) - } - }, - } - - cobra.OnInitialize(initConfig) - - cmd.AddCommand(util.VersionCmd()) - - cmd.Flags().String("analyzers", "", "filename or url of the analyzers to use") - cmd.Flags().Bool("debug", false, "enable debug logging") - - viper.BindPFlags(cmd.Flags()) - - viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) - - // Initialize klog flags - logger.InitKlogFlags(cmd) - - k8sutil.AddFlags(cmd.Flags()) - - // CPU and memory profiling flags - util.AddProfilingFlags(cmd) - - return cmd -} - -func InitAndExecute() { - if err := RootCmd().Execute(); err != nil { - os.Exit(1) - } -} - -func initConfig() { - viper.SetEnvPrefix("TROUBLESHOOT") - viper.AutomaticEnv() -} diff --git a/cmd/analyze/cli/run.go b/cmd/analyze/cli/run.go deleted file mode 100644 index 447e630e..00000000 --- a/cmd/analyze/cli/run.go +++ /dev/null @@ -1,68 +0,0 @@ -package cli - -import ( - "fmt" - "io/ioutil" - "net/http" - "os" - - "github.com/pkg/errors" - "github.com/replicatedhq/troubleshoot/internal/util" - analyzer "github.com/replicatedhq/troubleshoot/pkg/analyze" - "github.com/spf13/viper" -) - -func runAnalyzers(v *viper.Viper, bundlePath string) error { - specPath := v.GetString("analyzers") - - specContent := "" - var err error - if _, err = os.Stat(specPath); err == nil { - b, err := os.ReadFile(specPath) - if err != nil { - return err - } - - specContent = string(b) - } else { - if !util.IsURL(specPath) { - // TODO: Better error message when we do not have a file/url etc - return fmt.Errorf("%s is not a URL and was not found", specPath) - } - - req, err := http.NewRequest("GET", specPath, nil) - if err != nil { - return err - } - req.Header.Set("User-Agent", "Replicated_Analyzer/v1beta1") - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - - specContent = string(body) - } - - analyzeResults, err := analyzer.DownloadAndAnalyze(bundlePath, specContent) - if err != nil { - return errors.Wrap(err, "failed to download and analyze bundle") - } - - for _, analyzeResult := range analyzeResults { - if analyzeResult.IsPass { - fmt.Printf("Pass: %s\n %s\n", analyzeResult.Title, analyzeResult.Message) - } else if analyzeResult.IsWarn { - fmt.Printf("Warn: %s\n %s\n", analyzeResult.Title, analyzeResult.Message) - } else if analyzeResult.IsFail { - fmt.Printf("Fail: %s\n %s\n", analyzeResult.Title, analyzeResult.Message) - } - } - - return nil -} diff --git a/cmd/analyze/main.go b/cmd/analyze/main.go deleted file mode 100644 index 738dacb9..00000000 --- a/cmd/analyze/main.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import ( - "github.com/replicatedhq/troubleshoot/cmd/analyze/cli" - _ "k8s.io/client-go/plugin/pkg/client/auth" -) - -func main() { - cli.InitAndExecute() -} diff --git a/cmd/collect/cli/chroot_darwin.go b/cmd/collect/cli/chroot_darwin.go deleted file mode 100644 index c24bf112..00000000 --- a/cmd/collect/cli/chroot_darwin.go +++ /dev/null @@ -1,21 +0,0 @@ -package cli - -import ( - "errors" - "syscall" - - "github.com/replicatedhq/troubleshoot/internal/util" -) - -func checkAndSetChroot(newroot string) error { - if newroot == "" { - return nil - } - if !util.IsRunningAsRoot() { - return errors.New("Can only chroot when run as root") - } - if err := syscall.Chroot(newroot); err != nil { - return err - } - return nil -} diff --git a/cmd/collect/cli/chroot_linux.go b/cmd/collect/cli/chroot_linux.go deleted file mode 100644 index c24bf112..00000000 --- a/cmd/collect/cli/chroot_linux.go +++ /dev/null @@ -1,21 +0,0 @@ -package cli - -import ( - "errors" - "syscall" - - "github.com/replicatedhq/troubleshoot/internal/util" -) - -func checkAndSetChroot(newroot string) error { - if newroot == "" { - return nil - } - if !util.IsRunningAsRoot() { - return errors.New("Can only chroot when run as root") - } - if err := syscall.Chroot(newroot); err != nil { - return err - } - return nil -} diff --git a/cmd/collect/cli/chroot_windows.go b/cmd/collect/cli/chroot_windows.go deleted file mode 100644 index 84b349a2..00000000 --- a/cmd/collect/cli/chroot_windows.go +++ /dev/null @@ -1,9 +0,0 @@ -package cli - -import ( - "errors" -) - -func checkAndSetChroot(newroot string) error { - return errors.New("chroot is only implimented in linux/darwin") -} diff --git a/cmd/collect/cli/root.go b/cmd/collect/cli/root.go deleted file mode 100644 index 86fdc5c6..00000000 --- a/cmd/collect/cli/root.go +++ /dev/null @@ -1,90 +0,0 @@ -package cli - -import ( - "os" - "strings" - - "github.com/replicatedhq/troubleshoot/cmd/internal/util" - "github.com/replicatedhq/troubleshoot/pkg/k8sutil" - "github.com/replicatedhq/troubleshoot/pkg/logger" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "k8s.io/klog/v2" -) - -func RootCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "collect [url]", - Args: cobra.MinimumNArgs(1), - Short: "Run a collector", - Long: `Run a collector and output the results.`, - SilenceUsage: true, - PreRun: func(cmd *cobra.Command, args []string) { - v := viper.GetViper() - v.BindPFlags(cmd.Flags()) - - logger.SetupLogger(v) - - if err := util.StartProfiling(); err != nil { - klog.Errorf("Failed to start profiling: %v", err) - } - }, - RunE: func(cmd *cobra.Command, args []string) error { - v := viper.GetViper() - - if err := checkAndSetChroot(v.GetString("chroot")); err != nil { - return err - } - - return runCollect(v, args[0]) - }, - PostRun: func(cmd *cobra.Command, args []string) { - if err := util.StopProfiling(); err != nil { - klog.Errorf("Failed to stop profiling: %v", err) - } - }, - } - - cobra.OnInitialize(initConfig) - - cmd.AddCommand(util.VersionCmd()) - - cmd.Flags().StringSlice("redactors", []string{}, "names of the additional redactors to use") - cmd.Flags().Bool("redact", true, "enable/disable default redactions") - cmd.Flags().String("format", "json", "output format, one of json or raw.") - cmd.Flags().String("collector-image", "", "the full name of the collector image to use") - cmd.Flags().String("collector-pull-policy", "", "the pull policy of the collector image") - cmd.Flags().String("selector", "", "selector (label query) to filter remote collection nodes on.") - cmd.Flags().Bool("collect-without-permissions", false, "always generate a support bundle, even if it some require additional permissions") - cmd.Flags().Bool("debug", false, "enable debug logging") - cmd.Flags().String("chroot", "", "Chroot to path") - - // hidden in favor of the `insecure-skip-tls-verify` flag - 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") - - viper.BindPFlags(cmd.Flags()) - - viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) - - k8sutil.AddFlags(cmd.Flags()) - - // Initialize klog flags - logger.InitKlogFlags(cmd) - - // CPU and memory profiling flags - util.AddProfilingFlags(cmd) - - return cmd -} - -func InitAndExecute() { - if err := RootCmd().Execute(); err != nil { - os.Exit(1) - } -} - -func initConfig() { - viper.SetEnvPrefix("TROUBLESHOOT") - viper.AutomaticEnv() -} diff --git a/cmd/collect/cli/run.go b/cmd/collect/cli/run.go deleted file mode 100644 index 42771b67..00000000 --- a/cmd/collect/cli/run.go +++ /dev/null @@ -1,189 +0,0 @@ -package cli - -import ( - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "os/signal" - "strings" - "time" - - "github.com/pkg/errors" - "github.com/replicatedhq/troubleshoot/internal/util" - troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" - "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme" - "github.com/replicatedhq/troubleshoot/pkg/collect" - "github.com/replicatedhq/troubleshoot/pkg/docrewrite" - "github.com/replicatedhq/troubleshoot/pkg/k8sutil" - "github.com/replicatedhq/troubleshoot/pkg/specs" - "github.com/replicatedhq/troubleshoot/pkg/supportbundle" - "github.com/spf13/viper" - "k8s.io/apimachinery/pkg/labels" -) - -const ( - defaultTimeout = 30 * time.Second -) - -func runCollect(v *viper.Viper, arg string) error { - go func() { - signalChan := make(chan os.Signal, 1) - signal.Notify(signalChan, os.Interrupt) - <-signalChan - os.Exit(0) - }() - - var collectorContent []byte - var err error - 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], "collect-spec") - if err != nil { - return errors.Wrap(err, "failed to get spec from secret") - } - - collectorContent = spec - } else if arg == "-" { - b, err := io.ReadAll(os.Stdin) - if err != nil { - return err - } - - collectorContent = b - } else if _, err = os.Stat(arg); err == nil { - b, err := os.ReadFile(arg) - if err != nil { - return err - } - - collectorContent = b - } else { - if !util.IsURL(arg) { - return fmt.Errorf("%s is not a URL and was not found", arg) - } - - req, err := http.NewRequest("GET", arg, nil) - if err != nil { - return err - } - req.Header.Set("User-Agent", "Replicated_Collect/v1beta2") - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - - collectorContent = body - } - - collectorContent, err = docrewrite.ConvertToV1Beta2(collectorContent) - if err != nil { - return errors.Wrap(err, "failed to convert to v1beta2") - } - - multidocs := strings.Split(string(collectorContent), "\n---\n") - - decode := scheme.Codecs.UniversalDeserializer().Decode - - redactors, err := supportbundle.GetRedactorsFromURIs(v.GetStringSlice("redactors")) - if err != nil { - return errors.Wrap(err, "failed to get redactors") - } - - additionalRedactors := &troubleshootv1beta2.Redactor{ - Spec: troubleshootv1beta2.RedactorSpec{ - Redactors: redactors, - }, - } - - 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.(*troubleshootv1beta2.Redactor) - if !ok { - continue - } - additionalRedactors.Spec.Redactors = append(additionalRedactors.Spec.Redactors, multidocRedactors.Spec.Redactors...) - } - - // make sure we don't block any senders - progressCh := make(chan interface{}) - defer close(progressCh) - go func() { - for range progressCh { - } - }() - - restConfig, err := k8sutil.GetRESTConfig() - if err != nil { - return errors.Wrap(err, "failed to convert kube flags to rest config") - } - - labelSelector, err := labels.Parse(v.GetString("selector")) - if err != nil { - return errors.Wrap(err, "unable to parse selector") - } - - namespace := v.GetString("namespace") - if namespace == "" { - namespace = "default" - } - - timeout := v.GetDuration("request-timeout") - if timeout == 0 { - timeout = defaultTimeout - } - - createOpts := collect.CollectorRunOpts{ - CollectWithoutPermissions: v.GetBool("collect-without-permissions"), - KubernetesRestConfig: restConfig, - Image: v.GetString("collector-image"), - PullPolicy: v.GetString("collector-pullpolicy"), - LabelSelector: labelSelector.String(), - Namespace: namespace, - Timeout: timeout, - ProgressChan: progressCh, - } - - // we only support HostCollector or RemoteCollector kinds. - hostCollector, err := collect.ParseHostCollectorFromDoc([]byte(multidocs[0])) - if err == nil { - results, err := collect.CollectHost(hostCollector, additionalRedactors, createOpts) - if err != nil { - return errors.Wrap(err, "failed to collect from host") - } - return showHostStdoutResults(v.GetString("format"), hostCollector.Name, results) - } - - remoteCollector, err := collect.ParseRemoteCollectorFromDoc([]byte(multidocs[0])) - if err == nil { - results, err := collect.CollectRemote(remoteCollector, additionalRedactors, createOpts) - if err != nil { - return errors.Wrap(err, "failed to collect from remote host(s)") - } - return showRemoteStdoutResults(v.GetString("format"), remoteCollector.Name, results) - } - - return errors.New("failed to parse hostCollector or remoteCollector") -} diff --git a/cmd/collect/cli/stdout_results.go b/cmd/collect/cli/stdout_results.go deleted file mode 100644 index 50916683..00000000 --- a/cmd/collect/cli/stdout_results.go +++ /dev/null @@ -1,103 +0,0 @@ -package cli - -import ( - "encoding/json" - "fmt" - - "github.com/pkg/errors" - "github.com/replicatedhq/troubleshoot/pkg/collect" -) - -const ( - // FormatJSON is intended for CLI output. - FormatJSON = "json" - - // FormatRaw is intended for consumption by a remote collector. Output is a - // string of quoted JSON. - FormatRaw = "raw" -) - -func showHostStdoutResults(format string, collectName string, results *collect.HostCollectResult) error { - switch format { - case FormatJSON: - return showHostStdoutResultsJSON(collectName, results.AllCollectedData) - case FormatRaw: - return showHostStdoutResultsRaw(collectName, results.AllCollectedData) - default: - return errors.Errorf("unknown output format: %q", format) - } -} - -func showRemoteStdoutResults(format string, collectName string, results *collect.RemoteCollectResult) error { - switch format { - case FormatJSON: - return showRemoteStdoutResultsJSON(collectName, results.AllCollectedData) - case FormatRaw: - return errors.Errorf("raw format not supported for remote collectors") - default: - return errors.Errorf("unknown output format: %q", format) - } -} - -func showHostStdoutResultsJSON(collectName string, results map[string][]byte) error { - output := make(map[string]interface{}) - for file, collectorResult := range results { - var collectedItems map[string]interface{} - if err := json.Unmarshal([]byte(collectorResult), &collectedItems); err != nil { - return errors.Wrap(err, "failed to marshal collector results") - } - output[file] = collectedItems - } - - formatted, err := json.MarshalIndent(output, "", " ") - if err != nil { - return errors.Wrap(err, "failed to convert output to json") - } - - fmt.Print(string(formatted)) - return nil -} - -// showHostStdoutResultsRaw outputs the collector output as a string of quoted json. -func showHostStdoutResultsRaw(collectName string, results map[string][]byte) error { - strData := map[string]string{} - for k, v := range results { - strData[k] = string(v) - } - formatted, err := json.MarshalIndent(strData, "", " ") - if err != nil { - return errors.Wrap(err, "failed to convert output to json") - } - fmt.Print(string(formatted)) - return nil -} - -func showRemoteStdoutResultsJSON(collectName string, results map[string][]byte) error { - type CollectorResult map[string]interface{} - type NodeResult map[string]CollectorResult - - var output = make(map[string]NodeResult) - - for node, result := range results { - var nodeResult map[string]string - if err := json.Unmarshal(result, &nodeResult); err != nil { - return errors.Wrap(err, "failed to marshal node results") - } - nr := make(NodeResult) - for file, collectorResult := range nodeResult { - var collectedItems map[string]interface{} - if err := json.Unmarshal([]byte(collectorResult), &collectedItems); err != nil { - return errors.Wrap(err, "failed to marshal collector results") - } - nr[file] = collectedItems - } - output[node] = nr - } - - formatted, err := json.MarshalIndent(output, "", " ") - if err != nil { - return errors.Wrap(err, "failed to convert output to json") - } - fmt.Print(string(formatted)) - return nil -} diff --git a/cmd/collect/main.go b/cmd/collect/main.go deleted file mode 100644 index 7238c046..00000000 --- a/cmd/collect/main.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import ( - "github.com/replicatedhq/troubleshoot/cmd/collect/cli" - _ "k8s.io/client-go/plugin/pkg/client/auth" -) - -func main() { - cli.InitAndExecute() -} diff --git a/cmd/docsgen/cli/root.go b/cmd/docsgen/cli/root.go deleted file mode 100644 index 3e5f6888..00000000 --- a/cmd/docsgen/cli/root.go +++ /dev/null @@ -1,37 +0,0 @@ -package cli - -import ( - "log" - "os" - - preflightcli "github.com/replicatedhq/troubleshoot/cmd/preflight/cli" - troubleshootcli "github.com/replicatedhq/troubleshoot/cmd/troubleshoot/cli" - "github.com/spf13/cobra" - - "github.com/spf13/cobra/doc" -) - -func RootCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "docsgen", - Short: "Generate markdown docs for the commands in this project", - } - preflight := preflightcli.RootCmd() - troubleshoot := troubleshootcli.RootCmd() - commands := []*cobra.Command{preflight, troubleshoot} - - for _, command := range commands { - err := doc.GenMarkdownTree(command, "./docs") - if err != nil { - log.Fatal(err) - } - } - - return cmd -} - -func InitAndExecute() { - if err := RootCmd().Execute(); err != nil { - os.Exit(1) - } -} diff --git a/cmd/docsgen/main.go b/cmd/docsgen/main.go deleted file mode 100644 index 2a729b2a..00000000 --- a/cmd/docsgen/main.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import ( - "github.com/replicatedhq/troubleshoot/cmd/docsgen/cli" - _ "k8s.io/client-go/plugin/pkg/client/auth" -) - -func main() { - cli.InitAndExecute() -} diff --git a/cmd/schemagen/cli/root.go b/cmd/schemagen/cli/root.go deleted file mode 100644 index 219cd713..00000000 --- a/cmd/schemagen/cli/root.go +++ /dev/null @@ -1,174 +0,0 @@ -package cli - -import ( - "encoding/json" - "io/ioutil" - "os" - "path" - "path/filepath" - "strings" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - extensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - extensionsscheme "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme" - "k8s.io/client-go/kubernetes/scheme" -) - -func RootCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "schemagen", - Short: "Generate openapischemas for the kinds in this project", - SilenceUsage: true, - PreRun: func(cmd *cobra.Command, args []string) { - viper.BindPFlags(cmd.Flags()) - }, - RunE: func(cmd *cobra.Command, args []string) error { - v := viper.GetViper() - - return generateSchemas(v) - }, - } - - cobra.OnInitialize(initConfig) - - cmd.Flags().String("output-dir", "./schemas", "directory to save the schemas in") - - viper.BindPFlags(cmd.Flags()) - - viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) - - return cmd -} - -func InitAndExecute() { - if err := RootCmd().Execute(); err != nil { - os.Exit(1) - } -} - -func initConfig() { - viper.SetEnvPrefix("TROUBLESHOOT") - viper.AutomaticEnv() -} - -func generateSchemas(v *viper.Viper) error { - // we generate schemas from the config/crds in the root of this project - // those crds can be created from controller-gen or by running `make openapischema` - - workdir, err := os.Getwd() - if err != nil { - return errors.Wrap(err, "failed to get workdir") - } - - 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", - }, - } - - 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 -} - -func generateSchemaFromCRD(crd []byte, outfile string) error { - extensionsscheme.AddToScheme(scheme.Scheme) - decode := scheme.Codecs.UniversalDeserializer().Decode - obj, _, err := decode(crd, nil, nil) - if err != nil { - return errors.Wrap(err, "failed to decode crd") - } - - customResourceDefinition := obj.(*extensionsv1.CustomResourceDefinition) - - if len(customResourceDefinition.Spec.Versions) == 0 { - return errors.New("no versions found for CRD") - } - - crdSchema := customResourceDefinition.Spec.Versions[0].Schema - if crdSchema == nil { - return errors.New("CRD has a nil schema") - } - - b, err := json.MarshalIndent(crdSchema.OpenAPIV3Schema, "", " ") - if err != nil { - return errors.Wrap(err, "failed to marshal json") - } - - _, err = os.Stat(outfile) - if err == nil { - if err := os.Remove(outfile); err != nil { - return errors.Wrap(err, "failed to remove file") - } - } - - d, _ := path.Split(outfile) - _, err = os.Stat(d) - if os.IsNotExist(err) { - if err = os.MkdirAll(d, 0755); err != nil { - return errors.Wrap(err, "failed to mkdir") - } - } - - // whoa now - // working around the fact that controller-gen doesn't have tags to generate oneOf schemas, so this is hacky. - // going to work to add an issue there to support and if they accept, this terrible thing can go away - boolStringed := strings.ReplaceAll(string(b), `"type": "BoolString"`, `"oneOf": [{"type": "string"},{"type": "boolean"}]`) - - err = ioutil.WriteFile(outfile, []byte(boolStringed), 0644) - if err != nil { - return errors.Wrap(err, "failed to write file") - } - - return nil -} diff --git a/cmd/schemagen/main.go b/cmd/schemagen/main.go deleted file mode 100644 index db780f2e..00000000 --- a/cmd/schemagen/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "github.com/replicatedhq/troubleshoot/cmd/schemagen/cli" -) - -func main() { - cli.InitAndExecute() -} diff --git a/Person-2-PRD.md b/docs/Person-2-PRD.md similarity index 100% rename from Person-2-PRD.md rename to docs/Person-2-PRD.md diff --git a/design/proposal-concurrent-collectors.md b/docs/design/proposal-concurrent-collectors.md similarity index 100% rename from design/proposal-concurrent-collectors.md rename to docs/design/proposal-concurrent-collectors.md diff --git a/go.mod b/go.mod index b910a1d2..8ae95c09 100644 --- a/go.mod +++ b/go.mod @@ -104,7 +104,6 @@ require ( github.com/containerd/platforms v0.2.1 // indirect github.com/containerd/typeurl/v2 v2.2.3 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/ebitengine/purego v0.8.4 // indirect diff --git a/go.sum b/go.sum index c4a59b10..0f2c1819 100644 --- a/go.sum +++ b/go.sum @@ -178,7 +178,6 @@ github.com/containers/storage v1.59.1 h1:11Zu68MXsEQGBBd+GadPrHPpWeqjKS8hJDGiAHg github.com/containers/storage v1.59.1/go.mod h1:KoAYHnAjP3/cTsRS+mmWZGkufSY2GACiKQ4V3ZLQnR0= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=