ansible task doesn't resolve variable - ansible

I'm trying to get VG_Name using below code. I can see variable value using debug:var but it doesn't work inside actual task & print value as "vg": "hostvars[inventory_hostname].ansible_lvm.lvs.varlog.vg"
tasks:
- set_fact:
LV_name: "opt"
- name: Get VG Name
set_fact:
vg_command: "{{ 'hostvars[inventory_hostname].ansible_lvm.lvs.'+ LV_name +'.vg' }}"
- name: Show VG
debug:
var: "{{ vg_command }}"
- name: extend logical volume and file system
community.general.lvol:
vg: "{{ vg_command }}"
lv: "{{ LV_name }}"
size: +100%FREE
resizefs: yes
Output:
TASK [Get VG Name] *********************************************************************************************************************************************************************************
task path: /root/ansible_disk/disk_extend.yml:92
ok: [SERVER-NAME] => {
"ansible_facts": {
"vg_command": "hostvars[inventory_hostname].ansible_lvm.lvs.varlog.vg"
},
"changed": false
}
TASK [Show VG] *************************************************************************************************************************************************************************************
task path: /root/ansible_disk/disk_extend.yml:96
ok: [SERVER-NAME] => {
"hostvars[inventory_hostname].ansible_lvm.lvs.varlog.vg": "vg_00"
}
TASK [extend logical volume and file system] *******************************************************************************************************************************************************
task path: /root/ansible_disk/disk_extend.yml:109
fatal: [SERVER-NAME]: FAILED! => {
"changed": false,
"err": " Volume group name \"hostvars[inventory_hostname].ansible_lvm.lvs.varlog.vg\" has invalid characters.\n Cannot process volume group hostvars[inventory_hostname].ansible_lvm.lvs.varlog.vg\n",
"invocation": {
"module_args": {
"active": true,
"force": false,
"lv": "varlog",
"opts": null,
"pvs": null,
"resizefs": true,
"shrink": true,
"size": "+100%FREE",
"snapshot": null,
"state": "present",
"thinpool": null,
"vg": "hostvars[inventory_hostname].ansible_lvm.lvs.varlog.vg"
}
},
"msg": "Volume group hostvars[inventory_hostname].ansible_lvm.lvs.varlog.vg does not exist.",
"rc": 5
}
Tried all possible ways(lookup, vars etc) that I could think of but no luck, any help would be appreciated!

You are building your string incoorectly, leaving inventory[hostname] inside the single quotes, it will be treated as a literal; so:
vg_command: "{{ 'hostvars[inventory_hostname].ansible_lvm.lvs.'+ LV_name +'.vg' }}"
should instead be:
vg_command: "{{ hostvars[inventory_hostname].ansible_lvm.lvs[LV_name].vg }}"

Related

Output of Ansibble task

