You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2017/02/21 17:18:41 UTC

[01/28] ambari git commit: AMBARI-20066. 'Install' button is shown in Admin > Stack and Versions > Version page for the original stack version installed via Install Wizard (ncole)

Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-20053 9386eed40 -> 0c464b742


AMBARI-20066. 'Install' button is shown in Admin > Stack and Versions > Version page for the original stack version installed via Install Wizard (ncole)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/f2cb1b6e
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f2cb1b6e
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f2cb1b6e

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: f2cb1b6ef495d0708024749dfe5b702d270952a2
Parents: a5dc2d2
Author: Nate Cole <nc...@hortonworks.com>
Authored: Fri Feb 17 14:01:06 2017 -0500
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Fri Feb 17 15:52:15 2017 -0500

----------------------------------------------------------------------
 .../server/state/cluster/ClusterImpl.java       | 43 +++++++++--
 .../server/state/cluster/ClusterTest.java       | 78 +++++++++++++-------
 2 files changed, 88 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f2cb1b6e/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index db4aa21..2d94f1a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -1313,7 +1313,7 @@ public class ClusterImpl implements Cluster {
    * @return Return the effective Cluster Version State
    */
   private RepositoryVersionState getEffectiveState(Map<RepositoryVersionState, Set<String>> stateToHosts) {
-    if (stateToHosts == null || stateToHosts.keySet().size() < 1) {
+    if (stateToHosts == null || stateToHosts.size() < 1) {
       return null;
     }
 
@@ -1350,18 +1350,51 @@ public class ClusterImpl implements Cluster {
     }
 
     if (totalNotRequired > 0) {
-      if (totalInstalled + totalNotRequired == totalHosts) {
-        return RepositoryVersionState.INSTALLED;
+
+      // !!! if all we have is NOT_REQUIRED and something else, the return should be the something else
+      if (2 == stateToHosts.size()) {
+
+        Map<RepositoryVersionState, Set<String>> map = Maps.filterKeys(stateToHosts,
+            new com.google.common.base.Predicate<RepositoryVersionState>() {
+              @Override
+              public boolean apply(RepositoryVersionState repoState) {
+                return repoState != RepositoryVersionState.NOT_REQUIRED;
+              }
+            });
+
+        // !!! better be true
+        if (1 == map.size()) {
+          return map.keySet().iterator().next();
+        } else {
+          LOG.warn("The mix of NON_REQUIRED hosts is unexpected: {}", stateToHosts);
+          return RepositoryVersionState.OUT_OF_SYNC;
+        }
       }
 
-      if (totalInstalling + totalInstalled + totalNotRequired == totalHosts) {
+      // if any hosts are still installing, then cluster is INSTALLING
+      if (totalInstalling > 0) {
         return RepositoryVersionState.INSTALLING;
       }
 
+      // if any hosts are install_failed, then cluster is INSTALL_FAILED
+      if (totalInstallFailed > 0) {
+        return RepositoryVersionState.INSTALL_FAILED;
+      }
+
+      // should be covered by the 2-state check above
+      if (totalInstalled > 0) {
+        return RepositoryVersionState.INSTALLED;
+      }
+
+      // rare
+      if (totalNotRequired == totalHosts) {
+        return RepositoryVersionState.NOT_REQUIRED;
+      }
+
     }
 
     // Also returns when have a mix of CURRENT and INSTALLING|INSTALLED
-    LOG.warn("have a mix of CURRENT and INSTALLING|INSTALLED host versions, " +
+    LOG.warn("Have a mix of CURRENT and INSTALLING|INSTALLED host versions, " +
       "returning OUT_OF_SYNC as cluster version. Host version states: {}", stateToHosts);
     return RepositoryVersionState.OUT_OF_SYNC;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f2cb1b6e/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
index 6cdfbad..396680a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
@@ -221,6 +221,10 @@ public class ClusterTest {
   }
 
   private void createDefaultCluster() throws Exception {
+    createDefaultCluster(Sets.newHashSet("h1", "h2"));
+  }
+
+  private void createDefaultCluster(Set<String> hostNames) throws Exception {
     // TODO, use common function
     StackId stackId = new StackId("HDP", "0.1");
     StackEntity stackEntity = stackDAO.find(stackId.getStackName(), stackId.getStackVersion());
@@ -230,11 +234,10 @@ public class ClusterTest {
 
     clusters.addCluster(clusterName, stackId);
 
-    Map<String, String> hostAttributes = new HashMap<String, String>();
+    Map<String, String> hostAttributes = new HashMap<>();
     hostAttributes.put("os_family", "redhat");
     hostAttributes.put("os_release_version", "5.9");
 
-    Set<String> hostNames = new HashSet<String>() {{ add("h1"); add("h2"); }};
     for (String hostName : hostNames) {
       clusters.addHost(hostName);
 
@@ -279,7 +282,7 @@ public class ClusterTest {
     host2.setIpv4("192.168.0.2");
     host3.setIpv4("192.168.0.3");
 
-    List<HostEntity> hostEntities = new ArrayList<HostEntity>();
+    List<HostEntity> hostEntities = new ArrayList<>();
     hostEntities.add(host1);
     hostEntities.add(host2);
 
@@ -309,7 +312,7 @@ public class ClusterTest {
     when(stateEntity.getDesiredStack()).thenReturn(stackEntity);
 
     clusterServiceEntity.setServiceDesiredStateEntity(stateEntity);
-    List<ClusterServiceEntity> clusterServiceEntities = new ArrayList<ClusterServiceEntity>();
+    List<ClusterServiceEntity> clusterServiceEntities = new ArrayList<>();
     clusterServiceEntities.add(clusterServiceEntity);
     clusterEntity.setClusterServiceEntities(clusterServiceEntities);
     return clusterEntity;
@@ -444,8 +447,8 @@ public class ClusterTest {
     For some reason this still uses the metainfo.xml files for these services
     from HDP-2.0.5 stack instead of the provided Stack Id
     */
-    HashMap<String, Set<String>> componentsThatAdvertiseVersion = new HashMap<String, Set<String>>();
-    HashMap<String, Set<String>> componentsThatDontAdvertiseVersion = new HashMap<String, Set<String>>();
+    HashMap<String, Set<String>> componentsThatAdvertiseVersion = new HashMap<>();
+    HashMap<String, Set<String>> componentsThatDontAdvertiseVersion = new HashMap<>();
 
     Set<String> hdfsComponents = new HashSet<String>() {{ add("NAMENODE"); add("DATANODE"); add("HDFS_CLIENT"); }};
     Set<String> zkComponents = new HashSet<String>() {{ add("ZOOKEEPER_SERVER"); add("ZOOKEEPER_CLIENT"); }};
@@ -567,7 +570,7 @@ public class ClusterTest {
     hostInfo.setMemoryTotal(10);
     hostInfo.setMemorySize(100);
     hostInfo.setProcessorCount(10);
-    List<DiskInfo> mounts = new ArrayList<DiskInfo>();
+    List<DiskInfo> mounts = new ArrayList<>();
     mounts.add(new DiskInfo("/dev/sda", "/mnt/disk1",
         "5000000", "4000000", "10%", "size", "fstype"));
     hostInfo.setMounts(mounts);
@@ -839,7 +842,7 @@ public class ClusterTest {
     Assert.assertEquals(1, componentHostMap.get("JOBTRACKER").size());
     Assert.assertTrue(componentHostMap.get("JOBTRACKER").contains("h1"));
 
-    componentHostMap = c1.getServiceComponentHostMap(null, new HashSet<String>(Arrays.asList("HDFS", "MAPREDUCE")));
+    componentHostMap = c1.getServiceComponentHostMap(null, new HashSet<>(Arrays.asList("HDFS", "MAPREDUCE")));
     Assert.assertEquals(3, componentHostMap.size());
     Assert.assertEquals(1, componentHostMap.get("NAMENODE").size());
     Assert.assertTrue(componentHostMap.get("NAMENODE").contains("h1"));
@@ -896,7 +899,7 @@ public class ClusterTest {
     Assert.assertEquals(1, componentHostMap.get("DATANODE").size());
     Assert.assertTrue(componentHostMap.get("DATANODE").contains("h2"));
 
-    componentHostMap = c1.getServiceComponentHostMap(new HashSet<String>(Arrays.asList("h1", "h2", "h3")), null);
+    componentHostMap = c1.getServiceComponentHostMap(new HashSet<>(Arrays.asList("h1", "h2", "h3")), null);
     Assert.assertEquals(3, componentHostMap.size());
     Assert.assertEquals(1, componentHostMap.get("NAMENODE").size());
     Assert.assertTrue(componentHostMap.get("NAMENODE").contains("h1"));
@@ -959,10 +962,10 @@ public class ClusterTest {
   public void testGetAndSetConfigs() throws Exception {
     createDefaultCluster();
 
-    Map<String, Map<String, String>> c1PropAttributes = new HashMap<String, Map<String,String>>();
+    Map<String, Map<String, String>> c1PropAttributes = new HashMap<>();
     c1PropAttributes.put("final", new HashMap<String, String>());
     c1PropAttributes.get("final").put("a", "true");
-    Map<String, Map<String, String>> c2PropAttributes = new HashMap<String, Map<String,String>>();
+    Map<String, Map<String, String>> c2PropAttributes = new HashMap<>();
     c2PropAttributes.put("final", new HashMap<String, String>());
     c2PropAttributes.get("final").put("x", "true");
     Config config1 = configFactory.createNew(c1, "global", "version1",
@@ -1068,7 +1071,7 @@ public class ClusterTest {
     host.setIPv4("ipv4");
     host.setIPv6("ipv6");
 
-    Map<String, String> hostAttributes = new HashMap<String, String>();
+    Map<String, String> hostAttributes = new HashMap<>();
     hostAttributes.put("os_family", "redhat");
     hostAttributes.put("os_release_version", "5.9");
     host.setHostAttributes(hostAttributes);
@@ -1129,7 +1132,7 @@ public class ClusterTest {
     Config config2 = configFactory.createNew(c1, "core-site", "version2",
       new HashMap<String, String>() {{ put("x", "y"); }}, new HashMap<String, Map<String,String>>());
 
-    Set<Config> configs = new HashSet<Config>();
+    Set<Config> configs = new HashSet<>();
     configs.add(config1);
     configs.add(config2);
 
@@ -1190,7 +1193,7 @@ public class ClusterTest {
     Host host1 = clusters.getHost("h1");
     HostEntity hostEntity1 = hostDAO.findByName("h1");
 
-    Map<String, Map<String, String>> propAttributes = new HashMap<String, Map<String,String>>();
+    Map<String, Map<String, String>> propAttributes = new HashMap<>();
     propAttributes.put("final", new HashMap<String, String>());
     propAttributes.get("final").put("test", "true");
     Config config = configFactory.createNew(c1, "hdfs-site", "1", new HashMap<String, String>(){{
@@ -1204,7 +1207,7 @@ public class ClusterTest {
     assertTrue(configs.containsKey(hostEntity1.getHostId()));
     assertEquals(1, configs.get(hostEntity1.getHostId()).size());
 
-    List<Long> hostIds = new ArrayList<Long>();
+    List<Long> hostIds = new ArrayList<>();
     hostIds.add(hostEntity1.getHostId());
 
     configs = c1.getHostsDesiredConfigs(hostIds);
@@ -1294,7 +1297,7 @@ public class ClusterTest {
     Config config2 = configFactory.createNew(c1, "core-site", "version2",
       new HashMap<String, String>() {{ put("x", "y"); }}, new HashMap<String, Map<String,String>>());
 
-    Set<Config> configs = new HashSet<Config>();
+    Set<Config> configs = new HashSet<>();
     configs.add(config1);
     configs.add(config2);
 
@@ -1853,7 +1856,7 @@ public class ClusterTest {
 
   @Test
   public void testRecalculateClusterVersionStateWithNotRequired() throws Exception {
-    createDefaultCluster();
+    createDefaultCluster(Sets.newHashSet("h1", "h2", "h3"));
 
     Host h1 = clusters.getHost("h1");
     h1.setState(HostState.HEALTHY);
@@ -1861,6 +1864,9 @@ public class ClusterTest {
     Host h2 = clusters.getHost("h2");
     h2.setState(HostState.HEALTHY);
 
+    Host h3 = clusters.getHost("h3");
+    h3.setState(HostState.HEALTHY);
+
     // Phase 1: Install bits during distribution
     StackId stackId = new StackId("HDP-0.1");
     final String stackVersion = "0.1-1000";
@@ -1872,13 +1878,29 @@ public class ClusterTest {
         RepositoryVersionState.INSTALLING);
     c1.setCurrentStackVersion(stackId);
 
-    HostVersionEntity hv1 = helper.createHostVersion("h1", repositoryVersionEntity, RepositoryVersionState.INSTALLED);
-    HostVersionEntity hv2 = helper.createHostVersion("h2", repositoryVersionEntity, RepositoryVersionState.NOT_REQUIRED);
+    HostVersionEntity hv1 = helper.createHostVersion("h1", repositoryVersionEntity, RepositoryVersionState.NOT_REQUIRED);
+    HostVersionEntity hv2 = helper.createHostVersion("h2", repositoryVersionEntity, RepositoryVersionState.INSTALLING);
+    HostVersionEntity hv3 = helper.createHostVersion("h3", repositoryVersionEntity, RepositoryVersionState.INSTALLED);
 
     c1.recalculateClusterVersionState(repositoryVersionEntity);
-    //Should remain in its current state
-    checkStackVersionState(stackId, stackVersion,
-        RepositoryVersionState.INSTALLED);
+    ClusterVersionEntity cv = clusterVersionDAO.findByClusterAndStackAndVersion(c1.getClusterName(), stackId, stackVersion);
+    assertEquals(RepositoryVersionState.INSTALLING, cv.getState());
+
+    // 1 in NOT_REQUIRED, 1 in INSTALLED, 1 in CURRENT so should be INSTALLED
+    hv2.setState(RepositoryVersionState.CURRENT);
+    hostVersionDAO.merge(hv2);
+
+    c1.recalculateClusterVersionState(repositoryVersionEntity);
+    cv = clusterVersionDAO.findByClusterAndStackAndVersion(c1.getClusterName(), stackId, stackVersion);
+    assertEquals(RepositoryVersionState.INSTALLED, cv.getState());
+
+    // 1 in NOT_REQUIRED, and 2 in CURRENT, so cluster version should be CURRENT
+    hv3.setState(RepositoryVersionState.CURRENT);
+    hostVersionDAO.merge(hv3);
+
+    c1.recalculateClusterVersionState(repositoryVersionEntity);
+    cv = clusterVersionDAO.findByClusterAndStackAndVersion(c1.getClusterName(), stackId, stackVersion);
+    assertEquals(RepositoryVersionState.CURRENT, cv.getState());
   }
 
 
@@ -1949,7 +1971,7 @@ public class ClusterTest {
 
     RepositoryVersionEntity rv1 = helper.getOrCreateRepositoryVersion(stackId, v1);
 
-    Map<String, String> hostAttributes = new HashMap<String, String>();
+    Map<String, String> hostAttributes = new HashMap<>();
     hostAttributes.put("os_family", "redhat");
     hostAttributes.put("os_release_version", "6.4");
 
@@ -2106,7 +2128,7 @@ public class ClusterTest {
 
     RepositoryVersionEntity rv1 = helper.getOrCreateRepositoryVersion(stackId, v1);
 
-    Map<String, String> hostAttributes = new HashMap<String, String>();
+    Map<String, String> hostAttributes = new HashMap<>();
     hostAttributes.put("os_family", "redhat");
     hostAttributes.put("os_release_version", "6.4");
 
@@ -2180,7 +2202,7 @@ public class ClusterTest {
       h.setIPv4("ipv4");
       h.setIPv6("ipv6");
 
-      Map<String, String> hostAttributes = new HashMap<String, String>();
+      Map<String, String> hostAttributes = new HashMap<>();
       hostAttributes.put("os_family", "redhat");
       hostAttributes.put("os_release_version", "5.9");
       h.setHostAttributes(hostAttributes);
@@ -2249,7 +2271,7 @@ public class ClusterTest {
       h.setIPv4("ipv4");
       h.setIPv6("ipv6");
 
-      Map<String, String> hostAttributes = new HashMap<String, String>();
+      Map<String, String> hostAttributes = new HashMap<>();
       hostAttributes.put("os_family", "redhat");
       hostAttributes.put("os_release_version", "5.9");
       h.setHostAttributes(hostAttributes);
@@ -2582,8 +2604,8 @@ public class ClusterTest {
     // make sure the stacks are different
     Assert.assertFalse(stackId.equals(newStackId));
 
-    Map<String, String> properties = new HashMap<String, String>();
-    Map<String, Map<String, String>> propertiesAttributes = new HashMap<String, Map<String, String>>();
+    Map<String, String> properties = new HashMap<>();
+    Map<String, Map<String, String>> propertiesAttributes = new HashMap<>();
 
     // foo-type for v1 on current stack
     properties.put("foo-property-1", "foo-value-1");


[19/28] ambari git commit: AMBARI-20079. Unable to filter by job id.(Padma Priya N via gauravn7)

Posted by jo...@apache.org.
AMBARI-20079. Unable to filter by job id.(Padma Priya N via gauravn7)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/74293edf
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/74293edf
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/74293edf

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 74293edfe1d1903f8e96d5a7a3eac47c48d63061
Parents: 6a3d8fd
Author: Gaurav Nagar <gr...@gmail.com>
Authored: Tue Feb 21 16:08:30 2017 +0530
Committer: Gaurav Nagar <gr...@gmail.com>
Committed: Tue Feb 21 16:08:30 2017 +0530

----------------------------------------------------------------------
 .../src/main/resources/ui/app/components/search-create-new-bar.js  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/74293edf/contrib/views/wfmanager/src/main/resources/ui/app/components/search-create-new-bar.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/search-create-new-bar.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/search-create-new-bar.js
index e6f7ec8..96ee230 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/search-create-new-bar.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/search-create-new-bar.js
@@ -147,7 +147,7 @@ export default Ember.Component.extend(Ember.Evented,{
     }.on('didInsertElement'),
     mapSearchItems(key){
       key = key.replace(" ", "_").toLowerCase();
-      var keys = {"job_id":"id"};
+      var keys = {"job_id":"id","jobid":"id"};
       if(keys[key]){
         return keys[key];
       }


[15/28] ambari git commit: AMBARI-20069. hive.enforce.bucketing=true.(vbrodetskyi)

Posted by jo...@apache.org.
AMBARI-20069. hive.enforce.bucketing=true.(vbrodetskyi)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/60aaaeab
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/60aaaeab
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/60aaaeab

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 60aaaeab5e2e9c7581f982525950bf6290db3018
Parents: 1ecdee0
Author: Vitaly Brodetskyi <vb...@hortonworks.com>
Authored: Tue Feb 21 02:15:11 2017 +0200
Committer: Vitaly Brodetskyi <vb...@hortonworks.com>
Committed: Tue Feb 21 02:15:11 2017 +0200

----------------------------------------------------------------------
 .../main/resources/stacks/HDP/2.2/services/stack_advisor.py   | 7 +++++--
 .../main/resources/stacks/HDP/2.3/upgrades/config-upgrade.xml | 5 +++++
 .../stacks/HDP/2.3/upgrades/nonrolling-upgrade-2.6.xml        | 6 ++++++
 .../main/resources/stacks/HDP/2.3/upgrades/upgrade-2.6.xml    | 2 ++
 .../main/resources/stacks/HDP/2.4/upgrades/config-upgrade.xml | 5 +++++
 .../stacks/HDP/2.4/upgrades/nonrolling-upgrade-2.6.xml        | 6 ++++++
 .../main/resources/stacks/HDP/2.4/upgrades/upgrade-2.6.xml    | 2 ++
 .../main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml | 5 +++++
 .../stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml        | 6 ++++++
 .../main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml    | 1 +
 .../src/test/python/stacks/2.2/common/test_stack_advisor.py   | 1 -
 .../src/test/python/stacks/2.3/common/test_stack_advisor.py   | 2 --
 12 files changed, 43 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py b/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
index 0d7b8b9..ede41fc 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
@@ -374,14 +374,12 @@ class HDP22StackAdvisor(HDP21StackAdvisor):
       putHiveSiteProperty("hive.support.concurrency", "true")
       putHiveSiteProperty("hive.compactor.initiator.on", "true")
       putHiveSiteProperty("hive.compactor.worker.threads", "1")
-      putHiveSiteProperty("hive.enforce.bucketing", "true")
       putHiveSiteProperty("hive.exec.dynamic.partition.mode", "nonstrict")
     else:
       putHiveSiteProperty("hive.txn.manager", "org.apache.hadoop.hive.ql.lockmgr.DummyTxnManager")
       putHiveSiteProperty("hive.support.concurrency", "false")
       putHiveSiteProperty("hive.compactor.initiator.on", "false")
       putHiveSiteProperty("hive.compactor.worker.threads", "0")
-      putHiveSiteProperty("hive.enforce.bucketing", "false")
       putHiveSiteProperty("hive.exec.dynamic.partition.mode", "strict")
 
     hiveMetastoreHost = self.getHostWithComponent("HIVE", "HIVE_METASTORE", services, hosts)
@@ -1497,6 +1495,11 @@ class HDP22StackAdvisor(HDP21StackAdvisor):
             ldap_domain_property + " property, if you are using AD, if not, then " + ldap_baseDN_property + "!")})
 
 
+    hive_enforce_bucketing = "hive.enforce.bucketing"
+    if hive_enforce_bucketing in properties and properties[hive_enforce_bucketing].lower() == "false":
+      validationItems.append({"config-name" : hive_enforce_bucketing, "item" :
+        self.getWarnItem("Set " + hive_enforce_bucketing + " to true otherwise there is a potential of data corruption!")})
+
     configurationValidationProblems = self.toConfigurationValidationProblems(validationItems, "hive-site")
     configurationValidationProblems.extend(parentValidationProblems)
     return configurationValidationProblems

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/config-upgrade.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/config-upgrade.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/config-upgrade.xml
index ba155ab..cdd701a 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/config-upgrade.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/config-upgrade.xml
@@ -195,6 +195,11 @@
             <regex-replace key="content" find="#log4j.appender.DRFA.MaxBackupIndex=([0-9]+)" replace-with="#log4j.appender.DRFA.MaxBackupIndex={{hive_log_maxbackupindex}}"/>
             <replace key="content" find="log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender" replace-with="log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender&#xA;log4j.appender.DRFA.MaxFileSize = {{hive_log_maxfilesize}}MB"/>
           </definition>
+
+          <definition xsi:type="configure" id="hdp_2_6_0_0_hive_set_hive_enforce_bucketing_property">
+            <type>hive-site</type>
+            <set key="hive.enforce.bucketing" value="true"/>
+          </definition>
         </changes>
       </component>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/nonrolling-upgrade-2.6.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/nonrolling-upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/nonrolling-upgrade-2.6.xml
index e6a3c94..ff42022 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/nonrolling-upgrade-2.6.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/nonrolling-upgrade-2.6.xml
@@ -419,6 +419,12 @@
         </task>
       </execute-stage>
 
+      <execute-stage service="HIVE" component="HIVE_SERVER" title="Set hive.enforce.bucketing property">
+        <task xsi:type="configure" id="hdp_2_6_0_0_hive_set_hive_enforce_bucketing_property">
+          <summary>Updating hive.enforce.bucketing property to true value</summary>
+        </task>
+      </execute-stage>
+
       <!--OOZIE-->
       <execute-stage service="OOZIE" component="OOZIE_SERVER" title="Apply config changes for Oozie Server">
         <task xsi:type="server_action" class="org.apache.ambari.server.serveraction.upgrades.OozieConfigCalculation">

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/upgrade-2.6.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/upgrade-2.6.xml
index 7d8438f..b255bc0 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/upgrade-2.6.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/upgrade-2.6.xml
@@ -893,6 +893,8 @@
             <summary>Update hive-env content</summary>
           </task>
           <task xsi:type="configure" id="hive_log4j_parameterize" />
+
+          <task xsi:type="configure" id="hdp_2_6_0_0_hive_set_hive_enforce_bucketing_property" />
         </pre-upgrade>
 
         <pre-downgrade/>

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/config-upgrade.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/config-upgrade.xml b/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/config-upgrade.xml
index d19bb76..1bea263 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/config-upgrade.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/config-upgrade.xml
@@ -96,6 +96,11 @@
             <regex-replace key="content" find="#log4j.appender.DRFA.MaxBackupIndex=([0-9]+)" replace-with="#log4j.appender.DRFA.MaxBackupIndex={{hive_log_maxbackupindex}}"/>
             <replace key="content" find="log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender" replace-with="log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender&#xA;log4j.appender.DRFA.MaxFileSize = {{hive_log_maxfilesize}}MB"/>
           </definition>
+
+          <definition xsi:type="configure" id="hdp_2_6_0_0_hive_set_hive_enforce_bucketing_property">
+            <type>hive-site</type>
+            <set key="hive.enforce.bucketing" value="true"/>
+          </definition>
          </changes>
       </component>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/nonrolling-upgrade-2.6.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/nonrolling-upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/nonrolling-upgrade-2.6.xml
index 69a894c..86cd56a 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/nonrolling-upgrade-2.6.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/nonrolling-upgrade-2.6.xml
@@ -461,6 +461,12 @@
         </task>
       </execute-stage>
 
+      <execute-stage service="HIVE" component="HIVE_SERVER" title="Set hive.enforce.bucketing property">
+        <task xsi:type="configure" id="hdp_2_6_0_0_hive_set_hive_enforce_bucketing_property">
+          <summary>Updating hive.enforce.bucketing property to true value</summary>
+        </task>
+      </execute-stage>
+
       <execute-stage service="HIVE" component="WEBHCAT_SERVER" title="Parameterizing WebHCat Log4J Properties">
         <task xsi:type="configure" id="webhcat_log4j_parameterize">
           <summary>Updating the Webhcat Log4J properties to include parameterizations</summary>

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/upgrade-2.6.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/upgrade-2.6.xml
index 0c9a8ea..6a8e9d7 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/upgrade-2.6.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.4/upgrades/upgrade-2.6.xml
@@ -892,6 +892,8 @@
           </task>
           <task xsi:type="configure" id="hive_log4j_parameterize" />
 
+          <task xsi:type="configure" id="hdp_2_6_0_0_hive_set_hive_enforce_bucketing_property" />
+
         </pre-upgrade>
 
         <pre-downgrade/>

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
index 241ca8f..ca9cf47 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
@@ -358,6 +358,11 @@
             <regex-replace key="content" find="property.llap.daemon.log.maxfilesize = ([0-9]+)MB" replace-with="property.llap.daemon.log.maxfilesize = {{hive_llap_log_maxfilesize}}MB"/>
             <regex-replace key="content" find="property.llap.daemon.log.maxbackupindex = ([0-9]+)" replace-with="property.llap.daemon.log.maxbackupindex = {{hive_llap_log_maxbackupindex}}"/>
           </definition>
+
+          <definition xsi:type="configure" id="hdp_2_6_0_0_hive_set_hive_enforce_bucketing_property">
+            <type>hive-site</type>
+            <set key="hive.enforce.bucketing" value="true"/>
+          </definition>
         </changes>
       </component>
       <component name="HIVE_SERVER_INTERACTIVE">

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
index 0ef69cb..06cae78 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
@@ -478,6 +478,12 @@
         <task xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options_for_tez_am"/>
       </execute-stage>
 
+      <execute-stage service="HIVE" component="HIVE_SERVER" title="Set hive.enforce.bucketing property">
+        <task xsi:type="configure" id="hdp_2_6_0_0_hive_set_hive_enforce_bucketing_property">
+          <summary>Updating hive.enforce.bucketing property to true value</summary>
+        </task>
+      </execute-stage>
+
       <execute-stage service="HIVE" component="HIVE_SERVER_INTERACTIVE" title="Appending heap dump options for HiveSever2 Interactive">
         <task xsi:type="configure" id="hdp_2_6_0_0_hive_llap_append_heap_dump_options"/>
       </execute-stage>

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
index 6309bcb..64edbb8 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
@@ -781,6 +781,7 @@
           <task xsi:type="configure" id="hdp_2_6_0_0_hive_append_heap_dump_options"/>
           <task xsi:type="configure" id="hive_log4j_parameterize" />
           <task xsi:type="configure" id="hive_llap_log4j_parameterize" />
+          <task xsi:type="configure" id="hdp_2_6_0_0_hive_set_hive_enforce_bucketing_property" />
         </pre-upgrade>
         
         <pre-downgrade />

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py b/ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py
index 0c7af1a..b8762b3 100644
--- a/ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py
+++ b/ambari-server/src/test/python/stacks/2.2/common/test_stack_advisor.py
@@ -1300,7 +1300,6 @@ class TestHDP22StackAdvisor(TestCase):
           'hive.compactor.initiator.on': 'false',
           'hive.compactor.worker.threads': '0',
           'hive.compute.query.using.stats': 'true',
-          'hive.enforce.bucketing': 'false',
           'hive.exec.dynamic.partition.mode': 'strict',
           'hive.exec.failure.hooks': 'org.apache.hadoop.hive.ql.hooks.ATSHook',
           'hive.exec.orc.compression.strategy': 'SPEED',

http://git-wip-us.apache.org/repos/asf/ambari/blob/60aaaeab/ambari-server/src/test/python/stacks/2.3/common/test_stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/2.3/common/test_stack_advisor.py b/ambari-server/src/test/python/stacks/2.3/common/test_stack_advisor.py
index 7e93815..443331a 100644
--- a/ambari-server/src/test/python/stacks/2.3/common/test_stack_advisor.py
+++ b/ambari-server/src/test/python/stacks/2.3/common/test_stack_advisor.py
@@ -605,7 +605,6 @@ class TestHDP23StackAdvisor(TestCase):
           'hive.compactor.initiator.on': 'false',
           'hive.compactor.worker.threads': '0',
           'hive.compute.query.using.stats': 'true',
-          'hive.enforce.bucketing': 'false',
           'hive.exec.dynamic.partition.mode': 'strict',
           'hive.exec.failure.hooks': 'org.apache.hadoop.hive.ql.hooks.ATSHook',
           'hive.exec.orc.compression.strategy': 'SPEED',
@@ -883,7 +882,6 @@ class TestHDP23StackAdvisor(TestCase):
           'hive.compactor.initiator.on': 'false',
           'hive.compactor.worker.threads': '0',
           'hive.compute.query.using.stats': 'true',
-          'hive.enforce.bucketing': 'false',
           'hive.exec.dynamic.partition.mode': 'strict',
           'hive.exec.failure.hooks': 'org.apache.hadoop.hive.ql.hooks.ATSHook',
           'hive.exec.orc.compression.strategy': 'SPEED',


[10/28] ambari git commit: AMBARI-19076. Broken link in ambari-server/docs/api/v1/schemas.md (Masahiro Tanaka via adoroszlai)

Posted by jo...@apache.org.
AMBARI-19076. Broken link in ambari-server/docs/api/v1/schemas.md (Masahiro Tanaka via adoroszlai)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/2744ae82
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/2744ae82
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/2744ae82

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 2744ae82af2816222807b0066a4ae60771147e1c
Parents: 812397d
Author: Masahiro Tanaka <ta...@oss.nttdata.com>
Authored: Mon Feb 20 11:52:51 2017 +0100
Committer: Attila Doroszlai <ad...@hortonworks.com>
Committed: Mon Feb 20 11:52:51 2017 +0100

----------------------------------------------------------------------
 ambari-server/docs/api/v1/schemas.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2744ae82/ambari-server/docs/api/v1/schemas.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/schemas.md b/ambari-server/docs/api/v1/schemas.md
index f52bc10..e7e4c1c 100644
--- a/ambari-server/docs/api/v1/schemas.md
+++ b/ambari-server/docs/api/v1/schemas.md
@@ -33,7 +33,7 @@ Ambari API Response Schemas
 - [GET configuration](#get-configuration)
 - [GET request](#get-request)
 - [GET task](#get-task)
-- [POST/PUT/DELETE resource](#post-put-delete-resource)
+- [POST/PUT/DELETE resource](#postputdelete-resource)
 
 
 GET clusters


[23/28] ambari git commit: AMBARI-20089. HiveView2.0: Add new UDF is not working (pallavkul)

Posted by jo...@apache.org.
AMBARI-20089. HiveView2.0: Add new UDF is not working (pallavkul)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/299b0503
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/299b0503
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/299b0503

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 299b05033811d0149f2e474358b70e14d45ee9c3
Parents: 818a640
Author: pallavkul <pa...@gmail.com>
Authored: Tue Feb 21 17:03:24 2017 +0530
Committer: pallavkul <pa...@gmail.com>
Committed: Tue Feb 21 17:04:36 2017 +0530

----------------------------------------------------------------------
 .../main/resources/ui/app/routes/udfs/new.js    | 71 +++++++++++---------
 1 file changed, 40 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/299b0503/contrib/views/hive20/src/main/resources/ui/app/routes/udfs/new.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/udfs/new.js b/contrib/views/hive20/src/main/resources/ui/app/routes/udfs/new.js
index cdccbb3..84733e8 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/udfs/new.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/udfs/new.js
@@ -17,8 +17,9 @@
  */
 
 import Ember from 'ember';
+import UILoggerMixin from '../../mixins/ui-logger';
 
-export default Ember.Route.extend({
+export default Ember.Route.extend(UILoggerMixin, {
 
   beforeModel(){
 
@@ -94,42 +95,50 @@ export default Ember.Route.extend({
 
         let resourcePayload = {"name":resourceName,"path":resourcePath};
 
-        this.get('udf').savefileResource(resourcePayload)
-          .then((data) => {
+        var newFileResource = this.get('store').createRecord('file-resource',
+          {name:resourceName,
+            path:resourcePath
+          });
 
-            console.log('fileResource is', data.fileResource.id);
+        newFileResource.save().then((data) => {
+          console.log('fileResource is', data.get('id'));
+          let newUDF = this.get('store').createRecord('udf',
+            {name:udfName,
+              classname:udfClassName,
+              fileResource: data.get('id')
+            });
 
-            let newUDF = this.get('store').createRecord('udf',
-              {name:udfName,
-                classname:udfClassName,
-                fileResource: data.fileResource.id
+          newUDF.save().then((data) => {
+            console.log('udf saved');
+
+            this.get('store').findAll('udf').then((data) => {
+              let udfList = [];
+              data.forEach(x => {
+                let localUdf = {
+                  'id': x.get('id'),
+                  'name': x.get('name'),
+                  'classname': x.get('classname'),
+                  'fileResource': x.get('fileResource'),
+                  'owner': x.get('owner')
+                };
+                udfList.pushObject(localUdf);
               });
 
-            newUDF.save().then((data) => {
-              console.log('udf saved');
-
-              this.get('store').findAll('udf').then((data) => {
-                let udfList = [];
-                data.forEach(x => {
-                  let localUdf = {
-                    'id': x.get('id'),
-                    'name': x.get('name'),
-                    'classname': x.get('classname'),
-                    'fileResource': x.get('fileResource'),
-                    'owner': x.get('owner')
-                  };
-                  udfList.pushObject(localUdf);
-                });
-
-                this.controllerFor('udfs').set('udflist',udfList);
-                this.transitionTo('udfs');
-              })
-
-            });
+              this.controllerFor('udfs').set('udflist',udfList);
+              this.transitionTo('udfs');
+            })
+          })
+          .catch((error) => {
+            this.get('logger').danger('Failed to create UDF.', this.extractError(error));
+            this.transitionTo('udfs');
 
-          }, (error) => {
-            console.log("Error encountered", error);
           });
+        })
+        .catch((error) => {
+          this.get('logger').danger('Failed to create File Resource.', this.extractError(error));
+          this.transitionTo('udfs');
+        });
+
       }
     },
 


[21/28] ambari git commit: AMBARI-20084. Cut Node feature is broken in workflow manager.(Padma Priya N via gauravn7)

Posted by jo...@apache.org.
AMBARI-20084. Cut Node feature is broken in workflow manager.(Padma Priya N via gauravn7)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/4719b242
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/4719b242
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/4719b242

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 4719b242560326230dc1e10473ddcd535e29c0af
Parents: 6a7d919
Author: Gaurav Nagar <gr...@gmail.com>
Authored: Tue Feb 21 16:12:08 2017 +0530
Committer: Gaurav Nagar <gr...@gmail.com>
Committed: Tue Feb 21 16:12:08 2017 +0530

----------------------------------------------------------------------
 .../ui/app/components/flow-designer.js          |  4 +--
 .../ui/app/domain/cytoscape-flow-renderer.js    | 34 ++++++++++++--------
 2 files changed, 22 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/4719b242/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
index c1bd4be..190bb1a 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
@@ -670,9 +670,9 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
   copyNode(node){
     this.get('clipboardService').setContent(node, 'copy');
   },
-  cutNode(node){
+  cutNode(node, transitionsList){
     this.get('clipboardService').setContent(node, 'cut');
-    this.deleteWorkflowNode(node);
+    this.deleteWorkflowNode(node, transitionsList);
   },
   replaceNode(node){
     var clipboardContent = this.get('clipboardService').getContent();

http://git-wip-us.apache.org/repos/asf/ambari/blob/4719b242/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js
index 6f46fdc..51e0461 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js
@@ -287,18 +287,7 @@ var CytoscapeRenderer= Ember.Object.extend({
 
     this.get("context").$('.overlay-trash-icon i').off('click');
     this.get("context").$('.overlay-trash-icon i').on('click',function(){
-      var incomingNodes=this.get("currentCyNode").incomers("node").jsons().mapBy("data.node");
-      var transitionList=[];
-      var currentNodeId=this.get("currentCyNode").json().data.id;
-      for (var incomingNode of incomingNodes) {
-        for (var incomingTran of incomingNode.transitions ){
-          if (incomingTran.targetNode.id===currentNodeId){
-            incomingTran.sourceNode=incomingNode;
-            transitionList=transitionList.concat(incomingTran);
-          }
-        }
-      }
-      this.get("context").deleteWorkflowNode(this.get("context").$(".overlay-trash-icon").data("node"),transitionList);
+      this.get("context").deleteWorkflowNode(this.get("context").$(".overlay-trash-icon").data("node"), this.getIncomingTransitions(this.get("currentCyNode")));
       this.get("context").$('.overlay-node-actions').hide();
     }.bind(this));
 
@@ -316,7 +305,7 @@ var CytoscapeRenderer= Ember.Object.extend({
 
     this.get("context").$('.overlay-cut-icon i').off('click');
     this.get("context").$('.overlay-cut-icon i').on('click',function(){
-      this.get("context").cutNode(this.get("context").$(".overlay-cut-icon").data("node"));
+      this.get("context").cutNode(this.get("context").$(".overlay-cut-icon").data("node"), this.getIncomingTransitions(this.get("currentCyNode")));
       this.get("context").$('.overlay-node-actions').hide();
     }.bind(this));
 
@@ -344,8 +333,22 @@ var CytoscapeRenderer= Ember.Object.extend({
       this.get("context").$('.overlay-node-actions').hide();
     }.bind(this));
   },
+  getIncomingTransitions(node){
+    var incomingNodes=node.incomers("node").jsons().mapBy("data.node");
+    var transitionList=[];
+    var currentNodeId=this.get("currentCyNode").json().data.id;
+    for (var incomingNode of incomingNodes) {
+      for (var incomingTran of incomingNode.transitions ){
+        if (incomingTran.targetNode.id===currentNodeId){
+          incomingTran.sourceNode=incomingNode;
+          transitionList=transitionList.concat(incomingTran);
+        }
+      }
+    }
+    return transitionList;
+  },
   populateOkToandErrorTONodes(node){
-    let alternatePathNodes = this.cy.$('#'+node.id).predecessors("node[name][type='decision']").union(this.cy.$('#'+node.id).predecessors("node[name][type='decision']"));
+    let alternatePathNodes = this.cy.$('#'+node.id).predecessors("node[name][type='decision']").union(this.cy.$('#'+node.id).predecessors("node[name][type='fork']"));
     let descendantNodes = [];
     if(alternatePathNodes.length > 0){
       alternatePathNodes.forEach(childNode =>{
@@ -370,6 +373,9 @@ var CytoscapeRenderer= Ember.Object.extend({
     node.set('validOkToNodes', okToNodes);
     node.set('validErrorToNodes', errorToNodes);
   },
+  isWorkflowValid(){
+    return this.cy.nodes("node[name][type='start']").successors("node[name]").intersection(this.cy.nodes("node[name][type='end']").length > 0);
+  },
   renderWorkflow(workflow){
     this._getCyDataNodes(workflow);
     this.cy.startBatch();


[05/28] ambari git commit: AMBARI-20064 : hive20 view : added notification on error of preview or upload of table (nitirajrathore)

Posted by jo...@apache.org.
AMBARI-20064 : hive20 view : added notification on error of preview or upload of table (nitirajrathore)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/fad8f274
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/fad8f274
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/fad8f274

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: fad8f2745b8e39c51800fede563e170d30ddf9f3
Parents: c7bd689
Author: Nitiraj Singh Rathore <ni...@gmail.com>
Authored: Mon Feb 20 14:21:18 2017 +0530
Committer: Nitiraj Singh Rathore <ni...@gmail.com>
Committed: Mon Feb 20 14:21:18 2017 +0530

----------------------------------------------------------------------
 .../resources/ui/app/components/upload-table.js |  2 +-
 .../main/resources/ui/app/mixins/ui-logger.js   |  9 +++++
 .../databases/database/tables/upload-table.js   | 41 ++++----------------
 .../resources/ui/app/services/alert-messages.js |  7 +++-
 .../app/templates/components/upload-table.hbs   |  4 +-
 5 files changed, 27 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/fad8f274/contrib/views/hive20/src/main/resources/ui/app/components/upload-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/upload-table.js b/contrib/views/hive20/src/main/resources/ui/app/components/upload-table.js
index 8df03e5..3da3056 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/upload-table.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/upload-table.js
@@ -28,7 +28,7 @@ export default Ember.Component.extend({
   fileInfo: Ember.Object.create({
     files: Ember.A(),
     hdfsPath: null,
-    uploadSource: null,
+    uploadSource: "local",
   }),
   tableMeta: Ember.Object.create(),
   actions: {

http://git-wip-us.apache.org/repos/asf/ambari/blob/fad8f274/contrib/views/hive20/src/main/resources/ui/app/mixins/ui-logger.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/mixins/ui-logger.js b/contrib/views/hive20/src/main/resources/ui/app/mixins/ui-logger.js
index 277f69c..b01c4d4 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/mixins/ui-logger.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/mixins/ui-logger.js
@@ -29,5 +29,14 @@ export default Ember.Mixin.create({
     } else {
       return error;
     }
+  },
+  extractMessage(error) {
+    if (Ember.isArray(error.errors) && (error.errors.length >= 0)) {
+      return error.errors[0].message;
+    } else if(!Ember.isEmpty(error.errors)) {
+      return error.errors.message;
+    } else{
+      return error.message;
+    }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/fad8f274/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/upload-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/upload-table.js b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/upload-table.js
index a9bf9ea..e4c543b 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/upload-table.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/upload-table.js
@@ -22,8 +22,9 @@ import constants from '../../../../utils/constants';
 import Column from '../../../../models/column';
 import datatypes from '../../../../configs/datatypes';
 import Helpers from '../../../../configs/helpers';
+import UILoggerMixin from '../../../../mixins/ui-logger';
 
-export default NewTable.extend({
+export default NewTable.extend(UILoggerMixin, {
   COLUMN_NAME_REGEX: "^[a-zA-Z]{1}[a-zA-Z0-9_]*$",
   TABLE_NAME_REGEX: "^[a-zA-Z]{1}[a-zA-Z0-9_]*$",
   HDFS_PATH_REGEX: "^[/]{1}.+",  // unix path allows everything but here we have to mention full path so starts with /
@@ -630,26 +631,19 @@ export default NewTable.extend({
     if(error){
       console.log(" error : ", error);
       this.set('error', JSON.stringify(error));
-      // this.get('notifyService').warn(error);
-      // TODO : add notifyService warn message.
-      console.log("TODO : add notifyService warn message.");
+      this.get('notifyService').error( this.extractMessage(error), this.extractError(error));
     }else{
       this.set("error");
     }
   },
-  previewError: function (error) {
-    this.setError(error);
-  },
   uploadTableFromHdfs : function(tableData){
     console.log("uploadTableFromHdfs called.");
-    // if(!(this.get("inputFileTypeCSV") == true && this.get("isFirstRowHeader") == false) ){
-      this.pushUploadProgressInfos(this.formatMessage('uploadingFromHdfs'));
-    // }
+    this.pushUploadProgressInfos(this.formatMessage('uploadingFromHdfs'));
     var csvParams = tableData.get("fileFormatInfo.csvParams");
-    let columns = tableData.get("tableMeta").columns.map(function(column){
+    let columns = tableData.get("tableMeta").columns.map(function (column) {
       return {"name": column.get("name"), "type": column.get("type.label")};
     });
-    let header = columns; //JSON.stringify(columns);
+    let header = columns;
 
     return this.getUploader().uploadFromHDFS({
       "databaseName": tableData.get("database"),
@@ -687,24 +681,11 @@ export default NewTable.extend({
     console.log("onUploadSuccessfull : ", data);
     this._transitionToCreatedTable(this.get("tableData").get('database'), this.get("tableData").get('tableMeta').name);
 
-    // this.get('notifyService').success(this.translate('hive.messages.successfullyUploadedTableHeader'),
-    //   this.translate('hive.messages.successfullyUploadedTableMessage' ,{tableName:this.get("tableData").get("tableMeta").name ,databaseName:this.get("tableData").get("database")}));
+    this.get('notifyService').success(this.translate('hive.messages.successfullyUploadedTableHeader'),
+      this.translate('hive.messages.successfullyUploadedTableMessage' ,{tableName:this.get("tableData").get("tableMeta").name ,databaseName:this.get("tableData").get("database")}));
     this.clearFields();
   },
 
-  onUploadError: function (error) {
-    console.log("onUploadError : ", error);
-    this.setError(error);
-  },
-  showOrHide: function () {
-    if (this.get('show') == false) {
-      this.set("displayOption", "display:none");
-      this.set("showMoreOrLess", "Show More");
-    } else {
-      this.set("displayOption", "display:table-row");
-      this.set("showMoreOrLess", "Show Less");
-    }
-  },
   validateInputs: function(tableData){
     let tableMeta = tableData.get("tableMeta");
     let containsEndlines = tableData.get("fileFormatInfo.containsEndlines");
@@ -722,9 +703,6 @@ export default NewTable.extend({
       this.set('previewObject', previewObject);
       return this.generatePreview(previewObject)
     },
-    previewFromHdfs: function () {
-      return this.generatePreview();
-    },
     uploadTable: function (tableData) {
       console.log("tableData", tableData);
       try {
@@ -736,8 +714,5 @@ export default NewTable.extend({
         this.hideUploadModal();
       }
     },
-    uploadFromHDFS: function () {
-      this.set("isLocalUpload", false);
-    }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/fad8f274/contrib/views/hive20/src/main/resources/ui/app/services/alert-messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/alert-messages.js b/contrib/views/hive20/src/main/resources/ui/app/services/alert-messages.js
index a05fc7a..5280db2 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/services/alert-messages.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/services/alert-messages.js
@@ -112,7 +112,12 @@ export default Ember.Service.extend({
     data.id = this._getNextAlertId();
     data.type = type;
     data.status = options.status || -1;
-    data.trace = this._getDetailedError(options.trace);
+    if(options.trace){
+      data.trace = this._getDetailedError(options.trace);
+    }
+    else{
+      data.trace = this._getDetailedError(options.stack);
+    }
     delete options.status;
     delete options.error;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/fad8f274/contrib/views/hive20/src/main/resources/ui/app/templates/components/upload-table.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/upload-table.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/upload-table.hbs
index e4388f0..0ee6b81 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/upload-table.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/upload-table.hbs
@@ -41,10 +41,12 @@
         &nbsp;&nbsp;&nbsp;Table Preview
       </div>
     </div>
+  <div class="query-result">
     {{#if showPreview}}
-    {{simple-table header=columns rows=rows }}
+      {{simple-table header=columns rows=rows }}
     {{/if}}
   </div>
+  </div>
 </div>
 
 


[07/28] ambari git commit: AMBARI-20070. Agent heartbeat loop stuck in subprocess.Popen (adoroszlai)

Posted by jo...@apache.org.
AMBARI-20070. Agent heartbeat loop stuck in subprocess.Popen (adoroszlai)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ac4f3d11
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ac4f3d11
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ac4f3d11

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: ac4f3d11f05637639638daf204cb9405ab9fe198
Parents: 316d33a
Author: Attila Doroszlai <ad...@hortonworks.com>
Authored: Mon Feb 20 10:40:26 2017 +0100
Committer: Attila Doroszlai <ad...@hortonworks.com>
Committed: Mon Feb 20 10:40:26 2017 +0100

----------------------------------------------------------------------
 .../src/main/python/ambari_agent/main.py        | 23 ++++++++++++++++++++
 1 file changed, 23 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ac4f3d11/ambari-agent/src/main/python/ambari_agent/main.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/main.py b/ambari-agent/src/main/python/ambari_agent/main.py
index 6927b15..5ca89b3 100644
--- a/ambari-agent/src/main/python/ambari_agent/main.py
+++ b/ambari-agent/src/main/python/ambari_agent/main.py
@@ -42,6 +42,29 @@ def fix_subprocess_racecondition():
   del sys.modules['gc']
   import gc
 
+
+def fix_subprocess_popen():
+  '''
+  http://bugs.python.org/issue19809
+  '''
+  import os
+  import sys
+
+  if os.name == 'posix' and sys.version_info[0] < 3:
+    import subprocess
+    import threading
+
+    original_init = subprocess.Popen.__init__
+    lock = threading.RLock()
+
+    def locked_init(self, *a, **kw):
+      with lock:
+        original_init(self, *a, **kw)
+
+    subprocess.Popen.__init__ = locked_init
+
+
+fix_subprocess_popen()
 fix_subprocess_racecondition()
 fix_encoding_reimport_bug()
 


[25/28] ambari git commit: AMBARI-20100. Configs filter is not reset if configs has no filter input (akovalenko)

Posted by jo...@apache.org.
AMBARI-20100. Configs filter is not reset if configs has no filter input (akovalenko)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/4307f9bd
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/4307f9bd
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/4307f9bd

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 4307f9bd7252b329d63fe3f52468890d057b94c9
Parents: f1c96e5
Author: Aleksandr Kovalenko <ak...@hortonworks.com>
Authored: Tue Feb 21 17:59:09 2017 +0200
Committer: Aleksandr Kovalenko <ak...@hortonworks.com>
Committed: Tue Feb 21 17:59:09 2017 +0200

----------------------------------------------------------------------
 ambari-web/app/views/common/configs/service_config_view.js | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/4307f9bd/ambari-web/app/views/common/configs/service_config_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/service_config_view.js b/ambari-web/app/views/common/configs/service_config_view.js
index daf26b0..a53f6cd 100644
--- a/ambari-web/app/views/common/configs/service_config_view.js
+++ b/ambari-web/app/views/common/configs/service_config_view.js
@@ -131,6 +131,7 @@ App.ServiceConfigView = Em.View.extend({
     App.tooltip($(".glyphicon .glyphicon-lock"), {placement: 'right'});
     App.tooltip($("[rel=tooltip]"));
     this.checkCanEdit();
+    this.set('filter', '');
   },
 
   willDestroyElement: function() {


[06/28] ambari git commit: AMBARI-20076. Hive View 2: Results of one query reflected in other (pallavkul)

Posted by jo...@apache.org.
AMBARI-20076. Hive View 2: Results of one query reflected in other (pallavkul)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/316d33a9
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/316d33a9
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/316d33a9

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 316d33a9b7f95610dc2f603c3140e1dda695ed04
Parents: fad8f27
Author: pallavkul <pa...@gmail.com>
Authored: Mon Feb 20 14:30:52 2017 +0530
Committer: pallavkul <pa...@gmail.com>
Committed: Mon Feb 20 14:30:52 2017 +0530

----------------------------------------------------------------------
 .../src/main/resources/ui/app/adapters/query.js |   6 +-
 .../ui/app/components/query-result-table.js     |   8 +-
 .../resources/ui/app/configs/result-tabs.js     |  48 ++
 .../main/resources/ui/app/models/worksheet.js   |   8 +-
 .../hive20/src/main/resources/ui/app/router.js  |   6 +-
 .../resources/ui/app/routes/queries/query.js    | 450 ++++++++++---------
 .../ui/app/routes/queries/query/loading.js      |  24 +
 .../ui/app/routes/queries/query/log.js          | 104 +++++
 .../ui/app/routes/queries/query/results.js      |  59 +++
 .../ui/app/routes/queries/query/tez-ui.js       |  45 ++
 .../app/routes/queries/query/visual-explain.js  |  56 +++
 .../src/main/resources/ui/app/services/query.js |   4 +-
 .../templates/components/query-result-table.hbs |  20 +-
 .../app/templates/components/visual-explain.hbs |   1 -
 .../ui/app/templates/queries/query.hbs          |  64 +--
 .../ui/app/templates/queries/query/loading.hbs  |  21 +
 .../ui/app/templates/queries/query/log.hbs      |  29 ++
 .../ui/app/templates/queries/query/results.hbs  |  49 ++
 .../ui/app/templates/queries/query/tez-ui.hbs   |  19 +
 .../templates/queries/query/visual-explain.hbs  |  33 ++
 .../src/main/resources/ui/config/environment.js |   2 +-
 21 files changed, 743 insertions(+), 313 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/adapters/query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/query.js b/contrib/views/hive20/src/main/resources/ui/app/adapters/query.js
index e519e64..f878230 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/adapters/query.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/query.js
@@ -29,13 +29,13 @@ export default ApplicationAdapter.extend({
     let postURL = this.buildURL();
     return this.ajax(postURL , 'POST', { data: {job: payload} });
   },
-  getJob(jobId, dateSubmitted, firstCall){
+  getJob(jobId, firstCall){
 
     let url = '';
     if(firstCall){
-      url = this.buildURL() + jobId + '/results?first=true&_='+ dateSubmitted;
+      url = this.buildURL() + jobId + '/results?first=true';
     }else {
-      url = this.buildURL() + jobId + '/results?_='+ dateSubmitted;
+      url = this.buildURL() + jobId + '/results';
     }
 
     return this.ajax(url, 'GET')

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js b/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
index 0373f72..ea6dbc9 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
@@ -82,11 +82,11 @@ export default Ember.Component.extend({
     onColumnClick(column) {
       //console.log('I am in onColumnClick');
     },
-    goNextPage(){
-      this.sendAction('goNextPage');
+    goNextPage(payloadTitle){
+      this.sendAction('goNextPage', payloadTitle);
     },
-    goPrevPage(){
-      this.sendAction('goPrevPage');
+    goPrevPage(payloadTitle){
+      this.sendAction('goPrevPage', payloadTitle);
     },
     expandQueryResultPanel(){
       this.sendAction('expandQueryResultPanel');

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/configs/result-tabs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/configs/result-tabs.js b/contrib/views/hive20/src/main/resources/ui/app/configs/result-tabs.js
new file mode 100644
index 0000000..f48dcd8
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/configs/result-tabs.js
@@ -0,0 +1,48 @@
+/**
+ * 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';
+
+let resultsTabs = [
+  Ember.Object.create({
+    name: 'results',
+    label: 'RESULTS',
+    link: 'queries.query.results',
+    faIcon: 'paper-plane'
+  }),
+  Ember.Object.create({
+    name: 'log',
+    label: 'LOG',
+    link: 'queries.query.log',
+    faIcon: 'paper-plane'
+  }),
+  Ember.Object.create({
+    name: 'visual-explain',
+    label: 'VISUAL EXPLAIN',
+    link: 'queries.query.visual-explain',
+    faIcon: 'paper-plane'
+  }),
+  Ember.Object.create({
+    name: 'tez-ui',
+    label: 'TEZ UI',
+    link: 'queries.query.tez-ui',
+    faIcon: 'paper-plane'
+  })
+];
+
+export default resultsTabs;

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js b/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js
index 1787cc7..4b3e1f9 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/models/worksheet.js
@@ -30,13 +30,15 @@ export default DS.Model.extend({
   selected: DS.attr('boolean', {transient: true, defaultValue: false}),
   jobData: DS.attr({defaultValue: []}),
   currentJobData: DS.attr({defaultValue: null}),
-  hidePreviousButton: DS.attr('boolean', { defaultValue: true}),
+  hasNext: DS.attr('boolean', { defaultValue: false}),
+  hasPrevious: DS.attr('boolean', { defaultValue: false}),
   selectedTablesModels: DS.attr(),
   selectedMultiDb: DS.attr(),
   queryFile: DS.attr('string', {defaultValue: ""}),
   logFile: DS.attr('string', {defaultValue: ""}),
   logResults: DS.attr('string', {defaultValue: ""}),
   isQueryRunning: DS.attr('boolean', {defaultValue: false}),
-  isQueryResultContainer: DS.attr('boolean', {defaultValue: false})
-
+  isQueryResultContainer: DS.attr('boolean', {defaultValue: false}),
+  visualExplainJson: DS.attr({defaultValue: null}),
+  lastResultRoute: DS.attr({defaultValue: ""})
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/router.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/router.js b/contrib/views/hive20/src/main/resources/ui/app/router.js
index ffb0f83..250f945 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/router.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/router.js
@@ -66,7 +66,11 @@ Router.map(function() {
   this.route('queries', function() {
     this.route('new');
     this.route('query', {path: '/:worksheetId'}, function() {
-
+      this.route('results');
+      this.route('log');
+      this.route('visual-explain');
+      this.route('tez-ui');
+      this.route('loading');
     });
   });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
index 88202ff..04bb1da 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
@@ -17,17 +17,19 @@
  */
 
 import Ember from 'ember';
+import tabs from '../../configs/result-tabs';
+import UILoggerMixin from '../../mixins/ui-logger';
 
-export default Ember.Route.extend({
-
+export default Ember.Route.extend(UILoggerMixin, {
   query: Ember.inject.service(),
   jobs: Ember.inject.service(),
   savedQueries: Ember.inject.service(),
-
   isQueryEdidorPaneExpanded: false,
   isQueryResultPanelExpanded: false,
+  globalSettings: '',
 
-  beforeModel(){
+  beforeModel(params){
+    console.log('worksheetId', params.params['queries.query'].worksheetId);
     let existingWorksheets = this.store.peekAll('worksheet');
     existingWorksheets.setEach('selected', false);
   },
@@ -48,17 +50,36 @@ export default Ember.Route.extend({
         };
         fileResourceList.push(localFileResource);
       });
-
       this.controller.set('fileResourceList', fileResourceList);
+    });
 
+    this.store.findAll('setting').then((data) => {
+      let localStr = '';
+      data.forEach(x => {
+        localStr = localStr + 'set '+ x.get('key')+ '='+ x.get('value') + '\n';
+      });
+      this.set('globalSettings', localStr);
     });
 
+    //lastResultRoute
+    console.log('lastResultRoute:: ', model.get('lastResultRoute'));
+    let lastResultRoute = model.get('lastResultRoute');
 
+    if(Ember.isEmpty(lastResultRoute)){
+      if(model.get('jobData').length > 0){
+        this.transitionTo('queries.query.results');
+      } else {
+        this.transitionTo('queries.query');
+      }
+    } else {
+      this.transitionTo('queries.query' + lastResultRoute);
+    }
 
   },
 
   model(params) {
     let selectedWs = this.store.peekAll('worksheet').filterBy('title', params.worksheetId).get('firstObject');
+
     if(selectedWs) {
       selectedWs.set('selected', true);
       return selectedWs;
@@ -71,13 +92,8 @@ export default Ember.Route.extend({
 
     this._super(...arguments);
 
-    controller.set('showWorksheetModal',false);
-    controller.set('worksheetModalSuccess',false);
-    controller.set('worksheetModalFail',false);
-
     let self = this;
     let alldatabases = this.store.findAll('database');
-
     controller.set('alldatabases',alldatabases);
 
     let selecteDBName = model.get('selectedDb');
@@ -96,14 +112,14 @@ export default Ember.Route.extend({
     selectedMultiDb.pushObject(selecteDBName);
 
     controller.set('worksheet', model);
-    controller.set('selectedTablesModels',model.get('selectedTablesModels') || selectedTablesModels );
 
+    controller.set('selectedTablesModels',model.get('selectedTablesModels') || selectedTablesModels );
     controller.set('selectedMultiDb', model.get('selectedMultiDb') || selectedMultiDb);
+
     controller.set('isQueryRunning', model.get('isQueryRunning'));
     controller.set('currentQuery', model.get('query'));
-    controller.set('queryResult', model.get('queryResult'));
     controller.set('currentJobId', null);
-
+    controller.set('queryResult', model.get('queryResult'));
     controller.set('isJobSuccess', false);
 
     controller.set('isExportResultSuccessMessege', false);
@@ -111,24 +127,36 @@ export default Ember.Route.extend({
     controller.set('showSaveHdfsModal', false);
 
     controller.set('logResults', model.get('logResults') || '');
-    controller.set('showQueryEditorLog', false);
-    controller.set('showQueryEditorResult', !controller.get('showQueryEditorLog'));
 
     controller.set('isVisualExplainQuery', false);
-    controller.set('visualExplainJson', null);
+    controller.set('visualExplainJson', model.get('visualExplainJson'));
 
-  },
+    controller.set('showWorksheetModal',false);
+    controller.set('worksheetModalSuccess',false);
+    controller.set('worksheetModalFail',false);
 
+    controller.set('tabs', tabs);
+
+  },
 
   actions: {
-    createQuery(udfName, udfClassname, fileResourceName, fileResourcePath){
-      let query = "add jar "+ fileResourcePath + ";\ncreate temporary function " + udfName + " as '"+ udfClassname+ "';";
-      this.get('controller').set('currentQuery', query);
-      this.get('controller.model').set('query', query );
+
+    resetDefaultWorksheet(){
+      this.get('controller.model').set('queryResult',{'schema' :[], 'rows' :[]});
+      this.get('controller.model').set('currentPage',0);
+      this.get('controller.model').set('previousPage',-1);
+      this.get('controller.model').set('nextPage',1);
+      //this.get('controller.model').set('selected',false);
+      this.get('controller.model').set('jobData',[]);
+      this.get('controller.model').set('currentJobData',null);
+      this.get('controller.model').set('queryFile',"");
+      this.get('controller.model').set('logFile',"");
+      this.get('controller.model').set('logResults',"");
+      this.get('controller.model').set('isQueryRunning',false);
+      this.get('controller.model').set('isQueryResultContainer',false);
     },
 
     changeDbHandler(selectedDBs){
-
       let self = this;
       let selectedTablesModels =[];
       let selectedMultiDb = [];
@@ -142,7 +170,6 @@ export default Ember.Route.extend({
           }
         )
         selectedMultiDb.pushObject(db);
-
       });
 
       this.get('controller').set('selectedTablesModels', selectedTablesModels );
@@ -150,7 +177,6 @@ export default Ember.Route.extend({
 
       this.get('controller').set('selectedMultiDb', selectedMultiDb );
       this.get('controller.model').set('selectedMultiDb', selectedMultiDb );
-
     },
 
     showQueryResultContainer(){
@@ -159,8 +185,7 @@ export default Ember.Route.extend({
 
     showTables(db){
       let self = this;
-      //should we do this by writing a seperate component.
-      $('#' + db).toggle();
+      Ember.$('#' + db).toggle();
       this.get('controller.model').set('selectedDb', db);
     },
 
@@ -169,51 +194,63 @@ export default Ember.Route.extend({
       this.send('executeQuery');
     },
 
-    executeQuery(isFirstCall){
+    updateQuery(query){
+      this.get('controller').set('currentQuery', query);
+      this.get('controller.model').set('query', query);
+    },
+
+    executeQuery(){
 
       let self = this;
       this.get('controller').set('currentJobId', null);
 
-      //let queryInput = this.get('controller').get('currentQuery');
       let isVisualExplainQuery = this.get('controller').get('isVisualExplainQuery');
-      let queryInput =  (isVisualExplainQuery) ? 'explain formatted ' + this.get('controller').get('currentQuery') : this.get('controller').get('currentQuery') ;
 
+      let queryInput = this.get('controller').get('currentQuery');
+
+      if (isVisualExplainQuery) {
+        queryInput = "";
+        let queries = this.get('controller').get('currentQuery').split(";").filter(function (query) {
+          if (query && query.trim()) return true;
+        });
+
+        for (let i = 0; i < queries.length; i++) {
+          if (i == queries.length - 1) {
+            if(queries[i].toLowerCase().startsWith("explain formatted ")){
+              queryInput += queries[i] + ";";
+            } else{
+              queryInput += "explain formatted " + queries[i] + ";";
+            }
+          } else {
+            queryInput += queries[i] + ";";
+          }
+        }
+      }
 
       this.get('controller.model').set('query', queryInput);
 
       let dbid = this.get('controller.model').get('selectedDb');
       let worksheetTitle = this.get('controller.model').get('title');
 
-      self.get('controller.model').set('jobData', []);
-      self.get('controller.model').set('isQueryRunning', true);
+      this.get('controller.model').set('jobData', []);
+      this.get('controller.model').set('isQueryRunning', true);
+
+      this.get('controller').set('queryResult', self.get('controller').get('queryResult'));
+      this.get('controller.model').set('queryResult', self.get('controller').get('queryResult'));
 
-      //Making the result set emply every time query runs.
-      self.get('controller').set('queryResult', self.get('controller').get('queryResult'));
-      self.get('controller.model').set('queryResult', self.get('controller').get('queryResult'));
+      let globalSettings = this.get('globalSettings');
 
-      self.send('showQueryResultContainer');
+      this.send('showQueryResultContainer');
 
       let payload ={
         "title":worksheetTitle,
-        "hiveQueryId":null,
-        "queryFile":null,
-        "owner":null,
         "dataBase":dbid,
-        "status":null,
-        "statusMessage":null,
-        "dateSubmitted":null,
         "forcedContent":queryInput,
-        "logFile":null,
-        "dagName":null,
-        "dagId":null,
-        "sessionTag":null,
-        "statusDir":null,
         "referrer":"job",
-        "confFile":null,
-        "globalSettings":""};
+        "globalSettings":globalSettings};
 
-      this.get('query').createJob(payload).then(function(data) {
 
+      this.get('query').createJob(payload).then(function(data) {
         self.get('controller.model').set('currentJobData', data);
         self.get('controller.model').set('queryFile', data.job.queryFile);
         self.get('controller.model').set('logFile', data.job.logFile);
@@ -221,116 +258,81 @@ export default Ember.Route.extend({
 
         self.get('jobs').waitForJobToComplete(data.job.id, 2 * 1000, false)
           .then((status) => {
-
-              self.get('controller').set('isJobSuccess', true);
-
-              self.send('getJob', data);
-
-              //Last log
-              self.send('fetchLogs');
-
+            self.get('controller').set('isJobSuccess', true);
+            self.send('getJobResult', data, payload.title);
           }, (error) => {
-            Ember.run.later(() => {
-              // TODO: handle error
-            }, 2 * 1000);
+            console.log('error', error);
+            self.get('logger').danger('Failed to execute query.', self.extractError(error));
+            self.send('resetDefaultWorksheet');
           });
 
-        self.send('getLogsTillJobSuccess', data.job.id);
-
-      }, function(reason) {
-        console.log(reason);
+      }, function(error) {
+        console.log(error);
+        self.get('logger').danger('Failed to execute query.', self.extractError(error));
+        self.send('resetDefaultWorksheet');
       });
     },
 
-    getLogsTillJobSuccess(jobId){
+    getJobResult(data, payloadTitle){
       let self = this;
-      this.get('jobs').waitForJobStatus(jobId)
-        .then((status) => {
-          console.log('status', status);
-          if(status !== "succeeded"){
-            self.send('fetchLogs');
-            Ember.run.later(() => {
-              self.send('getLogsTillJobSuccess',jobId )
-            }, 5 * 1000);
-          } else {
-            self.send('fetchLogs');
-          }
-        }, (error) => {
-          console.log('error',error);
-        });
-    },
-
-    fetchLogs(){
-      let self = this;
-
-      let logFile = this.get('controller.model').get('logFile');
-      this.get('query').retrieveQueryLog(logFile).then(function(data) {
-        self.get('controller.model').set('logResults', data.file.fileContent);
-      }, function(error){
-        console.log('error', error);
-      });
-    },
-
-    showVisualExplain(){
-       let self = this;
-       let jobId = this.get('controller').get('currentJobId');
-       this.get('query').getVisualExplainJson(jobId).then(function(data) {
-          console.log('Successful getVisualExplainJson', data);
-
-          self.get('controller').set('visualExplainJson', data.rows[0][0]);
-
-       }, function(error){
-          console.log('error getVisualExplainJson', error);
-        });
-    },
-
-    getJob(data){
-
-      var self = this;
-      var data = data;
 
       let isVisualExplainQuery = this.get('controller').get('isVisualExplainQuery');
 
       let jobId = data.job.id;
-      let dateSubmitted = data.job.dateSubmitted;
 
       let currentPage = this.get('controller.model').get('currentPage');
       let previousPage = this.get('controller.model').get('previousPage');
       let nextPage = this.get('controller.model').get('nextPage');
 
-      this.get('query').getJob(jobId, dateSubmitted, true).then(function(data) {
-        // on fulfillment
-        console.log('getJob route', data );
+      this.get('query').getJob(jobId, true).then(function(data) {
+
+        let existingWorksheets = self.get('store').peekAll('worksheet');
+        let myWs = null;
+        if(existingWorksheets.get('length') > 0) {
+          myWs = existingWorksheets.filterBy('title', payloadTitle).get('firstObject');
+        }
 
-        self.get('controller').set('queryResult', data);
-        self.get('controller.model').set('queryResult', data);
-        self.get('controller.model').set('isQueryRunning', false);
+        myWs.set('queryResult', data);
+        myWs.set('isQueryRunning', false);
+        myWs.set('hasNext', data.hasNext);
 
-        let localArr = self.get('controller.model').get("jobData");
+        let localArr = myWs.get("jobData");
         localArr.push(data);
-        self.get('controller.model').set('jobData', localArr);
-        self.get('controller.model').set('currentPage', currentPage+1);
-        self.get('controller.model').set('previousPage', previousPage + 1 );
-        self.get('controller.model').set('nextPage', nextPage + 1);
+        myWs.set('jobData', localArr);
+        myWs.set('currentPage', currentPage+1);
+        myWs.set('previousPage', previousPage + 1 );
+        myWs.set('nextPage', nextPage + 1);
 
         if(isVisualExplainQuery){
-          Ember.run.later(() => {
-            self.send('showVisualExplain');
-          }, 500);
+          self.send('showVisualExplain', payloadTitle);
         }
 
-      }, function(reason) {
-        // on rejection
-        console.log('reason' , reason);
+        if( self.paramsFor('queries.query').worksheetId == payloadTitle){
+          self.transitionTo('queries.query.results');
+        }
+
+      }, function(error) {
+        console.log('error' , error);
       });
     },
 
-    updateQuery(query){
-      this.get('controller').set('currentQuery', query);
-      this.get('controller.model').set('query', query);
+    showVisualExplain(payloadTitle){
+       let self = this;
+       let jobId = this.get('controller').get('currentJobId');
+       this.get('query').getVisualExplainJson(jobId).then(function(data) {
+          console.log('Successful getVisualExplainJson', data);
+          self.get('controller.model').set('visualExplainJson', data.rows[0][0]);
+
+          if( self.paramsFor('queries.query').worksheetId == payloadTitle){
+           self.transitionTo('queries.query.visual-explain');
+          }
+
+        }, function(error){
+          console.log('error getVisualExplainJson', error);
+        });
     },
 
-    goNextPage(){
+    goNextPage(payloadTitle){
 
       let currentPage = this.get('controller.model').get('currentPage');
       let previousPage = this.get('controller.model').get('previousPage');
@@ -341,15 +343,12 @@ export default Ember.Route.extend({
         var self = this;
         var data = this.get('controller.model').get('currentJobData');
         let jobId = data.job.id;
-        let dateSubmitted = data.job.dateSubmitted;
 
-        this.get('query').getJob(jobId, dateSubmitted, false).then(function(data) {
-          // on fulfillment
-          console.log('getJob route', data );
-          self.get('controller').set('queryResult', data);
+        this.get('query').getJob(jobId, false).then(function(data) {
           self.get('controller.model').set('queryResult', data);
           self.get('controller.model').set('isQueryRunning', false);
-          self.get('controller.model').set('hidePreviousButton', false);
+          self.get('controller.model').set('hasNext', data.hasNext);
+          self.get('controller.model').set('hasPrevious', true);
 
           let localArr = self.get('controller.model').get("jobData");
           localArr.push(data);
@@ -358,21 +357,33 @@ export default Ember.Route.extend({
           self.get('controller.model').set('currentPage', currentPage+1);
           self.get('controller.model').set('previousPage', previousPage + 1 );
           self.get('controller.model').set('nextPage', nextPage + 1);
-        }, function(reason) {
-          // on rejection
-          console.log('reason' , reason);
+        }, function(error) {
+            console.log('error' , error);
         });
-      } else { //Pages from cache object
+      } else {
+        //Pages from cache object
         this.get('controller.model').set('currentPage', currentPage+1);
         this.get('controller.model').set('previousPage', previousPage + 1 );
         this.get('controller.model').set('nextPage', nextPage + 1);
-        this.get('controller.model').set('hidePreviousButton', false);
-        this.get('controller').set('queryResult', this.get('controller.model').get("jobData")[this.get('controller.model').get('currentPage')-1] );
+        this.get('controller.model').set('hasNext', this.get('controller.model').get('jobData')[this.get('controller.model').get('currentPage')-1].hasNext);
+        this.get('controller.model').set('hasPrevious', (this.get('controller.model').get('currentPage') > 1) ? true : false );
         this.get('controller.model').set('queryResult', this.get('controller.model').get("jobData")[this.get('controller.model').get('currentPage')-1] );
       }
+
+      let existingWorksheets = this.get('store').peekAll('worksheet');
+      let myWs = null;
+      if(existingWorksheets.get('length') > 0) {
+        myWs = existingWorksheets.filterBy('title', payloadTitle).get('firstObject');
+      }
+
+      this.transitionTo('queries.query.loading');
+
+      Ember.run.later(() => {
+        this.transitionTo('queries.query.results', myWs);
+      }, 1 * 1000);
     },
 
-    goPrevPage(){
+    goPrevPage(payloadTitle){
       let currentPage = this.get('controller.model').get('currentPage');
       let previousPage = this.get('controller.model').get('previousPage');
       let nextPage = this.get('controller.model').get('nextPage');
@@ -382,64 +393,25 @@ export default Ember.Route.extend({
         this.get('controller.model').set('currentPage', currentPage-1 );
         this.get('controller.model').set('previousPage', previousPage - 1 );
         this.get('controller.model').set('nextPage', nextPage-1);
-
         this.get('controller').set('queryResult', this.get('controller.model').get("jobData")[this.get('controller.model').get('currentPage') -1 ]);
         this.get('controller.model').set('queryResult', this.get('controller.model').get("jobData")[this.get('controller.model').get('currentPage') -1 ]);
-      } else {
-        this.get('controller.model').set('hidePreviousButton', true);
+        this.get('controller.model').set('hasNext', true);
+        this.get('controller.model').set('hasPrevious', (this.get('controller.model').get('currentPage') > 1) ? true : false );
       }
-    },
-
-    expandQueryEdidorPanel(){
 
-      if(!this.get('isQueryEdidorPaneExpanded')){
-        this.set('isQueryEdidorPaneExpanded', true);
-      } else {
-        this.set('isQueryEdidorPaneExpanded', false);
+      let existingWorksheets = this.get('store').peekAll('worksheet');
+      let myWs = null;
+      if(existingWorksheets.get('length') > 0) {
+        myWs = existingWorksheets.filterBy('title', payloadTitle).get('firstObject');
       }
-      Ember.$('.query-editor-panel').toggleClass('query-editor-full-width');
-      Ember.$('.database-panel').toggleClass("hide");
-
-    },
-
-    expandQueryResultPanel(){
-
-      if(!this.get('isQueryResultPanelExpanded')){
-
-        if(!this.get('isQueryEdidorPaneExpanded')){
-          Ember.$('.query-editor-container').addClass("hide");
-          Ember.$('.database-panel').addClass("hide");
-          Ember.$('.query-editor-panel').addClass('query-editor-full-width');
-        } else {
-
-          Ember.$('.query-editor-container').addClass("hide");
-        }
-        this.set('isQueryResultPanelExpanded', true);
-
-      } else {
 
-        if(!this.get('isQueryEdidorPaneExpanded')){
-          Ember.$('.query-editor-container').removeClass("hide");
-          Ember.$('.database-panel').removeClass("hide");
-          Ember.$('.query-editor-panel').removeClass('query-editor-full-width');
-        } else {
+      this.transitionTo('queries.query.loading');
 
-          Ember.$('.query-editor-container').removeClass("hide");
+      Ember.run.later(() => {
+        this.transitionTo('queries.query.results', myWs);
+      }, 1 * 1000);
 
-        }
-        this.set('isQueryResultPanelExpanded', false);
-
-      }
-
-    },
 
-    adjustPanelSize(){
-      let isFullHeight = ($(window).height() ==(parseInt(Ember.$('.ember-light-table').css('height'), 10)) ) || false;
-      if(!isFullHeight){
-        Ember.$('.ember-light-table').css('height', '100vh');
-      }else {
-        Ember.$('.ember-light-table').css('height', '70vh');
-      }
     },
 
     openWorksheetModal(){
@@ -463,22 +435,27 @@ export default Ember.Route.extend({
         "queryFile" : queryFile,
         "logFile" : logFile};
 
-      this.get('savedQueries').saveQuery(payload)
-        .then((data) => {
-          console.log('Created saved query.', data);
-          this.get('controller.model').set('title', newTitle);
-          this.get('controller').set('worksheetModalSuccess', true);
+      let newSaveQuery = this.get('store').createRecord('saved-query',
+        { dataBase:selectedDb,
+          title:newTitle,
+          queryFile: queryFile,
+          owner: owner,
+          shortQuery: (currentQuery.length > 0) ? currentQuery : ";"
+        });
 
-          Ember.run.later(() => {
-            this.get('controller').set('showWorksheetModal', false);
-          }, 2 * 1000);
 
-        }, (error) => {
-          console.log("Error encountered", error);
-          Ember.run.later(() => {
-            this.get('controller').set('worksheetModalFail', true);
-          }, 2 * 1000);
-        });
+      newSaveQuery.save().then((data) => {
+        console.log('saved query saved');
+
+        this.get('controller.model').set('title', newTitle);
+        this.get('controller').set('worksheetModalSuccess', true);
+
+        Ember.run.later(() => {
+          this.get('controller').set('showWorksheetModal', false);
+        }, 2 * 1000);
+
+      });
+
     },
 
     closeWorksheetModal(){
@@ -524,29 +501,54 @@ export default Ember.Route.extend({
 
     },
 
-    showQueryEditorLog(){
-      this.get('controller').set('showQueryEditorLog', true);
-      this.get('controller').set('showQueryEditorResult', false);
+    expandQueryEdidorPanel(){
+      if(!this.get('isQueryEdidorPaneExpanded')){
+        this.set('isQueryEdidorPaneExpanded', true);
+      } else {
+        this.set('isQueryEdidorPaneExpanded', false);
+      }
+      Ember.$('.query-editor-panel').toggleClass('query-editor-full-width');
+      Ember.$('.database-panel').toggleClass("hide");
+    },
+
+    expandQueryResultPanel(){
+      if(!this.get('isQueryResultPanelExpanded')){
+        if(!this.get('isQueryEdidorPaneExpanded')){
+          Ember.$('.query-editor-container').addClass("hide");
+          Ember.$('.database-panel').addClass("hide");
+          Ember.$('.query-editor-panel').addClass('query-editor-full-width');
+        } else {
 
-      $('.log-list-anchor').addClass('active');
-      $('.log-list').addClass('active');
-      $('.editor-result-list-anchor').removeClass('active');
-      $('.editor-result-list').removeClass('active');
+          Ember.$('.query-editor-container').addClass("hide");
+        }
+        this.set('isQueryResultPanelExpanded', true);
+      } else {
+        if(!this.get('isQueryEdidorPaneExpanded')){
+          Ember.$('.query-editor-container').removeClass("hide");
+          Ember.$('.database-panel').removeClass("hide");
+          Ember.$('.query-editor-panel').removeClass('query-editor-full-width');
+        } else {
+          Ember.$('.query-editor-container').removeClass("hide");
+        }
+        this.set('isQueryResultPanelExpanded', false);
+      }
     },
 
-    showQueryEditorResult(){
-      this.get('controller').set('showQueryEditorLog', false);
-      this.get('controller').set('showQueryEditorResult', true);
+    adjustPanelSize(){
+      let isFullHeight = ($(window).height() ==(parseInt(Ember.$('.ember-light-table').css('height'), 10)) ) || false;
+      if(!isFullHeight){
+        Ember.$('.ember-light-table').css('height', '100vh');
+      }else {
+        Ember.$('.ember-light-table').css('height', '70vh');
+      }
+    },
 
-      $('.log-list-anchor').removeClass('active');
-      $('.log-list').removeClass('active');
-      $('.editor-result-list-anchor').addClass('active');
-      $('.editor-result-list').addClass('active');
+    createQuery(udfName, udfClassname, fileResourceName, fileResourcePath){
+      let query = "add jar "+ fileResourcePath + ";\ncreate temporary function " + udfName + " as '"+ udfClassname+ "';";
+      this.get('controller').set('currentQuery', query);
+      this.get('controller.model').set('query', query );
     }
-  },
 
-  showQueryResultContainer(){
-    this.get('controller.model').set('isQueryResultContainer', true);
   }
 
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/loading.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/loading.js b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/loading.js
new file mode 100644
index 0000000..b5070bc
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/loading.js
@@ -0,0 +1,24 @@
+/**
+ * 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';
+
+export default Ember.Route.extend({
+  beforeModel() {
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/log.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/log.js b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/log.js
new file mode 100644
index 0000000..52f8dcc
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/log.js
@@ -0,0 +1,104 @@
+/**
+ * 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';
+
+export default Ember.Route.extend({
+
+  jobs: Ember.inject.service(),
+  query: Ember.inject.service(),
+
+  model(){
+    return this.modelFor('queries.query');
+  },
+
+  getLogsTillJobSuccess(jobId, model, controller){
+    let self = this;
+    this.get('jobs').waitForJobStatus(jobId)
+      .then((status) => {
+        console.log('status', status);
+        if(status !== "succeeded"){
+
+          self.fetchLogs(model).then((logFileContent) => {
+            controller.set('logResults', logFileContent );
+          }, (error) => {
+            console.log('error',error);
+          });
+
+          Ember.run.later(() => {
+            self.getLogsTillJobSuccess(jobId, model, controller);
+          }, 5 * 1000);
+
+        } else {
+
+          self.fetchLogs(model).then((logFileContent) => {
+            controller.set('logResults', logFileContent );
+          }, (error) => {
+            console.log('error',error);
+          });
+
+        }
+      }, (error) => {
+        console.log('error',error);
+      });
+  },
+
+  fetchLogs(model){
+    let logFile = model.get('logFile');
+    return new Promise( (resolve, reject) => {
+      this.get('query').retrieveQueryLog(logFile).then(function(data) {
+        resolve(data.file.fileContent);
+      }, function(error){
+        reject(error);
+      });
+    });
+  },
+
+  jobStatus(jobId){
+    return new Promise( (resolve, reject) => {
+      this.get('jobs').waitForJobStatus(jobId).then(function(status) {
+        resolve(status);
+      }, function(error){
+        reject(error);
+      });
+    });
+
+  },
+
+  setupController(controller, model){
+    this._super(...arguments);
+
+    model.set('lastResultRoute', ".log");
+
+    if(!Ember.isEmpty(model.get('currentJobData'))){
+      let jobId = model.get('currentJobData').job.id;
+      this.controller.set('jobId', jobId);
+      this.controller.set('logResults', model.get('logResults'));
+      this.getLogsTillJobSuccess(jobId, model, controller);
+      this.controller.set('hasJobAssociated', true);
+
+    } else {
+      this.controller.set('hasJobAssociated', false);
+    }
+  },
+
+  actions:{
+
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/results.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/results.js b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/results.js
new file mode 100644
index 0000000..4b59a13
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/results.js
@@ -0,0 +1,59 @@
+/**
+ * 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';
+
+export default Ember.Route.extend({
+
+  jobs: Ember.inject.service(),
+  query: Ember.inject.service(),
+
+  beforeModel() {
+  },
+
+  model(){
+    return this.modelFor('queries.query');
+  },
+
+  setupController(controller, model){
+    this._super(...arguments);
+
+    model.set('lastResultRoute', ".results");
+
+    if(!Ember.isEmpty(model.get('currentJobData'))){
+
+      let jobId = model.get('currentJobData').job.id;
+      this.controller.set('jobId', jobId);
+      this.controller.set('payloadTitle',  model.get('currentJobData').job.title);
+      this.controller.set('isQueryRunning', model.get('isQueryRunning'));
+      this.controller.set('previousPage', model.get('previousPage'));
+      this.controller.set('hasNext', model.get('hasNext'));
+      this.controller.set('hasPrevious', model.get('hasPrevious'));
+      this.controller.set('queryResult', model.get('queryResult'));
+      this.controller.set('hasJobAssociated', true);
+    } else {
+      this.controller.set('hasJobAssociated', false);
+    }
+
+  },
+
+  actions:{
+
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/tez-ui.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/tez-ui.js b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/tez-ui.js
new file mode 100644
index 0000000..daf142b
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/tez-ui.js
@@ -0,0 +1,45 @@
+/**
+ * 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';
+
+export default Ember.Route.extend({
+
+  jobs: Ember.inject.service(),
+  query: Ember.inject.service(),
+
+  beforeModel() {
+  },
+
+  model(){
+    return this.modelFor('queries.query');
+  },
+
+  setupController(controller, model){
+    this._super(...arguments);
+
+    model.set('lastResultRoute', ".tez-ui");
+
+
+  },
+
+  actions:{
+
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/visual-explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/visual-explain.js b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/visual-explain.js
new file mode 100644
index 0000000..ff3832d
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query/visual-explain.js
@@ -0,0 +1,56 @@
+/**
+ * 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';
+
+export default Ember.Route.extend({
+
+  jobs: Ember.inject.service(),
+  query: Ember.inject.service(),
+
+  beforeModel() {
+  },
+
+  model(){
+    return this.modelFor('queries.query');
+  },
+
+  setupController(controller, model){
+    this._super(...arguments);
+
+    model.set('lastResultRoute', ".visual-explain");
+
+    if(!Ember.isEmpty(model.get('currentJobData'))){
+
+      let jobId = model.get('currentJobData').job.id;
+      this.controller.set('jobId', jobId);
+      this.controller.set('payloadTitle',  model.get('currentJobData').job.title);
+      this.controller.set('isQueryRunning', model.get('isQueryRunning'));
+      this.controller.set('visualExplainJson', model.get('visualExplainJson'));
+
+      this.controller.set('hasJobAssociated', true);
+    } else {
+      this.controller.set('hasJobAssociated', false);
+    }
+  },
+
+  actions:{
+
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/services/query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/query.js b/contrib/views/hive20/src/main/resources/ui/app/services/query.js
index 42d4fb0..3bf10c0 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/services/query.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/services/query.js
@@ -31,10 +31,10 @@ export default Ember.Service.extend({
       });
     });
   },
-  getJob(jobId, dateSubmitted, firstCall){
+  getJob(jobId, firstCall){
     let self = this;
     return new Promise( (resolve, reject) => {
-      this.get('store').adapterFor('query').getJob(jobId, dateSubmitted, firstCall).then(function(data) {
+      this.get('store').adapterFor('query').getJob(jobId, firstCall).then(function(data) {
         resolve(data);
       }, function(err) {
           reject(err);

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
index 4d8524e..2590796 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
@@ -16,17 +16,6 @@
 * limitations under the License.
 }}
 
-
-
-{{#if isQueryRunning}}
-   <div style="position:relative">
-       <div style="margin: auto;position: absolute;top: 0;left: 0;bottom: 0;right: 0;text-align: center">
-         {{fa-icon "spinner fa-2" spin=true}}
-       </div>
-    </div>
-{{/if}}
-
-{{#unless isQueryRunning}}
   <div class="clearfix" style="text-align: right; padding-right:5px">
     <span class="dropdown">
       <button class="btn btn-default dropdown-toggle" title="Actions" data-toggle="dropdown">{{fa-icon "bars"}} </button>
@@ -36,9 +25,10 @@
       </ul>
     </span>&nbsp;
 
-    <button class="btn btn-default" title="Previous Page" {{action "goPrevPage" }}  >{{fa-icon "arrow-left"}} </button>
-    <button class="btn btn-default" title="Next Page" {{action "goNextPage" }}>{{fa-icon "arrow-right"}} </button> &nbsp;
+    <button class="btn btn-default" title="Previous Page" {{action "goPrevPage" payloadTitle }} disabled={{not hasPrevious}} >{{fa-icon "arrow-left"}} </button>
+    <button class="btn btn-default" title="Next Page" {{action "goNextPage" payloadTitle}} disabled={{not hasNext}} >{{fa-icon "arrow-right"}} </button> &nbsp;
     <button class="btn btn-default" title="Expand/Collspse" {{action "expandQueryResultPanel" }}>{{fa-icon "expand"}}</button>
+
   </div>
 
   <div class="clearfix">
@@ -66,10 +56,6 @@
     {{/light-table}}
   </div>
 
-
-{{/unless}}
-
-
 {{#if showSaveHdfsModal}}
   {{export-result
   confirmText="OK"

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/templates/components/visual-explain.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/visual-explain.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/visual-explain.hbs
index e0ceaa2..905e73c 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/visual-explain.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/visual-explain.hbs
@@ -29,7 +29,6 @@
   </div>
 {{/if}}
 
-
 {{#unless isQueryRunning}}
   <div id="explain-container" ></div>
 {{/unless}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
index 5b2b5c2..d62c781 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
@@ -43,69 +43,19 @@
             </ul>
         </div>
         <button class="btn btn-default" {{action "visualExplainQuery" }}>{{fa-icon "link"}} Visual Explain</button>
+
         {{#if worksheet.isQueryRunning}}
           {{fa-icon "spinner fa-1-5" spin=true}}
         {{/if}}
+
       </div>
     </div>
 
-    {{#if worksheet.isQueryResultContainer}}
-      <div class="query-result-container">
-        <div>
-          <ul class="row nav nav-tabs inverse">
-            <li class="editor-result-list active">
-              <a href="javascript:void(0)" class="editor-result-list-anchor active" {{action 'showQueryEditorResult' }}>
-                {{fa-icon "file-text-o"}}&nbsp;&nbsp;RESULT
-              </a>
-            </li>
-            <li class="log-list">
-              <a href="javascript:void(0)" class="log-list-anchor" {{action 'showQueryEditorLog' }}>
-                {{fa-icon "list"}}&nbsp;&nbsp;LOG
-              </a>
-            </li>
-          </ul>
-        </div>
+    {{#tabs-pane tabs=tabs inverse=true as |tab|}}
+      {{tabs-item tab=tab tabs=tabs}}
+    {{/tabs-pane}}
 
-        {{#if showQueryEditorLog}}
-          <div class="clearfix row query-editor-log">
-            {{query-result-log logResults=worksheet.logResults }}
-          </div>
-        {{/if}}
-        {{#if showQueryEditorResult}}
-          <div class="clearfix row query-editor-results">
-
-            {{#if isVisualExplainQuery}}
-                {{visual-explain
-                expandQueryResultPanel='expandQueryResultPanel'
-                isQueryRunning=worksheet.isQueryRunning
-                visualExplainJson=visualExplainJson
-                }}
-              {{else}}
-              {{query-result-table
-              queryResult=queryResult
-              jobId=currentJobId
-              updateQuery='updateQuery'
-              previousPage=worksheet.previousPage
-              hidePreviousButton=hidePreviousButton
-              goNextPage='goNextPage'
-              goPrevPage='goPrevPage'
-              expandQueryResultPanel='expandQueryResultPanel'
-              saveToHDFS='saveToHDFS'
-              downloadAsCsv='downloadAsCsv'
-              isExportResultSuccessMessege=isExportResultSuccessMessege
-              isExportResultFailureMessege=isExportResultFailureMessege
-              showSaveHdfsModal=showSaveHdfsModal
-              isQueryRunning=worksheet.isQueryRunning
-              }}
-            {{/if}}
-
-
-
-          </div>
-        {{/if}}
-
-      </div>
-    {{/if}}
+    {{outlet}}
   </div>
 </div>
 
@@ -181,4 +131,4 @@
   {{/modal-dialog}}
 {{/if}}
 
-{{outlet}}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/loading.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/loading.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/loading.hbs
new file mode 100644
index 0000000..b1de181
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/loading.hbs
@@ -0,0 +1,21 @@
+{{!
+* 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.
+}}
+
+<div class="alert alert-info text-center">
+  <p class="lead">Data Loading... Please wait. {{fa-icon "refresh" spin=true}}</p>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/log.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/log.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/log.hbs
new file mode 100644
index 0000000..db1cea2
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/log.hbs
@@ -0,0 +1,29 @@
+{{!
+* 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.
+}}
+
+{{#unless hasJobAssociated}}
+  <div>No Log avaiable.</div>
+{{/unless}}
+
+{{#if hasJobAssociated}}
+  <div>
+    <pre class="prettyprint">{{logResults}}</pre>
+  </div>
+
+{{/if}}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/results.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/results.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/results.hbs
new file mode 100644
index 0000000..370e3ef
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/results.hbs
@@ -0,0 +1,49 @@
+{{!
+* 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.
+}}
+
+{{outlet}}
+
+{{#unless hasJobAssociated}}
+  <div>No Results avaiable.</div>
+{{/unless}}
+
+{{#if hasJobAssociated}}
+  {{query-result-table
+  queryResult=queryResult
+  isQueryRunning=isQueryRunning
+  jobId=jobId
+  payloadTitle=payloadTitle
+  previousPage=previousPage
+  hasNext=hasNext
+  hasPrevious=hasPrevious
+  updateQuery='updateQuery'
+  goNextPage='goNextPage'
+  goPrevPage='goPrevPage'
+  saveToHDFS='saveToHDFS'
+  downloadAsCsv='downloadAsCsv'
+  expandQueryResultPanel='expandQueryResultPanel'
+  isExportResultSuccessMessege=false
+  isExportResultFailureMessege=false
+  showSaveHdfsModal=false
+  }}
+{{/if}}
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/tez-ui.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/tez-ui.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/tez-ui.hbs
new file mode 100644
index 0000000..9dfa3fa
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/tez-ui.hbs
@@ -0,0 +1,19 @@
+{{!
+* 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.
+}}
+
+<div>I am in tez-ui route.</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/visual-explain.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/visual-explain.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/visual-explain.hbs
new file mode 100644
index 0000000..ef441b5
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query/visual-explain.hbs
@@ -0,0 +1,33 @@
+{{!
+* 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.
+}}
+
+{{outlet}}
+
+{{#unless hasJobAssociated}}
+  <div>No Visual Explain avaiable.</div>
+{{/unless}}
+
+{{#if hasJobAssociated}}
+  {{#if visualExplainJson}}
+    {{visual-explain
+    expandQueryResultPanel='expandQueryResultPanel'
+    visualExplainJson=visualExplainJson
+    isQueryRunning=isQueryRunning
+    }}
+  {{/if}}
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/316d33a9/contrib/views/hive20/src/main/resources/ui/config/environment.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/config/environment.js b/contrib/views/hive20/src/main/resources/ui/config/environment.js
index 411ee99..c891508 100644
--- a/contrib/views/hive20/src/main/resources/ui/config/environment.js
+++ b/contrib/views/hive20/src/main/resources/ui/config/environment.js
@@ -34,7 +34,7 @@ module.exports = function(environment) {
     APP: {
       // Here you can pass flags/options to your application instance
       // when it is created
-      SHOULD_PERFORM_SERVICE_CHECK: true
+      SHOULD_PERFORM_SERVICE_CHECK: false
     }
   };
 


[28/28] ambari git commit: Merge branch 'trunk' into branch-feature-AMBARI-20053

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-feature-AMBARI-20053


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/0c464b74
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/0c464b74
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/0c464b74

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 0c464b742f206b0e6cf0c5d425d17023b47b4d9e
Parents: 9386eed 600d0a1
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Tue Feb 21 12:07:12 2017 -0500
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Tue Feb 21 12:07:12 2017 -0500

----------------------------------------------------------------------
 .../src/main/python/ambari_agent/main.py        |  23 +
 ambari-server/docs/api/v1/schemas.md            |   2 +-
 .../server/state/cluster/ClusterImpl.java       |  43 +-
 .../ATLAS/0.1.0.2.3/kerberos.json               |   3 +
 .../DRUID/0.9.2/package/scripts/params.py       |   2 +-
 .../0.5.0.2.2/configuration/gateway-site.xml    |   6 +
 .../0.5.0.2.2/package/scripts/params_linux.py   |  11 +
 .../SPARK2/2.0.0/package/scripts/params.py      |   2 +
 .../2.0.0/package/scripts/service_check.py      |   4 +-
 .../before-ANY/scripts/shared_initialization.py |   4 +
 .../stacks/HDP/2.2/services/stack_advisor.py    |   7 +-
 .../stacks/HDP/2.3/services/stack_advisor.py    |   2 +-
 .../stacks/HDP/2.3/upgrades/config-upgrade.xml  |   5 +
 .../HDP/2.3/upgrades/nonrolling-upgrade-2.6.xml |   6 +
 .../stacks/HDP/2.3/upgrades/upgrade-2.6.xml     |   2 +
 .../stacks/HDP/2.4/upgrades/config-upgrade.xml  |   5 +
 .../HDP/2.4/upgrades/nonrolling-upgrade-2.6.xml |   6 +
 .../stacks/HDP/2.4/upgrades/upgrade-2.6.xml     |   2 +
 .../HIVE/configuration/hive-interactive-env.xml |   2 +-
 .../stacks/HDP/2.5/upgrades/config-upgrade.xml  |  17 +-
 .../HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml |  20 +-
 .../stacks/HDP/2.5/upgrades/upgrade-2.6.xml     |   5 +-
 .../stacks/HDP/2.6/services/ATLAS/kerberos.json |   3 +
 .../services/KNOX/configuration/topology.xml    |  10 +
 .../stacks/HDP/2.6/services/stack_advisor.py    |   4 +-
 .../server/state/cluster/ClusterTest.java       |  36 +-
 .../2.0.6/hooks/before-ANY/test_before_any.py   |   3 +
 .../stacks/2.2/common/test_stack_advisor.py     |   1 -
 .../stacks/2.3/common/test_stack_advisor.py     |   2 -
 ambari-web/app/styles/application.less          |   8 +-
 ambari-web/app/styles/wizard.less               |   8 +
 .../common/assign_master_components.hbs         |   5 +-
 .../app/templates/common/form/dropdown.hbs      |  29 +
 ambari-web/app/views.js                         |   1 +
 .../common/assign_master_components_view.js     |   5 +-
 .../views/common/configs/service_config_view.js |   1 +
 ambari-web/app/views/common/form/dropdown.js    |  84 +++
 .../src/main/resources/ui/app/adapters/query.js |   6 +-
 .../ui/app/components/query-result-table.js     |  30 +-
 .../resources/ui/app/components/upload-table.js |   2 +-
 .../ui/app/components/visual-explain.js         |  31 +-
 .../resources/ui/app/configs/result-tabs.js     |  48 ++
 .../resources/ui/app/helpers/extract-value.js   |  27 +
 .../resources/ui/app/mixins/table-common.js     |  86 ---
 .../main/resources/ui/app/mixins/ui-logger.js   |   9 +
 .../main/resources/ui/app/models/worksheet.js   |   8 +-
 .../hive20/src/main/resources/ui/app/router.js  |   6 +-
 .../databases/database/tables/upload-table.js   |  41 +-
 .../resources/ui/app/routes/queries/query.js    | 467 +++++++-------
 .../ui/app/routes/queries/query/loading.js      |  24 +
 .../ui/app/routes/queries/query/log.js          | 104 +++
 .../ui/app/routes/queries/query/results.js      |  59 ++
 .../ui/app/routes/queries/query/tez-ui.js       |  45 ++
 .../app/routes/queries/query/visual-explain.js  |  56 ++
 .../main/resources/ui/app/routes/udfs/new.js    |  71 +-
 .../resources/ui/app/services/alert-messages.js |   7 +-
 .../src/main/resources/ui/app/services/query.js |   4 +-
 .../src/main/resources/ui/app/styles/app.scss   | 251 +++-----
 .../ui/app/templates/components/column-item.hbs |   4 +-
 .../templates/components/query-result-table.hbs |  79 ++-
 .../app/templates/components/upload-table.hbs   |   4 +-
 .../app/templates/components/visual-explain.hbs |   3 +-
 .../ui/app/templates/queries/query.hbs          |  66 +-
 .../ui/app/templates/queries/query/loading.hbs  |  21 +
 .../ui/app/templates/queries/query/log.hbs      |  29 +
 .../ui/app/templates/queries/query/results.hbs  |  49 ++
 .../ui/app/templates/queries/query/tez-ui.hbs   |  19 +
 .../templates/queries/query/visual-explain.hbs  |  33 +
 .../resources/ui/app/utils/hive-explainer.js    | 645 -------------------
 .../ui/app/utils/hive-explainer/enhancer.js     |  37 ++
 .../ui/app/utils/hive-explainer/fallback.js     |  34 +
 .../ui/app/utils/hive-explainer/index.js        |  31 +
 .../ui/app/utils/hive-explainer/processor.js    | 240 +++++++
 .../app/utils/hive-explainer/renderer-force.js  | 325 ++++++++++
 .../ui/app/utils/hive-explainer/renderer.js     | 327 ++++++++++
 .../ui/app/utils/hive-explainer/transformer.js  | 445 +++++++++++++
 .../hive20/src/main/resources/ui/bower.json     |   3 +-
 .../src/main/resources/ui/config/environment.js |   2 +-
 .../src/main/resources/ui/ember-cli-build.js    |   1 +
 .../hive20/src/main/resources/ui/package.json   |   1 -
 .../ambari/view/OozieProxyImpersonator.java     | 192 +++---
 .../apache/oozie/ambari/view/OozieUtils.java    |  18 +
 .../org/apache/oozie/ambari/view/Utils.java     |  14 +-
 .../oozie/ambari/view/WorkflowFilesService.java |  22 +-
 .../workflowmanager/WorkflowManagerService.java |   6 +-
 .../WorkflowsManagerResource.java               |   7 +-
 .../view/workflowmanager/WorkflowsRepo.java     |  40 +-
 .../ui/app/components/bundle-config.js          |  18 +-
 .../resources/ui/app/components/coord-config.js |   6 +-
 .../ui/app/components/flow-designer.js          |  70 +-
 .../resources/ui/app/components/hdfs-browser.js |   9 +
 .../main/resources/ui/app/components/job-row.js |   6 +
 .../main/resources/ui/app/components/save-wf.js |  11 +-
 .../ui/app/components/search-create-new-bar.js  |   2 +-
 .../resources/ui/app/components/search-table.js |  17 +-
 .../ui/app/domain/cytoscape-flow-renderer.js    |  34 +-
 .../ui/app/domain/workflow-xml-generator.js     |   4 -
 .../main/resources/ui/app/domain/workflow.js    |   8 +-
 .../app/templates/components/bundle-config.hbs  |   2 +-
 .../app/templates/components/hdfs-browser.hbs   |   5 +
 .../ui/app/templates/components/job-config.hbs  |  37 +-
 .../app/templates/components/search-table.hbs   |  11 +-
 102 files changed, 3117 insertions(+), 1581 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/0c464b74/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/0c464b74/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
----------------------------------------------------------------------


[11/28] ambari git commit: AMBARI-20081. Install actions fail when switching from root to non-root. (aonishuk)

Posted by jo...@apache.org.
AMBARI-20081. Install actions fail when switching from root to non-root. (aonishuk)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/709bf6ef
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/709bf6ef
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/709bf6ef

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 709bf6ef3261e609bec1161d02ae6787911e2919
Parents: 2744ae8
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Mon Feb 20 14:45:43 2017 +0200
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Mon Feb 20 14:45:43 2017 +0200

----------------------------------------------------------------------
 .../HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py  | 4 ++++
 .../test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py | 3 +++
 2 files changed, 7 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/709bf6ef/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py b/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py
index f97789b..4d0de7f 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py
@@ -198,6 +198,10 @@ def setup_java():
          not_if = format("test -f {jdk_curl_target}")
     )
 
+    File(jdk_curl_target,
+         mode = 0755,
+    )
+
     tmp_java_dir = tempfile.mkdtemp(prefix="jdk_tmp_", dir=params.tmp_dir)
 
     try:

http://git-wip-us.apache.org/repos/asf/ambari/blob/709bf6ef/ambari-server/src/test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py b/ambari-server/src/test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py
index 3b614d9..75c6543 100644
--- a/ambari-server/src/test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py
+++ b/ambari-server/src/test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py
@@ -193,6 +193,9 @@ class TestHookBeforeInstall(RMFTestCase):
                               content = DownloadSource('http://c6401.ambari.apache.org:8080/resources//jdk-7u67-linux-x64.tar.gz'),
                               not_if = 'test -f /tmp/jdk-7u67-linux-x64.tar.gz',
                               )
+    self.assertResourceCalled('File', '/tmp/jdk-7u67-linux-x64.tar.gz',
+                              mode = 0755,
+                              )
     self.assertResourceCalled('Directory', '/usr/jdk64',)
     self.assertResourceCalled('Execute', ('chmod', 'a+x', u'/usr/jdk64'),
                               sudo = True


[13/28] ambari git commit: AMBARI-20082. Wizard 'Assign Master ' step is showing inconsistent Select view (akovalenko)

Posted by jo...@apache.org.
AMBARI-20082. Wizard 'Assign Master ' step is showing inconsistent Select view (akovalenko)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ece4d36c
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ece4d36c
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ece4d36c

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: ece4d36cb32a0a4b60025e9d54ba4131105a794b
Parents: 6feb46a
Author: Aleksandr Kovalenko <ak...@hortonworks.com>
Authored: Mon Feb 20 14:44:38 2017 +0200
Committer: Aleksandr Kovalenko <ak...@hortonworks.com>
Committed: Mon Feb 20 15:42:13 2017 +0200

----------------------------------------------------------------------
 ambari-web/app/styles/application.less          |  8 +-
 ambari-web/app/styles/wizard.less               |  8 ++
 .../common/assign_master_components.hbs         |  5 +-
 .../app/templates/common/form/dropdown.hbs      | 29 +++++++
 ambari-web/app/views.js                         |  1 +
 .../common/assign_master_components_view.js     |  5 +-
 ambari-web/app/views/common/form/dropdown.js    | 84 ++++++++++++++++++++
 7 files changed, 133 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ece4d36c/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index aa8f075..686b28b 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -2637,4 +2637,10 @@ table.table.inner-table {
 
 a.abort-icon:hover {
   text-decoration: none;
-}
\ No newline at end of file
+}
+
+.dropdown {
+  button .selected-item {
+    text-transform: none;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ece4d36c/ambari-web/app/styles/wizard.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/wizard.less b/ambari-web/app/styles/wizard.less
index 579b21b..3855c9a 100644
--- a/ambari-web/app/styles/wizard.less
+++ b/ambari-web/app/styles/wizard.less
@@ -410,6 +410,14 @@
       height: 100px;
       color: #ccc;
     }
+    .dropdown {
+      button .selected-item {
+        width: 95%;
+        margin-right: 5px;
+        float: left;
+        overflow: hidden;
+      }
+    }
   }
 
   label.host-name {

http://git-wip-us.apache.org/repos/asf/ambari/blob/ece4d36c/ambari-web/app/templates/common/assign_master_components.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/assign_master_components.hbs b/ambari-web/app/templates/common/assign_master_components.hbs
index a0a4990..d5eaf75 100644
--- a/ambari-web/app/templates/common/assign_master_components.hbs
+++ b/ambari-web/app/templates/common/assign_master_components.hbs
@@ -89,8 +89,9 @@
                                 {{view App.SelectHostView
                                 componentBinding="this"
                                 disabledBinding="isInstalled"
-                                optionValuePath="content.host_name"
-                                optionLabelPath="content.host_info" }}
+                                contentBinding="content"
+                                optionValuePath="host_name"
+                                optionLabelPath="host_info" }}
                               {{/if}}
                               <span rel="popover" title="Warning" {{bindAttr data-content="warnMessage"}}>
                                 {{#if warnMessage}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ece4d36c/ambari-web/app/templates/common/form/dropdown.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/form/dropdown.hbs b/ambari-web/app/templates/common/form/dropdown.hbs
new file mode 100644
index 0000000..605389a
--- /dev/null
+++ b/ambari-web/app/templates/common/form/dropdown.hbs
@@ -0,0 +1,29 @@
+{{!
+* 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.
+}}
+
+<div class="dropdown">
+  <button {{bindAttr class=":btn :btn-default :dropdown-toggle view.disabled:disabled"}} type="button" data-toggle="dropdown">
+    {{view App.DropdownOptionView optionBinding="view.selection" optionLabelPathBinding="view.optionLabelPath" class="selected-item"}}
+    <span class="caret"></span>
+  </button>
+  <ul class="dropdown-menu">
+    {{#each option in view.content}}
+      <li><a href="#" {{action "selectOption" option target="view"}}>{{view App.DropdownOptionView optionBinding="option" optionLabelPathBinding="view.optionLabelPath"}}</a></li>
+    {{/each}}
+  </ul>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ece4d36c/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 6972d2a..d7df2ac 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -60,6 +60,7 @@ require('views/common/form/field');
 require('views/common/form/datepicker_view');
 require('views/common/form/spinner_input_view');
 require('views/common/form/manage_credentials_form_view');
+require('views/common/form/dropdown');
 require('views/common/quick_view_link_view');
 require('views/common/configs/services_config');
 require('views/common/configs/service_config_container_view');

http://git-wip-us.apache.org/repos/asf/ambari/blob/ece4d36c/ambari-web/app/views/common/assign_master_components_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/assign_master_components_view.js b/ambari-web/app/views/common/assign_master_components_view.js
index 4646cf0..73654c7 100644
--- a/ambari-web/app/views/common/assign_master_components_view.js
+++ b/ambari-web/app/views/common/assign_master_components_view.js
@@ -127,10 +127,7 @@ App.InputHostView = Em.TextField.extend(App.SelectHost, {
 
 });
 
-App.SelectHostView = Em.Select.extend(App.SelectHost, {
-
-  classNames: ['form-control'],
-  attributeBindings: ['disabled'],
+App.SelectHostView = App.DropdownView.extend(App.SelectHost, {
 
   didInsertElement: function () {
     this.initContent();

http://git-wip-us.apache.org/repos/asf/ambari/blob/ece4d36c/ambari-web/app/views/common/form/dropdown.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/form/dropdown.js b/ambari-web/app/views/common/form/dropdown.js
new file mode 100644
index 0000000..2e751b7
--- /dev/null
+++ b/ambari-web/app/views/common/form/dropdown.js
@@ -0,0 +1,84 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.DropdownView = Em.View.extend({
+
+  templateName: require('templates/common/form/dropdown'),
+
+  selection: null,
+
+  value: '',
+
+  optionValuePath: '',
+
+  optionLabelPath: '',
+
+  /**
+   * Used to prevent infinite loop because of cyclic updating of value and selection
+   * @type {Boolean}
+   */
+  isUpdating: false,
+
+  change: Em.K,
+
+  /**
+   * value should be updated after updating selection and vise versa
+   */
+  onValueOrSelectionUpdate: function (context, property) {
+    var selection = this.get('selection');
+    var value = this.get('value');
+    var content = this.get('content');
+    var optionValuePath = this.get('optionValuePath');
+    this.set('isUpdating', true);
+    if (property === 'value') {
+      this.set('selection', optionValuePath ? content.findProperty(optionValuePath, value) : value);
+    } else if (property === 'selection') {
+      this.set('value', Em.getWithDefault(selection, optionValuePath, selection) || '');
+    }
+    this.set('isUpdating', false);
+  }.observes('selection', 'value'),
+
+  selectOption: function (option) {
+    this.set('selection', option.context);
+    this.change();
+  },
+
+  /**
+   * Set default selection
+   */
+  observeEmptySelection: function () {
+    if (this.get('content.length') && !this.get('selection')) this.set('selection', this.get('content')[0]);
+  }.observes('content')
+
+});
+
+App.DropdownOptionView = Em.View.extend({
+
+  template: Em.Handlebars.compile('{{view.optionLabel}}'),
+
+  optionLabel: function () {
+    var optionLabelPath = this.get('optionLabelPath');
+    var option = this.get('option');
+    if (!option) return '';
+    if (optionLabelPath) return Em.get(option, optionLabelPath);
+    return option;
+  }.property('option', 'optionLabelPath')
+
+});


[09/28] ambari git commit: AMBARI-20048. Hive View 2.0: Visual Explain-The operators are being shown out of order. (Abhishek Kumar via pallavkul)

Posted by jo...@apache.org.
AMBARI-20048. Hive View 2.0: Visual Explain-The operators are being shown out of order. (Abhishek Kumar via pallavkul)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/812397d3
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/812397d3
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/812397d3

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 812397d3a054f2be8bb7c7c172bf59255b95a341
Parents: 07342bc
Author: pallavkul <pa...@gmail.com>
Authored: Mon Feb 20 15:56:41 2017 +0530
Committer: pallavkul <pa...@gmail.com>
Committed: Mon Feb 20 15:56:41 2017 +0530

----------------------------------------------------------------------
 .../ui/app/components/visual-explain.js         |  29 +-
 .../src/main/resources/ui/app/styles/app.scss   | 146 ++---
 .../resources/ui/app/utils/hive-explainer.js    | 645 -------------------
 .../ui/app/utils/hive-explainer/enhancer.js     |  37 ++
 .../ui/app/utils/hive-explainer/fallback.js     |  34 +
 .../ui/app/utils/hive-explainer/index.js        |  31 +
 .../ui/app/utils/hive-explainer/processor.js    | 240 +++++++
 .../app/utils/hive-explainer/renderer-force.js  | 325 ++++++++++
 .../ui/app/utils/hive-explainer/renderer.js     | 327 ++++++++++
 .../ui/app/utils/hive-explainer/transformer.js  | 445 +++++++++++++
 .../hive20/src/main/resources/ui/bower.json     |   3 +-
 .../src/main/resources/ui/ember-cli-build.js    |   1 +
 12 files changed, 1519 insertions(+), 744 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/app/components/visual-explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/visual-explain.js b/contrib/views/hive20/src/main/resources/ui/app/components/visual-explain.js
index 6805bb8..2800c09 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/visual-explain.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/visual-explain.js
@@ -33,31 +33,14 @@ export default Ember.Component.extend({
 
   isQueryRunning:false,
 
-  didInsertElement(){
+  didInsertElement() {
     this._super(...arguments);
 
-    const width = '100vw', height = '100vh';
-
-    d3.select('#explain-container').select('svg').remove();
-    const svg = d3.select('#explain-container').append('svg')
-      .attr('width', width)
-      .attr('height', height);
-
-    const container = svg.append('g');
-
-    const zoom =
-      d3.zoom()
-        .scaleExtent([1 / 10, 4])
-        .on('zoom', () => {
-          container.attr('transform', d3.event.transform);
-        });
-
-      svg
-        .call(zoom);
-
     const onRequestDetail = data => this.set('explainDetailData', JSON.stringify( data, null, '  ') );
-
-    explain(JSON.parse(this.get('visualExplainInput')), svg, container, zoom, onRequestDetail);
+    const explainData = JSON.parse(this.get('visualExplainInput'));
+    // if(explainData) {
+      explain(explainData, '#explain-container', onRequestDetail);
+    // }
 
   },
 
@@ -80,7 +63,7 @@ export default Ember.Component.extend({
     closeModal(){
       this.set('showDetailsModal', false);
       this.set('explainDetailData', '');
-      false;
+      return false;
     }
 
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
index a9c91c7..3e89ceb 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
+++ b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
@@ -896,81 +896,6 @@ ul.dropdown-menu {
   }
 }
 
-
-.step {
-  font-family: Roboto;
-  background-color:rgb(255, 255, 255);
-  padding: 8px 10px;
-  border: 1px solid rgb(223, 223, 223);
-  cursor: pointer;
-  &:hover {
-    background-color: rgb(223, 240, 247);
-  }
-
-  body {
-    font-family: Roboto;
-    background-color: rgba(0,0,0,0);
-  }
-}
-.step-sink {
-  body {
-    color: rgb(255, 255, 255);
-  }
-  background-color: rgb(42, 179, 119);
-  padding: 20px;
-}
-.step-sink .step-body {
-  font-weight: lighter;
-  margin-top: 10px;
-}
-
-.step-source {
-  body {
-    color: rgb(255, 255, 255);
-  }
-  background-color: rgb(85, 100, 105);
-}
-
-.step-job,
-.step-vectorization {
-  border: none;
-  background: none;
-  padding: 0;
-}
-
-.step-job body,
-.step-vectorization body {
-  height: 100%;
-  width: 100%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.step__pill {
-  font-size: 12px;
-  border-radius: 25px;
-  padding: 5px 10px;
-  min-width: 60px;
-  color: rgb(255, 255, 255);
-  background-color: rgb(85, 100, 105);
-  text-align: center;
-}
-
-
-.step-caption {
-  font-size: 10px;
-}
-.step-body {
-  font-size: 12px;
-}
-
-.edge {
-  stroke: rgb(83, 100, 106);
-  stroke-width: 2px;
-  fill: none;
-}
-
 #explain-container {
   height: 100%;
   width: 100%;
@@ -1028,3 +953,74 @@ ul.dropdown-menu {
 
 }
 
+
+rect.operator__box {
+
+  fill:rgb(255, 255, 255);
+  stroke:rgb(223, 223, 223);
+  stroke-width: 1;
+
+  &:hover {
+    fill: rgb(223, 240, 247);
+  }
+
+  &.operator__box--TableScan {
+    fill: rgb(85, 100, 105);
+  }
+
+  &.operator__box--Fetch_Operator {
+    fill: rgb(42, 179, 119);
+  }
+}
+
+.operator body {
+  cursor: pointer;
+
+  font-family: Roboto;
+  padding: 8px 10px;
+  background-color: rgba(0,0,0,0);
+}
+
+.operator--Fetch_Operator body {
+  color: rgb(255, 255, 255);
+  padding: 12px;
+}
+
+.operator--Fetch_Operator .operator-body {
+  font-weight: lighter;
+}
+
+.operator--TableScan body {
+  color: rgb(255, 255, 255);
+}
+
+.operator-caption {
+  font-size: 10px;
+}
+
+.operator-body {
+  font-size: 12px;
+}
+.edge--hidden {
+  display: none;
+}
+.edge {
+  stroke: rgb(83, 100, 106);
+  stroke-width: 2px;
+  fill: none;
+}
+
+#explain-container {
+  height: 100%;
+  width: 100%;
+  overflow: auto;
+}
+
+.explain--error {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  min-height: 100px;
+  font-size: 16px;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer.js b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer.js
deleted file mode 100644
index 2b59340..0000000
--- a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer.js
+++ /dev/null
@@ -1,645 +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.
- */
-
-
-export default function render(data, svg, container, zoom, onRequestDetail){
-
-  const steps = createOrder(data).steps;
-  const plans = data['STAGE PLANS'];
-  const stageKey =
-    Object
-      .keys(plans)
-      .find(cStageKey => plans[cStageKey].hasOwnProperty('Fetch Operator'));
-  let rows = 'Unknown';
-  if(stageKey && plans[stageKey]['Fetch Operator']['limit:']) {
-    rows = plans[stageKey]['Fetch Operator']['limit:'];
-  }
-  const root = [{
-    "type": "sink",
-    "sink-type": "table",
-    "sink-label": "Limit",
-    "rows": rows,
-    "children": [{
-      steps: steps
-    }]
-  }];
-  const transformed = getTransformed(root);
-  update(transformed, svg, container, zoom, onRequestDetail);
-}
-
-const RENDER_GROUP = {
-  join: d => `
-    <div style='display:flex;'>
-      <div class='step-meta'>
-        <i class='fa ${getIcon(d.type, d['join-type'])}' aria-hidden='true'></i>
-      </div>
-      <div class='step-body' style='margin-left: 10px;'>
-        <div>${d['join-type'] === 'merge' ? 'Merge' : 'Map'} Join</div>
-        <div><span style='font-weight: lighter;'>Rows:</span> ${abbreviate(d.rows)}</div>
-      </div>
-    </div>
-  `,
-  vectorization: d => '<div class="step__pill">U</div>',
-  job: d => `<div class="step__pill">${d.label.toUpperCase()}</div>`,
-  broadcast: d => `
-    <div style='display:flex;'>
-      <div class='step-meta'>
-        <i class='fa ${getIcon(d.type)}' aria-hidden='true'></i>
-      </div>
-      <div class='step-body' style='margin-left: 10px;'>
-        <div>Broadcast</div>
-        <!--div><span style='font-weight: lighter;'>Rows:</span> ${abbreviate(d.rows)}</div-->
-      </div>
-    </div>
-  `,
-  'partition-sort': d => `
-    <div style='display:flex;'>
-      <div class='step-meta'>
-        <i class='fa ${getIcon(d.type)}' aria-hidden='true'></i>
-      </div>
-      <div class='step-body' style='margin-left: 10px;'>
-        <div>Partition / Sort</div>
-        <div><span style='font-weight: lighter;'>Rows:</span> ${abbreviate(d.rows)}</div>
-      </div>
-    </div>
-  `,
-  sink: d => `
-// TODO
-  `,
-  'group-by': d => `
-    <div style='display:flex;'>
-      <div class='step-meta'>
-        <i class='fa ${getIcon(d.type)}' aria-hidden='true'></i>
-      </div>
-      <div class='step-body' style='margin-left: 10px;'>
-        <div>Group By</div>
-        <div><span style='font-weight: lighter;'>Rows:</span> ${abbreviate(d.rows)}</div>
-      </div>
-    </div>
-  `,
-  select: d => `
-    <div style='display:flex;'>
-      <div class='step-meta'>
-        <i class='fa ${getIcon(d.type)}' aria-hidden='true'></i>
-      </div>
-      <div class='step-body' style='margin-left: 10px;'>
-        <div>Select</div>
-        <div><span style='font-weight: lighter;'>Rows:</span> ${abbreviate(d.rows)}</div>
-      </div>
-    </div>
-  `,
-  source: d => `
-    <div style='display:flex;'>
-      <div class='step-meta'>
-        <i class='fa ${getIcon(d.type, d['source-type'])}' aria-hidden='true'></i>
-      </div>
-      <div class='step-body' style='margin-left: 10px;'>
-        <div>${d.label}</div>
-        <div><span style='font-weight: lighter;'>${d.isPartitioned ? 'Partitioned' : 'Unpartitioned'} | Rows:</span> ${abbreviate(d.rows)}</div>
-      </div>
-    </div>
-  `
-};
-
-function update(data, svg, container, zoom, onRequestDetail) {
-  const steps = container.selectAll('g.step')
-    .data(data)
-    .enter().append('g')
-    .attr('class', 'step');
-  steps
-    .append('foreignObject')
-    .attr('id', d => d.uuid)
-    .attr('class', 'step step-sink')
-    .attr('height', 300)
-    .attr('width', 220)
-    .append('xhtml:body')
-    .style('margin', 0)
-    .html(d => `
-        <div>
-          <div class='step-meta' style='display:flex;'>
-            <i class='fa ${getIcon(d.type, d['sink-type'])}' aria-hidden='true'></i>
-            <div class='step-header' style='margin-left: 10px;'>
-              <div class='step-title'>${d['sink-label']}</div>
-              <div class='step-caption'>${abbreviate(d.rows)} ${d.row === 1 ? 'row' : 'rows'}</div>
-            </div>
-          </div>
-          <div class='step-body'>${d['sink-description'] || ''}</div>
-        </div>
-      `)
-    .on('click', d => onRequestDetail(d));
-  steps
-    .call(recurse);
-  const edges =
-    container.selectAll('p.edge')
-      .data(getEdges(data))
-      .enter().insert('path', ':first-child')
-      .attr('class', 'edge')
-      .attr('d', d => getConnectionPath(d, svg, container));
-  reset(zoom, svg, container);
-
-
-  function recurse(step) {
-    const children =
-      step
-        .selectAll('g.child')
-        .data(d => d.children || []).enter()
-        .append('g')
-        .attr('class', 'child')
-        .style('transform', (d, index) => `translateY(${index * 100}px)`);
-    children.each(function(d) {
-      const child = d3.select(this);
-      const steps =
-        child.selectAll('g.step')
-          .data(d => d.steps || []).enter()
-          .append('g')
-          .attr('class', 'step')
-          .style('transform', (d, index) => `translateX(${250 + index * 150}px)`);
-      steps
-        .append('foreignObject')
-        .attr('id', d => d.uuid)
-        .attr('class', d => `step step-${d.type}`)
-        .classed('step-source', d => d.operator === 'TableScan')
-        .attr('height', 55)
-        .attr('width', d => d.type === 'source' ? 200 : 140)
-        .append('xhtml:body')
-        .style('margin', 0)
-        .html(d => getRenderer(d.type)(d))
-        .on('click', d => onRequestDetail(d));
-      steps.filter(d => Array.isArray(d.children))
-        .call(recurse);
-    });
-  }
-}
-
-function getRenderer(type) {
-  const renderer = RENDER_GROUP[type];
-  if(renderer) {
-    return renderer;
-  }
-
-  if(type === 'stage') {
-    return (d => `
-      <div style='display:flex;'>
-        <div class='step-meta'>
-          <i class='fa ' aria-hidden='true'></i>
-        </div>
-        <div class='step-body' style='margin-left: 10px;'>
-          <div>Stage</div>
-          <!--div><span style='font-weight: lighter;'>Rows:</span> ${abbreviate(getNumberOfRows(d['Statistics:']))}</div-->
-        </div>
-      </div>
-    `);
-  }
-
-  return (d => {
-    const isSource = d.operator === 'TableScan';
-    return (`
-      <div style='display:flex;'>
-        <div class='step-meta'>
-          <i class='fa ${getOperatorIcon(d.operator)}' aria-hidden='true'></i>
-        </div>
-        <div class='step-body' style='margin-left: 10px;'>
-          <div>${isSource ? d['alias:'] : getOperatorLabel(d.operator)}</div>
-          <div><span style='font-weight: lighter;'>Rows:</span> ${abbreviate(getNumberOfRows(d['Statistics:']))}</div>
-        </div>
-      </div>
-    `);
-  });
-}
-function getNumberOfRows(statistics) {
-  const match = statistics.match(/([^\?]*)\Num rows: (\d*)/);
-  return (match.length === 3 && Number.isNaN(Number(match[2])) === false) ? match[2] : 0;
-}
-function getOperatorLabel(operator) {
-  const operatorStr = operator.toString();
-  if(operatorStr.endsWith(' Operator')) {
-    return operatorStr.substring(0, operatorStr.length - ' Operator'.length);
-  }
-  if(operatorStr === 'TableScan') {
-    return 'Scan';
-  }
-  return operatorStr ? operatorStr : 'Unknown';
-}
-function getOperatorIcon(operator) {
-  switch(operator) {
-    case 'File Output Operator':
-      return 'fa-file-o';
-    case 'Reduce Output Operator':
-      return 'fa-compress';
-    case 'Filter Operator':
-      return 'fa-filter';
-    case 'Dynamic Partitioning Event Operator':
-      return 'fa-columns'
-    case 'Map Join Operator':
-      return 'fa-code-fork'
-    case 'Limit':
-    case 'Group By Operator':
-    case 'Select Operator':
-    case 'TableScan':
-      return 'fa-table';
-    default:
-      return '';
-  }
-}
-function getIcon (type, subtype) {
-  switch(type) {
-    case 'join':
-      return 'fa-code-fork'
-    case 'vectorization':
-    case 'job':
-      return;
-    case 'broadcast':
-    case 'partition-sort':
-      return 'fa-compress';
-    case 'source':
-    case 'sink':
-    case 'group-by':
-    case 'select':
-      return 'fa-table';
-  }
-};
-function abbreviate(value) {
-  let newValue = value;
-  if (value >= 1000) {
-    const suffixes = ["", "k", "m", "b","t"];
-    const suffixNum = Math.floor(("" + value).length / 3);
-    let shortValue = '';
-    for (var precision = 2; precision >= 1; precision--) {
-      shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
-      const dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
-      if (dotLessShortValue.length <= 2) { break; }
-    }
-    if (shortValue % 1 != 0) {
-      const  shortNum = shortValue.toFixed(1);
-    }
-    newValue = shortValue+suffixes[suffixNum];
-  }
-  return newValue;
-}
-function reset(zoom, svg, container) {
-  const steps = container.selectAll('g.step');
-  const bounds = [];
-  steps.each(function(d) {
-    const cStep = d3.select(this);
-    const box = cStep.node().getBoundingClientRect();
-    bounds.push(box);
-  });
-  const PADDING_PERCENT = 0.95;
-  const fullWidth = svg.node().clientWidth;
-  const fullHeight = svg.node().clientHeight;
-  const offsetY = svg.node().getBoundingClientRect().top;
-  const top = Math.min(...bounds.map(cBound => cBound.top));
-  const left = Math.min(...bounds.map(cBound => cBound.left));
-  const width = Math.max(...bounds.map(cBound => cBound.right)) - left;
-  const height = Math.max(...bounds.map(cBound => cBound.bottom)) - top;
-  const midX = left + width / 2;
-  const midY = top + height / 2;
-  if (width == 0 || height == 0) return; // nothing to fit
-  const scale = PADDING_PERCENT / Math.max(width / fullWidth, height / fullHeight);
-  const translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];
-  const zoomIdentity =
-    d3.zoomIdentity
-      .translate(translate[0], translate[1] + offsetY)
-      .scale(scale);
-  svg
-    .transition()
-    // .delay(750)
-    .duration(750)
-    // .call( zoom.transform, d3.zoomIdentity.translate(0, 0).scale(1) ); // not in d3 v4
-    .call(zoom.transform, zoomIdentity);
-}
-function getConnectionPath(edge, svg, container) {
-  const steps = container.selectAll('foreignObject.step');
-  const source = container.select(`#${edge.source}`);
-  const target = container.select(`#${edge.target}`);
-  const rSource = source.node().getBoundingClientRect();
-  const rTarget = target.node().getBoundingClientRect();
-  const pSource = {
-    x: (rSource.left + rSource.right) / 2,
-    y: (rSource.top + rSource.bottom) / 2,
-  };
-  const pTarget = {
-    x: (rTarget.left + rTarget.right) / 2,
-    y: (rTarget.top + rTarget.bottom) / 2,
-  };
-  const path = [
-    pSource
-  ];
-  if(pSource.y !== pTarget.y) {
-    path.push({
-      x: (pSource.x + pTarget.x) / 2,
-      y: pSource.y
-    }, {
-      x: (pSource.x + pTarget.x) / 2,
-      y: pTarget.y
-    })
-  }
-  path.push(pTarget);
-  const offsetY = svg.node().getBoundingClientRect().top;
-  return path.reduce((accumulator, cPoint, index) => {
-    if(index === 0) {
-      return accumulator + `M ${cPoint.x}, ${cPoint.y - offsetY}\n`
-    } else {
-      return accumulator + `L ${cPoint.x}, ${cPoint.y - offsetY}\n`
-    }
-  }, '');
-}
-function uuid() {
-  return 'step-xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
-    const r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
-    return v.toString(16);
-  });
-}
-function getEdges(steps) {
-  const edges = [];
-  for (let prev, index = 0; index < steps.length; index++) {
-    const cStep = steps[index];
-    if(prev) {
-      edges.push({
-        source: prev.uuid,
-        target: cStep.uuid
-      });
-    }
-    prev = cStep;
-    if(Array.isArray(cStep.children)) {
-      cStep.children.forEach(cChild => {
-        if(cChild.steps.length === 0) {
-          return;
-        }
-        edges.push({
-          source: cStep.uuid,
-          target: cChild.steps[0].uuid
-        });
-        edges.push(...getEdges(cChild.steps));
-      });
-    }
-  }
-  return edges;
-}
-function getTransformed(steps) {
-  return steps.map(cStep => {
-    let cResStep = cStep;
-    cResStep = Object.assign({}, cResStep, {
-      uuid: uuid()
-    });
-    if(Array.isArray(cResStep.children)) {
-      const children = cResStep.children.map(cChild => Object.assign({}, cChild, {
-        steps: getTransformed(cChild.steps)
-      }));
-      cResStep = Object.assign({}, cResStep, {
-        children: children
-      });
-    }
-    return cResStep;
-  });
-}
-function createOrder(data) {
-  const stageDeps = data['STAGE DEPENDENCIES'];
-  const stagePlans = data['STAGE PLANS'];
-  const stageRootKey = Object.keys(stageDeps).find(cStageKey => stageDeps[cStageKey]['ROOT STAGE'] === 'TRUE');
-  const root = Object.assign({}, getStageData(stageRootKey, stagePlans), {
-    _stages: getDependentStageTreeInOrder(stageRootKey, stageDeps, stagePlans)
-  });
-  const expanded = doExpandChild(root);
-  return doClean(expanded);
-}
-function getDependentStageTreeInOrder(sourceStageKey, stageDeps, stagePlans) {
-  const stageKeys =
-    Object
-      .keys(stageDeps)
-      .filter(cStageKey => stageDeps[cStageKey] && stageDeps[cStageKey]['DEPENDENT STAGES'] === sourceStageKey);
-  const stages =
-    stageKeys.map(cStageKey => Object.assign({}, getStageData(cStageKey, stagePlans), {
-      _stages: getDependentStageTreeInOrder(cStageKey, stageDeps, stagePlans)
-    }));
-  return stages;
-}
-function getStageData(stageKey, stagePlans) {
-  const plan = stagePlans[stageKey];
-  const engineKeys = Object.keys(plan);
-  if(engineKeys.length !== 1) {
-    return plan;
-  }
-  const engineKey = engineKeys[0];
-  // returns a job
-  let step;
-  switch(engineKey) {
-    case 'Map Reduce':
-      step = buildForMR(plan[engineKey]);
-      break;
-    case 'Map Reduce Local Work':
-      step = buildForMRLocal(plan[engineKey]);
-      break;
-    case 'Tez':
-      step = buildForTez(plan[engineKey]);
-      break;
-    case 'Fetch Operator':
-      step = buildForFetch(plan[engineKey]);
-      break;
-    default:
-      step = {
-        type: 'placeholder',
-        _engine: 'not_found',
-        _plan: plan
-      };
-  }
-  return ({
-    steps: [
-      step
-    ]
-  });
-}
-function buildForMR(plan) {
-  return ({
-    type: 'stage',
-    _engine: 'mr',
-    _plan: plan
-  });
-}
-function buildForMRLocal(plan) {
-  return ({
-    type: 'stage',
-    _engine: 'mr-local',
-    _plan: plan
-  });
-}
-function buildForTez(plan) {
-  const edges = plan['Edges:'];
-  const vertices = plan['Vertices:'];
-  const fEdges =
-    Object
-      .keys(edges)
-      .reduce((accumulator, cTargetKey) => {
-        if(Array.isArray(edges[cTargetKey])) {
-          const edgesFromSourceKey = edges[cTargetKey];
-          accumulator.push(...edgesFromSourceKey.map(cEdgeFromSourceKey => ({
-            source: cEdgeFromSourceKey['parent'],
-            target: cTargetKey,
-            type: cEdgeFromSourceKey['type']
-          })));
-        } else {
-          const edgeFromSourceKey = edges[cTargetKey];
-          accumulator.push({
-            source: edgeFromSourceKey['parent'],
-            target: cTargetKey,
-            type: edgeFromSourceKey['type']
-          });
-        }
-        return accumulator;
-      }, []);
-  const rootKey = fEdges.find(cEdge => fEdges.some(iEdge => iEdge.source === cEdge.target) === false).target;
-  return Object.assign({}, doTezBuildTreeFromEdges(rootKey, fEdges, vertices), {
-    _engine: 'tez',
-    _plan: plan
-  });
-}
-function buildForFetch(plan) {
-  return ({
-    type: 'stage',
-    _engine: 'fetch',
-    _plan: plan
-  });
-}
-function doTezBuildTreeFromEdges(parentKey, edges, vertices) {
-  const jobs =
-    Object
-      .keys(vertices)
-      .map(cVertexKey => ({
-        type: 'job',
-        label: cVertexKey,
-        _data: vertices[cVertexKey],
-      }))
-      .reduce((accumulator, cVertex) => Object.assign(accumulator, {
-        [cVertex.label]: cVertex
-      }), {});
-  edges.forEach(cEdge => {
-    const job = jobs[cEdge.target];
-    if(!Array.isArray(job.children)) {
-      job.children = [];
-    }
-    const steps = [];
-    if(cEdge.type === 'BROADCAST_EDGE') {
-      steps.push({
-        type: 'broadcast',
-        _data: jobs[cEdge.target],
-      });
-    }
-    steps.push(jobs[cEdge.source]);
-    job.children.push({
-      steps
-    });
-  });
-  return jobs[parentKey];
-}
-function doExpandChild(node) {
-  return Object.assign({}, node, {
-    steps: node.steps.reduce((accumulator, cStep) => [...accumulator, ...doExpandStep(cStep, 'step')], [])
-  });
-}
-function doExpandStep(node) {
-  switch(node.type) {
-    case 'job':
-      const key = Object.keys(doOmit(node._data, ['Execution mode:']))[0];
-      let root = node._data[key];
-      if(!Array.isArray(root)) {
-        root = [root];
-      }
-      const steps = doGetOperators(root);
-      const children = Array.isArray(node.children) ? node.children.map(cChild => doExpandChild(cChild)) : [];
-      return ([
-        doOmit(node, ['children']),
-        ...steps.reverse().slice(0, steps.length - 1),
-        Object.assign({}, steps[steps.length - 1], {
-          children
-        })
-      ]);
-    default:
-      return [node];
-  }
-}
-function doClean(node) {
-  let cleaned =
-    Object
-      .keys(node)
-      .filter(cNodeKey => cNodeKey.startsWith('_') === false)
-      .reduce((accumulator, cNodeKey) => Object.assign(accumulator, {
-        [cNodeKey]: node[cNodeKey]
-      }), {});
-  if(cleaned.hasOwnProperty('children')) {
-    cleaned = Object.assign({}, cleaned, {
-      children: cleaned.children.map(cChild => doClean(cChild))
-    })
-  }
-  if(cleaned.hasOwnProperty('steps')) {
-    cleaned = Object.assign({}, cleaned, {
-      steps: cleaned.steps.map(cStep => doClean(cStep))
-    })
-  }
-  return cleaned;
-}
-function doGetOperators(node) {
-  let stepx = node;
-  if(!Array.isArray(stepx)) {
-    stepx = [stepx];
-  }
-  const steps =
-    stepx
-      .reduce((accumulator, cStep) => {
-        const key = Object.keys(cStep)[0];
-        const obj = cStep[key];
-        let children = [];
-        if(obj.children) {
-          children = doGetOperators(obj.children);
-        }
-        const filtered =
-          Object
-            .keys(obj)
-            .filter(cKey => cKey !== 'children')
-            .reduce((accumulator, cKey) => {
-              accumulator[cKey] = obj[cKey];
-              return accumulator;
-            }, {});
-        return [
-          ...accumulator,
-          Object.assign({
-            _data: cStep,
-            operator: key
-          }, filtered),
-          ...children
-        ];
-      }, []);
-  return steps;
-}
-function doGetStep(node) {
-  const key = Object.keys(node)[0];
-  const obj = node[key];
-  return {
-    operator: key,
-    _data: obj
-  };
-}
-function doOmit(object, keys) {
-  return Object
-    .keys(object)
-    .filter(cKey => keys.indexOf(cKey) === -1)
-    .reduce((accumulator, cKey) => {
-      accumulator[cKey] = object[cKey];
-      return accumulator;
-    }, {});
-}
-

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/enhancer.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/enhancer.js b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/enhancer.js
new file mode 100644
index 0000000..a99b82e
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/enhancer.js
@@ -0,0 +1,37 @@
+/**
+ * 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.
+ */
+
+export default function doEnhance(vertices) {
+  return vertices.map(cVertex => Object.assign({}, cVertex, {
+    _children: cVertex._children.map(cChild => doEnhanceNode(cChild))
+  }));
+}
+
+function doEnhanceNode(node) {
+  return Object.assign({}, node, {
+    _uuid: uuid(),
+    _children: node._children.map(cChild => doEnhanceNode(cChild))
+  });
+}
+
+function uuid() {
+  return 'operator-xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
+    const r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
+    return v.toString(16);
+  });
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/fallback.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/fallback.js b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/fallback.js
new file mode 100644
index 0000000..2310b3c
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/fallback.js
@@ -0,0 +1,34 @@
+/**
+ * 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.
+ */
+
+export function isExplainable(data) {
+  const stages = data['STAGE PLANS'];
+  const isValidTezStageAvailable = Object.keys(stages).some(cStageKey => stages[cStageKey].hasOwnProperty('Tez'));
+  const isValidFetchStageAvailable = Object.keys(stages).find(cStageKey => stages[cStageKey].hasOwnProperty('Fetch Operator'));
+  return isValidTezStageAvailable && isValidFetchStageAvailable;
+}
+
+export function doRenderError(selector) {
+  d3.select(selector).select('*').remove();
+
+  d3.select(selector)
+    .append('div')
+      .attr('class', 'explain--error')
+      .append('div')
+        .text('No valid Tez plan found.');
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/index.js b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/index.js
new file mode 100644
index 0000000..3513a23
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/index.js
@@ -0,0 +1,31 @@
+/**
+ * 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 doTransform from './transformer';
+import doRender from './renderer';
+import {isExplainable, doRenderError} from './fallback';
+
+
+export default function draw(data, selector, onRequestDetail){
+  if(isExplainable(data)) {
+    const transformed = doTransform(data);
+    doRender(transformed, selector, onRequestDetail);
+  } else {
+    doRenderError(selector);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/processor.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/processor.js b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/processor.js
new file mode 100644
index 0000000..5dbeb2b
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/processor.js
@@ -0,0 +1,240 @@
+/**
+ * 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.
+ */
+
+export function getProcessedVertices(vertices, edges) {
+  const edgedVertices = processEdges(vertices, edges);
+  return processSource(edgedVertices);
+}
+
+function processEdges(vertices, edges) {
+
+  return vertices
+    .map(cVertex => {
+      const isVertexPartOfSimpleEdge = edges.some(cEdge => cEdge.type === 'SIMPLE_EDGE' && cEdge.parent === cVertex._vertex);
+      const isVertexPartOfBroadcastEdge = edges.some(cEdge => cEdge.type === 'BROADCAST_EDGE' && cEdge.parent === cVertex._vertex);
+      const isVertexPartOfCustomSimpleEdge = edges.some(cEdge => cEdge.type === 'CUSTOM_SIMPLE_EDGE' && cEdge.parent === cVertex._vertex);
+      const isVertexPartOfCustomEdge = edges.some(cEdge => cEdge.type === 'CUSTOM_EDGE' && cEdge.parent === cVertex._vertex);
+      const isVertexPartOfXProdEdge = edges.some(cEdge => cEdge.type === 'XPROD_EDGE' && cEdge.parent === cVertex._vertex);
+
+      let tVertex = cVertex;
+
+      if(isVertexPartOfSimpleEdge) {
+        tVertex = appendIfTerminusOfOperator(tVertex, {
+          _operator: 'Partition/Sort Pseudo-Edge'
+        });
+      }
+      if(isVertexPartOfBroadcastEdge) {
+        tVertex = appendIfTerminusOfOperator(tVertex, {
+          _operator: 'Broadcast Pseudo-Edge'
+        });
+      }
+      if(isVertexPartOfCustomSimpleEdge) {
+        tVertex = appendIfTerminusOfOperator(tVertex, {
+          _operator: 'Partition Pseudo-Edge'
+        });
+      }
+      if(isVertexPartOfCustomEdge) {
+        tVertex = appendIfTerminusOfOperator(tVertex, {
+          _operator: 'Co-partition Pseudo-Edge'
+        });
+      }
+      if(isVertexPartOfXProdEdge) {
+        tVertex = appendIfTerminusOfOperator(tVertex, {
+          _operator: 'Cross-product Distribute Pseudo-Edge'
+        });
+      }
+
+      return tVertex;
+    });
+}
+
+function appendIfTerminusOfOperator(node, pseudoNode) {
+  if(Array.isArray(node._children) === false || node._children.length === 0) {
+    // is terminus
+    switch(node._operator) {
+      case 'Reduce Output Operator':
+        return Object.assign({}, node, pseudoNode);
+      default:
+        return node;
+    }
+  }
+
+  return Object.assign({}, node, {
+    _children: node._children.map(cChild => appendIfTerminusOfOperator(cChild, pseudoNode))
+  });
+}
+
+function processSource(vertices) {
+  return vertices.map(cVertex => Object.assign({}, cVertex, {
+    _children: cVertex._children.map(cChild => getProcessedSequenceViaStack(cChild))
+  }));
+}
+
+// DANGER: impure function
+function getProcessedSequenceViaStack(root) {
+  const stack = [];
+
+  let cNode = root;
+  stack.push(cNode);
+  doCompaction(stack);
+  while(cNode._children.length === 1) {
+    cNode = cNode._children[0];
+
+    stack.push(cNode);
+    doCompaction(stack);
+  }
+
+  const lNode = stack[stack.length - 1];
+  if(lNode._children.length > 1) {
+    // begin processing new subtree
+    lNode._children = lNode._children.map(cChild => getProcessedSequenceViaStack(cChild));
+  }
+
+  return stack[0];
+}
+
+function doCompaction(stack) {
+  let index = stack.length;
+
+  while(index > 0) {
+    const cNode = stack[index - 0 - 1];
+    const cNodeMinus1 = stack[index - 1 - 1];
+    const cNodeMinus2 = stack[index - 2 - 1];
+    const cNodeMinus3 = stack[index - 3 - 1];
+    const cNodeMinus4 = stack[index - 4 - 1];
+
+    if(cNodeMinus1) {
+
+      if(cNode._operator === 'Select Operator' || cNode._operator === 'HASHTABLEDUMMY' || cNode._operator === 'File Output Operator') {
+        // remove cNode from stack
+        stack.pop();
+        index--;
+        // recreate groups
+        cNodeMinus1._groups = [
+          ...(cNodeMinus1._groups || [doCloneAndOmit(cNodeMinus1, ['_groups'])]),
+          ...(cNode._groups || [doCloneAndOmit(cNode, ['_groups'])]),
+        ];
+        // move children
+        cNodeMinus1._children = cNode._children;
+
+        continue;
+      }
+      if(cNodeMinus1._operator === 'Select Operator' || cNodeMinus1._operator === 'HASHTABLEDUMMY' || cNodeMinus1._operator === 'File Output Operator') {
+        // remove cNode and cNodeMinus1 from stack
+        stack.pop();
+        index--;
+        stack.pop();
+        index--;
+
+        // recreate groups
+        cNode._groups = [
+          ...(cNodeMinus1._groups || [doCloneAndOmit(cNodeMinus1, ['_groups'])]),
+          ...(cNode._groups || [doCloneAndOmit(cNode, ['_groups'])]),
+        ];
+        // no need to move chldren
+        // reinsert cNode
+        stack.push(cNode);
+        index++;
+
+        continue;
+      }
+
+
+      if(cNode._operator === 'Map Join Operator' && cNodeMinus1._operator === 'Map Join Operator') {
+        // remove cNode from stack
+        stack.pop();
+        index--;
+        // recreate groups
+        cNodeMinus1._groups = [
+          ...(cNodeMinus1._groups || [doCloneAndOmit(cNodeMinus1, ['_groups'])]),
+          ...(cNode._groups || [doCloneAndOmit(cNode, ['_groups'])]),
+        ];
+        // move chldren
+        cNodeMinus1._children = cNode._children;
+
+        continue;
+      }
+
+      if(cNode._operator === 'Filter Operator' && cNodeMinus1._operator === 'TableScan') {
+        // remove cNode from stack
+        stack.pop();
+        index--;
+        // recreate groups
+        cNodeMinus1._groups = [
+          ...(cNodeMinus1._groups || [doCloneAndOmit(cNodeMinus1, ['_groups'])]),
+          ...(cNode._groups || [doCloneAndOmit(cNode, ['_groups'])]),
+        ];
+        // move children
+        cNodeMinus1._children = cNode._children;
+
+        continue;
+      }
+
+      if(cNodeMinus2 && cNodeMinus3) {
+        if(cNode._operator === 'Broadcast Pseudo-Edge' && cNodeMinus1._operator === 'Group By Operator' && cNodeMinus2._operator === 'Reduce Output Operator' && cNodeMinus3._operator === 'Group By Operator') {
+          // remove cNode from stack
+          stack.pop();
+          index--;
+          // remove cNodeMinus1 from stack
+          stack.pop();
+          index--;
+          // remove cNodeMinus2 from stack
+          stack.pop();
+          index--;
+          // remove cNodeMinus3 from stack
+          stack.pop();
+          index--;
+
+          // recreate groups
+          cNodeMinus1._groups = [
+            ...(cNodeMinus3._groups || [doCloneAndOmit(cNodeMinus3, ['_groups'])]),
+            ...(cNodeMinus2._groups || [doCloneAndOmit(cNodeMinus2, ['_groups'])]),
+            ...(cNodeMinus1._groups || [doCloneAndOmit(cNodeMinus1, ['_groups'])]),
+          ];
+          // move children if required, cNodeMinus1 as child of cNodeMinus4
+          if(cNodeMinus4) {
+            cNodeMinus4._children = cNodeMinus2._children;
+          }
+          // rename
+          cNodeMinus1._operator = 'Build Bloom Filter';
+          // add renamed node
+          stack.push(cNodeMinus1);
+          index++;
+          // add original broadcast edge node
+          stack.push(cNode);
+          index++;
+
+
+          continue;
+        }
+      }
+
+    }
+    index--;
+
+  }
+}
+
+function doCloneAndOmit(obj, keys) {
+  return Object
+    .keys(obj)
+    .filter(cObjKey => keys.indexOf(cObjKey) === -1)
+    .reduce((tObj, cObjKey) => Object.assign({}, tObj, {
+      [cObjKey]: obj[cObjKey]
+    }), {});
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer-force.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer-force.js b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer-force.js
new file mode 100644
index 0000000..2dfdc86
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer-force.js
@@ -0,0 +1,325 @@
+/**
+ * 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.
+ */
+
+export default function doRender(data, selector, onRequestDetail) {
+
+  const {connections} = data;
+  const dataNodes = data.nodes;
+  const dataLinks = connections.map(cConnection => ({
+    source: cConnection._target,
+    target: cConnection._source
+  }));
+
+  const width = '960', height = '800';
+
+  d3.select(selector).select('*').remove();
+  const svg =
+    d3.select(selector)
+      .append('svg')
+        .attr('width', width)
+        .attr('height', height);
+
+  const container = svg.append('g');
+  const zoom =
+    d3.behavior.zoom()
+      .scaleExtent([1 / 10, 4])
+      .on('zoom', () => {
+        container.attr('transform', `translate(${d3.event.translate}) scale(${d3.event.scale})`);
+      });
+
+    svg
+      .call(zoom);
+
+  var force = cola.d3adaptor(d3)
+        .avoidOverlaps(true)
+        .flowLayout('x', 150)
+        .convergenceThreshold(1e-3)
+        .size([width, height])
+        .jaccardLinkLengths(150);
+    // .linkDistance(200)
+
+  var links = container.selectAll('path.edge')
+      .data(dataLinks)
+    .enter().append('path')
+      .attr('class', 'edge');
+
+  var nodes = container.selectAll('g.operator-wrapper')
+      .data(dataNodes)
+    .enter().append('g')
+      .attr('class', 'operator-wrapper');
+    // .call(force.drag);
+
+    nodes
+        .append('rect')
+      .attr('id', d => d._uuid)
+      .attr('data-operator', d => d._operator)
+      .attr('class', d => `operator__box operator__box--${d._operator.toString().replace(/[ ]/g, '_')}`)
+      .attr('height', d => d._operator === 'Fetch Operator' ? 150 : 55)
+      .attr('width', 140)
+
+    nodes
+        .append('foreignObject')
+      .attr('data-uuid', d => d._uuid)
+      .attr('data-operator', d => d._operator)
+      .attr('class', d => `operator operator--${d._operator.toString().replace(/[ ]/g, '_')}`)
+      .attr('height', d => d._operator === 'Fetch Operator' ? 150 : 55)
+      .attr('width', 140)
+        .append('xhtml:body')
+      .style('margin', 0)
+        .html(d => getRenderer(d._operator)(d))
+      .on('click', d => onRequestDetail(doClean(d)));
+
+  force
+      .nodes(dataNodes)
+      .links(dataLinks)
+      // .constraints([
+      //   {
+      //     type: 'alignment',
+      //     axis: 'y',
+      //     offsets: dataNodes.map((cNode, index) => ({
+      //       node: index,
+      //       offset: cNode._offsetY
+      //     }))
+      //   }
+      // ])
+      .on('tick', e => {
+        // node.each(function (d) { d.innerBounds = d.bounds.inflate(-margin); })
+        //   .attr("x", function (d) { return d.innerBounds.x; })
+        //   .attr("y", function (d) { return d.innerBounds.y; })
+        //   .attr("width", function (d) {
+        //       return d.innerBounds.width();
+        //   })
+        //   .attr("height", function (d) { return d.innerBounds.height(); });
+
+        // link.attr("d", function (d) {
+        //     var route = cola.makeEdgeBetween(d.source.innerBounds, d.target.innerBounds, 5);
+        //     return lineFunction([route.sourceIntersection, route.arrowStart]);
+        // });
+
+        // const k = 6 * e.alpha;
+
+        // Push sources up and targets down to form a weak tree.
+        links
+            // .each(function(d) { d.source.y -= k, d.target.y += k; })
+            .attr('d', d => getConnectionPath({
+                x: (d.source.bounds.X + d.source.bounds.x) / 2,
+                y: (d.source.bounds.Y + d.source.bounds.y) / 2,
+              }, {
+                x: (d.target.bounds.X + d.target.bounds.x) / 2,
+                y: (d.target.bounds.Y + d.target.bounds.y) / 2,
+              }));
+
+        nodes
+            .attr("transform", d =>  `translate(${d.x}, ${d.y})`);
+
+      })
+      .on('end', () => {
+        reset(zoom, svg, container);
+      })
+      .start();
+}
+
+function getRenderer(type) {
+  if(type === 'Fetch Operator') {
+    return (d => {
+      return (`
+        <div style='display:flex;align-items: center;'>
+          <div class='operator-meta'>
+            <i class='fa ${getOperatorIcon(d._operator)}' aria-hidden='true'></i>
+          </div>
+          <div class='operator-body' style='margin-left: 10px;'>
+            <div>${getOperatorLabel(d)}</div>
+            ${d['limit:'] ? '<div><span style="font-weight: lighter;">Limit:</span> ' + d['limit:'] + ' </div>' : ''}
+          </div>
+        </div>
+      `);
+    });
+  }
+
+  return (d => {
+    const stats = d['Statistics:'] ?  `<div><span style='font-weight: lighter;'>Rows:</span> ${abbreviate(getNumberOfRows(d['Statistics:']))}</div>` : '';
+    return (`
+      <div style='display:flex;'>
+        <div class='operator-meta'>
+          <i class='fa ${getOperatorIcon(d._operator)}' aria-hidden='true'></i>
+        </div>
+        <div class='operator-body' style='margin-left: 10px;'>
+          <div>${getOperatorLabel(d)}</div>
+          ${stats}
+        </div>
+      </div>
+    `);
+  });
+
+}
+
+function getNumberOfRows(statistics) {
+  const match = statistics.match(/([^\?]*)\Num rows: (\d*)/);
+  return (match.length === 3 && Number.isNaN(Number(match[2])) === false) ? match[2] : 0;
+}
+function getOperatorLabel(d) {
+  const operator = d._operator;
+
+  if(operator === 'TableScan') {
+    return d['alias:'];
+  }
+
+  const operatorStr = operator.toString();
+  if(operatorStr.endsWith(' Operator')) {
+    return operatorStr.substring(0, operatorStr.length - ' Operator'.length);
+  }
+  if(operatorStr.endsWith(' Pseudo-Edge')) {
+    return operatorStr.substring(0, operatorStr.length - ' Pseudo-Edge'.length);
+  }
+  return operatorStr ? operatorStr : 'Unknown';
+}
+function getOperatorIcon(operator) {
+  switch(operator) {
+    case 'File Output Operator':
+      return 'fa-file-o';
+    case 'Partition/Sort Pseudo-Edge':
+    case 'Broadcast Pseudo-Edge':
+    case 'Partition Pseudo-Edge':
+    case 'Co-partition Pseudo-Edge':
+    case 'Cross-product Distribute Pseudo-Edge':
+    case 'Reduce Output Operator':
+      return 'fa-compress';
+    case 'Filter Operator':
+      return 'fa-filter';
+    case 'Dynamic Partitioning Event Operator':
+      return 'fa-columns'
+    case 'Map Join Operator':
+      return 'fa-code-fork'
+    case 'Limit':
+    case 'Group By Operator':
+    case 'Select Operator':
+    case 'TableScan':
+    case 'Fetch Operator':
+      return 'fa-table';
+    default:
+      return '';
+  }
+}
+function getIcon (type, subtype) {
+  switch(type) {
+    case 'join':
+      return 'fa-code-fork'
+    case 'vectorization':
+    case 'job':
+      return;
+    case 'broadcast':
+    case 'partition-sort':
+      return 'fa-compress';
+    case 'source':
+    case 'sink':
+    case 'group-by':
+    case 'select':
+      return 'fa-table';
+  }
+};
+function abbreviate(value) {
+  let newValue = value;
+  if (value >= 1000) {
+    const suffixes = ["", "k", "m", "b","t"];
+    const suffixNum = Math.floor(("" + value).length / 3);
+    let shortValue = '';
+    for (var precision = 2; precision >= 1; precision--) {
+      shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
+      const dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
+      if (dotLessShortValue.length <= 2) { break; }
+    }
+    if (shortValue % 1 != 0) {
+      const  shortNum = shortValue.toFixed(1);
+    }
+    newValue = shortValue+suffixes[suffixNum];
+  }
+  return newValue;
+}
+function reset(zoom, svg, container) {
+  const vertices = container.selectAll('g.operator-wrapper');
+  const bounds = [];
+  vertices.each(function(d) {
+    const cVertex = d3.select(this);
+    const box = cVertex.node().getBoundingClientRect();
+    bounds.push(box);
+  });
+  const PADDING_PERCENT = 0.95;
+  const svgRect = svg.node().getBoundingClientRect();
+  const fullWidth = svgRect.width;
+  const fullHeight = svgRect.height;
+  const offsetY = svgRect.top;
+  const top = Math.min(...bounds.map(cBound => cBound.top));
+  const left = Math.min(...bounds.map(cBound => cBound.left));
+  const width = Math.max(...bounds.map(cBound => cBound.right)) - left;
+  const height = Math.max(...bounds.map(cBound => cBound.bottom)) - top;
+  const midX = left + width / 2;
+  const midY = top + height / 2;
+  if (width == 0 || height == 0){
+    // nothing to fit
+    return;
+  }
+  const scale = PADDING_PERCENT / Math.max(width / fullWidth, height / fullHeight);
+  const translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];
+
+  zoom.scale(scale).translate(translate);
+
+  svg
+    .transition()
+    .delay(750)
+    .call(zoom.event);
+}
+
+function getConnectionPath(pSource, pTarget) {
+  const path = [
+    pTarget
+  ];
+  const junctionXMultiplier = (pTarget.x - pSource.x < 0) ? +1 : -1;
+  if(pSource.y !== pTarget.y) {
+    path.push({
+      x: pTarget.x + junctionXMultiplier * 90,
+      y: pTarget.y
+    }, {
+      x: pTarget.x + junctionXMultiplier * 90,
+      y: pSource.y
+    });
+  }
+  path.push(pSource);
+  const offsetY = 0;
+  return path.reduce((accumulator, cPoint, index) => {
+    if(index === 0) {
+      return accumulator + `M ${cPoint.x}, ${cPoint.y - offsetY}\n`
+    } else {
+      return accumulator + `L ${cPoint.x}, ${cPoint.y - offsetY}\n`
+    }
+  }, '');
+}
+
+function doClean(node) {
+  if(Array.isArray(node._groups)) {
+    return node._groups.map(cGroup => doClean(cGroup));
+  } else {
+    return (
+      Object.keys(node)
+        .filter(cNodeKey => cNodeKey !== '_children')
+        .reduce((accumulator, cNodeKey) => {
+          accumulator[cNodeKey] = node[cNodeKey];
+          return accumulator;
+        }, {})
+    );
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer.js b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer.js
new file mode 100644
index 0000000..3dedd8f
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer.js
@@ -0,0 +1,327 @@
+/**
+ * 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.
+ */
+
+export default function doRender(data, selector, onRequestDetail) {
+
+  const width = '100vw', height = '100vh';
+
+  d3.select(selector).select('*').remove();
+  const svg =
+    d3.select(selector)
+      .append('svg')
+        .attr('width', width)
+        .attr('height', height);
+
+  const container = svg.append('g');
+  const zoom =
+    d3.behavior.zoom()
+      .scaleExtent([1 / 10, 4])
+      .on('zoom', () => {
+        container.attr('transform', `translate(${d3.event.translate}) scale(${d3.event.scale})`);
+      });
+
+    svg
+      .call(zoom);
+
+  const root =
+    container
+      .selectAll('g.vertex')
+        .data([data.tree])
+      .enter()
+        .append('g')
+      .attr('class', 'vertex')
+      .attr('data-vertex', d => d._vertex);
+
+  root
+    .call(recurseC, onRequestDetail);
+
+  root
+    .call(recurseV, onRequestDetail);
+
+  container.selectAll('path.edge')
+    .data(data.connections)
+    .enter()
+      .insert('path', ':first-child')
+    .attr('class', 'edge')
+    .attr('d', d => getConnectionPath(d, svg, container));
+
+  reset(zoom, svg, container);
+
+}
+
+function recurseV(vertices, onRequestDetail) {
+  vertices.each(function(cVertx) {
+    const vertex = d3.select(this);
+
+    const vertices =
+      vertex
+        .selectAll('g.vertex')
+          .data(d => d._vertices)
+        .enter()
+          .append('g')
+        .attr('class', 'vertex')
+        .attr('data-vertex', d => d._vertex)
+        .style('transform', d => `translate(${d._widthOfSelf * 200}px, ${d._offsetY * 100}px)`);
+
+      vertices
+        .call(recurseC, onRequestDetail);
+
+      vertices
+        .call(recurseV, onRequestDetail);
+  });
+}
+
+function recurseC(children, onRequestDetail) {
+  children.each(function(d) {
+    const child = d3.select(this);
+
+    const children =
+      child
+          .selectAll('g.child')
+        .data(d => d._children || []).enter()
+          .append('g')
+          .attr('class', 'child')
+          .style('transform', (d, index) => `translate(-${200}px, ${index * 100}px)`);
+
+      children
+          .append('rect')
+        .attr('id', d => d._uuid)
+        .attr('data-operator', d => d._operator)
+        .attr('class', d => `operator__box operator__box--${d._operator.toString().replace(/[ ]/g, '_')}`)
+        .attr('height', d => d._operator === 'Fetch Operator' ? 150 : 55)
+        .attr('width', 140)
+
+      children
+          .append('foreignObject')
+        .attr('data-uuid', d => d._uuid)
+        .attr('data-operator', d => d._operator)
+        .attr('class', d => `operator operator--${d._operator.toString().replace(/[ ]/g, '_')}`)
+        .attr('height', d => d._operator === 'Fetch Operator' ? 150 : 55)
+        .attr('width', 140)
+          .append('xhtml:body')
+        .style('margin', 0)
+          .html(d => getRenderer(d._operator)(d))
+        .on('click', d => onRequestDetail(doClean(d)));
+
+      children
+        .call(recurseC, onRequestDetail);
+    });
+}
+
+function getRenderer(type) {
+  if(type === 'Fetch Operator') {
+    return (d => {
+      return (`
+        <div style='display:flex;align-items: center;'>
+          <div class='operator-meta'>
+            <i class='fa ${getOperatorIcon(d._operator)}' aria-hidden='true'></i>
+          </div>
+          <div class='operator-body' style='margin-left: 10px;'>
+            <div>${getOperatorLabel(d)}</div>
+            ${d['limit:'] ? '<div><span style="font-weight: lighter;">Limit:</span> ' + d['limit:'] + ' </div>' : ''}
+          </div>
+        </div>
+      `);
+    });
+  }
+
+  return (d => {
+    const stats = d['Statistics:'] ?  `<div><span style='font-weight: lighter;'>Rows:</span> ${abbreviate(getNumberOfRows(d['Statistics:']))}</div>` : '';
+    return (`
+      <div style='display:flex;'>
+        <div class='operator-meta'>
+          <i class='fa ${getOperatorIcon(d._operator)}' aria-hidden='true'></i>
+        </div>
+        <div class='operator-body' style='margin-left: 10px;'>
+          <div>${getOperatorLabel(d)}</div>
+          ${stats}
+        </div>
+      </div>
+    `);
+  });
+
+}
+
+function getNumberOfRows(statistics) {
+  const match = statistics.match(/([^\?]*)\Num rows: (\d*)/);
+  return (match.length === 3 && Number.isNaN(Number(match[2])) === false) ? match[2] : 0;
+}
+function getOperatorLabel(d) {
+  const operator = d._operator;
+
+  if(operator === 'TableScan') {
+    return d['alias:'];
+  }
+
+  const operatorStr = operator.toString();
+  if(operatorStr.endsWith(' Operator')) {
+    return operatorStr.substring(0, operatorStr.length - ' Operator'.length);
+  }
+  if(operatorStr.endsWith(' Pseudo-Edge')) {
+    return operatorStr.substring(0, operatorStr.length - ' Pseudo-Edge'.length);
+  }
+  return operatorStr ? operatorStr : 'Unknown';
+}
+function getOperatorIcon(operator) {
+  switch(operator) {
+    case 'File Output Operator':
+      return 'fa-file-o';
+    case 'Partition/Sort Pseudo-Edge':
+    case 'Broadcast Pseudo-Edge':
+    case 'Partition Pseudo-Edge':
+    case 'Co-partition Pseudo-Edge':
+    case 'Cross-product Distribute Pseudo-Edge':
+    case 'Reduce Output Operator':
+      return 'fa-compress';
+    case 'Filter Operator':
+      return 'fa-filter';
+    case 'Dynamic Partitioning Event Operator':
+      return 'fa-columns'
+    case 'Map Join Operator':
+      return 'fa-code-fork'
+    case 'Limit':
+    case 'Group By Operator':
+    case 'Select Operator':
+    case 'TableScan':
+    case 'Fetch Operator':
+      return 'fa-table';
+    default:
+      return '';
+  }
+}
+function getIcon (type, subtype) {
+  switch(type) {
+    case 'join':
+      return 'fa-code-fork'
+    case 'vectorization':
+    case 'job':
+      return;
+    case 'broadcast':
+    case 'partition-sort':
+      return 'fa-compress';
+    case 'source':
+    case 'sink':
+    case 'group-by':
+    case 'select':
+      return 'fa-table';
+  }
+};
+function abbreviate(value) {
+  let newValue = value;
+  if (value >= 1000) {
+    const suffixes = ["", "k", "m", "b","t"];
+    const suffixNum = Math.floor(("" + value).length / 3);
+    let shortValue = '';
+    for (var precision = 2; precision >= 1; precision--) {
+      shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
+      const dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
+      if (dotLessShortValue.length <= 2) { break; }
+    }
+    if (shortValue % 1 != 0) {
+      const  shortNum = shortValue.toFixed(1);
+    }
+    newValue = shortValue+suffixes[suffixNum];
+  }
+  return newValue;
+}
+function reset(zoom, svg, container) {
+  const vertices = container.selectAll('g.vertex');
+  const bounds = [];
+  vertices.each(function(d) {
+    const cVertex = d3.select(this);
+    const box = cVertex.node().getBoundingClientRect();
+    bounds.push(box);
+  });
+  const PADDING_PERCENT = 0.95;
+  const svgRect = svg.node().getBoundingClientRect();
+  const fullWidth = svgRect.width;
+  const fullHeight = svgRect.height;
+  const offsetY = svgRect.top;
+  const top = Math.min(...bounds.map(cBound => cBound.top));
+  const left = Math.min(...bounds.map(cBound => cBound.left));
+  const width = Math.max(...bounds.map(cBound => cBound.right)) - left;
+  const height = Math.max(...bounds.map(cBound => cBound.bottom)) - top;
+  const midX = left + width / 2;
+  const midY = top + height / 2;
+  if (width == 0 || height == 0){
+    // nothing to fit
+    return;
+  }
+  const scale = PADDING_PERCENT / Math.max(width / fullWidth, height / fullHeight);
+  const translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];
+
+  zoom.scale(scale).translate([translate[0], 50]);
+
+  svg
+    .transition()
+    .delay(750)
+    .call( zoom.event );
+}
+
+function getConnectionPath(connector, svg, container) {
+  const operators = container.selectAll('.operator');
+  const source = container.select(`#${connector._source._uuid}`);
+  const target = container.select(`#${connector._target._uuid}`);
+  const rSource = source.node().getBoundingClientRect();
+  const rTarget = target.node().getBoundingClientRect();
+  const pSource = {
+    x: (rSource.left + rSource.right) / 2,
+    y: (rSource.top + rSource.bottom) / 2,
+  };
+  const pTarget = {
+    x: (rTarget.left + rTarget.right) / 2,
+    y: (rTarget.top + rTarget.bottom) / 2,
+  };
+  const path = [
+    pTarget
+  ];
+  const junctionXMultiplier = (pTarget.x - pSource.x < 0) ? +1 : -1;
+  if(pSource.y !== pTarget.y) {
+    path.push({
+      x: pTarget.x + junctionXMultiplier * 90,
+      y: pTarget.y
+    }, {
+      x: pTarget.x + junctionXMultiplier * 90,
+      y: pSource.y
+    });
+  }
+  path.push(pSource);
+  const offsetY = svg.node().getBoundingClientRect().top;
+  return path.reduce((accumulator, cPoint, index) => {
+    if(index === 0) {
+      return accumulator + `M ${cPoint.x}, ${cPoint.y - offsetY}\n`
+    } else {
+      return accumulator + `L ${cPoint.x}, ${cPoint.y - offsetY}\n`
+    }
+  }, '');
+}
+
+function doClean(node) {
+  if(Array.isArray(node._groups)) {
+    return node._groups.map(cGroup => doClean(cGroup));
+  } else {
+    return (
+      Object.keys(node)
+        .filter(cNodeKey => cNodeKey !== '_children')
+        .reduce((accumulator, cNodeKey) => {
+          accumulator[cNodeKey] = node[cNodeKey];
+          return accumulator;
+        }, {})
+    );
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/transformer.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/transformer.js b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/transformer.js
new file mode 100644
index 0000000..70647a8
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/transformer.js
@@ -0,0 +1,445 @@
+/**
+ * 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 doEnhance from './enhancer';
+import {getProcessedVertices} from './processor';
+
+export default function doTransform(data) {
+  const plan = getTezPlan(data);
+  const fetch = getFetchPlan(data);
+
+  const vertices = [
+    ...getVertices(plan),
+    getFetchVertex(fetch)
+  ];
+
+  const tezEdges = getEdges(plan, vertices);
+  const edges = getEdgesWithFetch(tezEdges, vertices);
+
+  const enhancedVertices = doEnhance(vertices);
+
+  const processedVertices = getProcessedVertices(enhancedVertices, edges);
+
+
+  const tree = getVertexTree(edges);
+  const connections = getConnections(processedVertices, edges);
+  const treeWithOffsetY = getTreeWithOffsetAndHeight(tree, processedVertices, connections);
+
+
+  const nodes = getNodes(processedVertices);
+
+  return ({
+    vertices: processedVertices,
+    edges,
+    tree: treeWithOffsetY,
+    nodes,
+    connections,
+  });
+}
+
+function getTezPlan(data) {
+  const stages = data['STAGE PLANS'];
+  const tezStageKey = Object.keys(stages).find(cStageKey => stages[cStageKey].hasOwnProperty('Tez'));
+  return stages[tezStageKey]['Tez'];
+}
+
+function getFetchPlan(data) {
+  const stages = data['STAGE PLANS'];
+  const fetchStageKey = Object.keys(stages).find(cStageKey => stages[cStageKey].hasOwnProperty('Fetch Operator'));
+  return stages[fetchStageKey]['Fetch Operator'];
+}
+
+function getFetchVertex(plan) {
+  return ({
+    _vertex: 'Fetch',
+    _children: [
+      Object.assign({}, plan, {
+        _operator: 'Fetch Operator',
+        _children: []
+      })
+    ]
+  });
+}
+
+function getVertexTree(edges) {
+  const rootKey = edges.find(cEdge => edges.every(tcEdge => cEdge._target !== tcEdge._source))._target;
+  const root = buildTree(rootKey, edges);
+
+  return getPrunedTree(root);
+}
+
+function getPrunedTree(node, used = {}) {
+  const vertices = node._vertices.filter(cVertex => used[cVertex._vertex] !== true);
+  vertices.forEach(cVertex => {
+    used[cVertex._vertex] = true;
+  });
+  return Object.assign({}, node, {
+    _vertices: vertices.map(cVertex => getPrunedTree(cVertex, used))
+  });
+}
+
+function buildTree(vertexKey, edges) {
+  const edgesWithVertexAsSource = edges.filter(cEdge => cEdge._target === vertexKey);
+
+  return Object.assign({
+    _vertex: vertexKey,
+    _vertices: edgesWithVertexAsSource.map(cEdge => buildTree(cEdge._source, edges))
+  });
+}
+
+function getEdgesWithFetch(tezEdges, vertices) {
+  const rootKeys =
+    tezEdges
+      .filter(cEdge => tezEdges.every(tcEdge => cEdge._target !== tcEdge._source))
+      .map(cRootEdge => cRootEdge._target);
+
+  const uniqueRootKeys = [...new Set(rootKeys)]
+
+  const fetchVertex = vertices.find(cVertex => cVertex._vertex === 'Fetch');
+
+  return ([
+    ...tezEdges,
+    ...uniqueRootKeys.map(cRootKey => ({
+      _source: cRootKey,
+      _target: fetchVertex._vertex,
+      parent: cRootKey,
+      type: '_PSEUDO_STAGE_EDGE',
+    }))
+  ]);
+}
+
+function getVertices(plan) {
+  const VERTEX_TREE_KEYS = ['Reduce Operator Tree:', 'Map Operator Tree:'];
+  const vertexObj = plan['Vertices:'];
+
+  const vertices =
+    Object
+      .keys(vertexObj)
+      .map(cVertexKey => {
+        const cVertex = vertexObj[cVertexKey];
+
+        const cTreeKey = VERTEX_TREE_KEYS.find(cVertexTreeKey => cVertex.hasOwnProperty(cVertexTreeKey));
+        let root = [{[cVertexKey]: {}}];
+        if(cTreeKey) {
+          // children available
+          root = cVertex[cTreeKey];
+        }
+        const children = doHarmonize(root);
+
+        return Object.assign({}, doCloneAndOmit(cVertex, VERTEX_TREE_KEYS), {
+          _vertex: cVertexKey,
+          _children: children,
+        });
+      });
+
+  return vertices;
+}
+
+function doHarmonize(nodes) {
+  if(Array.isArray(nodes) === false) {
+    return doHarmonize([ nodes ]);
+  }
+
+  return nodes.map(cNode => {
+    const cNodeOperatorKey = Object.keys(cNode)[0];
+    const cNodeItem = Object.assign({}, cNode[cNodeOperatorKey], {
+      _operator: cNodeOperatorKey
+    });
+
+    if(!cNodeItem.children) {
+      return Object.assign({}, cNodeItem, {
+        _children: []
+      });
+    }
+
+    if(Array.isArray(cNodeItem.children)) {
+      return Object.assign({}, doCloneAndOmit(cNodeItem, ['children']), {
+        _children: doHarmonize(cNodeItem.children)
+      });
+    }
+
+    return Object.assign({}, doCloneAndOmit(cNodeItem, ['children']), {
+      _children: doHarmonize([ cNodeItem.children ])
+    });
+  });
+}
+
+function doGetHeightOfNodes(children) {
+  if(children.length > 0) {
+    return children.reduce((height, cChild) => height + doGetHeightOfNodes(cChild._children), 0);
+  }
+  return 1;
+}
+
+function getTreeWithOffsetAndHeight(node, vertices, connections) {
+  const treeWithCumulativeHeight = getTreeWithCumulativeHeight(node, vertices);
+  const treeWithCumulativeWidth = getTreeWithIndividualWidth(treeWithCumulativeHeight, vertices);
+  const treeWithOffsetY = Object.assign({}, getTreeWithOffsetYInHiererchy(treeWithCumulativeWidth, connections), {
+    _offsetY: 0
+  });
+
+  return treeWithOffsetY;
+}
+
+function doGetWidthOfNodes(children = []) {
+  if(children.length === 0) {
+    return 0;
+  }
+  return 1 + Math.max(0, ...children.map(cChild => doGetWidthOfNodes(cChild._children)));
+}
+
+function getTreeWithCumulativeHeight(node, vertices) {
+  const vertexKey = node._vertex;
+  const vertex = vertices.find(cVertex => cVertex._vertex === vertexKey);
+
+  let _height = doGetHeightOfNodes(vertex._children);
+  let _vertices = [];
+  if(Array.isArray(node._vertices)){
+    _vertices = node._vertices.map(cVertex => getTreeWithCumulativeHeight(cVertex, vertices));
+    _height = Math.max(_height, _vertices.reduce((height, cVertex) => height + cVertex._height, 1));
+  }
+  return Object.assign({}, node, vertex, {
+    _height,
+    _vertices
+  });
+}
+
+function getTreeWithIndividualWidth(node, vertices) {
+  const vertexKey = node._vertex;
+  const vertex = vertices.find(cVertex => cVertex._vertex === vertexKey);
+
+  const _widthOfSelf = doGetWidthOfNodes(vertex._children);
+
+  let _vertices = [];
+  if(Array.isArray(node._vertices) && node._vertices.length > 0){
+    _vertices = node._vertices.map(cVertex => getTreeWithIndividualWidth(cVertex, vertices));
+  }
+  return Object.assign({}, node, vertex, {
+    _widthOfSelf,
+    _vertices
+  });
+}
+
+function getTreeWithOffsetYInHiererchy(node, connections) {
+  const _vertices = [];
+  const source = node._vertices[0] && getLastOperatorOf(node._vertices[0]);
+  const target = getFirstOperatorOf(node);
+  const isFirstConnectedToLast = connections.some(cConnection => source && target && cConnection._source._uuid === source._uuid && cConnection._target._uuid === target._uuid);
+  let offsetY = 0;
+  if(!isFirstConnectedToLast) {
+    // if parent has a connection but not this && offset y are same, add offset
+    offsetY = 1;
+  }
+  for(let index = 0; index < node._vertices.length; index++) {
+    const cNode = node._vertices[index];
+    const height = cNode._height;
+
+    _vertices.push(Object.assign({}, getTreeWithOffsetYInHiererchy(cNode, connections), {
+      _offsetY: offsetY
+    }));
+    offsetY = offsetY + height;
+  }
+
+  return Object.assign({}, node, {
+    _vertices
+  });
+}
+
+function getEdges(plan, vertices) {
+  const edgeObj = plan['Edges:'];
+
+  const edges =
+    Object
+      .keys(edgeObj)
+      .reduce((accumulator, cEdgeKey) => {
+        const cEdge = edgeObj[cEdgeKey];
+
+        if(Array.isArray(cEdge)) {
+          return ([
+            ...accumulator,
+            ...cEdge.map(tcEdge => Object.assign({}, tcEdge, {
+              _source: tcEdge.parent,
+              _target: cEdgeKey,
+            }))
+          ]);
+        } else {
+          return ([
+            ...accumulator,
+            Object.assign({}, cEdge, {
+              _source: cEdge.parent,
+              _target: cEdgeKey,
+            })
+          ]);
+        }
+      }, []);
+
+  const edgesWithFixedUnions =
+    edges
+      .map(cEdge => {
+        if(cEdge.type === 'CONTAINS') {
+          return Object.assign({}, cEdge, {
+            _source: cEdge._target,
+            _target: cEdge._source,
+          });
+        } else {
+          return cEdge;
+        }
+      });
+
+  return edgesWithFixedUnions;
+}
+
+function doCloneAndOmit(obj, keys) {
+  return Object
+    .keys(obj)
+    .filter(cObjKey => keys.indexOf(cObjKey) === -1)
+    .reduce((tObj, cObjKey) => Object.assign({}, tObj, {
+      [cObjKey]: obj[cObjKey]
+    }), {});
+}
+
+function getConnections(vertices, edges) {
+  const connections = [];
+
+  // iterate inside vertices to build connections between children
+  vertices.forEach(cVertex => {
+    cVertex._children.forEach(cChild => {
+      connections.push(...getIntraNodeConnections(cChild));
+    });
+  });
+
+  // iterate over edges to build connections
+  edges.forEach(cEdge => {
+    // get source uuid from source vertex
+    const sourceVertex = vertices.find(cVertex => cVertex._vertex === cEdge._source);
+    const sourceOperator = getLastOperatorOf(sourceVertex);
+    // get target uuid from target vertex
+    const targetVertex = vertices.find(cVertex => cVertex._vertex === cEdge._target);
+    const targetOperator = findVertexAsInputInNode(targetVertex, cEdge._source) || getFirstOperatorOf(targetVertex);
+    // push connection
+    connections.push({
+      _source: sourceOperator,
+      _target: targetOperator,
+    });
+  });
+
+  // iterate over vertices to find dynamic partitioning event operator
+  // - build connection from dpp to tablescan of target vertex
+  vertices.forEach(cVertex => {
+    // recurse over children to find dpp > source
+    const sourceOperators = findOperatorsInNode(cVertex, 'Dynamic Partitioning Event Operator', []);
+    // find first operator of target vertex > target
+    sourceOperators.forEach(cOperator => {
+      const targetVertexKey = cOperator['Target Vertex:'];
+      const targetVertex = vertices.find(cVertex => cVertex._vertex === targetVertexKey);
+
+      const targetOperator = getFirstOperatorOf(targetVertex);
+
+      // push connection
+      connections.push({
+        _source: cOperator,
+        _target: targetOperator,
+      });
+    })
+  });
+
+  return connections;
+}
+
+function findVertexAsInputInNode(node, vertexId) {
+  let isInputPresent = false;
+
+  const inputs = node['input vertices:'];
+  if(inputs) {
+    isInputPresent = Object.keys(inputs).some(cInputKey => inputs[cInputKey] === vertexId);
+  }
+  if(Array.isArray(node._groups)) {
+    isInputPresent = isInputPresent || node._groups.some(cGroupedOperator => {
+      const inputs = cGroupedOperator['input vertices:'];
+      if(inputs) {
+        return Object.keys(inputs).some(cInputKey => inputs[cInputKey] === vertexId);
+      }
+      return false;
+    });
+  }
+
+  if(isInputPresent) {
+    return node;
+  } else {
+    for(let i = 0; i < node._children.length; i++) {
+      const cChild = node._children[i];
+      const operator = findVertexAsInputInNode(cChild, vertexId);
+
+      if(operator) {
+        return operator;
+      }
+    }
+  }
+
+  return false;
+}
+
+function getLastOperatorOf(vertex) {
+  let operator = vertex._children[0];
+  while(operator._children.length > 0) {
+    operator = operator._children[0];
+  }
+  return operator;
+}
+
+function getFirstOperatorOf(vertex) {
+  return vertex._children[0];
+}
+
+function findOperatorsInNode(node, operatorKey, resultsAggregator) {
+  if(node._operator === operatorKey) {
+    return resultsAggregator.push(node);
+  }
+
+  node._children.forEach(cChild => findOperatorsInNode(cChild, operatorKey, resultsAggregator));
+
+  return resultsAggregator;
+}
+
+function getIntraNodeConnections(node) {
+  return node._children.reduce((aggregator, cChild) => {
+    aggregator.push({
+      _source: node,
+      _target: cChild,
+    });
+    aggregator.push(
+      ...getIntraNodeConnections(cChild)
+    );
+    return aggregator;
+  }, []);
+}
+
+function getNodes(vertices) {
+  return vertices.reduce((accumulator, cVertex) => ([
+    ...accumulator,
+    ...getNodesFromChildren(cVertex._children)
+  ]), []);
+}
+
+function getNodesFromChildren(children) {
+  return children.reduce((accumulator, cChild) => ([
+    ...accumulator,
+    cChild,
+    ...getNodesFromChildren(cChild._children)
+  ]), []);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/bower.json
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/bower.json b/contrib/views/hive20/src/main/resources/ui/bower.json
index 9fa7076..2069c88 100644
--- a/contrib/views/hive20/src/main/resources/ui/bower.json
+++ b/contrib/views/hive20/src/main/resources/ui/bower.json
@@ -1,7 +1,8 @@
 {
   "name": "ui",
   "dependencies": {
-    "d3": "~4.5.0",
+    "d3": "~3.5.17",
+    "webcola": "~3.3.2",
     "ember": "~2.7.0",
     "ember-cli-shims": "~0.1.1",
     "ember-qunit-notifications": "0.1.0",

http://git-wip-us.apache.org/repos/asf/ambari/blob/812397d3/contrib/views/hive20/src/main/resources/ui/ember-cli-build.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/ember-cli-build.js b/contrib/views/hive20/src/main/resources/ui/ember-cli-build.js
index d53cdac..c88799a 100644
--- a/contrib/views/hive20/src/main/resources/ui/ember-cli-build.js
+++ b/contrib/views/hive20/src/main/resources/ui/ember-cli-build.js
@@ -54,6 +54,7 @@ module.exports = function(defaults) {
    app.import('bower_components/codemirror/addon/hint/sql-hint.js');
    app.import('bower_components/codemirror/addon/hint/show-hint.js');
    app.import('bower_components/d3/d3.js');
+   app.import('bower_components/webcola/WebCola/cola.min.js');
    app.import('bower_components/codemirror/lib/codemirror.css');
    app.import('bower_components/jquery-ui/jquery-ui.js');
    app.import('bower_components/jquery-ui/themes/base/jquery-ui.css');


[03/28] ambari git commit: AMBARI-20060. update the headroom for llap - hdp stack (Siddharth Seth via smohanty)

Posted by jo...@apache.org.
AMBARI-20060. update the headroom for llap - hdp stack (Siddharth Seth via smohanty)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/bf85ccec
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/bf85ccec
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/bf85ccec

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: bf85ccec17802d26137e2f98e85bd3bfb13ce711
Parents: 7cde24e
Author: Sumit Mohanty <sm...@hortonworks.com>
Authored: Sat Feb 18 23:50:16 2017 -0800
Committer: Sumit Mohanty <sm...@hortonworks.com>
Committed: Sat Feb 18 23:50:16 2017 -0800

----------------------------------------------------------------------
 .../2.5/services/HIVE/configuration/hive-interactive-env.xml   | 2 +-
 .../main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml  | 6 ++++++
 .../stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml         | 6 ++++++
 .../src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml | 1 +
 4 files changed, 14 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/bf85ccec/ambari-server/src/main/resources/stacks/HDP/2.5/services/HIVE/configuration/hive-interactive-env.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/services/HIVE/configuration/hive-interactive-env.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/services/HIVE/configuration/hive-interactive-env.xml
index ef9be76..8f47182 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/services/HIVE/configuration/hive-interactive-env.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/services/HIVE/configuration/hive-interactive-env.xml
@@ -162,7 +162,7 @@
   </property>
   <property>
     <name>llap_headroom_space</name>
-    <value>6144</value>
+    <value>12288</value>
     <description>
       Maximum headroom reserved from the YARN container running LLAP daemons.
       This is an upper limit used during automatic size calculations, and the actual

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf85ccec/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
index 24f3f78..241ca8f 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
@@ -386,6 +386,12 @@
             <regex-replace key="content" find="appender.DRFA.strategy.max = ([0-9]+)" replace-with="appender.DRFA.strategy.max = {{llap_cli_log_maxbackupindex}}"/>
             <replace key="content" find="appender.DRFA.strategy.type = DefaultRolloverStrategy" replace-with="appender.DRFA.strategy.type = DefaultRolloverStrategy&#xA;appender.DRFA.policies.fsize.type = SizeBasedTriggeringPolicy&#xA;appender.DRFA.policies.fsize.size = {{llap_cli_log_maxfilesize}}MB"/>
           </definition>
+
+          <definition xsi:type="configure" id="llap_update_headroom" summary="Update headroom for LLAP">
+            <type>hive-interactive-env</type>
+            <set key="llap_headroom_space" value="12288"/>
+          </definition>
+
         </changes>
 
       </component>

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf85ccec/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
index 5614915..0ef69cb 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
@@ -602,6 +602,12 @@
           <function>wait_for_safemode_off</function>
         </task>
       </execute-stage>
+
+      <execute-stage service="HIVE" component="HIVE_SERVER_INTERACTIVE" title="Update headroom for LLAP">
+        <task xsi:type="configure" id="llap_update_headroom">
+          <summary>Updating the Hive Log4J2 properties to include parameterizations</summary>
+        </task>
+      </execute-stage>
     </group>
 
     <group xsi:type="restart" name="KAFKA" title="Kafka">

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf85ccec/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
index 723a34c..6309bcb 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
@@ -797,6 +797,7 @@
           <task xsi:type="configure" id="webhcat_log4j_parameterize" />
           <task xsi:type="configure" id="hive_log4j2_parameterize"/>
           <task xsi:type="configure" id="llap_cli_log4j2_parameterize"/>
+          <task xsi:type="configure" id="llap_update_headroom"/>
         </pre-upgrade>
         
         <pre-downgrade />


[27/28] ambari git commit: AMBARI-20095. Unique Name not created automatically when designing workflow (Venkat Sairam via pallavkul)

Posted by jo...@apache.org.
AMBARI-20095. Unique Name not created automatically when designing workflow (Venkat Sairam via pallavkul)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/600d0a1a
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/600d0a1a
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/600d0a1a

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 600d0a1a0ff4c2d927296339c05d71ac67cd2332
Parents: ebf81f6
Author: pallavkul <pa...@gmail.com>
Authored: Tue Feb 21 22:26:02 2017 +0530
Committer: pallavkul <pa...@gmail.com>
Committed: Tue Feb 21 22:26:02 2017 +0530

----------------------------------------------------------------------
 .../ui/app/components/flow-designer.js          | 34 ++++++++++++++++++--
 .../main/resources/ui/app/domain/workflow.js    |  7 ++--
 2 files changed, 36 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/600d0a1a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
index 190bb1a..b2b9c68 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
@@ -72,6 +72,7 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
   showActionEditor : false,
   flattenedNodes: [],
   dataNodes: [], /* For cytoscape */
+  counterMap : {},
   hoveredAction: null,
   workflowImporter:WorkflowImporter.create({}),
   actionTypeResolver: ActionTypeResolver.create({}),
@@ -110,7 +111,6 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
     this.sendAction('register', this.get('tabInfo'), this);
     this.set('flowRenderer',CytoscapeRenderer.create());
     this.set('workflow',Workflow.create({}));
-    this.set("isNew",true);
     CommonUtils.setTestContext(this);
   }.on('init'),
   elementsInserted :function(){
@@ -138,6 +138,7 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
           this.set("workflow",draftWorkflow);
           this.rerender();
           this.doValidation();
+          this.generateCounterMap();
         }
       }.bind(this)).catch(function(data){
       });
@@ -239,6 +240,22 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
     this.flowRenderer.initRenderer(function(){
       this.renderWorkflow();
     }.bind(this),{context:this,id : this.get('cyId'),flattenedNodes:this.get("flattenedNodes"),dataNodes:this.get("dataNodes"), cyOverflow:this.get("cyOverflow"),canvasHeight:canvasHeight});
+    this.generateCounterMap();
+  },
+  generateCounterMap() {
+    let len = 0, id = 0, val = null, self = this;
+    this.get('dataNodes').forEach(function(item){
+      if(item.data.node) {
+        if(item.data.node.type === "action") {
+          let keyMap = self.get("counterMap"), type = item.data.node.actionType;
+          if(keyMap.hasOwnProperty(type)){
+            keyMap[type] = parseInt(keyMap[type])+1;
+          } else {
+            keyMap[type] = 1;
+          }
+        }
+      }
+    });
   },
   renderWorkflow(){
     this.set('renderNodeTransitions', true);
@@ -488,6 +505,7 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
     this.get("workflow").resetWorfklow();
     this.set('globalConfig', {});
     this.set('parameters', {});
+    this.set('counterMap', {});
     this.set("undoAvailable", false);
     this.set("showingConfirmationNewWorkflow", false);
     if(this.get('workflow.parameters') !== null){
@@ -758,6 +776,16 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
     this.importWorkflowFromString(dataStr);
     this.send("hideStreamImport");
   },
+  generateUniqueNodeId(type){
+    let keyMap = this.get("counterMap");
+    if(keyMap.hasOwnProperty(type)){
+      keyMap[type] = ++keyMap[type];
+      return keyMap[type];
+    } else {
+      keyMap[type] = 1;
+      return 1;
+    }
+  },
   actions:{
     importWorkflowStream(dataStr){
       this.importWorkflowFromFile(dataStr);
@@ -864,7 +892,9 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
       var currentTransition=this.get("currentTransition.transition");
       var transition = this.get("currentTransition").source.transitions.findBy('targetNode.id',currentTransition.targetNode.id);
       transition.source=this.get("currentTransition").source;
-      this.get("workflow").addNode(transition, type);
+
+      let temp = this.generateUniqueNodeId(type);
+      this.get("workflow").addNode(transition, type, {}, temp);
       this.rerender();
       this.doValidation();
       this.scrollToNewPosition();

http://git-wip-us.apache.org/repos/asf/ambari/blob/600d0a1a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
index a563c20..0fc5d6c 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
@@ -134,18 +134,19 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{
     var generatedNode=this.generatedNode(null,"kill",settings);
     return source.addTransitionTo(generatedNode,"error");
   },
-  addNode(transition,type,settings) {
+  addNode(transition,type,settings, id) {
     var target=transition.targetNode;
     var computedTarget=target;
     if (target && target.isPlaceholder()){
       computedTarget=target.getTargets()[0];
     }
     var generatedNode=this.generatedNode(computedTarget,type,settings);
+    generatedNode.name = generatedNode.name+ "_"+ id;
     var sourceNode=transition.source;
-    if (sourceNode.isPlaceholder()){
+    if (sourceNode && sourceNode.isPlaceholder()) {
       var orignalTransition=this.findTransitionTo(this.startNode,sourceNode.id);
       orignalTransition.targetNode=generatedNode;
-    }else{
+    } else {
       transition.targetNode=generatedNode;
     }
     return generatedNode;


[17/28] ambari git commit: Hive View 2.0: Alter table should not allow setting existing column or new columns as partitioned or clustered. (dipayanb)

Posted by jo...@apache.org.
Hive View 2.0: Alter table should not allow setting existing column or new columns as partitioned or clustered. (dipayanb)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/e585eb6e
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/e585eb6e
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/e585eb6e

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: e585eb6ee1aeff2e391aabae9789a0f85cb76728
Parents: fb01ba5
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Tue Feb 21 13:20:30 2017 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Tue Feb 21 13:21:25 2017 +0530

----------------------------------------------------------------------
 .../main/resources/ui/app/templates/components/column-item.hbs   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/e585eb6e/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
index 21418c1..762c77c 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
@@ -91,14 +91,14 @@
               <div class="col-sm-offset-2 col-sm-10">
                 <div class="checkbox">
                   <label>
-                    {{input type="checkbox" checked=column.isPartitioned disabled=(not column.editing)}} Partitioned
+                    {{input type="checkbox" checked=column.isPartitioned disabled=(or (not column.editing) editMode)}} Partitioned
                   </label>
                 </div>
               </div>
               <div class="col-sm-offset-2 col-sm-10">
                 <div class="checkbox">
                   <label>
-                    {{input type="checkbox" checked=column.isClustered disabled=(not column.editing)}} Clustered
+                    {{input type="checkbox" checked=column.isClustered disabled=(or (not column.editing) editMode)}} Clustered
                   </label>
                 </div>
               </div>


[24/28] ambari git commit: AMBARI-19988: configure Knox proxy for Zeppelin in Ambari out-of-the-box (Prabhjyot Singh via r-kamath)

Posted by jo...@apache.org.
AMBARI-19988: configure Knox proxy for Zeppelin in Ambari out-of-the-box (Prabhjyot Singh via r-kamath)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/f1c96e5d
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f1c96e5d
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f1c96e5d

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: f1c96e5d095580183519afe04e42af6ad8c7c897
Parents: 299b050
Author: Renjith Kamath <re...@gmail.com>
Authored: Tue Feb 21 18:01:36 2017 +0530
Committer: Renjith Kamath <re...@gmail.com>
Committed: Tue Feb 21 18:05:42 2017 +0530

----------------------------------------------------------------------
 .../KNOX/0.5.0.2.2/configuration/gateway-site.xml        |  6 ++++++
 .../KNOX/0.5.0.2.2/package/scripts/params_linux.py       | 11 +++++++++++
 .../HDP/2.6/services/KNOX/configuration/topology.xml     | 10 ++++++++++
 3 files changed, 27 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f1c96e5d/ambari-server/src/main/resources/common-services/KNOX/0.5.0.2.2/configuration/gateway-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/KNOX/0.5.0.2.2/configuration/gateway-site.xml b/ambari-server/src/main/resources/common-services/KNOX/0.5.0.2.2/configuration/gateway-site.xml
index 3837019..ad599e0 100644
--- a/ambari-server/src/main/resources/common-services/KNOX/0.5.0.2.2/configuration/gateway-site.xml
+++ b/ambari-server/src/main/resources/common-services/KNOX/0.5.0.2.2/configuration/gateway-site.xml
@@ -62,4 +62,10 @@ limitations under the License.
     <description>Boolean flag indicating whether to enable debug messages for krb5 authentication</description>
     <on-ambari-upgrade add="true"/>
   </property>
+  <property>
+    <name>gateway.websocket.feature.enabled</name>
+    <value>{{websocket_support}}</value>
+    <description>Enable this if you want websocket support</description>
+    <on-ambari-upgrade add="true"/>
+  </property>
 </configuration>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f1c96e5d/ambari-server/src/main/resources/common-services/KNOX/0.5.0.2.2/package/scripts/params_linux.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/KNOX/0.5.0.2.2/package/scripts/params_linux.py b/ambari-server/src/main/resources/common-services/KNOX/0.5.0.2.2/package/scripts/params_linux.py
index 9b61a5f..8beb2c0 100644
--- a/ambari-server/src/main/resources/common-services/KNOX/0.5.0.2.2/package/scripts/params_linux.py
+++ b/ambari-server/src/main/resources/common-services/KNOX/0.5.0.2.2/package/scripts/params_linux.py
@@ -437,3 +437,14 @@ if "druid-router" in config['configurations']:
   port = config['configurations']['druid-router']['druid.port']
   for host in config['clusterHostInfo']['druid_router_hosts']:
     druid_router_urls += buildUrlElement("http", host, port, "")
+
+zeppelin_ui_urls = ""
+zeppelin_ws_urls = ""
+websocket_support = "false"
+if "zeppelin-config" in config['configurations']:
+  port = config['configurations']['zeppelin-config']['zeppelin.server.port']
+  protocol = "https" if config['configurations']['zeppelin-config']['zeppelin.ssl'] else "http"
+  host = config['clusterHostInfo']['zeppelin_master_hosts'][0]
+  zeppelin_ui_urls += buildUrlElement(protocol, host, port, "")
+  zeppelin_ws_urls += buildUrlElement("ws", host, port, "/ws")
+  websocket_support = "true"

http://git-wip-us.apache.org/repos/asf/ambari/blob/f1c96e5d/ambari-server/src/main/resources/stacks/HDP/2.6/services/KNOX/configuration/topology.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.6/services/KNOX/configuration/topology.xml b/ambari-server/src/main/resources/stacks/HDP/2.6/services/KNOX/configuration/topology.xml
index 6862e4d..df4c1b4 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.6/services/KNOX/configuration/topology.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.6/services/KNOX/configuration/topology.xml
@@ -143,6 +143,16 @@
                 {{druid_broker_urls}}
             &lt;/service&gt;
 
+            &lt;service&gt;
+                &lt;role&gt;ZEPPELINUI&lt;/role&gt;
+                {{zeppelin_ui_urls}}
+            &lt;/service&gt;
+
+            &lt;service&gt;
+                &lt;role&gt;ZEPPELINWS&lt;/role&gt;
+                {{zeppelin_ws_urls}}
+            &lt;/service&gt;
+
         &lt;/topology&gt;
     </value>
     <description>


[04/28] ambari git commit: AMBARI-20075. Fix druid router hosts in config (Nishant Bangarwa via smohanty)

Posted by jo...@apache.org.
AMBARI-20075. Fix druid router hosts in config (Nishant Bangarwa via smohanty)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/c7bd689d
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/c7bd689d
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/c7bd689d

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: c7bd689df4599829fe5e3212fe0baec230a2ddaa
Parents: bf85cce
Author: Sumit Mohanty <sm...@hortonworks.com>
Authored: Sat Feb 18 23:55:18 2017 -0800
Committer: Sumit Mohanty <sm...@hortonworks.com>
Committed: Sat Feb 18 23:56:55 2017 -0800

----------------------------------------------------------------------
 .../common-services/DRUID/0.9.2/package/scripts/params.py          | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/c7bd689d/ambari-server/src/main/resources/common-services/DRUID/0.9.2/package/scripts/params.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/DRUID/0.9.2/package/scripts/params.py b/ambari-server/src/main/resources/common-services/DRUID/0.9.2/package/scripts/params.py
index 61f35b2..c615fac 100644
--- a/ambari-server/src/main/resources/common-services/DRUID/0.9.2/package/scripts/params.py
+++ b/ambari-server/src/main/resources/common-services/DRUID/0.9.2/package/scripts/params.py
@@ -221,7 +221,7 @@ druid_coordinator_hosts = default("/clusterHostInfo/druid_coordinator_hosts", []
 druid_coordinator_host = ""
 if not len(druid_coordinator_hosts) == 0:
   druid_coordinator_host = druid_coordinator_hosts[0]
-druid_router_hosts = default("/clusterHostInfo/druid_coordinator_hosts", [])
+druid_router_hosts = default("/clusterHostInfo/druid_router_hosts", [])
 druid_router_host = ""
 if not len(druid_router_hosts) == 0:
   druid_router_host = druid_router_hosts[0]


[18/28] ambari git commit: AMBARI-20078. When uploading a file using the WFM, need a message to say that either the file upload succeeded or failed. (Padma Priya N via gauravn7)

Posted by jo...@apache.org.
AMBARI-20078. When uploading a file using the WFM, need a message to say that either the file upload succeeded or failed. (Padma Priya N via gauravn7)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/6a3d8fd7
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/6a3d8fd7
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/6a3d8fd7

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 6a3d8fd75f9b5a15f9a27d2c1948e07691d16a98
Parents: e585eb6
Author: Gaurav Nagar <gr...@gmail.com>
Authored: Tue Feb 21 16:04:17 2017 +0530
Committer: Gaurav Nagar <gr...@gmail.com>
Committed: Tue Feb 21 16:06:08 2017 +0530

----------------------------------------------------------------------
 .../src/main/resources/ui/app/components/hdfs-browser.js    | 9 +++++++++
 .../resources/ui/app/templates/components/hdfs-browser.hbs  | 5 +++++
 2 files changed, 14 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6a3d8fd7/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
index 1af9f4d..0194f13 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
@@ -53,6 +53,13 @@ export default Ember.Component.extend({
     this.set("alertDetails",data.details);
     this.set("alertMessage",data.message);
   },
+  isUpdated : function(){
+    if(this.get('showUploadSuccess')){
+      this.$('#success-alert').fadeOut(5000, ()=>{
+        this.set("showUploadSuccess", false);
+      });
+    }
+  }.on('didUpdate'),
   actions: {
     viewerError(error) {
       if (error.responseJSON && error.responseJSON.message && error.responseJSON.message.includes("Permission")) {
@@ -98,6 +105,8 @@ export default Ember.Component.extend({
     },
     uploadSuccess(e){
       this.get('uploaderService').trigger('uploadSuccess');
+      this.set('uploadSelected', false);
+      this.set('showUploadSuccess', true);
     },
     uploadFailure(textStatus,errorThrown){
       this.showNotification({

http://git-wip-us.apache.org/repos/asf/ambari/blob/6a3d8fd7/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
index b8da4a0..44f25c8 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
@@ -51,6 +51,11 @@
         </div>
         <div class="panel-body">
           <div>
+            {{#if showUploadSuccess}}
+              <div id="success-alert"class="alert alert-success alert-dismissible fade in" role="alert">
+                <span>File uploaded</span>
+              </div>
+            {{/if}}
             {{#if alertMessage}}
               <div class="alert alert-{{alertType}} col-xs-24">
                 {{alertMessage}}


[02/28] ambari git commit: AMBARI-20072. Add heap dump option for tez-site config 'tez.am.launch.cmd-opts'.

Posted by jo...@apache.org.
AMBARI-20072. Add heap dump option for tez-site config 'tez.am.launch.cmd-opts'.


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/7cde24ed
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/7cde24ed
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/7cde24ed

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 7cde24ed7eb410073b1e76819c54e600e0e6317f
Parents: f2cb1b6
Author: Swapan Shridhar <ss...@hortonworks.com>
Authored: Fri Feb 17 12:11:49 2017 -0800
Committer: Swapan Shridhar <ss...@hortonworks.com>
Committed: Fri Feb 17 16:35:09 2017 -0800

----------------------------------------------------------------------
 .../main/resources/stacks/HDP/2.3/services/stack_advisor.py  | 2 +-
 .../resources/stacks/HDP/2.5/upgrades/config-upgrade.xml     | 6 +++++-
 .../stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml       | 8 ++++++--
 .../main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml   | 3 ++-
 .../main/resources/stacks/HDP/2.6/services/stack_advisor.py  | 4 +++-
 5 files changed, 17 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/7cde24ed/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py b/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
index 30cbc7c..ee83be7 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
@@ -136,9 +136,9 @@ class HDP23StackAdvisor(HDP22StackAdvisor):
         versionSplits = re.split("\.", match.group(1))
         if versionSplits and len(versionSplits) > 1 and int(versionSplits[0]) > 0 and int(versionSplits[1]) > 7:
           jvmGCParams = "-XX:+UseG1GC -XX:+ResizeTLAB"
-    putTezProperty('tez.am.launch.cmd-opts', "-XX:+PrintGCDetails -verbose:gc -XX:+PrintGCTimeStamps -XX:+UseNUMA " + jvmGCParams)
     # Note: Same calculation is done in 2.6/stack_advisor::recommendTezConfigurations() for 'tez.task.launch.cmd-opts',
     # and along with it, are appended heap dump opts. If something changes here, make sure to change it in 2.6 stack.
+    putTezProperty('tez.am.launch.cmd-opts', "-XX:+PrintGCDetails -verbose:gc -XX:+PrintGCTimeStamps -XX:+UseNUMA " + jvmGCParams)
     putTezProperty('tez.task.launch.cmd-opts', "-XX:+PrintGCDetails -verbose:gc -XX:+PrintGCTimeStamps -XX:+UseNUMA " + jvmGCParams)
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7cde24ed/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
index 7236186..24f3f78 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/config-upgrade.xml
@@ -336,10 +336,14 @@
             <type>hive-env</type>
             <insert key="content" value="export HADOOP_CLIENT_OPTS=&quot;$HADOOP_CLIENT_OPTS{{heap_dump_opts}}&quot;" insert-type="append" newline-before="true" newline-after="true" />
           </definition>
-          <definition xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options">
+          <definition xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options_for_tez_task">
             <type>tez-site</type>
             <insert key="tez.task.launch.cmd-opts" value="{{heap_dump_opts}}" insert-type="append" newline-before="false" newline-after="false" />
           </definition>
+          <definition xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options_for_tez_am">
+            <type>tez-site</type>
+            <insert key="tez.am.launch.cmd-opts" value="{{heap_dump_opts}}" insert-type="append" newline-before="false" newline-after="false" />
+          </definition>
           <definition xsi:type="configure" id="hive_log4j_parameterize" summary="Parameterizing Hive Log4J Properties">
             <type>hive-log4j</type>
             <set key="hive_log_maxfilesize" value="256"/>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7cde24ed/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
index bb9ec1b..5614915 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/nonrolling-upgrade-2.6.xml
@@ -470,8 +470,12 @@
         <task xsi:type="configure" id="hdp_2_6_0_0_hive_append_heap_dump_options"/>
       </execute-stage>
 
-      <execute-stage service="HIVE" component="HIVE_SERVER" title="Appending heap dump options for Tez">
-        <task xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options"/>
+      <execute-stage service="HIVE" component="HIVE_SERVER" title="Appending heap dump options for Tez config 'tez.task.launch.cmd-opts'">
+        <task xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options_for_tez_task"/>
+      </execute-stage>
+
+      <execute-stage service="HIVE" component="HIVE_SERVER" title="Appending heap dump options for Tez config 'tez.am.launch.cmd-opts">
+        <task xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options_for_tez_am"/>
       </execute-stage>
 
       <execute-stage service="HIVE" component="HIVE_SERVER_INTERACTIVE" title="Appending heap dump options for HiveSever2 Interactive">

http://git-wip-us.apache.org/repos/asf/ambari/blob/7cde24ed/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
index 0a02734..723a34c 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/upgrades/upgrade-2.6.xml
@@ -776,7 +776,8 @@
 
       <component name="HIVE_SERVER">
         <pre-upgrade>
-          <task xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options"/>
+          <task xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options_for_tez_task"/>
+          <task xsi:type="configure" id="hdp_2_6_0_0_tez_append_heap_dump_options_for_tez_am"/>
           <task xsi:type="configure" id="hdp_2_6_0_0_hive_append_heap_dump_options"/>
           <task xsi:type="configure" id="hive_log4j_parameterize" />
           <task xsi:type="configure" id="hive_llap_log4j_parameterize" />

http://git-wip-us.apache.org/repos/asf/ambari/blob/7cde24ed/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py b/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
index d8413b6..3dd1bdd 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
@@ -270,8 +270,10 @@ class HDP26StackAdvisor(HDP25StackAdvisor):
     # Append 'jvmGCParams' and 'Heap Dump related option' (({{heap_dump_opts}}) Expanded while writing the
     # configurations at start/restart time).
     tez_jvm_updated_opts = tez_jvm_opts + jvmGCParams + "{{heap_dump_opts}}"
+    putTezProperty('tez.am.launch.cmd-opts', tez_jvm_updated_opts)
     putTezProperty('tez.task.launch.cmd-opts', tez_jvm_updated_opts)
-    Logger.info("Updated 'tez-site' config 'tez.task.launch.cmd-opts' as : {0}".format(tez_jvm_updated_opts))
+    Logger.info("Updated 'tez-site' config 'tez.task.launch.cmd-opts' and 'tez.am.launch.cmd-opts' as "
+                ": {0}".format(tez_jvm_updated_opts))
 
   def recommendRangerConfigurations(self, configurations, clusterData, services, hosts):
     super(HDP26StackAdvisor, self).recommendRangerConfigurations(configurations, clusterData, services, hosts)


[22/28] ambari git commit: AMBARI-20090. On submit of bundle, if any coordinator path contains variables, user should be notified about custom variables.(Padma Priya N via gauravn7)

Posted by jo...@apache.org.
AMBARI-20090. On submit of bundle, if any coordinator path contains variables, user should be notified about custom variables.(Padma Priya N via gauravn7)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/818a6409
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/818a6409
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/818a6409

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 818a64092b6d8fed6d233a2fd6fbda07c5f6800b
Parents: 4719b24
Author: Gaurav Nagar <gr...@gmail.com>
Authored: Tue Feb 21 16:14:05 2017 +0530
Committer: Gaurav Nagar <gr...@gmail.com>
Committed: Tue Feb 21 16:14:40 2017 +0530

----------------------------------------------------------------------
 .../ui/app/components/bundle-config.js          | 14 ++++----
 .../resources/ui/app/components/coord-config.js |  2 +-
 .../ui/app/domain/workflow-xml-generator.js     |  4 ---
 .../app/templates/components/bundle-config.hbs  |  2 +-
 .../ui/app/templates/components/job-config.hbs  | 37 +++++---------------
 5 files changed, 19 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/818a6409/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
index 9201d5c..3ccbc07 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
@@ -42,13 +42,13 @@ const Validations = buildValidations({
 
 export default Ember.Component.extend(Ember.Evented, Validations, {
   bundle : null,
-  errors: Ember.A([]),
   schemaVersions : SchemaVersions.create({}),
   propertyExtractor : Ember.inject.service('property-extractor'),
   fileBrowser : Ember.inject.service('file-browser'),
   workspaceManager : Ember.inject.service('workspace-manager'),
   initialize : function(){
     var self = this;
+    this.set('errors', Ember.A([]));
     this.get('workspaceManager').restoreWorkInProgress(this.get('tabInfo.id')).promise.then(function(draftBundle){
       self.loadBundle(draftBundle);
     }.bind(this)).catch(function(data){
@@ -98,7 +98,7 @@ export default Ember.Component.extend(Ember.Evented, Validations, {
       this.set('bundle.name', Ember.copy(this.get('tabInfo.name')));
     }
     this.schedulePersistWorkInProgress();
-  }, 
+  },
   schedulePersistWorkInProgress (){
     Ember.run.later(function(){
       this.persistWorkInProgress();
@@ -181,7 +181,7 @@ export default Ember.Component.extend(Ember.Evented, Validations, {
       deferred.resolve({data : data, type : type});
     }).fail(function(e){
       console.error(e);
-      deferred.reject();
+      deferred.reject(e);
     });
     return deferred;
   },
@@ -200,7 +200,7 @@ export default Ember.Component.extend(Ember.Evented, Validations, {
       deferred.resolve(data);
     }).fail(function(e){
       console.error(e);
-      deferred.reject();
+      deferred.reject(e);
     });
     return deferred;
   },
@@ -220,6 +220,7 @@ export default Ember.Component.extend(Ember.Evented, Validations, {
       var coordinatorJson = x2js.xml_str2json(coordinatorXml);
       var workflowPath = coordinatorJson['coordinator-app']['action']['workflow']['app-path'];
       if(this.get('propertyExtractor').containsParameters(workflowPath)){
+        this.set('containsParameteriedPaths', true);
         deferred.resolve(Array.from(coordProps.values()));
       }else{
         workflowPath = this.appendFileName(workflowPath, 'wf');
@@ -250,7 +251,7 @@ export default Ember.Component.extend(Ember.Evented, Validations, {
     closeFileBrowser(){
       this.set("showingFileBrowser", false);
       this.get('fileBrowser').getContext().trigger('fileSelected', this.get('filePath'));
-      if(this.get('bundleFilePath')){
+      if(this.get('filePathModel') === 'bundleFilePath'){
         this.importBundle(Ember.copy(this.get('bundleFilePath')));
         this.set('bundleFilePath', null);
       }
@@ -327,6 +328,7 @@ export default Ember.Component.extend(Ember.Evented, Validations, {
       this.$('#loading').show();
       this.get('bundle.coordinators').forEach((coordinator) =>{
         if(this.get('propertyExtractor').containsParameters(coordinator.appPath)){
+          this.set('containsParameteriedPaths', true);
           return;
         }
         var deferred = this.getJobProperties(coordinator.appPath);
@@ -336,7 +338,7 @@ export default Ember.Component.extend(Ember.Evented, Validations, {
         var combinedProps = [];
         var excludedProps = [];
         props.forEach((prop, index)=>{
-          var coordinator = this.get('bundle.coordinators').objectAt(0);
+          var coordinator = this.get('bundle.coordinators').objectAt(index);
           if(coordinator.configuration && coordinator.configuration.property){
             coordinator.configuration.property.forEach((config) => {
               var idx = prop.indexOf('${'+config.name+'}');

http://git-wip-us.apache.org/repos/asf/ambari/blob/818a6409/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
index c7da381..bbd619d 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
@@ -517,7 +517,7 @@ export default Ember.Component.extend(Validations, Ember.Evented, {
     closeFileBrowser(){
       this.set("showingFileBrowser", false);
       this.get('fileBrowser').getContext().trigger('fileSelected', this.get('filePath'));
-      if(this.get('coordinatorFilePath')){
+      if(this.get('filePathModel') === 'coordinatorFilePath'){
         this.importCoordinator(Ember.copy(this.get('coordinatorFilePath')));
         this.set('coordinatorFilePath', null);
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/818a6409/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js
index e30750f..eb8534b 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js
@@ -44,10 +44,6 @@ var WorkflowGenerator= Ember.Object.extend({
     }
     this.get("workflowMapper").handleCredentialsGeneration(this.workflow.credentials,workflowObj["workflow-app"]);
     this.get("workflowMapper").hanldeParametersGeneration(this.workflow.parameters,workflowObj["workflow-app"]);
-    if (!this.ignoreErrors && (!workflowObj["workflow-app"].action || workflowObj["workflow-app"].action.length<1)){
-      this.workflowContext.addError({message : "Miniumum of one action node must exist"});
-      return;
-    }
     var reordered={"workflow-app":{}};
     var srcWorkflowApp=workflowObj["workflow-app"];
     var targetWorkflowApp=reordered["workflow-app"];

http://git-wip-us.apache.org/repos/asf/ambari/blob/818a6409/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-config.hbs
index 749a173..ca58431 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-config.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-config.hbs
@@ -124,7 +124,7 @@
   {{hdfs-browser closeFileBrowser="closeFileBrowser" selectFileCallback=selectFileCallback filePath=filePath}}
 {{/if}}
 {{#if showingJobConfig}}
-  {{job-config type='bundle' closeJobConfigs="closeBundleSubmitConfig" jobFilePath=bundleFilePath openFileBrowser="openFileBrowser" closeFileBrowser="closeFileBrowser" jobConfigs=bundleConfigs}}
+  {{job-config type='bundle' closeJobConfigs="closeBundleSubmitConfig" jobFilePath=bundleFilePath openFileBrowser="openFileBrowser" closeFileBrowser="closeFileBrowser" jobConfigs=bundleConfigs containsParameteriedPaths=containsParameteriedPaths}}
 {{/if}}
 {{#if showingResetConfirmation}}
   {{#confirmation-dialog title="Confirm Bundle Reset"

http://git-wip-us.apache.org/repos/asf/ambari/blob/818a6409/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
index 2ac56e8..0f7fe00 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
@@ -28,33 +28,7 @@
       </div>
       <div class="modal-body">
         {{designer-errors errors=jobConfigs.errors}}
-        {{#if (and (eq type 'bundle') containsParameteriedPaths)}}
-        <div class="panel panel-default">
-          <div class="panel-body">
-            <div class="col-xs-24">
-              <span>The underlying workflow path is templatized.
-                 Please enter the workflow path to deduce the templatized properties in the workflow.
-               </span>
-            </div>
-            {{#each parameterizedPaths as |path index|}}
-            <div class="row form-group">
-              <div class="col-xs-3">
-                <label class="control-label" for="path">Workflow path</label><span class="requiredField">&nbsp;*</span>
-              </div>
-              <div class="col-xs-8">
-                <div class="input-group">
-                  {{input class="form-control" type="text" name=path.name value=path.value}}
-                  <span class="input-group-btn">
-                    <button type="button" class="btn btn-secondary" {{action "selectFile" path.name}}>Browse</button>
-                  </span>
-                </div>
-                {{field-error model=this field='filePath' showErrorMessage=showErrorMessage}}
-              </div>
-            </div>
-            {{/each}}
-          </div>
-        </div>
-        {{else if (and (eq type 'coord') containsParameteriedPaths)}}
+        {{#if (and (eq type 'coord') containsParameteriedPaths)}}
         <div class="col-xs-24">
           <div class="alert alert-warning" role="alert">
             Workflow path contains variables. Please provide the absolute path to auto detect templatized variables. Skip this step if you have configured all the templatized variables of the workflow in the coordinator.
@@ -75,6 +49,13 @@
           </div>
         </div>
         {{else}}
+        {{#if (and (eq type 'bundle') containsParameteriedPaths)}}
+          <div class="col-xs-24">
+            <div class="alert alert-warning" role="alert">
+              <span>Auto detecting variables is not possible as one or more underlying workflow/coordinator path contains variables.  You have to configure the variables in custom job properties/coordinator configuration.</span>
+            </div>
+          </div>
+        {{/if}}
         <div class="panel panel-default">
           <div class="panel-body">
             {{#if alertType}}
@@ -158,7 +139,7 @@
 
       </div>
       <div class="modal-footer">
-        {{#if containsParameteriedPaths}}
+        {{#if (and (eq type 'coord') containsParameteriedPaths)}}
           <button type="button" class="btn btn-default" {{action "skip"}}>Skip</button>
           <button type="button" class="btn btn-primary" {{action "next"}}>Next</button>
         {{else}}


[26/28] ambari git commit: AMBARI-20097. Hive 2: Visual Explain - Remove children in the JSON dump (pallavkul)

Posted by jo...@apache.org.
AMBARI-20097. Hive 2: Visual Explain - Remove children in the JSON dump (pallavkul)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ebf81f6e
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ebf81f6e
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ebf81f6e

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: ebf81f6e7b7113da9af067be6c3ce2960432902a
Parents: 4307f9b
Author: pallavkul <pa...@gmail.com>
Authored: Tue Feb 21 22:13:24 2017 +0530
Committer: pallavkul <pa...@gmail.com>
Committed: Tue Feb 21 22:13:24 2017 +0530

----------------------------------------------------------------------
 .../resources/ui/app/components/visual-explain.js  |  2 ++
 .../main/resources/ui/app/routes/queries/query.js  | 17 +++++++++++++----
 .../src/main/resources/ui/app/styles/app.scss      |  4 ++++
 .../ui/app/templates/components/visual-explain.hbs |  2 +-
 .../resources/ui/app/templates/queries/query.hbs   |  2 +-
 .../ui/app/utils/hive-explainer/renderer.js        |  2 +-
 6 files changed, 22 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ebf81f6e/contrib/views/hive20/src/main/resources/ui/app/components/visual-explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/visual-explain.js b/contrib/views/hive20/src/main/resources/ui/app/components/visual-explain.js
index 2800c09..fc7cf64 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/visual-explain.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/visual-explain.js
@@ -25,6 +25,8 @@ export default Ember.Component.extend({
 
   showDetailsModal: false,
 
+  classNames:['visual-explain-container'],
+
   explainDetailData: '',
 
   visualExplainInput: Ember.computed('visualExplainJson', function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/ebf81f6e/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
index d3768c1..9196d8b 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
@@ -190,8 +190,7 @@ export default Ember.Route.extend(UILoggerMixin, {
     },
 
     visualExplainQuery(){
-      this.get('controller').set('isVisualExplainQuery', true );
-      this.send('executeQuery');
+      this.send('executeQuery', true);
     },
 
     updateQuery(query){
@@ -199,12 +198,19 @@ export default Ember.Route.extend(UILoggerMixin, {
       this.get('controller.model').set('query', query);
     },
 
-    executeQuery(){
+    executeQuery(isVisualExplainQuery){
 
       let self = this;
       this.get('controller').set('currentJobId', null);
 
-      let isVisualExplainQuery = this.get('controller').get('isVisualExplainQuery');
+      if(!Ember.isEmpty(isVisualExplainQuery)){
+        var isVisualExplainQuery = true;
+        this.get('controller').set('isVisualExplainQuery', true);
+      } else {
+        var isVisualExplainQuery = false;
+        this.get('controller').set('isVisualExplainQuery', false);
+      }
+
 
       let queryInput = this.get('controller').get('currentQuery');
 
@@ -260,6 +266,7 @@ export default Ember.Route.extend(UILoggerMixin, {
           .then((status) => {
             self.get('controller').set('isJobSuccess', true);
             self.send('getJobResult', data, payload.title);
+            self.transitionTo('queries.query.loading');
           }, (error) => {
             console.log('error', error);
             self.get('logger').danger('Failed to execute query.', self.extractError(error));
@@ -305,6 +312,8 @@ export default Ember.Route.extend(UILoggerMixin, {
 
         if(isVisualExplainQuery){
           self.send('showVisualExplain', payloadTitle);
+        } else {
+          self.get('controller.model').set('visualExplainJson', null);
         }
 
         if( self.paramsFor('queries.query').worksheetId == payloadTitle){

http://git-wip-us.apache.org/repos/asf/ambari/blob/ebf81f6e/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
index fd1f0eb..5371aa3 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
+++ b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
@@ -821,6 +821,10 @@ ul.dropdown-menu {
   word-break: break-all;
 }
 
+.visual-explain-container{
+  position: relative;
+}
+
 .visual-explain-detail-container {
   width: 500px;
   position: absolute;

http://git-wip-us.apache.org/repos/asf/ambari/blob/ebf81f6e/contrib/views/hive20/src/main/resources/ui/app/templates/components/visual-explain.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/visual-explain.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/visual-explain.hbs
index 905e73c..30f9405 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/visual-explain.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/visual-explain.hbs
@@ -17,7 +17,7 @@
 }}
 
 
-<div style="position: relative;">
+<div>
   <button class="btn btn-default" title="Expand/Collspse" {{action "expandQueryResultPanel" }} style="position: absolute;top: 10px; right: 10px;">{{fa-icon "expand"}}</button>
 </div>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ebf81f6e/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
index d62c781..bf485ca 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/queries/query.hbs
@@ -42,7 +42,7 @@
               {{/each}}
             </ul>
         </div>
-        <button class="btn btn-default" {{action "visualExplainQuery" }}>{{fa-icon "link"}} Visual Explain</button>
+        <button class="btn btn-default" {{action "visualExplainQuery" }} disabled={{ worksheet.isQueryRunning}}>{{fa-icon "link"}} Visual Explain</button>
 
         {{#if worksheet.isQueryRunning}}
           {{fa-icon "spinner fa-1-5" spin=true}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ebf81f6e/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer.js b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer.js
index 3dedd8f..a332802 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/utils/hive-explainer/renderer.js
@@ -317,7 +317,7 @@ function doClean(node) {
   } else {
     return (
       Object.keys(node)
-        .filter(cNodeKey => cNodeKey !== '_children')
+        .filter(cNodeKey => cNodeKey !== '_children' && cNodeKey !== '_uuid')
         .reduce((accumulator, cNodeKey) => {
           accumulator[cNodeKey] = node[cNodeKey];
           return accumulator;


[20/28] ambari git commit: AMBARI-20080. WFM does not issue confirmation message when workflow is suspended or killed.(Padma Priya N via gauravn7)

Posted by jo...@apache.org.
AMBARI-20080. WFM does not issue confirmation message when workflow is suspended or killed.(Padma Priya N via gauravn7)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/6a7d9193
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/6a7d9193
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/6a7d9193

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 6a7d919390310baaa7f3ca92d64cf97bc6eaa7ff
Parents: 74293ed
Author: Gaurav Nagar <gr...@gmail.com>
Authored: Tue Feb 21 16:10:19 2017 +0530
Committer: Gaurav Nagar <gr...@gmail.com>
Committed: Tue Feb 21 16:11:05 2017 +0530

----------------------------------------------------------------------
 .../main/resources/ui/app/components/job-row.js    |  6 ++++++
 .../resources/ui/app/components/search-table.js    | 17 ++++++++++++++++-
 .../ui/app/templates/components/search-table.hbs   | 11 ++++++++---
 3 files changed, 30 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6a7d9193/contrib/views/wfmanager/src/main/resources/ui/app/components/job-row.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/job-row.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/job-row.js
index 1dd580e..2b40392 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/job-row.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/job-row.js
@@ -72,9 +72,15 @@ export default Ember.Component.extend({
         }else if(action === 'kill'){
           this.set('job.status','KILLED');
         }
+        this.sendAction('showMessage', {type:'success', message:`${action.toUpperCase()} action complete. Job is ${this.get('job.status')}`});
       }.bind(this)).catch(function(e){
         this.set('showError', true);
         this.set('showLoader', false);
+        var message = `${action.toUpperCase()} action for could not be completed`;
+        if(this.get('userName') !== this.get('job.user')){
+          message = `${message}. ${this.get('userName')} is not the job owner.`
+        }
+        this.sendAction('showMessage', {type:'error', message:message});
         console.error(e);
       }.bind(this));
       if(action === 'rerun' && this.get('job').bundleJobId){

http://git-wip-us.apache.org/repos/asf/ambari/blob/6a7d9193/contrib/views/wfmanager/src/main/resources/ui/app/components/search-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/search-table.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/search-table.js
index b2f2a57..c8df452 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/search-table.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/search-table.js
@@ -28,15 +28,21 @@ export default Ember.Component.extend({
     var roundedStart = this.get('jobs.start') - this.get('jobs.start') % 10;
     return (roundedStart / this.get('jobs.pageSize'))+1;
   }),
+  userName : Ember.computed.alias('userInfo.userName'),
   rendered : function(){
     this.sendAction('onSearch', this.get('history').getSearchParams());
   }.on('didInsertElement'),
   isUpdated : function(){
     if(this.get('showActionError')){
-      this.$('#alert').fadeOut(2500, ()=>{
+      this.$('#error-alert').fadeOut(5000, ()=>{
         this.set("showActionError", false);
       });
     }
+    if(this.get('showActionSuccess')){
+      this.$('#success-alert').fadeOut(5000, ()=>{
+        this.set("showActionSuccess", false);
+      });
+    }
   }.on('didUpdate'),
   actions: {
     selectAll() {
@@ -131,6 +137,15 @@ export default Ember.Component.extend({
       }else{
         this.set('showBulkAction', false);
       }
+    },
+    showMessage(messageInfo){
+      if(messageInfo.type === 'error'){
+        this.set('showActionError', true);
+        this.set('errorMessage', messageInfo.message);
+      }else{
+        this.set('showActionSuccess', true);
+        this.set('successMessage', messageInfo.message);
+      }
     }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/6a7d9193/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/search-table.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/search-table.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/search-table.hbs
index 5c15493..d28a497 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/search-table.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/search-table.hbs
@@ -16,8 +16,13 @@
 * limitations under the License.
 }}
 {{#if showActionError}}
-<div id="alert"class="alert alert-danger alert-dismissible fade in workflow-error" role="alert">
-  <span>Action could not be completed.</span>
+<div id="error-alert"class="alert alert-danger alert-dismissible fade in workflow-error" role="alert">
+  <span>{{errorMessage}}</span>
+</div>
+{{/if}}
+{{#if showActionSuccess}}
+<div id="success-alert"class="alert alert-success alert-dismissible fade in workflow-error" role="alert">
+  <span>{{successMessage}}. Refresh to see the latest status.</span>
 </div>
 {{/if}}
 <table id="search-table" class="table search-table listing table-striped table-hover table-bordered" cellspacing="0" width="100%">
@@ -54,7 +59,7 @@
   <tbody>
     {{#if jobs.jobs}}
       {{#each jobs.jobs as |job idx|}}
-        {{#job-row job=job onAction="onAction" showJobDetails="showJobDetails" rowSelected="rowSelected" userName=userName showError=showActionError}}{{/job-row}}
+        {{#job-row job=job onAction="onAction" showJobDetails="showJobDetails" rowSelected="rowSelected" userName=userName showMessage="showMessage"}}{{/job-row}}
       {{/each}}
     {{/if}}
   </tbody>


[16/28] ambari git commit: AMBARI-20042. HiveView2.0 : For large datasets, query results overlaps. (dipayanb)

Posted by jo...@apache.org.
AMBARI-20042. HiveView2.0 : For large datasets, query results overlaps. (dipayanb)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/fb01ba54
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/fb01ba54
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/fb01ba54

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: fb01ba548464e87d3d7ec8b45eefc9e7378d4af6
Parents: 60aaaea
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Tue Feb 21 12:57:09 2017 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Tue Feb 21 13:10:54 2017 +0530

----------------------------------------------------------------------
 .../ui/app/components/query-result-table.js     |  22 +++-
 .../resources/ui/app/helpers/extract-value.js   |  27 +++++
 .../resources/ui/app/mixins/table-common.js     |  86 ----------------
 .../resources/ui/app/routes/queries/query.js    |   2 -
 .../src/main/resources/ui/app/styles/app.scss   | 101 ++-----------------
 .../templates/components/query-result-table.hbs |  67 ++++++------
 .../hive20/src/main/resources/ui/package.json   |   1 -
 7 files changed, 91 insertions(+), 215 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/fb01ba54/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js b/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
index ea6dbc9..a2eb349 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/query-result-table.js
@@ -17,8 +17,6 @@
  */
 
 import Ember from 'ember';
-import Table from 'ember-light-table';
-import TableCommon from '../mixins/table-common';
 
 export default Ember.Component.extend({
 
@@ -28,6 +26,15 @@ export default Ember.Component.extend({
 
   queryResult: {'schema' :[], 'rows' :[]},
 
+  columnFilterText: null,
+  columnFilter: null,
+
+  columnFilterDebounced: Ember.observer('columnFilterText', function() {
+    Ember.run.debounce(this, () => {
+      this.set('columnFilter', this.get('columnFilterText'))
+    }, 500);
+  }),
+
   columns: Ember.computed('queryResult', function() {
     let queryResult = this.get('queryResult');
     let columnArr =[];
@@ -61,8 +68,11 @@ export default Ember.Component.extend({
     return rowArr;
   }),
 
-  table: Ember.computed('queryResult', 'rows', 'columns', function() {
-    return new Table(this.get('columns'), this.get('rows'));
+  filteredColumns: Ember.computed('columns', 'columnFilter', function() {
+    if (!Ember.isEmpty(this.get('columnFilter'))) {
+      return this.get('columns').filter((item) => item.label.indexOf(this.get('columnFilter')) > -1 );
+    }
+    return this.get('columns');
   }),
 
   showSaveHdfsModal:false,
@@ -130,6 +140,10 @@ export default Ember.Component.extend({
 
     showVisualExplain(){
       this.sendAction('showVisualExplain');
+    },
+
+    clearColumnsFilter() {
+      this.set('columnFilterText');
     }
 
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb01ba54/contrib/views/hive20/src/main/resources/ui/app/helpers/extract-value.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/helpers/extract-value.js b/contrib/views/hive20/src/main/resources/ui/app/helpers/extract-value.js
new file mode 100644
index 0000000..76b3dee
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/helpers/extract-value.js
@@ -0,0 +1,27 @@
+/**
+ * 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';
+
+export function extractValue(params,/*, hash*/) {
+  let map = params[0];
+  let key = params[1];
+  return map[key];
+}
+
+export default Ember.Helper.helper(extractValue);

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb01ba54/contrib/views/hive20/src/main/resources/ui/app/mixins/table-common.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/mixins/table-common.js b/contrib/views/hive20/src/main/resources/ui/app/mixins/table-common.js
deleted file mode 100644
index 4a2f517..0000000
--- a/contrib/views/hive20/src/main/resources/ui/app/mixins/table-common.js
+++ /dev/null
@@ -1,86 +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 Table from 'ember-light-table';
-
-const {
-  inject,
-  isEmpty
-  } = Ember;
-
-export default Ember.Mixin.create({
-  store: inject.service(),
-
-  page: 0,
-  limit: 10,
-  dir: 'asc',
-  sort: 'firstName',
-
-  isLoading: false,
-  canLoadMore: true,
-
-  model: null,
-  columns: null,
-  table: null,
-
-  init() {
-    this._super(...arguments);
-
-    let table = new Table(this.get('columns'), this.get('model'), { enableSync: true });
-    let sortColumn = table.get('allColumns').findBy('valuePath', this.get('sort'));
-
-    // Setup initial sort column
-    if (sortColumn) {
-      sortColumn.set('sorted', true);
-    }
-
-    this.set('table', table);
-  },
-
-  fetchRecords() {
-    this.set('isLoading', true);
-    this.get('store').query('user', this.getProperties(['page', 'limit', 'sort', 'dir'])).then((records) => {
-      this.get('model').pushObjects(records.toArray());
-      this.set('canLoadMore', !isEmpty(records));
-    }).finally(() => {
-      this.set('isLoading', false);
-    });
-  },
-
-  actions: {
-    onScrolledToBottom() {
-      if (this.get('canLoadMore')) {
-        this.incrementProperty('page');
-        this.fetchRecords();
-      }
-    },
-
-    onColumnClick(column) {
-      if (column.sorted) {
-        this.setProperties({
-          dir: column.ascending ? 'asc' : 'desc',
-          sort: column.get('valuePath'),
-          canLoadMore: true,
-          page: 0
-        });
-        this.get('model').clear();
-      }
-    }
-  }
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb01ba54/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
index 04bb1da..d3768c1 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/queries/query.js
@@ -410,8 +410,6 @@ export default Ember.Route.extend(UILoggerMixin, {
       Ember.run.later(() => {
         this.transitionTo('queries.query.results', myWs);
       }, 1 * 1000);
-
-
     },
 
     openWorksheetModal(){

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb01ba54/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
index 3e89ceb..fd1f0eb 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
+++ b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
@@ -325,6 +325,14 @@ pre {
   padding-top:10px;
 }
 
+.query-result {
+  .table {
+    margin-top: 10px;
+    display: inline-block;
+    overflow: auto;
+  }
+}
+
 .database-panel{
 
   .panel-heading {
@@ -438,103 +446,10 @@ pre {
     }
   }
 
-  .ember-light-table {
-    width: 100%;
-    margin: 0 auto;
-    border-collapse: collapse;
-    height: 65vh; //This can be controlled from the hbs also.
-  }
-
   .full-vw-height{
     height: 100vh;
   }
 
-  .ember-light-table .multi-select {
-    -webkit-touch-callout: none;
-    -webkit-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    user-select: none
-  }
-
-  .ember-light-table tfoot .lt-column {
-    border-top: 1px solid #DADADA
-  }
-
-  .ember-light-table thead .lt-column {
-    border-bottom: 1px solid #DADADA
-  }
-
-  .ember-light-table tfoot th.is-dragging,
-  .ember-light-table thead th.is-dragging {
-    opacity: .75;
-    background: #eee
-  }
-
-  .ember-light-table tfoot th.is-drag-target.drag-right,
-  .ember-light-table thead th.is-drag-target.drag-right {
-    border-right: 1px dotted #DADADA
-  }
-
-  .ember-light-table tfoot th.is-drag-target.drag-left,
-  .ember-light-table thead th.is-drag-target.drag-left {
-    border-left: 1px dotted #DADADA
-  }
-
-  .ember-light-table .lt-column {
-    font-weight: 200;
-    font-size: 12px;
-    padding: 10px
-  }
-
-  .ember-light-table .lt-column .lt-sort-icon {
-    width: 15px
-  }
-
-  .ember-light-table .lt-column.lt-group-column {
-    border: none!important;
-    padding-bottom: 10px
-  }
-
-  .ember-light-table .lt-column .lt-column-resizer {
-    border-right: 1px dashed #ccc;
-    border-left: 1px dashed #ccc
-  }
-
-  .ember-light-table .lt-row {
-    height: 50px
-  }
-
-  .ember-light-table .lt-row.is-selected {
-    background-color: #DEDEDE!important
-  }
-
-  .ember-light-table .lt-row:not(.is-selected):hover {
-    background-color: #F5F4F4!important
-  }
-
-  .ember-light-table .lt-row:last-of-type td {
-    border-bottom-width: 0
-  }
-
-  .ember-light-table .lt-row.lt-expanded-row:hover,
-  .ember-light-table .lt-row.lt-no-data:hover {
-    background-color: transparent!important
-  }
-
-  .ember-light-table .lt-row.lt-expanded-row td,
-  .ember-light-table .lt-row.lt-no-data td {
-    padding: 15px
-  }
-
-  .ember-light-table .lt-row td {
-    border-color: #DADADA;
-    border-width: 0 0 1px;
-    border-style: solid;
-    font-size: 13px;
-    padding: 0 10px
-  }
-
   tfoot tr>td {
     border-top: 1px solid #DADADA;
     padding: 10px 10px 0;

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb01ba54/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
index 2590796..395987f 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/query-result-table.hbs
@@ -16,8 +16,17 @@
 * limitations under the License.
 }}
 
-  <div class="clearfix" style="text-align: right; padding-right:5px">
-    <span class="dropdown">
+  <div class="clearfix">
+    <div class="col-md-2">
+      <div class="row input-group">
+        {{input type="text" value=columnFilterText placeholder="Filter columns" class="form-control"}}
+        <span class="input-group-btn">
+          <button class="btn btn-default" {{action "clearColumnsFilter"}}>{{fa-icon "times"}} </button>
+        </span>
+      </div>
+    </div>
+    <div class="pull-right">
+      <span class="dropdown">
       <button class="btn btn-default dropdown-toggle" title="Actions" data-toggle="dropdown">{{fa-icon "bars"}} </button>
       <ul class="dropdown-menu dropdown-menu-right">
         <li><a href="#" {{action "openSaveHdfsModal" }} class="text-uppercase">{{fa-icon "save"}} Save To HDFS</a></li>
@@ -25,35 +34,35 @@
       </ul>
     </span>&nbsp;
 
-    <button class="btn btn-default" title="Previous Page" {{action "goPrevPage" payloadTitle }} disabled={{not hasPrevious}} >{{fa-icon "arrow-left"}} </button>
-    <button class="btn btn-default" title="Next Page" {{action "goNextPage" payloadTitle}} disabled={{not hasNext}} >{{fa-icon "arrow-right"}} </button> &nbsp;
-    <button class="btn btn-default" title="Expand/Collspse" {{action "expandQueryResultPanel" }}>{{fa-icon "expand"}}</button>
-
+      <button class="btn btn-default" title="Previous Page" {{action "goPrevPage" payloadTitle }} disabled={{not hasPrevious}} >{{fa-icon "arrow-left"}} </button>
+      <button class="btn btn-default" title="Next Page" {{action "goNextPage" payloadTitle}} disabled={{not hasNext}} >{{fa-icon "arrow-right"}} </button> &nbsp;
+      <button class="btn btn-default" title="Expand/Collspse" {{action "expandQueryResultPanel" }}>{{fa-icon "expand"}}</button>
+    </div>
   </div>
 
-  <div class="clearfix">
-    {{#light-table table height='70vh' as |t|}}
-      {{#if columns.length}}
-        {{t.head
-        onColumnClick=(action 'onColumnClick')
-        iconAscending='fa fa-sort-asc'
-        iconDescending='fa fa-sort-desc'
-        fixed=true
-        }}
-
-        {{#t.body
-        canSelect=false
-        onScrolledToBottom=(action 'onScrolledToBottom')
-        as |body|
-        }}
-          {{#if isLoading}}
-            {{#body.loader}}
-              {{table-loader}}
-            {{/body.loader}}
-          {{/if}}
-        {{/t.body}}
-      {{/if}}
-    {{/light-table}}
+  <div class="col-md-12">
+    <div class="row">
+      <div class="query-result">
+        <table class="table table-striped">
+          <thead>
+            <tr>
+              {{#each filteredColumns as |column|}}
+                <th>{{column.label}}</th>
+              {{/each}}
+            </tr>
+          </thead>
+          <tbody>
+          {{#each rows as |row|}}
+            <tr>
+              {{#each filteredColumns as |column|}}
+                <td>{{extract-value row column.valuePath}}</td>
+              {{/each}}
+            </tr>
+          {{/each}}
+          </tbody>
+        </table>
+      </div>
+    </div>
   </div>
 
 {{#if showSaveHdfsModal}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb01ba54/contrib/views/hive20/src/main/resources/ui/package.json
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/package.json b/contrib/views/hive20/src/main/resources/ui/package.json
index a066bfd..5c0da36 100644
--- a/contrib/views/hive20/src/main/resources/ui/package.json
+++ b/contrib/views/hive20/src/main/resources/ui/package.json
@@ -48,7 +48,6 @@
     "ember-export-application-global": "^1.0.5",
     "ember-font-awesome": "2.2.0",
     "ember-i18n": "4.5.0",
-    "ember-light-table": "1.8.0",
     "ember-load-initializers": "^0.5.1",
     "ember-modal-dialog": "0.9.0",
     "ember-moment": "7.2.0",


[08/28] ambari git commit: AMBARI-20077. Server Error when trying to save and not overwrite. (Madhan Mohan Reddy via gauravn7)

Posted by jo...@apache.org.
AMBARI-20077. Server Error when trying to save and not overwrite. (Madhan Mohan Reddy via gauravn7)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/07342bc6
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/07342bc6
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/07342bc6

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 07342bc6e4a0e9ba2b2f850f5d8cbf38a948b50c
Parents: ac4f3d1
Author: Gaurav Nagar <gr...@gmail.com>
Authored: Mon Feb 20 15:40:41 2017 +0530
Committer: Gaurav Nagar <gr...@gmail.com>
Committed: Mon Feb 20 15:40:41 2017 +0530

----------------------------------------------------------------------
 .../ambari/view/OozieProxyImpersonator.java     | 192 ++++++++++---------
 .../apache/oozie/ambari/view/OozieUtils.java    |  18 ++
 .../org/apache/oozie/ambari/view/Utils.java     |  14 +-
 .../oozie/ambari/view/WorkflowFilesService.java |  22 ++-
 .../workflowmanager/WorkflowManagerService.java |   6 +-
 .../WorkflowsManagerResource.java               |   7 +-
 .../view/workflowmanager/WorkflowsRepo.java     |  40 +++-
 .../ui/app/components/bundle-config.js          |   4 +-
 .../resources/ui/app/components/coord-config.js |   4 +-
 .../ui/app/components/flow-designer.js          |  32 +---
 .../main/resources/ui/app/components/save-wf.js |  11 +-
 .../main/resources/ui/app/domain/workflow.js    |   1 +
 12 files changed, 213 insertions(+), 138 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
index a119a7e..6603a9c 100644
--- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
@@ -36,7 +36,6 @@ import javax.ws.rs.HttpMethod;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
@@ -68,26 +67,30 @@ import com.google.inject.Singleton;
 public class OozieProxyImpersonator {
   private final static Logger LOGGER = LoggerFactory
     .getLogger(OozieProxyImpersonator.class);
+  private static final boolean PROJ_MANAGER_ENABLED = true;
+  public static final String RESPONSE_TYPE = "response-type";
+  public static final String OLDER_FORMAT_DRAFT_INGORED = "olderFormatDraftIngored";
 
-  private ViewContext viewContext;
+  private final ViewContext viewContext;
   private final Utils utils = new Utils();
 
 
   private final HDFSFileUtils hdfsFileUtils;
   private final WorkflowFilesService workflowFilesService;
   private WorkflowManagerService workflowManagerService;
-  private static final boolean PROJ_MANAGER_ENABLED = true;
+
   private final OozieDelegate oozieDelegate;
   private final OozieUtils oozieUtils = new OozieUtils();
   private final AssetResource assetResource;
-  private  final AmbariIOUtil ambariIOUtil;
-  private static enum ErrorCodes {
+
+  private enum ErrorCodes {
     OOZIE_SUBMIT_ERROR("error.oozie.submit", "Oozie Submit error"), OOZIE_IO_ERROR(
       "error.oozie.io", "Oozie I/O error"), FILE_ACCESS_ACL_ERROR(
       "error.file.access.control",
       "Access Error to file due to access control"), FILE_ACCESS_UNKNOWN_ERROR(
       "error.file.access", "Error accessing file"), WORKFLOW_PATH_EXISTS(
-      "error.workflow.path.exists", "Worfklow path exists");
+      "error.workflow.path.exists", "Workflow Path exists"), WORKFLOW_XML_DOES_NOT_EXIST(
+      "error.workflow.xml.not.exists", "Workflow Xml does not exist");
     private String errorCode;
     private String description;
 
@@ -104,7 +107,18 @@ public class OozieProxyImpersonator {
       return description;
     }
   }
+  private static enum WorkflowFormat{
+    XML("xml"),
+    DRAFT("draft");
+    String value;
+    WorkflowFormat(String value) {
+      this.value=value;
+    }
 
+    public String getValue() {
+      return value;
+    }
+  }
   @Inject
   public OozieProxyImpersonator(ViewContext viewContext) {
     this.viewContext = viewContext;
@@ -115,7 +129,6 @@ public class OozieProxyImpersonator {
     if (PROJ_MANAGER_ENABLED) {
       workflowManagerService = new WorkflowManagerService(viewContext);
     }
-    ambariIOUtil=new AmbariIOUtil(viewContext);
 
     LOGGER.info(String.format(
       "OozieProxyImpersonator initialized for instance: %s",
@@ -158,6 +171,16 @@ public class OozieProxyImpersonator {
     return Response.ok(viewContext.getUsername()).build();
   }
 
+  @GET
+  @Path("/getWorkflowManagerConfigs")
+  public Response getWorkflowConfigs() {
+    HashMap<String, String> workflowConfigs = new HashMap<String, String>();
+    workflowConfigs.put("nameNode", viewContext.getProperties().get("webhdfs.url"));
+    workflowConfigs.put("resourceManager", viewContext.getProperties().get("yarn.resourcemanager.address"));
+    workflowConfigs.put("userName", viewContext.getUsername());
+    return Response.ok(workflowConfigs).build();
+  }
+
   @POST
   @Path("/submitJob")
   @Consumes({MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML})
@@ -176,67 +199,64 @@ public class OozieProxyImpersonator {
   @Path("/saveWorkflow")
   @Consumes({MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML})
   public Response saveWorkflow(String postBody, @Context HttpHeaders headers,
-                               @Context UriInfo ui, @QueryParam("app.path") String appPath, @QueryParam("description") String description,
-                               @QueryParam("projectId") String projectId, @QueryParam("jobType") String jobType,
+                               @Context UriInfo ui, @QueryParam("app.path") String appPath, @QueryParam("jobType") String jobTypeStr,
                                @DefaultValue("false") @QueryParam("overwrite") Boolean overwrite) {
     LOGGER.info("save workflow  called");
     if (StringUtils.isEmpty(appPath)) {
       throw new RuntimeException("app path can't be empty.");
     }
-
-    JobType deducedJobType = oozieUtils.deduceJobType(postBody);
-    appPath = workflowFilesService.getWorkflowFileName(appPath.trim(),deducedJobType);
-
+    JobType jobType = StringUtils.isEmpty(jobTypeStr) ? JobType.WORKFLOW : JobType.valueOf(jobTypeStr);
+    String workflowFilePath = workflowFilesService.getWorkflowFileName(appPath.trim(), jobType);
     if (!overwrite) {
-      boolean fileExists = hdfsFileUtils.fileExists(appPath);
+      boolean fileExists = hdfsFileUtils.fileExists(workflowFilePath);
       if (fileExists) {
         return getFileExistsResponse();
       }
     }
 
-    postBody = utils.formatXml(postBody);
     try {
-      String filePath = workflowFilesService.createFile(appPath,
-        postBody, overwrite);
-      LOGGER.info(String.format(
-        "submit workflow job done. filePath=[%s]", filePath));
+      if (utils.isXml(postBody)) {
+        saveWorkflowXml(jobType, appPath, postBody, overwrite);
+      } else {
+        saveDraft(jobType, appPath, postBody, overwrite);
+      }
       if (PROJ_MANAGER_ENABLED) {
-        String workflowName = oozieUtils.deduceWorkflowNameFromXml(postBody);
-        workflowManagerService.saveWorkflow(projectId, appPath,
-          deducedJobType, description,
-          viewContext.getUsername(), workflowName);
+        workflowManagerService.saveWorkflow(null, workflowFilePath,
+          jobType, null,
+          viewContext.getUsername(), getWorkflowName(postBody));
       }
-
-      return Response.ok().build();
-    } catch (Exception ex) {
-      LOGGER.error(ex.getMessage(), ex);
+    } catch (IOException ex) {
       return getRespCodeForException(ex);
+    }
 
+    return Response.ok().build();
+  }
+  private String getWorkflowName(String postBody){
+    if (utils.isXml(postBody)) {
+      return oozieUtils.deduceWorkflowNameFromXml(postBody);
+    }else{
+      return oozieUtils.deduceWorkflowNameFromJson(postBody);
     }
   }
 
-  @POST
-  @Path("/saveWorkflowDraft")
-  @Consumes({MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML})
-  public Response saveDraft(String postBody, @Context HttpHeaders headers,
-                            @Context UriInfo ui, @QueryParam("app.path") String appPath,
-                            @QueryParam("projectId") String projectId, @QueryParam("description") String description,
-                            @DefaultValue("false") @QueryParam("overwrite") Boolean overwrite, @QueryParam("jobType") String jobTypeStr)
-    throws IOException {
-    LOGGER.info("save workflow  called");
-    if (StringUtils.isEmpty(appPath)) {
-      throw new RuntimeException("app path can't be empty.");
-    }
-    JobType jobType = StringUtils.isEmpty(jobTypeStr) ? JobType.WORKFLOW : JobType.valueOf(jobTypeStr);
-    appPath = workflowFilesService.getWorkflowDraftFileName(appPath.trim(),jobType);
+  private void saveWorkflowXml(JobType jobType, String appPath, String postBody, Boolean overwrite) throws IOException {
+    appPath = workflowFilesService.getWorkflowFileName(appPath.trim(), jobType);
+    postBody = utils.formatXml(postBody);
     workflowFilesService.createFile(appPath, postBody, overwrite);
-    if (PROJ_MANAGER_ENABLED) {
-      String name = oozieUtils.deduceWorkflowNameFromJson(postBody);
-      workflowManagerService.saveWorkflow(projectId, appPath,
-        jobType, description,
-        viewContext.getUsername(), name);
+    String workflowDraftPath = workflowFilesService.getWorkflowDraftFileName(appPath.trim(), jobType);
+    if (hdfsFileUtils.fileExists(workflowDraftPath)) {
+      hdfsFileUtils.deleteFile(workflowDraftPath);
     }
-    return Response.ok().build();
+  }
+
+  private void saveDraft(JobType jobType, String appPath, String postBody, Boolean overwrite) throws IOException {
+    String workflowFilePath = workflowFilesService.getWorkflowFileName(appPath.trim(), jobType);
+    if (!hdfsFileUtils.fileExists(workflowFilePath)) {
+      String noOpWorkflow = oozieUtils.getNoOpWorkflowXml(postBody, jobType);
+      workflowFilesService.createFile(workflowFilePath, noOpWorkflow, overwrite);
+    }
+    String workflowDraftPath = workflowFilesService.getWorkflowDraftFileName(appPath.trim(), jobType);
+    workflowFilesService.createFile(workflowDraftPath, postBody, true);
   }
 
   @POST
@@ -415,30 +435,40 @@ public class OozieProxyImpersonator {
   }
 
   @GET
-  @Path("/readWorkflowDetail")
-  public Response getWorkflowDetail(
-    @QueryParam("workflowXmlPath") String workflowPath) {
-    WorkflowFileInfo workflowDetails = workflowFilesService
-      .getWorkflowDetails(workflowPath, null);
-    return Response.ok(workflowDetails).build();
-  }
-
-  @GET
   @Path("/readWorkflow")
   public Response readWorkflow(
-    @QueryParam("workflowPath") String workflowPath,@QueryParam("jobType") String jobTypeStr) {
-    WorkflowFileInfo workflowDetails = workflowFilesService
-      .getWorkflowDetails(workflowPath,JobType.valueOf(jobTypeStr));
-    String filePath;
-    String responseType;
+    @QueryParam("workflowPath") String workflowPath, @QueryParam("jobType") String jobTypeStr) {
+    String workflowFileName=workflowFilesService.getWorkflowFileName(workflowPath, JobType.valueOf(jobTypeStr));
+    if (!hdfsFileUtils.fileExists(workflowFileName)){
+      HashMap<String,String> response=new HashMap<>();
+      response.put("status", ErrorCodes.WORKFLOW_XML_DOES_NOT_EXIST.getErrorCode());
+      response.put("message", ErrorCodes.WORKFLOW_XML_DOES_NOT_EXIST.getDescription());
+      return Response.status(Status.BAD_REQUEST).entity(response).build();
+    }
 
-    if (workflowPath.endsWith(Constants.WF_DRAFT_EXTENSION) || workflowDetails.getIsDraftCurrent()){
-      filePath=workflowFilesService.getWorkflowDraftFileName(workflowPath,JobType.valueOf(jobTypeStr));
-      responseType="draft";
-    }else{
-      filePath=workflowFilesService.getWorkflowFileName(workflowPath,JobType.valueOf(jobTypeStr));
-      responseType="xml";
+    WorkflowFileInfo workflowDetails = workflowFilesService
+      .getWorkflowDetails(workflowPath, JobType.valueOf(jobTypeStr));
+    if (workflowPath.endsWith(Constants.WF_DRAFT_EXTENSION) || workflowDetails.getIsDraftCurrent()) {
+      String filePath = workflowFilesService.getWorkflowDraftFileName(workflowPath, JobType.valueOf(jobTypeStr));
+      try {
+        InputStream inputStream = workflowFilesService.readWorkflowXml(filePath);
+        String stringResponse = IOUtils.toString(inputStream);
+        if (!workflowFilesService.isDraftFormatCurrent(stringResponse)) {
+          filePath = workflowFilesService.getWorkflowFileName(workflowPath, JobType.valueOf(jobTypeStr));
+          return getWorkflowResponse(filePath, WorkflowFormat.XML.getValue(), true);
+        } else {
+          return Response.ok(stringResponse).header(RESPONSE_TYPE, WorkflowFormat.DRAFT.getValue()).build();
+        }
+      } catch (IOException e) {
+        return getRespCodeForException(e);
+      }
+    } else {
+      String filePath = workflowFilesService.getWorkflowFileName(workflowPath, JobType.valueOf(jobTypeStr));
+      return getWorkflowResponse(filePath, WorkflowFormat.XML.getValue(), false);
     }
+  }
+
+  private Response getWorkflowResponse(String filePath, String responseType, boolean olderFormatDraftIngored) {
     try {
       final InputStream is = workflowFilesService
         .readWorkflowXml(filePath);
@@ -451,7 +481,11 @@ public class OozieProxyImpersonator {
           os.close();
         }
       };
-      return Response.ok(streamer).header("response-type",responseType).status(200).build();
+      Response.ResponseBuilder responseBuilder = Response.ok(streamer).header(RESPONSE_TYPE, responseType);
+      if(olderFormatDraftIngored){
+        responseBuilder.header(OLDER_FORMAT_DRAFT_INGORED,Boolean.TRUE.toString());
+      }
+      return  responseBuilder.build();
     } catch (IOException e) {
       return getRespCodeForException(e);
     }
@@ -497,28 +531,6 @@ public class OozieProxyImpersonator {
   }
 
   @GET
-  @Path("/getDag")
-  @Produces("image/png")
-  public Response getDag(@Context HttpHeaders headers,
-                         @Context UriInfo ui, @QueryParam("jobid") String jobid) {
-    Map<String, String> newHeaders = utils.getHeaders(headers);
-    final InputStream is = oozieDelegate.readFromOozie(headers,
-      oozieDelegate.getDagUrl(jobid), HttpMethod.GET, null,
-      newHeaders);
-    StreamingOutput streamer = new StreamingOutput() {
-      @Override
-      public void write(OutputStream os) throws IOException,
-        WebApplicationException {
-        IOUtils.copy(is, os);
-        is.close();
-        os.close();
-      }
-
-    };
-    return Response.ok(streamer).status(200).build();
-  }
-
-  @GET
   @Path("/{path: .*}")
   public Response handleGet(@Context HttpHeaders headers, @Context UriInfo ui) {
     try {

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java
index 9791c47..83affd3 100644
--- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java
@@ -106,6 +106,10 @@ public class OozieUtils {
     String name = jsonElement.getAsJsonObject().get("name").getAsString();
     return name;
   }
+  public String deduceWorkflowSchemaVersionFromJson(String json) {
+    JsonElement jsonElement = new JsonParser().parse(json);
+    return jsonElement.getAsJsonObject().get("xmlns").getAsString();
+  }
 
   public String deduceWorkflowNameFromXml(String xml) {
     try {
@@ -172,4 +176,18 @@ public class OozieUtils {
       throw new RuntimeException(e);
     }
   }
+
+  public String getNoOpWorkflowXml(String json,JobType jobType) {
+    String schema=deduceWorkflowSchemaVersionFromJson(json);
+    String name=deduceWorkflowNameFromJson(json);
+    switch (jobType){
+      case WORKFLOW:
+        return String.format("<workflow-app xmlns=\"%s\" name=\"%s\"><start to=\"end\"/><end name=\"end\"/></workflow-app>",schema,name);
+      case COORDINATOR:
+        return String.format("<coordinator-app xmlns=\"%s\" name=\"%s\"></coordinator-app>",schema,name);
+      case BUNDLE:
+        return String.format("<bundle-app xmlns=\"%s\" name=\"%s\"></bundle-app>",schema,name);
+    }
+    return null;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java
index 61d878e..0b9adda 100644
--- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java
@@ -52,8 +52,9 @@ public class Utils {
 	private static final String XML_INDENT_AMT_PROP_NAME = "{http://xml.apache.org/xslt}indent-amount";
 	private final static Logger LOGGER = LoggerFactory
 			.getLogger(Utils.class);
+	private final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 	public String formatXml(String xml) {
-		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+
 		try {
 			DocumentBuilder db = dbf.newDocumentBuilder();
 			StreamResult result = new StreamResult(new StringWriter());
@@ -151,4 +152,15 @@ public class Utils {
 	}
 
 
+  public boolean isXml(String postBody) {
+		try {
+			DocumentBuilder db = dbf.newDocumentBuilder();
+			InputSource is = new InputSource();
+			is.setCharacterStream(new StringReader(postBody));
+			Document doc = db.parse(is);
+			return true;
+		} catch (Exception e) {
+			return false;
+		}
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java
index 24c263b..cdf4e99 100644
--- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java
@@ -20,6 +20,8 @@ package org.apache.oozie.ambari.view;
 import java.io.IOException;
 import java.io.InputStream;
 
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
 import org.apache.hadoop.fs.FileStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -28,6 +30,7 @@ public class WorkflowFilesService {
   private final static Logger LOGGER = LoggerFactory
           .getLogger(WorkflowFilesService.class);
   private HDFSFileUtils hdfsFileUtils;
+  private String currentDraftVersion="v1";
 
   public WorkflowFilesService(HDFSFileUtils hdfsFileUtils) {
     super();
@@ -118,8 +121,13 @@ public class WorkflowFilesService {
     if (appPath.endsWith(Constants.WF_ASSET_EXTENSION)) {
       assetFile = appPath;
     } else {
-      assetFile = appPath + (appPath.endsWith("/") ? "" : "/")
-              + Constants.DEFAULT_WORKFLOW_ASSET_FILENAME;
+      String[] paths=appPath.split("/");
+      if (paths[paths.length-1].contains(".")){
+        return appPath;
+      }else{
+        assetFile = appPath + (appPath.endsWith("/") ? "" : "/")
+          + Constants.DEFAULT_WORKFLOW_ASSET_FILENAME;
+      }
     }
     return assetFile;
   }
@@ -144,6 +152,7 @@ public class WorkflowFilesService {
               .getFileStatus(appPath);
       workflowInfo.setWorkflowModificationTime(workflowFileStatus
               .getModificationTime());
+
     }
     if (draftExists) {
       FileStatus draftFileStatus = hdfsFileUtils
@@ -167,4 +176,13 @@ public class WorkflowFilesService {
     }
   }
 
+  public boolean isDraftFormatCurrent(String json) {
+    JsonElement jsonElement = new JsonParser().parse(json);
+    JsonElement draftVersion = jsonElement.getAsJsonObject().get("draftVersion");
+    if (draftVersion != null && currentDraftVersion.equals(draftVersion.getAsString().trim())) {
+      return true;
+    } else {
+      return false;
+    }
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java
index fc08b80..dcb82ac 100644
--- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java
@@ -53,7 +53,7 @@ public class WorkflowManagerService {
 
     } else {
       String workflowFileName = workflowFilesService.getWorkflowFileName(path, jobType);
-      Workflow workflowByPath = workflowsRepository.getWorkflowByPath(workflowFileName);
+      Workflow workflowByPath = workflowsRepository.getWorkflowByPath(workflowFileName,userName);
       if (workflowByPath != null) {
         setWorkflowAttributes(jobType, userName, name, workflowByPath);
         workflowsRepository.update(workflowByPath);
@@ -74,8 +74,8 @@ public class WorkflowManagerService {
     wf.setType(jobType.name());
   }
 
-  public Collection<Workflow> getAllWorkflows() {
-    return workflowsRepository.findAll();
+  public Collection<Workflow> getAllWorkflows(String username) {
+    return workflowsRepository.getWorkflows(username);
   }
 
   public void deleteWorkflow(String projectId, Boolean deleteDefinition) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java
index 7513107..a0aa234 100644
--- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java
@@ -30,17 +30,18 @@ import javax.ws.rs.QueryParam;
 import org.apache.ambari.view.ViewContext;
 
 public class WorkflowsManagerResource {
-	private WorkflowManagerService workflowManagerService;
-	
+	private final WorkflowManagerService workflowManagerService;
+	private final ViewContext viewContext;
 	public WorkflowsManagerResource(ViewContext viewContext) {
 		super();
+		this.viewContext=viewContext;
 		this.workflowManagerService=new WorkflowManagerService(viewContext);
 	}
 
 	@GET
 	public Map<String,Object> getWorkflows(){
 	    HashMap<String,Object> result=new HashMap<>();
-	    result.put("wfprojects", workflowManagerService.getAllWorkflows());
+	    result.put("wfprojects", workflowManagerService.getAllWorkflows(viewContext.getUsername()));
 	    return result;
 	}
 	

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java
index 1fc0c5f..b0fb905 100644
--- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java
@@ -24,7 +24,9 @@ import org.apache.oozie.ambari.view.workflowmanager.model.Workflow;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 public class WorkflowsRepo extends BaseRepo<Workflow> {
   private final static Logger LOGGER = LoggerFactory
@@ -33,21 +35,47 @@ public class WorkflowsRepo extends BaseRepo<Workflow> {
     super(Workflow.class, dataStore);
 
   }
+  public Collection<Workflow> getWorkflows(String userName){
+    try {
+      Collection<Workflow> workflows = this.dataStore.findAll(Workflow.class,
+        "owner='" + userName + "'");
+      return  workflows;
+    } catch (PersistenceException e) {
+      throw new RuntimeException(e);
+    }
+  }
 
-  public Workflow getWorkflowByPath(String path) {
+  public Workflow getWorkflowByPath(String path, String userName) {
     try {
       Collection<Workflow> workflows = this.dataStore.findAll(Workflow.class,
-              "workflowDefinitionPath='" + path + "'");
+        "workflowDefinitionPath='" + path + "'");
       if (workflows == null || workflows.isEmpty()) {
         return null;
-      } else if (workflows.size() > 1) {
-        LOGGER.error("Duplicate workflows found having same path");
-        throw new RuntimeException("Duplicate workflows");
       } else {
-        return workflows.iterator().next();
+        List<Workflow> myWorkflows = filterWorkflows(workflows, userName, true);
+        if (myWorkflows.isEmpty()) {
+          return null;
+        } else if (myWorkflows.size() == 1) {
+          return myWorkflows.get(0);
+        } else {
+          LOGGER.error("Duplicate workflows found having same path");
+          throw new RuntimeException("Duplicate workflows. Remove one in Recent Workflows Manager");
+        }
       }
     } catch (PersistenceException e) {
       throw new RuntimeException(e);
     }
   }
+
+  private List<Workflow> filterWorkflows(Collection<Workflow> workflows,String userName,boolean matches ) {
+    List<Workflow> filteredWorkflows = new ArrayList<>();
+    for (Workflow wf : workflows) {
+      if (matches && userName.equals(wf.getOwner())) {
+        filteredWorkflows.add(wf);
+      } else if (!matches && !userName.equals(wf.getOwner())) {
+        filteredWorkflows.add(wf);
+      }
+    }
+    return filteredWorkflows;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
index db7a180..9201d5c 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
@@ -123,7 +123,9 @@ export default Ember.Component.extend(Ember.Evented, Validations, {
       coordinators : null,
       schemaVersions : {
         bundleVersion : this.get('schemaVersions').getDefaultVersion('bundle')
-      }
+      },
+      xmlns : "uri:oozie:bundle:" +this.get('schemaVersions').getDefaultVersion('bundle'),
+      draftVersion: 'v1'
     });
   },
   importSampleBundle (){

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
index 369481f..c7da381 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js
@@ -223,7 +223,9 @@ export default Ember.Component.extend(Validations, Ember.Evented, {
       slainfo : SlaInfo.create({}),
       schemaVersions : {
         coordinatorVersion : this.get('schemaVersions').getDefaultVersion('coordinator')
-      }
+      },
+      xmlns : "uri:oozie:coordinator:" +this.get('schemaVersions').getDefaultVersion('coordinator'),
+      draftVersion: 'v1'
     });
   },
   importSampleCoordinator (){

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
index 29c9dd2..c1bd4be 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
@@ -145,31 +145,7 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
   },
 
   importWorkflowFromProjManager(path){
-      var self = this;
-      this.set("showingFileBrowser",false);
-      if(path){
-        self.set("isWorkflowImporting", true);
-        this.isDraftExists(path).promise.then(function(data){
-          var draftData = JSON.parse(data);
-          if(draftData.draftExists && draftData.isDraftCurrent) {
-              self.set("workflowFilePath", path);
-              self.getDraftWorkflowData(path).promise.then(function(data){
-                var workflowImporter = WorkflowJsonImporter.create({});
-                var workflow = workflowImporter.importWorkflow(data);
-                self.resetDesigner();
-                self.set("workflow", workflow);
-                self.initAndRenderWorkflow();
-                self.set("isWorkflowImporting", false);
-                self.doValidation();
-              }.bind(this)).catch(function(data){
-              });
-          } else {
-            self.importWorkflow(path);
-          }
-        }.bind(this)).catch(function(e){
-          console.error(e);
-        });
-      }
+    this.importWorkflow(path);
   },
 
   observeXmlAppPath : Ember.observer('xmlAppPath', function(){
@@ -376,6 +352,7 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
     var workflow=workflowImporter.importWorkflow(data);
     this.resetDesigner();
     this.set("workflow", workflow);
+    this.initAndRenderWorkflow();
     this.rerender();
     this.doValidation();
   },
@@ -453,7 +430,9 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
     var actionNodeType = Object.keys(actionNodeXml)[0];
     var currentTransition = this.get("currentTransition.transition");
     this.createSnapshot();
-    var actionNode = this.get("workflow").addNode(this.findTransition(this.get("workflow").startNode, currentTransition.sourceNodeId, currentTransition.targetNode.id),actionNodeType);
+    var transition = this.get("currentTransition").source.transitions.findBy('targetNode.id',currentTransition.targetNode.id);
+    transition.source=this.get("currentTransition").source;
+    var actionNode = this.get("workflow").addNode(transition,actionNodeType);
     this.rerender();
     this.doValidation();
     this.scrollToNewPosition();
@@ -714,6 +693,7 @@ export default Ember.Component.extend(FindNodeMixin, Validations, {
     }, 1000);
   },
   openSaveWorkflow() {
+    this.get('workflowContext').clearErrors();
     if(Ember.isBlank(this.$('[name=wf_title]').val())) {
       this.set('errors',[{"message":"Workflow name is mandatory"}]);
       return;

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/resources/ui/app/components/save-wf.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/save-wf.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/save-wf.js
index 75cdaf9..17ee0fd 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/save-wf.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/save-wf.js
@@ -17,6 +17,7 @@
 
 import Ember from 'ember';
 import { validator, buildValidations } from 'ember-cp-validations';
+import CommonUtils from "../utils/common-utils";
 
 const Validations = buildValidations({
   'filePath': validator('presence', {
@@ -83,11 +84,11 @@ export default Ember.Component.extend(Validations, {
     }
   },
   saveJob(){
-    var url = Ember.ENV.API_URL + "/saveWorkflowDraft?app.path=" + this.get("filePath") + "&overwrite=" + this.get("overwritePath") + "&jobType="+this.get('displayName').toUpperCase();
-    this.saveWfJob(url, this.get("jobJson"));
-    if(!this.get('isDraft')){
-       url = Ember.ENV.API_URL + "/saveWorkflow?app.path=" + this.get("filePath") + "&overwrite=" + this.get("overwritePath");
-       this.saveWfJob(url, this.get("jobXml"));
+    var url = Ember.ENV.API_URL + "/saveWorkflow?app.path=" + this.get("filePath") + "&overwrite=" + this.get("overwritePath") + "&jobType="+this.get('displayName').toUpperCase();
+    if(this.get('isDraft')){
+       this.saveWfJob(url, this.get("jobJson"));
+    } else {
+      this.saveWfJob(url, this.get("jobXml"));
     }
   },
   saveWfJob(url, workflowData) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/07342bc6/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
index 26e72d5..a563c20 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
@@ -38,6 +38,7 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{
     var schemaVersions=SchemaVersions.create({});
     this.schemaVersions = {};
     this.schemaVersions.workflowVersion = schemaVersions.getDefaultVersion('workflow');
+    this.set("xmlns","uri:oozie:workflow:"+this.schemaVersions.workflowVersion);
     var actionsMap = new Map();
     Constants.actions.forEach((action)=>{
       if(action.supportsSchema){


[14/28] ambari git commit: AMBARI-20052. Spark2 service check is failing in secure cluster (echekanskiy)

Posted by jo...@apache.org.
AMBARI-20052. Spark2 service check is failing in secure cluster (echekanskiy)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/1ecdee0d
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/1ecdee0d
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/1ecdee0d

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 1ecdee0d559540204c66634871e6252d622552cd
Parents: ece4d36
Author: Eugene Chekanskiy <ec...@hortonworks.com>
Authored: Mon Feb 20 16:53:25 2017 +0200
Committer: Eugene Chekanskiy <ec...@hortonworks.com>
Committed: Mon Feb 20 16:53:25 2017 +0200

----------------------------------------------------------------------
 .../common-services/SPARK2/2.0.0/package/scripts/params.py       | 2 ++
 .../SPARK2/2.0.0/package/scripts/service_check.py                | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/1ecdee0d/ambari-server/src/main/resources/common-services/SPARK2/2.0.0/package/scripts/params.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/SPARK2/2.0.0/package/scripts/params.py b/ambari-server/src/main/resources/common-services/SPARK2/2.0.0/package/scripts/params.py
index b6889e4..45a8c07 100755
--- a/ambari-server/src/main/resources/common-services/SPARK2/2.0.0/package/scripts/params.py
+++ b/ambari-server/src/main/resources/common-services/SPARK2/2.0.0/package/scripts/params.py
@@ -131,6 +131,8 @@ security_enabled = config['configurations']['cluster-env']['security_enabled']
 kinit_path_local = get_kinit_path(default('/configurations/kerberos-env/executable_search_paths', None))
 spark_kerberos_keytab =  config['configurations']['spark2-defaults']['spark.history.kerberos.keytab']
 spark_kerberos_principal =  config['configurations']['spark2-defaults']['spark.history.kerberos.principal']
+smoke_user_keytab = config['configurations']['cluster-env']['smokeuser_keytab']
+smokeuser_principal =  config['configurations']['cluster-env']['smokeuser_principal_name']
 
 spark_thriftserver_hosts = default("/clusterHostInfo/spark2_thriftserver_hosts", [])
 has_spark_thriftserver = not len(spark_thriftserver_hosts) == 0

http://git-wip-us.apache.org/repos/asf/ambari/blob/1ecdee0d/ambari-server/src/main/resources/common-services/SPARK2/2.0.0/package/scripts/service_check.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/SPARK2/2.0.0/package/scripts/service_check.py b/ambari-server/src/main/resources/common-services/SPARK2/2.0.0/package/scripts/service_check.py
index acd3340..8e7a766 100755
--- a/ambari-server/src/main/resources/common-services/SPARK2/2.0.0/package/scripts/service_check.py
+++ b/ambari-server/src/main/resources/common-services/SPARK2/2.0.0/package/scripts/service_check.py
@@ -31,7 +31,7 @@ class SparkServiceCheck(Script):
     if params.security_enabled:
       spark_kinit_cmd = format("{kinit_path_local} -kt {spark_kerberos_keytab} {spark_principal}; ")
       Execute(spark_kinit_cmd, user=params.spark_user)
-      if (params.has_livyserver):
+      if params.has_livyserver:
         livy_kinit_cmd = format("{kinit_path_local} -kt {smoke_user_keytab} {smokeuser_principal}; ")
         Execute(livy_kinit_cmd, user=params.livy2_user)
 
@@ -41,7 +41,7 @@ class SparkServiceCheck(Script):
             logoutput=True
             )
     if params.has_livyserver:
-      live_livyserver_host = "";
+      live_livyserver_host = ""
       for livyserver_host in params.livy2_livyserver_hosts:
         try:
           Execute(format("curl -s -o /dev/null -w'%{{http_code}}' --negotiate -u: -k http://{livyserver_host}:{livy2_livyserver_port}/sessions | grep 200"),


[12/28] ambari git commit: AMBARI-20013. Appendum - add infra-solr keytabs to atlas in HDP2.6 as well (oleewere)

Posted by jo...@apache.org.
AMBARI-20013. Appendum - add infra-solr keytabs to atlas in HDP2.6 as well (oleewere)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/6feb46a3
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/6feb46a3
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/6feb46a3

Branch: refs/heads/branch-feature-AMBARI-20053
Commit: 6feb46a33ee448d25a35616c39b85144908f4ced
Parents: 709bf6e
Author: oleewere <ol...@gmail.com>
Authored: Mon Feb 20 14:33:01 2017 +0100
Committer: oleewere <ol...@gmail.com>
Committed: Mon Feb 20 14:33:17 2017 +0100

----------------------------------------------------------------------
 .../main/resources/common-services/ATLAS/0.1.0.2.3/kerberos.json  | 3 +++
 .../main/resources/stacks/HDP/2.6/services/ATLAS/kerberos.json    | 3 +++
 2 files changed, 6 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6feb46a3/ambari-server/src/main/resources/common-services/ATLAS/0.1.0.2.3/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/ATLAS/0.1.0.2.3/kerberos.json b/ambari-server/src/main/resources/common-services/ATLAS/0.1.0.2.3/kerberos.json
index 85f8207..0c25c95 100644
--- a/ambari-server/src/main/resources/common-services/ATLAS/0.1.0.2.3/kerberos.json
+++ b/ambari-server/src/main/resources/common-services/ATLAS/0.1.0.2.3/kerberos.json
@@ -48,6 +48,9 @@
               "keytab": {
                 "configuration": "application-properties/atlas.http.authentication.kerberos.keytab"
               }
+            },
+            {
+              "name": "/AMBARI_INFRA/INFRA_SOLR/infra-solr"
             }
           ]
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6feb46a3/ambari-server/src/main/resources/stacks/HDP/2.6/services/ATLAS/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.6/services/ATLAS/kerberos.json b/ambari-server/src/main/resources/stacks/HDP/2.6/services/ATLAS/kerberos.json
index 1cc581f..7d10ccc 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.6/services/ATLAS/kerberos.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.6/services/ATLAS/kerberos.json
@@ -88,6 +88,9 @@
             },
             {
               "name": "/KAFKA/KAFKA_BROKER/kafka_broker"
+            },
+            {
+              "name": "/AMBARI_INFRA/INFRA_SOLR/infra-solr"
             }
           ]
         }