Forráskód Böngészése

HUE-3797 [scheduler] Beat interface skeleton in Job Browser

Romain 6 éve
szülő
commit
137ce70c9a

+ 3 - 0
apps/jobbrowser/src/jobbrowser/apis/base_api.py

@@ -30,6 +30,7 @@ LOG = logging.getLogger(__name__)
 
 
 def get_api(user, interface, cluster=None):
+  from jobbrowser.apis.beat_api import BeatApi
   from jobbrowser.apis.bundle_api import BundleApi
   from jobbrowser.apis.data_eng_api import DataEngClusterApi, DataEngJobApi
   from jobbrowser.apis.clusters import ClusterApi
@@ -50,6 +51,8 @@ def get_api(user, interface, cluster=None):
     return ScheduleApi(user)
   elif interface == 'bundles':
     return BundleApi(user)
+  elif interface == 'celery-beat':
+    return BeatApi(user)
   elif interface == 'engines':
     return ClusterApi(user)
   elif interface == 'dataeng-clusters':

+ 86 - 0
apps/jobbrowser/src/jobbrowser/templates/job_browser.mako

@@ -394,6 +394,10 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
                   <div class="jb-panel" data-bind="template: { name: 'queries-page${ SUFFIX }' }"></div>
                 <!-- /ko -->
 
+                <!-- ko if: mainType() == 'beats' -->
+                  <div class="jb-panel" data-bind="template: { name: 'beats-page${ SUFFIX }' }"></div>
+                <!-- /ko -->
+
                 <!-- ko if: mainType() == 'workflows' -->
                   <!-- ko if: type() == 'workflow' -->
                     <div class="jb-panel" data-bind="template: { name: 'workflow-page${ SUFFIX }' }"></div>
@@ -1666,6 +1670,83 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
 </script>
 
 
+<script type="text/html" id="beats-page${ SUFFIX }">
+  <div class="row-fluid">
+    <div data-bind="css: {'span2': !$root.isMini(), 'span12': $root.isMini() }">
+      <div class="sidebar-nav">
+        <ul class="nav nav-list">
+          <li class="nav-header">${ _('Id') }</li>
+          <li class="break-word"><span data-bind="text: id"></span></li>
+          <!-- ko if: doc_url -->
+          <li class="nav-header">${ _('Document') }</li>
+          <li>
+            <a data-bind="hueLink: doc_url" href="javascript: void(0);" title="${ _('Open in editor') }">
+              <span data-bind="text: name"></span>
+            </a>
+          </li>
+          <!-- /ko -->
+          <!-- ko ifnot: doc_url -->
+          <li class="nav-header">${ _('Name') }</li>
+          <li><span data-bind="text: name"></span></li>
+          <!-- /ko -->
+          <li class="nav-header">${ _('Status') }</li>
+          <li><span data-bind="text: status"></span></li>
+          <li class="nav-header">${ _('User') }</li>
+          <li><span data-bind="text: user"></span></li>
+          <li class="nav-header">${ _('Progress') }</li>
+          <li><span data-bind="text: progress"></span>%</li>
+          <li>
+            <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-danger': apiStatus() === 'FAILED', 'progress-warning': apiStatus() === 'RUNNING', 'progress-success': apiStatus() === 'SUCCEEDED' }">
+              <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
+            </div>
+          </li>
+          <li class="nav-header">${ _('Duration') }</li>
+          <li><span data-bind="text: duration().toHHMMSS()"></span></li>
+          <li class="nav-header">${ _('Submitted') }</li>
+          <li><span data-bind="moment: {data: submitted, format: 'LLL'}"></span></li>
+        </ul>
+      </div>
+    </div>
+    <div data-bind="css:{'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
+
+      <ul class="nav nav-pills margin-top-20">
+        <li>
+          <a href="#livy-session-page-statements${ SUFFIX }" data-bind="click: function(){ fetchProfile('properties'); $('a[href=\'#livy-session-page-statements${ SUFFIX }\']').tab('show'); }">
+            ${ _('Properties') }</a>
+        </li>
+      </ul>
+
+      <div class="clearfix"></div>
+
+      <div class="tab-content">
+        <div class="tab-pane active" id="livy-session-page-statements${ SUFFIX }">
+          <table id="actionsTable" class="datatables table table-condensed">
+            <thead>
+            <tr>
+              <th>${_('Id')}</th>
+              <th>${_('State')}</th>
+              <th>${_('Output')}</th>
+            </tr>
+            </thead>
+            <tbody data-bind="foreach: properties['statements']">
+              <tr data-bind="click: function() {  $root.job().id(id); $root.job().fetchJob(); }" class="pointer">
+                <td>
+                  <a data-bind="hueLink: '/jobbrowser/jobs/' + id(), clickBubble: false">
+                    <i class="fa fa-tasks"></i>
+                  </a>
+                </td>
+                <td data-bind="text: state"></td>
+                <td data-bind="text: output"></td>
+              </tr>
+            </tbody>
+          </table>
+        </div>
+      </div>
+    </div>
+  </div>
+</script>
+
+
 <script type="text/html" id="job-actions${ SUFFIX }">
   <div class="btn-group">
     <!-- ko if: hasResume -->
@@ -3290,6 +3371,9 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
         var schedulerExtraInterfaceCondition = function () {
           return '${ is_mini }' == 'False' && schedulerInterfaceCondition();
         };