I am using command hcloud to create cloud server in Hetzner. I get an output like this:
changed: [localhost] => (item={'name': 'TEST-VARIABLES', 'server_type': 'cx11', 'os_image': 'ubuntu-20.04', 'server_labels': 'Name=test-server', 'server_location': 'hel1'}) => {
"ansible_loop_var": "item",
"changed": true,
"hcloud_server": {
"backup_window": "None",
"datacenter": "hel1-dc2",
"delete_protection": false,
"id": "19461514",
"image": "ubuntu-20.04",
"ipv4_address": "11.111.111.111",
"ipv6": "1a71:7f9:c011:0b09::/64",
"labels": {
"Name": "test-server"
},
"location": "hel1",
"name": "TEST-VARIABLES",
"placement_group": null,
"rebuild_protection": false,
"rescue_enabled": false,
"server_type": "cx11",
"status": "running"
},
"invocation": {
"module_args": {
"allow_deprecated_image": false,
"api_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"backups": null,
"datacenter": null,
"delete_protection": null,
"endpoint": "https://api.SERVER.cloud/v1",
"firewalls": null,
"force": false,
"force_upgrade": false,
"id": null,
"image": "ubuntu-20.04",
"labels": {
"Name": "test-server"
},
"location": "hel1",
"name": "TEST-VARIABLES",
"placement_group": null,
"rebuild_protection": null,
"rescue_mode": null,
"server_type": "cx11",
"ssh_keys": null,
"state": "present",
"upgrade_disk": false,
"user_data": null,
"volumes": null
}
},
"item": {
"name": "TEST-VARIABLES",
"os_image": "ubuntu-20.04",
"server_labels": "Name=test-server",
"server_location": "hel1",
"server_type": "cx11"
},
"root_password": "DFLDJFLDFDLFKJDLFKJ"
}
I try to get line with "ipv4_address": "11.111.111.111", and "root_password": "DFLDJFLDFDLFKJDLFKJ", but when I use task:
---
- name: Create a basic server
hcloud_server:
api_token: "{{ token }}"
name: "{{ item.name }}"
server_type: "{{ item.server_type }}"
image: "{{ item.os_image }}"
labels: "{{ item.server_labels }}"
location: "{{ item.server_location }}"
state: present
register: server_info
with_items: "{{ server }}"
- name: Here IP
debug:
var: server_info.root_password
I got error:
TASK [/etc/ansible/roles/CREATE-server : Here IP.] *********************************************************************************************************
ok: [localhost] => {
"server_info.root_password": "VARIABLE IS NOT DEFINED!"
}
Could you please help, how I can get IP line and password line, to use them in the next task (for example to send via email). Thank you!
you register the content of loop, so your result is a list (results):
- name: display
debug:
msg: "ip: {{ item.hcloud_server.ipv4_address }} has password: {{ item.root_password }}"
loop: "{{ server_info.results }}"
result: here you have just one server declared, so just one item in the list results
"msg": "ip: 11.111.111.111 has password: DFDFDFDFDFDFDFDF"
if you want to limit the output of record, you could add loop_control parameter to loop with argument label:
loop: "{{ server_info.results }}"
loop_control:
label: "{{ item.hcloud_server.ipv4_address }}"
you could put another comment if you want with label or even empty string:
loop: "{{ server_info.results }}"
loop_control:
label: "result"

add_host - add all host

I made a playbook that devid the hosts to windows and linux groups. this is the script (for now its just Linux and print the items that in the group):
---
- name: firstPlaybook
hosts: all
gather_facts: true
tasks:
- name: Linux Group
add_host:
name: "{{ item }}"
group: LinuxGroup
when: hostvars[item].ansible_system == 'Linux'
with_items: "{{ ansible_play_hosts }} "
run_once: yes
- name: dubug
debug:
msg: "{{ item }}"
with_items: LinuxGroup
and when I run the script with -vvv this is what I saw in the tasks itself:
TASK [Linux Group] *************************************************************
task path: /home/opc/playbooks/playbook.yml:7
skipping: [windowsserver] => (item=windowsserver) => {
"ansible_loop_var": "item",
"changed": false,
"item": "windowsserver",
"skip_reason": "Conditional result was False"
}
creating host via 'add_host': hostname=linuxserver
changed: [windowsserver] => (item=linuxserver) => {
"add_host": {
"groups": [
"LinuxGroup"
],
"host_name": "linuxserver",
"host_vars": {
"group": "LinuxGroup"
}
},
"ansible_loop_var": "item",
"changed": true,
"item": "linuxserver"
}
Perform task: TASK: dubug (N)o/(y)es/(c)ontinue: y
Perform task: TASK: dubug (N)o/(y)es/(c)ontinue: *******************************
TASK [dubug] *******************************************************************
task path: /home/opc/playbooks/playbook.yml:15
ok: [windowsserver] => (item=LinuxGroup) => {
"msg": "LinuxGroup"
}
ok: [linuxserver] => (item=LinuxGroup) => {
"msg": "LinuxGroup"
}
why its adding the windows server the the linux group even thought it suppose to be skipped (I changed the ips to windowsserver and linuxserver that I wont publish them)?
All is working as expected. Take a look at
- debug:
msg: "{{ groups.LinuxGroup }}"

Cant get the private ip from an EC2 result

