Ansible | Deploy VM then run additional playbooks against new host? - ansible

I am fairly new to Ansible. I have created an Ansible role that contains the following tasks that will deploy a vm from a template, then configure the VM with custom OS settings:
create-vm.yml
configure-vm.yml
I can successfully deploy a VM from a template via the "create-vm" task. But after that is
complete, I would like to continue with the "configure-vm" task. Since the playbooks/role-vm-deploy.yml file contains "localhost" as shown here...
- hosts: localhost
roles:
- vm-deploy
gather_facts: no
connection: local
... the next task doesn't run successfully because it is attempting to run the task against "localhost" and not the new VM hostname. I have since added the following to the end of the "create-vm" task...
- name: Add host to group 'just_created'
add_host:
name: '{{ hostname }}.{{ domain }}'
groups: just_created
...but I'm not quite sure what to do with it. I can't quite wrap my head around what else I need to do and how to call the new hostname in the "configure-vm" task instead of localhost.
I am executing the playbook via CLI
# ansible-playbook playbooks/role-vm-deploy.yml
I saw this post, which was kind of helpful
I also saw the dynamic inventory documentation, but it's a bit over my head at this juncture. Any help would be appreciated. Thank you!
Here are the contents for the playbooks and tasks
### playbooks -> role-vm-deploy.yml
- hosts: localhost
roles:
- vm-deploy
gather_facts: no
connection: local
### roles -> vm-deploy -> tasks -> main.yml
- name: Deploy VM
include: create-vm.yml
tags:
- create-vm
- name: Configure VM
include: configure-vm.yml
tags:
- configure-vm
### roles -> vm-deploy -> tasks -> create-vm.yml
- name: Clone the template
vmware_guest:
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
password: '{{ vcenter_pwd }}'
validate_certs: False
name: '{{ hostname }}'
template: '{{ template_name }}'
datacenter: '{{ datacenter }}'
folder: '/'
hardware:
memory_mb: '{{ memory }}'
num_cpus: '{{ num_cpu }}'
networks:
- label: "Network adapter 1"
state: present
connected: True
name: '{{ vlan }}'
state: poweredon
wait_for_ip_address: yes
### roles -> vm-deploy -> tasks -> configure-vm.yml
### This task is what I need to execute on the new hostname, but it attempts to execute on "localhost" ###
# Configure Networking
- name: Configure IP Address
lineinfile:
path: '{{ network_conf_file }}'
regexp: '^IPADDR='
line: 'IPADDR={{ ip_address }}'
- name: Configure Gateway Address
lineinfile:
path: '{{ network_conf_file }}'
regexp: '^GATEWAY='
line: 'GATEWAY={{ gw_address }}'
### roles -> vm-deploy -> defaults -> main.yml
- All of the variables reside here including "{{ hostname }}.{{ domain }}"

You got so close! The trick is to observe that a playbook is actually a list of plays (the yaml objects that are {"hosts": "...", "tasks": []}), and the targets of subsequent plays don't have to exist when the playbook starts -- presumably for this very reason. Thus:
- hosts: localhost
roles:
- vm-deploy
gather_facts: no
connection: local
# or wherever you were executing this -- it wasn't obvious from your question
post_tasks:
- name: Add host to group 'just_created'
add_host:
name: '{{ hostname }}.{{ domain }}'
groups: just_created
- hosts: just_created
tasks:
- debug:
msg: hello from the newly created {{ inventory_hostname }}

Related

Using Ansible to manage ESXI Inventory

I am trying to use Ansible to modify the DNS settings on a group of ESXI servers. I've been able to get my playbook to change the settings on a single server like this:
---
- hosts: localhost
tasks:
- name: Configure ESXi hostname and DNS servers
vmware_dns_config:
hostname: 'myesxiserver.domain.local'
username: 'username'
password: 'password'
dns_servers:
- x.x.x.x
- x.x.x.x
delegate_to: localhost
How can I get this to work for multiple servers? The Ansible documentation provides this example:
---
- hosts: localhost
tasks:
- name: Configure ESXi hostname and DNS servers
vmware_dns_config:
hostname: '{{ esxi_hostname }}'
username: '{{ esxi_username }}'
password: '{{ esxi_password }}'
change_hostname_to: esx01
domainname: foo.org
dns_servers:
- 8.8.8.8
- 8.8.4.4
delegate_to: localhost
I'm not clear on how to iterate through a list of hosts and pass the correct values into the variable '{{ esxi_hostname }}' for each of my servers. I'm assuming that the variables can be passed using an inventory file but I haven't found any good examples on how to do this for ESXI servers.
So I did get this working.
---
- hosts: localhost
vars_files:
- vars.yml
- vars2.yml
tasks:
- name: Configure ESXi hostname and DNS servers
vmware_dns_config:
hostname: "{{ item }}"
username: 'myadmin'
password: "{{ Password }}"
validate_certs: no
change_hostname_to: "{{ item }}"
domainname: foo.org
dns_servers:
- x.x.x.x
- x.x.x.x
delegate_to: localhost
loop: "{{ esxihost }}"
I had to pass a list of host names using vars_file and iterate through it using the loop keyword. I tried to use the {{inventory_hostname}} variable along with a standard inventory file but because SSH is not generally enabled by default on ESXi servers I would get an SSH connection error.

