From: Frank Brehm Date: Wed, 22 May 2024 15:57:19 +0000 (+0200) Subject: Implementing caching of vSphere VMs and templates. X-Git-Tag: 1.9.1^2~23 X-Git-Url: https://git.uhu-banane.de/?a=commitdiff_plain;h=13d0fc25785ae1128df5e80d6953bf7ca6f57378;p=pixelpark%2Fcreate-terraform.git Implementing caching of vSphere VMs and templates. --- diff --git a/lib/create_terraform/handler/__init__.py b/lib/create_terraform/handler/__init__.py index 4842ae7..a249a7c 100644 --- a/lib/create_terraform/handler/__init__.py +++ b/lib/create_terraform/handler/__init__.py @@ -46,7 +46,7 @@ from ..errors import AbortExecution from ..xlate import XLATOR -__version__ = '3.10.0' +__version__ = '4.0.0' LOG = logging.getLogger(__name__) _ = XLATOR.gettext @@ -86,7 +86,7 @@ class CreateTerraformHandler( steps = ( 'init', 'vmw-init', 'read-yaml', 'pdns-zones', 'vmw-test', 'collect-folders', - 'vmw-clusters', 'vmw-datastores', 'vmw-ds-clusters', 'vmw-networks', 'vmw-templates', + 'vmw-clusters', 'vmw-datastores', 'vmw-ds-clusters', 'vmw-vms', 'vmw-networks', 'vmw-templates', 'validate-yaml', 'validate-storage', 'validate-iface', 'validate-dns', 'perform-dns', 'project-dir', 'tf-files', 'ensure-vmw-folders', ) @@ -98,6 +98,7 @@ class CreateTerraformHandler( 'vmw-test': _('After testing VSPhere handlers.'), 'collect-folders': _('After collecting all VMWare and local folders.'), 'vmw-clusters': _('After collecting all VMWare clusters.'), + 'vmw-vms': _('After caching all VMWare VMs and templates.'), 'vmw-datastores': _('After collecting all VMWare datastores.'), 'vmw-ds-clusters': _('After collecting all VMWare datastore clusters.'), 'vmw-networks': _('After collecting all VMWare networks.'), @@ -140,6 +141,8 @@ class CreateTerraformHandler( self.vsphere_folders = [] + self.vsphere_vm_cache = [] + self.vsphere_user = None self.vsphere_password = None @@ -387,6 +390,7 @@ class CreateTerraformHandler( LOG.info(_("Retrieving information from vSphere.")) self.exec_vmw_clusters() + self.exec_cache_vmw_vms() self.exec_vmw_datastores() self.exec_vmw_ds_clusters() self.exec_vmw_networks() diff --git a/lib/create_terraform/handler/vmware.py b/lib/create_terraform/handler/vmware.py index 0ee2620..4e847cc 100644 --- a/lib/create_terraform/handler/vmware.py +++ b/lib/create_terraform/handler/vmware.py @@ -29,9 +29,11 @@ from fb_vmware.connect import VsphereConnection # Own modules from ..errors import AbortExecution +from ..slim_vm import SlimVm + from ..xlate import XLATOR -__version__ = '0.1.3' +__version__ = '0.2.0' LOG = logging.getLogger(__name__) _ = XLATOR.gettext @@ -53,14 +55,14 @@ class CrTfHandlerVmwMixin(): for vname in self.vsphere: self.vsphere[vname].get_datacenter() - LOG.debug(_("Collecting vSphere folders.")) + LOG.debug(_("Collecting used vSphere folders.")) self.vsphere_folders = [] for vm in self.vms: if vm.folder: if vm.folder not in self.vsphere_folders: self.vsphere_folders.append(vm.folder) self.vsphere_folders.sort(key=str.lower) - LOG.debug(_("Collected vSphere folders:") + "\n" + pp(self.vsphere_folders)) + LOG.debug(_("Collected used vSphere folders:") + "\n" + pp(self.vsphere_folders)) # Set project name and directory yfile = Path(yaml_file) @@ -243,6 +245,25 @@ class CrTfHandlerVmwMixin(): if self.stop_at_step == 'vmw-clusters': raise AbortExecution('vmw-clusters') + # -------------------------------------------------------------------------· + def exec_cache_vmw_vms(self): + + # if self.stop_at_step == 'vmw-vms': + # self.incr_verbosity() + + self.explore_vsphere_vms() + + if self.eval_errors: + msg = ngettext( + "Found one error in exploring vSphere VMs.", + "Found {n} errors in exploring vSphere VMs.", + self.eval_errors).format(n=self.eval_errors) + raise ExpectedHandlerError(msg) + + LOG.info(_("Finished step {!r}.").format('vmw-vms')) + if self.stop_at_step == 'vmw-vms': + raise AbortExecution('vmw-vms') + # -------------------------------------------------------------------------· def exec_vmw_datastores(self): @@ -428,57 +449,82 @@ class CrTfHandlerVmwMixin(): if self.stop_at_step == 'ensure-vmw-folders': raise AbortExecution('ensure-vmw-folders') + # -------------------------------------------------------------------------· + def explore_vsphere_vms(self): + + LOG.info(_("Exploring and caching all vSphere VMs and templates ...")) + + for vsphere_name in self.vsphere: + + re_vm = re.compile(r'.*') + vm_list = self.vsphere[vsphere_name].get_vms(re_vm, as_obj=True, stop_at_found=False) + + for vm in vm_list: + slim_vm = SlimVm(vsphere_name, vm.name, vm.path, is_template=vm.template) + self.vsphere_vm_cache.append(slim_vm) + + msg = ngettext( + 'Found one VM or template in vSphere.', + 'Found {nr} VMs and templates in vSphere.', len(self.vsphere_vm_cache)) + msg = msg.format(nr=len(self.vsphere_vm_cache)) + LOG.debug(msg) + + if self.verbose > 1: + msg = _("All explored vSphere VMs and templates:") + LOG.debug(msg + "\n" + pp(self.vsphere_vm_cache)) + # -------------------------------------------------------------------------· def explore_vsphere_templates(self): LOG.info(_("Exploring all vSphere templates ...")) - for vname in self.vsphere: + for vsphere_name in self.vsphere: - if vname not in self.vsphere_templates: - self.vsphere_templates[vname] = {} + if vsphere_name not in self.vsphere_templates: + self.vsphere_templates[vsphere_name] = {} - self.config.vsphere[vname].used_templates = [] + self.config.vsphere[vsphere_name].used_templates = [] for vm in self.vms: template_name = vm.vm_template if template_name: - if template_name not in self.config.vsphere[vname].used_templates: - self.config.vsphere[vname].used_templates.append(template_name) + if template_name not in self.config.vsphere[vsphere_name].used_templates: + self.config.vsphere[vsphere_name].used_templates.append(template_name) else: LOG.error(_("VM {!r} has not template defined.").format(vm.name)) self.eval_errors += 1 - msg = _("All {} VSPhere templates to explore:").format(vname) - msg += "\n" + pp(self.config.vsphere[vname].used_templates) + msg = _("All {} VSPhere templates to explore:").format(vsphere_name) + msg += "\n" + pp(self.config.vsphere[vsphere_name].used_templates) LOG.debug(msg) - for template_name in self.config.vsphere[vname].used_templates: + found_template = False + for template_name in self.config.vsphere[vsphere_name].used_templates: - if template_name in self.vsphere_templates[vname]: + if template_name in self.vsphere_templates[vsphere_name]: continue LOG.debug(_("Searching for template {t!r} in VSPhere {v!r} ...").format( - t=template_name, v=vname)) + t=template_name, v=vsphere_name)) re_vm = re.compile(r'^' + re.escape(template_name) + r'$', re.IGNORECASE) - vm_list = self.vsphere[vname].get_vms(re_vm, as_obj=True, stop_at_found=True) + vm_list = self.vsphere[vsphere_name].get_vms(re_vm, as_obj=True, stop_at_found=True) if vm_list: vm = vm_list[0] tname = vm.name.lower() - if tname not in self.vsphere_templates[vname]: - self.vsphere_templates[vname][template_name] = vm + if tname not in self.vsphere_templates[vsphere_name]: + self.vsphere_templates[vsphere_name][template_name] = vm else: LOG.error(_("Template {t!r} not found in VSPhere {v!r}.").format( - t=template_name, v=vname)) + t=template_name, v=vsphere_name)) self.eval_errors += 1 if self.verbose > 2: msg = _("All explored vSphere templates:") out_dict = {} - for vname in self.vsphere_templates: - out_dict[vname] = {} - for tname in self.vsphere_templates[vname]: - out_dict[vname][tname] = self.vsphere_templates[vname][tname].as_dict() + for vsphere_name in self.vsphere_templates: + out_dict[vsphere_name] = {} + for tname in self.vsphere_templates[vsphere_name]: + out_dict[vsphere_name][tname] = self.vsphere_templates[vsphere_name][tname].as_dict() msg += "\n" + pp(out_dict) LOG.debug(msg) diff --git a/lib/create_terraform/slim_vm.py b/lib/create_terraform/slim_vm.py new file mode 100644 index 0000000..6774a4e --- /dev/null +++ b/lib/create_terraform/slim_vm.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +@author: Frank Brehm +@contact: frank.brehm@pixelpark.com +@copyright: © 2024 by Frank Brehm, Berlin +@summary: A module for providing a slim VM object. +""" +from __future__ import absolute_import + +# Standard module +import logging + +# Third party modules +from fb_tools.obj import FbGenericBaseObject + +from .xlate import XLATOR + +__version__ = '0.1.0' +LOG = logging.getLogger(__name__) + +_ = XLATOR.gettext +ngettext = XLATOR.ngettext + + +# ============================================================================= +class SlimVm(FbGenericBaseObject): + """Class for encapsulation very basic data of a VM or a template in VMWare.""" + + # ------------------------------------------------------------------------- + def __init__(self, vs_name, name, path, is_template=False): + """Initialize the SlimVm object.""" + self._vs_name = None + self._name = None + self._path = '' + self._is_template = False + + self.vs_name = vs_name + self.name = name + self.path = path + self.is_template = is_template + + # ----------------------------------------------------------- + @property + def vs_name(self): + """Return the name of the vSphere of the VM or the template.""" + return self._vs_name + + @vs_name.setter + def vs_name(self, value): + if value is None: + raise TypeError(_('The vSphere name of a VM or template may not be None.')) + val = str(value).strip().lower() + if val == '': + raise ValueError(_('The vSphere name of a VM or template may not be empty.')) + + self._vs_name = val + + # ----------------------------------------------------------- + @property + def name(self): + """Return the name of the VM or the template.""" + return self._name + + @name.setter + def name(self, value): + if value is None: + raise TypeError(_('The name of a VM or template may not be None.')) + val = str(value).strip().lower() + if val == '': + raise ValueError(_('The name of a VM or template may not be empty.')) + + self._name = val + + # ----------------------------------------------------------- + @property + def path(self): + """Return the path in VSphere of the VM or the template.""" + return self._path + + @path.setter + def path(self, value): + if value is None: + self._path = '' + return + val = str(value).strip() + self._path = val + + # ----------------------------------------------------------- + @property + def is_template(self): + """Return, whether the object points to a template or a normal VM.""" + return self._is_template + + @is_template.setter + def is_template(self, value): + self._is_template = bool(value) + + # ------------------------------------------------------------------------- + def __repr__(self): + """Typecasting into a string for reproduction.""" + out = '<%s(' % (self.__class__.__name__) + + fields = [] + fields.append('vs_name={!r}'.format(self.vs_name)) + fields.append('name={!r}'.format(self.name)) + fields.append('path={!r}'.format(self.path)) + fields.append('is_template={!r}'.format(self.is_template)) + + out += ', '.join(fields) + ')>' + return out + + # ------------------------------------------------------------------------- + def as_dict(self, short=True): + """ + Transform the elements of the object into a dict. + + @param short: don't include local properties in resulting dict. + @type short: bool + + @return: structure as dict + @rtype: dict + """ + res = super(SlimVm, self).as_dict(short=short) + + res['vs_name'] = self.vs_name + res['name'] = self.name + res['path'] = self.path + res['is_template'] = self.is_template + + return res + + # ------------------------------------------------------------------------- + def __eq__(self, other): + """Compare for equality.""" + if not isinstance(other, SlimVm): + return False + + if self.vs_name.lower() != other.vs_name.lower(): + return False + + if self.name.lower() != other.name.lower(): + return False + + if self.path != other.PATH: + return False + + return True + +# ============================================================================= + +if __name__ == '__main__': + + pass + +# ============================================================================= + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4