【问题标题】:Ansible and jinja - Sending double-quote escaped JSON string into AWSAnsible 和 jinja - 将双引号转义的 JSON 字符串发送到 AWS
【发布时间】:2020-06-08 17:06:08
【问题描述】:

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

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

我尝试了一些过滤器来获取 ansible 和 jinja 以获取 JSON 变量并将其转换为所需格式的字符串,但结果永远不会完全正确。 | to_json |字符串给出以下结果:

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

当我尝试使用替换或正则表达式替换时,似乎即使使用保护字符,我最终也会遇到 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": ""
}

使用正则表达式替换,我可以一直删除单引号并将其替换为 '\',但任何添加 '\"' 的尝试总是会因上述解析错误而失败。

这是调用 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(`"`,`\\"`) }}"}'

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

最终编辑:

经过几天的工作,想出了这个。在每个步骤中,您都需要转换正确的类型以保留 JSON 格式。在进行更新时,每个列表元素都需要过滤到 to_json。示例:

  token_list: "{{ (token_list | default([]) + [_update]) | to_json }}"

_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}}}"

【问题讨论】:

  • token_list_update 这个值是什么?
  • 如果您在不使用非 JSON 字符(例如反引号)的情况下发布了错误,也会很有帮助;我怀疑 ansible 正在做正确的事情,但是如果您不习惯它,将消息打包为 JSON 本身的默认 stdout 回调可能会令人困惑。再往下走,你确定secret: "{{ token_list_update | to_json }}" 没有做你想做的事吗?您是否在 AWS 中检查该项目是否按预期存储?
  • token_list_update 是 dict-list-dict 本机对象。抱歉,我没有澄清这一点。 "{{ token_list_update | to_json }}" 在 AWS 中存储了不正确的值 - { "data": "[{'URL': 'beta.test.net', 'token': 'beta-token'}, {'token': 'test-token', 'URL': 'beta-prod.test.net'}]" }

标签: python ansible jinja2


【解决方案1】:

使用原生 jinja2 过滤器:tojson

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

我正在使用它:

toto.json.j2:

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

这个生成:

"{\"hello\" : \"world\"}"

【讨论】:

  • 您好,我喜欢这种方法,但它会在列表周围看到新引号,我们如何删除它
  • 这是正常的,这是一个字符串。不知道如何删除它,可能使用子字符串过滤器
【解决方案2】:

这有点长,但这应该可以满足您的需求。

剧本

---
- 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 }}"

print-string.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('\'', '\\"'))

将产生:

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

【讨论】:

  • 感谢您的帮助,丹尼!不幸的是,我们无法解决,但是,我确实找到了一个解决方案,我现在正在更新
  • 我对此进行了测试,似乎 ansible 转换了它:[WARNING]: The value <stripped> (type dict) in a string field was converted to <stripped> (type string). If this does not look like what you expect, quote the entire value to ensure it does not change.
  • 检查 AWS 中的密钥。我更新了我的帖子,并在 AWS Secrets Manager 中放了一张图片。
  • 告诉我你的想法。
  • 我们的开发人员得到了相同的结果,这与您用作源的字符串有关。该格式有效,但我们的来源是这个字符串:{ "data": "[{\"URL\": \"beta.test.net\", \"token\": \"beta-token\"}, {\"URL\": \"beta-prod.test.net\", \"token\": \"beta-prod-token\"}]" } 来源的引用似乎有所不同 - 无论哪种方式,一旦我有解决方案就会更新
猜你喜欢
  • 2020-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-06
相关资源
最近更新 更多