YARN-7827. Stop and Delete Yarn Service from RM UI fails with HTTP ERROR 404. Contributed by Sunil G

This commit is contained in:
Jian He 2018-02-08 21:32:02 -08:00
parent 1bc03ddf97
commit ddec08d7cc
10 changed files with 42 additions and 22 deletions

View File

@ -24,21 +24,24 @@ export default RESTAbstractAdapter.extend({
restNameSpace: "dashService",
serverName: "DASH",
deployService(request) {
deployService(request, user) {
var url = this.buildURL();
url += "/?user.name=" + user;
return this.ajax(url, "POST", {data: request});
},
stopService(serviceName) {
stopService(serviceName, user) {
var url = this.buildURL();
url += "/" + serviceName;
url += "/?user.name=" + user;
var data = {"state": "STOPPED", "name": serviceName};
return this.ajax(url, "PUT", {data: data});
},
deleteService(serviceName) {
deleteService(serviceName, user) {
var url = this.buildURL();
url += "/" + serviceName;
url += "/?user.name=" + user;
return this.ajax(url, "DELETE", {data: {}});
}
});

View File

@ -27,6 +27,7 @@ export default Ember.Component.extend({
customServiceDef: '',
serviceResp: null,
isLoading: false,
userName: '',
actions: {
showSaveTemplateModal() {
@ -36,11 +37,11 @@ export default Ember.Component.extend({
deployService() {
this.set('serviceResp', null);
if (this.get('isStandardViewType')) {
this.sendAction("deployServiceDef", this.get('serviceDef'));
this.sendAction("deployServiceDef", this.get('serviceDef'), this.get('userName'));
} else {
try {
var parsed = JSON.parse(this.get('customServiceDef'));
this.sendAction("deployServiceJson", parsed);
this.sendAction("deployServiceJson", parsed, this.get('userName'));
} catch (err) {
this.set('serviceResp', {type: 'error', message: 'Invalid JSON: ' + err.message});
throw err;
@ -148,16 +149,21 @@ export default Ember.Component.extend({
isValidTemplateName: Ember.computed.notEmpty('savedTemplateName'),
isUserNameGiven: Ember.computed.empty('userName'),
isValidServiceDef: Ember.computed('serviceDef.name', 'serviceDef.queue', 'serviceDef.serviceComponents.[]', function () {
return this.get('serviceDef').isValidServiceDef();
}),
isValidCustomServiceDef: Ember.computed.notEmpty('customServiceDef'),
enableSaveOrDeployBtn: Ember.computed('isValidServiceDef', 'isValidCustomServiceDef', 'viewType', 'isLoading', function() {
enableSaveOrDeployBtn: Ember.computed('isValidServiceDef', 'isValidCustomServiceDef', 'viewType', 'isLoading', 'isUserNameGiven', function() {
if (this.get('isLoading')) {
return false;
}
if (this.get('isUserNameGiven')) {
return false;
}
if (this.get('isStandardViewType')) {
return this.get('isValidServiceDef');
} else {

View File

@ -43,7 +43,7 @@ export default Ember.Controller.extend({
Ember.$("#stopServiceConfirmDialog").modal('hide');
var adapter = this.store.adapterFor('yarn-servicedef');
self.set('isLoading', true);
adapter.stopService(this.model.serviceName).then(function () {
adapter.stopService(this.model.serviceName, this.get('model.app.user')).then(function () {
self.set('actionResponse', { msg: 'Service stopped successfully. Auto refreshing in 5 seconds.', type: 'success' });
Ember.run.later(self, function () {
this.set('actionResponse', null);
@ -67,7 +67,7 @@ export default Ember.Controller.extend({
Ember.$("#deleteServiceConfirmDialog").modal('hide');
var adapter = this.store.adapterFor('yarn-servicedef');
self.set('isLoading', true);
adapter.deleteService(this.model.serviceName).then(function () {
adapter.deleteService(this.model.serviceName, this.get('model.app.user')).then(function () {
self.set('actionResponse', { msg: 'Service deleted successfully. Redirecting to services in 5 seconds.', type: 'success' });
Ember.run.later(self, function () {
this.set('actionResponse', null);

View File

@ -35,7 +35,7 @@ export default Ember.Controller.extend({
Ember.$("#stopServiceConfirmDialog").modal('hide');
var adapter = this.store.adapterFor('yarn-servicedef');
self.set('isLoading', true);
adapter.stopService(this.get('service')).then(function() {
adapter.stopService(this.get('service'), this.get('model.app.user')).then(function() {
self.set('actionResponse', {msg: 'Service stopped successfully. Auto refreshing in 5 seconds.', type: 'success'});
Ember.run.later(self, function() {
this.set('actionResponse', null);
@ -59,7 +59,7 @@ export default Ember.Controller.extend({
Ember.$("#deleteServiceConfirmDialog").modal('hide');
var adapter = this.store.adapterFor('yarn-servicedef');
self.set('isLoading', true);
adapter.deleteService(this.get('service')).then(function() {
adapter.deleteService(this.get('service'), this.get('model.app.user')).then(function() {
self.set('actionResponse', {msg: 'Service deleted successfully. Redirecting to services in 5 seconds.', type: 'success'});
Ember.run.later(self, function() {
this.set('actionResponse', null);

View File

@ -36,13 +36,13 @@ export default Ember.Controller.extend({
isLoading: false,
actions: {
deployServiceDef(serviceDef) {
deployServiceDef(serviceDef, userName) {
var defjson = serviceDef.getServiceJSON();
this.deployServiceApp(defjson);
this.deployServiceApp(defjson, userName);
},
deployServiceJson(json) {
this.deployServiceApp(json);
deployServiceJson(json, userName) {
this.deployServiceApp(json, userName);
}
},
@ -53,11 +53,11 @@ export default Ember.Controller.extend({
}, 1000);
},
deployServiceApp(requestJson) {
deployServiceApp(requestJson, userName) {
var self = this;
var adapter = this.store.adapterFor('yarn-servicedef');
this.set('isLoading', true);
adapter.deployService(requestJson).then(function() {
adapter.deployService(requestJson, userName).then(function() {
self.set('serviceResponse', {message: 'Service has been accepted successfully. Redirecting to services in a second.', type: 'success'});
self.gotoServices();
}, function(errmsg) {

View File

@ -29,6 +29,16 @@
</div>
</div>
{{/if}}
<div class="row">
<div class="col-md-4">
<div class="form-group shrink-height">
<label class="required">User Name for service</label>
<span class="glyphicon glyphicon-info-sign info-icon" data-info="userName"></span>
{{input type="text" class="form-control" placeholder="User Name" value=userName}}
</div>
<br>
</div>
</div>
<div class="panel panel-default {{if isLoading 'loading-state'}}">
{{#if isLoading}}
<img src="assets/images/spinner.gif" alt="Loading...">

View File

@ -140,12 +140,12 @@
{{confirm-dialog
dialogId="stopServiceConfirmDialog"
message=(concat 'Are you sure you want to stop service "' model.serviceName '" ?')
message=(concat 'Are you sure you want to stop service "' model.serviceName '" for user "' model.app.user '" ?')
action="stopService"
}}
{{confirm-dialog
dialogId="deleteServiceConfirmDialog"
message=(concat 'Are you sure you want to delete service "' model.serviceName '" ?')
message=(concat 'Are you sure you want to delete service "' model.serviceName '" for user "' model.app.user '" ?')
action="deleteService"
}}

View File

@ -128,12 +128,12 @@
{{confirm-dialog
dialogId="stopServiceConfirmDialog"
message=(concat 'Are you sure you want to stop service "' model.serviceName '" ?')
message=(concat 'Are you sure you want to stop service "' model.serviceName '" for user "' model.app.user '" ?')
action="stopService"
}}
{{confirm-dialog
dialogId="deleteServiceConfirmDialog"
message=(concat 'Are you sure you want to delete service "' model.serviceName '" ?')
message=(concat 'Are you sure you want to delete service "' model.serviceName '" for user "' model.app.user '" ?')
action="deleteService"
}}

View File

@ -22,5 +22,6 @@ export default {
lifetime: "Life time (in seconds) of the application from the time it reaches the STARTED state (after which it is automatically destroyed by YARN). For unlimited lifetime do not set a lifetime value.",
components: "One or more components of the application. If the application is HBase say, then the component can be a simple role like master or regionserver. If the application is a complex business webapp then a component can be other applications say Kafka or Storm. Thereby it opens up the support for complex and nested applications.",
configurations: "Set of configuration properties that can be injected into the application components via envs, files and custom pluggable helper docker containers. Files of several standard formats like xml, properties, json, yaml and templates will be supported.",
fileConfigs: "Set of file configurations that needs to be created and made available as a volume in an application component container."
fileConfigs: "Set of file configurations that needs to be created and made available as a volume in an application component container.",
userName: "Name of the user who launches the service."
};

View File

@ -30,7 +30,7 @@ module.exports = { // YARN UI App configurations
cluster: 'ws/v1/cluster',
metrics: 'ws/v1/cluster/metrics',
timelineV2: 'ws/v2/timeline',
dashService: 'ws/v1/services',
dashService: 'app/v1/services',
node: '{nodeAddress}/ws/v1/node'
},
};