你可以如何将变量传递给Ansible中命令模块的argv参数?

huangapple go评论68阅读模式
英文:

How can I pass variables to command module's argv parameter in Ansible?

问题

我试图编写一个配置Redis集群的Ansible角色。

创建集群的shell命令是:

$ /usr/bin/redis-cli --user admin --pass mypass --cluster create 10.226.2.194:6379 10.226.2.196:6379 10.226.2.195:6379 --cluster-replicas 1 --cluster-yes

我将用户名、密码、Redis服务器的IP地址和副本数量作为extra-vars传递给shell脚本:

#!/bin/sh
ansible-playbook /etc/ansible/playbook-redis.yml -vv \
--extra-vars='redis_admin_user=admin redis_admin_password=mypass' \
--extra-vars='redis_cluster_members="10.226.2.194:6379 10.226.2.196:6379 10.226.2.195:6379" redis_cluster_replicas=1';

在阅读命令模块的文档后,我编写了以下任务:

    - name: 创建Redis集群
      ansible.builtin.command:
        argv:
          - /usr/bin/redis-cli
          - "--user {{ redis_admin_user }}"
          - "--pass {{ redis_admin_password }}"
          - "--cluster create {{ redis_cluster_members }}"
          - "--cluster-replicas {{ redis_cluster_replicas }}"
          - --cluster-yes

但是当我运行它时,我收到以下错误消息:

"未识别的选项或参数数量不正确: '--user admin'"

这似乎是redis-cli不识别参数的错误。

通过更改任务,我成功解决了用户名和密码的问题,如下所示:

    - name: 创建Redis集群
      ansible.builtin.command:
        argv:
          - /usr/bin/redis-cli
          - --user
          - "{{ redis_admin_user }}"
          - --pass
          - "{{ redis_admin_password }}"
          - --cluster create
          - "{{ redis_cluster_members }}"
          - --cluster-replicas
          - "{{ redis_cluster_replicas }}"
          - --cluster-yes

这看起来不太美观,但至少传递了用户名和密码,因为以下任务有效:

    - name: 获取服务器信息
      ansible.builtin.command:
        argv:
          - /usr/bin/redis-cli
          - --user
          - "{{ redis_admin_user }}"
          - --pass
          - "{{ redis_admin_password }}"
          - info

但是现在它无法通过--cluster create参数:

"未识别的选项或参数数量不正确: '--cluster create'"

我还尝试了- --cluster create "{{ redis_cluster_members }}"以及以下方法,但都没有成功:

          - --cluster
          - create 
          - "{{ redis_cluster_members }}"

请问运行这个命令的正确语法是什么?

附言:
以下任务正常工作:

    - name: 获取Redis版本
      ansible.builtin.command:
        argv:
          - /usr/bin/redis-cli
          - --version

并返回版本号。

附言:
以下也有效:

    - name: 创建Redis集群
      ansible.builtin.command:
        cmd: "/usr/bin/redis-cli --user {{ redis_admin_user }} --pass {{ redis_admin_password }} --cluster create {{ redis_cluster_members }} --cluster-replicas {{ redis_cluster_replicas }} --cluster-yes"
英文:

I'm trying to write an Ansible role that configures Redis cluster.

The shell command that creates the cluster is:

$ /usr/bin/redis-cli --user admin --pass mypass --cluster create 10.226.2.194:6379 10.226.2.196:6379 10.226.2.195:6379 --cluster-replicas 1 --cluster-yes

I pass username, password, IP addresses of Redis servers and number of replicas as extra-vars in shell script

#!/bin/sh
ansible-playbook /etc/ansible/playbook-redis.yml -vv \
--extra-vars='redis_admin_user=admin redis_admin_password=mypass' \
--extra-vars='redis_cluster_members="10.226.2.194:6379 10.226.2.196:6379 10.226.2.195:6379" redis_cluster_replicas=1'

After reading the documentation for the command module I wrote the following task:

    - name: Create Redis cluster
      ansible.builtin.command:
        argv:
          - /usr/bin/redis-cli
          - "--user {{ redis_admin_user }}"
          - "--pass {{ redis_admin_password }}"
          - "--cluster create {{ redis_cluster_members }}"
          - "--cluster-replicas {{ redis_cluster_replicas }}"
          - --cluster-yes

