bash saltstack - 传递变量包含单引号、双引号、空格、...到 cmd.script?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29135939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 12:33:56  来源:igfitidea点击:

saltstack - Passing variable contains single, double quotes, space, ... to cmd.script?

bashescapingyamlsalt-stackjinja2

提问by quanta

I have a script that use loggerto simulate some "fake" logins:

我有一个脚本logger用于模拟一些“假”登录:

#!/bin/bash

{%- set maxretry = salt['pillar.get']('fail2ban:maxretry', 3) %}

tag=""
message=""

logger -p auth.info "The {{ maxretry + 1 }} \"$tag\" below lines are generated by logger to test Fail2ban"

for i in $(seq {{ maxretry + 1 }}); do
    logger -p auth.warning -t "$tag" "$message"
done

It is called in a macro:

它在宏中调用:

fake_{{ formula }}_login:
  cmd:
    - script
    - source: salt://fail2ban/fake_login.jinja2
    - template: jinja
    - args: "{{ tag|default(formula) }} '{{ message }}'"
    - require:
      - sls: bash
      - sls: fail2ban

The thing is {{ message }} can contain single/double quotes, space, square bracket,... According to the cmd.script doc, to pass a string containing a space, we will have to double-quote it. But if I have something like this:

事情是 {{ message }} 可以包含单/双引号,空格,方括号,...根据 cmd.script 文档,要传递包含空格的字符串,我们将不得不双引号它。但如果我有这样的事情:

{{ fail2ban_regex_test('mysql', tag='mysqld', message="150114  3:40:50 [Warning] Access denied for user 'root'@'5.6.7.8' (using password: YES)") }}

it will be logged to the syslog without the single quote around the user/host, just:

它将被记录到系统日志中,用户/主机周围没有单引号,只需:

mysqld: 150114  3:40:50 [Warning] Access denied for user [email protected] (using password: YES)

that make fail2ban failed to recognized as it does not match the filter regex.

这使 fail2ban 未能识别,因为它与过滤器正则表达式不匹配。

I can change the single quote to double quote and use backslash to escape:

我可以将单引号更改为双引号并使用反斜杠进行转义:

fake_{{ formula }}_login:
  cmd:
    - script
    - source: salt://fail2ban/fake_login.jinja2
    - template:
jinja
    - args: "{{ tag|default(formula) }} \"{{ message|safe }}\""

    - require:
      - sls: bash
      - sls: fail2ban

it handle the above case when message just contains the single quotes.

当消息只包含单引号时,它处理上述情况。

But if it contains the double quotes:

但如果它包含双引号:

{{ fail2ban_regex_test('postfix', tag='postfix/smtpd[20228]', message="NOQUEUE: reject: RCPT from sender.com["5.6.7.8"]: 554 5.7.1 <[email protected]>: Recipient address rejected: Access denied; from=<[email protected]> to=<[email protected]> proto=ESMTP helo=<mg01d1.sender.com>") }}

I got this error:

我收到此错误:

local:
    Data failed to compile:
----------
    Rendering SLS "base:postfix.test" failed: Jinja syntax error: expected token ',', got 'float'; line 29


---
[...]
- sls: openldap
- sls: openldap.diamond
- sls: openldap.nrpe
{%- endcall %}


{{ fail2ban_regex_test('postfix', tag='postfix/smtpd[20228]', message="NOQUEUE: reject: RCPT from sender.com["5.6.7.8"]: 554 5.7.1 <[email protected]>: Recipie
nt address rejected: Access denied; from=<[email protected]> to=<[email protected]> proto=ESMTP helo=<mg01d1.sender.com>") }}    <======================

If I tried to escape the double quote with a backslash:

如果我试图用反斜杠转义双引号:

... message="NOQUEUE: reject: RCPT from sender.com[\"5.6.7.8\"] ...

then I got another error:

然后我得到了另一个错误:

local:
    Data failed to compile:
----------
    Rendering SLS postfix.test failed, render error: while parsing a block mapping
  in "<unicode string>", line 84, column 7:
        - args: "postfix/smtpd[20228] \"NO ...
          ^
expected <block end>, but found '<scalar>'
  in "<unicode string>", line 84, column 76:
     ... : reject: RCPT from sender.com["5.6.7.8"]: 554 5.7.1 <user@examp ...

How to handle both cases?

这两种情况如何处理?

回答by cuonglm

saltstackextended jinjabuiltin filters with some custom filters:

saltstackjinja带有一些自定义过滤器的扩展内置过滤

  • yaml_dquote: Serializes a string into a properly-escaped YAML double-quoted string.
  • yaml_encode: Serializes a single object into a YAML scalar with any necessary handling for escaping special characters.
  • yaml_dquote: 将字符串序列化为正确转义的 YAML 双引号字符串。
  • yaml_encode:使用任何必要的处理来转义特殊字符,将单个对象序列化为 YAML 标量。

Something like:

就像是:

{%- set foo = 7.7 %}
{%- set bar = none %}
{%- set baz = true %}
{%- set zap = 'The word of the day is "salty".' %}
{%- set zip = '"The quick brown fox . . ."' %}

foo: {{ foo|yaml_encode }}
bar: {{ bar|yaml_encode }}
baz: {{ baz|yaml_encode }}
zap: {{ zap|yaml_encode }}
zip: {{ zip|yaml_dquote }}

give you:

给你:

foo: 7.7
bar: null
baz: true
zap: "The word of the day is \"salty\"."
zip: "\"The quick brown fox . . .\""

With arbitrary string, even {{ var|yaml_encode|yaml_decode }}may not work. It's better if you can encode the string then decode it in script.

使用任意字符串,甚至{{ var|yaml_encode|yaml_decode }}可能不起作用。如果您可以对字符串进行编码,然后在脚本中对其进行解码,那就更好了。

回答by anishsane

You have message variable, which can contain special characters.

您有消息变量,它可以包含特殊字符。

- args: "{{ tag|default(formula) }} '{{ message }}'"

My understanding is that your bash script takes 2 arguments:

我的理解是您的 bash 脚本需要 2 个参数:

#!/bin/bash
tag=
message=
echo "$message" #some use of message

You are calling your script with cmd.script.

您正在使用 cmd.script 调用您的脚本。

Instead of this, you can perhaps change your scripts as below:

取而代之的是,您可以按如下方式更改脚本:

- args: "{{ tag|default(formula) }}"
- stdin: "{{ message }}\n"

& bash script to:

& bash 脚本:

#!/bin/bash
tag=
read message
echo "$message" #some use of message