我们想要解组(在 golang 中)一个 GRPC 消息并将其转换为 amap[string]interface{}
以进一步处理它。使用此代码后:
err := ptypes.UnmarshalAny(resource, config)
configMarshal, err := json.Marshal(config)
var configInterface map[string]interface{}
err = json.Unmarshal(configMarshal, &configInterface)
我们得到以下结构:
{
"name": "envoy.filters.network.tcp_proxy",
"ConfigType": {
"TypedConfig": {
"type_url": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
"value": "ChBCbGFja0hvbGVDbHVzdGVyEhBCbGFja0hvbGVDbHVzdGVy"
}
}
}
字段TypedConfig
保持编码的位置。我们如何解码这个TypedConfig
领域?我们知道type_url
并且我们知道value
,但是要解组该字段,它必须是pbany.Any
类型。但是因为TypedConfig
结构是 a map[string] interface {}
,所以我们的程序要么编译失败,要么崩溃,抱怨它期待一个pbany.Any
类型,但它却得到了一个map[string] interface {}
.
我们有以下问题:
- 有没有办法将结构
TypedConfig
转换pbany.Any
为随后可以解组的类型? - 有没有办法递归解组整个 GRPC 消息?
编辑(提供有关使用的代码、模式/包的更多信息)
我们正在查看xds_proxy.go
这里的代码:https ://github.com/istio/istio/blob/master/pkg/istio-agent/xds_proxy.go
此代码*discovery.DiscoveryResponse
在此函数中使用了一个结构:
func forwardToEnvoy(con *ProxyConnection, resp *discovery.DiscoveryResponse) {
discovery.DiscoveryResponse
(以及代码中使用的所有其他结构)的 protobuf 模式位于此文件的https://github.com/envoyproxy/go-control-plane/存储库中: https ://github.com/envoyproxy/go-控制平面/blob/main/envoy/service/discovery/v3/discovery.pb.go
我们在forwardToEnvoy
函数中添加了代码来查看结构的整个未编组的内容*discovery.DiscoveryResponse
:
var config proto.Message
switch resp.TypeUrl {
case "type.googleapis.com/envoy.config.route.v3.RouteConfiguration":
config = &route.RouteConfiguration{}
case "type.googleapis.com/envoy.config.listener.v3.Listener":
config = &listener.Listener{}
// Six more cases here, truncated to save space
}
for _, resource := range resp.Resources {
err := ptypes.UnmarshalAny(resource, config)
if err != nil {
proxyLog.Infof("UnmarshalAny err %v", err)
return false
}
configMarshal, err := json.Marshal(config)
if err != nil {
proxyLog.Infof("Marshal err %v", err)
return false
}
var configInterface map[string]interface{}
err = json.Unmarshal(configMarshal, &configInterface)
if err != nil {
proxyLog.Infof("Unmarshal err %v", err)
return false
}
}
这很好用,除了现在我们有这些TypedConfig
仍然编码的字段:
{
"name": "virtualOutbound",
"address": {
"Address": {
"SocketAddress": {
"address": "0.0.0.0",
"PortSpecifier": {
"PortValue": 15001
}
}
}
},
"filter_chains": [
{
"filter_chain_match": {
"destination_port": {
"value": 15001
}
},
"filters": [
{
"name": "istio.stats",
"ConfigType": {
"TypedConfig": {
"type_url": "type.googleapis.com/udpa.type.v1.TypedStruct",
"value": "CkF0eXBlLmdvb2dsZWFwaXMuY29tL2Vudm95LmV4dGVuc2lvbnMuZmlsdG"
}
}
},
可视化TypedConfig
字段内容的一种方法是使用以下代码:
for index1, filterChain := range listenerConfig.FilterChains {
for index2, filter := range filterChain.Filters {
proxyLog.Infof("Listener %d: Handling filter chain %d, filter %d", i, index1, index2)
switch filter.ConfigType.(type) {
case *listener.Filter_TypedConfig:
proxyLog.Infof("Found TypedConfig")
typedConfig := filter.GetTypedConfig()
proxyLog.Infof("typedConfig.TypeUrl = %s", typedConfig.TypeUrl)
switch typedConfig.TypeUrl {
case "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy":
tcpProxyConfig := &tcp_proxy.TcpProxy{}
err := typedConfig.UnmarshalTo(tcpProxyConfig)
if err != nil {
proxyLog.Errorf("Failed to unmarshal TCP proxy configuration")
} else {
proxyLog.Infof("TcpProxy Config for filter chain %d filter %d: %s", index1, index2, prettyPrint(tcpProxyConfig))
}
但是代码变得非常复杂,因为我们有大量的结构,并且这些结构可以在消息中以不同的顺序出现。因此,我们希望通过使用来获得一种通用的方式来解组这些TypedConfig
消息pbAny
,从而解决我们的问题。