You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ja...@apache.org on 2015/12/11 01:09:55 UTC
ambari git commit: AMBARI-14337. Add service wizard hangs up on
Customize Services step on secure cluster after RU. (jaimin)
Repository: ambari
Updated Branches:
refs/heads/trunk 7bb890075 -> 7e52e66d5
AMBARI-14337. Add service wizard hangs up on Customize Services step on secure cluster after RU. (jaimin)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/7e52e66d
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/7e52e66d
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/7e52e66d
Branch: refs/heads/trunk
Commit: 7e52e66d5f2c118f822d4b0d9e1bc9eb6043663c
Parents: 7bb8900
Author: Jaimin Jetly <ja...@hortonworks.com>
Authored: Thu Dec 10 16:08:54 2015 -0800
Committer: Jaimin Jetly <ja...@hortonworks.com>
Committed: Thu Dec 10 16:09:46 2015 -0800
----------------------------------------------------------------------
.../app/mixins/wizard/addSecurityConfigs.js | 3 +-
ambari-web/app/utils/object_utils.js | 142 ++++++
ambari-web/test/utils/object_utils_test.js | 442 +++++++++++++++++++
3 files changed, 586 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/7e52e66d/ambari-web/app/mixins/wizard/addSecurityConfigs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/wizard/addSecurityConfigs.js b/ambari-web/app/mixins/wizard/addSecurityConfigs.js
index b010fcf..5b2bce8 100644
--- a/ambari-web/app/mixins/wizard/addSecurityConfigs.js
+++ b/ambari-web/app/mixins/wizard/addSecurityConfigs.js
@@ -17,6 +17,7 @@
*/
var App = require('app');
+var objectUtils = require('utils/object_utils');
/**
* Mixin for loading and setting secure configs
@@ -70,7 +71,7 @@ App.AddSecurityConfigs = Em.Mixin.create({
this.loadStackDescriptorConfigs().then(function(data) {
var stackArtifacts = data;
self.loadClusterDescriptorConfigs().then(function(clusterArtifacts) {
- dfd.resolve(self.createServicesStackDescriptorConfigs($.extend(true, {}, stackArtifacts, clusterArtifacts)));
+ dfd.resolve(self.createServicesStackDescriptorConfigs(objectUtils.deepMerge(data, clusterArtifacts)));
}, function() {
dfd.resolve(self.createServicesStackDescriptorConfigs(stackArtifacts));
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/7e52e66d/ambari-web/app/utils/object_utils.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/object_utils.js b/ambari-web/app/utils/object_utils.js
index 294fb95..2f68631 100644
--- a/ambari-web/app/utils/object_utils.js
+++ b/ambari-web/app/utils/object_utils.js
@@ -18,6 +18,17 @@
var stringUtils = require('utils/string_utils');
+var types = {
+ 'get': function(prop) {
+ return Object.prototype.toString.call(prop);
+ },
+ 'object': '[object Object]',
+ 'array': '[object Array]',
+ 'string': '[object String]',
+ 'boolean': '[object Boolean]',
+ 'number': '[object Number]'
+};
+
module.exports = {
isChild: function(obj)
@@ -162,5 +173,136 @@ module.exports = {
return leaf;
}
return r(obj,'');
+ },
+
+ /**
+ *
+ * @param {object|array|object[]} target
+ * @param {object|array|object[]} source
+ * @param {function} handler
+ * @returns {object|array|object[]}
+ */
+ deepMerge: function(target, source, handler) {
+ if (typeof target !== 'object' || typeof source !== 'object') return target;
+ var handlerOpts = Array.prototype.slice.call(arguments, 3);
+ var isArray = Em.isArray(source);
+ var ret = handler && typeof handler.apply(this, [target, source].concat(handlerOpts)) !== 'undefined' ?
+ handler(target, source) :
+ isArray ? [] : {};
+ var self = this;
+
+ // handle array
+ if (isArray) {
+ target = target || [];
+ ret = ret.concat(target);
+
+ if (types.object === types.get(target[0])) {
+ ret = self.smartArrayObjectMerge(target, source);
+ } else {
+ for(var i = 0; i < source.length; i++) {
+ if (typeof ret[i] === 'undefined') {
+ ret[i] = source[i];
+ } else if (typeof source[i] === 'object') {
+ ret[i] = this.deepMerge(target[i], source[i], handler, target, source);
+ } else {
+ if (target.indexOf(source[i]) === -1) {
+ ret.push(source[i]);
+ }
+ }
+ }
+ }
+ } else {
+ if (target && typeof target === 'object') {
+ Em.keys(target).forEach(function(key) {
+ ret[key] = target[key];
+ });
+ }
+ Em.keys(source).forEach(function(key) {
+ // handle value which is not Array or Object
+ if (typeof source[key] !== 'object' || !source[key]) {
+ ret[key] = source[key];
+ } else {
+ if (!target[key]) {
+ ret[key] = source[key];
+ } else {
+ ret[key] = self.deepMerge(target[key], source[key], handler, target, source);
+ }
+ }
+ });
+ }
+
+ return ret;
+ },
+
+ /**
+ * Find objects by index key (@see detectIndexedKey) and merge them.
+ *
+ * @param {object[]} target
+ * @param {object[]} source
+ * @returns {object[]}
+ */
+ smartArrayObjectMerge: function(target, source) {
+ // keep the first object and take all keys that contains primitive value
+ var id = this.detectIndexedKey(target);
+ var self = this;
+ // when uniq key not found let's merge items by the key itself
+ if (!id) {
+ source.forEach(function(obj) {
+ Em.keys(obj).forEach(function(objKey) {
+ var ret = self.objectByRoot(objKey, target);
+ if (!Em.isNone(ret)) {
+ if ([types.object, types.array].contains(types.get(ret))) {
+ target[objKey] = self.deepMerge(obj[objKey], ret);
+ } else {
+ target[objKey] = ret;
+ }
+ } else {
+ var _obj = {};
+ _obj[objKey] = obj[objKey];
+ target.push(_obj);
+ }
+ });
+ });
+ return target;
+ }
+
+ return target.mapProperty(id).concat(source.mapProperty(id)).uniq().map(function(value) {
+ if (!target.someProperty(id, value)) {
+ return source.findProperty(id, value);
+ } else if (!source.someProperty(id, value)) {
+ return target.findProperty(id, value);
+ }
+ return self.deepMerge(target.findProperty(id, value), source.findProperty(id, value));
+ });
+ },
+
+ /**
+ * Determines key with uniq value. This key will be used to find correct objects in target and source to merge.
+ *
+ * @param {object} target
+ * @returns {string|undefined}
+ */
+ detectIndexedKey: function(target) {
+ var keys = Em.keys(target[0]).map(function(key) {
+ if ([types.object, types.array].contains(types.get(target[0][key]))) {
+ return null;
+ }
+ return key;
+ }).compact();
+ return keys.filter(function(key) {
+ var values = target.mapProperty(key);
+ return values.length === values.uniq().length;
+ })[0];
+ },
+
+ /**
+ *
+ * @param {string} rootKey
+ * @param {object[]} target
+ */
+ objectByRoot: function(rootKey, target) {
+ return target.map(function(item) {
+ return item[rootKey] || null;
+ }).compact()[0];
}
};
http://git-wip-us.apache.org/repos/asf/ambari/blob/7e52e66d/ambari-web/test/utils/object_utils_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/object_utils_test.js b/ambari-web/test/utils/object_utils_test.js
index 1c84d78..35e7689 100644
--- a/ambari-web/test/utils/object_utils_test.js
+++ b/ambari-web/test/utils/object_utils_test.js
@@ -178,4 +178,446 @@ describe('utils/object_utils', function() {
});
});
+ describe('#deepMerge', function() {
+ var tests = [
+ {
+ target: {
+ a: [
+ {
+ c: 3
+ }
+ ]
+ },
+ source: {
+ a: [
+ {
+ b: 2
+ }
+ ]
+ },
+ e: {
+ a: [
+ {
+ c: 3
+ },
+ {
+ b: 2
+ }
+ ]
+ }
+ },
+ {
+ target: {
+ a: {}
+ },
+ source: {
+ a: {
+ b: 2,
+ c: [1,2,3]
+ }
+ },
+ e: {
+ a: {
+ b: 2,
+ c: [1,2,3]
+ }
+ }
+ },
+ {
+ target: {
+ artifact_data: {
+ services: [
+ {
+ name: "HIVE",
+ configurations: [
+ {
+ "hive-site": {
+ hive_prop1: "hive_val1"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ },
+ source: {
+ artifact_data: {
+ services: [
+ {
+ name: "HDFS",
+ configurations: [
+ {
+ "hdfs-site": {
+ hdfs_prop1: "hdfs_val1"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ },
+ e: {
+ artifact_data: {
+ services: [
+ {
+ name: "HIVE",
+ configurations: [
+ {
+ "hive-site": {
+ hive_prop1: "hive_val1"
+ }
+ }
+ ]
+ },
+ {
+ name: "HDFS",
+ configurations: [
+ {
+ "hdfs-site": {
+ hdfs_prop1: "hdfs_val1"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ source: {
+ "artifact_data" : {
+ "identities" : [
+ {
+ "principal" : {
+ "value" : "HTTP/_HOST@${realm}",
+ "type" : "service"
+ },
+ "name" : "spnego",
+ "keytab" : {
+ "file" : "${keytab_dir}/spnego.service.keytab",
+ "owner" : {
+ "name" : "root",
+ "access" : "r"
+ },
+ "group" : {
+ "name" : "${cluster-env/user_group}",
+ "access" : "r"
+ }
+ }
+ },
+ {
+ "principal" : {
+ "value" : "${cluster-env/smokeuser}-----@${realm}",
+ "local_username" : "${cluster-env/smokeuser}",
+ "configuration" : "cluster-env/smokeuser_principal_name",
+ "type" : "user"
+ },
+ "name" : "smokeuser",
+ "keytab" : {
+ "file" : "${keytab_dir}/smokeuser.headless.keytab",
+ "owner" : {
+ "name" : "${cluster-env/smokeuser}",
+ "access" : "r"
+ },
+ "configuration" : "cluster-env/smokeuser_keytab",
+ "group" : {
+ "name" : "${cluster-env/user_group}",
+ "access" : "r"
+ }
+ }
+ }
+ ]
+ }
+ },
+ target: {
+ "artifact_data" : {
+ "identities" : [
+ {
+ "principal" : {
+ "value" : "${cluster-env/smokeuser}@${realm}",
+ "local_username" : "${cluster-env/smokeuser}",
+ "configuration" : "cluster-env/smokeuser_principal_name",
+ "type" : "user"
+ },
+ "name" : "smokeuser",
+ "keytab" : {
+ "file" : "${keytab_dir}/smokeuser.headless.keytab",
+ "owner" : {
+ "name" : "${cluster-env/smokeuser}",
+ "access" : "r"
+ },
+ "configuration" : "cluster-env/smokeuser_keytab",
+ "group" : {
+ "name" : "${cluster-env/user_group}",
+ "access" : "r"
+ }
+ }
+ },
+ {
+ "principal" : {
+ "value" : "HTTP/_HOST@${realm}",
+ "local_username" : null,
+ "configuration" : null,
+ "type" : "service"
+ },
+ "name" : "spnego",
+ "keytab" : {
+ "file" : "${keytab_dir}/spnego.service.keytab",
+ "owner" : {
+ "name" : "root",
+ "access" : "r"
+ },
+ "configuration" : null,
+ "group" : {
+ "name" : "${cluster-env/user_group}",
+ "access" : "d"
+ }
+ }
+ },
+ {
+ "name": "anotherOne"
+ }
+ ]
+ }
+ },
+ e: {
+ "artifact_data" : {
+ "identities" : [
+ {
+ "principal" : {
+ "value" : "${cluster-env/smokeuser}-----@${realm}",
+ "local_username" : "${cluster-env/smokeuser}",
+ "configuration" : "cluster-env/smokeuser_principal_name",
+ "type" : "user"
+ },
+ "name" : "smokeuser",
+ "keytab" : {
+ "file" : "${keytab_dir}/smokeuser.headless.keytab",
+ "owner" : {
+ "name" : "${cluster-env/smokeuser}",
+ "access" : "r"
+ },
+ "configuration" : "cluster-env/smokeuser_keytab",
+ "group" : {
+ "name" : "${cluster-env/user_group}",
+ "access" : "r"
+ }
+ }
+ },
+ {
+ "principal" : {
+ "value" : "HTTP/_HOST@${realm}",
+ "local_username" : null,
+ "configuration" : null,
+ "type" : "service"
+ },
+ "name" : "spnego",
+ "keytab" : {
+ "file" : "${keytab_dir}/spnego.service.keytab",
+ "owner" : {
+ "name" : "root",
+ "access" : "r"
+ },
+ "configuration" : null,
+ "group" : {
+ "name" : "${cluster-env/user_group}",
+ "access" : "r"
+ }
+ }
+ },
+ {
+ "name": "anotherOne"
+ }
+ ]
+ }
+ }
+ }
+ ];
+
+ tests.forEach(function(test) {
+ it("Should merge objects `{0}`, `{1}`".format(JSON.stringify(test.target), JSON.stringify(test.source)), function() {
+ expect(objectUtils.deepMerge(test.target, test.source, test.handler)).to.be.eql(test.e);
+ });
+ });
+ });
+
+ describe('#detectIndexedKey', function() {
+ var tests = [
+ {
+ target: [
+ {
+ a: 1,
+ b: []
+ },
+ {
+ a: 3,
+ b: 2
+ },
+ {
+ a: 2,
+ b: {}
+ }
+ ],
+ e: 'a',
+ m: 'should detect uniq key as `a`'
+ },
+ {
+ target: [
+ {
+ "principal" : {
+ "value" : "HTTP/_HOST@${realm}",
+ "local_username" : null,
+ "configuration" : null,
+ "type" : "service"
+ },
+ "name" : "spnego",
+ "keytab" : {
+ "file" : "${keytab_dir}/spnego.service.keytab",
+ "owner" : {
+ "name" : "root",
+ "access" : "r"
+ },
+ "configuration" : null,
+ "group" : {
+ "name" : "${cluster-env/user_group}",
+ "access" : "r"
+ }
+ }
+ },
+ {
+ "principal" : {
+ "value" : "${cluster-env/smokeuser}-${cluster_name}@${realm}",
+ "local_username" : "${cluster-env/smokeuser}",
+ "configuration" : "cluster-env/smokeuser_principal_name",
+ "type" : "user"
+ },
+ "name" : "smokeuser",
+ "keytab" : {
+ "file" : "${keytab_dir}/smokeuser.headless.keytab",
+ "owner" : {
+ "name" : "${cluster-env/smokeuser}",
+ "access" : "r"
+ },
+ "configuration" : "cluster-env/smokeuser_keytab",
+ "group" : {
+ "name" : "${cluster-env/user_group}",
+ "access" : "r"
+ }
+ }
+ }
+ ],
+ e: 'name',
+ m: 'should detect uniq key as `name`'
+ },
+ ];
+
+ tests.forEach(function(test) {
+ it(test.m, function() {
+ expect(objectUtils.detectIndexedKey(test.target)).to.eql(test.e);
+ });
+ });
+ });
+
+ describe('#smartArrayObjectMerge', function() {
+ var tests = [
+ {
+ target: [
+ {
+ a: 2,
+ B: 2
+ }
+ ],
+ source: [
+ {
+ a: 3,
+ c: 4
+ },
+ ],
+ m: 'should merge {0} {1}, into {2}',
+ e: [
+ {
+ a: 2,
+ B: 2
+ },
+ {
+ a: 3,
+ c: 4
+ }
+ ]
+ },
+ {
+ target: [
+ {
+ a: 2,
+ B: 2
+ }
+ ],
+ source: [
+ {
+ a: 2,
+ B: 3,
+ b: 4
+ },
+ {
+ a: 3,
+ c: 4
+ }
+ ],
+ m: 'should merge {0} {1}, into {2}',
+ e: [
+ {
+ a: 2,
+ B: 3,
+ b: 4
+ },
+ {
+ a: 3,
+ c: 4
+ }
+ ]
+ },
+ {
+ target: [
+ {
+ "spark-defaults" : {
+ "spark.history.kerberos.enabled" : "true",
+ "spark.history.enabled" : "no"
+ }
+ }
+ ],
+ source: [
+ {
+ "spark-defaults" : {
+ "spark.history.kerberos.enabled" : "false"
+ }
+ },
+ {
+ "spark-site" : {
+ "spark.property" : "false"
+ }
+ }
+ ],
+ m: 'should merge {0} {1}, into {2}',
+ e: [
+ {
+ "spark-defaults" : {
+ "spark.history.kerberos.enabled" : "true",
+ "spark.history.enabled" : "no"
+ }
+ },
+ {
+ "spark-site" : {
+ "spark.property" : "false"
+ }
+ }
+ ]
+ }
+ ];
+
+ tests.forEach(function(test) {
+ it(test.m.format(JSON.stringify(test.target), JSON.stringify(test.source), JSON.stringify(test.e)), function() {
+ expect(objectUtils.smartArrayObjectMerge(test.target, test.source).toArray()).to.be.eql(test.e);
+ });
+ });
+ });
});