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