i have playbook, which have include. Also have var_prompt "name_VM" and i need transfer variable in include playbook "new-vm.yml", but i have error:
TASK [hostname]
**************************************************************** fatal: [192.168.250.102]: FAILED! => {"failed": true, "msg": "the
field 'args' has an invalid value, which appears to include a variable
that is undefined. The error was: {{ name_VM }}: 'name_VM' is
undefined\n\nThe error appears to have been in
'/etc/ansible/playbooks/tasks/new-vm.yml': line 7, column 7, but
may\nbe elsewhere in the file depending on the exact syntax
problem.\n\nThe offending line appears to be:\n\n pre_tasks:\n -
hostname:\n ^ here\n"}
How to transfer variables in pre_tasks include playbook?
Main playbook:
- hosts: localhost
gather_facts: false
connection: local
become: true
vars_files:
- ../roles/vm-create/vars/am-default.yml
vars_prompt:
- name: "name_VM"
prompt: "VM name:"
private: no
default: "vm001"
- name: "size_hard"
prompt: "Size hard disk (Gb)"
private: no
default: "16"
- name: "size_memory"
prompt: "Size memory (Mb)"
private: no
default: "2048"
- name: "count_CPU"
prompt: "Count CPU:"
private: no
default: "2"
roles:
- vm-create
tasks:
- include: tasks/check-ip.yml
- include: tasks/new-vm.yml
new-vm playbook:
- hosts: temp
vars:
ldap_server: ldap://ldap.example.com
agent_server: zabbix.aexample.com
pre_tasks:
- hostname:
name: "{{ name_vm }}"
roles:
- { role: zabbix-agent, tags: [ 'zabbix' ] }
- { role: ldap-client, tags: [ 'ldap' ] }
- { role: motd, tags: [ 'motd' ] }
tasks:
- telegram:
token: 'bot12345:XXXXXX'
chat_id: XXXXX
msg: "New VM {{ ansible_hostname }} ({{ ansible_all_ipv4_addresses }}) is created and has been configured."
tags:
- telegram
check_ip.yml in which i add host:
- vsphere_guest:
vcenter_hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
guest: "{{ name_VM }}"
vmware_guest_facts: yes
validate_certs: no
register: vsphere_facts
until: vsphere_facts.ansible_facts.hw_eth0.ipaddresses[0] | match("192.168.250.")
retries: 6
delay: 10
- name: Ensure virtual machine is in the dynamic inventory
add_host:
name: "{{ vsphere_facts.ansible_facts.hw_eth0.ipaddresses[0] }}"
ansible_user: root
ansible_ssh_pass: pass
groups: temp
In your case name_VM is play-bound and will not be visible from second play.
You need to assign a fact to temp host (I guess you use add_host somewhere inside vm-create role; so just add name_vm: "{{ name_VM }}" host fact there).
Then in second play you can access {{ name_vm }} host fact.
Update: example, based on question edit.
- name: Ensure virtual machine is in the dynamic inventory
add_host:
name: "{{ vsphere_facts.ansible_facts.hw_eth0.ipaddresses[0] }}"
name_vm: "{{ name_VM }}"
ansible_user: root
ansible_ssh_pass: pass
groups: temp
Related
I am setting up a vmware job in Ansible Tower to snapshot a list of VM's, ideally, this list should be generated by AWX/Tower from the vSphere dynamic inventory. Inventory is named "lab_vm" in AWX and use either the hostname or the UUID of the VM.
How do I pass this through in my playbook variables file?
---
vars:
vmware:
host: '{{ lookup("env", "VMWARE_HOST") }}'
username: '{{ lookup("env", "VMWARE_USER") }}'
password: '{{ lookup("env", "VMWARE_PASSWORD") }}'
vcenter_datacenter: "dc1"
vcenter_validate_certs: false
vm_name: "EVE-NG"
vm_template: "Win2019-Template"
vm_folder: "Network Labs"
my playbook
---
- name: vm snapshot
hosts: localhost
become: false
gather_facts: false
collections:
- community.vmware
pre_tasks:
- include_vars: vars.yml
tasks:
- name: create snapshot
vmware_guest_snapshot:
# hostname: "{{ host }}"
# username: "{{ user }}"
# password: "{{ password }}"
datacenter: "{{ vcenter_datacenter }}"
validate_certs: False
name: "{{ vm_name }}"
state: present
snapshot_name: "Ansible Managed Snapshot"
folder: "{{ vm_folder }}"
description: "This snapshot is created by Ansible Playbook"
You're going about it backward. Ansible loops through the inventory for you. Use that feature, and delegate the task to localhost:
---
- name: vm snapshot
hosts: all
become: false
gather_facts: false
collections:
- community.vmware
pre_tasks:
- include_vars: vars.yml
tasks:
- name: create snapshot
vmware_guest_snapshot:
datacenter: "{{ vcenter_datacenter }}"
validate_certs: False
name: "{{ inventory_hostname }}"
state: present
snapshot_name: "Ansible Managed Snapshot"
folder: "{{ vm_folder }}"
description: "This snapshot is created by Ansible Playbook"
delegate_to: localhost
I've not used this particular module before, but don't your want snapshot_name to be unique for each guest?
I'm trying to get server name as user input and if the server OS is RHEL7 it will proceed for further tasks. I'm trying with hostvars but it is not helping, kindly help me to find the OS version with when condition:
---
- name: Add hosts
hosts: localhost
vars:
- username: test
password: test
vars_prompt:
- name: server1
prompt: Server_1 IP or hostname
private: no
- name: server2
prompt: Server_2 IP or hostname
private: no
tasks:
- add_host:
name: "{{ server1 }}"
groups:
- cluster_nodes
- primary
- management
ansible_user: "{{ username }}"
ansible_password: "{{ password}}"
- add_host:
name: "{{ server2 }}"
groups:
- cluster_nodes
- secondary
ansible_user: "{{ username }}"
ansible_password: "{{ password}}"
- debug:
msg: "{{ hostvars['server1'].ansible_distribution_major_version }}"
When I execute the playbook, I'm getting below error:
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: \"hostvars['server1']\" is undefined\n\nThe error appears to be in '/var/lib/awx/projects/pacemaker_RHEL_7_ST/main_2.yml': line 33, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - debug:\n ^ here\n"}
You need to gather_facts on the newly added host before you consume the variable. As an example, this will do it with automatic facts gathering.
---
- name: Add hosts
hosts: localhost
vars:
- username: test
password: test
vars_prompt:
- name: server1
prompt: Server_1 IP or hostname
private: no
- name: server2
prompt: Server_2 IP or hostname
private: no
tasks:
- add_host:
name: "{{ server1 }}"
groups:
- cluster_nodes
- primary
- management
ansible_user: "{{ username }}"
ansible_password: "{{ password}}"
- add_host:
name: "{{ server2 }}"
groups:
- cluster_nodes
- secondary
ansible_user: "{{ username }}"
ansible_password: "{{ password}}"
- name: Gather facts for newly added targets
hosts: cluster_nodes
# gather_facts: true <= this is the default
- name: Do <whatever> targeting localhost again
hosts: localhost
gather_facts: false # already gathered in play1
tasks:
# Warning!! bad practice. Looping on a group usually
# shows you should have a play targeting that specific group
- debug:
msg: "OS version for {{ item }} is 7"
when: hostvars[item].ansible_distribution_major_version | int == 7
loop: "{{ groups['cluster_nodes'] }}"
If you don't want to rely on automatic gathering, you can manually play the setup module, e.g. for the second play:
- name: Gather facts for newly added targets
hosts: cluster_nodes
gather_facts: false
tasks:
- name: get facts from targets
setup:
I am having a play where i will collect available host names before running a task, i am using this for a purpose,
My play code:
--
- name: check reachable side A hosts
hosts: ????ha???
connection: local
gather_facts: no
roles:
- Juniper.junos
vars:
credentials:
host: "{{ loopback_v4 }}"
username: "test"
ssh_keyfile: "/id_rsa"
port: "{{ port }}"
timeout: 60
tasks:
- block:
- name: "Check netconf connectivity with switches"
juniper_junos_ping:
provider: "{{ credentials }}"
dest: "{{ loopback_v4 }}"
- name: Add devices with connectivity to the "reachable" group
group_by:
key: "reachable_other_pairs"
rescue:
- debug: msg="Cannot ping to {{inventory_hostname}}. Skipping OS Install"
When i print this using
- debug:
msg: "group: {{ groups['reachable_other_pairs'] }}"
i am getting below result
"this group : ['testha1', 'testha2', 'testha3']",
Now if again call the same play with different hosts grouping with the same key i am getting the new host names appending to the existing values, like below
- name: check reachable side B hosts
hosts: ????hb???
connection: local
gather_facts: no
roles:
- Juniper.junos
vars:
credentials:
host: "{{ loopback_v4 }}"
username: "test"
ssh_keyfile: "/id_rsa"
port: "{{ port }}"
timeout: 60
tasks:
- block:
- name: "Check netconf connectivity with switches"
juniper_junos_ping:
provider: "{{ credentials }}"
dest: "{{ loopback_v4 }}"
- name: Add devices with connectivity to the "reachable" group
group_by:
key: "reachable_other_pairs"
rescue:
- debug: msg="Cannot ping to {{inventory_hostname}}. Skipping OS Install"
if i print the reachable_other_pairs i am getting below results
"msg": " new group: ['testhb1', 'testhb2', 'testhb3', 'testha1', 'testha2', 'testha3']"
All i want is only first 3 entries ['testhb1', 'testhb2', 'testhb3']
Can some one let me know how to achieve this?
Add this as as task just before your block. It will refresh your inventory and clean up all groups that are not in there:
- meta: refresh_inventory
I need to add a host from the user's input. Now I'm trying to use the ansible in-memory inventory, add_host module and prompt to add the target host to execute the remaining tasks. This is the content of my playbook:
Deploy.yml
- name: Adding the host server
hosts: localhost
- vars_prompt:
- name: "Server IP"
prompt: "Server"
private: no
- name: "Username (default: Ubuntu)"
prompt: "User"
default: "Ubuntu"
private: no
- name: "Password"
prompt: "Passwd"
private: yes
encrypt: "sha512_crypt"
- name: "Identity file path"
prompt: "IdFile"
private: no
when: Passwd is undefined
tasks:
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_private_key_file: "{{ IdFile }}"
when: IdFile is defined
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_pass: "{{ Passwd }}"
when: Passwd is defined
- hosts: "{{ Server }}"
tasks:
- name: Copy the script file to the server
copy:
src: script.sh
dest: "{{ ansible_env.HOME }}/folder/"
mode: 755
force: yes
attr:
- +x
When I run this playbook with this command $ ansible-playbook Deploy.yml, The output is:
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Adding the host server] ***********************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************
ok: [localhost]
Server: <server-ip>
User [Ubuntu]:
Passwd:
IdFile: <path/to/id/file>
ERROR! the field 'hosts' is required but was not set
I don't know why it throws this error:
ERROR! the field 'hosts' is required but was not set
How can I do what I need to do?
UPDATE:
It still not working. This is the content of my playbook:
Deploy.yml
- name: Adding the host server
hosts: localhost
vars_prompt:
- name: "Server"
prompt: "Server IP"
private: no
- name: "User"
prompt: "Username"
default: "Ubuntu"
private: no
- name: "Passwd"
prompt: "Password"
private: yes
encrypt: "sha512_crypt"
- name: "IdFile"
prompt: "Identity file path"
private: no
when: Passwd is undefined
tasks:
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_private_key_file: "{{ IdFile }}"
when: IdFile is defined
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_pass: "{{ Passwd }}"
when: IdFile is undefined
- hosts: "{{ Server }}"
tasks:
- name: Copy the script file to the server
copy:
src: script.sh
dest: "{{ ansible_env.HOME }}/folder/"
mode: 755
force: yes
attr:
- +x
When I run this playbook with this command $ ansible-playbook Deploy.yml, The output is:
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Adding the host server] ***********************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************
ok: [localhost]
Server IP: <server-ip>
Username [Ubuntu]:
Password:
Identity file path: <path/to/id/file>
ERROR! the field 'hosts' is required but was not set
I don't know why it throws this error:
ERROR! The field 'hosts' has an invalid value, which includes an undefined variable. The error was: 'Server' is undefined
Here is a flowchart of how the playbook should works:
+------------------+ +---------------+ +-----------------+
|Use ansible to run| |Get host IP fom| |Get ssh User from|
| this playbook +---->+ user's input +---->+ user's input |
+------------------+ +---------------+ +--------+--------+
|
v
+------------+--------+
|Get ssh password from|
| user's input |
+------------+--------+
|
v
+---------------+ *************************
|Add a host with| Yes | Did the user inputted |
v----------+ password +<---+| a password? |
+----------------+ +---------------+ ***************+*********
||Run some tasks|| |No
||in recently || v
||added host || +---------------+ +------------+--------+
+----------------+ |Add a host with| |Get ssh identity file|
^----------+ identity file +<------+ from user's input |
+---------------+ +---------------------+
Ok I've updated my answer to suit the changes in your question, with the original answer left for historic reasons.
To solve the substitution error you are seeing, which results in an empty host list in your second play, I would instead use an inventory group.
There are also two other syntax errors in the second play
The file mode needs to be octal (i.e. 0700)
The attribute is invalid. My assumption is you are trying to make the file executable, so fix the file mode and remove the attribute.
Here is an updated playbook:
- name: Adding the host server
hosts: localhost
vars_prompt:
- name: "Server"
prompt: "Server IP"
private: no
- name: "User"
prompt: "Username"
default: "Ubuntu"
private: no
- name: "Passwd"
prompt: "Password"
private: yes
encrypt: "sha512_crypt"
- name: "IdFile"
prompt: "Identity file path"
private: no
when: Passwd is undefined
tasks:
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_private_key_file: "{{ IdFile }}"
group: added_hosts
when: IdFile is defined
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_pass: "{{ Passwd }}"
group: added_hosts
when: IdFile is undefined
- hosts: added_hosts
tasks:
- name: Copy the script file to the server
copy:
src: script.sh
dest: "{{ ansible_env.HOME }}/folder/"
mode: 0755
force: yes
=== OLD ANSWER ===
User input is stored in the whatever variable you are using for the name attribute in each of the variable prompts.
You need to switch around your name and prompt values under vars_prompt
There are also YAML formatting issues
For example:
- vars_prompt:
- name: "Server IP"
prompt: "Server"
private: no
should be:
vars_prompt:
- name: "server"
prompt: "Server IP"
private: no
Then you can refer to the {{ server }} variable in your tasks
Your ansible script is having a problem.
vars_prompt:
remove - from vars_prompt line it will work properly.
I tried in my local server the same script is working properly.
- name: Adding the host server
hosts: localhost
vars_prompt:
- name: "Server"
prompt: "Server IP"
private: no
- name: "User"
prompt: "Username"
default: "Ubuntu"
private: no
- name: "Passwd"
prompt: "Password"
private: yes
encrypt: "sha512_crypt"
- name: "IdFile"
prompt: "Identity file path"
private: no
when: Passwd is undefined
tasks:
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_private_key_file: "{{ IdFile }}"
when: IdFile is defined
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_pass: "{{ Passwd }}"
when: Passwd is defined
- name: Create a file
shell: touch newfile
delegate_to: "{{ Server }}"
In the last task update to your task and run it.
- name: Create a file
shell: touch newfile
delegate_to: "{{ Server }}"
I want to use in my imported playbook the varaibles which I have defined in the master playbook. Unfortunately I get the following error message:
fatal: [localhost]: FAILED! =>
{
"msg": "The task includes an option with an
undefined variable. The error was: 'vcenter_username' is undefined\n\nThe
error appears to have been in '/home/ansible/ansible/vcenter/vm-
provisioning/vcenter_vm_creation.yml': line 4, column 7, but may\nbe
elsewhere in the file depending on the exact syntax
problem.\n\nThe
offending line appears to be:\n\n tasks:\n
}
My Playbook looks like this:
---
- hosts: localhost
vars_prompt:
- name: prompt_vcenter_domain
prompt: "Enter the Vcenter Domain Name for example vcenter"
private: no
- name: prompt_vcenter_username
prompt: "Enter your Vcenter User Name"
private: no
- name: prompt_vcenter_password
prompt: "Enter your Vcenter user Password"
- name: prompt_environment_to_deploy
prompt: "Enter the right Environment, Type Produktiv or Test VM"
private: no
- name: prompt_template_to_deploy
prompt: "Enter the right Template, Template Ubuntu 18.04 LTS x64 or Template Ubuntu 18.04 LTS x64 SMALL"
private: no
- name: prompt_vm_hostname
prompt: "Enter the VM Hostname"
- import_playbook: vcenter_vm_creation.yml
vars:
vcenter_domain: "{{ prompt_vcenter_domain }}"
vcenter_username: "{{ prompt_vcenter_username }}"
vcenter_password: "{{ prompt_vcenter_password }}"
vm_hostname: "{{ prompt_vm_hostname }}"
template_to_deploy: "{{ prompt_template_to_deploy }}"
environment_to_deploy: "{{ prompt_environment_to_deploy }}"
and the child playbook looks like this:
---
- hosts: localhost
tasks:
- name: Clone the template
vmware_guest:
hostname: '{{ vcenter_domain }}.muc.lv1871.de'
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: False
name: "{{ vm_hostname }}"
template: "{{ template_to_deploy }}"
folder: /{{ environment_to_deploy }}/Linux
state: poweredon
wait_for_ip_address: no
Can anyone help how to get the variables in the child playbook?
You can use set_vact for this purpose. Variable that defined in set_fact will be available to subsequent plays during ansible-playbook execution.
Can be confirmed with following playbook:
- hosts: localhost
gather_facts: false
vars_prompt:
- name: prompt_vcenter_username
prompt: "Enter your Vcenter User Name"
tasks:
- name: Set vcenter_username variable with set_fact
set_fact:
vcenter_username: "{{ prompt_vcenter_username }}"
- hosts: localhost
gather_facts: false
tasks:
- name: Display vcenter_username
debug:
msg: "{{ vcenter_username }}"
Results:
Enter your Vcenter User Name:
PLAY [localhost] *******************************************************************************
TASK [Set vcenter_username variable with set_fact] *********************************************
ok: [localhost]
PLAY [localhost] *******************************************************************************
TASK [Display vcenter_username] ****************************************************************
ok: [localhost] => {
"msg": "test_user"
}
PLAY RECAP *************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
I am not sure you can pass vars into the import_playbook directive like that, hence you are seeing them as undefined. Moreover, unless you have a specific reason to, using import_playbook at all, is not really a common pattern.
You can simply place the 'Clone the template' task in the same play as the one containing the vars_prompt, or if you want to split it out into a separate file, use the include statement, making the included file part of the same play:
playbook.yml
---
- hosts: localhost
vars_prompt:
- name: vcenter_domain
prompt: "Enter the Vcenter Domain Name for example vcenter"
private: no
- name: vcenter_username
prompt: "Enter your Vcenter User Name"
private: no
- name: vcenter_password
prompt: "Enter your Vcenter user Password"
- name: environment_to_deploy
prompt: "Enter the right Environment, Type Produktiv or Test VM"
private: no
- name: template_to_deploy
prompt: "Enter the right Template, Template Ubuntu 18.04 LTS x64 or Template Ubuntu 18.04 LTS x64 SMALL"
private: no
- name: vm_hostname
prompt: "Enter the VM Hostname"
tasks:
- include: template_clone.yml
template_clone.yml
---
- name: Clone the template
vmware_guest:
hostname: '{{ vcenter_domain }}.muc.lv1871.de'
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: False
name: "{{ vm_hostname }}"
template: "{{ template_to_deploy }}"
folder: /{{ environment_to_deploy }}/Linux
state: poweredon
wait_for_ip_address: no