Ansible : Playbook to Deploy a New VM with Kickstart File


Creating playbooks for Ansible is a relatively easy task as most considerations are handled by the modules. All modules are made as “idempotently” as possible, meaning that a module first checks what it is supposed to do with what has been done on the system and only then applies the changes if they are different.

We don’t need any additional facts for this.

For this to work, we need to have a web server and a location to store the kickstart files, which will be served by the web server.

For the sake of convenience, our web server is called web.domain.tld, the location on this web server is /var/www/html/kickstart, and this directory can be accessed through http://web.domain.tld/kickstart.

We also need a KVM host. In this case, we’ll call our KVM server kvm.domain.tld.

Let’s create the playbook that will provision new systems via the following steps:

  1. Create a ~/playbooks/provisioning.yml playbook with the following contents:
    - name: Provision new machines
      hosts: all
      gather_facts: no
      - name: Publish kickstart template as new file to webserver
        action: template src=templates/kickstart/rhel7.ks dest=/var/www/html/kickstart/{{ inventory_hostname }}.ks
                         owner=apache group=apache mode=0644
                         seuser=system_u serole=object_r setype=httpd_sys_content_t selevel=s0
        delegate_to: web.domain.tld
      - name: Create new isolinux file to contain reference to the kickstart file
        action: template src=templates/isolinux/isolinux.cfg.el7 dest=/root/iso/isolinux/isolinux.cfg
        delegate_to: kvm.domain.tld
      - name: Create new iso boot media
        action: shell cd /root/iso; mkisofs -o /tmp/{{ inventory_hostname }}.iso -b isolinux/isolinux.bin -c isolinux/ -no-emul-boot -boot-load-size 4 -boot-info-table -J -r .
        delegate_to: kvm.domain.tld
      - name: Create disk for the new kvm guest
        action: virsh vol-create-as --pool localfs-vm --name {{ hostname }}-vda.qcows2 --format qcows2 --capacity 15G
        delegate_to: kvm.domain.tld
      - name: Create new vm on KVM
        action: shell virt-install --hvm --name {{ inventory_hostname }} --ram 2048 --vcpus 2 --os-type linux  --boot hd,cdrom,network,menu=on --controller type=scsi,model=virtio-scsi --disk device=cdrom,path=/tmp/{{ inventory_hostname }}.iso,readonly=on,bus=scsi --disk device=disk,vol=localfs-vm/{{ inventory_hostname }}-vda.qcows2,cache=none,bus=scsi --network network=bridge-eth0,model=virtio --graphics vnc --graphics spice --noautoconsole --memballoon virtio
        delegate_to: kvm.domain.tld
  2. You’ll also need to create the template for the ~/templates/isolinux/isolinux.cfg.el7file; you can do this by executing the following:
    default vesamenu.c32
    timeout 600
    display boot.msg
    menu clear
    menu background splash.png
    menu title Red Hat Enterprise Linux 7.0
    menu vshift 8
    menu rows 18
    menu margin 8
    menu helpmsgrow 15
    menu tabmsgrow 13
    menu color sel 0 #ffffffff #00000000 none
    menu color title 0 #ffcc000000 #00000000 none
    menu color tabmsg 0 #84cc0000 #00000000 none
    menu color hotsel 0 #84cc0000 #00000000 none
    menu color hotkey 0 #ffffffff #00000000 none
    menu color cmdmark 0 #84b8ffff #00000000 none
    menu color cmdline 0 #ffffffff #00000000 none
    label linux
      menu label ^Install Red Hat Enterprise Linux 7.0
      kernel vmlinuz
      append initrd=initrd.img ks=http://web.domain.tld/kickstart/{{ inventory_hostname }}.ks text
    label local
      menu label Boot from ^local drive
      localboot 0xffff
    menu end
  3. Now, use the following command to execute the playbook:
    ~]# ansible-playbook --limit newhost ~/playbooks/provisioning.yml
    PLAY [Provision new machines] ********************************
    TASK: [Publish kickstart template as new file to webserver] **
    changed: [newhost -> web.domain.tld]
    TASK: [Create new isolinux file to contain reference to the kickstart file] ***
    changed: [newhost -> kvm.domain.tld]
    TASK: [Create new iso boot media] ****************************
    changed: [newhost -> kvm.domain.tld]
    TASK: [Create disk for the new kvm guest] ********************
    changed: [newhost -> kvm.domain.tld]
    TASK: [Create new vm on KVM] *********************************
    changed: [newhost -> kvm.domain.tld]
    PLAY RECAP ***************************************************
    newhost             : ok=5  changed=5  unreachable=0  failed=0

How this works ?

The playbook starts off with a name describing the playbook, as does each task. Personally, I think naming your playbooks and tasks is a good idea as it will allow you to troubleshoot any issue at hand more easily.

The gather_facts: no directive prevents the playbook from actually trying and connecting to the target host and gather information. As the host is yet to be built, this is of no use and will make the playbook fail.

The first task uses a template (such as the one created in the previous tutorial) to generate a new kickstart file. By default, tasks are executed on the host specified in the command line, but by specifying the delegate_to directive, this is executed on the web server with the facts of the selected host.

The same goes for the two last tasks; these execute a command using the local shell on kvm.domain.tld with the host’s facts.

As you can see, the playbook also makes use of Jinja, allowing us to create dynamic playbooks that can do different things based on the available facts.

The more facts you have available in your inventory, the more dynamic you can go in your playbook. For instance, your source template could be OS-version specific and you can create all the virtual disks at once and specify the correct amount of CPUs and RAM upon system creation.



Please enter your comment!
Please enter your name here