diff --git a/monkey_business/cc/admin/ui/index.html b/monkey_business/cc/admin/ui/index.html index f85c8885f..678b3813e 100644 --- a/monkey_business/cc/admin/ui/index.html +++ b/monkey_business/cc/admin/ui/index.html @@ -1,7 +1,7 @@ - Monkeys Admin + Monkeys Business @@ -93,29 +93,35 @@ Configure Auto Tester + +
+
- New Job + Job Properties
+
- diff --git a/monkey_business/cc/admin/ui/js/monkeysb-admin.js b/monkey_business/cc/admin/ui/js/monkeysb-admin.js index 247381a0a..c7ce468b5 100644 --- a/monkey_business/cc/admin/ui/js/monkeysb-admin.js +++ b/monkey_business/cc/admin/ui/js/monkeysb-admin.js @@ -71,13 +71,37 @@ function updateJobs() { var jobsList = json.objects; for (var i = 0; i < jobsList.length; i++) { - jobsTable.row.add([jobsList[i].id, jobsList[i].creation_time, jobsList[i].type,jobsList[i].state, JSON.stringify(jobsList[i].properties)]); + r = jobsTable.row.add([jobsList[i].id, jobsList[i].creation_time, jobsList[i].type,jobsList[i].state, JSON.stringify(jobsList[i].properties)]); + $(this).addClass('selected'); + if (jobsList[i].id == selectedJob) { + jobsTable.row(r[0]).nodes().to$().addClass( 'selected' ); + } } jobsTable.draw(); }); } +function stopJob() { + $.ajax({ + headers : { + 'Accept' : 'application/json', + }, + url : '/job?action=stop&id=' + selectedJob, + type : 'GET', + success : function(response, textStatus, jqXhr) { + console.log("Stopped job"); + }, + error : function(jqXHR, textStatus, errorThrown) { + // log the error to the console + console.log("The following error occured: " + textStatus, errorThrown); + }, + complete : function() { + console.log("Trying to stop job..."); + } + }); +} + function loadConnectorsConfig() { elem = document.getElementById('connectors-config'); elem.innerHTML = "" @@ -134,8 +158,8 @@ function updateConnectorConfig() { } function emptySelection() { - showLog(); selectedJob = undefined; + showLog(); jobsTable.$('tr.selected').removeClass('selected'); } @@ -146,6 +170,9 @@ function createNewJob(id, state) { elem = document.getElementById('job-config'); elem.innerHTML = "" + document.getElementById("btnSendJob").style.visibility = "hidden"; + document.getElementById("btnDeleteJob").style.visibility = "hidden"; + document.getElementById("btnStopJob").style.visibility = "hidden"; jobCfg = new JSONEditor(elem,{ schema: { type: "object", @@ -170,8 +197,10 @@ function createNewJob(id, state) { jobCfg.on('ready',function() { if (id && state != "pending") { jobCfg.disable(); - document.getElementById("btnSendJob").style.visibility = "hidden"; - document.getElementById("btnDeleteJob").style.visibility = "hidden"; + if (state == "running") { + document.getElementById("btnStopJob").style.visibility = "visible"; + } + } else { jobCfg.enable(); @@ -179,9 +208,6 @@ function createNewJob(id, state) { if (id) { document.getElementById("btnDeleteJob").style.visibility = "visible"; } - else { - document.getElementById("btnDeleteJob").style.visibility = "hidden"; - } } }); } diff --git a/monkey_business/cc/connectors/vcenter.py b/monkey_business/cc/connectors/vcenter.py index 4ddbf3c2d..c18366eb4 100644 --- a/monkey_business/cc/connectors/vcenter.py +++ b/monkey_business/cc/connectors/vcenter.py @@ -59,8 +59,11 @@ class VCenterConnector(NetControllerConnector): objview.Destroy() return self._cache["vlans"] - def get_entities_on_vlan(self, vlanid): - return [] + def get_vm(self, vmname): + if not self.is_connected(): + self.connect() + vcontent = self._service_instance.RetrieveContent() # get updated vsphare state + return self._get_obj(vcontent, [vim.VirtualMachine], vmname) def deploy_monkey(self, vm_name): if not self._properties["monkey_template_name"]: @@ -99,6 +102,14 @@ class VCenterConnector(NetControllerConnector): task = vm_obj.PowerOnVM_Task() return self._wait_for_task(task) + def power_off(self, vm_obj): + task = vm_obj.PowerOffVM_Task() + return self._wait_for_task(task) + + def destroy(self, vm_obj): + task = vm_obj.Destroy_Task() + return self._wait_for_task(task) + def disconnect(self): Disconnect(self._service_instance) self._service_instance = None @@ -242,3 +253,19 @@ class VCenterJob(NetControllerJob): return True + def stop(self): + if not self._connector: + return False + + if not self._vm_obj: + self._vm_obj = self._connector.get_vm(self._properties["vm_name"]) + + if not self._vm_obj: + self.log("Error: Couldn't find VM %s" % self._properties["vm_name"]) + return False + + self.log("Stopping: %s" % self._properties["vm_name"]) + self._connector.power_off(self._vm_obj) + self._connector.destroy(self._vm_obj) + + return True diff --git a/monkey_business/cc/main.py b/monkey_business/cc/main.py index 8a1d37fcb..d96f98301 100644 --- a/monkey_business/cc/main.py +++ b/monkey_business/cc/main.py @@ -30,11 +30,18 @@ class Job(restful.Resource): if action == "log": return {"log": get_job_log(id)} + elif action == "stop": + job = mongo.db.job.find_one_or_404({"_id": bson.ObjectId(id)}) + if "running" == job.get("state"): + tasks_manager.stop_task.delay(bson.ObjectId(id)) + return {'status': 'ok'} + else: + return {'status': 'failed'} result = {} if id: - return mongo.db.job.find_one_or_404({"_id": id}) + return mongo.db.job.find_one_or_404({"_id": bson.ObjectId(id)}) else: result['timestamp'] = datetime.now().isoformat() @@ -49,7 +56,7 @@ class Job(restful.Resource): if job_json.has_key('pk'): job = mongo.db.job.find_one_or_404({"pk": job_json["pk"]}) - if "pending" != job.get("status"): + if "pending" != job.get("state"): res = {"status": "cannot change job at this state", "res" : 0} return res if "delete" == job_json["action"]: diff --git a/monkey_business/cc/tasks_manager.py b/monkey_business/cc/tasks_manager.py index 03a82e537..2c89589f4 100644 --- a/monkey_business/cc/tasks_manager.py +++ b/monkey_business/cc/tasks_manager.py @@ -96,12 +96,31 @@ class JobExecution(object): self._log_resutls(res) return True + def stop(self): + self.log("Trying to stop...") + res = None + + try: + res = self._job.stop() + except Exception, e: + self.log("Exception raised while running: %s" % e) + self.update_job_state("error") + return False + + if res: + self.log("Done stop job") + self.update_job_state("ended") + else: + self.log("Job stopping error") + self.update_job_state("error") + + return res + @celery.task def run_task(jobid): - print "searching for ", jobid - aquire_task = mongo.db.job.update({"_id": jobid, "state": "pending"}, {"$set": {"state": "processing"}}) - if aquire_task["nModified"] != 1: + acquire_task = mongo.db.job.update({"_id": jobid, "state": "pending"}, {"$set": {"state": "processing"}}) + if acquire_task["nModified"] != 1: return False job_info = mongo.db.job.find_one({"_id": jobid}) @@ -128,6 +147,38 @@ def run_task(jobid): return "done task: " + run_task.request.id +@celery.task +def stop_task(jobid): + acquire_task = mongo.db.job.update({"_id": jobid, "state": "running"}, {"$set": {"state": "stopping"}}) + if acquire_task["nModified"] != 1: + print "could not acquire lock on job" + return False + + job_info = mongo.db.job.find_one({"_id": jobid}) + if not job_info: + print "could not get job info" + return False + + 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("error") + return False + + job_exec.get_results() + + if not job_exec.stop(): + print "error stopping" + return False + + return "done stop_task" + + @celery.task def update_cache(connector): time.sleep(30)