def exit(self):
        tool.write_to_log("Exiting Job Scheduler Thread")
        self.__running = False

        if self.__parent and hasattr(self.__parent, 'js_thread'):
            self.__parent.js_thread.join()
            self.__parent.js_thread = None
 def __start_job(self, job_profile):
     tool.write_to_log("Job '{0}' is now starting".format(
         job_profile['Job_Name']))
     job_class = Job(deepcopy(job_profile))
     timeout = get_timeout(hours=job_profile['Timeout_HH'],
                           minutes=job_profile['Timeout_MM'])
     thread = Thread(target=process_job, args=(job_class, ))
     thread.daemon = True
     thread.start()
     self.__jobs[job_profile['Job_Name']] = [
         thread, job_class, timeout, self
     ]
    def start(self):
        tool.write_to_log("Starting Job Scheduler Thread")
        from time import sleep
        self.__running = True
        self.__jobs = dict()

        try:
            initiated = True

            while self.__running:
                job_names = local_config['Jobs'].keys()

                for job_name in job_names:
                    if job_name in local_config['Jobs'].keys():
                        job_profile = local_config['Jobs'][job_name]
                        self.__job_validate(job_profile, initiated)
                        self.__job_watch(job_profile)

                initiated = False
                sleep(1)
        except Exception as e:
            tool.write_to_log(format_exc(), 'critical')
            tool.write_to_log("Job Main - ECode '{0}', {1}".format(
                type(e).__name__, str(e)))
        finally:
            self.__kill_all_jobs()
            tool.write_to_log("Job Scheduler Thread has been stopped")
