【问题标题】:Go Templates - Check whether a key exists in json listGo Templates - 检查 json 列表中是否存在键
【发布时间】:2017-02-16 22:43:18
【问题描述】:

我正在使用 confd 进行动态 nginx 服务重新配置,并且在使用 Go 模板时遇到了一些困难。我有一个名为 $data 的 json 对象,$data.subsets 可能包含一个名为“地址”的键——如果满足该条件,我只想在循环内执行模板。

我已经尝试过各种方法,例如您在下面看到的 $data.subsets[0].addresses,这是完全错误的。我不确定如何正确地做到这一点。

这是我的 nginx 模板的一部分,我只想在至少有 1 个上游服务时渲染它,而不是在没有/不可用的情况下渲染。

在模板之后是 $data 的 json 对象,无论成功还是失败。

提前感谢您的帮助,非常感谢!

{{ range $ns := getvs "/registry/services/endpoints/*/app" }}
{{ $data := json $ns }}
    {{ if $data.subsets[0].addresses }}
upstream {{ $data.metadata.namespace }}_{{ $data.metadata.name }}_pool {
        {{ range $subset := $data.subsets }}{{ range $ref := $subset.addresses }}{{ range $portConfig := $subset.ports }}
 server {{ $ref.ip }}:{{ $portConfig.port }};
        {{ end }}{{ end }}{{ end }}
}
    {{ end }}
{{ end }}

没有安排 Pod 时的 $data 示例:

{  
   "kind":"Endpoints",
   "apiVersion":"v1",
   "metadata":{  
      "name":"app",
      "namespace":"ns1",
      "selfLink":"/api/v1/namespaces/ns1/endpoints/app",
      "labels":{  
         "app":"app"
      }
   },
   "subsets":[]
}

$data 的示例,当有 pod 正在运行但不健康时:

{  
   "kind":"Endpoints",
   "apiVersion":"v1",
   "metadata":{  
      "name":"app",
      "namespace":"ns1",
      "labels":{  
         "app":"app"
      }
   },
   "subsets":[  
      {  
         "notReadyAddresses":[  
            {  
               "ip":"10.254.60.5",
               "targetRef":{  
                  "kind":"Pod",
                  "namespace":"ns1",
                  "name":"app-421757659-83rfg",
               }
            }
         ],
         "ports":[  
            {  
               "name":"ns1-app-8080",
               "port":8080,
               "protocol":"TCP"
            }
         ]
      }
   ]
}

$data 的示例,当有 pod 正在运行且可用时。这是模板迭代渲染时我希望满足的唯一条件。

{  
   "kind":"Endpoints",
   "apiVersion":"v1",
   "metadata":{  
      "name":"app",
      "namespace":"ns1",
      "selfLink":"/api/v1/namespaces/ns1/endpoints/app",
      "labels":{  
         "app":"app"
      }
   },
   "subsets":[  
      {  
         "addresses":[  
            {  
               "ip":"10.254.18.11",
               "targetRef":{  
                  "kind":"Pod",
                  "namespace":"ns1",
                  "name":"app-3869480132-kfthi"
               }
            },
            {  
               "ip":"10.254.18.9",
               "targetRef":{  
                  "kind":"Pod",
                  "namespace":"ns1",
                  "name":"app-3869480132-9bufk"
               }
            }
         ],
         "ports":[  
            {  
               "name":"ns1-app-8080",
               "port":8080,
               "protocol":"TCP"
            }
         ]
      }
   ]
}

【问题讨论】:

  • 为什么不使用普通的 json 处理检查普通 Go 代码中的条件,然后将 bool 传递给模板?无论它是哪种变体,访问 json 中的值都非常简单,但是鉴于在该上下文中使用的库,我不确定您将如何做到这一点。除非$data 对象在其他地方大量使用,否则我认为根本不应该将它传递给模板,因为其中大部分与该上下文无关。事实上,您可能应该只提取地址列表并传递它,并且在您的模板中没有这些逻辑。

标签: go kubernetes coreos go-templates confd


【解决方案1】:

$data.subsets[0].addresses 是非法的模板表达式(包含[])。试试下面的模板定义:

{{range $cfg := getvs "/registry/services/endpoints/*/app"}}
{{$data := json $cfg}}
{{range $data.subsets}}{{range $addr := .addresses}}
{{with $ns := $addr.targetRef.namespace}}
upstream {{$ns}}_{{$addr.targetRef.name}}_pool {
    {{range $data.subsets}}{{range $port := .ports}}
        {{/* 
            Split port.name then test if address namespace 
            match the port.name. Test Condition:
            len($portDesc) > 0 && $portDesc[0] == $ns
        */}}
        {{$portDesc := split $port.name "-"}}
        {{if and (gt (len $portDesc) 0) (eq (index $portDesc 0) $ns)}}
  server {{ $addr.ip }}:{{ $port.port }};
        {{end}}
    {{end}}{{ end }}
}
{{end}}
{{end}}{{end}}

以上三个json数据生成的输出(去掉空行后)应该是:

upstream ns1_app-3869480132-kfthi_pool {
  server 10.254.18.11:8080;
}
upstream ns1_app-3869480132-9bufk_pool {
  server 10.254.18.9:8080;
}

关键是{{range $data.subsets}}{{range $addr := .addresses}} 中的range 操作。如果管道的lensubsetsaddresses)为零,即subsets 不包含元素或addressesnull(没有名为addresses 的子集元素),则不会写入任何内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-07
    • 2021-06-27
    • 2022-07-12
    • 2014-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    相关资源
    最近更新 更多