1
0
mirror of https://github.com/newnius/YAO-portal.git synced 2025-06-07 15:41:56 +00:00
This commit is contained in:
Newnius 2019-03-25 15:40:28 +08:00
parent 3a22e99602
commit bab3a98ce5
6 changed files with 342 additions and 54 deletions

View File

@ -68,7 +68,7 @@ switch ($action) {
case 'job_submit': case 'job_submit':
$job = new CRObject(); $job = new CRObject();
$job->set('name', cr_get_POST('name')); $job->set('name', cr_get_POST('name', '') . '-' . time());
$job->set('virtual_cluster', cr_get_POST('cluster')); $job->set('virtual_cluster', cr_get_POST('cluster'));
$job->set('workspace', cr_get_POST('workspace')); $job->set('workspace', cr_get_POST('workspace'));
$job->set('priority', cr_get_POST('priority')); $job->set('priority', cr_get_POST('priority'));
@ -90,6 +90,19 @@ switch ($action) {
$res = job_describe($job); $res = job_describe($job);
break; break;
case 'job_status':
$job = new CRObject();
$job->set('name', cr_get_GET('name'));
$res = job_status($job);
break;
case 'task_logs':
$task = new CRObject();
$task->set('job', cr_get_GET('job'));
$task->set('task', cr_get_GET('task'));
$res = task_logs($task);
break;
case 'agent_list': case 'agent_list':
$rule = new CRObject(); $rule = new CRObject();
$rule->set('offset', cr_get_GET('offset')); $rule->set('offset', cr_get_GET('offset'));

View File

@ -21,6 +21,7 @@ function job_submit(CRObject $job)
return $res; return $res;
} }
$job->set('created_by', Session::get('uid')); $job->set('created_by', Session::get('uid'));
$job->set('created_at', time());
$res['errno'] = JobManager::add($job) ? Code::SUCCESS : Code::UNKNOWN_ERROR; $res['errno'] = JobManager::add($job) ? Code::SUCCESS : Code::UNKNOWN_ERROR;
$log = new CRObject(); $log = new CRObject();
$log->set('scope', Session::get('uid')); $log->set('scope', Session::get('uid'));
@ -28,7 +29,27 @@ function job_submit(CRObject $job)
$content = array('job' => $job, 'response' => $res['errno']); $content = array('job' => $job, 'response' => $res['errno']);
$log->set('content', json_encode($content)); $log->set('content', json_encode($content));
CRLogger::log($log); CRLogger::log($log);
/* TODO notify scheduler */
/* notify YAO-scheduler */
$spider = new Spider();
$tasks = json_decode($job->get('tasks'), true);
foreach ($tasks as $i => $task) {
$task['cpu_number'] = intval($task['cpu_number']);
$task['memory'] = intval($task['memory']);
$task['gpu_number'] = intval($task['gpu_number']);
$task['gpu_memory'] = intval($task['gpu_memory']);
$tasks[$i] = $task;
}
$job->set('tasks', $tasks);
$job->set('workspace', $job->getInt('workspace'));
$job->set('virtual_cluster', $job->getInt('virtual_cluster'));
$job->set('priority', $job->getInt('priority'));
$job->set('run_before', $job->getInt('run_before'));
$job->set('created_by', $job->getInt('created_by'));
$data['job'] = json_encode($job);
$spider->doPost(YAO_SCHEDULER_ADDR . '?action=job_submit', $data);
$res['message'] = $spider->getBody();
return $res; return $res;
} }
@ -72,9 +93,75 @@ function job_list(CRObject $rule)
$res['errno'] = Code::NO_PRIVILEGE; $res['errno'] = Code::NO_PRIVILEGE;
return $res; return $res;
} }
$res['jobs'] = JobManager::gets($rule);
$res['count'] = JobManager::count($rule);
$res['errno'] = $res['jobs'] === null ? Code::FAIL : Code::SUCCESS; $spider = new Spider();
$spider->doGet(YAO_SCHEDULER_ADDR . '?action=jobs');
$msg = json_decode($spider->getBody(), true);
if ($msg['code'] !== 0) {
$res['errno'] = $msg['code'];
$res['msg'] = $msg['error'];
return $res;
}
$res['jobs'] = array_reverse($msg['jobs']);
for ($i = 0; $i < sizeof($res['jobs']); $i++) {
$res['jobs'][$i]['tasks'] = json_encode($res['jobs'][$i]['tasks']);
if ($res['jobs'][$i]['run_before'] === 0) {
$res['jobs'][$i]['run_before'] = null;
}
}
$res['errno'] = Code::SUCCESS;
//$res['jobs'] = JobManager::gets($rule);
//$res['count'] = JobManager::count($rule);
//$res['errno'] = $res['jobs'] === null ? Code::FAIL : Code::SUCCESS;
return $res;
}
function job_status(CRObject $job)
{
if (!AccessController::hasAccess(Session::get('role', 'visitor'), 'job.list')) {
$res['errno'] = Code::NO_PRIVILEGE;
return $res;
}
$spider = new Spider();
$spider->doGet(YAO_SCHEDULER_ADDR . '?action=job_status&id=' . $job->get('name'));
$msg = json_decode($spider->getBody(), true);
if ($msg['code'] !== 0) {
$res['errno'] = $msg['code'];
$res['msg'] = $msg['error'];
return $res;
}
$res['tasks'] = array_reverse($msg['status']);
$res['errno'] = Code::SUCCESS;
return $res;
}
function task_logs(CRObject $job)
{
if (!AccessController::hasAccess(Session::get('role', 'visitor'), 'job.list')) {
$res['errno'] = Code::NO_PRIVILEGE;
return $res;
}
$spider = new Spider();
$spider->doGet(YAO_SCHEDULER_ADDR . '?action=task_logs&job=' . $job->get('job') . '&task=' . $job->get('task'));
$msg = json_decode($spider->getBody(), true);
if ($msg['code'] !== 0) {
$res['errno'] = $msg['code'];
$res['msg'] = $msg['error'];
return $res;
}
$res['logs'] = $msg['logs'];
$res['errno'] = Code::SUCCESS;
return $res; return $res;
} }