VMware VM Portgroup change with Ansible 2.9.6

My script doesn't change the portgroup of a VM Network adapter, what am I doing wrong ?
Let's assume that I want to change the current portgroup named "A" to a different portgroup named "B".
---
- hosts: localhost
gather_facts: no
vars:
vm_name: VM
tasks:
- name: Changing Portgroup for Network adapter 1
vmware_guest_network:
hostname: "{{ vc_host }}"
username: "{{ vc_user }}"
password: "{{ vc_pass }}"
validate_certs: no
name: "{{ vm_name }}"
gather_network_info: false
networks:
- label: "Network adapter 1"
name: "B"
state: present
delegate_to: localhost
register: network_info
I'm getting output that something changed, but in VM Settings nothing changed.
TASK [Changing Portgroup for Network Adapter 1]
******************************************************************************
changed: [localhost -> localhost]
I found that removing and adding a Network adapter changes the portgroup, but when I do that I cannot add a Network adapter type Flexible which I had in the first place.
Edit1: After updating Ansible to 2.9.12 I get OK output when running the script, so it really isn't changing anything.
TASK [Changing Portgroup for Network Adapter 1] ******************************************************************************
ok: [localhost]
Edit2: After a few days searching I found that it isn't possible to just change the portgroup with Ansible, so I used PowerCLI to help me with task.
---
- hosts: localhost
gather_facts: no
vars:
vm_name: "VM"
tasks:
- name: "Changing the portgroup for {{ vm_name }}"
win_command: 'powershell.exe -ExecutionPolicy ByPass -File C:\Scripts\change_portgroup.ps1 {{ vm_name }}'
delegate_to: WIN_SRV
With powershell script going like this:
$OldNetwork = "PG old"
$NewNetwork = "PG new"
Get-VM -Name $args[0] |Get-NetworkAdapter |Where {$_.NetworkName -eq $OldNetwork } |Set-NetworkAdapter -NetworkName $NewNetwork -Confirm:$false
Edit 3:
I got it working with vmware community module. (Thanks #sky-jokerxx)
First I installed it with command:
ansible-galaxy collection install community.vmware
Then used the module like this:
- name: Change network
community.vmware.vmware_guest_network:
validate_certs: no
hostname: '{{ vc_host }}'
username: '{{ vc_user }}'
password: '{{ vc_pass }}'
name: '{{ vm_name }}'
label: "Network adapter 1"
network_name: "B"
state: present
delegate_to: localhost
The vmware_guest_network module has a lot of issues.
https://github.com/ansible-collections/community.vmware/issues/378
The following vmware_guest_network module is fixed some issues.
https://github.com/ansible-collections/community.vmware/pull/401
In the following procedure, you can use the above module.
# ansible-galaxy collection install community.vmware -p collections
# mkdir library
# cd library/
# curl -L https://raw.githubusercontent.com/ansible-collections/community.vmware/7ac9ebb9bf5df0f1ead3ef1a3ed35f2d4ad45622/plugins/modules/vmware_guest_network.py -O
# cd ..
https://docs.ansible.com/ansible/latest/dev_guide/developing_locally.html
Maybe it's fixed, so how about trying it?

Ansible read variables from bash

I created 2 playbooks:
deploy VM(centos8) into ESX
join VM to AD
Inside of them are plenty variables which are useful only for one specific VM (beside info about ESX)
---
- name: create vm from template on ESX
hosts: localhost
gather_facts: no
become: yes
tasks:
- name: clone the template
vmware_guest:
hostname: "IP.."
username: "user"
password: "password"
validate_certs: false
name: ll-ansible
template: ll
datacenter: "LAB KE"
folder: "OIR"
resource_pool: "pool"
cluster: "PROD cluster"
networks:
- name: IS-VLAN1102
device_type: vmxnet3
vlan: IS-VLAN1102
ip: ip.ip.ip.ip
netmask: 255.255.255.0
gateway: gw.gw.gw.gw
customization:
hostname: ll-ansible
timezone: timezone
domain: domain
dns_servers:
- ip.ip.ip.ip
- ip.ip.ip.ip
disk:
- size: 60gb
type: default
datastore: Dell-OIR
- size: 10gb
type: default
datastore: Dell-OIR
hardware:
memory_mb: 4096
num_cpus: 4
num_cpu_cores_per_socket: 2
boot-firmware: efi
state: poweredon
wait_for_ip_address: yes
register: vm
- debug: msg "{{ vm }}"
My question is:
Is there a way to make a script which will read all necessary variables for deploying VM from command line and fill fields in playbook and then run playbook.
Or if is it possible make it only within ansible possibilities.
There are many ways to send variables to playbook.
Let's start from these 3 most popular options:
env vars
ansible-playbook CLI arguments
var files
See also all 22 options: Understanding variable precedence
Option 1: use lookup('env') in the playbook
Just use "{{ lookup('env', 'ENV_VAR_NAME')}}"
E.g., for your case:
---
- name: create vm from template on ESX
hosts: localhost
gather_facts: no
become: yes
tasks:
- name: clone the template
vmware_guest:
hostname: "{{ lookup('env', 'IP_ADDRESS')}}"
Option 2: pass var through CLI args
You may pass Env var value using --extra-vars CLI argument
For your case:
playbook.yml
...
- name: clone the template
vmware_guest:
hostname: "{{ ip_address }}"
user: "{{ user }}"
usage:
ansible-playbook playbook.yml --extra-vars="user={{ lookup('env', 'USER') }}, ip_address='10.10.10.10'"
Option 3: use vars_files in the playbook
For your case:
playbook.yml:
---
- name: create vm from template on ESX
hosts: localhost
gather_facts: no
become: yes
vars_files:
- "vars/vars.yml"
tasks:
- name: clone the template
vmware_guest:
hostname: "{{ hostname }}"
vars/vars.yml:
---
hostname: "host.example.com"
Let's combine them all:
Suppose you have two different environments:
staging for staging environment
prod for productive environment
Then we create two different vars files:
vars/staging.yml
---
hostname: "staging.domain.com"
vars/prod.yml
---
hostname: "prod.domain.com"
playbook.yml:
---
- name: create vm from template on ESX
y6uu hosts: localhost
gather_facts: no
become: yes
vars_files:
- "vars/{{ env }}.yml"
tasks:
- name: clone the template
vmware_guest:
hostname: "{{ hostname }}"
Usage
run playbook with staging vars:
ansible-playbook playbook.yml --extra-vars=staging
run playbook with prod vars:
ansible-playbook playbook.yml --extra-vars=prod

Ansible playbook for Cisco Nexus fails with nxapi in provider

I have not been able to get this playbook working. I am trying to use the 'nxapi' provider method. I have nxapi setup on the target devices. I have a group_vars file with the following settings:
ansible_connection: local
ansible_network_os: nxos
ansible_user: user
ansible_password: password
The playbook code is:
- name: nxos_facts module
hosts: "{{ myhosts }}"
vars:
ssh:
host: "{{ myhosts }}"
username: "{{ ansible_user }}"
password: "{{ ansible_password }}"
transport: cli
nxapi:
host: "{{ myhosts }}"
username: "{{ ansible_user }}"
password: "{{ ansible_password }}"
transport: nxapi
use_ssl: yes
validate_certs: no
port: 8443
tasks:
- name: nxos_facts nxapi
nxos_facts:
provider: "{{ nxapi }}"
When I debug the failed playbook, I see this line:
ESTABLISH LOCAL CONNECTION FOR USER: < MY USER NAME >
It seems like the Playbook is not using the variables in the group_vars file , which specify a specific user to connect to the nxapi service on the switch.
Can't add a comment due to lack of rep
Make sure your group_vars match a child group in your host file. (Can't tell from your question)
host file:
all:
hosts:
SWITCH1:
ansible_host: 192.168.1.1
children:
group1:
hosts:
SWITCH1:
You can then have your Group variables in one of 2 files, all.yml or group1.yml

Ansible Module vmware_host_facts only returning one Host

I'm playing around with Ansible VMWare Modules and tried to get all the Information from ESXi Hosts from a vCenter.
With the Module vmware_host_facts it should be possible.
But when I run a Playbook with the following configuration, I only get the Information of one Host back - and not all. In this vCenter there are about 20 Hosts.
Playbook:
- name: Gather vmware host facts
vmware_host_facts:
hostname: vCenter_IP
username: username
password: password
register: host_facts
delegate_to: localhost
In the Documentation it tells me, that the hostname can also be a vCenter IP.
Resource:
http://docs.ansible.com/ansible/latest/modules/vmware_host_facts_module.html#vmware-host-facts
Is that module not the correct one to gather all host information from a vCenter? Or is there a "hidden trick", which I am missing?
Thanks a lot!
Kind regards,
M
I got an answer on another resource.
https://github.com/ansible/ansible/issues/43187
Basically you have to add the Hostnames as a list to the Task.
Example:
- name: Gather vmware host facts
vmware_host_facts:
hostname: "{{ item.esxi_hostname }}"
username: "{{ item.esxi_user }}"
password: "{{ item.esxi_pass }}"
validate_certs: no
register: host_facts
delegate_to: localhost
with_items:
- {esxi_hostname: hostname_1, esxi_user: username_host_1, esxi_pass: pass_host_1}
- {esxi_hostname: hostname_2, esxi_user: username_host_2, esxi_pass: pass_host_2}
These Hostnames you can gather with another module - vmware_vm_facts. Here you can get the Hostnames from. I will update this with an example playbook in the near future.
I use this module with these options, so far I have one issue if I put vcenter address it only give me first Esxi output.
- name: Somethign.
vmware_host_facts:
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_user }}'
password: '{{ vcenter_pass }}'
validate_certs: no
register: all_cluster_hosts_facts
delegate_to: localhost
- debug: var=all_cluster_hosts_facts

Resources