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 recipe.
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 (refer to Chapter 1, Working with KVM Guests, on how to set up a KVM server). 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:
~/playbooks/provisioning.yml
playbook with the following contents:- name: Provision new machines hosts: all gather_facts: no tasks: - 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/boot.cat -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
~/templates/isolinux/isolinux.cfg.el7
file; 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
~]# 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 ~]#
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 recipe) 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.
For more information on playbooks, go to http://docs.ansible.com/ansible/playbooks.html.
For more information on Ansible templates, go to http://docs.ansible.com/ansible/modules_by_category.html.