Trying to create a playbook that will let me choose if i want spot or On-demand EC2 with passing external var, all going fine except the part of getting the private ip from the result and settings it as fact for further usage.
i've tried different paths like item.instances[0].private_ip
and just cant seems to get the right one.
---
- hosts: localhost
tasks:
- name: when true
ec2:
region: us-east-1
instance_type: t2.nano
key_name: test_key
instance_type: t2.micro
image: ami-0aec0138b2*****
wait: yes
count: 1
vpc_subnet_id: subnet-00fdda1452d****
assign_public_ip: no
spot_price: 1
register: ci_ec2_true
when: var == "true"
- name: when false
ec2:
region: us-east-1
instance_type: t2.nano
key_name: test_key
instance_type: t2.micro
image: ami-0aec0138b2****
wait: yes
count: 1
vpc_subnet_id: subnet-00fdda1452d0****
assign_public_ip: no
register: ci_ec2_false
when: var == "false"
- name: ci_ec2_true
debug:
msg: "{{ ci_ec2_true }}"
- name: Spot / On-demand var router
set_fact:
ci_ec2: "{{ ci_ec2_true if ci_ec2_false is skipped else ci_ec2_false }}"
- name: debug ci_ec2
debug:
msg: "{{ ci_ec2 }}"
- name: ec2_prov - set fact for all ci_machine_ips
set_fact: private_ips="{{ item.instances[0].private_ip }}"
with_items: "{{ ci_ec2 }}"
register: ci_ec2_ip_results
- debug:
msg: "{{ ci_ec2_ip_results }}"
The expected result should be the private ip value, instead im getting this error:
TASK [ec2_prov - set fact for all ci_machine_ips] ******************************
**********
fatal: [localhost]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'ansible.vars.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'instances'\n\nThe error appears to have been in '/root/test/when-create.yml': line 50, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: ec2_prov - set fact for all ci_machine_ips\n ^ here\n"}
the command used to run the playbook is:
ansible-playbook when-create.yml -e var=true
TASK [debug ci_ec2] ************************************************************
ok: [localhost] => {
"msg": {
"changed": true,
"instance_ids": [
"i-0485794cd8a299b27"
],
"instances": [
{
"ami_launch_index": "0",
"architecture": "x86_64",
"block_device_mapping": {
"/dev/xvda": {
"delete_on_termination": true,
"status": "attached",
"volume_id": "vol-0cd42f8696aef9bbd"
}
},
"dns_name": "",
"ebs_optimized": false,
"groups": {
"sg-07c7177c": "default"
},
"hypervisor": "xen",
"id": "i-0485794cd8a299b27",
"image_id": "ami-0aec0138b2a5****",
"instance_type": "t2.micro",
"kernel": null,
"key_name": "test_Key",
"launch_time": "2019-05-11T16:41:10.000Z",
"placement": "us-east-1a",
"private_dns_name": "ip-10-220-129-224.ec2.internal",
"private_ip": "10.220.129.224",
"public_dns_name": "",
"public_ip": null,
"ramdisk": null,
"region": "us-east-1",
"root_device_name": "/dev/xvda",
"root_device_type": "ebs",
"state": "running",
"state_code": 16,
"tags": {
"Created_By": "InstanceLaunch"
},
"tenancy": "default",
"virtualization_type": "hvm"
}
],
"tagged_instances": []
}
}
so eventually i found the way...
- name: ec2_prov - set fact for all ci_machine_ips
set_fact: private_ips="{{ item.private_ip }}"
with_items: "{{ ci_ec2.instances }}"
register: ci_ec2_ip_results

Ansible Dynamic Variables in Playbook

