Browse Source

HUE-1176 [jb] Load info of single job when selecting it from the list

Romain Rigaux 9 năm trước cách đây
mục cha
commit
0e9e25e

+ 10 - 1
apps/jobbrowser/src/jobbrowser/api2.py

@@ -59,7 +59,16 @@ def jobs(request):
 
 
 @api_error_handler
-def job(request): return {}
+def job(request):
+  response = {'status': -1}
+
+  interface = json.loads(request.POST.get('interface'))
+  appid = json.loads(request.POST.get('appid'))
+
+  response['app'] = get_api(request.user, interface).app(appid)
+  response['status'] = 0
+
+  return JsonResponse(response)
 
 
 @api_error_handler

+ 23 - 4
apps/jobbrowser/src/jobbrowser/job_api.py

@@ -19,10 +19,7 @@ import logging
 
 from django.utils.translation import ugettext as _
 
-# TODO Protect in case modules are not there
-from jobbrowser.api import YarnApi as NativeYarnApi
 from liboozie.oozie_api import get_oozie
-from oozie.conf import OOZIE_JOBS_COUNT
 
 from desktop.lib.exceptions_renderable import PopupException
 
@@ -30,6 +27,12 @@ from desktop.lib.exceptions_renderable import PopupException
 LOG = logging.getLogger(__name__)
 
 
+try:
+  from jobbrowser.api import YarnApi as NativeYarnApi
+  from oozie.conf import OOZIE_JOBS_COUNT
+except Exception, e:
+  LOG.exception('Some application are not enabled: %s' % e)
+
 
 def get_api(user, interface):
   if interface == 'batches':
@@ -49,7 +52,7 @@ class Api():
 
   def apps(self): return []
 
-  def app(self): return {}
+  def app(self, appid): return {}
 
   def kill(self): return {}
 
@@ -70,6 +73,10 @@ class YarnApi(Api):
     jobs = NativeYarnApi(self.user).get_jobs(self.user, username=self.user.username, state='all', text='')
     return [{'id': app.jobId, 'status': app.status} for app in jobs]
 
+  def app(self, appid):
+    app = NativeYarnApi(self.user).get_job(jobid=appid)
+    return {'id': app.jobId, 'name': app.name, 'status': app.status}
+
 
 class MapReduce2Api(Api):
   pass
@@ -100,6 +107,12 @@ class BatchApi(Api):
 
     return [{'id': app.id, 'status': app.status} for app in wf_list.jobs]
 
+  def app(self, appid):
+    oozie_api = get_oozie(self.user)
+    workflow = oozie_api.get_job(jobid=appid)
+
+    return {'id': workflow.id, 'name': workflow.appName, 'status': workflow.status}
+
 
 # Schedule
 
@@ -112,6 +125,12 @@ class ScheduleApi(Api):
 
     return [{'id': app.id, 'status': app.status} for app in wf_list.jobs]
 
+  def app(self, appid):
+    oozie_api = get_oozie(self.user)
+    workflow = oozie_api.get_coordinator(jobid=appid)
+
+    return {'id': workflow.coordJobId, 'name': workflow.coordJobName, 'status': workflow.status}
+
 
 # History
 

+ 47 - 15
apps/jobbrowser/src/jobbrowser/templates/apps.mako

@@ -47,14 +47,13 @@ ${ require.config() }
 
 
 <div class="container-fluid">
-
   ${_('Username')} <input id="userFilter" type="text" class="input-medium search-query" placeholder="${_('Search for username')}" value="${ user_filter or '' }">
   &nbsp;&nbsp;${_('Text')} <input id="textFilter" type="text" class="input-xlarge search-query" placeholder="${_('Search for id, name, status...')}" value="${ text_filter or '' }">
 
   <span>
-    <span><input class="btn btn-status" type="radio" name="interface" value="jobs" data-bind="checked: jobs.interface" />${ _('Jobs') }</span>
-    <span><input class="btn btn-status" type="radio" name="interface" value="batches" data-bind="checked: jobs.interface" />${ _('Batches') }</span>
-    <span><input class="btn btn-status" type="radio" name="interface" value="schedules" data-bind="checked: jobs.interface" />${ _('Schedules') }</span>
+    <span><input class="btn btn-status" type="radio" name="interface" value="jobs" data-bind="checked: interface" />${ _('Jobs') }</span>
+    <span><input class="btn btn-status" type="radio" name="interface" value="batches" data-bind="checked: interface" />${ _('Batches') }</span>
+    <span><input class="btn btn-status" type="radio" name="interface" value="schedules" data-bind="checked: interface" />${ _('Schedules') }</span>
   </span>
 
   <span class="btn-group">
