我尝试使用jq
来解析JSON(实际上是OpenShift oc process ...
命令的输出),并且添加/更新 env 具有新键/值对的container
数组。
示例输入:
{
"kind": "List",
"apiVersion": "v1",
"metadata": {},
"items": [
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"annotations": {
"description": "Exposes and load balances the node.js application pods"
},
"name": "myapp-web"
},
"spec": {
"ports": [
{
"name": "web",
"port": 3000,
"protocol": "TCP",
"targetPort": 3000
}
],
"selector": {
"name": "myapp"
}
}
},
{
"apiVersion": "v1",
"kind": "Route",
"metadata": {
"name": "myapp-web"
},
"spec": {
"host": "app.internal.io",
"port": {
"targetPort": "web"
},
"to": {
"kind": "Service",
"name": "myapp-web"
}
}
},
{
"apiVersion": "v1",
"kind": "DeploymentConfig",
"metadata": {
"annotations": {
"description": "Defines how to deploy the application server"
},
"name": "myapp"
},
"spec": {
"replicas": 1,
"selector": {
"name": "myapp"
},
"strategy": {
"type": "Rolling"
},
"template": {
"metadata": {
"labels": {
"name": "myapp"
},
"name": "myapp"
},
"spec": {
"containers": [
{
"env": [
{
"name": "A_ENV",
"value": "a-value"
}
],
"image": "node",
"name": "myapp-node",
"ports": [
{
"containerPort": 3000,
"name": "app",
"protocol": "TCP"
}
]
}
]
}
},
"triggers": [
{
"type": "ConfigChange"
}
]
}
}
]
}
在这个JSON中,我想做以下事情:
DeploymentConfig
对象env
数组{"name": "B_ENV", "value": "b-value"}
env
数组,其中包含对象{"name": "B_ENV", "value": "b-value"}
到目前为止,我能够解决部分问题,我能够找到相关对象,并将新的env var添加到容器中:
oc process -f <dc.yaml> -o json | jq '.items | map(if .kind == "DeploymentConfig"
then .spec.template.spec.containers[0].env |= .+ [{"name": "B_ENV", "value": "b-value"}]
else .
end)'
这可以按预期插入新的env var,但输出是一个数组,如下所示。 此外,它根本不处理 env
数组可能不存在的部分。
我希望能够生成与输入相同的输出,但添加了新的env var。
示例输出:
[
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"annotations": {
"description": "Exposes and load balances the node.js application pods"
},
"name": "myapp-web"
},
"spec": {
"ports": [
{
"name": "web",
"port": 3000,
"protocol": "TCP",
"targetPort": 3000
}
],
"selector": {
"name": "myapp"
}
}
},
{
"apiVersion": "v1",
"kind": "Route",
"metadata": {
"name": "myapp-web"
},
"spec": {
"host": "app.internal.io",
"port": {
"targetPort": "web"
},
"to": {
"kind": "Service",
"name": "myapp-web"
}
}
},
{
"apiVersion": "v1",
"kind": "DeploymentConfig",
"metadata": {
"annotations": {
"description": "Defines how to deploy the application server"
},
"name": "myapp"
},
"spec": {
"replicas": 1,
"selector": {
"name": "myapp"
},
"strategy": {
"type": "Rolling"
},
"template": {
"metadata": {
"labels": {
"name": "myapp"
},
"name": "myapp"
},
"spec": {
"containers": [
{
"env": [
{
"name": "A_ENV",
"value": "a-value"
},
{
"name": "B_ENV",
"value": "b-value"
}
],
"image": "node",
"name": "myapp-node",
"ports": [
{
"containerPort": 3000,
"name": "app",
"protocol": "TCP"
}
]
}
]
}
},
"triggers": [
{
"type": "ConfigChange"
}
]
}
}
]
这是可行的,还是与jq
太过分了,我应该在python或node中这样做?
编辑1 :
我刚刚意识到env
数组的条件添加/更新已经由|=
语法处理了!
所以,我基本上只需要能够将相同的结构作为输入返回,并在相关数组中添加相关的env var。
答案 0 :(得分:3)
你几乎拥有它,但是你想要重构你的过滤器以保留完整的结果。您希望确保没有任何过滤器更改上下文。从.items
开始,您将其从根对象更改为items
数组。这本身并不是一个问题,而是你做的事情。请记住,分配/更新会在应用更改时保留原始上下文。因此,如果您根据更新编写过滤器,它将适合您。
为此,您要在env
项中找到第一个容器的DeploymentConfig
数组。首先让我们找到:
.items[] | select(.kind == "DeploymentConfig").spec.template.spec.containers[0].env
您不需要在错误处理方面做任何其他事情,因为select
根本不会产生任何结果。从那里,您只需要通过添加新值来更新数组。
(.items[] | select(.kind == "DeploymentConfig").spec.template.spec.containers[0].env) +=
[{name:"B_ENV",value:"b-value"}]
如果数组存在,它将添加新项。如果没有,它将创建一个新的env
数组。如果env
不是数组,那将是一个不同的问题。