View File

@ -31,6 +31,23 @@
</div> </div>
</div> </div>
<!-- task logs modal -->
<div class="modal fade" id="modal-task-logs" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content panel-info">
<div class="modal-header panel-heading">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">Task Outputs</h4>
</div>
<div class="modal-body">
<pre id="modal-task-logs-content"></pre>
</div>
</div>
</div>
</div>
<!-- job modal --> <!-- job modal -->
<div class="modal fade" id="modal-job" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal fade" id="modal-job" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg"> <div class="modal-dialog modal-lg">
@ -91,7 +108,8 @@
</div> </div>
</div> </div>
<label>Tasks</label> <label>Tasks</label>
<div class="row" id="form-job-tasks"> <div class="" id="form-job-tasks">
<div class="row">
<div class="col-md-2"> <div class="col-md-2">
<label>Name</label> <label>Name</label>
<div class="form-group"> <div class="form-group">
@ -135,6 +153,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<div> <div>
<button id="form-job-submit" type="submit" class="btn btn-primary btn-lg">Submit</button> <button id="form-job-submit" type="submit" class="btn btn-primary btn-lg">Submit</button>
</div> </div>

View File

@ -14,6 +14,17 @@ function register_events_job() {
run_before = moment(run_before).unix(); run_before = moment(run_before).unix();
} }
var tasks = []; var tasks = [];
$('#form-job-tasks').find('.row').each(function () {
var vals = $(this).find('input');
var task = {};
task['name'] = vals.eq(0).val();
task['cmd'] = vals.eq(1).val();
task['cpu_number'] = vals.eq(2).val();
task['memory'] = vals.eq(3).val();
task['gpu_number'] = vals.eq(4).val();
task['gpu_memory'] = vals.eq(5).val();
tasks.push(task);
});
/* TODO validate form */ /* TODO validate form */
@ -153,29 +164,33 @@ var clusterFormatter = function (cluster) {
}; };
var priorityFormatter = function (status) { var priorityFormatter = function (status) {
status = parseInt(status);
switch (status) { switch (status) {
case '1': case 1:
return '<span class="text-normal">Low</span>'; return '<span class="text-normal">Low</span>';
case '25': case 25:
return '<span class="text-info">Medium</span>'; return '<span class="text-info">Medium</span>';
case '50': case 50:
return '<span class="text-success">High</span>'; return '<span class="text-success">High</span>';
case '99': case 99:
return '<span class="text-danger">Urgent</span>'; return '<span class="text-danger">Urgent</span>';
} }
return 'Unknown (' + status + ')'; return 'Unknown (' + status + ')';
}; };
var statusFormatter = function (status) { var statusFormatter = function (status) {
status = parseInt(status);
switch (status) { switch (status) {
case '0': case 0:
return '<span class="text-normal">Pending</span>'; return '<span class="text-normal">Created</span>';
case '1': case 1:
return '<span class="text-normal">Starting</span>';
case 2:
return '<span class="text-info">Running</span>'; return '<span class="text-info">Running</span>';
case '2': case 3:
return '<span class="text-success">Finished</span>';
case '3':
return '<span class="text-danger">Stopped</span>'; return '<span class="text-danger">Stopped</span>';
case 4:
return '<span class="text-success">Finished</span>';
} }
return 'Unknown(' + status + ')'; return 'Unknown(' + status + ')';
}; };
@ -195,19 +210,25 @@ function jobResponseHandler(res) {
function jobOperateFormatter(value, row, index) { function jobOperateFormatter(value, row, index) {
var div = '<div class="btn-group" role="group" aria-label="...">'; var div = '<div class="btn-group" role="group" aria-label="...">';
if (page_type === 'jobs') if (page_type === 'jobs')
div += '<button class="btn btn-default view"><i class="glyphicon glyphicon-eye-open"></i>&nbsp;</button>'; div += '<button class="btn btn-default config"><i class="glyphicon glyphicon-cog"></i>&nbsp;</button>';
if (page_type === 'jobs' && (row.status === '0' || row.status === '1')) if (page_type === 'jobs')
div += '<button class="btn btn-default stats"><i class="glyphicon glyphicon-eye-open"></i>&nbsp;</button>';
if (page_type === 'jobs' && (parseInt(row.status) === 0 || parseInt(row.status) === 1))
div += '<button class="btn btn-default stop"><i class="glyphicon glyphicon-remove"></i>&nbsp;</button>'; div += '<button class="btn btn-default stop"><i class="glyphicon glyphicon-remove"></i>&nbsp;</button>';
div += '</div>'; div += '</div>';
return div; return div;
} }
window.jobOperateEvents = { window.jobOperateEvents = {
'click .view': function (e, value, row, index) { 'click .config': function (e, value, row, index) {
row.tasks = JSON.parse(row.tasks);
var formattedData = JSON.stringify(row, null, '\t'); var formattedData = JSON.stringify(row, null, '\t');
$('#modal-job-description-content').text(formattedData); $('#modal-job-description-content').text(formattedData);
$('#modal-job-description').modal('show'); $('#modal-job-description').modal('show');
}, },
'click .stats': function (e, value, row, index) {
window.open("?job_status&name=" + row.name);
},
'click .stop': function (e, value, row, index) { 'click .stop': function (e, value, row, index) {
if (!confirm('Are you sure to stop this job?')) { if (!confirm('Are you sure to stop this job?')) {
return; return;
@ -231,3 +252,126 @@ window.jobOperateEvents = {
}); });
} }
}; };
function load_job_status(name) {
$("#table-task").bootstrapTable({
url: window.config.BASE_URL + '/service?action=job_status&name=' + name,
responseHandler: jobStatusResponseHandler,
sidePagination: 'server',
cache: false,
striped: true,
pagination: false,
pageSize: 10,
pageList: [10, 25, 50, 100, 200],
search: false,
showColumns: true,
showRefresh: true,
showToggle: false,
showPaginationSwitch: true,
minimumCountColumns: 2,
clickToSelect: false,
sortName: 'nobody',
sortOrder: 'desc',
smartDisplay: true,
mobileResponsive: true,
showExport: true,
columns: [{
field: 'id',
title: 'ID',
align: 'center',
valign: 'middle'
}, {
field: 'image',
title: 'Image',
align: 'center',
valign: 'middle',
visible: false,
}, {
field: 'image_digest',
title: 'Image Version',
align: 'center',
valign: 'middle',
visible: false,
}, {
field: 'hostname',
title: 'Hostname',
align: 'center',
valign: 'middle'
}, {
field: 'command',
title: 'Command',
align: 'center',
valign: 'middle'
}, {
field: 'created_at',
title: 'Created At',
align: 'center',
valign: 'middle'
}, {
field: 'finished_at',
title: 'Finished At',
align: 'center',
valign: 'middle',
visible: false
}, {
field: 'status',
title: 'Status',
align: 'center',
valign: 'middle'
}, {
field: 'operate',
title: 'Operate',
align: 'center',
events: jobStatusOperateEvents,
formatter: jobStatusOperateFormatter
}]
});
}
function jobStatusResponseHandler(res) {
if (res['errno'] === 0) {
var tmp = {};
tmp["total"] = res["count"];
tmp["rows"] = res["tasks"];
return tmp;
}
$("#modal-msg-content").html(res["msg"]);
$("#modal-msg").modal('show');
return [];
}
function jobStatusOperateFormatter(value, row, index) {
var div = '<div class="btn-group" role="group" aria-label="...">';
div += '<button class="btn btn-default logs"><i class="glyphicon glyphicon-eye-open"></i>&nbsp;</button>';
div += '</div>';
return div;
}
window.jobStatusOperateEvents = {
'click .logs': function (e, value, row, index) {
var job = getParameterByName('name');
var task = row.id;
var ajax = $.ajax({
url: window.config.BASE_URL + "/service?action=task_logs",
type: 'GET',
data: {
job: job,
task: task
}
});
ajax.done(function (res) {
if (res["errno"] !== 0) {
$("#modal-msg-content").html(res["msg"]);
$("#modal-msg").modal('show');
}
$('#modal-task-logs-content').text(res['logs']);
$('#modal-task-logs').modal('show');
});
ajax.fail(function (jqXHR, textStatus) {
$("#modal-msg-content").html("Request failed : " + jqXHR.statusText);
$("#modal-msg").modal('show');
$('#table-job').bootstrapTable("refresh");
});
}
};

