Преглед изворни кода

AMBARI-1829. HDFS Mirroring: Display Status and handle maintenance operations like Stop, Suspend, Activate etc. (Arun Kandregula via srimanth)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/trunk@1466218 13f79535-47bb-0310-9956-ffa450edef68
Srimanth пре 12 година
родитељ
комит
ff96a4c758

+ 3 - 0
CHANGES.txt

@@ -12,6 +12,9 @@ Trunk (unreleased changes):
 
  NEW FEATURES
 
+ AMBARI-1829. HDFS Mirroring: Display Status and handle maintenance operations 
+ like Stop, Suspend, Activate etc. (Arun Kandregula via srimanth)
+
  AMBARI-1840. For global properties show restart for appropriate services
  only. (srimanth)
 

+ 25 - 2
ambari-web/app/controllers/main/mirroring/jobs_controller.js

@@ -20,7 +20,30 @@ var App = require('app');
 
 App.MainJobsController = Em.Controller.extend({
   name: 'mainJobsController',
-  jobs: function() {
+  jobs: function () {
     return App.DataSetJob.find().filterProperty('dataset', this.get('content'));
-  }.property('content')
+  }.property('content'),
+
+  actionDesc: function () {
+    var dataset_status = this.get('content.status');
+    if (dataset_status === "SCHEDULED") {
+      return "Suspend";
+    } else {
+      return "Schedule";
+    }
+  }.property('content.status'),
+
+  isScheduled: function () {
+    var dataset_status = this.get('content.status');
+    return dataset_status === "SCHEDULED";
+  }.property('content.status'),
+
+  suspend: function () {
+    this.set('content.status', 'SUSPENDED');
+  },
+
+  schedule: function () {
+    this.set('content.status', 'SCHEDULED');
+  }
+
 });

+ 3 - 1
ambari-web/app/mappers/dataset_mapper.js

