Ansible : iterate over inventory groups

你说的曾经没有我的故事 提交于 2019-12-12 19:17:05

问题


I have group tgt-cluster includes 3 hosts. I have written down role to deploy container which is executing on tgt-cluster group. I am controlling the number of containers to deploy with with_sequence. My tasks looks like this.

- name: Deploy Container 
  docker_container:
    name: "C{{ item }}"
    image: "{{ image_name }}:{{ image_tag }}"
    recreate: yes
    detach: yes
    tty: yes
    interactive: yes
  with_sequence: count="{{ number_of_container_to_deploy }}"  

If I want to deploy one container, currently playbook is executing on all 3 hosts in tgt-cluster group and I end up with 3 containers. So How should I created nested loop in this case to control the task execution on hosts on round robin fashion.

Say if we want to deploy 4 container.. 1st container should be deployed on 1st host in group, 2nd container should be deployed on 2nd container in group, 3rd should be deployed on 3rd hosts in group and 4th container should be deployed back to the 1st host in group.

I have updated my variable file with following, and count_per_hosts variable is assigned to with_sequence. While executing I was getting error stating "can't parse arg count=u'' as integer". So I updated with_sequence: count="{{ count_per_hosts | int }}" and it's not throwing error but It is not executing tasking not skipping it.

the_hosts: "{{ groups['tgt-cluster']}}" 
num_hosts: "{{ the_hosts | length }}" 
count_per_hosts: > 
  "{% for x in range(number_of_container_to_deploy) %} 
    - set idx = x % num_hosts 
      set cc = assignment.get(the_hosts[idx], 0) 
      set _ = assignment.update({the_hosts[idx]: cc + 1}) 
  {% endfor %}"

Currently my execution looks like this. deploy_container : Deploy Process tasks should create container but we don't see any logs over there. Also, I tried to move the_hosts and num_hosts inside count_per_hosts same syntax as indicated in answers but execution does not spill any output.

PLAY [bin installation] **************************************************************************************************************************************************************************************
META: ran handlers

TASK [deploy_container : Deploy Process] *************************************************************************************************************************************************************
task path: /home/tg/Documents/playbooks/roles/deploy_container/tasks/main.yml:3
META: ran handlers
META: ran handlers

PLAY RECAP *****************************************************************************************************************************************************************************************************
br1.lab            : ok=0    changed=0    unreachable=0    failed=0
br2.lab            : ok=0    changed=0    unreachable=0    failed=0
br3.lab            : ok=0    changed=0    unreachable=0    failed=0

Also, I tried default(0) but ansible is throwing error. { "msg": "can't parse arg count=u\"#' # ' idx = x % num_hosts\\ncc = assignment.get(the_hosts[idx], 0)\\n_ = assignment.update({the_hosts[idx]: cc + 1})\\nidx = x % num_hosts\\ncc = assignment.get(the_hosts[idx], 0)\\n_ = assignment.update({the_hosts[idx]: cc + 1})\\n'\\n\" as integer" }

Current playbook looks like this,

- name: bin installation
  hosts: tgt-cluster
  user: "{{ user }}"
  gather_facts: no
  become: yes
  vars:
    count_per_hosts: |
      {% set the_hosts = groups["tgt-cluster"] %}
      {% set num_hosts = the_hosts | length %}
      {% set result = {} %}
      {% for x in range(number_of_process_to_deploy) %}
      {%   set idx = x % num_hosts %}
      {%   set h   = the_hosts[idx] %}
      {%   set cc  = result.get(h, 0) %}
      {%   set  _  = result.update({h: cc + 1}) %}
      {% endfor %}
      {{ result }}
  roles:
    - deploy_container

output with with_sequence: count="{{ count_per_hosts }}" if we specify with_sequence: count="{{ count_per_hostsget(ansible_hostname, 0) }}" we get fatal: [br1.lab]: FAILED! => {"msg": "'ansible_hostname' is undefined"}

TASK [deploy_container : Deploy Process] ***************************************************************************
fatal: [br1.lab]: FAILED! => {"msg": "can't parse arg count=u\"{u'br1.lab': 1, u'br2.lab': 1}\" as integer"}
fatal: [br2.lab]: FAILED! => {"msg": "can't parse arg count=u\"{u'br1.lab': 1, u'br2.lab': 1}\" as integer"}
fatal: [br3.lab]: FAILED! => {"msg": "can't parse arg count=u\"{u'br1.lab': 1, u'br2.lab': 1}\" as integer"}

I tried to register the output and check and ran debug on that to see the content and found it's not able to pick the host from group.

ok: [br1.lab] => { "my_content": { "changed": false, "results": [], "skipped": true, "skipped_reason": "No items in the list" } }


回答1:


You will be much happier just doing the count assignment by yourself:

vars:
  the_hosts: "{{ groups['tgt-cluster']}}" 
  num_hosts: "{{ the_hosts | length }}" 
  count_per_hosts: |
    {% set result = {} %}
    {% for x in range(number_of_container_to_deploy) %}
    {%   set idx = x % num_hosts %}
    {%   set h   = the_hosts[idx] %}
    {%   set cc  = result.get(h, 0) %}
    {%   set  _  = result.update({h: cc + 1}) %}
    {% endfor %}
    {{ result }}

Then in the actual docker_container: task, you are now able to have the with_sequence: be a count per host, and some of them may be zero:

- name: Deploy Container 
  docker_container:
    name: "C{{ item }}"
    image: "{{ image_name }}:{{ image_tag }}"
    recreate: yes
    detach: yes
    tty: yes
    interactive: yes
  with_sequence:
    count: "{{ count_per_hosts.get(ansible_hostname, 0) }}"


来源:https://stackoverflow.com/questions/53683136/ansible-iterate-over-inventory-groups

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!