Răsfoiți Sursa

HUE-1132 [pig] Stop button

Abraham Elmahrek 12 ani în urmă
părinte
comite
3d02d48

+ 3 - 0
apps/pig/src/pig/api.py

@@ -102,6 +102,9 @@ class OozieApi:
     workflow.delete()
     return oozie_wf
 
+  def stop(self, job_id):
+    return get_oozie().job_control(job_id, 'kill')
+
   def get_jobs(self):
     kwargs = {'cnt': OozieApi.MAX_DASHBOARD_JOBS,}
     kwargs['user'] = self.user.username

+ 14 - 2
apps/pig/src/pig/templates/app.mako

@@ -128,9 +128,9 @@ ${ commonheader(_('Pig'), "pig", user, "100px") | n,unicode }
                 <i class="icon-play"></i> ${ _('Run') }
               </a>
             </li>
-            <li data-bind="visible: currentScript().isRunning()">
+            <li data-bind="click: showStopModal, visible: currentScript().isRunning()">
               <a href="#" title="${ _('Run the script') }" rel="tooltip" data-placement="right" class="disabled">
-                <i class="icon-spinner icon-spin"></i> ${ _('Running...') }
+                <i class="icon-spinner icon-ban-circle"></i> ${ _('Stop') }
               </a>
             </li>
             <li data-bind="visible: currentScript().id() != -1, click: copyScript">
@@ -393,6 +393,17 @@ ${ commonheader(_('Pig'), "pig", user, "100px") | n,unicode }
   </div>
 </div>
 
+<div id="stopModal" class="modal hide fade">
+  <div class="modal-header">
+    <a href="#" class="close" data-dismiss="modal">&times;</a>
+    <h3>${_('Stop Script')} '<span data-bind="text: currentScript().name"></span>' ${_('?')}</h3>
+  </div>
+  <div class="modal-footer">
+    <a class="btn" data-dismiss="modal">${_('No')}</a>
+    <a id="stopScriptBtn" class="btn btn-danger disable-feedback" data-bind="click: stopScript">${_('Yes')}</a>
+  </div>
+</div>
+
 <div id="chooseFile" class="modal hide fade">
     <div class="modal-header">
         <a href="#" class="close" data-dismiss="modal">&times;</a>
@@ -444,6 +455,7 @@ ${ commonheader(_('Pig'), "pig", user, "100px") | n,unicode }
     listScripts: "${ url('pig:scripts') }",
     saveUrl: "${ url('pig:save') }",
     runUrl: "${ url('pig:run') }",
+    stopUrl: "${ url('pig:stop') }",
     copyUrl: "${ url('pig:copy') }",
     deleteUrl: "${ url('pig:delete') }"
   }

+ 21 - 0
apps/pig/src/pig/tests.py

@@ -103,3 +103,24 @@ class TestWithHadoop(OozieBase):
 
     response = self.c.post(reverse('pig:run'), data=post_data, follow=True)
     self.wait_until_completion(json.loads(response.content)['id'])
+
+  def test_stop(self):
+    script = PigScript.objects.get(id=1)
+    script_dict = script.dict
+
+    post_data = {
+      'id': script.id,
+      'name': script_dict['name'],
+      'script': script_dict['script'],
+      'user': script.owner,
+      'parameters': json.dumps(script_dict['parameters']),
+      'resources': json.dumps(script_dict['resources']),
+      'submissionVariables': json.dumps([{"name": "output", "value": '/tmp/test_pig'}]),
+    }
+
+    submit_response = self.c.post(reverse('pig:run'), data=post_data, follow=True)
+    script = PigScript.objects.get(id=json.loads(submit_response.content)['id'])
+    assert_true(script.dict['job_id'], script.dict)
+
+    stop_response = self.c.post(reverse('pig:stop'), data={'id': script.id}, follow=True)
+    assert_equal('KILLED', json.loads(stop_response.content)['workflow']['status'])

+ 1 - 0
apps/pig/src/pig/urls.py

@@ -30,5 +30,6 @@ urlpatterns = patterns('pig.views',
   url(r'^copy/$', 'copy', name='copy'),
   url(r'^delete/$', 'delete', name='delete'),
   url(r'^watch/(?P<job_id>[-\w]+)$', 'watch', name='watch'),
+  url(r'^stop/$', 'stop', name='stop'),
   url(r'^install_examples$', 'install_examples', name='install_examples'),
 )

