]> Frank Brehm's Git Trees - pixelpark/create-vmware-tpl.git/commitdiff
Implemented waiting for SSH available
authorFrank Brehm <frank.brehm@pixelpark.com>
Wed, 11 Apr 2018 14:04:49 +0000 (16:04 +0200)
committerFrank Brehm <frank.brehm@pixelpark.com>
Wed, 11 Apr 2018 14:04:49 +0000 (16:04 +0200)
etc/create-vmware-template.ini.default
lib/cr_vmware_tpl/config.py
lib/cr_vmware_tpl/handler.py

index 091dc884e5d609d42d1c99cb9e3b1a3f66bc0580..1bf992578cc26818bc2182377e8b5cd15bb4fa3b 100644 (file)
@@ -28,7 +28,7 @@
 
 ;mac_address = 00:16:3e:54:ab:2b
 
-
+;max_wait_for_finish_install = 3600
 
 
 
index 2002c1e21fb5fd95bbdb18640f8e0dadf9ddc157..fcf924496c40d4e932d844c2b94ffcfa7e98a3a4 100644 (file)
@@ -26,7 +26,7 @@ from .errors import FunctionNotImplementedError, PpError
 
 from .obj import PpBaseObject
 
-__version__ = '0.4.5'
+__version__ = '0.5.1'
 LOG = logging.getLogger(__name__)
 
 
@@ -57,6 +57,9 @@ class CrTplConfiguration(PpBaseObject):
     default_ram_mb = 4 * 1024
     default_network = '192.168.88.0_23'
     default_mac_address = '00:16:3e:54:ab:2b'
