我有一个 Ansible 剧本,其中包括在我的集群服务器上通过
cert-manager
生成 Let's Encrypt 证书。
但是我必须等到证书准备好后,才能继续执行剧本中的下一个任务。
这给了我以下 Ansible 任务:
- name: Get TLS certificate secret and wait until ready
command:
cmd: 'kubectl get certificate tls-rancher-ingress -n cattle-system -ojson'
register: certificate_result
changed_when: (certificate_result.stdout | json_query('status.conditions[0].status') == '"True"')
retries: 10
delay: 30
在上面的代码中,证书名为
tls-rancher-ingress
,我通过调用 kubectl
获取有关证书的一般信息。输出以 JSON 形式呈现。
kubectl
命令的输出(稍微匿名)采用以下形式:
{
"apiVersion": "cert-manager.io/v1",
"kind": "Certificate",
"metadata": {
"creationTimestamp": "2024-05-27T23:19:38Z",
"generation": 2,
"name": "tls-rancher-ingress",
"namespace": "cattle-system",
"resourceVersion": "2331753",
"uid": "30b816cd-f548-4bf7-90d2-47a0406cdbb1"
},
"spec": {
"commonName": "rancher.example.com",
"dnsNames": [
"rancher.example.com"
],
"issuerRef": {
"kind": "ClusterIssuer",
"name": "letsencrypt-prod"
},
"secretName": "tls-rancher-ingress"
},
"status": {
"conditions": [
{
"lastTransitionTime": "2024-05-28T00:38:38Z",
"message": "Certificate is up to date and has not expired",
"observedGeneration": 2,
"reason": "Ready",
"status": "True",
"type": "Ready"
}
],
"notAfter": "2024-08-25T23:38:35Z",
"notBefore": "2024-05-27T23:38:36Z",
"renewalTime": "2024-07-26T23:38:35Z",
"revision": 2
}
}
但我对整个 JSON 对象不感兴趣,而只对路径
status.conditions[0].status
等于 "True"
感兴趣。
我想我可以使用管道过滤器将
certificate_result.stdout
发送到json_query("status.conditions[0].status")
,然后得到响应,即"True"
或"False"
。
使用任务悬停来调试
change_when
行会显示 json_query
返回空字符串?
我使用以下任务进行调试:
- name: Debug changed_when
debug:
msg: "DEBUG: {{ certificate_result.stdout | community.general.json_query('status.conditions[0].status') }}"
我使用单引号还是双引号封装字符串并不重要。
有没有人可以解释一下这是怎么回事?
是否因为
stdout
没有被视为 JSON 对象,如果是这样:将其发送到 json_query 的正确方法是什么?
供参考:
json_query
是 community.general
集合的一部分,已安装在我运行 Ansible playbook 的位置。
经过一番搜索后,我成功了。
使用的过滤器是
from_json
,这让我有点困惑。
因为虽然输出的结构是 JSON 对象,但
certificate_result.stdout
的输出将被视为字符串,因此我必须使用 to_json
将其转换为可查询的 JSON 对象。
但我显然有点……倒退了?
因此正确的命令是:
not (certificate_result.stdout | from_json | json_query("status.conditions[0].status") == "True")
整个任务如下:
- name: Get TLS certificate secret and wait until ready
command:
cmd: 'kubectl get certificate tls-rancher-ingress -n cattle-system -ojson'
register: certificate_result
until: certificate_result.stdout | from_json | json_query("status.conditions[0].status") == "True"
retries: 10
delay: 30
changed_when: false
快速解释正在发生的事情:
kubectl
命令每 30 秒调用一次,将其内容输出为 JSON 对象。
并希望任务循环直到查询路径
status.conditions[0].status
的结果为真。
如果查询在第 10 次迭代后未返回 true,则任务将失败,这与任务由于 30 秒中断而在 300 秒后超时相同。
changed_when
只是ansible的一个标志,用于告知此任务是否更新了任何值,但事实并非如此,因此它应该始终返回值“false”。