I am struggling with the with_dict module - ansible

I am trying to automate VMware builds using Ansible. I am expecting a workflow engine to output a file that would act as a var_file and have all of the objects that can be used to build the VM using the vmware_guest module. It works great until you get to the networks dictionary portion of the module then it falls apart.
I initially tried setting up a vars_file with all of the variables like this:
---
validate_certs: no
datacenter: this is the DC
cluster: this is the cluster
folder: "this is the folder"
name: some-server
template: template-name
datastore: "datastore-name"
netname: This is the network
ip: 10.6.6.10
netmask: 255.255.255.0
gateway: 10.6.6.1
mac: aa:bb:dd:aa:00:14
domain: domain.com
However, that returned:
argument networks is of type <type 'dict'> and we were unable to convert to list: <type 'dict'> cannot be converted to a list"}
Where the code fails is on this task:
- name: Clone a virtual machine from Windows template and customize
vmware_guest:
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: "{{ validate_certs }}"
datacenter: "{{ datacenter }}"
cluster: "{{ cluster }}"
folder: "{{ folder }}"
name: "{{name }}"
template: "{{ template }}"
datastore: "{{ datastore}}"
networks:
name: "{{ netname }}"
ip: "{{ ip }}"
netmask: "{{ netmask }}"
gateway: "{{ gateway }}"
mac: "{{ mac }}"
domain: "{{ domain }}"```
I tried creating a dictionary in the variable file like this:
---
validate_certs: no
datacenter: this is the DC
cluster: this is the cluster
folder: "this is the folder"
name: some-server
template: template-name
datastore: "datastore-name"
bnetworks:
name: This is the network
ip: 10.6.6.10
netmask: 255.255.255.0
gateway: 10.6.6.1
mac: aa:bb:dd:aa:00:14
domain: americas.global-legal.com
And changed the task to include this:
networks:
name: "{{ item.value.name }}"
ip: "{{ item.value.ip }}"
netmask: "{{ item.value.netmask }}"
gateway: "{{ item.value.gateway }}"
mac: "{{ item.value.mac }}"
domain: "{{ item.value.domain }}"
with_dict: bnetworks```
And I get this error:
The task includes an option with an undefined variable. The error was: 'item' is undefined
Any help would be appreciated.