@@ -22,6 +22,7 @@ App.dataSetMapper = App.QuickDataMapper.create({
   config: {
     id: 'id', // approach 2 : to be calculated (TBC1)
     name: 'Feeds.name', // from json
+    status: 'Feeds.status', // from json
     source_cluster_name: 'Feeds.clusters.cluster[0].name', // approach1 : from json
     $target_cluster: 'none', // will be loaded outside parser ( TBC2 ),
     source_dir: 'Feeds.locations.location.path',
@@ -40,6 +41,7 @@ App.dataSetMapper = App.QuickDataMapper.create({
   jobs_config: {
     $dataset_id: 'none', // will be loaded outside parser
     id: 'Instances.id',
+    status : 'Instances.status',
     start_date: 'start_date',
     end_date: 'end_date',
     duration: 'duration'
@@ -177,7 +179,7 @@ App.dataSetMapper = App.QuickDataMapper.create({
       }, this);
 
 
-
+      debugger;
       console.debug('Before load: App.Dataset.find().content : ' + App.Dataset.find().content);
       App.store.loadMany(this.get('model'), dataset_results);
       console.debug('After load: App.Dataset.find().content : ' + App.Dataset.find().content);

+ 8 - 7
ambari-web/app/models/dataset.js

@@ -22,6 +22,7 @@ var App = require('app');
 App.Dataset = DS.Model.extend({
   id: DS.attr('string'),
   name: DS.attr('string'),
+  status: DS.attr('string'),
   sourceClusterName: DS.attr('string'),
   targetCluster: DS.belongsTo('App.TargetCluster'),
   sourceDir: DS.attr('string'),
@@ -38,13 +39,13 @@ App.Dataset = DS.Model.extend({
 
 App.Dataset.Schedule = DS.Model.extend({
   id: DS.attr('string'),
-  startDate : DS.attr('string'),
-  endDate :  DS.attr('string'),
-  startTime : DS.attr('string'),
-  endTime : DS.attr('string'),
-  timezone : DS.attr('string'),
-  frequency : DS.attr('string'),
-  dataset : DS.belongsTo('App.Dataset')
+  startDate: DS.attr('string'),
+  endDate: DS.attr('string'),
+  startTime: DS.attr('string'),
+  endTime: DS.attr('string'),
+  timezone: DS.attr('string'),
+  frequency: DS.attr('string'),
+  dataset: DS.belongsTo('App.Dataset')
 });
 
 App.Dataset.FIXTURES = [/*

+ 2 - 1
ambari-web/app/models/dataset_job.js

@@ -22,10 +22,11 @@ var date = require('utils/date');
 
 App.DataSetJob = DS.Model.extend({
   dataset: DS.belongsTo('App.Dataset'),
+  status: DS.attr('string'),
   startDate: DS.attr('number'),
   endDate: DS.attr('number'),
   duration: DS.attr('number'),
-  startDateFormatted: function() {
+  startDateFormatted: function () {
     return date.dateFormatShort(this.get('startDate'));
   }.property('startDate')
   //data : DS.attr('string')

+ 14 - 14
ambari-web/app/models/job.js

@@ -25,22 +25,22 @@ App.Job = DS.Model.extend({
 
   run: DS.belongsTo('App.Run'),
 
-  jobName:DS.attr('string'),
-  workflowEntityName:DS.attr('string'),
-  userName:DS.attr('string'),
-  confPath:DS.attr('string'),
-  submitTime:DS.attr('number'),
-  maps:DS.attr('number'),
-  reduces:DS.attr('number'),
-  status:DS.attr('string'),
-  input:DS.attr('number'),
-  output:DS.attr('number'),
-  elapsedTime:DS.attr('number'),
-  duration: function() {
+  jobName: DS.attr('string'),
+  workflowEntityName: DS.attr('string'),
+  userName: DS.attr('string'),
+  confPath: DS.attr('string'),
+  submitTime: DS.attr('number'),
+  maps: DS.attr('number'),
+  reduces: DS.attr('number'),
+  status: DS.attr('string'),
+  input: DS.attr('number'),
+  output: DS.attr('number'),
+  elapsedTime: DS.attr('number'),
+  duration: function () {
     return date.timingFormat(parseInt(this.get('elapsedTime')));
   }.property('elapsedTime'),
-  jobTimeLine:DS.attr('string'),
-  jobTaskView:DS.attr('string'),
+  jobTimeLine: DS.attr('string'),
+  jobTaskView: DS.attr('string'),
   /**
    *  Sum of input bandwidth for all jobs with appropriate measure
    */

+ 43 - 0
ambari-web/app/templates/main/mirroring/jobs.hbs

@@ -27,6 +27,23 @@
       <p>{{t mirroring.dataset.dateCreated}}: <span class="pull-right">{{view.dataset.createdDate}}</span></p>
     </div>
     <div class="span10">
+      {{#if App.isAdmin}}
+          <div class="mirroring-top-nav button-section pull-right">
+            {{#if isScheduled}}
+                <span class="label label-success">{{content.status}}</span>
+              <a href="javascript:void(null)" data-toggle="modal" class="btn btn-danger" {{action "suspend" target="controller"}}>
+                <i class="icon-pause"></i>
+                {{actionDesc}}
+              </a>
+            {{else}}
+                <span class="label label-important">{{content.status}}</span>
+                <a href="javascript:void(null)" data-toggle="modal" class="btn btn-success" {{action "schedule" target="controller"}}>
+                    <i class="icon-play"></i>
+                  {{actionDesc}}
+                </a>
+            {{/if}}
+          </div>
+      {{/if}}
     <div id="mirroring">
       <table class="table table-bordered table-striped">
         <thead>
@@ -38,6 +55,10 @@
               {{view view.parentView.endSort}}
               {{view view.parentView.durationSort}}
               {{view view.parentView.dataSort}}
+              <th>
+                  {{t common.status}}
+              </th>
+
             {{/view}}
         </tr>
         <tr>
@@ -66,6 +87,28 @@
               </td>
 
               <td>{{job.data}}</td>
+              <td>
+
+                {{#if view.canActionBeTaken}}
+                    <div class="btn-group">
+                        <a {{bindAttr class="view.statusClass"}} data-toggle="dropdown" href="#">
+                            {{view.content.status}}
+                            <span class="caret"></span>
+                        </a>
+                        <ul class="dropdown-menu">
+                          {{#each view.listOfOptions}}
+                              <li><a href="#" {{action "changeStatus" this target="view" on="click"}}>{{title}}</a></li>
+                          {{/each}}
+                        </ul>
+                    </div>
+                 {{else}}
+                    {{#if view.isKilled}}
+                      <span class="label label-important">{{view.content.status}}</span>
+                    {{else}}
+                      <span class="label label-info">{{view.content.status}}</span>
+                    {{/if}}
+                {{/if}}
+              </td>
             {{/view}}
           {{/each}}
         {{else}}

+ 82 - 2
ambari-web/app/views/main/mirroring/jobs_view.js

@@ -26,11 +26,11 @@ App.MainJobsView = App.TableView.extend({
     return this.get('controller.jobs');
   }.property('controller.jobs'),
 
-  didInsertElement: function() {
+  didInsertElement: function () {
     this.set('content', this.get('controller.jobs'));
   },
 
-  dataset: function() {
+  dataset: function () {
     return this.get('controller.content');
   }.property('controller.content'),
 
@@ -105,6 +105,84 @@ App.MainJobsView = App.TableView.extend({
   JobView: Em.View.extend({
     content: null,
     tagName: 'tr',
+    canActionBeTaken: function () {
+      var job_status = this.get('content.status');
+
+      if (job_status == "RUNNING" || job_status == "SUSPENDED") {
+        return true;
+      }
+
+      return false;
+
+    }.property('content.status'),
+
+    isKilled: function () {
+      var job_status = this.get('content.status');
+      return job_status == 'KILLED';
+    }.property(),
+
+    statusClass: function () {
+      var job_status = this.get('content.status');
+      switch (job_status) {
+        case 'RUNNING' :
+          return "btn btn-success dropdown-toggle";
+          break;
+        case 'SUSPENDED' :
+          return "btn btn-warning dropdown-toggle";
+          break;
+        case 'SUCCEEDED' :
+          return "label label-success";
+          break;
+        case 'KILLED' :
+          return "label label-important";
+          break;
+        case 'WAITING' :
+          return "label";
+          break;
+        case 'KILLED' :
+        case 'FAILED' :
+        case 'ERROR' :
+          return "label label-important";
+          break;
+        default :
+          return "label";
+          break;
+      }
+    }.property('content.status'),
+
+    listOfOptions: function () {
+      var listOfActions = [];
+      var status = this.get('content.status');
+      switch (status) {
+        case 'RUNNING' :
+          listOfActions.push({title: 'Suspend', value: 'Suspend'});
+          listOfActions.push({title: 'Abort', value: 'Abort'});
+          break;
+        case 'SUSPENDED' :
+          listOfActions.push({title: 'Resume', value: 'Resume'});
+          listOfActions.push({title: 'Abort', value: 'Abort'});
+          break;
+      }
+      return listOfActions;
+    }.property('content.status'),
+
+    changeStatus: function (event) {
+      var selected = event.context;
+      var self = this;
+      App.showConfirmationPopup(function () {
+        switch (selected.title) {
+          case 'Suspend' :
+            self.set('content.status', 'SUSPENDED');
+            break;
+          case 'Resume' :
+            self.set('content.status', 'RUNNING');
+            break;
+          case 'Abort' :
+            self.set('content.status', 'KILLED');
+            break;
+        }
+      });
+    },
 
     durationFormatted: function () {
       var milliseconds = this.get('content.duration');
@@ -140,4 +218,6 @@ App.MainJobsView = App.TableView.extend({
     return associations;
   }.property()
 
+
+
 });