]> Frank Brehm's Git Trees - pixelpark/create-vmware-tpl.git/commitdiff
Selecting a datastore to create the temporary VM.
authorFrank Brehm <frank.brehm@pixelpark.com>
Thu, 22 Mar 2018 16:25:33 +0000 (17:25 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Thu, 22 Mar 2018 16:25:33 +0000 (17:25 +0100)
lib/cr_vmware_tpl/app.py
lib/cr_vmware_tpl/handler.py

index 6ff4b8b402ec0e09e6bbfec23de05454273eb558..0e6ed1c5fa44d4104559752943be9f83951707ff 100644 (file)
@@ -32,9 +32,10 @@ from .obj import PpBaseObject
 
 from .config import CrTplConfiguration
 
-from .handler import TempVmExistsError, CrTplHandler
+from .handler import TempVmExistsError, NoDatastoreFoundError
+from .handler import CrTplHandler
 
-__version__ = '0.3.1'
+__version__ = '0.3.2'
 LOG = logging.getLogger(__name__)
 
 
@@ -432,7 +433,7 @@ class CrTplApplication(PpBaseObject):
 
         try:
             self.handler()
-        except TempVmExistsError as e:
+        except (TempVmExistsError, NoDatastoreFoundError) as e:
             self.handle_error(str(e), "Temporary VM")
             self.exit(5)
 
index 60eb9ac6cbe1c4c0c6935515105cfffafdf0ad97..aed1ee3d15d4db49a7f3f124a59ca1a5d7e0d51c 100644 (file)
@@ -13,6 +13,8 @@ import sys
 import os
 import logging
 import ssl
+import re
+import random
 
 # Third party modules
 import six
@@ -28,7 +30,7 @@ from .obj import PpBaseObject
 
 from .config import CrTplConfiguration
 
-__version__ = '0.3.1'
+__version__ = '0.3.2'
 LOG = logging.getLogger(__name__)
 
 
@@ -56,6 +58,29 @@ class TempVmExistsError(HandlerError):
         return msg
 
 
+# =============================================================================
+class NoDatastoreFoundError(HandlerError):
+    """Special error class for the case, that no SAN based data store was with
+        enogh free space was found."""
+
+
+    # -------------------------------------------------------------------------
+    def __init__(self, needed_bytes):
+
+        self.needed_bytes = int(needed_bytes)
+
+    # -------------------------------------------------------------------------
+    def __str__(self):
+
+        mb = float(self.needed_bytes) / 1024.0 / 1024.0
+        gb = mb / 1024.0
+
+        msg = (
+            "No SAN based datastore found with at least {m:0.0f} MiB == {g:0.1f} GiB "
+            "available space found.").format(m=mb, g=gb)
+        return msg
+
+
 # =============================================================================
 class CannotConnectError(HandlerError):
     """Special error class for the case, it cannot connect
@@ -83,6 +108,7 @@ class CrTplHandler(PpBaseObject):
     """
 
     max_depth = 10
+    re_local_ds = re.compile(r'^local[_-]', re.IGNORECASE)
 
     # -------------------------------------------------------------------------
     def __init__(
@@ -100,6 +126,7 @@ class CrTplHandler(PpBaseObject):
         self.config = config
         self.server_instance = None
         self.tpl_vm_folder = None
+        self.tpl_data_store = None
 
         if initialized:
             self.initialized = True
@@ -137,6 +164,7 @@ class CrTplHandler(PpBaseObject):
         try:
             self.ensure_vm_folder()
             self.check_for_temp_tpl_vm()
+            self.select_data_store()
         finally:
             LOG.debug("Disconnecting from vSphere host {h}:{p} ...".format(
                 h=self.config.vsphere_host, p=self.config.vsphere_port))
@@ -246,6 +274,59 @@ class CrTplHandler(PpBaseObject):
 
         return None
 
+    # -------------------------------------------------------------------------
+    def select_data_store(self):
+
+        LOG.debug((
+            "Selecting a SAN based datastore with at least {:0.1f} GiB available "
+            "space.").format(self.config.data_size_gb))
+
+        content = self.server_instance.RetrieveContent()
+        dc = self.get_obj(content, [vim.Datacenter], self.config.dc)
+
+        ds_list = []
+
+        for child in dc.datastoreFolder.childEntity:
+            self._get_data_stores(child, ds_list)
+
+        if not len(ds_list):
+            raise NoDatastoreFoundError(self.config.data_size)
+
+        LOG.debug("Found {} usable datastores.".format(len(ds_list)))
+        self.tpl_data_store = random.choice(ds_list)
+        LOG.info("Using datastore {!r} for volume of temporary VM to create.".format(
+            self.tpl_data_store.summary.name))
+
+    # -------------------------------------------------------------------------
+    def _get_data_stores(self, child, ds_list, depth=1):
+
+        if hasattr(child, 'childEntity'):
+            if depth > self.max_depth:
+                return
+            for sub_child in child.childEntity:
+                self._get_data_stores(sub_child, ds_list, depth + 1)
+            return
+
+        if isinstance(child, vim.Datastore):
+            #if not child.summary.multipleHostAccess:
+            if self.re_local_ds.match(child.summary.name):
+                if self.verbose > 2:
+                    LOG.debug("Datastore {!r} seems to be local.".format(child.summary.name))
+                return
+            free_bytes = child.summary.freeSpace
+            free_gbytes = float(free_bytes) / 1024.0 / 1024.0 / 1024.0
+            if free_bytes >= self.config.data_size:
+                if self.verbose > 2:
+                    LOG.debug("Found datastore {n!r} with {f:0.1f} GiB free space.".format(
+                        n=child.summary.name, f=free_gbytes))
+                ds_list.append(child)
+                return
+
+            LOG.debug("Datastore {n!r} has too less space ({f:0.1f} GiB available).".format(
+                n=child.summary.name, f=free_gbytes))
+
+        return
+
 
 # =============================================================================