argument networks is of type <type 'dict'> and we were unable to convert to list: cannot be converted to a list"}
There might be more networks in one VM therefor a list is needed. The corect syntax is below
- name: Clone a virtual machine from Windows template and customize
vmware_guest:
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: "{{ validate_certs }}"
datacenter: "{{ datacenter }}"
cluster: "{{ cluster }}"
folder: "{{ folder }}"
name: "{{name }}"
template: "{{ template }}"
datastore: "{{ datastore}}"
networks:
- name: "{{ netname }}"
ip: "{{ ip }}"
netmask: "{{ netmask }}"
gateway: "{{ gateway }}"
mac: "{{ mac }}"
domain: "{{ domain }}"```
This is a list
list:
- key: value
This is a dictionary
dictionary:
key: value
This is a list of dictionaries
dictionary:
- key1: value-1-1
key2: value-2-1
- key1: value-2-1
key2: value-2-2
The task includes an option with an undefined variable. The error was: 'item' is undefined
The indentation of with_dict is wrong. The correct syntax is below.
vmware_guest:
...
networks:
- name: "{{ item.value.name }}"
ip: "{{ item.value.ip }}"
netmask: "{{ item.value.netmask }}"
gateway: "{{ item.value.gateway }}"
mac: "{{ item.value.mac }}"
domain: "{{ item.value.domain }}"
with_dict: "{{ bnetworks }}"

Related

Ansible - vmware_guest module to create windows server machine

I am trying to create a windows server machine with the vmware_guest module from a template. I see that it ignore the parameter disk and its option size_gb. When the playbook create the virtual machine, it has the same disk size of the template This only happens when I create a windows server machine, if I try to create a linux server, the module it works correctly.
This is my playbook
- name: Clone VM from template with static IP
vmware_guest:
validate_certs: "{{ validate_certs | default('False') }}"
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
datacenter: "{{ vm_datacenter }}"
name: "{{ vm_name }}"
folder: "{{ vm_folder }}"
template: "{{ vm_template }}"
state: poweredon
annotation: "{{ vm_notes | default('Provisioned by ansible') }}"
cluster: "{{ vm_cluster }}"
hardware:
num_cpus: "{{ cpu }}"
memory_mb: "{{ mem_mb }}"
hotadd_cpu: "{{ hot_add_cpu | default('True') }}"
hotremove_cpu: "{{ hot_remove_cpu | default('True') }}"
hotadd_memory: "{{ hot_add_memory | default('True') }}"
disk:
- size_gb: "{{ disk_size | default('16') }}"
type: "{{ vm_disk_type | default('thin') }}"
datastore: "{{ vm_datastore }}"
networks:
- name: "{{ vm_port_group }}"
type: static
ip: "{{ vm_ip }}"
netmask: "{{ netmask }}"
gateway: "{{ network_gateway }}"
wait_for_ip_address: yes
customization:
dns_servers:
- "{{ dns_server1 }}"
register: static_vm
I would try limiting your indentation. See if that helps.
disk:
- size_gb: "{{ disk_size | default('16') }}"
type: "{{ vm_disk_type | default('thin') }}"
datastore: "{{ vm_datastore }}"

How can I create Virtual Machine in ESXI using Ansible?

I have esxi and vcenter installed. I found an ansible playbook online which creates a vm from a template:
---
# create a new VM from a template
- name: VM from template
hosts: localhost
gather_facts: false
connection: local
vars:
vcenter_hostname: vcenter-app
vcenter_user: john#doe
vcenter_pass: blabla6
esxhost: esx-4.cbalo.fr
datastore: VM-PROD-02-NORMAL
vmtemplate: Centos7-template
name: "newvm2"
notes: Ansible Test
dumpfacts: False
tasks:
- name: Create VM from template
vmware_guest:
validate_certs: False
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
esxi_hostname: "{{ esxhost }}"
datacenter: CD06
folder: Test
name: "{{ name }}"
template: "{{ vmtemplate }}"
disk:
- size_gb: "{{ disk_size | default(17) }}"
type: thin
datastore: "{{ datastore }}"
hardware:
memory_mb: "{{ vm_memory | default(1024) }}"
wait_for_ip_address: True
state: present
register: newvm2
I want to create my VM from ISO. Also, I can't see the network part in that script: is it using the template network (DHCP)? Any help is really appreciated .

Ansible VMWare not clean datastore

I wrote 2 Ansible playbooks to create and destroy a vm inside an ESXi instance.
The create task is:
- name: Clone the template
delegate_to: localhost
community.vmware.vmware_guest:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
cluster: "{{ vcenter_cluster_name }}"
datacenter: "{{ vcenter_datacenter_name }}"
folder: "{{ vcenter_datacenter_folder }}"
datastore: "{{ vcenter_datastore }}"
validate_certs: False
name: "{{ inventory_hostname }}"
template: "{{ vm_template }}"
state: poweredon
wait_for_ip_address: yes
networks:
- name: "DSwitch_Dati-VM Network 869"
ip: "{{ ansible_host }}"
netmask: "{{ vm_netmask }}"
gateway: "{{ vm_gateway }}"
start_connected: yes
The delete playbook is:
- name: TMS Cleaner
hosts: all
remote_user: tms
tasks:
- name: Set powerstate of virtual machine to poweroff
delegate_to: localhost
community.vmware.vmware_guest:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: False
name: "{{ inventory_hostname }}"
state: poweredoff
- name: Remove virtual machine from inventory
delegate_to: localhost
community.vmware.vmware_guest:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
folder: "{{ vcenter_datacenter_folder }}"
datastore: "{{ vcenter_datastore }}"
validate_certs: False
name: "{{ inventory_hostname }}"
delete_from_inventory: True
state: absent
The creation is correct, while deletion can correctly stop and remove the vm BUT it doeas not remove the folder from the datastore.
What should I do to have a full deletion of all files related to a vm?
If you want to have the files deleted also from datastore you need to remove the following line:
delete_from_inventory: True
The ansible documentation for this module says:
delete_from_inventory:
Choices: Whether to delete Virtual machine from inventory or delete from disk.
no | yes
Only remove that line and files will be deleted from datastore.

ansible vmware windows server

I am trying to execute my ansible playbook to launch VMware-windows-server with IP settings, but VM is getting launched but without IP settings.
after executing the playbook am not getting any errors and its shows changes also done, but when i checked in Vmware environment IP is not reflecting.
tried all possible ways, can anyone help me out on this.
thanks
here is my playbook :
---
- hosts: vm-windows-server2012
gather_facts: false
connection: local
vars_files:
- group_vars/vm-windows-server2012
tasks:
- name: "PROVISION | Create Windows server 2012 from template"
vmware_guest:
validate_certs: false
hostname: "{{ vcenter_host }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
datacenter: "{{ datacenter }}"
name: "{{ guest_name }}"
folder: "{{ folder }}"
template: "{{ vmtemplate }}"
state: poweredon
esxi_hostname: "{{ esxi_host }}"
hardware:
num_cpus: "{{ cpu }}"
memory_mb: "{{ mem_mb }}"
disk:
- size_gb: "{{ disk }}"
type: thin
datastore: "{{ datastore }}"
register: new_vm
- name: Wait for VMware tools to become available
vmware_guest_tools_wait:
hostname: "{{ vcenter_host }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: False
name: "{{ vm_name }}"
folder: "/{{ datacenter }}/vm/{{ folder }}"
- name: "IP configuration"
local_action:
module: vmware_vm_shell
hostname: "{{ vcenter_host }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
datacenter: "{{ datacenter }}"
vm_id: "{{ vm_name }}"
vm_username: "{{ v_username }}"
vm_password: "{{ v_password }}"
vm_shell: 'C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe'
vm_shell_args: 'netsh interface ip set address "Ethernet0 2" static 10.193.34.250 255.255.255.192 10.193.34.193'
vm_shell_cwd: 'C:\Users\Administrator'
validate_certs: False
Your code is fine, but you have to wait for the VMWare Tools to be active on the VM in order to use vmware_vm_shell.
Use this before your vmware_vm_shell:
- name: Wait for VMware tools to become available
vmware_guest_tools_wait:
hostname: "{{ vcenter_host }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: False
name: "{{ vm_name }}"
folder: "/{{ vcenter_datacenter }}/vm/{{ default_vm_folder }}"
- name: Change IP Address for Windows Machine
vmware_vm_shell:
hostname: "{{ vcenter_host }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: False
datacenter: "{{ vcenter_datacenter }}"
folder: "/{{ datacenter }}/vm/{{ folder }}"
vm_id: "{{ vm_name }}"
vm_username: "{{ v_username }}"
vm_password: "{{ v_password }}"
vm_shell: netsh.exe
vm_shell_args: ' interface ip set address name="Ethernet0 2" static 10.193.34.250 255.255.255.192 10.193.34.193'
vm_shell_cwd: "C:\\Windows\\System32"
- name: Change DNS for Windows Machine
vmware_vm_shell:
hostname: "{{ vcenter_host }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: False
datacenter: "{{ vcenter_datacenter }}"
folder: "/{{ datacenter }}/vm/{{ folder }}"
vm_id: "{{ vm_name }}"
vm_username: "{{ v_username }}"
vm_password: "{{ v_password }}"
vm_shell : netsh.exe
vm_shell_args : ' interface ip set dns name="Ethernet0 2" static 8.8.8.8'
vm_shell_cwd : "C:\\Windows\\System32"
- name: Wait until the ipaddress of machine is ready
wait_for:
port: 5986
delay: 20
state: started
host: "10.193.34.250"

Use Jinja2 dict as part of an Ansible modules options

I have the following dict:
endpoint:
esxi_hostname: servername.domain.com
I'm trying to use it as an option via jinja2 for the vmware_guest but have been unsuccessful. The reason I'm trying to do it this way is because the dict is dynamic...it can either be cluster: clustername or esxi_hostname: hostname, both mutually exclusive in the vmware_guest module.
Here is how I'm presenting it to the module:
- name: Create VM pysphere
vmware_guest:
hostname: "{{ vcenter_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: no
datacenter: "{{ ansible_host_datacenter }}"
folder: "/DCC/{{ ansible_host_datacenter }}/vm"
"{{ endpoint }}"
name: "{{ guest }}"
state: present
guest_id: "{{ osid }}"
disk: "{{ disks }}"
networks: "{{ niclist }}"
hardware:
memory_mb: "{{ memory_gb|int * 1024 }}"
num_cpus: "{{ num_cpus|int }}"
scsi: "{{ scsi }}"
customvalues: "{{ customvalues }}"
cdrom:
type: client
delegate_to: localhost
And here is the error I'm getting when including the tasks file:
TASK [Preparation : Include VM tasks] *********************************************************************************************************************************************************************************
fatal: [10.10.10.10]: FAILED! => {"reason": "Syntax Error while loading YAML.
The error appears to have been in '/data01/home/hit/tools/ansible/playbooks/roles/Preparation/tasks/prepareVM.yml': line 36, column 4, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
"{{ endpoint }}"
hostname: "{{ vcenter_hostname }}"
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
exception type: <class 'yaml.parser.ParserError'>
exception: while parsing a block mapping
in "<unicode string>", line 33, column 3
did not find expected key
in "<unicode string>", line 36, column 4"}
So in summary, I'm not sure how to format this or if it is even possible.
The post from techraf sums up your problem, but for a possible solution, in the docs, especially regarding Jinja filters, there is the following bit:
Omitting Parameters
As of Ansible 1.8, it is possible to use the default filter to omit
module parameters using the special omit variable:
- name: touch files with an optional mode
file: dest={{item.path}} state=touch mode={{item.mode|default(omit)}} > with_items:
- path: /tmp/foo
- path: /tmp/bar
- path: /tmp/baz
mode: "0444"
For the first two files in the list, the default mode will be
determined by the umask of the system as the mode= parameter will not
be sent to the file module while the final file will receive the
mode=0444 option.
So it looks like what should be tried is:
esxi_hostname: "{{ endpoint.esxi_hostname | default(omit) }}"
# however you want the alternative cluster settings done.
# I dont know this module.
cluster: "{{ cluster | default(omit) }}"
This is obviously reliant on the vars to only have one choice set.
There is no way you could ever use the syntax you tried in the question, because firstly and foremostly Ansible requires a valid YAML file.
The closest workaround would be to use a YAML anchor/alias although it would work only with literals:
# ...
vars:
endpoint: &endpoint
esxi_hostname: servername.domain.com
tasks:
- name: Create VM pysphere
vmware_guest:
hostname: "{{ vcenter_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: no
datacenter: "{{ ansible_host_datacenter }}"
folder: "/DCC/{{ ansible_host_datacenter }}/vm"
<<: *endpoint
name: "{{ guest }}"
state: present
guest_id: "{{ osid }}"
disk: "{{ disks }}"
networks: "{{ niclist }}"
hardware:
memory_mb: "{{ memory_gb|int * 1024 }}"
num_cpus: "{{ num_cpus|int }}"
scsi: "{{ scsi }}"
customvalues: "{{ customvalues }}"
cdrom:
type: client
delegate_to: localhost

Resources