added job logging, successful vm clone

This commit is contained in:
itsikkes 2016-06-05 18:52:04 +03:00
parent 4103b30ba0
commit 9ad0c2046d
8 changed files with 135 additions and 38 deletions

View File

@ -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 -->

View File

@ -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');

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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])

View File

@ -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():