mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Working chain reaction tasks
This commit is contained in:
parent
a908a3a7ac
commit
c1020ff3d1
@ -113,6 +113,8 @@ class Schedules(Model):
|
||||
comment = CharField()
|
||||
one_time = BooleanField(default=False)
|
||||
cron_string = CharField(default="")
|
||||
parent = IntegerField(null=True)
|
||||
delay = IntegerField(default=0)
|
||||
|
||||
class Meta:
|
||||
table_name = 'schedules'
|
||||
@ -279,6 +281,10 @@ class helpers_management:
|
||||
def get_schedules_by_server(server_id):
|
||||
return Schedules.select().where(Schedules.server_id == server_id).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_child_schedules_by_server(schedule_id, server_id):
|
||||
return Schedules.select().where(Schedules.server_id == server_id, Schedules.parent == schedule_id).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_schedules_all():
|
||||
return Schedules.select().execute()
|
||||
|
@ -8,6 +8,7 @@ from tzlocal import get_localzone
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
import datetime
|
||||
|
||||
from app.classes.web.tornado_handler import Webserver
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
@ -160,59 +161,60 @@ class TasksManager:
|
||||
|
||||
#load schedules from DB
|
||||
for schedule in schedules:
|
||||
if schedule.cron_string != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(schedule.cron_string,
|
||||
timezone=str(self.tz)),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.warning("Removing failed task from DB.")
|
||||
logger.error(f"Failed to schedule task with error: {e}.")
|
||||
logger.warning("Removing failed task from DB.")
|
||||
#remove items from DB if task fails to add to apscheduler
|
||||
management_helper.delete_scheduled_task(schedule.schedule_id)
|
||||
else:
|
||||
if schedule.interval_type == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(schedule.interval),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
elif schedule.interval_type == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(schedule.interval),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
elif schedule.interval_type == 'days':
|
||||
curr_time = schedule.start_time.split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(schedule.interval),
|
||||
hour=curr_time[0],
|
||||
minute=curr_time[1],
|
||||
id=str(schedule.schedule_id),
|
||||
args=[schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
if schedule.interval != 'reaction':
|
||||
if schedule.cron_string != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(schedule.cron_string,
|
||||
timezone=str(self.tz)),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.warning("Removing failed task from DB.")
|
||||
logger.error(f"Failed to schedule task with error: {e}.")
|
||||
logger.warning("Removing failed task from DB.")
|
||||
#remove items from DB if task fails to add to apscheduler
|
||||
management_helper.delete_scheduled_task(schedule.schedule_id)
|
||||
else:
|
||||
if schedule.interval_type == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(schedule.interval),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
elif schedule.interval_type == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(schedule.interval),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
elif schedule.interval_type == 'days':
|
||||
curr_time = schedule.start_time.split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(schedule.interval),
|
||||
hour=curr_time[0],
|
||||
minute=curr_time[1],
|
||||
id=str(schedule.schedule_id),
|
||||
args=[schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
self.scheduler.start()
|
||||
jobs = self.scheduler.get_jobs()
|
||||
logger.info("Loaded schedules. Current enabled schedules: ")
|
||||
@ -231,7 +233,8 @@ class TasksManager:
|
||||
job_data['enabled'],
|
||||
job_data['one_time'],
|
||||
job_data['cron_string'])
|
||||
if job_data['enabled']:
|
||||
#Check to see if it's enabled and is not a chain reaction.
|
||||
if job_data['enabled'] and job_data['interval_type'] != 'reaction':
|
||||
if job_data['cron_string'] != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
@ -293,12 +296,13 @@ class TasksManager:
|
||||
def remove_all_server_tasks(self, server_id):
|
||||
schedules = management_helper.get_schedules_by_server(server_id)
|
||||
for schedule in schedules:
|
||||
self.remove_job(schedule.schedule_id)
|
||||
if schedule.interval != 'reaction':
|
||||
self.remove_job(schedule.schedule_id)
|
||||
|
||||
def remove_job(self, sch_id):
|
||||
job = management_helper.get_scheduled_task_model(sch_id)
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
if job.enabled:
|
||||
if job.enabled and job.interval_type != 'reaction':
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
logger.info(f"Job with ID {sch_id} was deleted.")
|
||||
else:
|
||||
@ -308,61 +312,63 @@ class TasksManager:
|
||||
def update_job(self, sch_id, job_data):
|
||||
management_helper.update_scheduled_task(sch_id, job_data)
|
||||
try:
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
if job_data['interval'] != 'reaction':
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
except:
|
||||
logger.info("No job found in update job. Assuming it was previously disabled. Starting new job.")
|
||||
|
||||
if job_data['enabled']:
|
||||
if job_data['cron_string'] != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(job_data['cron_string'],
|
||||
timezone=str(self.tz)),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.info("Removing failed task from DB.")
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
else:
|
||||
if job_data['interval_type'] == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'days':
|
||||
curr_time = job_data['start_time'].split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(job_data['interval']),
|
||||
hour = curr_time[0],
|
||||
minute = curr_time[1],
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
if job_data['interval'] != 'reaction':
|
||||
if job_data['cron_string'] != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(job_data['cron_string'],
|
||||
timezone=str(self.tz)),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.info("Removing failed task from DB.")
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
else:
|
||||
if job_data['interval_type'] == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'days':
|
||||
curr_time = job_data['start_time'].split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(job_data['interval']),
|
||||
hour = curr_time[0],
|
||||
minute = curr_time[1],
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
else:
|
||||
try:
|
||||
self.scheduler.get_job(str(sch_id))
|
||||
@ -376,9 +382,21 @@ class TasksManager:
|
||||
task = management_helper.get_scheduled_task_model(int(event.job_id))
|
||||
management_helper.add_to_audit_log_raw('system', users_helper.get_user_id_by_name('system'), task.server_id,
|
||||
f"Task with id {task.schedule_id} completed successfully", '127.0.0.1')
|
||||
#check if the task is a single run.
|
||||
if task.one_time:
|
||||
self.remove_job(task.schedule_id)
|
||||
logger.info("one time task detected. Deleting...")
|
||||
#check for any child tasks for this. It's kind of backward, but this makes DB management a lot easier. One to one instead of one to many.
|
||||
for schedule in management_helper.get_child_schedules_by_server(task.schedule_id, task.server_id):
|
||||
#event job ID's are strings so we need to look at this as the same data type.
|
||||
if str(schedule.parent) == str(event.job_id):
|
||||
if schedule.enabled:
|
||||
delaytime = datetime.datetime.now() + datetime.timedelta(seconds=schedule.delay)
|
||||
self.scheduler.add_job(management_helper.add_command, 'date', run_date=delaytime, id=str(schedule.schedule_id),
|
||||
args=[schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command])
|
||||
else:
|
||||
logger.info("Event job ID is not numerical. Assuming it's stats - not stored in DB. Moving on.")
|
||||
else:
|
||||
|
@ -45,10 +45,11 @@
|
||||
<input type="hidden" name="subpage" value="config">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="difficulty">Basic / Cron Select<small class="text-muted ml-1"></small> </label><br>
|
||||
<label for="difficulty">Basic / Cron Select / Chain-Reaction<small class="text-muted ml-1"></small> </label><br>
|
||||
<select id="difficulty" name="difficulty" onchange="basicAdvanced(this);" class="form-control form-control-lg select-css" value="{{ data['schedule']['difficulty'] }}">
|
||||
<option id="basic" value="basic">Basic</option>
|
||||
<option id="advanced" value="advanced">Advanced</option>
|
||||
<option id="reaction" value="reaction">Chain-Reaction</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -58,7 +59,7 @@
|
||||
<option id="restart" value="restart">Restart Server</option>
|
||||
<option id="stop" value="stop">Shutdown Server</option>
|
||||
<option id="backup" value="backup">Backup Server</option>
|
||||
<option id="command" value="command">Custon Command</option>
|
||||
<option id="command" value="command">Custom Command</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="ifBasic">
|
||||
@ -92,6 +93,26 @@
|
||||
<input type="input" class="form-control" name="cron" id="cron" value="{{ data['schedule']['cron_string'] }}" placeholder="* * * * *">
|
||||
</div>
|
||||
</div>
|
||||
<div id="ifReaction" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label for="delay">Delay Offset <small class="text-muted ml-1"> - How long should we wait to fire this after firing the first task? (Seconds)</small> </label>
|
||||
<input type="number" class="form-control" name="delay" id="delay" value="0">
|
||||
<br>
|
||||
<br>
|
||||
<label for="parent">Parent Task <small class="text-muted ml-1"> - Which task should trigger this one?</small> </label>
|
||||
<select id="parent" name="parent" class="form-control form-control-lg select-css" value="{{ data['schedule']['action'] }}">
|
||||
{% for schedule in data['schedules'] %}
|
||||
{% if schedule.schedule_id != data['schedule']['schedule_id'] %}
|
||||
{% if schedule.interval != '' %}
|
||||
<option id="{{schedule.schedule_id}}" value="{{schedule.schedule_id}}">ID: {{schedule.schedule_id}} | {{schedule.command}} | {{schedule.interval}} {{ schedule.interval_type}}</option>
|
||||
{% else %}
|
||||
<option id="{{schedule.schedule_id}}" value="{{schedule.schedule_id}}">ID: {{schedule.schedule_id}} {{schedule.command}} {{schedule.cron_string}}</option>
|
||||
{% end %}
|
||||
{% end %}
|
||||
{% end %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check-flat">
|
||||
<label for="enabled" class="form-check-label ml-4 mb-4">
|
||||
@ -149,12 +170,27 @@
|
||||
function basicAdvanced() {
|
||||
if (document.getElementById('difficulty').value == "advanced") {
|
||||
document.getElementById("ifAdvanced").style.display = "block";
|
||||
document.getElementById("ifReaction").style.display = "none";
|
||||
document.getElementById("ifBasic").style.display = "none";
|
||||
document.getElementById("delay").required = false;
|
||||
document.getElementById("parent").required = false;
|
||||
document.getElementById("interval").required = false;
|
||||
document.getElementById("time").required = false;
|
||||
} else {
|
||||
} else if(document.getElementById('difficulty').value == "reaction"){
|
||||
document.getElementById("ifReaction").style.display = "block";
|
||||
document.getElementById("ifBasic").style.display = "none";
|
||||
document.getElementById("ifAdvanced").style.display = "none";
|
||||
document.getElementById("delay").required = true;
|
||||
document.getElementById("parent").required = true;
|
||||
document.getElementById("interval").required = false;
|
||||
document.getElementById("time").required = false;
|
||||
}
|
||||
else {
|
||||
document.getElementById("ifAdvanced").style.display = "none";
|
||||
document.getElementById("ifReaction").style.display = "none";
|
||||
document.getElementById("ifBasic").style.display = "block";
|
||||
document.getElementById("delay").required = false;
|
||||
document.getElementById("parent").required = false;
|
||||
document.getElementById("interval").required = true;
|
||||
document.getElementById("time").required = true;
|
||||
}
|
||||
|
@ -45,7 +45,8 @@
|
||||
<table class="table table-hover d-none d-lg-block responsive-table" id="schedule_table" width="100%" style="table-layout:fixed;">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th style="width: 25%; min-width: 50px;">Action</th>
|
||||
<th style="width: 2%; min-width: 10px;">ID</th>
|
||||
<th style="width: 23%; min-width: 50px;">Action</th>
|
||||
<th style="width: 40%; min-width: 50px;">Command</th>
|
||||
<th style="width: 10%; min-width: 50px;">Interval</th>
|
||||
<th style="width: 10%; min-width: 50px;">Start Time</th>
|
||||
@ -56,6 +57,9 @@
|
||||
<tbody>
|
||||
{% for schedule in data['schedules'] %}
|
||||
<tr>
|
||||
<td id="{{schedule.schedule_id}}" class="id">
|
||||
<p>{{schedule.schedule_id}}</p>
|
||||
</td>
|
||||
<td id="{{schedule.action}}" class="action">
|
||||
<p>{{schedule.action}}</p>
|
||||
</td>
|
||||
@ -66,6 +70,8 @@
|
||||
{% if schedule.interval != '' %}
|
||||
<p>Every</p>
|
||||
<p>{{schedule.interval}} {{schedule.interval_type}}</p>
|
||||
{% elif schedule.interval_type == 'reaction' %}
|
||||
<p>{{schedule.interval_type}}<br><br>child of ID: {{ schedule.parent }}</p>
|
||||
{% else %}
|
||||
<p>Cron String:</p>
|
||||
<p>{{schedule.cron_string}}</p>
|
||||
@ -141,6 +147,9 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul style="list-style: none;">
|
||||
<li id="{{schedule.schedule_id}}" class="id" style="border-top: .1em solid gray;">
|
||||
<h4>ID</h4><p>{{schedule.schedule_id}}</p>
|
||||
</li>
|
||||
<li id="{{schedule.action}}" class="action" style="border-top: .1em solid gray;">
|
||||
<h4>Action</h4><p>{{schedule.action}}</p>
|
||||
</li>
|
||||
@ -150,6 +159,8 @@
|
||||
<li id="{{schedule.interval}}" class="action" style="border-top: .1em solid gray;">
|
||||
{% if schedule.interval != '' %}
|
||||
<h4>Interval</h4> <p>Every {{schedule.interval}} {{schedule.interval_type}}</p>
|
||||
{% elif schedule.interval_type == 'reaction' %}
|
||||
<h4>Interval</h4> <p>{{schedule.interval_type}}<br><br>child of ID: {{ schedule.parent }}</p>
|
||||
{% else %}
|
||||
<h4>Interval</h4> <p>Cron String: {{schedule.cron_string}}</p>
|
||||
{% end %}
|
||||
|
Loading…
Reference in New Issue
Block a user