async def manage_schedule(context, conn, app): username = context["username"] if context["schedule"] or context["window"]: await set_schedule(username, conn, context.get("schedule"), context.get("window")) schedule, window = await get_schedule(username, conn) print("New schedule for user %s: %s (within %s hour(s))" % (username, get_description(schedule), window)) regenerate_reminder_for_user( schedule, username, window, datetime.now(pytz.timezone(context["timezone"])), app, ) else: row = await get_schedule(username, conn) if not row: print( "User %s has no schedule. Set one with e.g. " '/phb schedule --username %s --schedule "0 9 * * 1-5" --window 3' % (username, username)) return schedule, window = row print("User %s's schedule: %s (within %d hour(s))" % (username, get_description(schedule), window))
def test_second_minutes_hours_intervals(self): self.assertEqual(("Seconds 5 through 10 past the minute, " "minutes 30 through 35 past the hour, " "between 10:00 AM and 12:59 PM"), get_description("5-10 30-35 10-12 * * *", self.options))
def cron_translate(self, cron_slices): '''Translates cron job into human redable''' raw_result = get_description(cron_slices) final_result = [x.strip() for x in raw_result.split(',')] return final_result
def test_day_of_week_modifier_with_sunday_start_one(self): options = Options() options.day_of_week_start_index_zero = False self.assertEqual("At 12:23 PM, on the second Sunday of the month", get_description("23 12 * * 1#2", options))
def test_between_with_interval(self): self.assertEqual(( "Every 03 minutes, minutes 02 through 59 past the hour, " "at 01:00 AM, 09:00 AM, and 10:00 PM, between day 11 and 26 of the month, " "January through June"), get_description("2-59/3 1,9,22 11-26 1-6 ?"))
def test_every_2_day_of_the_week_in_range_with_sunday_start_one(self): options = Options() options.day_of_week_start_index_zero = False self.assertEqual( "Every second, every 2 days of the week, Monday through Friday", get_description("* * * ? * 2-6/2", options))
def get_schedule(service_type): import json import pandas as pd from cron_descriptor import get_description data = [] for key, info in gramex.conf.get(service_type, {}).items(): entry = dict(info) entry['name'] = key entry['args'] = json.dumps(entry.get('args', [])) entry['kwargs'] = json.dumps(entry.get('kwargs', {})) entry['schedule'] = '' if key not in gramex.service[service_type]: entry['schedule'] = 'NA' data.append(entry) continue schedule = gramex.service[service_type][key] entry['next'] = schedule.next * 1000 if schedule.next else None if hasattr(schedule, 'cron_str'): cron = schedule.cron_str # cron_descriptor requires year to start with a number if cron.endswith(' *'): cron = cron[:-2] entry['schedule'] = get_description(cron) entry['schedule'] += ' UTC' if schedule.utc else '' entry['startup'] = 'Y' if entry.get('startup', False) else '' entry['thread'] = 'Y' if entry.get('thread', False) else '' data.append(entry) return pd.DataFrame(data)
def test_minutes_past_the_hour_range(self): self.assertEqual(("At 30 minutes past the hour, " "between 10:00 AM and 01:59 PM, " "only on Wednesday and Friday"), get_description("0 30 10-13 ? * WED,FRI", self.options))
def activate_cron_job(cronjob_from_request, cron_job): cronjob_raw_expression = cron_job.expression cronjob_converted_expression = get_description(cronjob_raw_expression) script_command = cron_job.command if (cronjob_from_request['log']['logFile'] & cronjob_from_request['log']['sendMail']): command = MyCronTab.cmd_woutput_log_mail( script_command, str(cron_job.id), cronjob_from_request['description']) elif (cronjob_from_request['log']['sendMail']): command = MyCronTab.cmd_woutput_mail( script_command, cronjob_from_request['description']) elif (cronjob_from_request['log']['logFile']): command = MyCronTab.cmd_woutput_log(script_command, str(cron_job.id)) status = "On Hold" if (platform.system() == 'Windows'): cron = CronTab() script_path = '' else: cron = CronTab(user='******') script_body = MyCronTab.create_cron_shell_script(cron_job.id, command) script_path = MyCronTab.write_cron_shell_file(cron_job.id, script_body) job = cron.new(command='/bin/bash {0}'.format(script_path), comment=str(cron_job.id)) job.setall(cronjob_raw_expression) print("job: ", job) print("job.is_valid? ", job.is_valid()) if job.is_valid(): status = "Enabled" cron.write(user='******') nextRun = datetime.datetime.now().strftime("%Y-%m-%d") return status
def hf_schedule(self) -> str: sch = self.schedule_as_string if "seconds" in sch and self.seconds: result = f"Every {self.seconds // 60} minutes" else: result = get_description(sch) result = result.replace("00:00 AM", "midnight") return result
def convert_cron_job(): cronjob_from_request = request.get_json() cronjob_to_convert = cronjob_from_request['expression'] print("cronjob_to_convert", cronjob_to_convert) try: converted = get_description(cronjob_to_convert) return jsonify(converted_cron_job=converted, status="ok") except Exception: return jsonify(converted_cron_job="", status="error")
def get_readable_cron(self): """If the job is scheduled, return the cron syntax and a human readable version of the cron syntax.""" periodic_task = self.get_periodic_task() if periodic_task: crontab_lst = str(periodic_task.crontab).split(" ") crontab = " ".join(crontab_lst[:len(crontab_lst) - 2]) return crontab, get_description(crontab) else: return "", "Manual"
async def get_all_schedules(context, conn): async with conn.execute( "SELECT username, schedule, window FROM schedule", ) as cur: schedules = await cur.fetchall() if not schedules: print("No users registered.") print("Standup schedules: ") for username, schedule, window in schedules: print(" * %s: %s (within %d hour(s))" % (username, get_description(schedule), window))
def post(self): try: cron_expression = request.form.get('expression', None) if cron_expression: expression = get_description(cron_expression, options=self.options) return {'description': str(expression)}, 200 else: return make_response(('', 200)) except Exception as e: return {'err': 'not valid %s' % e}, 500
def checktimeplan(self): """Checks timeplan and prints description""" valid = crontab.CronSlices.is_valid(self.jobtimeplan) if valid: timedesc = get_description(self.jobtimeplan) lineprint("Your timeplan will run " + timedesc) else: lineprint("Timeplan is not valid..") return valid
def validate_cron(cron_str): valid_chars = '-/,*0123456789 ' e = t('Невалидная нотация. Строка должна содержать только знаки {0}' ', и четыре одинарных пробела. Удобно настроить и скопировать строку' ' можно здесь{1}') e = e.format(valid_chars, ' - https://crontab.guru/') try: pycron.is_now(cron_str) cron_descriptor.get_description(cron_str) except Exception: raise ValidationError(e) spaces_counter = 0 for char in cron_str: if char == ' ': spaces_counter += 1 if char not in valid_chars: raise ValidationError(e) if spaces_counter != 4: raise ValidationError(e) return cron_str
def build_schedule_html(html_top: str = "<div>", html_bottom: str = "</div>") -> str: """Create a basic HTML table with the currently scheduled jobs. Args: html_top (str, optional): HTML to go before the table. Defaults to "<div>". html_bottom (str, optional): HTML to go at hte end of the table. Defaults to "</div>". Returns: str: HTML code. """ # Ensure scheduler is shut down, then re-add jobs and retrieve scheduled jobs from okr/scrapers/scheduler.py scheduler.setup() scheduler.scheduler.shutdown() scheduler.add_jobs() jobs_list = scheduler.scheduler.get_jobs() options = Options() options.locale_code = "de_DE" options.use_24hour_time_format = True # parse and convert job information into list table_lines = [] for job in jobs_list: cron_expression = " ".join(map(str, reversed(job.trigger.fields[1:]))) table_lines.append([ parse_job_info_method(job), get_description(cron_expression, options=options), ]) # sort list by module and reformat to a module.method format (instead of library.module.method) formatted_list = sorted(table_lines, key=itemgetter(0)) for entry in formatted_list: args_idx = entry[0].index("(") path = entry[0][:args_idx] rest = entry[0][args_idx:] path = ".".join(path.split(".")[-2:]) entry[0] = f"{path}{rest}" # convert jobs list into HTML table table_contents = tabulate( formatted_list, headers=["Aufgerufene Methode", "Zeitschema"], tablefmt="html", ) return str(html_top + table_contents + html_bottom)
def cron_check(self, setall_string, command): desc = None is_valid = False try: desc = get_description(setall_string) if desc: is_valid = True if not command.startswith('curl'): error = 'Only curl allowed!' except Exception: pass return is_valid, desc
def handle(self, arguments, user, **kwargs): if not arguments: raise exceptions.HandleError( 'You need to provide a crontab expression such as `1 * 2 * *`', code='missing_arg') tz = arguments try: description = cron_descriptor.get_description(arguments) except cron_descriptor.FormatException as e: raise exceptions.HandleError( '{0} is not a valid crontab expression: {1}'.format( arguments, str(e)), code='invalid_arg') return {'description': description, 'crontab': arguments}
def describe_cron(request): cron_str = request.GET.get('cron_str', '') try: err = '' res = cron_descriptor.get_description(cron_str) except Exception as e: err = e res = 'Невалидный крон' return JsonResponse({ "e": str(err), "cron_verb": res }, safe=False, json_dumps_params={ 'indent': 4, 'ensure_ascii': False })
def get_scheduled_jobs(self): # Grab job templates run_list = self.get('/jobs/list')['jobs'] # Filter all the jobs that have a schedule defined scheduled_jobs = filter(lambda x: x['settings'].has_key('schedule'), run_list) jobs_list = [] for x in scheduled_jobs: y = dict() y['creator_user_name'] = x['creator_user_name'] y['job_id'] = x['job_id'] y['job_name'] = x['settings']['name'] y['created_time'] = datetime.datetime.fromtimestamp( x['created_time'] / 1000.0).strftime('%Y-%m-%d %H:%M:%S.%f') y['schedule'] = get_description( x['settings']['schedule']['quartz_cron_expression']) jobs_list.append(y) return jobs_list
def parse_cron(expression: str) -> Tuple[str, str]: if '?' in expression: raise InvalidCronException(f"Cannot parse the cron expression: '?' symbols are not allowed\n" f"Please use https://crontab.guru/#{expression.replace(' ', '_')} as a reference.") try: human_readable_description = get_description(expression) aws_cron = _cron_to_aws_cron(expression) except FormatException as e: raise InvalidCronException(f"Cannot parse the cron expression: {str(e)}\n You can find out what part of your " "expression is not written in a standard notation by following this link " f"https://crontab.guru/#{expression.replace(' ', '_')}.") except ValueError as e: if 'too many values to unpack (expected 5)' in str(e): raise InvalidCronException("Currently we support only cron expressions that consist of 5 parts. " "Your expression had more. " "If you have any questions please shoot an email at [email protected]") else: raise e return aws_cron, human_readable_description
def format_trigger(trigger: Union[CronTrigger, DateTrigger]) -> Text: """ Format a trigger to human readable format. """ if isinstance(trigger, CronTrigger): trigger_fields = {field.name: str(field) for field in trigger.fields} description = remove_first_cap( cron_descriptor.get_description( f"{trigger_fields['minute']} {trigger_fields['hour']} {trigger_fields['day']} " f"{trigger_fields['month']} {trigger_fields['day_of_week']}"). replace("only on", "every")) if trigger_fields["day"] == "*" and trigger_fields[ "day_of_week"] == "*": description = f"{description}, every day" elif trigger_fields["week"].startswith("*/"): week_interval = int(trigger_fields["week"][2:]) week_interval_ordinal = ("other" if week_interval == 2 else format_ordinal(week_interval)) description = f"{description}, every {week_interval_ordinal} week" return description return trigger.run_date.strftime("on %A %B %-d at %I:%M %p")
def generate_cron_job(session, cronjob_to_save, status, nextRun): if cronjob_to_save["creationDate"] is None: cronjob_to_save["creationDate"] = datetime.datetime.now().strftime( "%Y-%m-%d, %H:%M:%S") nextRun = datetime.datetime.now().strftime("%Y-%m-%d, %H:%M:%S") #expression = cronjob_to_save["minute"]+" "+ cronjob_to_save["hour"]+" "+cronjob_to_save["day"]+" "+cronjob_to_save["month"]+" "+cronjob_to_save["weekDay"] expression = cronjob_to_save["expression"] schedule = get_description(expression) cron_job = CronJob( datetime.datetime.now(), cronjob_to_save["command"], cronjob_to_save["type"], schedule, expression, cronjob_to_save["lastRun"], status, nextRun, ) session.add(cron_job) session.flush() print(cron_job.id) return cron_job, ' was scheduled successfully', True
def get_message(self, session, item): failed_task_attachments = None if isinstance(item, WorkflowInstance): item_type = 'Workflow' name = item.workflow_name failed_tasks = session.query(TaskInstance)\ .filter(TaskInstance.workflow_instance_id == item.id, TaskInstance.status == 'failed')\ .all() failed_task_attachments = [] for failed_task in failed_tasks: failed_task_attachments.append({ 'title': 'Failed Workflow Task', 'color': '#ff0000', 'fields': [{ 'title': 'Task', 'value': failed_task.task_name }, { 'title': 'ID', 'value': failed_task.id }, { 'title': 'Number of Attempts', 'value': failed_task.attempts }, { 'title': 'Logs', 'value': self.get_log_url(failed_task) }] }) else: item_type = 'Task' name = item.task_name attachments = [{ 'title': '{} Failure'.format(item_type), 'text': '<!channel> A {} in Taskflow failed'.format(item_type.lower()), 'color': '#ff0000', 'fields': [{ 'title': item_type, 'value': name, 'short': False }, { 'title': 'ID', 'value': item.id }, { 'title': 'Priority', 'value': item.priority }, { 'title': 'Scheduled Run Time', 'value': '{:%Y-%m-%d %H:%M:%S}'.format(item.run_at) }, { 'title': 'Start Time', 'value': '{:%Y-%m-%d %H:%M:%S}'.format(item.started_at) }, { 'title': 'Failure Time', 'value': '{:%Y-%m-%d %H:%M:%S}'.format(item.ended_at) }] }] if item.scheduled: if isinstance(item, WorkflowInstance): schedulable = self.taskflow.get_workflow(item.workflow_name) else: schedulable = self.taskflow.get_task(item.task_name) attachments[0]['fields'].append({ 'title': 'Schedule', 'value': '{} ({})'.format(get_description(schedulable.schedule), schedulable.schedule) }) if failed_task_attachments: attachments += failed_task_attachments else: attachments[0]['fields'].append({ 'title': 'Number of Attempts', 'value': item.attempts }) attachments[0]['fields'].append({ 'title': 'Logs', 'value': self.get_log_url(item) }) return {'attachments': attachments}
def schedule(self): # FIXME this is a mess om = get_omega(self.args) name = self.args.get('<name>') at = self.args.get('--at') # get interval specs if at: hour, minute = at.split(':') else: hour = self.args.get('--hour') minute = self.args.get('--minute') weekday = self.args.get('--weekday') monthday = self.args.get('--monthday') month = self.args.get('--month') delete = self.args.get('delete') show = self.args.get('show') spec = self.args.get('--cron') next_n = self.args.get('--next') interval = self.args.get('<interval>') # by default we show if no interval is specified show = show or not any(s for s in (weekday, monthday, month, hour, minute, interval, spec)) # print current schedule and triggers run_at, triggers = om.jobs.get_schedule(name, only_pending=True) if run_at: human_sched = get_description(run_at) self.logger.info("Currently {name} is scheduled at {human_sched}".format(**locals())) if next_n: self.logger.info("Given this existing interval, next {next_n} times would be:".format(**locals())) for time in om.jobs.Schedule.from_cron(run_at).next_times(int(next_n)): self.logger.info(" {}".format(time)) else: self.logger.info("Currently {name} is not scheduled".format(**locals())) # show current triggers if triggers: trigger = triggers[-1] if trigger['status'] == 'PENDING': event = trigger['event'] self.logger.info("{name} is scheduled to run next at {event}".format(**locals())) # delete if currently scheduled if delete: if run_at or triggers: answer = self.ask("Do you want to delete this schedule?", options='Y/n', default='y') should_drop = answer.lower().startswith('y') return om.jobs.drop_schedule(name) if should_drop else None # create new schedule if not (show or delete): if interval: try: # nlp text-like spec = om.jobs.Schedule(interval).cron except Exception as e: self.logger.info(f"Cannot parse {interval}, error was {e}") raise if not spec: cron_repr = ('{0._orig_minute} {0._orig_hour} {0._orig_day_of_month} ' '{0._orig_month_of_year} {0._orig_day_of_week}') sched = om.jobs.Schedule(minute=minute or '*', hour=hour or '*', monthday=monthday or '*', weekday=weekday or '*', month=month or '*') cron_sched = sched.cron else: cron_sched = spec human_sched = get_description(cron_sched) if next_n: self.logger.info("Given this new interval, next {next_n} times would be:".format(**locals())) for time in om.jobs.Schedule.from_cron(cron_sched).next_times(int(next_n)): self.logger.info(" {}".format(time)) text = "Do you want to schedule {name} at {human_sched}?".format(**locals()) answer = self.ask(text, options="Y/n", default='y') if answer.lower().startswith('n'): self.logger.info('Ok, not scheduled. Try again.') return self.logger.info('{name} will be scheduled to run {human_sched}'.format(**locals())) om.jobs.schedule(name, run_at=cron_sched, last_run=datetime.datetime.now())
def crontab_humanized(self) -> str: return get_description(self.crontab)
def text(self): """ return the human readable representation of the schedule """ from cron_descriptor import get_description return get_description(self.cron)
def handle_command(user, command, channel): """ Executes bot command if the command is known Args: user: Slack user ID command: Command string channel: Originating Slack channel """ # Default response is help text for the user default_response = "Sorry, I am not sure what you mean. Try _*@Xarvis help*_ to see what I can help you with\n" # Finds and executes the given command, filling in response response = None # This is where you start to implement more commands! if command.lower().startswith("schedule "): command_split = command.split("schedule ") if command_split[1].lower().startswith("list"): response = "*Scheduled jobs*\n" for key in JOBS: response += "- " + JOBS[key]["title"] + "\n" else: partial_reponse = "" for key in JOBS: description = pretty_cron.prettify_cron(JOBS[key]["sequence"]) if description == JOBS[key]["sequence"]: description = get_description(description) description = description[0].lower() + description[1:] if command_split[1].lower() in JOBS[key]["title"].lower( ) or JOBS[key]["title"].lower() in command_split[1].lower(): partial_reponse += "*" + JOBS[key]["title"] + "*\n" \ "- Runs " + description + " (ET)\n" if len(partial_reponse) > 0: response = "Job scheduled time(s)\n" + partial_reponse elif command.lower().startswith("help"): response = "Hey there, following are the queries that I am trained to help you with as of now,\n" \ "- *schedule list* - _Get a list of cron pattern based scheduled jobs stored_\n" \ "- *schedule <job_name>* - _Get the scheduled time of a specific job_\n" \ "- *holidays* - _Get the list of US holidays for the year_\n" \ "- *calc <expression>* - _Do a calculation_\n" \ "- *execute <job_name> <optional parameters>* - _Execute a predifined job_\n" \ "Use *@Xarvis _command_* to ask me something" elif command.lower().startswith("holidays"): now = datetime.datetime.now() response = "US public holidays\n" for date, name in sorted(holidays.US(years=now.year).items()): response += "- " + "*" + date.strftime( "%A") + "*, " + date.strftime("%B %d ") + date.strftime( ", %Y") + ": " + name + "\n" elif "thank" in command.lower() or "thanks" in command.lower(): response = "You are welcome <@" + user + ">" elif command.lower().startswith("calc "): command_split = command.split("calc ") try: result = eval(command_split[1]) if isinstance(result, numbers.Real): response = "<@" + user + ">, result: " + str(result) else: response = "<@" + user + ">, invalid mathematical expression" except: response = "<@" + user + ">, invalid mathematical expression" elif "hi" in command.lower() or "hey" in command.lower(): response = "Hey <@" + user + ">, Try _*@Xarvis help*_ to see what I can help you with" elif command.lower().startswith("execute"): response = handlers.tasks.execute_task( command.lower().strip()[8:].split(" "), TASKS) # Sends the response back to the channel SLACK_CLIENT.api_call("chat.postMessage", channel=channel, text=response or default_response)
def text(self): from cron_descriptor import get_description return get_description(self.cron)