Ansible - 高级Shell命令执行格式

5

我有3个变量名称为IPOctet、ServerIPRange和epcrange。 如果我在终端中执行以下操作,它将完美地工作:

IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc)

如何在Ansible任务中实现类似的操作,例如:
---
- hosts: localhost
  gather_facts: False

  vars_prompt:
    - name: epcrange
      prompt: Enter the number of EPCs that you want to configure
      private: False
      default: "1"
    - name: serverrange
      prompt: Enter the number of Clients that you want to configure
      private: False
      default: "1"
    - name: ServerIPRange
      prompt: Enter the ServerIP range
      private: False
      default: '128'
    - name: LastIPOctet
      prompt: Enter The last Octet of the IP you just entered
      private: False
      default: '10'

  pre_tasks:


    - name: Set some facts
      set_fact:
        ServerIP1: "{{ServerIP}}"
        ServerIPRange1: "{{ServerIPRange}}"
        IPOctet: "{{LastIPOctet}}"

    - name: local action math
      local_action: shell {{IPOctet}}=$(echo "${{ServerIPRange}}/${{epcrange}}+${{IPOctet}}" | bc)  # Proper Syntax?
      with_sequence: start=1 end=4
      register: result
      ignore_errors: yes

这个命令的正确语法是什么?也许可以使用shell echo "......."。我只需要将此命令的内容保存到IPOctet变量中,IPOctet将在每个循环迭代中更改,结果应该存储在我的结果寄存器中。
附注:如何单独访问数组中的各个项?
编辑:是否有类似这样的东西?目前它只会计算一次,并将其4次存储在寄存器中...
- name: bashless math
  set_fact:
    IPOctet: "{{ (ServerIPRange|int/epcrange|int)+IPOctet|int }}"
  register: IPOctet
  with_sequence: "start=1 end={{stop}} "
  register: my_ip_octet
2个回答

3
  1. Your terminal expression reassigns the IPOctet shell variable, so it gives a different result each time it is executed. This is fine, but difficult to reproduce in Ansible:

    $ IPOctet=10 ServerIPRange=128 epcrange=1
    $ IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc); echo $IPOctet
    138
    
    $ IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc); echo $IPOctet
    266
    
  2. The syntax: "shell {{IPOctet}}=$(echo ..." does NOT assign to the Ansible variable. The shell attempts to execute a command like "10=138", which is not found.

  3. When register is used within a loop, the target variable is not set until the loop completes - so your expression always sees the original value for {{IPOctet}}.

  4. A solution is to run the whole loop as a single shell command:

    - name: local action math2
      local_action: shell IPOctet={{IPOctet}}; for i in 1 2 3 4; do IPOctet=$(expr {{ServerIPRange}} / {{epcrange}} + $IPOctet); echo $IPOctet; done
      register: result
    

    NOTE: I've used the expr command rather than bc, but the results are the same.

  5. You can iterate over these results using result.stdout_lines:

    - name: iterate results
      local_action: debug msg={{item}}
      with_items: result.stdout_lines
    

非常感谢。还有一件事,这个循环是硬编码的,我能不能做像这样的事情:for (int i=0, i<IPOctet, i+=pow(2,x)) - Khan
我可以像这样使用循环吗 for i in range(0,{{IPOctet}},{{ 2{{x}} }})**,其中x是在vars_prompt中定义的变量。 - Khan
是的,您可以使用bash算术for循环(注意双括号): for ((i=0; i<128; i+=2**4)); do echo $i; done - Derek Baum

2

首先,你的Jinja模板有误,每个变量都需要用一对花括号括起来。你不能在单个花括号中使用多个变量。例如,

{{ ServerIPRange }}

其次,set_fact仅用于设置事实值。您不能使用set_fact运行shell命令。您应该使用shell模块。

- name: local action math
  local_action: shell {{ IPOctet }}=$(echo {{ ServerIPRange|int }}/{{ epcrange|int }}+{{ IPOctet|int }}" | bc)
  with_sequence: start=1 end=4
  register: result
  ignore_errors: yes

Ansible会进行4次计算,并将结果存储在一个列表中,作为四个不同的元素。您可以检查此列表中存储的所有内容,甚至可以通过循环访问它。

- debug: msg={{ result }}

希望这能帮到你 :)

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