from .config import CrTplConfiguration
-__version__ = '0.7.3'
+__version__ = '0.7.4'
LOG = logging.getLogger(__name__)
TZ = pytz.timezone('Europe/Berlin')
self.ssh_user = 'root'
self.ssh_timeout = 30
self.max_wait_for_shutdown = 600
+ self.rotate_only = True
if initialized:
self.initialized = True
self.ensure_vm_folder()
self.check_for_temp_tpl_vm()
self.select_data_store()
- self.check_network()
- self.create_vm()
- self.tpl_vm = self.get_temp_tpl_vm()
- if not self.tpl_vm:
- raise HandlerError(
- "Could not find VM after creating.")
- self.poweron_vm()
- self.wait_for_finish_install()
- self.post_install_tasks_ssh()
- self.poweroff_vm()
- self.rename_and_change_vm()
+ if not self.rotate_only:
+ self.check_network()
+ self.create_vm()
+ self.tpl_vm = self.get_temp_tpl_vm()
+ if not self.tpl_vm:
+ raise HandlerError(
+ "Could not find VM after creating.")
+ self.poweron_vm()
+ self.wait_for_finish_install()
+ self.post_install_tasks_ssh()
+ self.poweroff_vm()
+ self.rotate_templates()
+ if not self.rotate_only:
+ self.rename_and_change_vm()
finally:
LOG.debug("Disconnecting from vSphere host {h}:{p} ...".format(
h=self.config.vsphere_host, p=self.config.vsphere_port))
return None
+ # -------------------------------------------------------------------------
+ def get_templates(self):
+
+ templates = []
+
+ content = self.service_instance.RetrieveContent()
+ dc = self.get_obj(content, [vim.Datacenter], self.config.dc)
+
+ for child in dc.vmFolder.childEntity:
+ tpl_list = self._get_templates(child)
+ if tpl_list and len(tpl_list):
+ templates.extend(tpl_list)
+
+ return templates
+
+ # -------------------------------------------------------------------------
+ def _get_templates(self, child, depth=1):
+
+ tpl_list = []
+
+ if hasattr(child, 'childEntity'):
+ if depth > self.max_depth:
+ return None
+ templates = []
+ for sub_child in child.childEntity:
+ tpl_list = self._get_templates(sub_child, depth + 1)
+ if tpl_list and len(tpl_list):
+ templates.extend(tpl_list)
+ return templates
+
+ if hasattr(child, 'summary'):
+ summary = child.summary
+ vm_name = summary.config.name
+ if summary.config.template and vm_name.startswith(self.config.template_name):
+ tpl_list.append(child)
+
+ return tpl_list
+
# -------------------------------------------------------------------------
def check_network(self):
"VM {h!r} was not shut down after {t:0.1f} seconds, current state is {s!r}.".format(
h=self.config.template_vm, t=cur_diff, s=guest_state))
+ # -------------------------------------------------------------------------
+ def rotate_templates(self):
+
+ LOG.info("Searching for existing templates and rotate them ...")
+ re_is_numeric = re.compile(r'^\s*(\d+)\s*$')
+
+ templates = self.get_templates()
+ templates_ts = {}
+ templates_sorted = []
+
+ if not templates:
+ LOG.info("Did not found any existing templates.")
+ return
+
+ LOG.debug("Found {} existing templates.".format(len(templates)))
+ for template in templates:
+ tpl_name = template.summary.config.name
+ val_map = {}
+ for extra_cfg in template.config.extraConfig:
+ key = extra_cfg.key
+ value = extra_cfg.value
+ val_map[key] = value
+ created = time.time()
+ if val_map['created'] and re_is_numeric.match(val_map['created']):
+ created = float(val_map['created'])
+ ts_created = datetime.datetime.fromtimestamp(created, tz=TZ)
+ LOG.debug("Found template {n!r}, created: {ts}.".format(
+ n=tpl_name, ts=ts_created.isoformat(' ')))
+ if self.verbose > 2:
+ LOG.debug("Template Summary Config:\n{}".format(template.summary.config))
+ LOG.debug("Template Extra Config:\n{}".format(pp(val_map)))
+
+ templates_ts[tpl_name] = created
+
+ for tpl_name in sorted(templates_ts.keys(), key=lambda tpl: templates_ts[tpl]):
+ templates_sorted.append(tpl_name)
+
+ LOG.debug("Templates sorted by creation date:\n{}".format(
+ pp(templates_sorted)))
+ templates_sorted.reverse()
+ templates_to_remove = []
+ i = 0
+ for tpl_name in templates_sorted:
+ if i > self.config.max_nr_templates_stay - 2:
+ templates_to_remove.append(tpl_name)
+ i += 1
+ templates_to_remove.reverse()
+ LOG.debug("Templates to remove:\n{}".format(pp(templates_to_remove)))
+
+ for template in templates:
+ tpl_name = template.summary.config.name
+ if tpl_name in templates_to_remove:
+ LOG.info("Removing template {!r} ...".format(tpl_name))
+ task = template.Destroy_Task()
+ self.wait_for_tasks([task])
+ LOG.debug("Successful removed template {!r}.".format(tpl_name))
+ continue
+ if tpl_name.strip().lower() == self.config.template_name.strip().lower():
+ created = templates_ts[tpl_name]
+ ts_created = datetime.datetime.fromtimestamp(created, tz=TZ)
+ new_name = tpl_name + '.' + ts_created.strftime('%Y-%m-%d_%H-%M-%S')
+ LOG.info("Renaming template {o!r} => {n!r} ...".format(
+ o=tpl_name, n=new_name))
+ task = template.Rename_Task(new_name)
+ self.wait_for_tasks([task])
+ LOG.debug("Successful renamed template into {!r}.".format(new_name))
+
# -------------------------------------------------------------------------
def rename_and_change_vm(self):