From 993bac94f5007b37d36134b34a9f927ae44d00b2 Mon Sep 17 00:00:00 2001
From: Jesse Pretorius <jesse.pretorius@rackspace.co.uk>
Date: Wed, 15 Aug 2018 19:25:12 +0100
Subject: [PATCH] MNAIO: Extend image saving to include manifest

In order to more successfully reproduce an environment using
saved images, we include the VM XML definition files and the
output from 'pip freeze'. We capture the list of files, their
checksums and the SHA for the git repo into a json manifest
file.

Change-Id: Ia0bf74d509b4acb10b0dd832a4cfe1bb2afb2503
---
 multi-node-aio/playbooks/deploy-vms.yml | 17 ++++++-
 multi-node-aio/playbooks/save-vms.yml   | 63 +++++++++++++++++++++++--
 2 files changed, 74 insertions(+), 6 deletions(-)

diff --git a/multi-node-aio/playbooks/deploy-vms.yml b/multi-node-aio/playbooks/deploy-vms.yml
index c7a2256f..b6ce90d8 100644
--- a/multi-node-aio/playbooks/deploy-vms.yml
+++ b/multi-node-aio/playbooks/deploy-vms.yml
@@ -83,7 +83,7 @@
         - default_vm_disk_mode == "lvm"
       with_items: "{{ groups['pxe_servers'] }}"
 
-    - name: Setup file-based disk images
+    - name: Setup/clean-up file-based disk images
       when:
         - default_vm_disk_mode == "file"
       block:
@@ -99,6 +99,14 @@
           when:
             - vm_use_snapshot is not defined
 
+        - name: Clean up base image files if they are not being used
+          file:
+            path: "{{ item.path }}"
+            state: absent
+          with_items: "{{ _base_images.files }}"
+          when:
+            - not (vm_use_snapshot | bool)
+
         - name: Create VM Disk Image
           command: >-
             qemu-img create
@@ -123,7 +131,12 @@
       virt:
         name: "{{ hostvars[item]['server_hostname'] }}"
         command: define
-        xml: "{{ lookup('template', 'kvm/kvm-vm.xml.j2') }}"
+        xml: >-
+          {%- if vm_use_snapshot | bool %}
+          {{ lookup('file', _virt_pools.pools.default.path | default('/data') ~ '/' ~ hostvars[item]['server_hostname'] ~ '.xml') }}
+          {%- else %}
+          {{ lookup('template', 'kvm/kvm-vm.xml.j2') }}
+          {%- endif %}
       failed_when: false
       when:
         - hostvars[item]['server_vm'] | default(false) | bool
diff --git a/multi-node-aio/playbooks/save-vms.yml b/multi-node-aio/playbooks/save-vms.yml
index d7303b09..1c3fef9e 100644
--- a/multi-node-aio/playbooks/save-vms.yml
+++ b/multi-node-aio/playbooks/save-vms.yml
@@ -35,6 +35,8 @@
       virt_pool:
         command: info
       register: _virt_pools
+      tags:
+        - always
 
     - name: Stop running VMs
       virt:
@@ -45,10 +47,63 @@
       with_items: "{{ groups['pxe_servers'] }}"
 
     - name: Save VM Disk Image
-      command: >-
-        mv
-        {{ _virt_pools.pools.default.path | default('/data') }}/{{ hostvars[item]['server_hostname'] }}.img
-        {{ _virt_pools.pools.default.path | default('/data') }}/{{ hostvars[item]['server_hostname'] }}-base.img
+      shell: |
+        if [[ -e {{ hostvars[item]['server_hostname'] }}.img ]]; then
+          if [[ -e {{ hostvars[item]['server_hostname'] }}-base.img ]]; then
+            qemu-img commit {{ hostvars[item]['server_hostname'] }}.img
+          else
+            mv {{ hostvars[item]['server_hostname'] }}.img {{ hostvars[item]['server_hostname'] }}-base.img
+          fi
+          exit 2
+        fi
+      args:
+        executable: /bin/bash
+        chdir: "{{ _virt_pools.pools.default.path | default('/data') }}"
       when:
         - hostvars[item]['server_vm'] | default(false) | bool
       with_items: "{{ groups['pxe_servers'] }}"
+      register: _save_disk_image
+      changed_when: _save_disk_image.rc == 2
+
+    - name: Save VM definition
+      copy:
+        src: "/etc/libvirt/qemu/{{ hostvars[item]['server_hostname'] }}.xml"
+        dest: "{{ _virt_pools.pools.default.path | default('/data') }}/"
+        remote_src: yes
+      when:
+        - hostvars[item]['server_vm'] | default(false) | bool
+      with_items: "{{ groups['pxe_servers'] }}"
+
+    - name: Get the current SHA1 for the manifest
+      command: "git rev-parse HEAD"
+      args:
+        chdir: "{{ playbook_dir }}"
+      register: _repo_sha
+      changed_when: false
+
+    - name: Add pip freeze results to the data
+      shell: "pip --disable-pip-version-check freeze > pip-requirements.txt"
+      args:
+        executable: /bin/bash
+        chdir: "{{ _virt_pools.pools.default.path | default('/data') }}"
+      changed_when: false
+
+    - name: Find all the files for the manifest
+      find:
+        paths: "{{ _virt_pools.pools.default.path | default('/data') }}"
+        patterns:
+          - "*-base.img"
+          - "*.xml"
+          - "*.txt"
+        get_checksum: yes
+      register: _manifest_files
+
+    - name: Prepare the manifest file content
+      set_fact:
+        _manifest_content: >-
+          { 'openstack-ansible-ops_SHA1': '{{ _repo_sha.stdout }}', 'files': {{ _manifest_files.files | json_query('[*].{path: path, checksum: checksum}') | sort(attribute='path') }} }
+
+    - name: Write out the manifest file
+      copy:
+        content: "{{ _manifest_content | to_nice_json }}"
+        dest: "{{ _virt_pools.pools.default.path | default('/data') }}/manifest.json"