But when I run it I get the following error:

"Unrecognized option or bad number of args for: '--user admin'"

which seems to be error of redis-cli that it doesn't recognize the argument.

I was able to get around the username and password by changing the task as following:

    - name: Create Redis cluster
      ansible.builtin.command:
        argv:
          - /usr/bin/redis-cli
          - --user 
          - "{{ redis_admin_user }}"
          - --pass
          - "{{ redis_admin_password }}"
          - --cluster create
          - "{{ redis_cluster_members }}"
          - --cluster-replicas
          - "{{ redis_cluster_replicas }}"
          - --cluster-yes

This is not exactly nice looking, but at least it passes the username and the password, because the following task works:

    - name: Get server info
      ansible.builtin.command:
        argv:
          - /usr/bin/redis-cli
          - --user
          - "{{ redis_admin_user }}"
          - --pass
          - "{{ redis_admin_password }}"
          - info

But now it can't get past the --cluster create argument:

"Unrecognized option or bad number of args for: '--cluster create'"

I also tried - --cluster create "{{ redis_cluster_members }}" and

          - --cluster
          - create 
          - "{{ redis_cluster_members }}"

to no avail.

What is the correct syntax to run this command?

P.S.

The following task works correctly:

    - name: Get Redis version
      ansible.builtin.command:
        argv:
          - /usr/bin/redis-cli
          - --version

and returns the version.

P.P.S
The following also works

    - name: Create Redis cluster
      ansible.builtin.command:
        cmd: "/usr/bin/redis-cli --user {{ redis_admin_user }} --pass {{ redis_admin_password }} --cluster create {{ redis_cluster_members }} --cluster-replicas {{ redis_cluster_replicas }} --cluster-yes"

答案1

得分: 1

以下是翻译好的部分:

  • 我不能测试,但我相当肯定您需要在argv列表中将每个集群成员分开为自己的项目。以下内容有点丑陋,但应该可以工作。
    - name: 创建 Redis 集群
      vars:
        argv_start:
          - /usr/bin/redis-cli
          - --user
          - "{{ redis_admin_user }}"
          - --pass
          - "{{ redis_admin_password }}"
          - --cluster
          - create
        argv_end:
          - --cluster-replicas
          - "{{ redis_cluster_replicas }}"
          - --cluster-yes
      ansible.builtin.command:
        argv: "{{ argv_start + [redis_cluster_replicas] + argv_end }}"
英文:

I can't test but I'm pretty sure you need to separate each cluster member in its own item in the argv list. The following is a bit ugly but should work.

    - name: Create Redis cluster
      vars:
        argv_start:
          - /usr/bin/redis-cli
          - --user 
          - "{{ redis_admin_user }}"
          - --pass
          - "{{ redis_admin_password }}"
          - --cluster
          - create
        argv_end:
          - --cluster-replicas
          - "{{ redis_cluster_replicas }}"
          - --cluster-yes
      ansible.builtin.command:
        argv: "{{ argv_start + redis_cluster_replicas | split + argv_end }}"

答案2

得分: 0

Got help from Ansible devs at GitHub. The reason for this behavior is how command module and redis-cli utility work with arguments.

argv adds delimiters when passing the command to the command line. So this:

- name: Create Redis cluster
  ansible.builtin.command:
    argv:
      - /usr/bin/redis-cli
      - "--user {{ redis_admin_user }}"
      - "--pass {{ redis_admin_password }}"
      - "--cluster create {{ redis_cluster_members }}"
      - "--cluster-replicas {{ redis_cluster_replicas }}"
      - --cluster-yes

turns to (mind the single quotation marks)

/usr/bin/redis-cli '--user admin' '--pass mypass' '--cluster create 10.226.2.194:6379 10.226.2.196:6379 10.226.2.195:6379' '--cluster-replicas 1' '--cluster-yes'

If you enter the above command directly you'll get the same error when running the task - "Unrecognized option or bad number of args for: '--user admin'"

This is because how redis-cli delimits arguments. From redis-cli documentation:

> When redis-cli parses a command, whitespace characters automatically delimit the arguments.

So, the correct command should be (note the single quotation marks)

/usr/bin/redis-cli '--user' 'admin' '--pass' 'mypass' '--cluster' 'create' '10.226.2.194:6379' '10.226.2.196:6379' '10.226.2.195:6379' '--cluster-replicas' '1' '--cluster-yes'