+ 21 - 1
apps/pig/src/pig/views.py

@@ -29,7 +29,9 @@ from django.views.decorators.http import require_http_methods
 
 from desktop.lib.django_util import render
 from desktop.lib.exceptions_renderable import PopupException
-from oozie.views.dashboard import show_oozie_error, check_job_access_permission
+from desktop.lib.rest.http_client import RestException
+from oozie.views.dashboard import show_oozie_error, check_job_access_permission,\
+                                  check_job_edition_permission
 
 from pig import api
 from pig.management.commands import pig_setup
@@ -82,6 +84,24 @@ def save(request):
   return HttpResponse(json.dumps(response), content_type="text/plain")
 
 
+@show_oozie_error
+def stop(request):
+  if request.method != 'POST':
+    raise PopupException(_('POST request required.'))
+
+  pig_script = PigScript.objects.get(id=request.POST.get('id'))
+  job_id = pig_script.dict['job_id']
+
+  job = check_job_access_permission(request, job_id)
+  check_job_edition_permission(job, request.user)
+
+  try:
+    api.get(request, request.user).stop(job_id)
+  except RestException, e:
+    raise PopupException(_("Error stopping Pig script.") % e.message)
+
+  return watch(request, job_id)
+
 
 @show_oozie_error
 def run(request):

+ 44 - 0
apps/pig/static/js/pig.ko.js

@@ -109,6 +109,7 @@ var PigViewModel = function (props) {
   self.LIST_SCRIPTS = props.listScripts;
   self.SAVE_URL = props.saveUrl;
   self.RUN_URL = props.runUrl;
+  self.STOP_URL = props.stopUrl;
   self.COPY_URL = props.copyUrl;
   self.DELETE_URL = props.deleteUrl;
 
@@ -219,6 +220,10 @@ var PigViewModel = function (props) {
     showDeleteModal();
   };
 
+  self.stopScript = function () {
+    callStop(self.currentScript());
+  };
+
   self.listRunScript = function () {
     callRun(self.selectedScript());
   };
@@ -281,6 +286,15 @@ var PigViewModel = function (props) {
     });
   };
 
+  self.showStopModal = function showStopModal() {
+    $("#stopScriptBtn").button("reset");
+    $("#stopScriptBtn").attr("data-loading-text", $("#stopScriptBtn").text() + " ...");
+    $("#stopModal").modal({
+      keyboard: true,
+      show: true
+    });
+  }
+
   self.showFileChooser = function showFileChooser() {
     var inputPath = this;
     var path = inputPath.value().substr(0, inputPath.value().lastIndexOf("/"));
@@ -314,6 +328,24 @@ var PigViewModel = function (props) {
     });
   }
 
+  function showStopModal() {
+    $(".stopMsg").addClass("hide");
+    if (self.currentStopType() == "single") {
+      $(".stopMsg.single").removeClass("hide");
+    }
+    if (self.currentStopType() == "multiple") {
+      if (self.selectedScripts().length > 1) {
+        $(".stopMsg.multiple").removeClass("hide");
+      } else {
+        $(".stopMsg.single").removeClass("hide");
+      }
+    }
+    $("#stopModal").modal({
+      keyboard: true,
+      show: true
+    });
+  }
+
   function callSave(script) {
     $(document).trigger("saving");
     $.post(self.SAVE_URL,
@@ -345,6 +377,7 @@ var PigViewModel = function (props) {
         function (data) {
           if (data.id && self.currentScript().id() != data.id){
             self.currentScript(script);
+            script.id(data.id);
             $(document).trigger("loadEditor");
           }
           script.isRunning(true);
@@ -357,6 +390,17 @@ var PigViewModel = function (props) {
         }, "json");
   }
 
+  function callStop(script) {
+    $(document).trigger("stopping");
+    $.post(self.STOP_URL, {
+        id: script.id()
+      },
+      function (data) {
+        $(document).trigger("stopped");
+        $("#stopModal").modal("hide");
+      }, "json");
+  }
+
   function callCopy(script) {
     $.post(self.COPY_URL,
         {