【问题标题】:How to update value of a yaml key value pair using jq如何使用 jq 更新 yaml 键值对的值
【发布时间】:2018-04-16 18:22:57
【问题描述】:

我会使用 yq / jq 更新 kubernetes yaml 文件中的一些键。这些文件包含用于 kubernetes 部署和服务的多个 yaml 文档。我设法更新了一些键的值。但我坚持更新数组(env)中的键值对。当我对数组索引进行硬编码时,它就可以工作了。但这使它变脆。是否有正确的方法来查找环境名称并使用前缀更新它的值。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: zxl-portalsvc-deployment-$appEnv
spec:
  replicas: 1 
  template: 
    metadata:
      labels:
        app: zxl-portalsvc-$appEnv
    spec:
      containers:
      - name: zxl-portalsvc
        image:  artifactory.oss.oxcart.com:5000/frontface-zxl-mca:5.6.4_17
        imagePullPolicy: Always
        resources:
          limits:
            cpu: "2"
            memory: 4096Mi
          requests:
            cpu: "1"
            memory: 2048Mi
        env:
        - name: MYROLE
          value: "zxl-portalsvc-service-$appEnv.frontface.svc.cluster.local"
        - name: MYAPPS
          value: "contentservices.war portalserver.war c1-integration.war"
        - name: tomcat_Xmx
          value: "3276m"
        ports:
        - containerPort: 8080
        volumeMounts:
          - name: frontface-configs
            mountPath: /usr/local/tomcat/frontface/config
          - name: sso-configs
            mountPath: /usr/local/tomcat/frontface/sso-config/idp_metadata.xml
            subPath: idp_metadata.xml
          - name: sso-configs
            mountPath: /usr/local/tomcat/frontface/sso-config/zxlKeystore.jks
            subPath: zxlKeystore.jks
          - name: tomcat-configs
            mountPath: /usr/local/tomcat/conf/context.xml
            subPath: context.xml
          - name: tomcat-configs
            mountPath: /usr/local/tomcat/conf/logging.properties
            subPath: logging.properties
          - name: tomcat-configs
            mountPath: /usr/local/tomcat/conf/server.xml
            subPath: server.xml
          - name: tomcat-configs
            mountPath: /usr/local/tomcat/conf/tomcat-users.xml
            subPath: tomcat-users.xml
          - name: tomcat-configs
            mountPath: /usr/local/tomcat/conf/web.xml
            subPath: web.xml
          - name: tomcat-configs
            mountPath: /usr/local/tomcat/bin/setenv.sh
            subPath: setenv.sh

      - name: zxl-nginxsvc
        image: artifactory.oss.oxcart.com:5000/oxcart-httpauth:1.3.0
        resources:
          limits:
            cpu: 250m
            memory: 200Mi
          requests:
            cpu: 200m
            memory: 100Mi
        env:
        - name: proxyDst
          value: "localhost"
        ports:
        - containerPort: 80
        volumeMounts:
          - name: nginx-configs
            mountPath: /etc/nginx/conf.d/nginx.htpasswd
            subPath: nginx.htpasswd
          - name: nginx-configs
            mountPath: /etc/nginx/conf.d/default.conf
            subPath: default.conf

      volumes:
      - name: frontface-configs
        configMap:
          name: frontface-config-$appEnv
      - name: sso-configs
        secret:
          secretName: sso-config-$appEnv
      - name: tomcat-configs
        configMap:
          name: tomcat-config-$appEnv
      - name: nginx-configs
        configMap:
          name: nginx-config-$appEnv

---

apiVersion: v1
kind: Service
metadata:
  labels:
    name: zxl-portalsvc-service-$appEnv
  name: zxl-portalsvc-service-$appEnv
spec:
  ports:
    - protocol: TCP
      port: 8080
  selector:
    app: zxl-portalsvc-$appEnv

我让它部分工作,除了它很脆。如果匹配不是第一个元素,那么它将中断。有没有办法解决这个问题。也许通过识别匹配的数组索引。

这是我目前所处的位置:

cat yq_test.yml | yq -y 'if .kind == "Deployment" 
    then (.metadata.name,.spec.template.metadata.labels.app) |= "ORG-" + "DEV-" +  sub("-\\$appEnv";"") | 
        if .spec.template.spec.containers[].env[].name == "MYROLE" then 
            .spec.template.spec.containers[].env[0].value  = "ORG-" + "DEV-" + .spec.template.spec.containers[].env[0].value 
        else empty end 
elif .kind == "Service" then 
    (.metadata.name,.metadata.labels.name,.spec.selector.app) |= "ORG-" + "DEV-" +  sub("-\\$appEnv";"") 
else . end'

【问题讨论】:

    标签: yaml jq


    【解决方案1】:

    通过对 jq 查询进行最小更改来解决问题(据我所知)的一种方法是使用“indexof”函数,例如:

    # Returns the least integer index corresponding to 
    # the first element in the input array or object
    # at which f is truthy, else null
    def indexof(f):
      label $out
      | foreach .[] as $x (null;
           .+1;
           if ($x|f) then (.-1, break $out) else empty end) 
        // null;
    

    然后您的查询可以改写如下:

    if .kind == "Deployment" 
    then (.metadata.name,.spec.template.metadata.labels.app) |=
             "ORG-" + "DEV-" +  sub("-\\$appEnv";"")
          | (.spec.template.spec.containers[].env | indexof(.name == "MYROLE")) as $ix
          | if $ix 
            then .spec.template.spec.containers[].env[$ix].value |= "ORG-" + "DEV-" + .
            else empty
            end 
    elif .kind == "Service"
    then (.metadata.name,.metadata.labels.name,.spec.selector.app) |=
      "ORG-" + "DEV-" +  sub("-\\$appEnv";"") 
    else .
    end
    

    当然,由于使用了containers[],这仍然不可靠。

    通用解决方案

    以下假设要修改所有“MYROLE”组件:

    if .kind == "Deployment" 
    then (.metadata.name,.spec.template.metadata.labels.app) |=
            ("ORG-" + "DEV-" +  sub("-\\$appEnv";""))
          | .spec.template.spec as $spec
          | reduce range(0; $spec.containers | length) as $c (.;
              reduce range(0; $spec.containers[$c].env|length) as $ix (.;
                if $spec.containers[$c].env[$ix].name == "MYROLE"
                then .spec.template.spec.containers[$c].env[$ix].value |=
                  "ORG-" + "DEV-" + .
                else .
                end))
    elif .kind == "Service" 
    then (.metadata.name,.metadata.labels.name,.spec.selector.app) |=
           "ORG-" + "DEV-" +  sub("-\\$appEnv";"") 
    else .
    end
    

    “浮动”解决方案

    在本节中,我们将重点关注更新的目标 .containers[$i].env[$j].value 如果.containers[$i].env[$j].name 是一个指定的值,不管这个相对路径出现在哪里。

    # paths for which: **.containers.*.env.*.name == $value
    def relevantPaths($value):
      . as $in
      | paths 
      | select(.[-1] == "name" and .[-3] == "env" and .[-5] == "containers") as $p
      | select($in|getpath($p) == $value) ;
    
    reduce (relevantPaths("MYROLE") | ((.[-1] = "value"))) as $p (.;
      setpath($p; "ORG-DEV-" + getpath($p)) )
    

    【讨论】:

    • 这解决了我的问题。我选择了通用解决方案。这是我第一次看到reduce函数。我还可以使用 indexOf 函数。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多