├── README.md └── image_provisioner.yml /README.md: -------------------------------------------------------------------------------- 1 | # image-provisioner 2 | 3 | A simple Ansible playbook to quickly provision VMs in a KVM/QEMU environment. 4 | 5 | ## Assumptions 6 | 7 | You have Ansible installed on your KVM host 8 | 9 | ## Usage 10 | 11 | 1. Create a `cloud-init` `user-data` and `meta-data` file. Read about `cloud-init` [here](https://cloudinit.readthedocs.io/en/latest/) 12 | 13 | 2. Create the following directories or change them in the playbook to suit your environment. 14 | - `/data/vm_storage/cloud-init` 15 | - `/data/vm_storage/cloud-init/isos` 16 | - `/data/vm_storage/images/base` 17 | 18 | At a minimum you should have storage for your cloud images, a directory for your `cloud-init` files and a directory 19 | for your installed VMs. 20 | 21 | 3. Download a qcow2 cloud image for the operating system of your choice. 22 | 23 | 4. Move the cloud image to `/data/vm_storage/images/base` 24 | 25 | 5. Change the `base_disk` disk variable to match the image you downloaded. 26 | 27 | 6. Ensure the `disk_path` variable matches the directory for your installed VMs. 28 | 29 | 7. Run the playbook as follows: 30 | `ansible-playbook image_provisioner.yml --extra-vars="host_name=HOSTNAME full_host_name=FQDN memory=MEMORY vcpus=VCPUS network=NETWORK disk_size=DISK_SIZE"` 31 | 32 | 8. If everything works, this will rysnc and resize the disk image, mount your cloud-init data, install it with `virt-install` and delete the old cloud-init data. 33 | -------------------------------------------------------------------------------- /image_provisioner.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # First attempt 3 | - hosts: localhost 4 | vars: 5 | host_name: '{{ host_name }}' 6 | full_host_name: '{{ full_host_name }}' 7 | memory: '{{ memory }}' 8 | vpcus: '{{ vcpus }}' 9 | disk_size: '{{ disk_size }}' 10 | network: '{{ network }}' 11 | ansible_hosts: '/etc/ansible/hosts' 12 | cloud_init_path: '/data/vm_storage/cloud-init' 13 | cloud_init_isos: '/data/vm_storage/cloud-init/isos' 14 | base_disk: '/data/vm_storage/images/base/CentOS-7-x86_64-GenericCloud-1804.qcow2' 15 | disk_path: '/data/vm_storage/images' 16 | 17 | tasks: 18 | - name: Instantiate image 19 | command: rsync -a {{ base_disk }} {{ disk_path }}/{{ host_name }}.qcow2 20 | become: yes 21 | 22 | - name: Generate new meta-data instance-id 23 | shell: 'echo instance-id: {{ host_name }} >> {{ cloud_init_path }}/meta-data' 24 | become: yes 25 | 26 | - name: Generate new meta-data local-hostname 27 | shell: 'echo local-hostname: {{ full_host_name }} >> {{ cloud_init_path }}/meta-data' 28 | become: yes 29 | 30 | - name: Generate cloud-init ISO 31 | command: genisoimage -output {{ cloud_init_isos }}/{{ host_name }}.iso -joliet -volid cidata \ 32 | -r {{ cloud_init_path }}/user-data {{ cloud_init_path }}/meta-data 33 | become: yes 34 | 35 | - name: Resize disk image 36 | command: qemu-img resize {{ disk_path }}/{{ host_name }}.qcow2 {{ disk_size }} 37 | 38 | 39 | - name: Import the VM 40 | command: virt-install \ 41 | --name {{ host_name }} \ 42 | --vcpus {{ vcpus }} \ 43 | --memory {{ memory }} \ 44 | --import \ 45 | --disk '{{ disk_path }}/{{ host_name }}'.qcow2,format=qcow2,bus=virtio \ 46 | --disk {{ cloud_init_isos }}/{{ host_name }}.iso,device=cdrom 47 | --network network={{ network }} 48 | --os-type=linux 49 | --os-variant=rhel7 50 | --noautoconsole 51 | become: yes 52 | 53 | - name: Eject the cloud-init ISO 54 | command: virsh change-media {{ host_name }} hda --eject --config 55 | become: yes 56 | 57 | - name: Delete the cloud-init ISO 58 | command: rm '{{ cloud_init_isos }}/{{ host_name }}'.iso 59 | become: yes 60 | 61 | - name: Remove old meta-data file 62 | command: rm '{{ cloud_init_path }}/meta-data' 63 | become: yes 64 | 65 | - name: Add {{ host_name }} to ansible/hosts 66 | lineinfile: 67 | path: '{{ ansible_hosts }}' 68 | line: '{{ host_name }}' 69 | state: present 70 | become: yes 71 | 72 | - name: Remove {{ host_name }} entry in .ssh/known_hosts 73 | lineinfile: 74 | path: ~/.ssh/known_hosts 75 | line: '{{ host_name }}' 76 | state: absent 77 | 78 | - name: Reboot {{ host_name }} 79 | command: virsh reboot {{ host_name }} 80 | become: yes 81 | --------------------------------------------------------------------------------