But for the Ansible task there is a problem - redis_cluster_members variable.

The solution suggested to me at GitHub:

- name: Create Redis cluster
  ansible.builtin.command:
    argv: "{{ redis_argv | flatten }}"
  vars:
    redis_argv:
      - /usr/bin/redis-cli
      - --user
      - "{{ redis_admin_user }}"
      - --pass
      - "{{ redis_admin_password }}"
      - --cluster
      - create
      - "{{ redis_cluster_members | split }}"
      - --cluster-replicas
      - "{{ redis_cluster_replicas }}"
      - --cluster-yes

It works, but I decided to use a workaround. In vars/main.yml I defined a variable

redis_create_cluster_command: >
  /usr/bin/redis-cli --user {{ redis_admin_user | quote }} --pass {{ redis_admin_password | quote }}
  --cluster create {{ redis_cluster_members }}
  --cluster-replicas {{ redis_cluster_replicas | quote }} --cluster-yes

For the explanation about > please read this article, particularly the second part.

The quote filter is for, as suggested in command module's documentation, "to avoid injection issues". Note that it's missing from redis_cluster_members line because it too breaks the arguments.

The task itself:

- name: Create Redis cluster
  ansible.builtin.command:
    cmd: "{{ redis_create_cluster_command }}"
    creates: "{{ redis_etc }}/redis_cluster.created"
  no_log: true
英文:

Got help from Ansible devs at GitHub. The reason for this behavior is how command module and redis-cli utility work with arguments.
argv adds delimiters when passing the command to the command line. So this:

    - name: Create Redis cluster
      ansible.builtin.command:
        argv:
          - /usr/bin/redis-cli
          - "--user {{ redis_admin_user }}"
          - "--pass {{ redis_admin_password }}"
          - "--cluster create {{ redis_cluster_members }}"
          - "--cluster-replicas {{ redis_cluster_replicas }}"
          - --cluster-yes

turns to (mind the single quotation marks)

/usr/bin/redis-cli '--user admin' '--pass mypass' '--cluster create 10.226.2.194:6379 10.226.2.196:6379 10.226.2.195:6379' '--cluster-replicas 1' '--cluster-yes'

If you enter the above command directly you'll get the same error when running the task - "Unrecognized option or bad number of args for: '--user admin'"

This is because how redis-cli delimits arguments. From redis-cli documentation:
> When redis-cli parses a command, whitespace characters automatically delimit the arguments.

So, the correct command should be (note the single quotation marks)

/usr/bin/redis-cli '--user' 'admin' '--pass' 'mypass' '--cluster' 'create' '10.226.2.194:6379' '10.226.2.196:6379' '10.226.2.195:6379' '--cluster-replicas' '1' '--cluster-yes'

But for the Ansible task there is a problem - redis_cluster_members variable.
The solution suggested to me at GitHub:

    - name: Create Redis cluster
      ansible.builtin.command:
        argv: "{{ redis_argv | flatten }}"
      vars:
        redis_argv:
          - /usr/bin/redis-cli
          - --user
          - "{{ redis_admin_user }}"
          - --pass
          - "{{ redis_admin_password }}"
          - --cluster
          - create
          - "{{ redis_cluster_members | split }}"
          - --cluster-replicas
          - "{{ redis_cluster_replicas }}"
          - --cluster-yes

It works, but I decided to use a workaround.
In vars/main.yml I defined a variable

redis_create_cluster_command: >
  /usr/bin/redis-cli --user {{ redis_admin_user | quote }} --pass {{ redis_admin_password | quote }}
  --cluster create {{ redis_cluster_members }}
  --cluster-replicas {{ redis_cluster_replicas | quote }} --cluster-yes

For the explanation about > please read this article, particularly the second part.
The quote filter is for, as suggested in command module's documentation, "to avoid injection issues". Note that it's missing from redis_cluster_members line because it too breaks the arguments.

The task itself:

        - name: Create Redis cluster
          ansible.builtin.command:
            cmd: "{{ redis_create_cluster_command }}"
            creates: "{{ redis_etc }}/redis_cluster.created"
          no_log: true

huangapple
  • 本文由 发表于 2023年2月9日 00:23:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75388765.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定