def remove_dir(dir_filepath):
    if exists(dir_filepath):
        from shutil import rmtree

        for filename in listdir(dir_filepath):
            file_path = join(dir_filepath, filename)
            try:
                if isfile(file_path) or islink(file_path):
                    unlink(file_path)
                elif isdir(file_path):
                    rmtree(file_path)
            except Exception as e:
                tool.write_to_log(
                    'Failed to delete %s. Reason: %s' % (file_path, e),
                    'warning')
                pass
 def email_results(self, err_msg=None):
     if self.__job_profile and self.__task_profiles:
         try:
             self.write_job_log("Job '%s' is sending e-mail to distros" %
                                self.__job_profile['Job_Name'])
             self.__err_msg = err_msg
             self.__package_tasks()
             self.__package_email()
             self.__package_attach()
             self.__email.send()
             self.write_job_log("Job '%s' is e-mail was sent successfully" %
                                self.__job_profile['Job_Name'])
         except Exception as e:
             tool.write_to_log(format_exc(), 'critical')
             tool.write_to_log("Email - ECode '{0}', {1}".format(
                 type(e).__name__, str(e)))
    def __kill_job(job, job_name, reason):
        if job and job_name and reason and not job[1].tasks_finished:
            message = "failed execution because %s" % reason

            try:
                if job[0].is_alive():
                    job[1].terminate(kill_thread=True)
                    job[0].join()

                job[1].email_results(message)
            except Exception as e:
                tool.write_to_log(format_exc(), 'critical')
                tool.write_to_log("Kill Job - ECode '{0}', {1}".format(
                    type(e).__name__, str(e)))
                pass
            finally:
                job[1].close_email()
    def terminate(self, kill_thread=False):
        from KGlobal.sql import SQLEngineClass
        self.__kill_thread = kill_thread

        if self.__sql_engine and isinstance(self.__sql_engine, SQLEngineClass):
            self.__sql_engine.close_connections(destroy_self=True)

        if self.__sub_proc and self.__sub_proc.poll() is None:
            tool.write_to_log(
                "Job '{0}' - Attempting to kill process thread {1}".format(
                    self.job_name, self.__sub_proc.pid))

            try:
                kill(self.__sub_proc.pid, -9)
            except Exception as e:
                self.write_job_log(format_exc())
                tool.write_to_log("Job '{0}' kill ECode '{1}', {2}".format(
                    self.job_name,
                    type(e).__name__, str(e)))
                pass

        self.__sql_engine = None
        self.__sub_proc = None
 def __init__(self, parent):
     tool.write_to_log("Initializing Job Scheduler")
     self.__parent = parent
    def __package_email(self):
        if self.__to_email and self.__job_profile['Job_Name']:
            from exchangelib import Message

            body = list()
            self.__email = Message(account=email_engine)
            names = [
                str(email.split('@')[0]).title() for email in self.__to_email
            ]

            if self.__to_email:
                self.__email.to_recipients = self.__gen_email_list(
                    self.__to_email)

            if self.__cc_email:
                self.__email.cc_recipients = self.__gen_email_list(
                    self.__cc_email)

            body.append('Happy {0} {1},\n'.format(
                datetime.today().strftime("%A"), '; '.join(names)))

            if self.__err_msg:
                tool.write_to_log(
                    "Job '{0}' failed job execution due to {1}".format(
                        self.__job_profile['Job_Name'], self.__err_msg))
                self.__email.subject = "<Job Failed> Job \"%s\"" % self.__job_profile[
                    'Job_Name']
                sub_body = "Job \"{0}\", {1}".format(
                    self.__job_profile['Job_Name'], self.__err_msg)
            else:
                tool.write_to_log("Job '%s' completed successfully" %
                                  self.__job_profile['Job_Name'])
                self.__email.subject = "Job \"%s\" completed successfully" % self.__job_profile[
                    'Job_Name']
                sub_body = "Job \"{0}\" completed successfully".format(
                    self.__job_profile['Job_Name'])

            body.append("{0}. Total job runtime was {1}.\n".format(
                sub_body, parse_time(self.job_start, datetime.now())))

            for task_profile in self.__task_profiles:
                if task_profile['Task_Type'] == 1:
                    task_type = 'Stored Proc'
                else:
                    task_type = 'Program'

                if task_profile['Task_Error']:
                    body.append(
                        '\t\u2022  {0} "{1}" <Failed Task> ({2}) [Err Code: {3}]'
                        .format(
                            task_type, task_profile['Task_Name'],
                            parse_time(task_profile['Task_Start'],
                                       task_profile['Task_End']),
                            task_profile['Task_Error'][0]))
                else:
                    body.append(
                        '\t\u2022  {0} "{1}" <Succeeded Task> ({2})'.format(
                            task_type, task_profile['Task_Name'],
                            parse_time(task_profile['Task_Start'],
                                       task_profile['Task_End'])))

            body.append("\nYour's Truly,\n")
            body.append("The BI Team")
            self.__email.body = '\n'.join(body)
    def __package_attach(self):
        if self.__attachments:
            from zipfile import ZipFile
            from exchangelib import FileAttachment
            from portalocker import Lock

            file_dir = join(attach_dir, datetime.today().__format__("%Y%m%d"))
            file_path = join(
                file_dir, '{0}_{1}.zip'.format(
                    hash(datetime.now().__format__("%I:%M:%S %p")),
                    self.__job_profile['Job_Name']))

            if not exists(file_dir):
                makedirs(file_dir)

            if exists(file_path):
                try:
                    remove(file_path)
                except Exception as e:
                    tool.write_to_log(
                        "Attach File Rem - ECode '{0}', {1}".format(
                            type(e).__name__, str(e)))
                    return

            zip_file = ZipFile(file_path, mode='w')

            try:
                for attachment in self.__attachments:
                    try:
                        if isfile(attachment) and exists(
                                attachment) and stat(attachment).st_size > 0:
                            zip_file.write(attachment, basename(attachment))
                    except Exception as e:
                        self.write_job_log(format_exc())
                        tool.write_to_log(
                            "Job '{0}' failed to zip file due to ECode '{1}', {2}"
                            .format(self.__job_profile['Job_Name'],
                                    type(e).__name__, str(e)))
                        pass
                    finally:
                        if isfile(attachment) and exists(
                                attachment) and stat(attachment).st_size > 0:
                            remove(attachment)
            except Exception as e:
                self.write_job_log(format_exc())
                tool.write_to_log(
                    "Job '{0}' failed to zip file in mainloop due to ECode '{1}', {2}"
                    .format(self.__job_profile['Job_Name'],
                            type(e).__name__, str(e)))
                pass
            finally:
                zip_file.close()

            if exists(file_path) and stat(file_path).st_size > 0:
                with Lock(file_path, 'rb') as f:
                    self.__email.attach(
                        FileAttachment(name=basename(file_path),
                                       content_type='zip',
                                       content=f.read(),
                                       is_inline=False))
            elif exists(file_path):
                remove(file_path)

                try:
                    unlink(file_dir)
                except Exception as e:
                    tool.write_to_log("Dir Unlink - ECode '{0}', {1}".format(
                        type(e).__name__, str(e)))
                    pass