+    default_max_wait_for_finish_install = 60 * 60
+    min_max_wait_for_finish_install = 3 * 60
+    max_max_wait_for_finish_install = 24 * 60 * 60
 
     # -------------------------------------------------------------------------
     def __init__(
@@ -76,6 +79,7 @@ class CrTplConfiguration(PpBaseObject):
         self.ram_mb = self.default_ram_mb
         self.network = self.default_network
         self.mac_address = self.default_mac_address
+        self.max_wait_for_finish_install = self.default_max_wait_for_finish_install
 
         self.encoding = 'utf-8'
 
@@ -146,6 +150,9 @@ class CrTplConfiguration(PpBaseObject):
         res['default_ram_mb'] = self.default_ram_mb
         res['default_network'] = self.default_network
         res['default_mac_address'] = self.default_mac_address
+        res['default_max_wait_for_finish_install'] = self.default_max_wait_for_finish_install
+        res['min_max_wait_for_finish_install'] = self.min_max_wait_for_finish_install
+        res['max_max_wait_for_finish_install'] = self.max_max_wait_for_finish_install
         res['data_size_mb'] = self.data_size_mb
         res['data_size_kb'] = self.data_size_kb
         res['data_size'] = self.data_size
@@ -208,7 +215,6 @@ class CrTplConfiguration(PpBaseObject):
                         if val > self.verbose:
                             self.verbose = val
 
-
             if section.lower() == 'vsphere':
 
                 for (key, value) in config.items(section):
@@ -266,6 +272,22 @@ class CrTplConfiguration(PpBaseObject):
                         v = value.strip().lower()
                         if v:
                             self.mac_address = v
+                    if key.lower() == 'max_wait_for_finish_install':
+                        v = float(value)
+                        if v < self.min_max_wait_for_finish_install:
+                            LOG.err((
+                                "Value {val} for max_wait_for_finish_install is less than {minval}, "
+                                "using {default} seconds.").format(val=v,
+                                    minval=self.min_max_wait_for_finish_install,
+                                    default=self.default_max_wait_for_finish_install))
+                        elif v > self.max_max_wait_for_finish_install:
+                            LOG.err((
+                                "Value {val} for max_wait_for_finish_install is greater than {maxval}, "
+                                "using {default} seconds.").format(val=v,
+                                    maxval=self.max_max_wait_for_finish_install,
+                                    default=self.default_max_wait_for_finish_install))
+                        else:
+                            self.max_wait_for_finish_install = v
 
 
 # =============================================================================
index 727a0ca392c7221bd18f2f0bd546ff6f8c5a9d50..27a7229b4c76008595a342929839acd6d15e9b70 100644 (file)
@@ -37,7 +37,7 @@ from .obj import PpBaseObject
 
 from .config import CrTplConfiguration
 
-__version__ = '0.6.1'
+__version__ = '0.6.2'
 LOG = logging.getLogger(__name__)
 TZ = pytz.timezone('Europe/Berlin')
 
@@ -633,6 +633,88 @@ class CrTplHandler(PpBaseObject):
             cur_duration = cur_time - self.ts_start_install
         print('', flush=True)
 
+        LOG.debug("Waiting for SSH available ...")
+        print('   ==> ', end='', flush=True)
+
+        addr_infos = socket.getaddrinfo(
+            self.config.template_vm, 22, socket.AF_INET, socket.SOCK_STREAM)
+        if self.verbose > 1:
+            LOG.debug("Got following address_infos for {h!r}, IPv4 TCP port 22:\n{ai}".format(
+                h=self.config.template_vm, pp(addr_infos)))
+        if not addr_infos:
+            raise HandlerError("Did not get address infos for {!r}, IPv4 TCP port 22.".format(
+                self.config.template_vm))
+
+        addr_info = random.choice(addr_infos)
+        LOG.debug("Using address info: {}".format(pp(addr_info)))
+        family, socktype, proto, canonname, sockaddr = addr_info
+
+        ssh_available = False
+        cur_duration = cur_time - self.ts_start_install
+        cur_time = time.time()
+        last_dot = cur_time
+        i = 0
+        first = True
+        while not ssh_available and cur_duration <= self.config.max_wait_for_finish_install:
+
+            if not first:
+                time.sleep(self.interval_poll)
+            else:
+                first = False
+
+            cur_time = time.time()
+            cur_duration = cur_time - self.ts_start_install
+            if (cur_time - last_dot) >= self.interval_dot:
+                print('.', end='', flush=True)
+                i += 1
+                if i >= 60:
+                    print('', flush=True)
+                    print('       ', end='', flush=True)
+                    i = 0
+                last_dot = cur_time
+
+            if self.verbose > 2:
+                LOG.debug("Trying to connect to {a} via TCP port {p} ...".format(
+                    a=sockaddr[0], p=sockaddr[1]))
+
+            try:
+                sock = socket.socket(family, socktype, proto)
+            except socket.error as e:
+                sock = None
+                LOG.warn("Error creating socket: {}".format(e))
+                continue
+
+            try:
+                sock.connect(sockaddr)
+            except socket.error as e:
+                sock.close()
+                sock = None
+                if self.verbose > 2:
+                    LOG.debug("Could not connect: {}".format(e))
+                continue
+
+            LOG.info("Connected to {a} via TCP port {p} ...".format(
+                a=sockaddr[0], p=sockaddr[1]))
+            data = sock.recv(4096)
+            if data:
+                msg = to_str(data).strip()
+                LOG.info("Got banner: {}".format(msg))
+            sock.close()
+            sock = None
+            ssh_available = True
+            self.ts_finish_install = time.time()
+
+        duration = self.ts_finish_install - self.ts_start_install
+        minutes = int(int(duration) / 60)
+        seconds = duration - float(minutes * 60)
+
+        LOG.info("Needed {m} minutes and {s:0.1f} seconds.".format(
+            m=minutes, s=seconds))
+
+        if not ssh_available:
+            raise ExpectedHandlerError(
+                "SSH not available after {:0.1f} seconds, giving up.".format(duration))
+
 # =============================================================================
 
 if __name__ == "__main__":