From 342a1c643729c36befafc5bb2b4b4ef44a998618 Mon Sep 17 00:00:00 2001 From: Dave Parfitt Date: Fri, 27 Jul 2018 14:15:54 -0400 Subject: [PATCH] add an ark bug command Signed-off-by: Dave Parfitt --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- docs/cli-reference/ark.md | 1 + docs/cli-reference/ark_bug.md | 37 +++++ docs/issue-template-gen/main.go | 45 ++++++ docs/troubleshooting.md | 2 + hack/update-generated-issue-template.sh | 36 +++++ hack/verify-generated-issue-template.sh | 39 +++++ pkg/cmd/ark/ark.go | 2 + pkg/cmd/cli/bug/bug.go | 203 ++++++++++++++++++++++++ 9 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 docs/cli-reference/ark_bug.md create mode 100644 docs/issue-template-gen/main.go create mode 100755 hack/update-generated-issue-template.sh create mode 100755 hack/verify-generated-issue-template.sh create mode 100644 pkg/cmd/cli/bug/bug.go diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 8a4520367..64bd0a6bc 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -27,7 +27,7 @@ about: Tell us about a problem you are experiencing **Environment:** -- Ark version (use `ark version`): +- Ark version (use `ark version`): - Kubernetes version (use `kubectl version`): - Kubernetes installer & version: - Cloud provider or hardware configuration: diff --git a/docs/cli-reference/ark.md b/docs/cli-reference/ark.md index b66760527..f6a77e6a2 100644 --- a/docs/cli-reference/ark.md +++ b/docs/cli-reference/ark.md @@ -31,6 +31,7 @@ operations can also be performed as 'ark backup get' and 'ark schedule create'. ### SEE ALSO * [ark backup](ark_backup.md) - Work with backups +* [ark bug](ark_bug.md) - Report an Ark bug * [ark client](ark_client.md) - Ark client related commands * [ark completion](ark_completion.md) - Output shell completion code for the specified shell (bash or zsh) * [ark create](ark_create.md) - Create ark resources diff --git a/docs/cli-reference/ark_bug.md b/docs/cli-reference/ark_bug.md new file mode 100644 index 000000000..716ff1d5d --- /dev/null +++ b/docs/cli-reference/ark_bug.md @@ -0,0 +1,37 @@ +## ark bug + +Report an Ark bug + +### Synopsis + + +Open a browser window to report an Ark bug + +``` +ark bug [flags] +``` + +### Options + +``` + -h, --help help for bug +``` + +### Options inherited from parent commands + +``` + --alsologtostderr log to standard error as well as files + --kubeconfig string Path to the kubeconfig file to use to talk to the Kubernetes apiserver. If unset, try the environment variable KUBECONFIG, as well as in-cluster configuration + --kubecontext string The context to use to talk to the Kubernetes apiserver. If unset defaults to whatever your current-context is (kubectl config current-context) + --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) + --log_dir string If non-empty, write log files in this directory + --logtostderr log to standard error instead of files + -n, --namespace string The namespace in which Ark should operate (default "heptio-ark") + --stderrthreshold severity logs at or above this threshold go to stderr (default 2) + -v, --v Level log level for V logs + --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging +``` + +### SEE ALSO +* [ark](ark.md) - Back up and restore Kubernetes cluster resources. + diff --git a/docs/issue-template-gen/main.go b/docs/issue-template-gen/main.go new file mode 100644 index 000000000..19ef0ab85 --- /dev/null +++ b/docs/issue-template-gen/main.go @@ -0,0 +1,45 @@ +/* +Copyright 2018 the Heptio Ark contributors. + +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. +*/ + +// This code renders the IssueTemplate string in pkg/cmd/cli/bug/bug.go to +// .github/ISSUE_TEMPLATE/bug_report.md via the hack/update-generated-issue-template.sh script. + +package main + +import ( + "log" + "os" + "text/template" + + "github.com/heptio/ark/pkg/cmd/cli/bug" +) + +func main() { + outTemplateFilename := os.Args[1] + outFile, err := os.OpenFile(outTemplateFilename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) + if err != nil { + log.Fatal(err) + } + defer outFile.Close() + tmpl, err := template.New("ghissue").Parse(bug.IssueTemplate) + if err != nil { + log.Fatal(err) + } + err = tmpl.Execute(outFile, bug.ArkBugInfo{}) + if err != nil { + log.Fatal(err) + } +} diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index c6d770ba9..af0b52aa9 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -2,6 +2,8 @@ These tips can help you troubleshoot known issues. If they don't help, you can [file an issue][4], or talk to us on the [#ark-dr channel][25] on the Kubernetes Slack server. +In `ark` version >= `0.1.0`, you can use the `ark bug` command to open a [Github issue][4] by launching a browser window with some prepopulated values. Values included are OS, CPU architecture, `kubectl` client and server versions (if available) and the `ark` client version. This information isn't submitted to Github until you click the `Submit new issue` button in the Github UI, so feel free to add, remove or update whatever information you like. + Some general commands for troubleshooting that may be helpful: * `ark backup describe ` - describe the details of a backup diff --git a/hack/update-generated-issue-template.sh b/hack/update-generated-issue-template.sh new file mode 100755 index 000000000..05ad23bc4 --- /dev/null +++ b/hack/update-generated-issue-template.sh @@ -0,0 +1,36 @@ +#!/bin/bash -e +# +# Copyright 2018 the Heptio Ark contributors. +# +# 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. + +ARK_ROOT=$(dirname ${BASH_SOURCE})/.. +BIN=${ARK_ROOT}/_output/bin + +mkdir -p ${BIN} + +echo "Updating generated Github issue template" +go build -o ${BIN}/issue-tmpl-gen ./docs/issue-template-gen/main.go + +if [[ $# -gt 1 ]]; then + echo "usage: ${BASH_SOURCE} [OUTPUT_FILE]" + exit 1 +fi + +OUTPUT_ISSUE_FILE="$1" +if [[ -z "${OUTPUT_ISSUE_FILE}" ]]; then + OUTPUT_ISSUE_FILE=${ARK_ROOT}/.github/ISSUE_TEMPLATE/bug_report.md +fi + +${BIN}/issue-tmpl-gen ${OUTPUT_ISSUE_FILE} +echo "Success!" diff --git a/hack/verify-generated-issue-template.sh b/hack/verify-generated-issue-template.sh new file mode 100755 index 000000000..43832c6ac --- /dev/null +++ b/hack/verify-generated-issue-template.sh @@ -0,0 +1,39 @@ +#!/bin/bash -e +# +# Copyright 2018 the Heptio Ark contributors. +# +# 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. + +ARK_ROOT=$(dirname ${BASH_SOURCE})/.. +HACK_DIR=$(dirname "${BASH_SOURCE}") +ISSUE_TEMPLATE_FILE=${ARK_ROOT}/.github/ISSUE_TEMPLATE/bug_report.md +OUT_TMP_FILE="$(mktemp -d)"/bug_report.md + + +trap cleanup INT TERM HUP EXIT + +cleanup() { + rm -rf ${TMP_DIR} +} + +echo "Verifying generated Github issue template" +${HACK_DIR}/update-generated-issue-template.sh ${OUT_TMP_FILE} > /dev/null +output=$(echo "`diff ${ISSUE_TEMPLATE_FILE} ${OUT_TMP_FILE}`") + +if [[ -n "${output}" ]] ; then + echo "FAILURE: verification of generated template failed:" + echo "${output}" + exit 1 +fi + +echo "Success!" diff --git a/pkg/cmd/ark/ark.go b/pkg/cmd/ark/ark.go index b80b14c55..f3c324484 100644 --- a/pkg/cmd/ark/ark.go +++ b/pkg/cmd/ark/ark.go @@ -23,6 +23,7 @@ import ( "github.com/heptio/ark/pkg/client" "github.com/heptio/ark/pkg/cmd/cli/backup" + "github.com/heptio/ark/pkg/cmd/cli/bug" cliclient "github.com/heptio/ark/pkg/cmd/cli/client" "github.com/heptio/ark/pkg/cmd/cli/completion" "github.com/heptio/ark/pkg/cmd/cli/create" @@ -69,6 +70,7 @@ operations can also be performed as 'ark backup get' and 'ark schedule create'.` cliclient.NewCommand(), completion.NewCommand(), restic.NewCommand(f), + bug.NewCommand(), ) // add the glog flags diff --git a/pkg/cmd/cli/bug/bug.go b/pkg/cmd/cli/bug/bug.go new file mode 100644 index 000000000..753f65006 --- /dev/null +++ b/pkg/cmd/cli/bug/bug.go @@ -0,0 +1,203 @@ +/* +Copyright 2018 the Heptio Ark contributors. + +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 bug + +import ( + "bytes" + "errors" + "fmt" + "net/url" + "os" + "os/exec" + "runtime" + "strings" + "text/template" + "time" + + "github.com/heptio/ark/pkg/buildinfo" + "github.com/heptio/ark/pkg/cmd" + "github.com/spf13/cobra" +) + +const ( + // kubectlTimeout is how long we wait in seconds for `kubectl version` + // before killing the process + kubectlTimeout = 5 * time.Second + issueURL = "https://github.com/heptio/ark/issues/new" + // IssueTemplate is used to generate .github/ISSUE_TEMPLATE/bug_report.md + // as well as the initial text that's place in a new Github issue as + // the result of running `ark bug`. + IssueTemplate = `--- +name: Bug report +about: Tell us about a problem you are experiencing + +--- + +**What steps did you take and what happened:** +[A clear and concise description of what the bug is, and what commands you ran.) + + +**What did you expect to happen:** + + +**The output of the following commands will help us better understand what's going on**: +(Pasting long output into a [GitHub gist](https://gist.github.com) or other pastebin is fine.) + +* ` + "`kubectl logs deployment/ark -n heptio-ark`" + ` +* ` + "`ark backup describe ` or `kubectl get backup/ -n heptio-ark -o yaml`" + ` +* ` + "`ark backup logs `" + ` +* ` + "`ark restore describe ` or `kubectl get restore/ -n heptio-ark -o yaml`" + ` +* ` + "`ark restore logs `" + ` + + +**Anything else you would like to add:** +[Miscellaneous information that will assist in solving the issue.] + + +**Environment:** + +- Ark version (use ` + "`ark version`" + `):{{.ArkVersion}} {{.GitCommit}} {{.GitTreeState}} +- Kubernetes version (use ` + "`kubectl version`" + `): +{{- if .KubectlVersion}} +` + "```" + ` +{{.KubectlVersion}} +` + "```" + ` +{{end}} +- Kubernetes installer & version: +- Cloud provider or hardware configuration: +- OS (e.g. from ` + "`/etc/os-release`" + `): +{{if .RuntimeOS}} - RuntimeOS: {{.RuntimeOS}}{{end -}} +{{if .RuntimeArch}} - RuntimeArch: {{.RuntimeArch}}{{end -}} +` +) + +func NewCommand() *cobra.Command { + c := &cobra.Command{ + Use: "bug", + Short: "Report an Ark bug", + Long: "Open a browser window to report an Ark bug", + Run: func(c *cobra.Command, args []string) { + kubectlVersion, err := getKubectlVersion() + if err != nil { + // we don't want to prevent the user from submitting a bug + // if we can't get the kubectl version, so just display a warning + fmt.Fprintf(os.Stderr, "WARNING: can't get kubectl version: %v\n", err) + } + body, err := renderToString(newBugInfo(kubectlVersion)) + cmd.CheckError(err) + cmd.CheckError(showIssueInBrowser(body)) + }, + } + return c +} + +type ArkBugInfo struct { + ArkVersion string + GitCommit string + GitTreeState string + RuntimeOS string + RuntimeArch string + KubectlVersion string +} + +// cmdExistsOnPath checks to see if an executable is available on the current PATH +func cmdExistsOnPath(name string) bool { + if _, err := exec.LookPath(name); err != nil { + return false + } + return true +} + +// getKubectlVersion makes a best-effort to run `kubectl version` +// and return it's output. This func will timeout and return an empty +// string after kubectlTimeout if we're not connected to a cluster. +func getKubectlVersion() (string, error) { + if !cmdExistsOnPath("kubectl") { + return "", errors.New("kubectl not found on PATH") + } + + kubectlCmd := exec.Command("kubectl", "version") + var outbuf bytes.Buffer + kubectlCmd.Stdout = &outbuf + if err := kubectlCmd.Start(); err != nil { + return "", errors.New("can't start kubectl") + } + + done := make(chan error, 1) + go func() { + done <- kubectlCmd.Wait() + }() + select { + case <-time.After(kubectlTimeout): + // we don't care about the possible error returned from Kill() here, + // just return an empty string + kubectlCmd.Process.Kill() + return "", errors.New("timeout waiting for kubectl version") + + case err := <-done: + if err != nil { + return "", errors.New("error waiting for kubectl process") + } + } + versionOut := outbuf.String() + kubectlVersion := strings.TrimSpace(string(versionOut)) + return kubectlVersion, nil +} + +func newBugInfo(kubectlVersion string) *ArkBugInfo { + return &ArkBugInfo{ + ArkVersion: buildinfo.Version, + GitCommit: buildinfo.GitSHA, + GitTreeState: buildinfo.GitTreeState, + RuntimeOS: runtime.GOOS, + RuntimeArch: runtime.GOARCH, + KubectlVersion: kubectlVersion} +} + +// renderToString renders IssueTemplate to a string using the +// supplied *ArkBugInfo +func renderToString(bugInfo *ArkBugInfo) (string, error) { + outputTemplate, err := template.New("ghissue").Parse(IssueTemplate) + if err != nil { + return "", err + } + var buf bytes.Buffer + err = outputTemplate.Execute(&buf, bugInfo) + if err != nil { + return "", err + } + return buf.String(), nil +} + +// showIssueInBrowser opens a browser window to submit a Github issue using +// a platform specific binary. +func showIssueInBrowser(body string) error { + url := issueURL + "?body=" + url.QueryEscape(body) + switch runtime.GOOS { + case "darwin": + return exec.Command("open", url).Start() + case "linux": + if cmdExistsOnPath("xdg-open") { + return exec.Command("xdg-open", url).Start() + } + return fmt.Errorf("ark can't open a browser window using the command '%s'", "xdg-open") + case "windows": + return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() + default: + return fmt.Errorf("ark can't open a browser window on platform %s", runtime.GOOS) + } +}