@@ -83,7 +82,7 @@ ${ require.config() }
     </tr>
     </thead>
     <tbody data-bind="foreach: jobs.apps">
-      <tr>
+      <tr data-bind="click: fetchJob">
         <td></td>
         <td data-bind="text: id"></td>
         <td data-bind="text: name"></td>
@@ -101,6 +100,18 @@ ${ require.config() }
 </div>
 
 
+<!-- ko if: $root.job() -->
+<div data-bind="template: { name: 'app-page', data: $root.job() }"></div>
+<!-- /ko -->
+
+
+<script type="text/html" id="app-page">
+  ${ _('Id') } <span data-bind="text: id"></span>
+  ${ _('Name') } <span data-bind="text: name"></span>
+  ${ _('Status') } <span data-bind="text: status"></span>
+</script>
+
+
 <script type="text/javascript" charset="utf-8">
   require([
     "knockout",
@@ -125,32 +136,47 @@ ${ require.config() }
       self.progress = ko.observable(typeof job.progress != "undefined" && job.progress != null ? job.progress : null);
       self.duration = ko.observable(typeof job.duration != "undefined" && job.duration != null ? job.duration : null);
       self.submitted = ko.observable(typeof job.submitted != "undefined" && job.submitted != null ? job.submitted : null);
+
+      self.properties = ko.observable(typeof job.properties != "undefined" && job.properties != null ? job.properties : {});
+
+      self.loadingJob = ko.observable(false);
+
+      self.fetchJob = function () {
+        self.loadingJob(true);
+        $.post("/jobbrowser/api/job", {
+          appid: ko.mapping.toJSON(self.id),
+          interface: ko.mapping.toJSON(vm.interface)
+        }, function(data) {
+          if (data.status == 0) {
+            vm.job(new Job(self, job));
+          } else {
+            $(document).trigger("error", data.message);
+          }
+        }).always(function(){
+          self.loadingJob(false);
+        });
+      };
     };
 
     var Jobs = function (vm, options) {
       var self = this;
 
       self.apps = ko.observableArray();
-      self.loadingApps = ko.observable(false);
+      self.loadingJobs = ko.observable(false);
 
       self.username = ko.observable('${ user.username }');
 
-      self.interface = ko.observable('jobs');
-      self.interface.subscribe(function(val) {
-        self.fetchJobs();
-      });
-
       self.fetchJobs = function () {
-        self.loadingApps(true);
+        self.loadingJobs(true);
         $.post("/jobbrowser/api/jobs", {
           username: ko.mapping.toJSON(self.username),
-          interface: ko.mapping.toJSON(self.interface)
+          interface: ko.mapping.toJSON(vm.interface)
         }, function(data) {
           if (data.status == 0) {
             var apps = [];
             if (data && data.apps) {
               data.apps.forEach(function(job){
-                apps.push(new Job(self, job));
+                apps.push(new Job(vm, job));
               });
             }
             self.apps(apps);
@@ -158,7 +184,7 @@ ${ require.config() }
             $(document).trigger("error", data.message);
           }
         }).always(function(){
-          self.loadingApps(false);
+          self.loadingJobs(false);
         });
       };
     }
@@ -167,6 +193,12 @@ ${ require.config() }
       var self = this;
 
       self.jobs = new Jobs(self, options);
+      self.job = ko.observable();
+
+      self.interface = ko.observable('jobs');
+      self.interface.subscribe(function(val) {
+        self.jobs.fetchJobs();
+      });
     };
 
     var viewModel;

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

@@ -56,4 +56,5 @@ urlpatterns += patterns('jobbrowser.views',
 
 urlpatterns += patterns('jobbrowser.api2',
   url(r'api/jobs', 'jobs', name='jobs'),
+  url(r'api/job', 'job', name='job'),
 )

+ 1 - 1
apps/jobbrowser/src/jobbrowser/views.py

@@ -54,7 +54,7 @@ except:
 
 from jobbrowser.conf import LOG_OFFSET, SHARE_JOBS
 from jobbrowser.api import get_api, ApplicationNotRunning, JobExpired
-from jobbrowser.models import Job, JobLinkage, Tracker, Cluster, can_view_job, can_modify_job, LinkJobLogs, can_kill_job
+from jobbrowser.models import Job, JobLinkage, Tracker, Cluster, can_view_job, LinkJobLogs, can_kill_job
 from jobbrowser.yarn_models import Application