mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-08 14:22:46 +00:00
kubevirt: Add new kubevirt_vm module (#50768)
This module is managing virtual machines using KubeVirt. Signed-off-by: Ondra Machacek <omachace@redhat.com>
This commit is contained in:
committed by
John R Barker
parent
6e409a91ba
commit
797a5218fb
193
lib/ansible/module_utils/kubevirt.py
Normal file
193
lib/ansible/module_utils/kubevirt.py
Normal file
@@ -0,0 +1,193 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
# Copyright (c) 2018, KubeVirt Team <@kubevirt>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
from ansible.module_utils.k8s.common import list_dict_str
|
||||
from ansible.module_utils.k8s.raw import KubernetesRawModule
|
||||
|
||||
try:
|
||||
from openshift import watch
|
||||
from openshift.helper.exceptions import KubernetesException
|
||||
except ImportError:
|
||||
# Handled in k8s common:
|
||||
pass
|
||||
|
||||
|
||||
API_VERSION = 'kubevirt.io/v1alpha3'
|
||||
|
||||
|
||||
VM_COMMON_ARG_SPEC = {
|
||||
'name': {},
|
||||
'force': {
|
||||
'type': 'bool',
|
||||
'default': False,
|
||||
},
|
||||
'resource_definition': {
|
||||
'type': list_dict_str,
|
||||
'aliases': ['definition', 'inline']
|
||||
},
|
||||
'src': {
|
||||
'type': 'path',
|
||||
},
|
||||
'namespace': {},
|
||||
'api_version': {'type': 'str', 'default': API_VERSION, 'aliases': ['api', 'version']},
|
||||
'merge_type': {'type': 'list', 'choices': ['json', 'merge', 'strategic-merge']},
|
||||
'wait': {'type': 'bool', 'default': True},
|
||||
'wait_timeout': {'type': 'int', 'default': 120},
|
||||
'memory': {'type': 'str'},
|
||||
'disks': {'type': 'list'},
|
||||
'labels': {'type': 'dict'},
|
||||
'interfaces': {'type': 'list'},
|
||||
'machine_type': {'type': 'str'},
|
||||
'cloud_init_nocloud': {'type': 'dict'},
|
||||
}
|
||||
|
||||
|
||||
def virtdict():
|
||||
"""
|
||||
This function create dictionary, with defaults to dictionary.
|
||||
"""
|
||||
return defaultdict(virtdict)
|
||||
|
||||
|
||||
class KubeVirtRawModule(KubernetesRawModule):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.api_version = API_VERSION
|
||||
super(KubeVirtRawModule, self).__init__(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def merge_dicts(x, y):
|
||||
"""
|
||||
This function merge two dictionaries, where the first dict has
|
||||
higher priority in merging two same keys.
|
||||
"""
|
||||
for k in set(x.keys()).union(y.keys()):
|
||||
if k in x and k in y:
|
||||
if isinstance(x[k], dict) and isinstance(y[k], dict):
|
||||
yield (k, dict(KubeVirtRawModule.merge_dicts(x[k], y[k])))
|
||||
else:
|
||||
yield (k, y[k])
|
||||
elif k in x:
|
||||
yield (k, x[k])
|
||||
else:
|
||||
yield (k, y[k])
|
||||
|
||||
def _create_stream(self, resource, namespace, wait_timeout):
|
||||
""" Create a stream of events for the object """
|
||||
w = None
|
||||
stream = None
|
||||
try:
|
||||
w = watch.Watch()
|
||||
w._api_client = self.client.client
|
||||
stream = w.stream(resource.get, serialize=False, namespace=namespace, timeout_seconds=wait_timeout)
|
||||
except KubernetesException as exc:
|
||||
self.fail_json(msg='Failed to initialize watch: {0}'.format(exc.message))
|
||||
return w, stream
|
||||
|
||||
def get_resource(self, resource):
|
||||
try:
|
||||
existing = resource.get(name=self.name, namespace=self.namespace)
|
||||
except Exception:
|
||||
existing = None
|
||||
|
||||
return existing
|
||||
|
||||
def _define_cloud_init(self, cloud_init_nocloud, template_spec):
|
||||
"""
|
||||
Takes the user's cloud_init_nocloud parameter and fill it in kubevirt
|
||||
API strucuture. The name of the volume is hardcoded to ansiblecloudinitvolume
|
||||
and the name for disk is hardcoded to ansiblecloudinitdisk.
|
||||
"""
|
||||
if cloud_init_nocloud:
|
||||
if not template_spec['volumes']:
|
||||
template_spec['volumes'] = []
|
||||
if not template_spec['domain']['devices']['disks']:
|
||||
template_spec['domain']['devices']['disks'] = []
|
||||
|
||||
template_spec['volumes'].append({'name': 'ansiblecloudinitvolume', 'cloudInitNoCloud': cloud_init_nocloud})
|
||||
template_spec['domain']['devices']['disks'].append({
|
||||
'name': 'ansiblecloudinitdisk',
|
||||
'volumeName': 'ansiblecloudinitvolume',
|
||||
'disk': {'bus': 'virtio'},
|
||||
})
|
||||
|
||||
def _define_interfaces(self, interfaces, template_spec):
|
||||
"""
|
||||
Takes interfaces parameter of Ansible and create kubevirt API interfaces
|
||||
and networks strucutre out from it.
|
||||
"""
|
||||
if interfaces:
|
||||
# Extract interfaces k8s specification from interfaces list passed to Ansible:
|
||||
spec_interfaces = []
|
||||
for i in interfaces:
|
||||
spec_interfaces.append(dict((k, v) for k, v in i.items() if k != 'network'))
|
||||
template_spec['domain']['devices']['interfaces'] = spec_interfaces
|
||||
|
||||
# Extract networks k8s specification from interfaces list passed to Ansible:
|
||||
spec_networks = []
|
||||
for i in interfaces:
|
||||
net = i['network']
|
||||
net['name'] = i['name']
|
||||
spec_networks.append(net)
|
||||
template_spec['networks'] = spec_networks
|
||||
|
||||
def _define_disks(self, disks, template_spec):
|
||||
"""
|
||||
Takes disks parameter of Ansible and create kubevirt API disks and
|
||||
volumes strucutre out from it.
|
||||
"""
|
||||
if disks:
|
||||
# Extract k8s specification from disks list passed to Ansible:
|
||||
spec_disks = []
|
||||
for d in disks:
|
||||
spec_disks.append(dict((k, v) for k, v in d.items() if k != 'volume'))
|
||||
template_spec['domain']['devices']['disks'] = spec_disks
|
||||
|
||||
# Extract volumes k8s specification from disks list passed to Ansible:
|
||||
spec_volumes = []
|
||||
for d in disks:
|
||||
volume = d['volume']
|
||||
volume['name'] = d['name']
|
||||
spec_volumes.append(volume)
|
||||
template_spec['volumes'] = spec_volumes
|
||||
|
||||
def execute_crud(self, kind, definition, template):
|
||||
""" Module execution """
|
||||
self.client = self.get_api_client()
|
||||
|
||||
disks = self.params.get('disks', [])
|
||||
memory = self.params.get('memory')
|
||||
labels = self.params.get('labels')
|
||||
interfaces = self.params.get('interfaces')
|
||||
cloud_init_nocloud = self.params.get('cloud_init_nocloud')
|
||||
machine_type = self.params.get('machine_type')
|
||||
template_spec = template['spec']
|
||||
|
||||
# Merge additional flat parameters:
|
||||
if memory:
|
||||
template_spec['domain']['resources']['requests']['memory'] = memory
|
||||
|
||||
if labels:
|
||||
template['metadata']['labels'] = labels
|
||||
|
||||
if machine_type:
|
||||
template_spec['domain']['machine']['type'] = machine_type
|
||||
|
||||
# Define cloud init disk if defined:
|
||||
self._define_cloud_init(cloud_init_nocloud, template_spec)
|
||||
|
||||
# Define disks
|
||||
self._define_disks(disks, template_spec)
|
||||
|
||||
# Define interfaces:
|
||||
self._define_interfaces(interfaces, template_spec)
|
||||
|
||||
# Perform create/absent action:
|
||||
definition = dict(self.merge_dicts(self.resource_definitions[0], definition))
|
||||
resource = self.find_resource(kind, self.api_version, fail=True)
|
||||
definition = self.set_defaults(resource, definition)
|
||||
return self.perform_action(resource, definition)
|
||||
Reference in New Issue
Block a user