-
Notifications
You must be signed in to change notification settings - Fork 7
/
support_bugreport.go
181 lines (161 loc) · 5.27 KB
/
support_bugreport.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package main
import (
"context"
"fmt"
"io"
"github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/action"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"github.com/flomesh-io/fsm/pkg/bugreport"
"github.com/flomesh-io/fsm/pkg/constants"
policyClientset "github.com/flomesh-io/fsm/pkg/gen/client/policy/clientset/versioned"
"github.com/flomesh-io/fsm/pkg/k8s"
)
const bugReportDescription = `
Generate a bug report.
# Specifying the archive format:
If '--out-file' or '-o' is not specified, the bug report will be generated as a
compressed tar file in the tar.gz format. To generate the bug report using
a different archive format, specify the output file along with its extension
type.
The format of the archive is determined by its
file extension. Supported extensions:
.zip
.tar
.tar.gz
.tgz
.tar.bz2
.tbz2
.tar.xz
.txz
.tar.lz4
.tlz4
.tar.sz
.tsz
.rar (open only)
.bz2
.gz
.lz4
.sz
.xz
*Note:
- Both 'fsm' and 'kubectl' CLI must reside in the evironment's lookup path.
- If the environment includes sensitive information that should not be collected,
please do not specify the associated resources. Before sharing the bug report,
please audit and redact any sensitive information that should not be shared.
`
const bugReportExample = `
# Generate a bug report for the given namespaces, deployments, and pods
fsm support bug-report --app-namespaces bookbuyer,bookstore \
--app-deployments bookbuyer/bookbuyer,bookstore/bookstore-v1 \
--app-pods bookthief/bookthief-7bb7f9b98c-qplq4
`
type bugReportCmd struct {
stdout io.Writer
stderr io.Writer
kubeClient kubernetes.Interface
policyClient policyClientset.Interface
all bool
appNamespaces []string
appDeployments []string
appPods []string
outFile string
collectIngress bool
}
func newSupportBugReportCmd(config *action.Configuration, stdout io.Writer, stderr io.Writer) *cobra.Command {
bugReportCmd := &bugReportCmd{
stdout: stdout,
stderr: stderr,
}
cmd := &cobra.Command{
Use: "bug-report",
Short: "generate bug report",
Long: bugReportDescription,
Args: cobra.MaximumNArgs(1),
RunE: func(_ *cobra.Command, args []string) error {
config, err := settings.RESTClientGetter().ToRESTConfig()
if err != nil {
return fmt.Errorf("Error fetching kubeconfig: %w", err)
}
bugReportCmd.kubeClient, err = kubernetes.NewForConfig(config)
if err != nil {
return fmt.Errorf("Could not access Kubernetes cluster, check kubeconfig: %w", err)
}
bugReportCmd.policyClient, err = policyClientset.NewForConfig(config)
if err != nil {
return fmt.Errorf("Could not access FSM, check configuration: %w", err)
}
return bugReportCmd.run()
},
Example: bugReportExample,
}
f := cmd.Flags()
f.BoolVar(&bugReportCmd.all, "all", false, "All pods in the mesh")
f.StringSliceVar(&bugReportCmd.appNamespaces, "app-namespaces", nil, "Application namespaces")
f.StringSliceVar(&bugReportCmd.appDeployments, "app-deployments", nil, "Application deployments: <namespace>/<deployment>")
f.StringSliceVar(&bugReportCmd.appPods, "app-pods", nil, "Application pods: <namespace>/<pod>")
f.BoolVar(&bugReportCmd.collectIngress, "ingress", false, "Collect ingress")
f.StringVarP(&bugReportCmd.outFile, "out-file", "o", "", "Output file with archive format extension")
return cmd
}
func (cmd *bugReportCmd) run() error {
var appPods, appDeployments []types.NamespacedName
if cmd.all {
cmd.collectIngress = true
ctx := context.Background()
cmd.appNamespaces = nil
namespaces, err := cmd.kubeClient.CoreV1().Namespaces().List(ctx, metav1.ListOptions{
LabelSelector: constants.FSMKubeResourceMonitorAnnotation,
})
if err != nil {
fmt.Fprintf(cmd.stderr, "Unable to list mesh namespaces")
}
for _, namespace := range namespaces.Items {
namespaceName := namespace.ObjectMeta.Name
cmd.appNamespaces = append(cmd.appNamespaces, namespaceName)
pods, err := cmd.kubeClient.CoreV1().Pods(namespaceName).List(ctx, metav1.ListOptions{})
if err != nil {
fmt.Fprintf(cmd.stderr, "Unable to get pods from namespace %s", namespaceName)
}
for _, pod := range pods.Items {
nsName := types.NamespacedName{
Namespace: pod.Namespace,
Name: pod.Name,
}
appPods = append(appPods, nsName)
}
}
} else {
for _, pod := range cmd.appPods {
p, err := k8s.NamespacedNameFrom(pod)
if err != nil {
fmt.Fprintf(cmd.stderr, "Pod name %s is not namespaced, skipping it", pod)
continue
}
appPods = append(appPods, p)
}
for _, deployment := range cmd.appDeployments {
d, err := k8s.NamespacedNameFrom(deployment)
if err != nil {
fmt.Fprintf(cmd.stderr, "Deployment name %s is not namespaced, skipping it", deployment)
continue
}
appDeployments = append(appDeployments, d)
}
}
bugReportCfg := &bugreport.Config{
Stdout: cmd.stdout,
Stderr: cmd.stderr,
KubeClient: cmd.kubeClient,
PolicyClient: cmd.policyClient,
ControlPlaneNamepace: settings.Namespace(),
AppNamespaces: cmd.appNamespaces,
AppDeployments: appDeployments,
AppPods: appPods,
OutFile: cmd.outFile,
CollectIngress: cmd.collectIngress,
}
return bugReportCfg.Run()
}