Ansible 和 jinja - 将双引号转义的 JSON 字符串发送到 AWS

ans*_*erp 5 python jinja2 ansible

我们需要将双引号转义的 JSON 字符串提供到 NodeJS 产品的 AWS 密钥中。单内双引号格式不适用于该应用程序。结构化数据采用 dict-list-dict 格式。例子:

{
  "data": "[{\"URL\": \"beta.test.net\", \"token\": \"beta-token\"}, {\"URL\": \"beta-prod.test.net\", \"token\": \"beta-prod-token\"}]"
}
Run Code Online (Sandbox Code Playgroud)

我尝试了许多过滤器来让 ansible 和 jinja 获取 JSON 变量并将其转换为所需格式的字符串,但结果从来都不太正确。| 到_json | 字符串给出以下结果:

{
  "data": "[{'URL': 'beta.test.net', 'token': 'beta-token'}, {'token': 'test-token', 'URL': 'beta-prod.test.net'}]"
}
Run Code Online (Sandbox Code Playgroud)

当我尝试使用替换或正则表达式替换时,即使使用保护字符,我最终也会遇到 python 解析错误。下面是一个示例,仅使用坟墓的重音“`”转义进行替换。

TASK [Update secret in AWS] ***************************************************************************************************
task path: path:27
The full traceback is:
Traceback (most recent call last):
  File "/home/.local/lib/python3.5/site-packages/ansible/executor/task_executor.py", line 146, in run
    res = self._execute()
  File "/home/.local/lib/python3.5/site-packages/ansible/executor/task_executor.py", line 587, in _execute
    self._task.post_validate(templar=templar)
  File "/home/.local/lib/python3.5/site-packages/ansible/playbook/task.py", line 296, in post_validate
    super(Task, self).post_validate(templar)
  File "/home/.local/lib/python3.5/site-packages/ansible/playbook/base.py", line 431, in post_validate
    value = templar.template(getattr(self, name))
  File "/home/.local/lib/python3.5/site-packages/ansible/template/__init__.py", line 623, in template
    disable_lookups=disable_lookups,
  File "/home/.local/lib/python3.5/site-packages/ansible/template/__init__.py", line 578, in template
    disable_lookups=disable_lookups,
  File "/home/.local/lib/python3.5/site-packages/ansible/template/__init__.py", line 806, in do_template
    data = _escape_backslashes(data, myenv)
  File "/home/.local/lib/python3.5/site-packages/ansible/template/__init__.py", line 149, in _escape_backslashes
    for token in jinja_env.lex(d2):
  File "/home/.local/lib/python3.5/site-packages/jinja2/lexer.py", line 739, in tokeniter
    name, filename)
jinja2.exceptions.TemplateSyntaxError: unexpected char '`' at 51
  line 1
fatal: [beta-prod]: FAILED! => {
    "msg": "Unexpected failure during module execution.",
    "stdout": ""
}
Run Code Online (Sandbox Code Playgroud)

使用正则表达式替换我可以完全删除单引号并将其替换为“\”,但是任何添加“\””的尝试都将始终失败并出现上述解析错误。

以下是调用 AWS 机密的 ansible 代码,以及我提供正确格式的一些尝试:

    - name: Update secret in AWS
      aws_secret:
        name: '{{ aws_secret_name }}'
        state: present
        secret_type: 'string'
 #       secret: "{{ token_list_update | to_json | replace(\"'\",\"\") | string }}"
        secret: '{{ token_list_update | to_json | string }}'
   #     secret: ' {"data": "{{ token_list | to_json | regex_replace(`"`,`\\"`) }}"}'
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激。我意识到我需要编写自己的过滤器来处理这个问题。我确实询问过应用程序是否接受单双引号 JSON 字符串,但团队表示这是不可接受的。格式必须是双引号转义的 JSON 字符串。

最终编辑:

经过几天的努力,终于解决了这个问题。在每一步中,您都需要转换正确的类型以保留 JSON 格式。进行更新时,每个列表元素都需要过滤为_json。例子:

  token_list: "{{ (token_list | default([]) + [_update]) | to_json }}"
Run Code Online (Sandbox Code Playgroud)

_update 是一个辅助变量,它是 JMESPath 搜索

最终提交到AWS:

    - name: Update secret in AWS
      aws_secret:
        name: "{{ aws_secret_name }}"
        state: present
        secret_type: "string"
        secret: "{\"data\":{{ token_list | to_json}}}"
Run Code Online (Sandbox Code Playgroud)

Tho*_*aux 7

使用本机 jinja2 过滤器:tojson

https://jinja.palletsprojects.com/en/2.10.x/templates/#tojson

我使用它的方式如下:

toto.json.j2:

{"hello" : "world"}
Run Code Online (Sandbox Code Playgroud)
{{ lookup('template', './toto.json.j2') | to_json | tojson }}
Run Code Online (Sandbox Code Playgroud)

这会生成:

"{\"hello\" : \"world\"}"
Run Code Online (Sandbox Code Playgroud)


Dan*_*nez 0

它有点长,但这应该能满足您的需要。

剧本

---
- hosts: localhost

  tasks:
    - name: get string
      shell: "python3.7 print-string.py"
      register: json_string
    - name: Update secret in AWS
      aws_secret:
        name: 'testing/json_string'
        state: present
        secret_type: 'string'
        secret: "{{ json_string['stdout'] | string }}"
Run Code Online (Sandbox Code Playgroud)

打印字符串.py

import json

data = {
      "data": "[{'URL': 'beta.test.net', 'token': 'beta-token'}, {'token': 'beta-prod-token', 'URL': 'beta-prod.test.net'}]"
    }

print(json.dumps(data).replace('[{\'', '[{\\"').replace('\': \'', '\\": \\"').replace('\'', '\\"'))
Run Code Online (Sandbox Code Playgroud)

将产生:

{
  "data": "[{\"URL\": \"beta.test.net\", \"token\": \"beta-token\"}, {\"token\": \"beta-prod-token\", \"URL\": \"beta-prod.test.net\"}]"
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述