Ansible mit ESXi

In den beiden vorangegangenen Artikeln (ESXi auf Raspberry Pi 4 und Einführung in Ansible) habe ich die Grundlage geschaffen um zu erreichen, dass per Ansible automatisch virtuelle Maschinen installiert werden können. Nach einigen Tricks und Kniffen, u.a. weil ein ESX Host alleine dafür eigentlich nicht vorgesehen ist, gelang es mir dennoch die Aufgabe zu erfüllen. Nun ging es daran, das Shellscript bzw. den ESX Host und Ansible zu kombinieren.

Vorab eine kleine Anmerkung: Der gesamte Prozess und vor allem die Scripte und Playbooks sind keineswegs optimiert. Das hier ist quasi der erste Wurf, welcher funktioniert. Erweitertes Error-Handling usw. folgt in späteren Versionen.

Die Grundlage bildet das Shellscript zum erstellen der VM auf dem ESX Host, welches nun per Ansible gestartet wird. Des weiteren soll die neu installierte VM in die Ansible Verwaltung aufgenommen, und der Hostname auf der VM geändert werden. Das ergibt drei Hauptschritte für das Playbook und somit drei Plays:

  1. Shellscript auf dem ESX Host starten und warten bis die VM erstellt wurde
  2. Die neue VM in die Verwaltung von Ansible aufnehmen
  3. Den Hostname der neu erstellten VM anpassen

Das Shellscript ermittelt den nächsten freien Namen automatisch und lässt nicht mehr als 10 VMs auf dem ESX Host zu.

Play 1 - Das Shellscript auf dem ESX Host

- name: Deploy new VM
  hosts: 192.168.1.20
  remote_user: root
  vars:
      template: 20210327-deb10-arm64

  tasks:

     - name: Execute deployscript on ESX Host
       command: sh /scratch/downloads/deployNewVM/deployNewVM.sh -t "{{ template }}"

     - name: Get new VM name
       shell: cat /tmp/newvm
       register: vmname

     - debug:
         msg: "{{ vmname.stdout }}"

     - set_fact:
         vmname: "{{ vmname.stdout }}"

     - name: Get ID from new VM
       shell: vim-cmd vmsvc/getallvms | grep "{{ vmname }}" | awk '{print $1}'
       register: vmid

     - debug:
         msg: "{{ vmid.stdout }}"

     - name: Get IP from new VM
       shell: vim-cmd vmsvc/getallvms | grep "{{ vmid.stdout }}" | awk '{print $1}' | xargs vim-cmd vmsvc/get.guest | grep -i 'ipaddress = "'  | head -n 1 | cut -d'"' -f2
       register: vmip

     - name: Store VM IP for next plays
       set_fact:
         vmip: "{{ vmip.stdout }}"

     - debug:
         msg: "{{ vmip }}"



Die einzelnen Schritte im Task (erkenntlich am Namen), sind relativ selbsterklärend. Dieses Play teilt sich in vier Hauptschritte unter:

  • Script ausführen
  • Namen der neuen VM auslesen (das Shellscript erstellt eine temporäre Textdatei)
  • ID der neuen VM ermitteln
  • IP der neuen VM anhand der ID ermitteln

Die "set_fact" Schritte dienen dazu die Variablen für die anderen Plays zwischenzuspeichern. Das Debugging kann nach Bedarf natürlich auch auskommentiert werden.



Play 2 - Neue VM in die Verwaltung aufnehmen

- name: Add new deployed VM to ansible host group
  hosts: localhost

  tasks:

     - name: Get variable 'vmip' from ESX-Host play
       set_fact:
         vmip: "{{ hostvars['192.168.1.20']['vmip'] }}"

     - debug:
         msg: "{{ vmip }}"

     - name: Add host
       add_host:
         name: "{{ vmip }}"
         groups: vms

     - name: Add new host to hosts-file
       lineinfile:
         path: /etc/ansible/hosts
         insertafter: 'vms'
         line: "{{ vmip }}"
         firstmatch: yes
         state: present



In diesem Play wird die neue VM zunächst mit der "add_host" Funktion temporär in den Ansible Prozess (dieses Playbooks) aufgenommen. Achtung: Der Host wird mit dieser Funktion nicht dauerhaft der Verwaltung hinzugefügt - da bin ich auch drauf reingefallen. Hierfür ist der nächste Schritt notwendig, wo die IP der neuen VM in die /etc/ansible/hosts geschrieben wird (in den Block [vms]). Die "add_host" Funktion ermöglicht es zudem, dass Play 3 überhaupt funktioniert.

Der SSH Key muss nicht mehr verteilt werden, da dieser im Template vorhanden ist. In produktiven Umgebungen würde ich hiervon abraten, da sich die Ansible Controller durchaus verändern können. Vermutlich gibt es auch viel elegantere Wege für die Verwaltung, aber wie eingangs erwähnt, sind das hier mein ersten Berührungspunkte mit Ansible :)



Play 3 - Ändern des Hostnames auf der neuen VM

- name: Some configuration on new VM
  hosts: "{{ hostvars['192.168.1.20']['vmip'] }}"

  tasks:

     - name: Get variable 'vmname' from ESX-Host play
       set_fact:
         vmname: "{{ hostvars['192.168.1.20']['vmname'] }}"

     - debug:
         msg: "{{ vmname }}"

     - name: Run hostnamectl on new VM
       command: hostnamectl set-hostname "{{ vmname }}"

     - name: Change /etc/hosts on new VM
       shell: sed -i "s/vm00/{{ vmname }}/g" /etc/hosts

     - name: Reboot new VM
       reboot:



Zunächst wird wie in Play 2 die benötigte Variable abgerufen. Anschließend erfolgen nur noch zwei Befehle um den Hostname zu ändern und ein Neustart. Das komplette Playbook steht hier zur Verfügung.

Ausgabe des Playbooks:



Ausblick

Jetzt fehlt vielleicht noch eine nette Benachrichtigung wenn die VM erstellt wurde (bspw. eine Mail) und natürlich das automatische Abbauen von VMs. Anschließend könnte man dann die Playbooks erweitern, oder neue erstellen, um spezifische Software zu installieren.