如何使用jq更新yaml键值对的值

时间:2018-04-16 18:22:58

标签: yaml jq

我会使用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'

1 个答案:

答案 0 :(得分:0)

使用" indexof"解决问题的方法(据我所知),对jq查询的更改很少。功能,例如:

# 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)) )