diff options
Diffstat (limited to 'lib/ansible/modules/cloud/kubevirt/kubevirt_vm.py')
-rw-r--r-- | lib/ansible/modules/cloud/kubevirt/kubevirt_vm.py | 473 |
1 files changed, 0 insertions, 473 deletions
diff --git a/lib/ansible/modules/cloud/kubevirt/kubevirt_vm.py b/lib/ansible/modules/cloud/kubevirt/kubevirt_vm.py deleted file mode 100644 index 99731c6a7e..0000000000 --- a/lib/ansible/modules/cloud/kubevirt/kubevirt_vm.py +++ /dev/null @@ -1,473 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2019, Ansible Project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = ''' ---- -module: kubevirt_vm - -short_description: Manage KubeVirt virtual machine - -description: - - Use Openshift Python SDK to manage the state of KubeVirt virtual machines. - -version_added: "2.8" - -author: KubeVirt Team (@kubevirt) - -options: - state: - description: - - Set the virtual machine to either I(present), I(absent), I(running) or I(stopped). - - "I(present) - Create or update a virtual machine. (And run it if it's ephemeral.)" - - "I(absent) - Remove a virtual machine." - - "I(running) - Create or update a virtual machine and run it." - - "I(stopped) - Stop a virtual machine. (This deletes ephemeral VMs.)" - default: "present" - choices: - - present - - absent - - running - - stopped - type: str - name: - description: - - Name of the virtual machine. - required: true - type: str - namespace: - description: - - Namespace where the virtual machine exists. - required: true - type: str - ephemeral: - description: - - If (true) ephemeral virtual machine will be created. When destroyed it won't be accessible again. - - Works only with C(state) I(present) and I(absent). - type: bool - default: false - datavolumes: - description: - - "DataVolumes are a way to automate importing virtual machine disks onto pvcs during the virtual machine's - launch flow. Without using a DataVolume, users have to prepare a pvc with a disk image before assigning - it to a VM or VMI manifest. With a DataVolume, both the pvc creation and import is automated on behalf of the user." - type: list - template: - description: - - "Name of Template to be used in creation of a virtual machine." - type: str - template_parameters: - description: - - "New values of parameters from Template." - type: dict - -extends_documentation_fragment: - - k8s_auth_options - - kubevirt_vm_options - - kubevirt_common_options - -requirements: - - python >= 2.7 - - openshift >= 0.8.2 -''' - -EXAMPLES = ''' -- name: Start virtual machine 'myvm' - kubevirt_vm: - state: running - name: myvm - namespace: vms - -- name: Create virtual machine 'myvm' and start it - kubevirt_vm: - state: running - name: myvm - namespace: vms - memory: 64Mi - cpu_cores: 1 - bootloader: efi - smbios_uuid: 5d307ca9-b3ef-428c-8861-06e72d69f223 - cpu_model: Conroe - headless: true - hugepage_size: 2Mi - tablets: - - bus: virtio - name: tablet1 - cpu_limit: 3 - cpu_shares: 2 - disks: - - name: containerdisk - volume: - containerDisk: - image: kubevirt/cirros-container-disk-demo:latest - path: /custom-disk/cirros.img - disk: - bus: virtio - -- name: Create virtual machine 'myvm' with multus network interface - kubevirt_vm: - name: myvm - namespace: vms - memory: 512M - interfaces: - - name: default - bridge: {} - network: - pod: {} - - name: mynet - bridge: {} - network: - multus: - networkName: mynetconf - -- name: Combine inline definition with Ansible parameters - kubevirt_vm: - # Kubernetes specification: - definition: - metadata: - labels: - app: galaxy - service: web - origin: vmware - - # Ansible parameters: - state: running - name: myvm - namespace: vms - memory: 64M - disks: - - name: containerdisk - volume: - containerDisk: - image: kubevirt/cirros-container-disk-demo:latest - path: /custom-disk/cirros.img - disk: - bus: virtio - -- name: Start ephemeral virtual machine 'myvm' and wait to be running - kubevirt_vm: - ephemeral: true - state: running - wait: true - wait_timeout: 180 - name: myvm - namespace: vms - memory: 64M - labels: - kubevirt.io/vm: myvm - disks: - - name: containerdisk - volume: - containerDisk: - image: kubevirt/cirros-container-disk-demo:latest - path: /custom-disk/cirros.img - disk: - bus: virtio - -- name: Start fedora vm with cloud init - kubevirt_vm: - state: running - wait: true - name: myvm - namespace: vms - memory: 1024M - cloud_init_nocloud: - userData: |- - #cloud-config - password: fedora - chpasswd: { expire: False } - disks: - - name: containerdisk - volume: - containerDisk: - image: kubevirt/fedora-cloud-container-disk-demo:latest - path: /disk/fedora.qcow2 - disk: - bus: virtio - node_affinity: - soft: - - weight: 1 - term: - match_expressions: - - key: security - operator: In - values: - - S2 - -- name: Create virtual machine with datavolume and specify node affinity - kubevirt_vm: - name: myvm - namespace: default - memory: 1024Mi - datavolumes: - - name: mydv - source: - http: - url: https://url/disk.qcow2 - pvc: - accessModes: - - ReadWriteOnce - storage: 5Gi - node_affinity: - hard: - - term: - match_expressions: - - key: security - operator: In - values: - - S1 - -- name: Remove virtual machine 'myvm' - kubevirt_vm: - state: absent - name: myvm - namespace: vms -''' - -RETURN = ''' -kubevirt_vm: - description: - - The virtual machine dictionary specification returned by the API. - - "This dictionary contains all values returned by the KubeVirt API all options - are described here U(https://kubevirt.io/api-reference/master/definitions.html#_v1_virtualmachine)" - returned: success - type: complex - contains: {} -''' - - -import copy -import traceback - -from ansible.module_utils.k8s.common import AUTH_ARG_SPEC -from ansible.module_utils.kubevirt import ( - virtdict, - KubeVirtRawModule, - VM_COMMON_ARG_SPEC, - VM_SPEC_DEF_ARG_SPEC -) - -VM_ARG_SPEC = { - 'ephemeral': {'type': 'bool', 'default': False}, - 'state': { - 'type': 'str', - 'choices': [ - 'present', 'absent', 'running', 'stopped' - ], - 'default': 'present' - }, - 'datavolumes': {'type': 'list'}, - 'template': {'type': 'str'}, - 'template_parameters': {'type': 'dict'}, -} - -# Which params (can) modify 'spec:' contents of a VM: -VM_SPEC_PARAMS = list(VM_SPEC_DEF_ARG_SPEC.keys()) + ['datavolumes', 'template', 'template_parameters'] - - -class KubeVirtVM(KubeVirtRawModule): - - @property - def argspec(self): - """ argspec property builder """ - argument_spec = copy.deepcopy(AUTH_ARG_SPEC) - argument_spec.update(VM_COMMON_ARG_SPEC) - argument_spec.update(VM_ARG_SPEC) - return argument_spec - - @staticmethod - def fix_serialization(obj): - if obj and hasattr(obj, 'to_dict'): - return obj.to_dict() - return obj - - def _wait_for_vmi_running(self): - for event in self._kind_resource.watch(namespace=self.namespace, timeout=self.params.get('wait_timeout')): - entity = event['object'] - if entity.metadata.name != self.name: - continue - status = entity.get('status', {}) - phase = status.get('phase', None) - if phase == 'Running': - return entity - - self.fail("Timeout occurred while waiting for virtual machine to start. Maybe try a higher wait_timeout value?") - - def _wait_for_vm_state(self, new_state): - if new_state == 'running': - want_created = want_ready = True - else: - want_created = want_ready = False - - for event in self._kind_resource.watch(namespace=self.namespace, timeout=self.params.get('wait_timeout')): - entity = event['object'] - if entity.metadata.name != self.name: - continue - status = entity.get('status', {}) - created = status.get('created', False) - ready = status.get('ready', False) - if (created, ready) == (want_created, want_ready): - return entity - - self.fail("Timeout occurred while waiting for virtual machine to achieve '{0}' state. " - "Maybe try a higher wait_timeout value?".format(new_state)) - - def manage_vm_state(self, new_state, already_changed): - new_running = True if new_state == 'running' else False - changed = False - k8s_obj = {} - - if not already_changed: - k8s_obj = self.get_resource(self._kind_resource) - if not k8s_obj: - self.fail("VirtualMachine object disappeared during module operation, aborting.") - if k8s_obj.spec.get('running', False) == new_running: - return False, k8s_obj - - newdef = dict(metadata=dict(name=self.name, namespace=self.namespace), spec=dict(running=new_running)) - k8s_obj, err = self.patch_resource(self._kind_resource, newdef, k8s_obj, - self.name, self.namespace, merge_type='merge') - if err: - self.fail_json(**err) - else: - changed = True - - if self.params.get('wait'): - k8s_obj = self._wait_for_vm_state(new_state) - - return changed, k8s_obj - - def _process_template_defaults(self, proccess_template, processedtemplate, defaults): - def set_template_default(default_name, default_name_index, definition_spec): - default_value = proccess_template['metadata']['annotations'][default_name] - if default_value: - values = definition_spec[default_name_index] - default_values = [d for d in values if d.get('name') == default_value] - defaults[default_name_index] = default_values - if definition_spec[default_name_index] is None: - definition_spec[default_name_index] = [] - definition_spec[default_name_index].extend([d for d in values if d.get('name') != default_value]) - - devices = processedtemplate['spec']['template']['spec']['domain']['devices'] - spec = processedtemplate['spec']['template']['spec'] - - set_template_default('defaults.template.cnv.io/disk', 'disks', devices) - set_template_default('defaults.template.cnv.io/volume', 'volumes', spec) - set_template_default('defaults.template.cnv.io/nic', 'interfaces', devices) - set_template_default('defaults.template.cnv.io/network', 'networks', spec) - - def construct_definition(self, kind, our_state, ephemeral): - definition = virtdict() - processedtemplate = {} - - # Construct the API object definition: - defaults = {'disks': [], 'volumes': [], 'interfaces': [], 'networks': []} - vm_template = self.params.get('template') - if vm_template: - # Find the template the VM should be created from: - template_resource = self.client.resources.get(api_version='template.openshift.io/v1', kind='Template', name='templates') - proccess_template = template_resource.get(name=vm_template, namespace=self.params.get('namespace')) - - # Set proper template values taken from module option 'template_parameters': - for k, v in self.params.get('template_parameters', {}).items(): - for parameter in proccess_template.parameters: - if parameter.name == k: - parameter.value = v - - # Proccess the template: - processedtemplates_res = self.client.resources.get(api_version='template.openshift.io/v1', kind='Template', name='processedtemplates') - processedtemplate = processedtemplates_res.create(proccess_template.to_dict()).to_dict()['objects'][0] - - # Process defaults of the template: - self._process_template_defaults(proccess_template, processedtemplate, defaults) - - if not ephemeral: - definition['spec']['running'] = our_state == 'running' - template = definition if ephemeral else definition['spec']['template'] - template['metadata']['labels']['vm.cnv.io/name'] = self.params.get('name') - dummy, definition = self.construct_vm_definition(kind, definition, template, defaults) - - return self.merge_dicts(definition, processedtemplate) - - def execute_module(self): - # Parse parameters specific to this module: - ephemeral = self.params.get('ephemeral') - k8s_state = our_state = self.params.get('state') - kind = 'VirtualMachineInstance' if ephemeral else 'VirtualMachine' - _used_params = [name for name in self.params if self.params[name] is not None] - # Is 'spec:' getting changed? - vm_spec_change = True if set(VM_SPEC_PARAMS).intersection(_used_params) else False - changed = False - crud_executed = False - method = '' - - # Underlying module_utils/k8s/* code knows only of state == present/absent; let's make sure not to confuse it - if ephemeral: - # Ephemerals don't actually support running/stopped; we treat those as aliases for present/absent instead - if our_state == 'running': - self.params['state'] = k8s_state = 'present' - elif our_state == 'stopped': - self.params['state'] = k8s_state = 'absent' - else: - if our_state != 'absent': - self.params['state'] = k8s_state = 'present' - - # Start with fetching the current object to make sure it exists - # If it does, but we end up not performing any operations on it, at least we'll be able to return - # its current contents as part of the final json - self.client = self.get_api_client() - self._kind_resource = self.find_supported_resource(kind) - k8s_obj = self.get_resource(self._kind_resource) - if not self.check_mode and not vm_spec_change and k8s_state != 'absent' and not k8s_obj: - self.fail("It's impossible to create an empty VM or change state of a non-existent VM.") - - # If there are (potential) changes to `spec:` or we want to delete the object, that warrants a full CRUD - # Also check_mode always warrants a CRUD, as that'll produce a sane result - if vm_spec_change or k8s_state == 'absent' or self.check_mode: - definition = self.construct_definition(kind, our_state, ephemeral) - result = self.execute_crud(kind, definition) - changed = result['changed'] - k8s_obj = result['result'] - method = result['method'] - crud_executed = True - - if ephemeral and self.params.get('wait') and k8s_state == 'present' and not self.check_mode: - # Waiting for k8s_state==absent is handled inside execute_crud() - k8s_obj = self._wait_for_vmi_running() - - if not ephemeral and our_state in ['running', 'stopped'] and not self.check_mode: - # State==present/absent doesn't involve any additional VMI state management and is fully - # handled inside execute_crud() (including wait logic) - patched, k8s_obj = self.manage_vm_state(our_state, crud_executed) - changed = changed or patched - if changed: - method = method or 'patch' - - # Return from the module: - self.exit_json(**{ - 'changed': changed, - 'kubevirt_vm': self.fix_serialization(k8s_obj), - 'method': method - }) - - -def main(): - module = KubeVirtVM() - try: - module.execute_module() - except Exception as e: - module.fail_json(msg=str(e), exception=traceback.format_exc()) - - -if __name__ == '__main__': - main() |