From c0a04a80f2954523f90626d922309c7fb04b5dcc Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Wed, 16 May 2018 17:17:58 +0200 Subject: [PATCH] Handling post install errors --- lib/cr_vmware_tpl/app.py | 5 ++- lib/cr_vmware_tpl/handler.py | 84 +++++++++++++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/lib/cr_vmware_tpl/app.py b/lib/cr_vmware_tpl/app.py index e21c85b..64c037a 100644 --- a/lib/cr_vmware_tpl/app.py +++ b/lib/cr_vmware_tpl/app.py @@ -34,7 +34,7 @@ from .config import CrTplConfiguration from .handler import ExpectedHandlerError, CrTplHandler -__version__ = '0.5.1' +__version__ = '0.6.1' LOG = logging.getLogger(__name__) @@ -443,7 +443,8 @@ class CrTplApplication(PpBaseObject): LOG.info("Starting ...") try: - self.handler() + ret = self.handler() + self.exit(ret) except ExpectedHandlerError as e: self.handle_error(str(e), "Temporary VM") self.exit(5) diff --git a/lib/cr_vmware_tpl/handler.py b/lib/cr_vmware_tpl/handler.py index a062c47..1e25c14 100644 --- a/lib/cr_vmware_tpl/handler.py +++ b/lib/cr_vmware_tpl/handler.py @@ -36,7 +36,7 @@ from .obj import PpBaseObject from .config import CrTplConfiguration -__version__ = '0.8.2' +__version__ = '0.9.1' LOG = logging.getLogger(__name__) TZ = pytz.timezone('Europe/Berlin') @@ -170,6 +170,7 @@ class CrTplHandler(PpBaseObject): self.max_wait_for_shutdown = 600 self.rotate_only = False self.abort = False + self.postinstall_errors = None if initialized: self.initialized = True @@ -220,14 +221,19 @@ class CrTplHandler(PpBaseObject): "Could not find VM after creating.") self.poweron_vm() self.wait_for_finish_install() + self.get_postinstall_error() if self.abort: LOG.warn("Aborting after creation of template VM.") - LOG.warn("You are responsible yourself to clewaning up the VM!!!") + LOG.warn("You are responsible yourself to cleaning up the VM!!!") else: - self.post_install_tasks_ssh() - self.poweroff_vm() - self.change_mac_address() - if not self.abort: + if self.postinstall_errors: + self.purge_template_vm() + return 10 + else: + self.post_install_tasks_ssh() + self.poweroff_vm() + self.change_mac_address() + if not self.abort and not self.postinstall_errors: self.rotate_templates() if not self.rotate_only: self.rename_and_change_vm() @@ -236,6 +242,8 @@ class CrTplHandler(PpBaseObject): h=self.config.vsphere_host, p=self.config.vsphere_port)) Disconnect(self.service_instance) + return 0 + # ------------------------------------------------------------------------- def get_obj(self, content, vimtype, name): @@ -781,6 +789,70 @@ class CrTplHandler(PpBaseObject): raise ExpectedHandlerError( "SSH not available after {:0.1f} seconds, giving up.".format(duration)) + # ------------------------------------------------------------------------- + def get_postinstall_error(self): + + LOG.info("Trying to get possible post-installation errors ...") + + ssh = None + cmd = textwrap.dedent("""\ + if [ -f /root/postinst-error.txt ] ; then + cat /root/postinst-error.txt + fi + """) + + try: + + LOG.debug("Initializing paramiko SSHClient") + ssh = paramiko.SSHClient() + LOG.debug("Loading SSH system host keys.") + ssh.load_system_host_keys() + LOG.debug("Setting SSH missing host key policy to AutoAddPolicy.") + ssh.set_missing_host_key_policy(paramiko.client.AutoAddPolicy()) + + LOG.debug("Connecting to {h!r}, port {p} as {u!r} per SSH ...".format( + h=self.config.template_vm, p=self.ssh_port, u=self.ssh_user)) + ssh.connect( + self.config.template_vm, port=self.ssh_port, timeout=self.ssh_timeout, + username=self.ssh_user, key_filename=self.private_ssh_key) + + LOG.debug("Trying to read /root/postinst-error.txt ...") + if self.verbose > 1: + LOG.debug("Commands to execute:\n{}".format(cmd)) + + stdin, stdout, stderr = ssh.exec_command( + cmd, timeout=self.ssh_timeout) + + output = to_str(stdout.read()).strip() + err = to_str(stderr.read()).strip() + + LOG.debug("Output on STDERR:\n{}".format(err)) + + if output: + self.postinstall_errors = output + LOG.error("Got postinstall errors:\n{}".format(output)) + + finally: + if ssh: + if self.verbose > 2: + LOG.debug("Closing SSH connection.") + ssh.close() + + if self.postinstall_errors: + LOG.warn("Template VM {!r} has to be removed.".format(self.config.template_vm)) + + # ------------------------------------------------------------------------- + def purge_template_vm(self): + + self.poweroff_vm() + + LOG.info("Purging VM {!r} because of errors.".format(self.config.template_vm)) + vm = self.get_temp_tpl_vm() + task = vm.Destroy_Task() + self.wait_for_tasks([task]) + + LOG.warn("Successful removed VM {!r}.".format(self.config.template_vm)) + # ------------------------------------------------------------------------- def post_install_tasks_ssh(self): -- 2.39.5