From 52a8840d31eaf25ecc3d00e9921c9bda71640e5f Mon Sep 17 00:00:00 2001 From: Tomas Tomecek Date: Feb 13 2018 18:50:36 +0000 Subject: [PATCH 1/2] inventory,qcow2: remove noop Signed-off-by: Tomas Tomecek --- diff --git a/inventory/standard-inventory-qcow2 b/inventory/standard-inventory-qcow2 index 7a6feea..0a571ac 100755 --- a/inventory/standard-inventory-qcow2 +++ b/inventory/standard-inventory-qcow2 @@ -119,7 +119,6 @@ def host(image): os.dup2(tty, 2) except OSError: tty = None - pass # A directory for temporary stuff directory = tempfile.mkdtemp(prefix="inventory-cloud") From 8e0be63ff5ed7edef0d436365f03376117c96ea9 Mon Sep 17 00:00:00 2001 From: Tomas Tomecek Date: Feb 15 2018 08:30:27 +0000 Subject: [PATCH 2/2] inventory,qcow2: add a way to lock on a file I am using the inventory script directly from a playbook. The thing is that Ansible creates a long chain of processes and if the VM's parent process waits on its parent process, the VM is terminated sometime during a playbook run. This commit adds a way to lock on a presence of a file, not just a process. Signed-off-by: Tomas Tomecek --- diff --git a/README.md b/README.md index 364df0e..f27d712 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,52 @@ a QCow2 image into a virtual machine, or installing an RPM. Tests are not required to use these scripts but they provide useful, usable defaults for this task. + + +## `standard-inventory-qcow2` + +This inventory script launches a virtual machine via qemu. The VM image should +be specified via command line or an environment variable `TEST_SUBJECTS`. + +By default, the virtual machine is killed when the process (your shell) it +invoked the script, is gone. This behavior may not be desirable when invoking +the inventory script from an Ansible playbook (since Ansible spawns a long +hierarchy of processes). For that purpose you can use environment variable `LOCK_ON_FILE`: the VM will be killed once the file specified by this variable is missing. Let's look at an example: + +```yaml +--- +- hosts: localhost + vars: + # path to the VM image to use + vm_image: "./Fedora-Cloud-Base-27-1.6.x86_64.qcow2" + # inventory name of the VM + vm_name: "awesome-vm" + # which python interpreter should be used by ansible (e.g. Fedora doesn't have /usr/bin/python) + vm_python_interpreter: "/usr/bin/python3" + # path to the script which will provision the VM + vm_provisioning_script: /usr/share/ansible/inventory/standard-inventory-qcow2 + tasks: + - name: create lock file to synchronize on the VM + tempfile: + prefix: inventory-cloud + suffix: .lock + state: file + register: tmp_lock_file + - name: provision the VM + command: "{{ vm_provisioning_script }} {{ vm_image }}" + register: vm_provision_data + environment: + LOCK_ON_FILE: "{{ tmp_lock_file.path }}" + - name: prepare inventory data for add_host + set_fact: + inventory_data: '{{ (vm_provision_data.stdout | from_json)._meta.hostvars[vm_image] }}' + - add_host: + name: "{{ vm_name }}" + ansible_ssh_common_args: "{{ inventory_data.ansible_ssh_common_args }}" + ansible_ssh_host: "{{ inventory_data.ansible_ssh_host }}" + ansible_ssh_pass: "{{ inventory_data.ansible_ssh_pass }}" + ansible_ssh_port: "{{ inventory_data.ansible_ssh_port }}" + ansible_ssh_private_key_file: "{{ inventory_data.ansible_ssh_private_key_file }}" + ansible_ssh_user: "{{ inventory_data.ansible_ssh_user }}" + ansible_python_interpreter: "{% if vm_python_interpreter != '' %}{{ vm_python_interpreter }}{% else %}/usr/bin/python2{% endif %}" +``` diff --git a/inventory/standard-inventory-qcow2 b/inventory/standard-inventory-qcow2 index 0a571ac..ab8c8bc 100755 --- a/inventory/standard-inventory-qcow2 +++ b/inventory/standard-inventory-qcow2 @@ -234,15 +234,23 @@ def host(image): os.dup2(tty, 1) os.dup2(tty, 2) - # Now wait for the parent process to go away, then kill the VM + # alternatively, lock on a file + lock_file = os.environ.get("LOCK_ON_FILE", None) while True: time.sleep(3) - try: - os.kill(ppid, 0) - os.kill(proc.pid, 0) - except OSError: - break # Either of the processes no longer exist + if lock_file: + if not os.path.exists(lock_file): + sys.stderr.write("Lock file is gone.") + break + else: + # Now wait for the parent process to go away, then kill the VM + try: + os.kill(ppid, 0) + os.kill(proc.pid, 0) + except OSError: + sys.stderr.write("Either parent process or VM process is gone.") + break # Either of the processes no longer exist if diagnose: sys.stderr.write("\n")