GEARPUMP-6: show add/remove worker buttons for admin
Project: http://git-wip-us.apache.org/repos/asf/incubator-gearpump/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-gearpump/commit/02597f75 Tree: http://git-wip-us.apache.org/repos/asf/incubator-gearpump/tree/02597f75 Diff: http://git-wip-us.apache.org/repos/asf/incubator-gearpump/diff/02597f75 Branch: refs/heads/master Commit: 02597f75fe34740bc8db2dff1716a1ba6a9ec693 Parents: 37e0a38 Author: Qian Xu <[email protected]> Authored: Thu Mar 31 16:31:45 2016 +0800 Committer: manuzhang <[email protected]> Committed: Tue Apr 26 14:24:31 2016 +0800 ---------------------------------------------------------------------- project/Build.scala | 2 +- services/dashboard/index.html | 5 +- services/dashboard/services/models/models.js | 7 +++ services/dashboard/services/restapi.js | 29 +++++++++++ .../dashboard/views/apps/submit/submit.html | 7 +-- .../views/cluster/workers/add_worker.html | 46 ++++++++++++++++++ .../views/cluster/workers/add_worker.js | 35 ++++++++++++++ .../views/cluster/workers/workers_listview.html | 17 +++++-- .../views/cluster/workers/workers_listview.js | 51 +++++++++++++++++--- 9 files changed, 183 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-gearpump/blob/02597f75/project/Build.scala ---------------------------------------------------------------------- diff --git a/project/Build.scala b/project/Build.scala index 761c3b9..a99530f 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -308,7 +308,7 @@ object Build extends sbt.Build { "org.webjars.bower" % "vis" % "4.7.0", "org.webjars.bower" % "clipboard.js" % "0.1.1", "org.webjars.npm" % "dashing-deps" % "0.1.2", - "org.webjars.npm" % "dashing" % "0.4.6" + "org.webjars.npm" % "dashing" % "0.4.8" ).map(_.exclude("org.scalamacros", "quasiquotes_2.10")).map(_.exclude("org.scalamacros", "quasiquotes_2.10.3"))) lazy val serviceJSSettings = Seq( http://git-wip-us.apache.org/repos/asf/incubator-gearpump/blob/02597f75/services/dashboard/index.html ---------------------------------------------------------------------- diff --git a/services/dashboard/index.html b/services/dashboard/index.html index 3ba09e3..26511ec 100644 --- a/services/dashboard/index.html +++ b/services/dashboard/index.html @@ -17,7 +17,7 @@ <link rel="stylesheet" href="webjars/ui-select/0.14.2/dist/select.min.css"/> <link rel="stylesheet" href="webjars/angular-loading-bar/0.8.0/build/loading-bar.min.css"/> <link rel="stylesheet" href="webjars/vis/4.7.0/dist/vis.min.css"/> - <link rel="stylesheet" href="webjars/dashing/0.4.6/dist/dashing.min.css"/> + <link rel="stylesheet" href="webjars/dashing/0.4.8/dist/dashing.min.css"/> <!-- Site styles --> <link rel="stylesheet" href="webjars/dashing-deps/0.1.2/roboto/roboto.min.css"/> @@ -62,7 +62,7 @@ <script src="webjars/ng-file-upload/5.0.9/ng-file-upload-all.min.js"></script> <script src="webjars/clipboard.js/0.1.1/clipboard.js"></script> <script src="webjars/dashing-deps/0.1.2/echarts/2.2.7-compact/echarts-all.min.js"></script> -<script src="webjars/dashing/0.4.6/dist/dashing.min.js"></script> +<script src="webjars/dashing/0.4.8/dist/dashing.min.js"></script> <!-- Application --> <script src="dashboard.js"></script> @@ -82,6 +82,7 @@ <script src="views/landing/breadcrumbs.js"></script> <script src="views/landing/header.js"></script> <script src="views/cluster/master/master.js"></script> +<script src="views/cluster/workers/add_worker.js"></script> <script src="views/cluster/workers/workers_listview.js"></script> <script src="views/cluster/workers/worker/worker.js"></script> <script src="views/jvm/jvm_metrics_view.js"></script> http://git-wip-us.apache.org/repos/asf/incubator-gearpump/blob/02597f75/services/dashboard/services/models/models.js ---------------------------------------------------------------------- diff --git a/services/dashboard/services/models/models.js b/services/dashboard/services/models/models.js index f05ff59..794f2ce 100644 --- a/services/dashboard/services/models/models.js +++ b/services/dashboard/services/models/models.js @@ -122,6 +122,9 @@ angular.module('io.gearpump.models', []) configLink: restapi.workerConfigLink(obj.workerId) }); }, + supervisor: function(obj) { + return obj; + }, apps: function(wrapper) { var objs = wrapper.appMasters; return decoder._asAssociativeArray(objs, decoder.appSummary, 'appId'); @@ -362,6 +365,10 @@ angular.module('io.gearpump.models', []) _workerMetrics: function(workerId, args) { return getter._metrics('worker/' + workerId + '/metrics/', 'worker' + workerId, args); }, + supervisor: function() { + return get('supervisor', + decoder.supervisor); + }, apps: function() { return get('master/applist', decoder.apps); http://git-wip-us.apache.org/repos/asf/incubator-gearpump/blob/02597f75/services/dashboard/services/restapi.js ---------------------------------------------------------------------- diff --git a/services/dashboard/services/restapi.js b/services/dashboard/services/restapi.js index f9cdceb..483fcf9 100644 --- a/services/dashboard/services/restapi.js +++ b/services/dashboard/services/restapi.js @@ -187,6 +187,35 @@ angular.module('dashboard') }); }, + /** Add a new worker */ + addWorker: function(onComplete) { + var count = 1; + var url = restapiV1Root + 'supervisor/addworker/' + count; + return $http.post(url).then(function(response) { + if (angular.isFunction(onComplete)) { + onComplete(decodeSuccessResponse(response.data)); + } + }, function(response) { + if (angular.isFunction(onComplete)) { + onComplete(decodeErrorResponse(response.data)); + } + }); + }, + + /** Remove a new worker */ + removeWorker: function(workerId, onComplete) { + var url = restapiV1Root + 'supervisor/removeworker/' + workerId; + return $http.post(url).then(function(response) { + if (angular.isFunction(onComplete)) { + onComplete(decodeSuccessResponse(response.data)); + } + }, function(response) { + if (angular.isFunction(onComplete)) { + onComplete(decodeErrorResponse(response.data)); + } + }); + }, + /** Replace a dag processor at runtime */ replaceDagProcessor: function(files, formFormNames, appId, oldProcessorId, newProcessorDescription, onComplete) { var url = restapiV1Root + 'appmaster/' + appId + '/dynamicdag'; http://git-wip-us.apache.org/repos/asf/incubator-gearpump/blob/02597f75/services/dashboard/views/apps/submit/submit.html ---------------------------------------------------------------------- diff --git a/services/dashboard/views/apps/submit/submit.html b/services/dashboard/views/apps/submit/submit.html index 001a75a..2b15000 100644 --- a/services/dashboard/views/apps/submit/submit.html +++ b/services/dashboard/views/apps/submit/submit.html @@ -10,7 +10,7 @@ <p style="padding-top: 4px; padding-bottom: 14px;">Application will be launched immediately, after the JAR file is uploaded.</p> - <div ng-show="shouldNoticeSubmitFailed"> + <div ng-if="shouldNoticeSubmitFailed"> <div class="alert alert-danger alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" ng-click="shouldNoticeSubmitFailed=false"> @@ -41,8 +41,9 @@ ng-model="conf" accept-pattern="{{confFileSuffix}}"></form-control> <!-- input 3 --> <form-control - type="integer" min="1" label="Executor Count" ng-hide="isStormApp" - help="How many JVM processes to start for this job in the whole cluster. E.g. set it as 12 will start 12 executor processes spanning across the cluster" + ng-if="!isStormApp" + type="integer" min="1" label="Executors" + help="The number of executor (JVM) processes to be spawned in the cluster." ng-model="executorNum"></form-control> <!-- input 4 --> <form-control http://git-wip-us.apache.org/repos/asf/incubator-gearpump/blob/02597f75/services/dashboard/views/cluster/workers/add_worker.html ---------------------------------------------------------------------- diff --git a/services/dashboard/views/cluster/workers/add_worker.html b/services/dashboard/views/cluster/workers/add_worker.html new file mode 100644 index 0000000..d8a1ecf --- /dev/null +++ b/services/dashboard/views/cluster/workers/add_worker.html @@ -0,0 +1,46 @@ +<div class="modal" tabindex="-1"> + <div class="modal-dialog" style="max-width: 440px"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" ng-click="$hide()"> + <span>×</span></button> + <h4>Add Workers</h4> + </div> + <div class="modal-body"> + <p style="padding-top: 4px; padding-bottom: 14px;" ng-bind="description"></p> + + <div ng-if="shouldNoticeSubmitFailed"> + <div class="alert alert-danger alert-dismissible" role="alert"> + <button type="button" class="close" data-dismiss="alert" + ng-click="shouldNoticeSubmitFailed=false"> + <span aria-hidden="true">×</span> + </button> + <h5 style="margin-top: 0">Something went wrong!</h5> + <p ng-bind="error"></p> + </div> + </div> + + <form name="form" class="form-horizontal"> + <!-- right margin align to cancel button right --> + <div style="margin-bottom: 18px"> + <!-- input 1 --> + <form-control + label-style-class="col-sm-4" + control-style-class="col-sm-8" + type="integer" min="1" label="Instance Count" + ng-model="count"></form-control> + </div> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-primary btn-sm" + ng-click="add()"> + <span ng-show="adding" + class="glyphicon glyphicon-repeat rotate-animation"></span> + Add + </button> + <button type="button" class="btn btn-default btn-sm" ng-click="$hide()">Cancel</button> + </div> + </div> + </div> +</div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-gearpump/blob/02597f75/services/dashboard/views/cluster/workers/add_worker.js ---------------------------------------------------------------------- diff --git a/services/dashboard/views/cluster/workers/add_worker.js b/services/dashboard/views/cluster/workers/add_worker.js new file mode 100644 index 0000000..ab4b42e --- /dev/null +++ b/services/dashboard/views/cluster/workers/add_worker.js @@ -0,0 +1,35 @@ +/* + * Licensed under the Apache License, Version 2.0 + * See accompanying LICENSE file. + */ +angular.module('dashboard') + + .controller('AddWorkerCtrl', ['$scope', 'restapi', 'i18n', + function($scope, restapi, i18n) { + 'use strict'; + + $scope.description = i18n.terminology.worker; + $scope.count = 1; + + $scope.add = function() { + $scope.adding = true; + $scope.shouldNoticeSubmitFailed = false; + return restapi.addWorker( + function handleResponse(response) { + $scope.shouldNoticeSubmitFailed = !response.success; + $scope.adding = false; + if (response.success) { + $scope.$hide(); + } else { + $scope.error = response.error; + } + }, + function handleException(ex) { + $scope.shouldNoticeSubmitFailed = true; + $scope.adding = false; + $scope.error = ex; + } + ); + }; + }]) +; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-gearpump/blob/02597f75/services/dashboard/views/cluster/workers/workers_listview.html ---------------------------------------------------------------------- diff --git a/services/dashboard/views/cluster/workers/workers_listview.html b/services/dashboard/views/cluster/workers/workers_listview.html index f0eecf4..1f5295d 100644 --- a/services/dashboard/views/cluster/workers/workers_listview.html +++ b/services/dashboard/views/cluster/workers/workers_listview.html @@ -2,10 +2,21 @@ <!-- control toolbar --> <div class="row"> <div class="col-md-6"> - <span class="table-caption-ext">Workers</span> + <span class="table-caption-ext pull-left">Workers</span> + <!-- dropdown button --> + <div ng-if="isSupervisor" + class="btn-group btn-group-after-heading"> + <span class="btn btn-xs btn-default pull-left" + ng-click="showAddWorkerDialog()"> + <span class="fa fa-plus"></span> + Add</span> + </div> </div> - <div class="col-md-3 col-md-offset-3 hidden-sm hidden-xs"> - <searchbox ng-model="search" placeholder="Search Anything"></searchbox> + <div class="col-md-3 col-sm-6 text-right"> + <!--FILTER--> + </div> + <div class="col-md-3 hidden-sm hidden-xs"> + <searchbox ng-model="search" placeholder="Search Workers"></searchbox> </div> </div> <!-- end of control toolbar --> http://git-wip-us.apache.org/repos/asf/incubator-gearpump/blob/02597f75/services/dashboard/views/cluster/workers/workers_listview.js ---------------------------------------------------------------------- diff --git a/services/dashboard/views/cluster/workers/workers_listview.js b/services/dashboard/views/cluster/workers/workers_listview.js index 3cdf14e..c277b38 100644 --- a/services/dashboard/views/cluster/workers/workers_listview.js +++ b/services/dashboard/views/cluster/workers/workers_listview.js @@ -18,28 +18,33 @@ angular.module('dashboard') resolve: { workers0: ['models', function(models) { return models.$get.workers(); + }], + supervisor0: ['models', function(models) { + return models.$get.supervisor(); }] } }); }]) - .controller('WorkersListViewCtrl', ['$scope', '$sortableTableBuilder', 'workers0', - function($scope, $stb, workers0) { + .controller('WorkersListViewCtrl', ['$scope', '$modal', '$sortableTableBuilder', '$dialogs', + 'restapi', 'workers0', 'supervisor0', + function($scope, $modal, $stb, $dialogs, restapi, workers0, supervisor0) { 'use strict'; + $scope.isSupervisor = (supervisor0.path||'').length > 0; $scope.workersTable = { cols: [ // group 1/3 (4-col) $stb.indicator().key('state').canSort('state.condition+"_"+aliveFor').styleClass('td-no-padding').done(), - $stb.link('ID').key('id').canSort().sortDefaultDescent().styleClass('col-md-1').done(), - $stb.text('Address').key('akkaAddr').canSort().styleClass('col-md-1').done(), - $stb.text('JVM Info').key('jvm').styleClass('col-md-2 hidden-xs').done(), + $stb.link('ID').key('id').canSort().sortDefaultDescent().done(), + $stb.text('JVM Info').key('jvm').styleClass('col-md-1').done(), + $stb.text('Address').key('akkaAddr').canSort().styleClass('col-md-3 hidden-xs').done(), // group 2/3 (5-col) $stb.number('Executors').key('executors').canSort().styleClass('col-md-1 hidden-xs').done(), $stb.progressbar('Slots Usage').key('slots').sortBy('slots.usage').styleClass('col-md-1').done(), $stb.duration('Uptime').key('aliveFor').canSort().styleClass('col-md-3 hidden-sm hidden-xs').done(), // group 3/3 (3-col) - $stb.button('Quick Links').key(['detail', 'conf']).styleClass('col-md-3').done() + $stb.button('Quick Links').key(['detail', 'conf', 'kill']).styleClass('col-md-3').done() ], rows: null }; @@ -56,7 +61,27 @@ angular.module('dashboard') slots: {current: worker.slots.used, max: worker.slots.total, usage: worker.slots.usage}, executors: worker.executors.length || 0, detail: {href: worker.pageUrl, text: 'Details', class: 'btn-xs btn-primary'}, - conf: {href: worker.configLink, target: '_blank', text: 'Config', class: 'btn-xs'} + conf: {href: worker.configLink, target: '_blank', text: 'Config', class: 'btn-xs'}, + kill: { + text: 'Kill', class: 'btn-xs', + disabled: !$scope.isSupervisor, + click: function() { + $dialogs.confirm('Are you sure to kill this worker?', function() { + restapi.removeWorker(worker.workerId, + function handleResponse(response) { + if (response.success) { + window.location.reload(); + } else { + $dialogs.notice(response.error, 'Something went wrong'); + } + }, + function handleException(ex) { + $dialogs.notice(ex, 'Something went wrong'); + } + ); + }); + } + }, }; })); } @@ -65,5 +90,17 @@ angular.module('dashboard') workers0.$subscribe($scope, function(data) { updateTable(data); }); + + var addWorkerDialog = $modal({ + templateUrl: 'views/cluster/workers/add_worker.html', + controller: 'AddWorkerCtrl', + backdrop: 'static', + keyboard: true, + show: false + }); + + $scope.showAddWorkerDialog = function() { + addWorkerDialog.$promise.then(addWorkerDialog.show); + }; }]) ; \ No newline at end of file
