istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/writer/envoy/configdump/configdump.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 configdump 16 17 import ( 18 "fmt" 19 "io" 20 "strings" 21 "text/tabwriter" 22 23 adminv3 "github.com/envoyproxy/go-control-plane/envoy/admin/v3" 24 "sigs.k8s.io/yaml" 25 26 "istio.io/istio/istioctl/pkg/util/configdump" 27 sdscompare "istio.io/istio/istioctl/pkg/writer/compare/sds" 28 "istio.io/istio/pkg/util/protomarshal" 29 ) 30 31 // ConfigWriter is a writer for processing responses from the Envoy Admin config_dump endpoint 32 type ConfigWriter struct { 33 Stdout io.Writer 34 configDump *configdump.Wrapper 35 } 36 37 // includeConfigType is a flag to indicate whether to include the config type in the output 38 var includeConfigType bool 39 40 func SetPrintConfigTypeInSummary(p bool) { 41 includeConfigType = p 42 } 43 44 // Prime loads the config dump into the writer ready for printing 45 func (c *ConfigWriter) Prime(b []byte) error { 46 w := &configdump.Wrapper{} 47 err := w.UnmarshalJSON(b) 48 if err != nil { 49 return fmt.Errorf("error unmarshalling config dump response from Envoy: %v", err) 50 } 51 c.configDump = w 52 return nil 53 } 54 55 // PrintBootstrapDump prints just the bootstrap config dump to the ConfigWriter stdout 56 func (c *ConfigWriter) PrintBootstrapDump(outputFormat string) error { 57 if c.configDump == nil { 58 return fmt.Errorf("config writer has not been primed") 59 } 60 bootstrapDump, err := c.configDump.GetBootstrapConfigDump() 61 if err != nil { 62 return err 63 } 64 out, err := protomarshal.ToJSONWithIndent(bootstrapDump, " ") 65 if err != nil { 66 return fmt.Errorf("unable to marshal bootstrap in Envoy config dump: %v", err) 67 } 68 if outputFormat == "yaml" { 69 outbyte, err := yaml.JSONToYAML([]byte(out)) 70 if err != nil { 71 return err 72 } 73 out = string(outbyte) 74 } 75 fmt.Fprintln(c.Stdout, out) 76 return nil 77 } 78 79 // PrintSecretDump prints just the secret config dump to the ConfigWriter stdout 80 func (c *ConfigWriter) PrintSecretDump(outputFormat string) error { 81 if c.configDump == nil { 82 return fmt.Errorf("config writer has not been primed") 83 } 84 secretDump, err := c.configDump.GetSecretConfigDump() 85 if err != nil { 86 return fmt.Errorf("sidecar doesn't support secrets: %v", err) 87 } 88 out, err := protomarshal.ToJSONWithIndent(secretDump, " ") 89 if err != nil { 90 return fmt.Errorf("unable to marshal secrets in Envoy config dump: %v", err) 91 } 92 if outputFormat == "yaml" { 93 outbyte, err := yaml.JSONToYAML([]byte(out)) 94 if err != nil { 95 return err 96 } 97 out = string(outbyte) 98 } 99 fmt.Fprintln(c.Stdout, out) 100 return nil 101 } 102 103 // PrintSecretSummary prints a summary of dynamic active secrets from the config dump 104 func (c *ConfigWriter) PrintSecretSummary() error { 105 secretDump, err := c.configDump.GetSecretConfigDump() 106 if err != nil { 107 return err 108 } 109 if len(secretDump.DynamicActiveSecrets) == 0 && 110 len(secretDump.DynamicWarmingSecrets) == 0 { 111 fmt.Fprintln(c.Stdout, "No active or warming secrets found.") 112 return nil 113 } 114 secretItems, err := sdscompare.GetEnvoySecrets(c.configDump) 115 if err != nil { 116 return err 117 } 118 119 secretWriter := sdscompare.NewSDSWriter(c.Stdout, sdscompare.TABULAR) 120 return secretWriter.PrintSecretItems(secretItems) 121 } 122 123 func (c *ConfigWriter) PrintFullSummary(cf ClusterFilter, lf ListenerFilter, rf RouteFilter, epf EndpointFilter) error { 124 if err := c.PrintBootstrapSummary(); err != nil { 125 return err 126 } 127 _, _ = c.Stdout.Write([]byte("\n")) 128 if err := c.PrintClusterSummary(cf); err != nil { 129 return err 130 } 131 _, _ = c.Stdout.Write([]byte("\n")) 132 if err := c.PrintListenerSummary(lf); err != nil { 133 return err 134 } 135 _, _ = c.Stdout.Write([]byte("\n")) 136 if err := c.PrintRouteSummary(rf); err != nil { 137 return err 138 } 139 _, _ = c.Stdout.Write([]byte("\n")) 140 if err := c.PrintSecretSummary(); err != nil { 141 return err 142 } 143 _, _ = c.Stdout.Write([]byte("\n")) 144 if err := c.PrintEndpointsSummary(epf); err != nil { 145 return err 146 } 147 return nil 148 } 149 150 // PrintBootstrapSummary prints bootstrap information for Istio and Envoy from the config dump 151 func (c *ConfigWriter) PrintBootstrapSummary() error { 152 if c.configDump == nil { 153 return fmt.Errorf("config writer has not been primed") 154 } 155 156 bootstrapDump, err := c.configDump.GetBootstrapConfigDump() 157 if err != nil { 158 return err 159 } 160 161 var ( 162 istioVersion, istioProxySha = c.getIstioVersionInfo(bootstrapDump) 163 envoyVersion = c.getUserAgentVersionInfo(bootstrapDump) 164 165 tw = tabwriter.NewWriter(c.Stdout, 0, 8, 1, ' ', 0) 166 ) 167 168 if len(istioVersion) > 0 { 169 fmt.Fprintf(tw, "Istio Version:\t%s\n", istioVersion) 170 } 171 if len(istioProxySha) > 0 { 172 fmt.Fprintf(tw, "Istio Proxy Version:\t%s\n", istioProxySha) 173 } 174 if len(envoyVersion) > 0 { 175 fmt.Fprintf(tw, "Envoy Version:\t%s\n", envoyVersion) 176 } 177 178 return tw.Flush() 179 } 180 181 // PrintPodRootCAFromDynamicSecretDump prints just pod's root ca from dynamic secret config dump to the ConfigWriter stdout 182 func (c *ConfigWriter) PrintPodRootCAFromDynamicSecretDump() (string, error) { 183 if c.configDump == nil { 184 return "", fmt.Errorf("config writer has not been primed") 185 } 186 secretDump, err := c.configDump.GetSecretConfigDump() 187 if err != nil { 188 return "", fmt.Errorf("sidecar doesn't support secrets: %v", err) 189 } 190 for _, secret := range secretDump.DynamicActiveSecrets { 191 // check the ROOTCA from secret dump 192 if secret.Name == "ROOTCA" { 193 var returnStr string 194 var returnErr error 195 strCA, err := c.configDump.GetRootCAFromSecretConfigDump(secret.GetSecret()) 196 if err != nil { 197 returnStr = "" 198 returnErr = fmt.Errorf("can not dump ROOTCA from secret: %v", err) 199 } else { 200 returnStr = strCA 201 returnErr = nil 202 } 203 return returnStr, returnErr 204 } 205 } 206 return "", fmt.Errorf("can not find ROOTCA from secret") 207 } 208 209 func (c *ConfigWriter) getIstioVersionInfo(bootstrapDump *adminv3.BootstrapConfigDump) (version, sha string) { 210 const ( 211 istioVersionKey = "ISTIO_VERSION" 212 istioProxyShaKey = "ISTIO_PROXY_SHA" 213 ) 214 215 md := bootstrapDump.GetBootstrap().GetNode().GetMetadata().GetFields() 216 217 if versionPB, ok := md[istioVersionKey]; ok { 218 version = versionPB.GetStringValue() 219 } 220 if shaPB, ok := md[istioProxyShaKey]; ok { 221 sha = shaPB.GetStringValue() 222 if shaParts := strings.Split(sha, ":"); len(shaParts) > 1 { 223 sha = shaParts[1] 224 } 225 } 226 227 return 228 } 229 230 func (c *ConfigWriter) getUserAgentVersionInfo(bootstrapDump *adminv3.BootstrapConfigDump) string { 231 const ( 232 buildLabelKey = "build.label" 233 buildTypeKey = "build.type" 234 statusKey = "revision.status" 235 sslVersionKey = "ssl.version" 236 ) 237 238 var ( 239 buildVersion = bootstrapDump.GetBootstrap().GetNode().GetUserAgentBuildVersion() 240 version = buildVersion.GetVersion() 241 md = buildVersion.GetMetadata().GetFields() 242 243 sb strings.Builder 244 ) 245 246 fmt.Fprintf(&sb, "%d.%d.%d", version.GetMajorNumber(), version.GetMinorNumber(), version.GetPatch()) 247 if label, ok := md[buildLabelKey]; ok { 248 fmt.Fprintf(&sb, "-%s", label.GetStringValue()) 249 } 250 if status, ok := md[statusKey]; ok { 251 fmt.Fprintf(&sb, "/%s", status.GetStringValue()) 252 } 253 if typ, ok := md[buildTypeKey]; ok { 254 fmt.Fprintf(&sb, "/%s", typ.GetStringValue()) 255 } 256 if sslVersion, ok := md[sslVersionKey]; ok { 257 fmt.Fprintf(&sb, "/%s", sslVersion.GetStringValue()) 258 } 259 260 return sb.String() 261 }