forked from p15670423/monkey
added job logging, successful vm clone
This commit is contained in:
parent
4103b30ba0
commit
9ad0c2046d
|
@ -56,6 +56,22 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- /.Jobs section -->
|
||||
<!-- Log section -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="#logs" data-toggle="collapse">Log</a>
|
||||
</div>
|
||||
<div id="logs" class="panel-body panel-collapse collapse in">
|
||||
<table class="table table-bordered table-hover" id="logs-table">
|
||||
<thead>
|
||||
<tr><th>Time</th><th>Data</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.Log section -->
|
||||
</div>
|
||||
<!-- /.Main section -->
|
||||
|
||||
|
|
|
@ -11,8 +11,10 @@ const ICONS_EXT = ".png";
|
|||
// If variable from local storage != null, assign it, otherwise set it's default value.
|
||||
|
||||
var jobsTable = undefined;
|
||||
var logsTable = undefined;
|
||||
var vcenterCfg = undefined;
|
||||
var jobCfg = undefined;
|
||||
var selectedJob = undefined;
|
||||
|
||||
JSONEditor.defaults.theme = 'bootstrap3';
|
||||
|
||||
|
@ -22,6 +24,9 @@ function initAdmin() {
|
|||
"ordering": true,
|
||||
"order": [[1, "desc"]],
|
||||
});
|
||||
logsTable = $("#logs-table").DataTable({
|
||||
"ordering": false,
|
||||
});
|
||||
jobsTable.on( 'click', 'tr', function () {
|
||||
if ( $(this).hasClass('selected') ) {
|
||||
$(this).removeClass('selected');
|
||||
|
@ -31,7 +36,9 @@ function initAdmin() {
|
|||
$(this).addClass('selected');
|
||||
}
|
||||
jobdata = jobsTable.row(this).data();
|
||||
createNewJob(jobdata[0], jobdata[3]);
|
||||
selectedJob = jobdata[0];
|
||||
createNewJob(selectedJob, jobdata[3]);
|
||||
showLog(selectedJob);
|
||||
} );
|
||||
|
||||
vcenterCfg = new JSONEditor(document.getElementById('vcenter-config'),{
|
||||
|
@ -98,12 +105,31 @@ function initAdmin() {
|
|||
disable_properties: true,
|
||||
});
|
||||
|
||||
window.setTimeout(updateJobs, 5000);
|
||||
setInterval(updateJobs, 2000);
|
||||
setInterval(showLog, 2000);
|
||||
loadVcenterConfig();
|
||||
updateJobs();
|
||||
|
||||
}
|
||||
|
||||
function showLog() {
|
||||
logsTable.clear();
|
||||
|
||||
if (!selectedJob) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.getJSON('/job?action=log&id=' + selectedJob, function(json) {
|
||||
var logsList = json.log;
|
||||
for (var i = 0; i < logsList.length; i++) {
|
||||
logsTable.row.add([logsList[i][0], logsList[i][1]]);
|
||||
}
|
||||
|
||||
logsTable.draw();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function updateJobs() {
|
||||
$.getJSON('/job', function(json) {
|
||||
jobsTable.clear();
|
||||
|
@ -150,9 +176,15 @@ function updateVcenterConfig() {
|
|||
|
||||
}
|
||||
|
||||
function emptySelection() {
|
||||
showLog();
|
||||
selectedJob = undefined;
|
||||
jobsTable.$('tr.selected').removeClass('selected');
|
||||
}
|
||||
|
||||
function createNewJob(id, state) {
|
||||
if (!id) {
|
||||
jobsTable.$('tr.selected').removeClass('selected');
|
||||
emptySelection();
|
||||
}
|
||||
|
||||
elem = document.getElementById('job-config');
|
||||
|
|
|
@ -6,8 +6,8 @@ available_jobs = [VCenterJob, DemoJob]
|
|||
|
||||
def get_connector_by_name(name):
|
||||
for jobclass in available_jobs:
|
||||
if name == jobclass.connector.__name__:
|
||||
return jobclass.connector()
|
||||
if name == jobclass.connector_type.__name__:
|
||||
return jobclass.connector_type()
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
@ -36,9 +36,17 @@ class NetControllerConnector(object):
|
|||
def disconnect(self):
|
||||
return
|
||||
|
||||
def log(self, text):
|
||||
pass
|
||||
|
||||
def set_logger(self, logger):
|
||||
self.log = logger
|
||||
|
||||
class NetControllerJob(object):
|
||||
connector = NetControllerConnector
|
||||
connector_type = NetControllerConnector
|
||||
_connector = None
|
||||
_logger = None
|
||||
|
||||
_properties = {
|
||||
# property: value
|
||||
}
|
||||
|
@ -47,9 +55,15 @@ class NetControllerJob(object):
|
|||
|
||||
}
|
||||
|
||||
def __init__(self, existing_connector = None):
|
||||
if existing_connector:
|
||||
self.connector = existing_connector
|
||||
def __init__(self, existing_connector=None, logger=None):
|
||||
self._connector = existing_connector
|
||||
self._logger = logger
|
||||
if logger:
|
||||
self._connector.set_logger(self.log)
|
||||
|
||||
def log(self, text):
|
||||
if self._logger:
|
||||
self._logger.log(text)
|
||||
|
||||
def get_job_properties(self):
|
||||
return self._properties
|
||||
|
|
|
@ -35,7 +35,7 @@ class DemoConnector(NetControllerConnector):
|
|||
return []
|
||||
|
||||
class DemoJob(NetControllerJob):
|
||||
connector = DemoConnector
|
||||
connector_type = DemoConnector
|
||||
_properties = {
|
||||
"vlan": 0,
|
||||
}
|
||||
|
@ -45,4 +45,5 @@ class DemoJob(NetControllerJob):
|
|||
|
||||
def run(self):
|
||||
import time
|
||||
self.log("Running demo job...")
|
||||
time.sleep(30)
|
|
@ -63,20 +63,25 @@ class VCenterConnector(NetControllerConnector):
|
|||
def get_entities_on_vlan(self, vlanid):
|
||||
return []
|
||||
|
||||
def deploy_monkey(self, vlanid, vm_name):
|
||||
def deploy_monkey(self, vm_name):
|
||||
if not self._properties["monkey_template_name"]:
|
||||
raise Exception("Monkey template not configured")
|
||||
|
||||
if not self.is_connected():
|
||||
self.connect()
|
||||
|
||||
vcontent = self._service_instance.RetrieveContent() # get updated vsphare state
|
||||
monkey_template = self._get_obj(vcontent, [vim.VirtualMachine], self._properties["monkey_template_name"])
|
||||
if not monkey_template:
|
||||
raise Exception("Monkey template not found")
|
||||
|
||||
task = self._clone_vm(vcontent, monkey_template, vm_name)
|
||||
if not task:
|
||||
self.log("Cloning vm: (%s -> %s)" % (monkey_template, vm_name))
|
||||
monkey_vm = self._clone_vm(vcontent, monkey_template, vm_name)
|
||||
if not monkey_vm:
|
||||
raise Exception("Error deploying monkey VM")
|
||||
self.log("Finished cloning")
|
||||
|
||||
monkey_vm = task.entity
|
||||
return monkey_vm
|
||||
|
||||
def disconnect(self):
|
||||
Disconnect(self._service_instance)
|
||||
|
@ -101,7 +106,7 @@ class VCenterConnector(NetControllerConnector):
|
|||
else:
|
||||
datastore = self._get_obj(vcontent, [vim.Datastore], vm.datastore[0].info.name)
|
||||
|
||||
# get vm target resoucepool
|
||||
# get vm target resource pool
|
||||
if self._properties["monkey_vm_info"]["resource_pool"]:
|
||||
resource_pool = self._get_obj(vcontent, [vim.ResourcePool], self._properties["monkey_vm_info"]["resource_pool"])
|
||||
else:
|
||||
|
@ -116,12 +121,12 @@ class VCenterConnector(NetControllerConnector):
|
|||
clonespec = vim.vm.CloneSpec()
|
||||
clonespec.location = relospec
|
||||
|
||||
self.log("Starting clone task with the following info: %s" % repr({"folder": destfolder, "name": name, "clonespec": clonespec}))
|
||||
|
||||
task = vm.Clone(folder=destfolder, name=name, spec=clonespec)
|
||||
return self._wait_for_task(task)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _wait_for_task(task):
|
||||
def _wait_for_task(self, task):
|
||||
""" wait for a vCenter task to finish """
|
||||
task_done = False
|
||||
while not task_done:
|
||||
|
@ -129,6 +134,7 @@ class VCenterConnector(NetControllerConnector):
|
|||
return task.info.result
|
||||
|
||||
if task.info.state == 'error':
|
||||
self.log("Error waiting for task: %s" % repr(task.info))
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
|
@ -153,9 +159,9 @@ class VCenterConnector(NetControllerConnector):
|
|||
|
||||
|
||||
class VCenterJob(NetControllerJob):
|
||||
connector = VCenterConnector
|
||||
connector_type = VCenterConnector
|
||||
_properties = {
|
||||
"vlan": 0,
|
||||
"vlan": "",
|
||||
"vm_name": "",
|
||||
}
|
||||
_enumerations = {
|
||||
|
@ -163,5 +169,9 @@ class VCenterJob(NetControllerJob):
|
|||
}
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
if not self._connector:
|
||||
return False
|
||||
|
||||
monkey_vm = self._connector.deploy_monkey(self._properties["vm_name"])
|
||||
return True
|
||||
|
||||
|
|
|
@ -24,8 +24,13 @@ class Root(restful.Resource):
|
|||
|
||||
class Job(restful.Resource):
|
||||
def get(self, **kw):
|
||||
id = kw.get('id')
|
||||
id = request.args.get('id')
|
||||
timestamp = request.args.get('timestamp')
|
||||
action = request.args.get('action')
|
||||
|
||||
if action == "log":
|
||||
return {"log": get_job_log(id)}
|
||||
|
||||
result = {}
|
||||
|
||||
if (id):
|
||||
|
@ -65,8 +70,8 @@ class Connector(restful.Resource):
|
|||
if not contype:
|
||||
conlist = []
|
||||
for jobclass in available_jobs:
|
||||
if jobclass.connector.__name__ not in conlist:
|
||||
conlist.append(jobclass.connector.__name__)
|
||||
if jobclass.connector_type.__name__ not in conlist:
|
||||
conlist.append(jobclass.connector_type.__name__)
|
||||
return {"oneOf": conlist}
|
||||
|
||||
con = get_connector_by_name(contype)
|
||||
|
@ -101,7 +106,7 @@ class JobCreation(restful.Resource):
|
|||
res = []
|
||||
update_connectors()
|
||||
for con in available_jobs:
|
||||
if con.connector.__name__ in active_connectors:
|
||||
if con.connector_type.__name__ in active_connectors:
|
||||
res.append({"title": con.__name__, "$ref": "/jobcreate?type=" + con.__name__})
|
||||
return {"oneOf": res}
|
||||
|
||||
|
@ -121,7 +126,7 @@ class JobCreation(restful.Resource):
|
|||
else:
|
||||
return {'status': 'bad state'}
|
||||
|
||||
if job and job.connector.__name__ in active_connectors.keys():
|
||||
if job and job.connector_type.__name__ in active_connectors.keys():
|
||||
properties = {
|
||||
"type": {
|
||||
"type": "enum",
|
||||
|
@ -148,7 +153,7 @@ class JobCreation(restful.Resource):
|
|||
properties[prop]["type"] = "string"
|
||||
enum = job.get_property_function(prop)
|
||||
if enum:
|
||||
properties[prop]["enum"] = list(active_connectors[job.connector.__name__].__getattribute__(enum)())
|
||||
properties[prop]["enum"] = list(active_connectors[job.connector_type.__name__].__getattribute__(enum)())
|
||||
|
||||
res = dict({
|
||||
"title": "%s Job" % jobtype,
|
||||
|
@ -229,11 +234,17 @@ def output_json(obj, code, headers=None):
|
|||
return resp
|
||||
|
||||
|
||||
def get_job_log(jobid):
|
||||
res = mongo.db.results.find_one({"jobid": bson.ObjectId(jobid)})
|
||||
if res:
|
||||
return res["log"]
|
||||
return []
|
||||
|
||||
def update_connectors():
|
||||
for con in available_jobs:
|
||||
connector_name = con.connector.__name__
|
||||
connector_name = con.connector_type.__name__
|
||||
if connector_name not in active_connectors:
|
||||
active_connectors[connector_name] = con.connector()
|
||||
active_connectors[connector_name] = con.connector_type()
|
||||
|
||||
if not active_connectors[connector_name].is_connected():
|
||||
refresh_connector_config(mongo, active_connectors[connector_name])
|
||||
|
|
|
@ -23,6 +23,7 @@ fapp.config.from_object('dbconfig')
|
|||
celery = make_celery(fapp)
|
||||
mongo = PyMongo(fapp)
|
||||
|
||||
|
||||
class JobExecution(object):
|
||||
_jobinfo = None
|
||||
_job = None
|
||||
|
@ -35,9 +36,10 @@ class JobExecution(object):
|
|||
self.update_job_state("processing")
|
||||
|
||||
job_class = get_jobclass_by_name(self._jobinfo["type"])
|
||||
con = job_class.connector()
|
||||
con = job_class.connector_type()
|
||||
refresh_connector_config(self._mongo, con)
|
||||
self._job = job_class(con)
|
||||
self._job = job_class(con, self)
|
||||
self._job.load_job_properties(self._jobinfo["properties"])
|
||||
|
||||
def get_job(self):
|
||||
return self._job
|
||||
|
@ -56,22 +58,27 @@ class JobExecution(object):
|
|||
upsert=True)
|
||||
|
||||
def log(self, text):
|
||||
self._log.append("[%s] %s" % (datetime.now(), text))
|
||||
self._log.append([datetime.now().isoformat(), text])
|
||||
self._mongo.db.results.update({"jobid": self._jobinfo["_id"]},
|
||||
{"$set": {"log": self._log}},
|
||||
upsert=True)
|
||||
|
||||
def run(self):
|
||||
self.log("Starting job")
|
||||
res = False
|
||||
try:
|
||||
self._job.run()
|
||||
res = self._job.run()
|
||||
except Exception, e:
|
||||
self.log("Exception raised while running: %s" % e)
|
||||
self.update_job_state("error")
|
||||
return False
|
||||
self.log("done job startup")
|
||||
self.update_job_state("running")
|
||||
return True
|
||||
if res:
|
||||
self.log("Done job startup")
|
||||
self.update_job_state("running")
|
||||
else:
|
||||
self.log("Job startup error")
|
||||
self.update_job_state("error")
|
||||
return res
|
||||
|
||||
def get_results(self):
|
||||
self.log("Trying to get results")
|
||||
|
@ -92,9 +99,15 @@ def run_task(jobid):
|
|||
if not job_info:
|
||||
return False
|
||||
|
||||
job_exec = JobExecution(mongo, job_info)
|
||||
job_exec = None
|
||||
try:
|
||||
job_exec = JobExecution(mongo, job_info)
|
||||
except Exception, e:
|
||||
print "init JobExecution exception - ", e
|
||||
return False
|
||||
|
||||
if not job_exec.get_job():
|
||||
job_exec.update_job_state(job_info, "error")
|
||||
job_exec.update_job_state("error")
|
||||
return False
|
||||
|
||||
if not job_exec.run():
|
||||
|
|
Loading…
Reference in New Issue