From 782c60a9493f10e77b192235c0939ad8264c7b81 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Thu, 6 Jan 2022 22:39:26 +0100 Subject: finalize vm/guest/deploy --- .../deploy/action_plugins/replace_vm_image.py | 66 ++++++++++++++++++++++ roles/vm/guest/deploy/defaults/main.yml | 7 --- roles/vm/guest/deploy/tasks/main.yml | 22 ++------ 3 files changed, 71 insertions(+), 24 deletions(-) create mode 100644 roles/vm/guest/deploy/action_plugins/replace_vm_image.py (limited to 'roles/vm/guest') diff --git a/roles/vm/guest/deploy/action_plugins/replace_vm_image.py b/roles/vm/guest/deploy/action_plugins/replace_vm_image.py new file mode 100644 index 00000000..44db9698 --- /dev/null +++ b/roles/vm/guest/deploy/action_plugins/replace_vm_image.py @@ -0,0 +1,66 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os + +from ansible.errors import AnsibleError, AnsibleAction, AnsibleActionFail, AnsibleActionSkip, AnsibleConnectionFailure +from ansible.module_utils._text import to_native, to_bytes +from ansible.plugins.action import ActionBase +from ansible.utils.cmd_functions import run_cmd + + +class ActionModule(ActionBase): + TRANSFERS_FILES = False + + DECOMPRESSORS = { + 'application/gzip': 'gunzip', + 'application/zstd': 'unzstd', + 'application/x-bzip2': 'bunzip2', + 'application/x-xz': 'unxz', + } + + def _get_decompressor_for_file(self, file): + try: + rc, out, err = run_cmd('file --mime-type --mime-encoding %s' % (file)) + if rc != 0: + raise Exception('unable to read mime-type of file: %s' % (file)) + out = to_native(out, errors='surrogate_or_strict') + mimetype = out.rsplit(':', 1)[1].split(';')[0] + return self.DECOMPRESSORS.get(mimetype.strip(), 'cat') + except Exception as e: + raise AnsibleActionFail(to_native(e)) + + def run(self, tmp=None, task_vars=None): + if task_vars is None: + task_vars = dict() + + result = super(ActionModule, self).run(tmp, task_vars) + del tmp # tmp no longer has any effect + + try: + if self._play_context.check_mode: + raise AnsibleActionSkip('Check mode is not supported for this task.') + + result['changed'] = True + + source = to_native(self._task.args.get('src', ''), errors='surrogate_or_strict') + destination = to_native(self._task.args.get('dest', ''), errors='surrogate_or_strict') + decompressor = self._get_decompressor_for_file(source) + try: + source = self._loader.get_real_file(self._find_needle('files', source), decrypt=False) + with open(to_bytes(source, errors='surrogate_or_strict'), 'rb') as f: + source = to_bytes(f.read(), nonstring='passthru') + except AnsibleError as e: + raise AnsibleActionFail(to_native(e)) + + result.update(self._low_level_execute_command('%s > %s' % (decompressor, destination), in_data=source)) + # workaround for gzip trailing garbage handling + if 'rc' in result and result['rc'] == 2: + if 'stderr' in result and 'decompression OK' in result['stderr']: + result['rc'] = 0 + self._fixup_perms2((destination), execute=False) + + except AnsibleAction as e: + result.update(e.result) + + return result diff --git a/roles/vm/guest/deploy/defaults/main.yml b/roles/vm/guest/deploy/defaults/main.yml index 63deb439..786eef26 100644 --- a/roles/vm/guest/deploy/defaults/main.yml +++ b/roles/vm/guest/deploy/defaults/main.yml @@ -1,10 +1,3 @@ --- -vm_deploy_decompressors: - "application/octet-stream": cat - "application/gzip": gunzip - "application/zstd": unzstd - "application/x-bzip2": bunzip2 - "application/x-xz": unxz - # vm_deploy_primary_disk: # path: /srv/root.img diff --git a/roles/vm/guest/deploy/tasks/main.yml b/roles/vm/guest/deploy/tasks/main.yml index aa27b59d..1b4a4e63 100644 --- a/roles/vm/guest/deploy/tasks/main.yml +++ b/roles/vm/guest/deploy/tasks/main.yml @@ -1,11 +1,4 @@ --- -- name: fetch infos from image file - delegate_to: localhost - stat: - path: "{{ output_images | first }}" - get_mime: yes - register: output_image_info - - name: make sure primary disk image path exists delegate_to: "{{ vm_host.name }}" file: @@ -16,16 +9,11 @@ import_role: name: vm/guest/remove - ## TODO: actually call this directly and make file replacement atomic!! - ## Probably by writing and action plugin based on this: https://github.com/socratesx/Ansible-Decompress -- name: copy disk image - pause: - prompt: | - Please copy the image to the vm-host i.e. by calling this: - - cat {{ output_image_info.stat.path }} | {{ vm_deploy_decompressors[output_image_info.stat.mimetype] }} | ssh {{ vm_host.name }} 'cat > {{ vm_deploy_primary_disk.path }}' - - When done press ENTER to continue or CTRL-C then A to abort. +- name: deploy disk image + delegate_to: "{{ vm_host.name }}" + replace_vm_image: + src: "{{ output_images | first }}" + dest: "{{ vm_deploy_primary_disk.path }}" - name: create vm vars: -- cgit v1.2.3