istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/proxystatus/proxystatus.go (about) 1 // Copyright Istio 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 proxystatus 16 17 import ( 18 "context" 19 "fmt" 20 "io" 21 "os" 22 23 discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" 24 "github.com/spf13/cobra" 25 26 "istio.io/istio/istioctl/pkg/cli" 27 "istio.io/istio/istioctl/pkg/clioptions" 28 "istio.io/istio/istioctl/pkg/completion" 29 "istio.io/istio/istioctl/pkg/multixds" 30 "istio.io/istio/istioctl/pkg/util/ambient" 31 "istio.io/istio/istioctl/pkg/writer/compare" 32 "istio.io/istio/istioctl/pkg/writer/pilot" 33 pilotxds "istio.io/istio/pilot/pkg/xds" 34 "istio.io/istio/pkg/log" 35 ) 36 37 var configDumpFile string 38 39 func readConfigFile(filename string) ([]byte, error) { 40 file := os.Stdin 41 if filename != "-" { 42 var err error 43 file, err = os.Open(filename) 44 if err != nil { 45 return nil, err 46 } 47 } 48 defer func() { 49 if err := file.Close(); err != nil { 50 log.Errorf("failed to close %s: %s", filename, err) 51 } 52 }() 53 data, err := io.ReadAll(file) 54 if err != nil { 55 return nil, err 56 } 57 return data, nil 58 } 59 60 func StableXdsStatusCommand(ctx cli.Context) *cobra.Command { 61 cmd := XdsStatusCommand(ctx) 62 unstableFlags := []string{"xds-via-agents", "xds-via-agents-limit"} 63 cmd.PreRunE = func(cmd *cobra.Command, args []string) error { 64 for _, flag := range unstableFlags { 65 if cmd.PersistentFlags().Changed(flag) { 66 return fmt.Errorf("--%s is experimental. Use `istioctl experimental ps --%s`", flag, flag) 67 } 68 } 69 return nil 70 } 71 for _, flag := range unstableFlags { 72 _ = cmd.PersistentFlags().MarkHidden(flag) 73 } 74 return cmd 75 } 76 77 func XdsStatusCommand(ctx cli.Context) *cobra.Command { 78 var opts clioptions.ControlPlaneOptions 79 var centralOpts clioptions.CentralControlPlaneOptions 80 var multiXdsOpts multixds.Options 81 82 statusCmd := &cobra.Command{ 83 Use: "proxy-status [<type>/]<name>[.<namespace>]", 84 Short: "Retrieves the synchronization status of each Envoy in the mesh", 85 Long: ` 86 Retrieves last sent and last acknowledged xDS sync from Istiod to each Envoy in the mesh 87 `, 88 Example: ` # Retrieve sync status for all Envoys in a mesh 89 istioctl proxy-status 90 91 # Retrieve sync status for Envoys in a specific namespace 92 istioctl proxy-status --namespace foo 93 94 # Retrieve sync diff for a single Envoy and Istiod 95 istioctl proxy-status istio-egressgateway-59585c5b9c-ndc59.istio-system 96 97 # SECURITY OPTIONS 98 99 # Retrieve proxy status information directly from the control plane, using token security 100 # (This is the usual way to get the proxy-status with an out-of-cluster control plane.) 101 istioctl ps --xds-address istio.cloudprovider.example.com:15012 102 103 # Retrieve proxy status information via Kubernetes config, using token security 104 # (This is the usual way to get the proxy-status with an in-cluster control plane.) 105 istioctl proxy-status 106 107 # Retrieve proxy status information directly from the control plane, using RSA certificate security 108 # (Certificates must be obtained before this step. The --cert-dir flag lets istioctl bypass the Kubernetes API server.) 109 istioctl ps --xds-address istio.example.com:15012 --cert-dir ~/.istio-certs 110 111 # Retrieve proxy status information via XDS from specific control plane in multi-control plane in-cluster configuration 112 # (Select a specific control plane in an in-cluster canary Istio configuration.) 113 istioctl ps --xds-label istio.io/rev=default 114 `, 115 Aliases: []string{"ps"}, 116 RunE: func(c *cobra.Command, args []string) error { 117 kubeClient, err := ctx.CLIClientWithRevision(opts.Revision) 118 if err != nil { 119 return err 120 } 121 multiXdsOpts.MessageWriter = c.OutOrStdout() 122 123 if len(args) > 0 { 124 podName, ns, err := ctx.InferPodInfoFromTypedResource(args[0], ctx.Namespace()) 125 if err != nil { 126 return err 127 } 128 if ambient.IsZtunnelPod(kubeClient, podName, ns) { 129 _, _ = fmt.Fprintf(c.OutOrStdout(), 130 "Sync diff is not available for ztunnel pod %s.%s\n", podName, ns) 131 return nil 132 } 133 var envoyDump []byte 134 if configDumpFile != "" { 135 envoyDump, err = readConfigFile(configDumpFile) 136 } else { 137 path := "config_dump" 138 envoyDump, err = kubeClient.EnvoyDo(context.TODO(), podName, ns, "GET", path) 139 } 140 if err != nil { 141 return fmt.Errorf("could not contact sidecar: %w", err) 142 } 143 144 xdsRequest := discovery.DiscoveryRequest{ 145 ResourceNames: []string{fmt.Sprintf("%s.%s", podName, ns)}, 146 TypeUrl: pilotxds.TypeDebugConfigDump, 147 } 148 xdsResponses, err := multixds.FirstRequestAndProcessXds(&xdsRequest, centralOpts, ctx.IstioNamespace(), "", "", kubeClient, multiXdsOpts) 149 if err != nil { 150 return err 151 } 152 c, err := compare.NewXdsComparator(c.OutOrStdout(), xdsResponses, envoyDump) 153 if err != nil { 154 return err 155 } 156 return c.Diff() 157 } 158 xdsRequest := discovery.DiscoveryRequest{ 159 TypeUrl: pilotxds.TypeDebugSyncronization, 160 } 161 xdsResponses, err := multixds.AllRequestAndProcessXds(&xdsRequest, centralOpts, ctx.IstioNamespace(), "", "", kubeClient, multiXdsOpts) 162 if err != nil { 163 return err 164 } 165 sw := pilot.XdsStatusWriter{ 166 Writer: c.OutOrStdout(), 167 Namespace: ctx.Namespace(), 168 } 169 return sw.PrintAll(xdsResponses) 170 }, 171 ValidArgsFunction: completion.ValidPodsNameArgs(ctx), 172 } 173 174 opts.AttachControlPlaneFlags(statusCmd) 175 centralOpts.AttachControlPlaneFlags(statusCmd) 176 statusCmd.PersistentFlags().StringVarP(&configDumpFile, "file", "f", "", 177 "Envoy config dump JSON file") 178 statusCmd.PersistentFlags().BoolVar(&multiXdsOpts.XdsViaAgents, "xds-via-agents", false, 179 "Access Istiod via the tap service of each agent") 180 statusCmd.PersistentFlags().IntVar(&multiXdsOpts.XdsViaAgentsLimit, "xds-via-agents-limit", 100, 181 "Maximum number of pods being visited by istioctl when `xds-via-agent` flag is true."+ 182 "To iterate all the agent pods without limit, set to 0") 183 184 return statusCmd 185 }