-
Notifications
You must be signed in to change notification settings - Fork 364
/
command_list.go
162 lines (149 loc) · 5.63 KB
/
command_list.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
// Copyright 2019 Antrea Authors
//
// 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 antctl
import (
"fmt"
"io"
"math"
"os"
"strings"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/klog/v2"
"antrea.io/antrea/pkg/antctl/runtime"
)
// commandList organizes commands definitions.
// It is the protocol for a pair of antctl client and server.
type commandList struct {
definitions []commandDefinition
rawCommands []rawCommand
codec serializer.CodecFactory
}
func (cl *commandList) applyPersistentFlagsToRoot(root *cobra.Command) {
root.PersistentFlags().BoolP("verbose", "v", false, "enable verbose output")
root.PersistentFlags().StringP("kubeconfig", "k", "", "absolute path to the kubeconfig file")
root.PersistentFlags().DurationP("timeout", "t", 0, "time limit of the execution of the command")
root.PersistentFlags().StringP("server", "s", "", "address and port of the API server, taking precedence over the default endpoint and the one set in kubeconfig")
}
// applyToRootCommand is the "internal" version of ApplyToRootCommand, used for testing
func (cl *commandList) applyToRootCommand(root *cobra.Command, client AntctlClient, out io.Writer) {
for _, groupCommand := range groupCommands {
root.AddCommand(groupCommand)
}
for i := range cl.definitions {
def := &cl.definitions[i]
if (runtime.Mode == runtime.ModeAgent && def.agentEndpoint == nil) ||
(runtime.Mode == runtime.ModeController && def.controllerEndpoint == nil) ||
(runtime.Mode == runtime.ModeFlowAggregator && def.flowAggregatorEndpoint == nil) {
continue
}
def.applySubCommandToRoot(root, client, out)
}
cl.applyPersistentFlagsToRoot(root)
for _, cmd := range cl.rawCommands {
if (runtime.Mode == runtime.ModeAgent && cmd.supportAgent) ||
(runtime.Mode == runtime.ModeController && cmd.supportController) ||
(runtime.Mode == runtime.ModeFlowAggregator && cmd.supportFlowAggregator) ||
(!runtime.InPod && cmd.commandGroup == mc) {
if groupCommand, ok := groupCommands[cmd.commandGroup]; ok {
groupCommand.AddCommand(cmd.cobraCommand)
} else {
root.AddCommand(cmd.cobraCommand)
}
}
}
root.SilenceUsage = true
root.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
enableVerbose, err := root.PersistentFlags().GetBool("verbose")
if err != nil {
return err
}
klog.LogToStderr(enableVerbose)
if enableVerbose {
var logLevel klog.Level
if err := logLevel.Set(fmt.Sprint(math.MaxInt32)); err != nil {
return err
}
}
return nil
}
renderDescription(root)
}
// ApplyToRootCommand applies the commandList to the root cobra command, it applies
// each commandDefinition of it to the root command as a sub-command.
func (cl *commandList) ApplyToRootCommand(root *cobra.Command) {
client := newClient(cl.codec)
cl.applyToRootCommand(root, client, os.Stdout)
}
// validate checks the validation of the commandList.
func (cl *commandList) validate() []error {
var errs []error
if len(cl.definitions) == 0 {
return []error{fmt.Errorf("no command found in the command list")}
}
for i, c := range cl.definitions {
for _, err := range c.validate() {
errs = append(errs, fmt.Errorf("#%d command<%s>: %w", i, c.use, err))
}
}
return errs
}
// GetDebugCommands returns all commands supported by Controller, Agent or Flow Aggregator
// that are used for debugging purpose.
func (cl *commandList) GetDebugCommands(mode string) [][]string {
var allCommands [][]string
for _, def := range cl.definitions {
// TODO: incorporate query commands into e2e testing once proxy access is implemented
if def.commandGroup == query {
continue
}
if mode == runtime.ModeController && def.use == "log-level" {
// log-level command does not support remote execution.
continue
}
if mode == runtime.ModeAgent && def.agentEndpoint != nil ||
mode == runtime.ModeController && def.controllerEndpoint != nil ||
mode == runtime.ModeFlowAggregator && def.flowAggregatorEndpoint != nil {
var currentCommand []string
if group, ok := groupCommands[def.commandGroup]; ok {
currentCommand = append(currentCommand, group.Use)
}
currentCommand = append(currentCommand, def.use)
allCommands = append(allCommands, currentCommand)
}
}
for _, cmd := range cl.rawCommands {
if cmd.cobraCommand.Use == "proxy" {
// proxy will keep running until interrupted so it
// cannot be used as is in e2e tests.
continue
}
if mode == runtime.ModeController && cmd.supportController ||
mode == runtime.ModeAgent && cmd.supportAgent {
var currentCommand []string
if group, ok := groupCommands[cmd.commandGroup]; ok {
currentCommand = append(currentCommand, group.Use)
}
currentCommand = append(currentCommand, strings.Split(cmd.cobraCommand.Use, " ")[0])
allCommands = append(allCommands, currentCommand)
}
}
return allCommands
}
// renderDescription replaces placeholders ${component} in Short and Long of a command
// to the determined component during runtime.
func renderDescription(command *cobra.Command) {
command.Short = strings.ReplaceAll(command.Short, "${component}", runtime.Mode)
command.Long = strings.ReplaceAll(command.Long, "${component}", runtime.Mode)
}