1

我们想要解组(在 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 {}.

我们有以下问题:

  1. 有没有办法将结构TypedConfig转换pbany.Any为随后可以解组的类型?
  2. 有没有办法递归解组整个 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,从而解决我们的问题。

4

0 回答 0