Related
I'm trying to deploy some virtual machines which seems to be working fine, and I can get the output to a debug screen, but what I would like is to be able to filter the output a bit and show hostname and IP address really. But I'm not sure how to loop the output! I've tried:
- debug:
msg: {{ item.instance.ipv4 }}
with_items: _result.results
Here is my playbook:
---
- name: Clone VMs
hosts: localhost
gather_facts: false
vars_files:
- vars.yml
- secrets.yml
tasks:
- name: Clone multiple VMs from template
local_action:
module: vmware_guest
hostname: "{{ vcenter_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: no
folder: "{{ folder }}"
template: "{{ item.template }}"
name: "{{ item.name }}"
esxi_hostname: "{{ esxi_hostname }}"
datacenter: "{{ datacenter }}"
state: "{{ state }}"
# customization_spec: "{{ customization_spec }}"
with_items: "{{ servers }}"
register: _result
- name: Output
debug:
msg: "{{ _result.results }}"
#with_items: _result.results.msg
In my vars I have the following (amongst other things)
servers:
- { name: centos8_01, template: centos8 }
- { name: centos7_01, template: centos7-minimal }
The output in the debug currently is:
ok: [localhost] => {
"msg": [
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"instance": {
"annotation": "",
"current_snapshot": null,
"customvalues": {},
"guest_consolidation_needed": false,
"guest_question": null,
"guest_tools_status": "guestToolsRunning",
"guest_tools_version": "10346",
"hw_cluster": "Cluster",
"hw_cores_per_socket": 1,
"hw_datastores": [
"SSD"
],
"hw_esxi_host": "******",
"hw_eth0": {
"addresstype": "assigned",
"ipaddresses": [],
"label": "Network adapter 1",
"macaddress": "00:50:56:a3:4b:ba",
"macaddress_dash": "00-50-56-a3-4b-ba",
"portgroup_key": null,
"portgroup_portkey": null,
"summary": "10.0.0.0"
},
"hw_files": [
"[SSD] centos8_01/centos8_01.vmx",
"[SSD] centos8_01/centos8_01.nvram",
"[SSD] centos8_01/centos8_01.vmsd",
"[SSD] centos8_01/centos8_01.vmdk"
],
"hw_folder": "/Learn/vm/L2L",
"hw_guest_full_name": "CentOS 8 (64-bit)",
"hw_guest_ha_state": null,
"hw_guest_id": "centos8_64Guest",
"hw_interfaces": [
"eth0"
],
"hw_is_template": false,
"hw_memtotal_mb": 4096,
"hw_name": "centos8_01",
"hw_power_status": "poweredOn",
"hw_processor_count": 2,
"hw_product_uuid": "4223465f-32ce-38ab-0d0e-a92f187b7d4d",
"hw_version": "vmx-14",
"instance_uuid": "5023b456-cda0-1fa6-c0a5-67d57ede5707",
"ipv4": null,
"ipv6": null,
"module_hw": true,
"moid": "vm-12173",
"snapshots": [],
"vimref": "vim.VirtualMachine:vm-12173",
"vnc": {}
},
"invocation": {
"module_args": {
"annotation": null,
"cdrom": [],
"cluster": null,
"convert": null,
"customization": {},
"customization_spec": null,
"customvalues": [],
"datacenter": "******",
"datastore": null,
"disk": [],
"esxi_hostname": "******",
"folder": "L2L",
"force": false,
"guest_id": null,
"hardware": {},
"hostname": "******",
"is_template": false,
"linked_clone": false,
"name": "centos8_01",
"name_match": "first",
"networks": [],
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"port": 443,
"proxy_host": null,
"proxy_port": null,
"resource_pool": null,
"snapshot_src": null,
"state": "poweredon",
"state_change_timeout": 0,
"template": "centos8",
"use_instance_uuid": false,
"username": "******#vsphere.local",
"uuid": null,
"validate_certs": false,
"vapp_properties": [],
"wait_for_customization": false,
"wait_for_ip_address": false
}
},
"item": {
"name": "centos8_01",
"template": "centos8"
}
},
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"instance": {
"annotation": "",
"current_snapshot": null,
"customvalues": {},
"guest_consolidation_needed": false,
"guest_question": null,
"guest_tools_status": "guestToolsRunning",
"guest_tools_version": "10309",
"hw_cluster": "Corby",
"hw_cores_per_socket": 1,
"hw_datastores": [
"SSD"
],
"hw_esxi_host": "******",
"hw_eth0": {
"addresstype": "assigned",
"ipaddresses": [
"10.0.0.137",
"fe80::e1b4:c7c5:8268:4e7b"
],
"label": "Network adapter 1",
"macaddress": "00:50:56:a3:f8:9f",
"macaddress_dash": "00-50-56-a3-f8-9f",
"portgroup_key": null,
"portgroup_portkey": null,
"summary": "VM Network"
},
"hw_files": [
"[SSD] centos7_01/centos7_01.vmx",
"[SSD] centos7_01/centos7_01.nvram",
"[SSD] centos7_01/centos7_01.vmsd",
"[SSD] centos7_01/centos7_01_2.vmdk"
],
"hw_folder": "/Learn/vm/L2L",
"hw_guest_full_name": "CentOS 6 (64-bit)",
"hw_guest_ha_state": null,
"hw_guest_id": "centos6_64Guest",
"hw_interfaces": [
"eth0"
],
"hw_is_template": false,
"hw_memtotal_mb": 2048,
"hw_name": "centos7_01",
"hw_power_status": "poweredOn",
"hw_processor_count": 1,
"hw_product_uuid": "4223d5ef-9363-03d4-8aea-7b1822b21e36",
"hw_version": "vmx-14",
"instance_uuid": "5023eea9-85ac-1c18-48bb-e0b63339c9fa",
"ipv4": "10.0.0.137",
"ipv6": null,
"module_hw": true,
"moid": "vm-12174",
"snapshots": [],
"vimref": "vim.VirtualMachine:vm-12174",
"vnc": {}
},
"invocation": {
"module_args": {
"annotation": null,
"cdrom": [],
"cluster": null,
"convert": null,
"customization": {},
"customization_spec": null,
"customvalues": [],
"datacenter": "******",
"datastore": null,
"disk": [],
"esxi_hostname": "******",
"folder": "******",
"force": false,
"guest_id": null,
"hardware": {},
"hostname": "******",
"is_template": false,
"linked_clone": false,
"name": "centos7_01",
"name_match": "first",
"networks": [],
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"port": 443,
"proxy_host": null,
"proxy_port": null,
"resource_pool": null,
"snapshot_src": null,
"state": "poweredon",
"state_change_timeout": 0,
"template": "centos7-minimal",
"use_instance_uuid": false,
"username": "******",
"uuid": null,
"validate_certs": false,
"vapp_properties": [],
"wait_for_customization": false,
"wait_for_ip_address": false
}
},
"item": {
"name": "centos7_01",
"template": "centos7-minimal"
}
}
]
}
There are multiple ways to do this.
A loop is one of them:
- debug:
msg:
hostname: "{{ item.invocation.module_args.hostname }}"
ip: "{{ item.instance.ipv4 }}"
loop: "{{ _result.results }}"
loop_control:
label: "item.invocation.module_args.hostname"
This would yield:
ok: [localhost] => (item=item.invocation.module_args.hostname) =>
msg:
hostname: '******'
ip: ''
ok: [localhost] => (item=item.invocation.module_args.hostname) =>
msg:
hostname: '******'
ip: 10.0.0.137
Another solution is to use JMESPath and the json_query filter:
- debug:
var: >-
_result.results
| json_query('[].{
hostname: invocation.module_args.hostname, ip: instance.ipv4
}')
This would yield:
ok: [localhost] =>
? |-
_result.results | json_query('[].{
hostname: invocation.module_args.hostname, ip: instance.ipv4
}')
: - hostname: '******'
ip: null
- hostname: '******'
ip: 10.0.0.137
I am trying to create k8s secrets with the storing username and secret in results module of ansible but i created one loop for the name and namespace section and i am trying to create one more loop from the json results output. but it was taking one secret for all the projects
variables:
project_namespaces:
- projectName: helm
Namespaces:
- default
- core
- projectName: proxy
Namespaces:
- default
- core
robot_result:
ok: [harbor_stg1_dkp1] => {
"robot_result": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"content_type": "application/json",
"cookies": {
"sid": "557b377ba2bbe3f054d68bd56b0e10ef"
},
"invocation": {
"module_args": {
"attributes": null,
"body": {
"description": "pull artifacts for helm",
"disable": true,
"duration": -1,
"level": "system",
"name": "helm-robot",
"permissions": [
{
"access": [
{
"action": "pull",
"resource": "repository"
}
],
"kind": "project",
"namespace": "helm"
}
]
},
"body_format": "json",
"headers": {
"Accept": "application/json",
"Authorization": "Basic ",
"Content-Type": "application/json"
},
"http_agent": "ansible-httpget",
"status_code": [
201
],
"timeout": 30,
"unix_socket": null,
"validate_certs": false
}
},
"item": {
"name": "helm-robot",
"projectName": "helm"
},
"json": {
"creation_time": "2022-03-21T10:05:49.248Z",
"expires_at": -1,
"id": 67,
"name": "robot#helm-robot",
"secret": "Q8mjthgRJFmscjfmqW1QzXEyKjmLEPQm"
},
"x_envoy_upstream_service_time": "18",
"x_request_id": "496faaa6-bdc4-4e83-890a-2c577576f16b"
},
{
"ansible_loop_var": "item",
"content_type": "application/json",
"cookies": {
"sid": "6275d7bfe74e71db0a3947f4beb1e159"
},
"cookies_string": "sid=6275d7bfe74e71db0a3947f4beb1e159",
"date": "Mon, 21 Mar 2022 10:05:56 GMT",
"elapsed": 1,
"failed": false,
"failed_when_result": false,
"invocation": {
"module_args": {
"attributes": null,
"body": {
"description": "pull artifacts for proxy",
"disable": true,
"duration": -1,
"level": "system",
"name": "proxy-robot",
"permissions": [
{
"access": [
{
"action": "pull",
"resource": "repository"
}
],
"kind": "project",
"namespace": "proxy"
}
]
},
"body_format": "json",
"group": null,
"headers": {
"Accept": "application/json",
"Authorization": "Basic ",
"Content-Type": "application/json"
},
"http_agent": "ansible-httpget",
"method": "POST"
],
"timeout": 30,
"unix_socket": null,
"validate_certs": false
}
},
"item": {
"name": "proxy-robot",
"projectName": "proxy"
},
"json": {
"creation_time": "2022-03-21T10:05:56.807Z",
"expires_at": -1,
"id": 68,
"name": "robot#proxy-robot",
"secret": "slPnm8Zkp0OGBLec6tTcPuPITgOU2PAn"
},
"msg": "OK (144 bytes)",
"x_envoy_upstream_service_time": "15",
"x_request_id": "93478b05-897b-4df9-abb4-e07e03723af0"
}
task.yaml
- name: Create secrets
k8s:
state: present
definition:
apiVersion: v1
kind: Secret
metadata:
name: "{{ item.0.projectName }}"
namespace: "{{ item.1 }}"
stringData:
password: "{{ project.secret }}"
username: "{{ project.name }}"
type: Opaque
vars:
project: "{{ (robot_result.results | json_query('[*].json'))[ansible_loop.index0] }}"
loop: "{{ project_namespaces | subelements('Namespaces') }}"
loop_control:
extended: yes
label: "{{ item.0.projectName }}"
when i executing this task i was getting the output like
ok: [localhost] => (item=helm) => {
"msg": "name: helm, namespace: default, password: Q8mjthgRJFmscjfmqW1QzXEyKjmLEPQm, username: robot#helm-robot"
}
ok: [localhost] => (item=helm) => {
"msg": "name: helm, namespace: core, password: slPnm8Zkp0OGBLec6tTcPuPITgOU2PAn, username: robot#proxy-robot"
}
fatal: [harbor_shiplab_stg1_dkp1]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: {{ (robot_result.results | json_query('[*].json'))[ansible_loop.index0] }}: list object has no element 2\n\nThe error appears to be in '/home/ubuntu/konvoy/ansible/roles/harbor-gc/tasks/main.yml': line 47, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Create secrets\n ^ here\n"}
but my requirement would be like this
ok: [localhost] => (item=helm) => {
"msg": "name: helm, namespace: default, password: Q8mjthgRJFmscjfmqW1QzXEyKjmLEPQm, username: robot#helm-robot"
}
ok: [localhost] => (item=helm) => {
"msg": "name: helm, namespace: core, password: Q8mjthgRJFmscjfmqW1QzXEyKjmLEPQm, username: robot#helm-robot"
}
ok: [localhost] => (item=proxy) => {
"msg": "name: proxy, namespace: default, password: slPnm8Zkp0OGBLec6tTcPuPITgOU2PAn, username: robot#proxy-robot"
}
ok: [localhost] => (item=proxy) => {
"msg": "name: proxy, namespace: core, password: slPnm8Zkp0OGBLec6tTcPuPITgOU2PAn, username: robot#proxy-robot"
}
As i am new to this ansible i was not much understanding this loops.Any help or suggestions would be appreciated and Thank you
You have to link secret with projectName:
- name: link projectname and json
set_fact:
dico: "{{ dico | d({}) | combine({item.projectName: project[ansible_loop.index0]}) }}"
vars:
project: "{{ (robot_result.results | json_query('[*].json')) }}"
it: "{{ (robot_result.results | json_query('[*].item')) }}"
loop: "{{ it }}"
loop_control:
extended: yes
- debug:
msg: "name: {{ item.0.projectName }}, namespace: {{ item.1 }}, password: {{ dico[item.0.projectName].secret }}, username: {{ dico[item.0.projectName].username }}" #{{ ansible_loop.index0 }}"
vars:
project: "{{ (robot_result.results | json_query('[*].json')) }}"
loop: "{{ project_namespaces | subelements('Namespaces') }}"
loop_control:
label: "{{ item.0.projectName }}"
result:
ok: [localhost] => (item=helm) => {
"msg": "name: helm, namespace: default, password: YzDDEtJcqYoBL2soZHfTqZxvhIfGKURT, username: robot#helm-robot"
}
ok: [localhost] => (item=helm) => {
"msg": "name: helm, namespace: core, password: YzDDEtJcqYoBL2soZHfTqZxvhIfGKURT, username: robot#helm-robot"
}
ok: [localhost] => (item=proxy) => {
"msg": "name: proxy, namespace: default, password: 7imXCVAGHV91AkeN7LAhWxQHabmYDRmg, username: robot#proxy-robot"
}
ok: [localhost] => (item=proxy) => {
"msg": "name: proxy, namespace: core, password: 7imXCVAGHV91AkeN7LAhWxQHabmYDRmg, username: robot#proxy-robot"
}
I need the string or destination path as the output and use it in other task but the output displayed is dfifferent.
Here is the register output
ok: [localhost] => {
"msg": {
"changed": true,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": true,
"checksum": "b045e5836bbd01d9c6dd2b7426afb5d1c8957b30",
"dest": "/home/ec2-user/bb/Data-1.1.tar.gz",
"failed": false,
"invocation": {
"module_args": {
"_original_basename": null,
"attributes": null,
"backup": false,
"checksum": null,
"content": null,
"delimiter": null,
"dest": "/home/ec2-user/bb/Data-1.1.tar.gz",
"directory_mode": null,
"follow": false,
"force": true,
"group": null,
"local_follow": null,
"mode": null,
"owner": null,
"regexp": null,
"remote_src": true,
"selevel": null,
"serole": null,
"setype": null,
"seuser": null,
"src": "/home/ec2-user/aa/Data-1.1.tar.gz",
"unsafe_writes": null,
"validate": null
}
},
"item": "/home/ec2-user/aa/Data-1.1.tar.gz",
"md5sum": "df9309334454cc3ceac9a6ac8fea8989",
"src": "/home/ec2-user/aa/Data-1.1.tar.gz"
I used the below the task to display the destination path
- set_fact:
filefact: "{{ output.results | map(attribute='item') | string }}"
- debug:
msg: "{{ filefact }}"
The output displayed is
ok: [localhost] => {
"msg": "<generator object do_map at 0x7f59539f01e0>"
i'd write :
- set_fact:
filefact: "{{ filefact | default([]) + [output.results.item] }}"
- debug:
msg: "{{ filefact }}"
the right syntax , following your output should be:
- set_fact:
filefact: "{{ filefact | default([]) + [output.results[0].item] }}"
or
- set_fact:
filefact: "{{ filefact | default([]) + [item.item] }}"
loop: "{{ output.results }}"
Im pulling a list of VLANs from our IPAM via an API and I want to be able to locate an unused "vlanId" that isnt in the list. I was expecting that I could use with_items for the JSON content and then use the random function with an until loop and occasionally it will initially generate a number that doesnt exist in the list. Mostly it just gets stuck and doesnt generate a new random number when the one generated already exists.
Playbook:
- uri:
url: "#"
validate_certs: no
headers:
token: "{{ token }}"
method: GET
force_basic_auth: yes
return_content: yes
register: ipam
- set_fact:
value: "{{ 4094 | random(start=1) }}"
until: value not in item.vlanId
with_items: "{{ ipam.json.data }}"
retries: 4093
- debug: msg="{{ value }}"
Relevant Output:
ok: [localhost] => (item={u'domainId': u'3', u'description': u'#', u'editDate': None, u'Customer ID': None, u'number': u'2241', u'vlanId': u'548', u'name': u'2241', u'Customer Name': None, u'custom_fields': None, u'Engineer': None}) => {
"ansible_facts": {
"value": "2727"
},
"ansible_facts_cacheable": false,
"attempts": 1,
"changed": false,
"item": {
"Customer ID": null,
"Customer Name": null,
"Engineer": null,
"custom_fields": null,
"description": "#",
"domainId": "3",
"editDate": null,
"name": "2241",
"number": "2241",
"vlanId": "548"
}
}
ok: [localhost] => (item={u'domainId': u'3', u'description': u'#', u'editDate': None, u'Customer ID': None, u'number': u'2242', u'vlanId': u'549', u'name': u'2242', u'Customer Name': None, u'custom_fields': None, u'Engineer': None}) => {
"ansible_facts": {
"value": "1955"
},
"ansible_facts_cacheable": false,
"attempts": 1,
"changed": false,
"item": {
"Customer ID": null,
"Customer Name": null,
"Engineer": null,
"custom_fields": null,
"description": "#",
"domainId": "3",
"editDate": null,
"name": "2242",
"number": "2242",
"vlanId": "549"
}
}
FAILED - RETRYING: set_fact (4000 retries left).Result was: {
"ansible_facts": {
"value": "50"
},
"ansible_facts_cacheable": false,
"attempts": 1,
"changed": false,
"retries": 4001
}
FAILED - RETRYING: set_fact (3999 retries left).Result was: {
"ansible_facts": {
"value": "50"
},
"ansible_facts_cacheable": false,
"attempts": 2,
"changed": false,
"retries": 4001
}
FAILED - RETRYING: set_fact (3998 retries left).Result was: {
"ansible_facts": {
"value": "50"
},
"ansible_facts_cacheable": false,
"attempts": 3,
"changed": false,
"retries": 4001
Im currently using ansible 2.4.2.0
If this is something that cant/shouldnt be done in Ansible, any guidance would be appreciated.
Here's what you want:
- debug:
msg: "{{ range(1, 4095) | difference(vlanIds) | random }}"
vars:
vlanIds: "{{ ipam.json.data | map(attribute='vlanId') | list }}"
Explanation:
map(attribute=... - create a list of vlan IDs,
range - generate a sequence from 1 to 4094,
difference - select all the elements from the above. that are not on the vlanIds list,
random - select a random element from the above.
For strings (as the title suggests) replace range with a list of possible strings.
I have a following hash/dict structure of sites:
sites:
example.com:
site: example.com
mail: info#example.com
site_alias: www.example.com
example.fi:
site: example.fi
mail: info#example.fi
site_alias: example.fi
...
I register a value for every site, if there is also a folder for it. Print the result.
name: "Check if path already exists so it is the first time."
stat: path={{ cert_files }}/{{ item.value.site }}
register: check_path
with_dict: "{{ sites }}"
debug: var=check_path.results
# No need to print the whole dictionary, all results are already there.
# with_dict: "{{ sites }}"
So I get something like:
TASK [letsencrypt : debug] *****************************************************
ok: [78.47.67.114] => (item={'key': u'example.com', 'value': {u'mail': u'mail#example.com', u'site_alias': u'www.example.com', u'site': u'example.com'}}) => {
"check_path.results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_checksum": true,
"get_md5": true,
"mime": false,
"path": "/etc/letsencrypt/live/example.com"
},
"module_name": "stat"
},
"item": {
"key": "example.com",
"value": {
"mail": "info#example.com",
"site": "example.com",
"site_alias": "www.example.com"
}
},
"stat": {
"atime": 147869032.3522692,
"ctime": 149636484.0226028,
"dev": 2049,
"executable": true,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 15725,
"isblk": false,
"ischr": false,
"isdir": true,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": false,
"issock": false,
"isuid": false,
"mode": "0755",
"mtime": 14632684.026028,
"nlink": 2,
"path": "/etc/letsencrypt/live/example.com",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": 4096,
"uid": 0,
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": true,
"xoth": true,
"xusr": true
}
},
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_checksum": true,
"get_md5": true,
"mime": false,
"path": "/etc/letsencrypt/live/example.com"
},
"module_name": "stat"
},
"item": {
"key": "example.fi",
"value": {
"mail": "info#example.fi",
"site": "example.fi",
"site_alias": "www.example.fi"
}
},
"stat": {
"atime": 1493734857.9738503,
"ctime": 1485960159.8090317,
"dev": 2049,
"executable": true,
"exists": true,
How can I the use or get the value "check_path.results.stats.exists" the last value in the next task if I want to iterate again through {{ sites }} ?
I have tried something like this with no success.
- name: Make a certificate the first time.
command: /bin/bash /opt/letsencrypt/letsencrypt-auto certonly -- standalone --email "{{ item.value.mail }}" --agree-tos --keep-until- expiring -d "{{ item.value.site }}" -d "{{ item.value.site_alias }}"
with_items: check_path
when: check_path.results.stat.exists == false
or
- name: Make a certificate the first time.
command: /bin/bash /opt/letsencrypt/letsencrypt-auto certonly standalone --email "{{ item.value.mail }}" --agree-tos --keep-until-expiring -d "{{ item.value.site }}" -d "{{ item.value.site_alias }}"
with_dict: "{{ sites }}"
when: check_path.results.stat.exists == false
You should iterate over result, not over original list:
- name: Make a certificate the first time.
command: /bin/bash /opt/letsencrypt/letsencrypt-auto certonly standalone --email "{{ item.item.value.mail }}" --agree-tos --keep-until-expiring -d "{{ item.item.value.site }}" -d "{{ item.item.value.site_alias }}"
with_items: "{{ check_path.results }}"
when: not item.stat.exists
here item.item is an item of the original list.