From 843ad6659cc0bd6b8baaf2033e680d32a0531b2d Mon Sep 17 00:00:00 2001 From: spmfox Date: Sat, 10 Jun 2023 22:50:30 -0400 Subject: adding tags, adding guest configuration --- README.md | 13 +++++++- docs/sample-environment.yml | 9 +++++- roles/guest-configure/tasks/main.yml | 17 +++++++++++ roles/guest-configure/tasks/packages.yml | 5 +++ roles/guest-configure/tasks/services.yml | 6 ++++ roles/guest-configure/tasks/update.yml | 4 +++ roles/guest-configure/tasks/user.yml | 52 ++++++++++++++++++++++++++++++++ roles/guest-configure/vars/main.yml | 6 ++++ roles/libvirt/vars/main.yml | 8 ++--- roles/zfs/vars/main.yml | 2 +- vm-create.yml | 48 ++++++++++++++++++++++++----- vm-delete.yml | 30 ++++++++++++++---- 12 files changed, 179 insertions(+), 21 deletions(-) create mode 100644 roles/guest-configure/tasks/main.yml create mode 100644 roles/guest-configure/tasks/packages.yml create mode 100644 roles/guest-configure/tasks/services.yml create mode 100644 roles/guest-configure/tasks/update.yml create mode 100644 roles/guest-configure/tasks/user.yml create mode 100644 roles/guest-configure/vars/main.yml diff --git a/README.md b/README.md index baa7577..be4abaa 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,12 @@ all: parent_dataset: "zfs-parent-dataset/zfs-child-dataset" network: "bridge:vm-bridge" root_password: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}" - root_ssh_key: "" + user: "admin" + ssh_key: "" + packages: + - qemu-guest-agent + services: + - qemu-guest-agent ``` An example with multiple VMs is located in the ```docs``` directory. @@ -48,6 +53,12 @@ An example with multiple VMs is located in the ```docs``` directory. - Kickstart files and compatible distros are required - The delete play will completely remove any VMs or datasets defined in your inventory +## Known Issues +- Currently cannot delete VMs with libvirt snapshots + - community.libvirt.virt module has upstream code to do this, but it has not been released yet + - Workaround is to manually delete snapshots from VM before deletion + - Does NOT apply to ZFS snapshots + ## Architecture The KVM and ZFS tasks are split into different roles, ```libvirt``` and ```zfs```. These roles contain all the needed tasks and variables for each feature. Variables for libvirt tasks start with ```libvirt_``` and zfs ones start with ```zfs_```. These are the "real" variables that are used in the tasks, diff --git a/docs/sample-environment.yml b/docs/sample-environment.yml index 959f2f5..b04c051 100644 --- a/docs/sample-environment.yml +++ b/docs/sample-environment.yml @@ -26,5 +26,12 @@ all: parent_dataset: "zfs-parent-dataset/zfs-child-dataset" network: "bridge:vm-bridge" root_password: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}" #Random root password - root_ssh_key: | + user: "admin" #Regular user with sudo rights + # SSH key for root and regular user + ssh_key: | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDFyY+3A07lMnHkyQ6bMez/BEi9j2vh4sotxQdqEMlCS+EJCta8G/CCj54kBvFKrrkiPMs0Jj1Od02ZjWZqGf+W/stZ+KLh97M0EM/69zbRbQJZ7xuCQKng7U87bbopbXcx9Mu9DUCC1pjNJ5Bb7nG6z51hk7mh3mF8QGHJ6qp03FrK+Eiud/2d9Zbn4lNH/E5W7iZ3J7zZHU16nLQH1Tsbx2LFUDkVhz/A4/7sqRmWT/mpwSCVgxN9cFgs1KMHsqb4Z1XXtbb//SWj+bmPvcfbfDUkTnb8Z+KTOd1OViKjDH1owgymxZtDML5S7OOZ2AX0/c5JaDplLRhji7gpVTRLZJE5XHvfVqwJCkxVrxoc4sbcZb9I/G+clJ3CBzSMZXh7p85J4OLVP5GmfOh0o93pakWVsTZBrPgO3EjhOyj0pGay3qUHiQfPqIlU+q92Mku5iijsbFDv28HdUlz5e69igg7E8Hr2/SruZuDijxOqkkHkmW0pnM8kXQpvU5dvW0U= pubkey@box + packages: # Packages to install on guest + - qemu-guest-agent + services: # Services to enable on guest + - qemu-guest-agent + diff --git a/roles/guest-configure/tasks/main.yml b/roles/guest-configure/tasks/main.yml new file mode 100644 index 0000000..4e4b429 --- /dev/null +++ b/roles/guest-configure/tasks/main.yml @@ -0,0 +1,17 @@ +- name: Wait for guest connectivity + ansible.builtin.wait_for_connection: + +- name: Gather facts + ansible.builtin.setup: + +- name: Import user creation task + ansible.builtin.import_tasks: user.yml + +- name: Import update task + ansible.builtin.import_tasks: update.yml + +- name: Import packages task + ansible.builtin.import_tasks: packages.yml + +- name: Import services task + ansible.builtin.import_tasks: services.yml diff --git a/roles/guest-configure/tasks/packages.yml b/roles/guest-configure/tasks/packages.yml new file mode 100644 index 0000000..cffd690 --- /dev/null +++ b/roles/guest-configure/tasks/packages.yml @@ -0,0 +1,5 @@ +- name: Install packages + ansible.builtin.package: + name: "{{ item }}" + state: present + loop: "{{ guest_configure_packages }}" diff --git a/roles/guest-configure/tasks/services.yml b/roles/guest-configure/tasks/services.yml new file mode 100644 index 0000000..56a5626 --- /dev/null +++ b/roles/guest-configure/tasks/services.yml @@ -0,0 +1,6 @@ +- name: Enable and start services + ansible.builtin.service: + name: "{{ item }}" + enabled: yes + state: started + loop: "{{ guest_configure_services }}" diff --git a/roles/guest-configure/tasks/update.yml b/roles/guest-configure/tasks/update.yml new file mode 100644 index 0000000..f74b190 --- /dev/null +++ b/roles/guest-configure/tasks/update.yml @@ -0,0 +1,4 @@ +- name: Update all packages + ansible.builtin.package: + name: "*" + state: latest diff --git a/roles/guest-configure/tasks/user.yml b/roles/guest-configure/tasks/user.yml new file mode 100644 index 0000000..c0e418b --- /dev/null +++ b/roles/guest-configure/tasks/user.yml @@ -0,0 +1,52 @@ +- name: Create user + ansible.builtin.user: + name: "{{ guest_configure_user }}" + +- name: RedHat block + block: + - name: Add user to sudo group (RedHat) + ansible.builtin.user: + name: "{{ guest_configure_user }}" + groups: "wheel" + append: yes + + - name: Allow wheel group nopasswd in sudoers (RedHat) + lineinfile: + path: /etc/sudoers + state: present + regexp: '^%wheel' + line: '%wheel ALL=(ALL) NOPASSWD: ALL' + validate: 'visudo -cf %s' + when: ansible_os_family == "RedHat" + +- name: Debian block + block: + - name: Add user to sudo group (Debian) + ansible.builtin.user: + name: "{{ guest_configure_user }}" + groups: "sudo" + append: yes + + - name: Allow sudo group nopasswd in sudoers (Debian) + lineinfile: + path: /etc/sudoers + state: present + regexp: '^%sudo' + line: '%sudo ALL=(ALL) NOPASSWD: ALL' + validate: 'visudo -cf %s' + when: ansible_os_family == "Debian" + +- name: Create user .ssh folder + ansible.builtin.file: + path: "/home/{{ guest_configure_user }}/.ssh/" + state: directory + mode: "0700" + owner: "{{ guest_configure_user }}" + +- name: Copy root ssh authorized_keys key to new user + ansible.builtin.copy: + src: "/root/.ssh/authorized_keys" + dest: "/home/{{ guest_configure_user }}/.ssh/authorized_keys" + remote_src: yes + mode: "0600" + owner: "{{ guest_configure_user }}" diff --git a/roles/guest-configure/vars/main.yml b/roles/guest-configure/vars/main.yml new file mode 100644 index 0000000..10881fb --- /dev/null +++ b/roles/guest-configure/vars/main.yml @@ -0,0 +1,6 @@ +ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" +ansible_user: root + +guest_configure_user: "{{ user }}" +guest_configure_packages: "{{ packages }}" +guest_configure_services: "{{ services }}" diff --git a/roles/libvirt/vars/main.yml b/roles/libvirt/vars/main.yml index 82140c5..54fd9e7 100644 --- a/roles/libvirt/vars/main.yml +++ b/roles/libvirt/vars/main.yml @@ -1,4 +1,4 @@ -libvirt_vm_name: "{{ vm_name }}" +libvirt_vm_name: "{{ inventory_hostname }}" libvirt_vm_memory: "{{ memory_mb }}" libvirt_vm_vcpus: "{{ cpus }}" libvirt_vm_disk_size: "{{ disk_gb }}" @@ -6,10 +6,10 @@ libvirt_vm_disk_format: "{{ disk_format }}" libvirt_vm_os: "{{ os }}" libvirt_vm_kickstart_file: "{{ kickstart }}" libvirt_vm_location_path: "{{ iso_path }}" -libvirt_vm_destination: "{{ parent_dataset }}/{{ vm_name }}" +libvirt_vm_destination: "{{ parent_dataset }}/{{ inventory_hostname }}" libvirt_vm_network: "{{ network }}" -libvirt_kickstart_hostname: "{{ vm_name }}" +libvirt_kickstart_hostname: "{{ inventory_hostname }}" libvirt_kickstart_timezone: "{{ timezone }}" -libvirt_kickstart_root_ssh_key: "{{ root_ssh_key }}" +libvirt_kickstart_root_ssh_key: "{{ ssh_key }}" libvirt_kickstart_root_password: "{{ root_password }}" diff --git a/roles/zfs/vars/main.yml b/roles/zfs/vars/main.yml index a53eb98..825fd0b 100644 --- a/roles/zfs/vars/main.yml +++ b/roles/zfs/vars/main.yml @@ -1 +1 @@ -zfs_dataset: "{{ parent_dataset }}/{{ vm_name }}" +zfs_dataset: "{{ parent_dataset }}/{{ inventory_hostname }}" diff --git a/vm-create.yml b/vm-create.yml index 7c03b30..1c7c98e 100644 --- a/vm-create.yml +++ b/vm-create.yml @@ -3,44 +3,76 @@ gather_facts: false tasks: - - ansible.builtin.include_role: + - name: Import zfs role for duplicate dataset check + ansible.builtin.include_role: name: zfs tasks_from: dataset-check-duplicate.yml apply: + tags: zfs delegate_to: "{{ hypervisor_host }}" + tags: zfs - - ansible.builtin.include_role: + - name: Import libvirt role for duplicate VM check + ansible.builtin.include_role: name: libvirt tasks_from: vm-check-duplicate.yml apply: + tags: libvirt delegate_to: "{{ hypervisor_host }}" + tags: libvirt - - ansible.builtin.include_role: + - name: Import zfs role for creating dataset + ansible.builtin.include_role: name: zfs tasks_from: dataset-create.yml apply: + tags: zfs delegate_to: "{{ hypervisor_host }}" + tags: zfs - - block: - - ansible.builtin.include_role: + - name: Block for VM creation and rescue for rolling back ZFS changes if creation fails + block: + - name: Import libvirt role for creating VM + ansible.builtin.include_role: name: libvirt tasks_from: vm-install.yml apply: + tags: libvirt delegate_to: "{{ hypervisor_host }}" + tags: libvirt rescue: - - ansible.builtin.debug: + - name: Print VM install failure message + ansible.builtin.debug: msg: VM install failed, removing dataset + tags: always - - ansible.builtin.include_role: + - name: Import zfs role for checking dataset before destroy + ansible.builtin.include_role: name: zfs tasks_from: dataset-confirm-info.yml apply: + tags: zfs delegate_to: "{{ hypervisor_host }}" + tags: zfs - - ansible.builtin.include_role: + - name: Import zfs role for destroying dataset + ansible.builtin.include_role: name: zfs tasks_from: dataset-destroy.yml apply: + tags: zfs delegate_to: "{{ hypervisor_host }}" + tags: zfs + - name: Fail host + ansible.builtin.fail: + msg: Host failed build process + tags: always + + - name: Import guest-configure role + ansible.builtin.include_role: + name: guest-configure + apply: + tags: guest-configure + tags: guest-configure diff --git a/vm-delete.yml b/vm-delete.yml index 6907c84..a76e73f 100644 --- a/vm-delete.yml +++ b/vm-delete.yml @@ -3,38 +3,56 @@ gather_facts: false tasks: - - ansible.builtin.include_role: + - name: Import zfs role to check if dataset exists + ansible.builtin.include_role: name: zfs tasks_from: dataset-check-exists.yml apply: + tags: zfs delegate_to: "{{ hypervisor_host }}" + tags: zfs - - ansible.builtin.include_role: + - name: Import libvirt role to check if VM exists + ansible.builtin.include_role: name: libvirt tasks_from: vm-check-exists.yml apply: + tags: libvirt delegate_to: "{{ hypervisor_host }}" + tags: libvirt - - ansible.builtin.include_role: + - name: Import libvirt role to confirm if VM has expected configuration + ansible.builtin.include_role: name: libvirt tasks_from: vm-confirm-info.yml apply: + tags: libvirt delegate_to: "{{ hypervisor_host }}" + tags: libvirt - - ansible.builtin.include_role: + - name: Import zfs role to confirm if the dataset has expected configuration + ansible.builtin.include_role: name: zfs tasks_from: dataset-confirm-info.yml apply: + tags: zfs delegate_to: "{{ hypervisor_host }}" + tags: zfs - - ansible.builtin.include_role: + - name: Import libvirt role to undefine VM + ansible.builtin.include_role: name: libvirt tasks_from: vm-undefine.yml apply: + tags: libvirt delegate_to: "{{ hypervisor_host }}" + tags: libvirt - - ansible.builtin.include_role: + - name: Import zfs role to destroy the dataset + ansible.builtin.include_role: name: zfs tasks_from: dataset-destroy.yml apply: + tags: zfs delegate_to: "{{ hypervisor_host }}" + tags: zfs -- cgit