1
// Copyright Istio Authors
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
7
// http://www.apache.org/licenses/LICENSE-2.0
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.
23
"github.com/spf13/cobra"
24
"github.com/spf13/viper"
26
"istio.io/istio/istioctl/pkg/admin"
27
"istio.io/istio/istioctl/pkg/analyze"
28
"istio.io/istio/istioctl/pkg/authz"
29
"istio.io/istio/istioctl/pkg/checkinject"
30
"istio.io/istio/istioctl/pkg/cli"
31
"istio.io/istio/istioctl/pkg/completion"
32
"istio.io/istio/istioctl/pkg/config"
33
"istio.io/istio/istioctl/pkg/dashboard"
34
"istio.io/istio/istioctl/pkg/describe"
35
"istio.io/istio/istioctl/pkg/injector"
36
"istio.io/istio/istioctl/pkg/internaldebug"
37
"istio.io/istio/istioctl/pkg/kubeinject"
38
"istio.io/istio/istioctl/pkg/metrics"
39
"istio.io/istio/istioctl/pkg/multicluster"
40
"istio.io/istio/istioctl/pkg/precheck"
41
"istio.io/istio/istioctl/pkg/proxyconfig"
42
"istio.io/istio/istioctl/pkg/proxystatus"
43
"istio.io/istio/istioctl/pkg/root"
44
"istio.io/istio/istioctl/pkg/tag"
45
"istio.io/istio/istioctl/pkg/util"
46
"istio.io/istio/istioctl/pkg/validate"
47
"istio.io/istio/istioctl/pkg/version"
48
"istio.io/istio/istioctl/pkg/wait"
49
"istio.io/istio/istioctl/pkg/waypoint"
50
"istio.io/istio/istioctl/pkg/workload"
51
"istio.io/istio/operator/cmd/mesh"
52
"istio.io/istio/pkg/cmd"
53
"istio.io/istio/pkg/collateral"
54
"istio.io/istio/pkg/config/constants"
55
"istio.io/istio/pkg/log"
56
"istio.io/istio/tools/bug-report/pkg/bugreport"
60
// Location to read istioctl defaults from
61
defaultIstioctlConfig = "$HOME/.istioctl/config.yaml"
68
// ConfigAndEnvProcessing uses spf13/viper for overriding CLI parameters
69
func ConfigAndEnvProcessing() error {
70
configPath := filepath.Dir(root.IstioConfig)
71
baseName := filepath.Base(root.IstioConfig)
72
configType := filepath.Ext(root.IstioConfig)
73
configName := baseName[0 : len(baseName)-len(configType)]
75
configType = configType[1:]
78
// Allow users to override some variables through $HOME/.istioctl/config.yaml
79
// and environment variables.
80
viper.SetEnvPrefix("ISTIOCTL")
82
viper.AllowEmptyEnv(true) // So we can say ISTIOCTL_CERT_DIR="" to suppress certs
83
viper.SetConfigName(configName)
84
viper.SetConfigType(configType)
85
viper.AddConfigPath(configPath)
86
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
87
err := viper.ReadInConfig()
88
// Ignore errors reading the configuration unless the file is explicitly customized
89
if root.IstioConfig != defaultIstioctlConfig {
97
viper.SetDefault("istioNamespace", constants.IstioSystemNamespace)
98
viper.SetDefault("xds-port", 15012)
101
// GetRootCmd returns the root of the cobra command-tree.
102
func GetRootCmd(args []string) *cobra.Command {
103
rootCmd := &cobra.Command{
105
Short: "Istio control interface.",
107
DisableAutoGenTag: true,
108
PersistentPreRunE: ConfigureLogging,
109
Long: `Istio configuration command line utility for service operators to
110
debug and diagnose their Istio mesh.
114
rootCmd.SetArgs(args)
116
flags := rootCmd.PersistentFlags()
117
rootOptions := cli.AddRootFlags(flags)
119
ctx := cli.NewCLIContext(rootOptions)
121
_ = rootCmd.RegisterFlagCompletionFunc(cli.FlagIstioNamespace, func(
122
cmd *cobra.Command, args []string, toComplete string,
123
) ([]string, cobra.ShellCompDirective) {
124
return completion.ValidNamespaceArgs(cmd, ctx, args, toComplete)
126
_ = rootCmd.RegisterFlagCompletionFunc(cli.FlagNamespace, func(
127
cmd *cobra.Command, args []string, toComplete string,
128
) ([]string, cobra.ShellCompDirective) {
129
return completion.ValidNamespaceArgs(cmd, ctx, args, toComplete)
132
// Attach the Istio logging options to the command.
133
root.LoggingOptions.AttachCobraFlags(rootCmd)
134
hiddenFlags := []string{
135
"log_as_json", "log_rotate", "log_rotate_max_age", "log_rotate_max_backups",
136
"log_rotate_max_size", "log_stacktrace_level", "log_target", "log_caller", "log_output_level",
138
for _, opt := range hiddenFlags {
139
_ = rootCmd.PersistentFlags().MarkHidden(opt)
142
cmd.AddFlags(rootCmd)
144
kubeInjectCmd := kubeinject.InjectCommand(ctx)
145
hideInheritedFlags(kubeInjectCmd, cli.FlagNamespace)
146
rootCmd.AddCommand(kubeInjectCmd)
148
experimentalCmd := &cobra.Command{
150
Aliases: []string{"x", "exp"},
151
Short: "Experimental commands that may be modified or deprecated",
154
xdsBasedTroubleshooting := []*cobra.Command{
155
// TODO(hanxiaop): I think experimental version still has issues, so we keep the old version for now.
156
version.XdsVersionCommand(ctx),
157
// TODO(hanxiaop): this is kept for some releases in case someone is using it.
158
proxystatus.XdsStatusCommand(ctx),
160
troubleshootingCommands := []*cobra.Command{
161
version.NewVersionCommand(ctx),
162
proxystatus.StableXdsStatusCommand(ctx),
164
var debugCmdAttachmentPoint *cobra.Command
165
if viper.GetBool("PREFER-EXPERIMENTAL") {
166
legacyCmd := &cobra.Command{
168
Short: "Legacy command variants",
170
rootCmd.AddCommand(legacyCmd)
171
for _, c := range xdsBasedTroubleshooting {
172
rootCmd.AddCommand(c)
174
debugCmdAttachmentPoint = legacyCmd
176
debugCmdAttachmentPoint = rootCmd
178
for _, c := range xdsBasedTroubleshooting {
179
experimentalCmd.AddCommand(c)
181
for _, c := range troubleshootingCommands {
182
debugCmdAttachmentPoint.AddCommand(c)
185
rootCmd.AddCommand(experimentalCmd)
186
rootCmd.AddCommand(proxyconfig.ProxyConfig(ctx))
187
rootCmd.AddCommand(admin.Cmd(ctx))
188
experimentalCmd.AddCommand(injector.Cmd(ctx))
190
rootCmd.AddCommand(mesh.NewVerifyCommand(ctx))
191
rootCmd.AddCommand(mesh.UninstallCmd(ctx))
193
experimentalCmd.AddCommand(authz.AuthZ(ctx))
194
rootCmd.AddCommand(seeExperimentalCmd("authz"))
195
experimentalCmd.AddCommand(metrics.Cmd(ctx))
196
experimentalCmd.AddCommand(describe.Cmd(ctx))
197
experimentalCmd.AddCommand(wait.Cmd(ctx))
198
experimentalCmd.AddCommand(config.Cmd())
199
experimentalCmd.AddCommand(workload.Cmd(ctx))
200
experimentalCmd.AddCommand(internaldebug.DebugCommand(ctx))
201
experimentalCmd.AddCommand(precheck.Cmd(ctx))
202
experimentalCmd.AddCommand(proxyconfig.StatsConfigCmd(ctx))
203
experimentalCmd.AddCommand(checkinject.Cmd(ctx))
204
experimentalCmd.AddCommand(waypoint.Cmd(ctx))
206
analyzeCmd := analyze.Analyze(ctx)
207
hideInheritedFlags(analyzeCmd, cli.FlagIstioNamespace)
208
rootCmd.AddCommand(analyzeCmd)
210
dashboardCmd := dashboard.Dashboard(ctx)
211
hideInheritedFlags(dashboardCmd, cli.FlagNamespace, cli.FlagIstioNamespace)
212
rootCmd.AddCommand(dashboardCmd)
214
manifestCmd := mesh.ManifestCmd(ctx)
215
hideInheritedFlags(manifestCmd, cli.FlagNamespace, cli.FlagIstioNamespace, FlagCharts)
216
rootCmd.AddCommand(manifestCmd)
218
operatorCmd := mesh.OperatorCmd(ctx)
219
hideInheritedFlags(operatorCmd, cli.FlagNamespace, cli.FlagIstioNamespace, FlagCharts)
220
rootCmd.AddCommand(operatorCmd)
222
installCmd := mesh.InstallCmd(ctx)
223
hideInheritedFlags(installCmd, cli.FlagNamespace, cli.FlagIstioNamespace, FlagCharts)
224
rootCmd.AddCommand(installCmd)
226
profileCmd := mesh.ProfileCmd(ctx)
227
hideInheritedFlags(profileCmd, cli.FlagNamespace, cli.FlagIstioNamespace, FlagCharts)
228
rootCmd.AddCommand(profileCmd)
230
upgradeCmd := mesh.UpgradeCmd(ctx)
231
hideInheritedFlags(upgradeCmd, cli.FlagNamespace, cli.FlagIstioNamespace, FlagCharts)
232
rootCmd.AddCommand(upgradeCmd)
234
bugReportCmd := bugreport.Cmd(ctx, root.LoggingOptions)
235
hideInheritedFlags(bugReportCmd, cli.FlagNamespace, cli.FlagIstioNamespace)
236
rootCmd.AddCommand(bugReportCmd)
238
tagCmd := tag.TagCommand(ctx)
239
hideInheritedFlags(tag.TagCommand(ctx), cli.FlagNamespace, cli.FlagIstioNamespace, FlagCharts)
240
rootCmd.AddCommand(tagCmd)
242
// leave the multicluster commands in x for backwards compat
243
rootCmd.AddCommand(multicluster.NewCreateRemoteSecretCommand(ctx))
244
rootCmd.AddCommand(proxyconfig.ClustersCommand(ctx))
246
rootCmd.AddCommand(collateral.CobraCommand(rootCmd, collateral.Metadata{
247
Title: "Istio Control",
248
Section: "istioctl CLI",
249
Manual: "Istio Control",
252
validateCmd := validate.NewValidateCommand(ctx)
253
hideInheritedFlags(validateCmd, "kubeconfig")
254
rootCmd.AddCommand(validateCmd)
256
rootCmd.AddCommand(optionsCommand(rootCmd))
258
// BFS applies the flag error function to all subcommands
259
seenCommands := make(map[*cobra.Command]bool)
260
var commandStack []*cobra.Command
262
commandStack = append(commandStack, rootCmd)
264
for len(commandStack) > 0 {
265
n := len(commandStack) - 1
266
curCmd := commandStack[n]
267
commandStack = commandStack[:n]
268
seenCommands[curCmd] = true
269
for _, command := range curCmd.Commands() {
270
if !seenCommands[command] {
271
commandStack = append(commandStack, command)
274
curCmd.SetFlagErrorFunc(func(_ *cobra.Command, e error) error {
275
return util.CommandParseError{Err: e}
282
func hideInheritedFlags(orig *cobra.Command, hidden ...string) {
283
orig.SetHelpFunc(func(cmd *cobra.Command, args []string) {
284
for _, hidden := range hidden {
285
_ = cmd.Flags().MarkHidden(hidden) // nolint: errcheck
288
orig.SetHelpFunc(nil)
289
orig.HelpFunc()(cmd, args)
293
func ConfigureLogging(_ *cobra.Command, _ []string) error {
294
return log.Configure(root.LoggingOptions)
297
// seeExperimentalCmd is used for commands that have been around for a release but not graduated from
299
// for graduatedCmd see https://github.com/istio/istio/pull/26408
300
// for softGraduatedCmd see https://github.com/istio/istio/pull/26563
301
func seeExperimentalCmd(name string) *cobra.Command {
302
msg := fmt.Sprintf("(%s is experimental. Use `istioctl experimental %s`)", name, name)
303
return &cobra.Command{
306
RunE: func(_ *cobra.Command, _ []string) error {
307
return errors.New(msg)