Repository: ambari Updated Branches: refs/heads/branch-2.1 c33e7d722 -> 2580916a6
http://git-wip-us.apache.org/repos/asf/ambari/blob/2580916a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js index b8748cb..366d18c 100644 --- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js +++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js @@ -24,89 +24,113 @@ moduleFor('controller:settings', 'SettingsController', { 'controller:databases', 'controller:index', 'controller:open-queries', - 'controller:loaded-files', 'controller:index/history-query/results', 'controller:index/history-query/explain', - 'controller:columns', 'controller:udfs', 'controller:index/history-query/logs', 'controller:visual-explain', 'controller:tez-ui', - 'controller:tables', - 'controller:job-progress', 'adapter:database', - 'adapter:application' + 'adapter:application', + 'service:settings', + 'service:notify', + 'service:database', + 'service:file', + 'service:session', + 'service:job', + 'service:job-progress' ] }); -// test('can add a setting', function() { -// var controller = this.subject(); +test('can add a setting', function() { + var controller = this.subject(); -// ok(!controller.get('currentSettings.settings.length'), 'No initial settings'); + ok(!controller.get('settings.length'), 'No initial settings'); -// Ember.run(function() { -// controller.send('add'); -// }); + Ember.run(function() { + controller.send('add'); + }); -// equal(controller.get('currentSettings.settings.length'), 1, 'Can add settings'); -// }); - -// test('hasSettings return true if there are settings', function() { -// var controller = this.subject(); - -// controller.get('currentSettings'); -// ok(!controller.hasSettings(null), 'No settings => return false'); - -// Ember.run(function() { -// controller.send('add'); -// }); - -// ok(controller.hasSettings(null), '1 setting => returns true'); -// }); - -// test('setSettingForQuery', function() { -// var controller = this.subject(); - -// var settings = [ Ember.Object.create({key: 'key', value: 'value'}) ]; - -// Ember.run(function() { -// controller.setSettingForQuery(1, settings); -// }); - -// equal(controller.get('currentSettings.settings.firstObject.key'), settings.get('key'), 'It sets the settings for specified query'); -// }); + equal(controller.get('settings.length'), 1, 'Can add settings'); +}); -// test('validate', function() { -// var predefinedSettings = [ -// { -// name: 'some.key', -// validate: new RegExp(/^\d+$/) // digits -// } -// ]; +test('validate', function() { + var predefinedSettings = [ + { + name: 'some.key', + validate: new RegExp(/^\d+$/) // digits + } + ]; + + var controller = this.subject({ + predefinedSettings: predefinedSettings + }); + + controller.set('openQueries.update', function () { + var defer = Ember.RSVP.defer(); + defer.resolve(); + + return defer.promise; + }); + + var settings = [ + Ember.Object.create({key: { name: 'some.key' }, value: 'value'}), + Ember.Object.create({key: { name: 'some.key' }, value: '123'}) + ]; + + Ember.run(function() { + controller.set('settings', settings); + }); + + var currentSettings = controller.get('settings'); + ok(!currentSettings.get('firstObject.valid'), "First setting doesn\' pass validataion"); + ok(currentSettings.get('lastObject.valid'), 'Second setting passes validation'); +}); -// var controller = this.subject({ -// predefinedSettings: predefinedSettings -// }); +test('Actions', function(assert) { + assert.expect(5); + + var settingsService = Ember.Object.create({ + add: function() { + assert.ok(true, 'add called'); + }, + remove: function(setting) { + assert.ok(setting, 'Setting param is sent'); + }, + createKey: function(name) { + assert.ok(name, 'Name param is sent'); + }, + removeAll: function() { + assert.ok(true, 'removeAll called'); + }, + saveDefaultSettings: function() { + assert.ok(true, 'saveDefaultSettings called'); + } + }); + + var controller = this.subject(); + controller.set('settingsService', settingsService); + + Ember.run(function() { + controller.send('add'); + controller.send('remove', {}); + controller.send('addKey', {}); + controller.send('removeAll'); + controller.send('saveDefaultSettings'); + }); +}); -// controller.set('openQueries.update', function () { -// var defer = Ember.RSVP.defer(); -// defer.resolve(); -// return defer.promise; -// }); +test('Excluded settings', function(assert) { + var controller = this.subject(); -// var settings = [ -// Ember.Object.create({key: { name: 'some.key' }, value: 'value'}), -// Ember.Object.create({key: { name: 'some.key' }, value: '123'}) -// ]; + console.log(controller.get('predefinedSettings')); + assert.equal(controller.get('excluded').length, 0, 'Initially there are no excluded settings'); -// Ember.run(function() { -// controller.set('index.model', Ember.Object.create({ id: 1 })); -// controller.get('currentSettings'); -// controller.setSettingForQuery(1, settings); -// }); + Ember.run(function() { + controller.get('settings').pushObject(Ember.Object.create({ key: { name: 'hive.tez.container.size' }})); + controller.get('settings').pushObject(Ember.Object.create({ key: { name: 'hive.prewarm.enabled' }})); + }); -// var currentSettings = controller.get('model.firstObject.settings'); -// ok(!currentSettings.get('firstObject.valid'), "First setting doesn\' pass validataion"); -// ok(currentSettings.get('lastObject.valid'), 'Second setting passes validation'); -// }); + assert.equal(controller.get('excluded').length, 2, 'Two settings are excluded'); +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/2580916a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/tez-ui-test.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/tez-ui-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/tez-ui-test.js index e03b561..fdf4a89 100644 --- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/tez-ui-test.js +++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/tez-ui-test.js @@ -35,10 +35,12 @@ moduleFor('controller:tez-ui', 'TezUIController', { 'controller:index/history-query/explain', 'controller:settings', 'controller:visual-explain', - 'controller:job-progress', 'adapter:database', 'service:database', - 'service:notify' + 'service:notify', + 'service:job-progress', + 'service:session', + 'service:settings' ], setup: function() { http://git-wip-us.apache.org/repos/asf/ambari/blob/2580916a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udf-test.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udf-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udf-test.js deleted file mode 100644 index 8fd643e..0000000 --- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/udf-test.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import Ember from 'ember'; -import { moduleFor, test } from 'ember-qunit'; - -moduleFor('controller:udf', 'UdfController', {}); - -test('controller is initialized', function() { - expect(2); - - var model = Ember.Object.create({ - id: 1, - name: 'udfmodel', - classname: 'cls', - isNew: true, - fileResource: 'fileresource' - }); - - var component = this.subject({ model: model}); - - ok(component.get('isEditing'), 'Model is new, isEditing is set to true'); - equal(component.get('fileBackup'), model.get('fileResource'), 'fileBackup is set to model.fileResource'); -}); - -test('addFileResource', function() { - expect(3); - - var model = Ember.Object.create({ - id: 1, - name: 'udfmodel', - classname: 'cls', - isNew: true, - fileResource: null - }); - - var store = { - createRecord: function() { - return 'newfileresource'; - } - }; - - var component = this.subject({model: model, store: store }); - - equal(component.get('model.fileResource'), null, 'fileResource is set to null'); - - Ember.run(function () { - component.send('addFileResource'); - }); - - ok(component.get('isEditingResource'), 'isEditingResource is set to true'); - equal(component.get('model.fileResource'), store.createRecord(), 'New file resource is set on the model'); -}); - -test('editFileResource', function() { - expect(3); - - var model = Ember.Object.create({ - id: 1, - name: 'udfmodel', - classname: 'cls', - isNew: true, - fileResource: null - }); - - var file = 'fileresource'; - var component = this.subject({model: model }); - - equal(component.get('model.fileResource'), null, 'fileResource is set to null'); - - Ember.run(function () { - component.send('editFileResource', file); - }); - - ok(component.get('isEditingResource'), 'isEditingResource is set to true'); - equal(component.get('model.fileResource'), file, 'New file resource is set on the model'); -}); http://git-wip-us.apache.org/repos/asf/ambari/blob/2580916a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/services/settings-test.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/services/settings-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/services/settings-test.js new file mode 100644 index 0000000..cb99882 --- /dev/null +++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/services/settings-test.js @@ -0,0 +1,155 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Ember from 'ember'; +import { moduleFor, test } from 'ember-qunit'; + +moduleFor('service:settings', 'SettingsService'); + +test('Init', function(assert) { + var service = this.subject(); + assert.ok(service); +}); + +test('Can create a setting object', function(assert) { + assert.expect(2); + + var service = this.subject(); + + var setting = service._createSetting('sName', 'sValue'); + + assert.equal(setting.get('key.name'), 'sName', 'Settign has the correct name'); + assert.equal(setting.get('value'), 'sValue', 'Settign has the correct value'); + + service.removeAll(); +}); + +test('Can create default settings', function(assert) { + assert.expect(2); + + var service = this.subject(); + + var settings = { + 'sName1': 'sValue1', + 'sName2': 'sValue2', + 'sName3': 'sValue3' + }; + + service._createDefaultSettings(); + + assert.equal(service.get('settings.length'), 0, '0 settings created'); + + service._createDefaultSettings(settings); + + assert.equal(service.get('settings.length'), 3, '3 settings created'); + + service.removeAll(); +}); + +test('Can add a setting', function(assert) { + assert.expect(2); + + var service = this.subject(); + assert.equal(service.get('settings.length'), 0, 'No settings'); + service.add(); + service.add(); + assert.equal(service.get('settings.length'), 2, '2 settings added'); + + service.removeAll(); +}); + +test('Can remove a setting', function(assert) { + assert.expect(2); + + var service = this.subject(); + + service.add(); + service.add(); + + assert.equal(service.get('settings.length'), 2, '2 settings added'); + var firstSetting = service.get('settings.firstObject'); + service.remove(firstSetting); + assert.equal(service.get('settings.length'), 1, 'Setting removed'); + + service.removeAll(); +}); + +test('Can create key', function(assert) { + assert.expect(2); + var service = this.subject(); + + assert.ok(!service.get('predefinedSettings').findBy('name', 'new.key.name'), 'Key doesn\'t exist'); + + var setting = service._createSetting(); + setting.set('key', null); + service.get('settings').pushObject(setting); + service.createKey('new.key.name'); + + assert.ok(service.get('predefinedSettings').findBy('name', 'new.key.name'), 'Key created'); + + service.removeAll(); +}); + +test('Can get settings string', function(assert) { + var service = this.subject(); + + var noSettings = service.getSettings(); + assert.equal(noSettings, "", 'An empty string is returned if there are no settings'); + + var settings = { + 'sName1': 'sValue1', + 'sName2': 'sValue2' + }; + + service._createDefaultSettings(settings); + + var expectedWithSettings = "set sName1=sValue1;\nset sName2=sValue2;\n--Global Settings--\n\n"; + var withSettings = service.getSettings(); + + assert.equal(withSettings, expectedWithSettings, 'Returns correct string'); +}); + +test('It can parse global settings', function(assert) { + var service = this.subject(); + + assert.ok(!service.parseGlobalSettings(), 'It returns if query or model is not passed'); + + var settings = { + 'sName1': 'sValue1', + 'sName2': 'sValue2' + }; + + + var globalSettingsString = "set sName1=sValue1;\nset sName2=sValue2;\n--Global Settings--\n\n"; + + var model = Ember.Object.create({ + globalSettings: globalSettingsString + }); + + var query = Ember.Object.create({ + fileContent: globalSettingsString + "{{match}}" + }); + + assert.ok(!service.parseGlobalSettings(query, model), 'It returns if current settings don\'t match models global settings'); + + service._createDefaultSettings(settings); + + service.parseGlobalSettings(query, model); + + assert.equal(query.get('fileContent'), "{{match}}", 'It parsed global settings'); +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/2580916a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/AmbariApi.java ---------------------------------------------------------------------- diff --git a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/AmbariApi.java b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/AmbariApi.java index fcf070d..f18448c 100644 --- a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/AmbariApi.java +++ b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/AmbariApi.java @@ -118,6 +118,21 @@ public class AmbariApi { } /** + * Returns first host with requested component installed + * @param requestComponent name of component + * @return any hostname of node that contains the component + * @throws AmbariApiException + */ + public String getAnyHostWithComponent(String requestComponent) throws AmbariApiException { + List<String> foundHosts = getHostsWithComponent(requestComponent); + + if (foundHosts.size() == 0) { + throw new AmbariApiException("RA100 Host with component " + requestComponent + " not found"); + } + return foundHosts.get(0); + } + + /** * Shortcut for GET method * @param path REST API path * @return response http://git-wip-us.apache.org/repos/asf/ambari/blob/2580916a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/Services.java ---------------------------------------------------------------------- diff --git a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/Services.java b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/Services.java index 9ee6628..0b49076 100644 --- a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/Services.java +++ b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/ambari/Services.java @@ -22,7 +22,13 @@ import org.apache.ambari.view.ViewContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.util.HashMap; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Utilities for specific Hadoop services and util functions for them @@ -32,6 +38,7 @@ public class Services { public static final String HTTP_ONLY = "HTTP_ONLY"; public static final String YARN_SITE = "yarn-site"; public static final String YARN_HTTP_POLICY = "yarn.http.policy"; + public static final String YARN_RESOURCEMANAGER_HA_ENABLED = "yarn.resourcemanager.ha.enabled"; private final AmbariApi ambariApi; private ViewContext context; @@ -55,6 +62,7 @@ public class Services { if (ambariApi.isClusterAssociated()) { String protocol; + String haEnabled = ambariApi.getCluster().getConfigurationValue(YARN_SITE, YARN_RESOURCEMANAGER_HA_ENABLED); String httpPolicy = ambariApi.getCluster().getConfigurationValue(YARN_SITE, YARN_HTTP_POLICY); if (httpPolicy.equals(HTTPS_ONLY)) { protocol = "https"; @@ -68,6 +76,10 @@ public class Services { } url = addProtocolIfMissing(url, protocol); + + if (haEnabled != null && haEnabled.equals("true")) { + url = getActiveRMUrl(url); + } } else { url = context.getProperties().get("yarn.resourcemanager.url"); if (!hasProtocol(url)) { @@ -75,9 +87,42 @@ public class Services { "RA070 View is not cluster associated. Resource Manager URL should contain protocol."); } } + return removeTrailingSlash(url); + } + + private String removeTrailingSlash(String url) { + if (url.endsWith("/")) { + url = url.substring(0, url.length() - 1); + } return url; } + public final Pattern refreshHeaderUrlPattern = Pattern.compile("^\\d+;\\s*url=(.*)$"); + + /** + * Returns active RM URL. Makes a request to RM passed as argument. + * If response contains Refresh header then passed url was standby RM. + * @param url url of random RM + * @return url of active RM + */ + private String getActiveRMUrl(String url) { + String activeRMUrl = url; + try { + HttpURLConnection httpURLConnection = context.getURLConnectionProvider(). + getConnection(url, "GET", (String) null, new HashMap<String, String>()); + String refreshHeader = httpURLConnection.getHeaderField("Refresh"); + if (refreshHeader != null) { // we hit standby RM + Matcher matcher = refreshHeaderUrlPattern.matcher(refreshHeader); + if (matcher.find()) { + activeRMUrl = matcher.group(1); + } + } + } catch (IOException e) { + throw new AmbariApiException("RA110 ResourceManager is not accessible"); + } + return activeRMUrl; + } + /** * Returns URL to WebHCat in format like http://<hostname>:<port>/templeton/v1 * @return url to WebHCat