I'm provisioning a bunch of systems (VMs) on a physical host. I'm up to the step where the VM's are running. Now I need to ssh into the VM's via their DHCP addresses. I can pull the IP addresses from the server but I need a way to set these to host_vars. Here are my groups:
ok: [kvm01] => {
"msg": {
"all": [
"kvm01",
"dcos-master-1",
"dcos-agent-1",
"dcos-agent-2",
"dcos_bootstrap"
],
"dcos": [
"dcos-master-1",
"dcos-agent-1",
"dcos-agent-2",
"dcos_bootstrap"
],
"dcos-agents": [
"dcos-agent-1",
"dcos-agent-2"
],
"dcos-bootstraps": [
"dcos_bootstrap"
],
"dcos-masters": [
"dcos-master-1"
],
"kvm": [
"kvm01"
],
"ungrouped": []
}
}
Here's my command:
- name: Get the IP of the VM (DHCP)
command: "/getip.sh {{ item }}"
register: "result"
with_items: "{{ groups['dcos'] }}"
- name: List the output of the variables
debug: msg="{{item.stdout}}"
with_items: "{{result.results}}"
When I run the playbook I get results but they are the FULL JSON result of the command rather than the stdout. There's probably a way to pull out the stdout and assign it to a fact but it's a complex hash. Here's the last result:
TASK [vm_install : Get the IP of the VM (DHCP)] ***************************************************************************
changed: [kvm01] => (item=dcos-master-1)
changed: [kvm01] => (item=dcos-agent-1)
changed: [kvm01] => (item=dcos-agent-2)
changed: [kvm01] => (item=dcos_bootstrap)
TASK [vm_install : List the output of the variables] **********************************************************************
......
ok: [kvm01] => (item={'_ansible_parsed': True, 'stderr_lines': [u'] => {
"item": {
"changed": false,
"cmd": [
"/getip.sh",
"dcos_bootstrap"
],
"delta": "0:00:00.056193",
"end": "2017-09-18 15:45:45.409693",
"invocation": {
"module_args": {
"_raw_params": "/getip.sh dcos_bootstrap",
"_uses_shell": false,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
}
},
"item": "dcos_bootstrap",
"rc": 0,
"start": "2017-09-18 15:45:45.353500",
"stderr": " ",
"stdout": "192.168.1.130",
"stdout_lines": [
"192.168.1.130"
]
},
"msg": "192.168.1.130"
}
How can I put the output of the command into an array so that I can use it later in my playbook?
So, like I said in my comment, you've already managed to extract the information you want into an array. You can iterate over those items using with_items as in the follow task that will create an ip_address for each host:
- set_fact:
ip_address: "{{ item.stdout }}"
with_items: "{{ results.results }}"
delegate_to: "{{ item.item }}"
delegate_facts: true
Or you can create a single array containing all of the addresses using Jinja filters:
- set_fact:
all_ip_addresses: "{{ results.results|map(attribute='stdout')|list }}"
Or you could create a dictionary with the same information:
- set_fact:
all_ip_addresses: >
{{ all_ip_addresses
|default({})
|combine({ item.item: item.stdout })}}
with_items: "{{ results.results }}"

Ansible shows error: "One or more undefined variables: 'item' is undefined" when using 'with_items'

I am trying to count the instances inside an elb. This is my Ansible playbook:
- name: Get elb facts
local_action:
module: ec2_elb_facts
name: "{{elb}}"
region: "{{ansible_ec2_placement_region}}"
environment: creds
register: elb_facts
- debug:
var: elb_facts
verbosity: 2
- debug:
msg: "Instance: {{ item.instances }}"
with_items: "{{ elb_facts.elbs }}"
and my output (sensitive data removed):
TASK: [debug ] ****************************************************************
ok: [10.0.0.0] => {
"elb_facts": {
"changed": false,
"elbs": [
{
"availability_zones": [
"ap-southeast-2b",
"ap-southeast-2a"
],
"dns_name": "elbname123.ap-southeast-2.elb.amazonaws.com",
"health_check": {
"healthy_threshold": 2,
"interval": 10,
"target": "TCP:0000",
"timeout": 5,
"unhealthy_threshold": 2
},
"instances": [
{
"id": "i-000000000000000",
"state": null
}
],
"name": "accessgateway",
"scheme": "internal",
"security_groups": [
"sg-00000000"
],
"subnet": [
"subnet-0000000",
"subnet-1111111"
],
"vpc_id": "vpc-000000"
}
],
"invocation": {
"module_args": "",
"module_name": "ec2_elb_facts"
}
}
}
TASK: [debug ] ****************************************************************
fatal: [10.0.0.0] => One or more undefined variables: 'item' is undefined
FATAL: all hosts have already failed -- aborting
So what im trying to do is just loop through and print everything inside the elb_facts, instances variable. From what I can tell it's a hash, containing a list of hashes.
I am using http://docs.ansible.com/ansible/playbooks_loops.html#looping-over-subelements as a reference. I cannot for the life of mine figure out why this is not working.
with_items (and the whole family of with_ loops) is a dictionary key defined in a task, not as a parameter to the action.
Fix the indentation:
- debug:
msg: "Instance: {{ item.instances }}"
with_items: "{{ elb_facts.elbs }}"

Resources