Ansible playbook命令出现问题?

8

我想在我的机器上执行docker中的命令,来控制其他机器。当我执行以下命令时:

- name: Add header
      command: docker exec cli bash -l -c "echo '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":'$(cat jaguar_update.json)'}}}' | jq . > jaguar_update_in_envelope.json"

通过ansible playbook,我得到了下面显示的错误。
fatal:[  
   command-task
]:FAILED! =>{  
   "changed":true,
   "cmd":[  ],
   "delta":"0:00:00.131115",
   "end":"2019-07-11 17:32:44.651504",
   "msg":"non-zero return code",
   "rc":4,
   "start":"2019-07-11 17:32:44.520389",
   "stderr":"mesg: ttyname   
failed: Inappropriate ioctl for device\nparse error: Invalid numeric   
literal at line 1, column 9",
   "stderr_lines":[  
      "mesg: ttyname failed: 
Inappropriate ioctl for device",
      "parse error: Invalid numeric literal 
at line 1, column 9"
   ],
   "stdout":"",
   "stdout_lines":[  

   ]
}

但是,如果我在Docker容器中手动执行命令,则可以正常工作,不会出现任何问题。
编辑: 如建议所示,我尝试使用shell模块。
shell: docker exec cli -it bash -l -c "echo '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":'$(cat jaguar_update.json)'}}}' | jq . > jaguar_update_in_envelope.json"

但是我遇到以下错误:

致命错误:[command-task]:FAILED! => {"changed": true,"cmd": "docker exec cli-it bash -l -c echo '{\"payload\":{\"header\":{\"channel_header\":{\"channel_id\":\"gll\",\"type\":2}},\"data\":{\"config_update\":'$(cat jaguar_update.json)'}}}' | jq . > jaguar_update_in_envelope.json","delta": "0:00:00.110341","end": "2019-07-12 10:21:45.204049","msg": "非零返回代码","rc": 4,"start": "2019-07-12 10:21:45.093708","stderr": "cat:jaguar_update.json:没有那个文件或目录\n解析错误:第1行,第4列的数字文字非法","stderr_lines":["cat:jaguar_update.json:没有那个文件或目录","解析错误:第1行,第4列的数字文字非法"],"stdout":","stdout_lines":[]}

所有文件'jaguar_update.json'都在工作目录中。 我已确认工作目录。

如果我将这些命令放在一个shell脚本文件中,然后从ansible执行该shell脚本,则可以运行以上命令。


你可以尝试使用 docker exec -it cli bash -l -c 命令,其中 -it 选项用于交互式终端。试试看吧。 - mchawre
它没有起作用。 - TechChain
1
你可以尝试使用Shell模块吗? - Smily
1
这里需要使用shell而不是commandcommand无法使用管道和重定向。下一个问题将是嵌套引号。 - Vladimir Botka
我应该如何在这里使用Shell? - TechChain
3个回答

3

正如大家所提到的,这需要您使用shell而不是command。现在,您希望简化此命令,以便可以在bash中首先运行。可以使用printf轻松完成此操作。

$ printf "%s%s%s" '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":' $(<jaguar_update.json'}}}' | jq . > jaguar_update_in_envelope.json

$ cat jaguar_update_in_envelope.json
{
  "payload": {
    "header": {
      "channel_header": {
        "channel_id": "gll",
        "type": 2
      }
    },
    "data": {
      "config_update": {
        "name": "tarun"
      }
    }
  }
}

现在我们的命令可以正常运行。下一步是将其移动到bash -l -c格式。因此,我们不再使用需要将整个命令作为一个参数传递的-c,而是使用多行命令。

$ bash -l <<EOF
printf "%s%s%s" '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":' $(<jaguar_update.json) '}}}' | jq . > jaguar_update_in_envelope.json
EOF

但是这会导致错误。
{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":{bash: line 2: name:: command not found
bash: line 3: syntax error near unexpected token `}'
bash: line 3: `} '}}}' | jq . > jaguar_update_in_envelope.json'

这是因为 EOF 格式会将每个新行视为不同的命令。所以我们需要替换所有的新行字符。

bash -l <<EOF
printf "%s%s%s" '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":' $(sed -E 's|"|\\"|g' jaguar_update.json | tr -d '\n') '}}}' | jq . > jaguar_update_in_envelope.json
EOF

现在在ansible中,
- name: a play that runs entirely on the ansible host
  hosts: 127.0.0.1
  connection: local
  tasks:
     - name: Solve the problem
       shell: |
           bash -l <<EOF
                printf "%s%s%s" '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":' $(sed -E 's|"|\\"|g' jaguar_update.json | tr -d '\n') '}}}' | jq . > jaguar_update_in_envelope.json
           EOF

结果如下:

$ ansible-playbook test.yml
PLAY [a play that runs entirely on the ansible host] *********************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************************************************
ok: [127.0.0.1]

TASK [Solve the problem] *************************************************************************************************************************************************************
changed: [127.0.0.1]

PLAY RECAP ***************************************************************************************************************************************************************************
127.0.0.1                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

$ cat jaguar_update_in_envelope.json
{
  "payload": {
    "header": {
      "channel_header": {
        "channel_id": "gll",
        "type": 2
      }
    },
    "data": {
      "config_update": {
        "name": "tarun"
      }
    }
  }
}

1

请参阅文档 -

  • 这些命令不会通过shell进行处理,因此像$HOME这样的变量和"<", ">", "|", ";" 和 "&"等操作将无法使用。 如果需要这些功能,请使用shell模块。

shell 相当于向sh命令解析器提交脚本。

另一个注意点-在$(cat jaguar_update.json)之前结束单引号并在之后重新开始,但不要在其周围使用任何双引号。您的输出可能会处理它,但我想提醒一下以防有影响。


1
为了避免复杂性,可以尝试像这个问题中一样使用脚本来包装您的命令,并调用该脚本(使用commandshell)。
- name: Add header
      raw: /path/to/script/docker-add-header.sh

/path/to/script/docker-add-header.sh 中:
docker exec cli -it bash -l -c "echo '{"payload":{"header":{"channel_header":{"channel_id":"gll", "type":2}},"data":{"config_update":'$(cat jaguar_update.json)'}}}' | jq . > jaguar_update_in_envelope.json

首先尝试让脚本独立工作(不使用Ansible)。
如果脚本在任何Ansible调用之外都无法正常工作,请注意避免嵌套的双引号:

docker exec cli -it bash -l -c "echo '{\"payload\":{\"header\":...

哈哈。这是我现在为解决它所做的修复措施。但我也在寻找ansible的解决方案 :-) - TechChain
@DhirajKumar 我明白。但是经过多次尝试,我最终也是使用脚本来完成的。 - VonC
谢谢@Vonc。我认为我们现在只剩下shell脚本解决方案了。 - TechChain
@DhirajKumar 我同意:让我们等待你的悬赏结束,看看是否有更好的解决方案可以提供。 - VonC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接