View File

@ -11,6 +11,10 @@ $(function () {
register_events_job(); register_events_job();
load_jobs('self'); load_jobs('self');
break; break;
case "job_status":
register_events_job();
load_job_status(getParameterByName('name'));
break;
case "agents": case "agents":
register_events_agent(); register_events_agent();
load_agents(''); load_agents('');

View File

@ -30,6 +30,9 @@ if (isset($_GET['logs'])) {
} elseif (isset($_GET['jobs'])) { } elseif (isset($_GET['jobs'])) {
$page_type = 'jobs'; $page_type = 'jobs';
} elseif (isset($_GET['job_status'])) {
$page_type = 'job_status';
} elseif (isset($_GET['jobs_all'])) { } elseif (isset($_GET['jobs_all'])) {
$page_type = 'jobs_all'; $page_type = 'jobs_all';
@ -147,6 +150,24 @@ foreach ($entries as $entry) {
</div> </div>
</div> </div>
<?php } elseif ($page_type === 'job_status') { ?>
<div id="jobs">
<div class="panel panel-default">
<div class="panel-heading">Job Status</div>
<div class="panel-body">
<div class="table-responsive">
<div id="toolbar">
<button id="btn-job-stop" class="btn btn-default">
<i class="glyphicon glyphicon-remove"></i> Stop
</button>
</div>
<table id="table-task" data-toolbar="#toolbar" class="table table-striped">
</table>
</div>
</div>
</div>
</div>
<?php } elseif ($page_type === 'resources') { ?> <?php } elseif ($page_type === 'resources') { ?>
<div id="resources"> <div id="resources">
<div class="panel panel-default"> <div class="panel panel-default">