+        var schedulerBeatInterfaceCondition = function () {
+          return self.appConfig() && self.appConfig()['scheduler'] && self.appConfig()['scheduler']['interpreter_names'].indexOf('celery-beat') != -1;
+        };
         var livyInterfaceCondition = function () {
           return '${ is_mini }' == 'False' && self.appConfig() && self.appConfig()['editor'] && self.appConfig()['editor']['interpreter_names'].indexOf('pyspark') != -1 && (!self.cluster() || self.cluster()['type'].indexOf('altus') == -1);
         };
@@ -3305,6 +3389,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
           {'interface': 'dataware2-clusters', 'label': '${ _ko('Warehouses') }', 'condition': dataWarehouse2InterfaceCondition},
           {'interface': 'engines', 'label': '${ _ko('') }', 'condition': enginesInterfaceCondition},
           {'interface': 'queries', 'label': '${ _ko('Queries') }', 'condition': queryInterfaceCondition},
+          {'interface': 'celery-beat', 'label': '${ _ko('Beat Schedules') }', 'condition': schedulerBeatInterfaceCondition},
           {'interface': 'workflows', 'label': '${ _ko('Workflows') }', 'condition': schedulerInterfaceCondition},
           {'interface': 'schedules', 'label': '${ _ko('Schedules') }', 'condition': schedulerInterfaceCondition},
           {'interface': 'bundles', 'label': '${ _ko('Bundles') }', 'condition': schedulerExtraInterfaceCondition},
@@ -3493,6 +3578,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
           case 'oozie-info':
           case 'jobs':
           case 'queries':
+          case 'beats':
           case 'workflows':
           case 'schedules':
           case 'bundles':

+ 3 - 4
desktop/core/src/desktop/lib/scheduler/lib/api.py

@@ -20,18 +20,17 @@ from builtins import object
 def get_api(request, interface):
   if interface == 'beat':
     from desktop.lib.scheduler.lib.beat import CeleryBeatApi
-    return CeleryBeatApi(interface=interface, user=request.user)
+    return CeleryBeatApi(user=request.user)
   elif interface == 'oozie':
     from desktop.lib.scheduler.lib.oozie import OozieApi
-    return OozieApi(interface=interface, user=request.user)
+    return OozieApi(user=request.user)
   else:
     raise PopupException(_('Scheduler connector interface not recognized: %s') % interface)
 
 
 class Api(object):
 
-  def __init__(self, interface, user):
-    self.interface = interface
+  def __init__(self, user):
     self.user = user
 
   def get_schedule(self):

+ 1 - 1
desktop/core/src/desktop/lib/scheduler/lib/beat.py

@@ -72,7 +72,7 @@ class CeleryBeatApi(Api):
       )
 
 
-  def list_schedules(self, user):
+  def list_tasks(self, user):
     PeriodicTask.objects.filter(description=user.username)
 
 

+ 14 - 21
desktop/core/src/desktop/models.py

@@ -48,7 +48,7 @@ from useradmin.models import User, Group, get_organization
 from desktop import appmanager
 from desktop.auth.backend import is_admin
 from desktop.conf import get_clusters, CLUSTER_ID, IS_MULTICLUSTER_ONLY, IS_K8S_ONLY, ENABLE_ORGANIZATIONS, ENABLE_PROMETHEUS,\
-    has_connectors
+    has_connectors, TASK_SERVER
 from desktop.lib import fsmanager
 from desktop.lib.connectors.api import _get_installed_connectors
 from desktop.lib.i18n import force_unicode
@@ -1902,26 +1902,7 @@ class ClusterConfig(object):
 
 
   def _get_scheduler(self):
-    interpreters = [{
-        'type': 'oozie-workflow',
-        'displayName': _('Workflow'),
-        'buttonName': _('Schedule'),
-        'tooltip': _('Workflow'),
-        'page': '/oozie/editor/workflow/new/'
-      }, {
-        'type': 'oozie-coordinator',
-        'displayName': _('Schedule'),
-        'buttonName': _('Schedule'),
-        'tooltip': _('Schedule'),
-        'page': '/oozie/editor/coordinator/new/'
-      }, {
-        'type': 'oozie-bundle',
-        'displayName': _('Bundle'),
-        'buttonName': _('Schedule'),
-        'tooltip': _('Bundle'),
-        'page': '/oozie/editor/bundle/new/'
-      }
-    ]
+    interpreters = []
 
     if 'oozie' in self.apps and not (self.user.has_hue_permission(action="disable_editor_access", app="oozie") and not is_admin(self.user)):
       interpreters.extend([{
@@ -1945,11 +1926,23 @@ class ClusterConfig(object):
         }
       ])
 
+    if TASK_SERVER.BEAT_ENABLED.get():
+      interpreters.append({
+          'type': 'celery-beat',
+          'displayName': _('Scheduled Tasks'),
+          'buttonName': _('Scheduled Tasks'),
+          'tooltip': _('Scheduled Tasks'),
+          'page': '/jobbrowser/'
+        }
+      )
+
+    if interpreters:
       return {
           'name': 'oozie',
           'displayName': _('Scheduler'),
           'buttonName': _('Schedule'),
           'interpreters': interpreters,
+          'interpreter_names': [interpreter['type'] for interpreter in interpreters],
           'page': interpreters[0]['page']
         }
     else: