You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2017/11/27 20:24:11 UTC

[01/49] ambari git commit: AMBARI-22318 repositoryFile entity populating for wrong repository for RU (dgrinenko)

Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-20859 d173011c8 -> 167b48294


http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index d95dcef..f8b6709 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -52,7 +52,6 @@ import java.util.UUID;
 
 import javax.persistence.EntityManager;
 
-import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ClusterNotFoundException;
 import org.apache.ambari.server.DuplicateResourceException;
 import org.apache.ambari.server.H2DatabaseCleaner;
@@ -332,11 +331,11 @@ public class AmbariManagementControllerTest {
     host.setHostAttributes(hostAttributes);
   }
 
-  private void addHost(String hostname) throws AmbariException {
+  private void addHost(String hostname) throws Exception {
     addHostToCluster(hostname, null);
   }
 
-  private void addHostToCluster(String hostname, String clusterName) throws AmbariException {
+  private void addHostToCluster(String hostname, String clusterName) throws Exception {
 
     if (!clusters.hostExists(hostname)) {
       clusters.addHost(hostname);
@@ -349,27 +348,30 @@ public class AmbariManagementControllerTest {
     }
   }
 
-  private void deleteHost(String hostname) throws AmbariException {
+  private void deleteHost(String hostname) throws Exception {
     clusters.deleteHost(hostname);
   }
 
+
+
   /**
    * Creates a Cluster object, along with its corresponding ClusterVersion based on the stack.
    * @param clusterName Cluster name
-   * @throws AmbariException
+   * @throws Exception
    */
-  private void createCluster(String clusterName) throws AmbariException, AuthorizationException {
+  private void createCluster(String clusterName) throws Exception{
+    RepositoryVersionDAO repoDAO = injector.getInstance(RepositoryVersionDAO.class);
     ClusterRequest r = new ClusterRequest(null, clusterName, State.INSTALLED.name(), SecurityType.NONE, "HDP-0.1", null);
     controller.createCluster(r);
   }
 
-  private void createService(String clusterName, String serviceName, State desiredState) throws AmbariException, AuthorizationException {
+  private void createService(String clusterName, String serviceName, State desiredState) throws Exception, AuthorizationException {
     createService(clusterName, serviceName, repositoryVersion02, desiredState);
   }
 
   private void createService(String clusterName, String serviceName,
       RepositoryVersionEntity repositoryVersion, State desiredState)
-      throws AmbariException, AuthorizationException {
+      throws Exception, AuthorizationException {
     String dStateStr = null;
     if (desiredState != null) {
       dStateStr = desiredState.toString();
@@ -387,7 +389,7 @@ public class AmbariManagementControllerTest {
 
   private void createServiceComponent(String clusterName,
       String serviceName, String componentName, State desiredState)
-      throws AmbariException, AuthorizationException {
+      throws Exception, AuthorizationException {
     String dStateStr = null;
     if (desiredState != null) {
       dStateStr = desiredState.toString();
@@ -402,7 +404,7 @@ public class AmbariManagementControllerTest {
 
   private void createServiceComponentHost(String clusterName,
       String serviceName, String componentName, String hostname,
-      State desiredState) throws AmbariException, AuthorizationException {
+      State desiredState) throws Exception, AuthorizationException {
     String dStateStr = null;
     if (desiredState != null) {
       dStateStr = desiredState.toString();
@@ -417,7 +419,7 @@ public class AmbariManagementControllerTest {
 
   private void deleteServiceComponentHost(String clusterName,
                                           String serviceName, String componentName, String hostname,
-                                          State desiredState) throws AmbariException, AuthorizationException {
+                                          State desiredState) throws Exception, AuthorizationException {
     String dStateStr = null;
     if (desiredState != null) {
       dStateStr = desiredState.toString();
@@ -432,7 +434,7 @@ public class AmbariManagementControllerTest {
 
   private Long createConfigGroup(Cluster cluster, String serviceName, String name, String tag,
                               List<String> hosts, List<Config> configs)
-                              throws AmbariException {
+                              throws Exception {
 
     Map<Long, Host> hostMap = new HashMap<>();
     Map<String, Config> configMap = new HashMap<>();
@@ -459,7 +461,7 @@ public class AmbariManagementControllerTest {
 
   private long stopService(String clusterName, String serviceName,
       boolean runSmokeTests, boolean reconfigureClients) throws
-      AmbariException, AuthorizationException {
+      Exception, AuthorizationException {
     ServiceRequest r = new ServiceRequest(clusterName, serviceName, null, State.INSTALLED.toString(), null);
     Set<ServiceRequest> requests = new HashSet<>();
     requests.add(r);
@@ -516,7 +518,7 @@ public class AmbariManagementControllerTest {
 
   private long startService(String clusterName, String serviceName,
                             boolean runSmokeTests, boolean reconfigureClients) throws
-      AmbariException, AuthorizationException {
+      Exception, AuthorizationException {
     return startService(clusterName, serviceName, runSmokeTests, reconfigureClients, null);
   }
 
@@ -524,7 +526,7 @@ public class AmbariManagementControllerTest {
   private long startService(String clusterName, String serviceName,
                             boolean runSmokeTests, boolean reconfigureClients,
                             MaintenanceStateHelper maintenanceStateHelper) throws
-      AmbariException, AuthorizationException {
+      Exception, AuthorizationException {
     ServiceRequest r = new ServiceRequest(clusterName, serviceName, repositoryVersion02.getId(),
         State.STARTED.toString(), null);
     Set<ServiceRequest> requests = new HashSet<>();
@@ -565,7 +567,7 @@ public class AmbariManagementControllerTest {
 
   private long installService(String clusterName, String serviceName,
                               boolean runSmokeTests, boolean reconfigureClients)
-      throws AmbariException, AuthorizationException {
+      throws Exception, AuthorizationException {
     return installService(clusterName, serviceName, runSmokeTests, reconfigureClients, null, null);
   }
 
@@ -578,7 +580,7 @@ public class AmbariManagementControllerTest {
                               boolean runSmokeTests, boolean reconfigureClients,
                               MaintenanceStateHelper maintenanceStateHelper,
                               Map<String, String> mapRequestPropsInput)
-      throws AmbariException, AuthorizationException {
+      throws Exception, AuthorizationException {
 
     ServiceRequest r = new ServiceRequest(clusterName, serviceName, repositoryVersion02.getId(),
         State.INSTALLED.toString(), null);
@@ -618,7 +620,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testCreateClusterSimple() throws AmbariException, AuthorizationException {
+  public void testCreateClusterSimple() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     Set<ClusterResponse> r =
@@ -631,13 +633,13 @@ public class AmbariManagementControllerTest {
     try {
       createCluster(cluster1);
       fail("Duplicate cluster creation should fail");
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       // Expected
     }
   }
 
   @Test
-  public void testCreateClusterWithHostMapping() throws AmbariException, AuthorizationException {
+  public void testCreateClusterWithHostMapping() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
 
     String host1 = getUniqueName();
@@ -697,7 +699,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testCreateServicesSimple() throws AmbariException, AuthorizationException {
+  public void testCreateServicesSimple() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     String serviceName = "HDFS";
@@ -722,7 +724,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testCreateServicesWithInvalidRequest() throws AmbariException, AuthorizationException {
+  public void testCreateServicesWithInvalidRequest() throws Exception, AuthorizationException {
     // invalid request
     // dups in requests
     // multi cluster updates
@@ -755,7 +757,7 @@ public class AmbariManagementControllerTest {
       set1.add(rInvalid);
       ServiceResourceProviderTest.createServices(controller, repositoryVersionDAO, set1);
       fail("Expected failure for invalid cluster");
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       // Expected
       Assert.assertTrue(checkExceptionType(e, ClusterNotFoundException.class));
     }
@@ -827,7 +829,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testCreateServiceWithInvalidInfo() throws AmbariException, AuthorizationException {
+  public void testCreateServiceWithInvalidInfo() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     String serviceName = "HDFS";
@@ -868,7 +870,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testCreateServicesMultiple() throws AmbariException, AuthorizationException {
+  public void testCreateServicesMultiple() throws Exception, AuthorizationException {
     Set<ServiceRequest> set1 = new HashSet<>();
 
     String cluster1 = getUniqueName();
@@ -888,7 +890,7 @@ public class AmbariManagementControllerTest {
       set1.add(valid2);
       ServiceResourceProviderTest.createServices(controller, repositoryVersionDAO, set1);
       fail("Expected failure for invalid services");
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       // Expected
       Assert.assertTrue(checkExceptionType(e, DuplicateResourceException.class));
     }
@@ -900,7 +902,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testCreateServiceComponentSimple() throws AmbariException, AuthorizationException {
+  public void testCreateServiceComponentSimple() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     String serviceName = "HDFS";
@@ -941,7 +943,7 @@ public class AmbariManagementControllerTest {
 
   @Test
   public void testCreateServiceComponentWithInvalidRequest()
-      throws AmbariException, AuthorizationException {
+      throws Exception, AuthorizationException {
     // multiple clusters
     // dup objects
     // existing components
@@ -1319,8 +1321,6 @@ public class AmbariManagementControllerTest {
                                         RoleCommand.START);
     assertEquals(cluster1, ec.getClusterName());
     assertNotNull(ec.getCommandParams());
-    assertTrue(ec.getCommandParams().containsKey("custom_folder"));
-    assertEquals("dashboards", ec.getCommandParams().get("custom_folder"));
     assertNotNull(ec.getHostLevelParams());
     assertTrue(ec.getHostLevelParams().containsKey(ExecutionCommand.KeyNames.USER_LIST));
     assertEquals("[\"myhdfsuser\"]", ec.getHostLevelParams().get(ExecutionCommand.KeyNames.USER_LIST));
@@ -1331,7 +1331,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testCreateServiceComponentMultiple() throws AmbariException, AuthorizationException {
+  public void testCreateServiceComponentMultiple() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     String cluster2 = getUniqueName();
 
@@ -1379,7 +1379,7 @@ public class AmbariManagementControllerTest {
   }
 
   private void createServiceComponentHostSimple(String clusterName, String host1,
-      String host2) throws AmbariException, AuthorizationException {
+      String host2) throws Exception, AuthorizationException {
 
     createCluster(clusterName);
     clusters.getCluster(clusterName)
@@ -1478,7 +1478,7 @@ public class AmbariManagementControllerTest {
 
   @Test
   public void testCreateServiceComponentHostMultiple()
-      throws AmbariException, AuthorizationException {
+      throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     String serviceName = "HDFS";
@@ -1536,7 +1536,7 @@ public class AmbariManagementControllerTest {
 
   @Test
   public void testCreateServiceComponentHostWithInvalidRequest()
-      throws AmbariException, AuthorizationException {
+      throws Exception, AuthorizationException {
     // multiple clusters
     // dup objects
     // existing components
@@ -1663,7 +1663,7 @@ public class AmbariManagementControllerTest {
       set1.add(rInvalid);
       controller.createHostComponents(set1);
       fail("Expected failure for invalid service");
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       // Expected
     }
 
@@ -1682,7 +1682,7 @@ public class AmbariManagementControllerTest {
       set1.add(rInvalid);
       controller.createHostComponents(set1);
       fail("Expected failure for invalid host");
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       // Expected
     }
 
@@ -1709,7 +1709,7 @@ public class AmbariManagementControllerTest {
       set1.add(rInvalid);
       controller.createHostComponents(set1);
       fail("Expected failure for invalid host cluster mapping");
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       // Expected
     }
 
@@ -1798,7 +1798,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testCreateHostSimple() throws AmbariException, AuthorizationException {
+  public void testCreateHostSimple() throws Exception {
     String cluster1 = getUniqueName();
     String host1 = getUniqueName();
     String host2 = getUniqueName();
@@ -1827,7 +1827,7 @@ public class AmbariManagementControllerTest {
     try {
       HostResourceProviderTest.createHosts(controller, requests);
       fail("Create host should fail for invalid clusters");
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       // Expected
     }
 
@@ -1851,7 +1851,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testCreateHostMultiple() throws AmbariException, AuthorizationException {
+  public void testCreateHostMultiple() throws Exception {
     String host1 = getUniqueName();
     String host2 = getUniqueName();
     String host3 = getUniqueName();
@@ -1887,7 +1887,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testCreateHostWithInvalidRequests() throws AmbariException {
+  public void testCreateHostWithInvalidRequests() throws Exception {
     // unknown host
     // invalid clusters
     // duplicate host
@@ -2198,7 +2198,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testGetClusters() throws AmbariException, AuthorizationException {
+  public void testGetClusters() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
 
     clusters.addCluster(cluster1, new StackId("HDP-0.1"));
@@ -2229,7 +2229,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testGetClustersWithFilters() throws AmbariException, AuthorizationException {
+  public void testGetClustersWithFilters() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     String cluster2 = getUniqueName();
     String cluster3 = getUniqueName();
@@ -2260,7 +2260,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testGetServices() throws AmbariException {
+  public void testGetServices() throws Exception {
     String cluster1 = getUniqueName();
 
     StackId stackId = new StackId("HDP-0.1");
@@ -2289,7 +2289,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testGetServicesWithFilters() throws AmbariException {
+  public void testGetServicesWithFilters() throws Exception {
     String cluster1 = getUniqueName();
     String cluster2 = getUniqueName();
 
@@ -2369,7 +2369,7 @@ public class AmbariManagementControllerTest {
 
 
   @Test
-  public void testGetServiceComponents() throws AmbariException {
+  public void testGetServiceComponents() throws Exception {
     String cluster1 = getUniqueName();
 
     StackId stackId = new StackId("HDP-0.2");
@@ -2406,7 +2406,7 @@ public class AmbariManagementControllerTest {
 
 
   @Test
-  public void testGetServiceComponentsWithFilters() throws AmbariException {
+  public void testGetServiceComponentsWithFilters() throws Exception {
     String cluster1 = getUniqueName();
     String cluster2 = getUniqueName();
 
@@ -2527,7 +2527,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testGetServiceComponentHosts() throws AmbariException, AuthorizationException {
+  public void testGetServiceComponentHosts() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     String host1 = getUniqueName();
 
@@ -2573,7 +2573,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testGetServiceComponentHostsWithStaleConfigFilter() throws AmbariException, AuthorizationException {
+  public void testGetServiceComponentHostsWithStaleConfigFilter() throws Exception, AuthorizationException {
 
     final String host1 = getUniqueName();
     final String host2 = getUniqueName();
@@ -2761,7 +2761,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testHbaseDecommission() throws AmbariException, AuthorizationException {
+  public void testHbaseDecommission() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     clusters.getCluster(cluster1).setDesiredStackVersion(new StackId("HDP-2.0.7"));
@@ -2903,7 +2903,7 @@ public class AmbariManagementControllerTest {
   }
 
   private Cluster setupClusterWithHosts(String clusterName, String stackId, List<String> hosts,
-                                        String osType) throws AmbariException, AuthorizationException {
+                                        String osType) throws Exception, AuthorizationException {
     ClusterRequest r = new ClusterRequest(null, clusterName, stackId, null);
     controller.createCluster(r);
     Cluster c1 = clusters.getCluster(clusterName);
@@ -2914,7 +2914,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testGetServiceComponentHostsWithFilters() throws AmbariException, AuthorizationException {
+  public void testGetServiceComponentHostsWithFilters() throws Exception, AuthorizationException {
     final String cluster1 = getUniqueName();
     final String host1 = getUniqueName();
     final String host2 = getUniqueName();
@@ -3063,7 +3063,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testGetHosts() throws AmbariException, AuthorizationException {
+  public void testGetHosts() throws Exception, AuthorizationException {
     final String cluster1 = getUniqueName();
     final String cluster2 = getUniqueName();
     final String host1 = getUniqueName();
@@ -3137,7 +3137,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testServiceUpdateBasic() throws AmbariException, AuthorizationException {
+  public void testServiceUpdateBasic() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     String serviceName = "HDFS";
@@ -3180,7 +3180,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testServiceUpdateInvalidRequest() throws AmbariException, AuthorizationException {
+  public void testServiceUpdateInvalidRequest() throws Exception, AuthorizationException {
     // multiple clusters
     // dup services
     // multiple diff end states
@@ -3262,7 +3262,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Ignore("Something fishy with the stacks here that's causing the RCO to be loaded incorrectly")
-  public void testServiceUpdateRecursive() throws AmbariException, AuthorizationException {
+  public void testServiceUpdateRecursive() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
 
     createCluster(cluster1);
@@ -3517,7 +3517,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testServiceComponentUpdateRecursive() throws AmbariException, AuthorizationException {
+  public void testServiceComponentUpdateRecursive() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
 
     createCluster(cluster1);
@@ -4055,7 +4055,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testComponentCategorySentWithRestart() throws AmbariException, AuthorizationException {
+  public void testComponentCategorySentWithRestart() throws Exception, AuthorizationException {
     final String cluster1 = getUniqueName();
     final String host1 = getUniqueName();
 
@@ -4421,7 +4421,7 @@ public class AmbariManagementControllerTest {
     try {
       RequestStatusResponse response = controller.createAction(actionRequest, requestProperties);
       Assert.fail("createAction should fail");
-    } catch (AmbariException ex) {
+    } catch (Exception ex) {
       LOG.info(ex.getMessage());
       if (!ex.getMessage().contains(message)) {
         fail(String.format("Expected '%s' to contain '%s'", ex.getMessage(), message));
@@ -5119,7 +5119,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testReConfigureServiceClient() throws AmbariException, AuthorizationException {
+  public void testReConfigureServiceClient() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     Cluster cluster = clusters.getCluster(cluster1);
@@ -5401,7 +5401,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testClientServiceSmokeTests() throws AmbariException, AuthorizationException {
+  public void testClientServiceSmokeTests() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     String serviceName = "PIG";
@@ -5495,7 +5495,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testSkipTaskOnUnhealthyHosts() throws AmbariException, AuthorizationException {
+  public void testSkipTaskOnUnhealthyHosts() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     clusters.getCluster(cluster1)
@@ -5630,7 +5630,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testServiceCheckWhenHostIsUnhealthy() throws AmbariException, AuthorizationException {
+  public void testServiceCheckWhenHostIsUnhealthy() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     clusters.getCluster(cluster1).setDesiredStackVersion(new StackId("HDP-0.1"));
@@ -5722,13 +5722,13 @@ public class AmbariManagementControllerTest {
     try {
       response = controller.createAction(actionRequest, requestProperties);
       assertTrue("Exception should have been raised.", false);
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       assertTrue(e.getMessage().contains("there were no healthy eligible hosts"));
     }
   }
 
   @Test
-  public void testReInstallForInstallFailedClient() throws AmbariException, AuthorizationException {
+  public void testReInstallForInstallFailedClient() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     clusters.getCluster(cluster1)
@@ -5857,7 +5857,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testReInstallClientComponentFromServiceChange() throws AmbariException, AuthorizationException {
+  public void testReInstallClientComponentFromServiceChange() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     clusters.getCluster(cluster1)
@@ -6094,7 +6094,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testResourceFiltersWithCustomActions() throws AmbariException, AuthorizationException {
+  public void testResourceFiltersWithCustomActions() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     final String host1 = getUniqueName();
     final String host2 = getUniqueName();
@@ -6166,7 +6166,7 @@ public class AmbariManagementControllerTest {
     RequestStatusResponse response = null;
     try {
       response = controller.createAction(actionRequest, requestProperties);
-    } catch (AmbariException ae) {
+    } catch (Exception ae) {
       LOG.info("Expected exception.", ae);
       Assert.assertTrue(ae.getMessage().contains("Custom action definition only " +
         "allows one resource filter to be specified"));
@@ -6197,7 +6197,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testResourceFiltersWithCustomCommands() throws AmbariException, AuthorizationException {
+  public void testResourceFiltersWithCustomCommands() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     final String host1 = getUniqueName();
     final String host2 = getUniqueName();
@@ -6351,7 +6351,7 @@ public class AmbariManagementControllerTest {
 
 
   @Test
-  public void testConfigsAttachedToServiceChecks() throws AmbariException, AuthorizationException {
+  public void testConfigsAttachedToServiceChecks() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     Cluster cluster = clusters.getCluster(cluster1);
@@ -6433,7 +6433,7 @@ public class AmbariManagementControllerTest {
 
   @Test
   @Ignore("Unsuported feature !")
-  public void testConfigsAttachedToServiceNotCluster() throws AmbariException, AuthorizationException {
+  public void testConfigsAttachedToServiceNotCluster() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     clusters.getCluster(cluster1).setDesiredStackVersion(new StackId("HDP-0.1"));
@@ -6513,7 +6513,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testHostLevelParamsSentWithCommands() throws AmbariException, AuthorizationException {
+  public void testHostLevelParamsSentWithCommands() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     String serviceName = "PIG";
@@ -6570,7 +6570,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testConfigGroupOverridesWithHostActions() throws AmbariException, AuthorizationException {
+  public void testConfigGroupOverridesWithHostActions() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     Cluster cluster = clusters.getCluster(cluster1);
@@ -6727,7 +6727,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testConfigGroupOverridesWithDecommissionDatanode() throws AmbariException, AuthorizationException {
+  public void testConfigGroupOverridesWithDecommissionDatanode() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     Cluster cluster = clusters.getCluster(cluster1);
@@ -6832,7 +6832,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testConfigGroupOverridesWithServiceCheckActions() throws AmbariException, AuthorizationException {
+  public void testConfigGroupOverridesWithServiceCheckActions() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     createCluster(cluster1);
     Cluster cluster = clusters.getCluster(cluster1);
@@ -7321,7 +7321,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testUpdateClusterUpgradabilityCheck() throws AmbariException, AuthorizationException {
+  public void testUpdateClusterUpgradabilityCheck() throws Exception, AuthorizationException {
     String cluster1 = getUniqueName();
     StackId currentStackId = new StackId("HDP-0.2");
 
@@ -7334,7 +7334,7 @@ public class AmbariManagementControllerTest {
     ClusterRequest r = new ClusterRequest(c.getClusterId(), cluster1, "HDP-0.3", null);
     try {
       controller.updateClusters(Collections.singleton(r), mapRequestProps);
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       Assert.assertTrue(e.getMessage().contains("Illegal request to upgrade to"));
     }
 
@@ -7345,7 +7345,7 @@ public class AmbariManagementControllerTest {
     r = new ClusterRequest(c.getClusterId(), cluster1, "HDP-0.2", null);
     try {
       controller.updateClusters(Collections.singleton(r), mapRequestProps);
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       Assert.assertTrue(e.getMessage().contains("Upgrade is not allowed from"));
     }
   }
@@ -7613,7 +7613,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testGetTasksByRequestId() throws AmbariException {
+  public void testGetTasksByRequestId() throws Exception {
     ActionManager am = injector.getInstance(ActionManager.class);
 
     final long requestId1 = am.getNextRequestId();
@@ -8357,7 +8357,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testExecutionCommandConfiguration() throws AmbariException {
+  public void testExecutionCommandConfiguration() throws Exception {
     Map<String, Map<String, String>> config = new HashMap<>();
     config.put("type1", new HashMap<>());
     config.put("type3", new HashMap<>());
@@ -8400,7 +8400,7 @@ public class AmbariManagementControllerTest {
 
     String tag = "version1";
     String type = "core-site";
-    AmbariException exception = null;
+    Exception exception = null;
     try {
       AmbariManagementController amc = injector.getInstance(AmbariManagementController.class);
       Clusters clusters = injector.getInstance(Clusters.class);
@@ -8432,7 +8432,7 @@ public class AmbariManagementControllerTest {
       amc.createConfiguration(configurationRequest);
 
       amc.createConfiguration(configurationRequest);
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       exception = e;
     }
 
@@ -9090,7 +9090,7 @@ public class AmbariManagementControllerTest {
   private void testRunSmokeTestFlag(Map<String, String> mapRequestProps,
                                     AmbariManagementController amc,
                                     Set<ServiceRequest> serviceRequests)
-      throws AmbariException, AuthorizationException {
+      throws Exception, AuthorizationException {
     RequestStatusResponse response;//Starting HDFS service. No run_smoke_test flag is set, smoke
 
     String cluster1 = getUniqueName();
@@ -9914,7 +9914,7 @@ public class AmbariManagementControllerTest {
     try {
       controller.updateClusters(Collections.singleton(cr), new HashMap<>());
       Assert.fail("Expect failure when creating a config that exists");
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       // expected
     }
   }
@@ -10018,7 +10018,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testConfigAttributesStaleConfigFilter() throws AmbariException, AuthorizationException {
+  public void testConfigAttributesStaleConfigFilter() throws Exception, AuthorizationException {
 
     final String host1 = getUniqueName();
     final String host2 = getUniqueName();
@@ -10119,7 +10119,7 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
-  public void testSecretReferences() throws AmbariException, AuthorizationException {
+  public void testSecretReferences() throws Exception, AuthorizationException {
 
     final String host1 = getUniqueName();
     final String host2 = getUniqueName();
@@ -10208,7 +10208,7 @@ public class AmbariManagementControllerTest {
     try {
       controller.updateClusters(Collections.singleton(crReq), null);
       fail("Request need to be failed with wrong secret reference");
-    } catch (AmbariException e){
+    } catch (Exception e){
 
     }
     // reference to config which does not contain requested property
@@ -10237,7 +10237,7 @@ public class AmbariManagementControllerTest {
     try {
       controller.updateClusters(Collections.singleton(crReq), null);
       fail("Request need to be failed with wrong secret reference");
-    } catch (AmbariException e) {
+    } catch (Exception e) {
       assertEquals("Error when parsing secret reference. Cluster: " + cluster1 + " ConfigType: hdfs-site ConfigVersion: 4 does not contain property 'test.password'",
           e.getMessage());
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
index f45ff75..a6fc919 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
@@ -1913,8 +1913,53 @@ public class ClusterStackVersionResourceProviderTest {
      stackEntity.setStackName("HDP");
      stackEntity.setStackVersion("2.1.1");
 
-     File f = new File("src/test/resources/hbase_version_test.xml");
-     String xmlString = IOUtils.toString(new FileInputStream(f));
+     String hbaseVersionTestXML = "\n" +
+       "<repository-version xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+       "  xsi:noNamespaceSchemaLocation=\"version_definition.xsd\">\n" +
+       "  \n" +
+       "  <release>\n" +
+       "    <type>PATCH</type>\n" +
+       "    <stack-id>HDP-2.3</stack-id>\n" +
+       "    <version>2.3.4.0</version>\n" +
+       "    <build>3396</build>\n" +
+       "    <compatible-with>2.3.2.[0-9]</compatible-with>\n" +
+       "    <release-notes>http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.3.4/</release-notes>\n" +
+       "  </release>\n" +
+       "  \n" +
+       "  <manifest>\n" +
+       "    <service id=\"HBASE-112\" name=\"HBASE\" version=\"1.1.2\" version-id=\"2_3_4_0-3396\" />\n" +
+       "  </manifest>\n" +
+       "  \n" +
+       "  <available-services>\n" +
+       "    <service idref=\"HBASE-112\" />\n" +
+       "  </available-services>\n" +
+       "  \n" +
+       "  <repository-info>\n" +
+       "    <os family=\"redhat6\">\n" +
+       "      <package-version>2_3_4_0_3396</package-version>\n" +
+       "      <repo>\n" +
+       "        <baseurl>http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.3.4.0</baseurl>\n" +
+       "        <repoid>HDP-2.3</repoid>\n" +
+       "        <reponame>HDP</reponame>\n" +
+       "        <unique>true</unique>\n" +
+       "      </repo>\n" +
+       "      <repo>\n" +
+       "        <baseurl>http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6</baseurl>\n" +
+       "        <repoid>HDP-UTILS-1.1.0.20</repoid>\n" +
+       "        <reponame>HDP-UTILS</reponame>\n" +
+       "        <unique>false</unique>\n" +
+       "      </repo>\n" +
+       "    </os>\n" +
+       "  </repository-info>\n" +
+       "  \n" +
+       "  <upgrade>\n" +
+       "    <configuration type=\"hdfs-site\">\n" +
+       "      <set key=\"foo\" value=\"bar\" />\n" +
+       "    </configuration>\n" +
+       "  </upgrade>\n" +
+       "</repository-version>";
+
+     String xmlString = hbaseVersionTestXML;
      // hack to remove ZK
      xmlString = xmlString.replace("<service idref=\"ZOOKEEPER-346\" />", "");
 
@@ -2013,7 +2058,7 @@ public class ClusterStackVersionResourceProviderTest {
      expect(managementController.findConfigurationTagsWithOverrides(anyObject(Cluster.class), EasyMock.anyString()))
      .andReturn(new HashMap<String, Map<String, String>>()).anyTimes();
 
-     expect(clusters.getCluster(anyObject(String.class))).andReturn(cluster);
+     expect(clusters.getCluster(anyObject(String.class))).andReturn(cluster).anyTimes();
      expect(clusters.getHostsForCluster(anyObject(String.class))).andReturn(
          hostsForCluster).anyTimes();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
index 64d416f..ec240df 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
@@ -214,23 +214,25 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
     StackEntity stackEntity220 = stackDAO.find("HDP", "2.2.0");
     StackId stack211 = new StackId(stackEntity211);
 
+    String operatingSystems = "[{\"OperatingSystems/ambari_managed_repositories\":\"true\",\"repositories\":[{\"Repositories/repo_id\":\"HDP\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP\"},{\"Repositories/repo_id\":\"HDP-UTILS\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP-UTILS\"}],\"OperatingSystems/os_type\":\"redhat6\"}]";
+
     repoVersionEntity2110 = new RepositoryVersionEntity();
     repoVersionEntity2110.setDisplayName("My New Version 1");
-    repoVersionEntity2110.setOperatingSystems("");
+    repoVersionEntity2110.setOperatingSystems(operatingSystems);
     repoVersionEntity2110.setStack(stackEntity211);
     repoVersionEntity2110.setVersion("2.1.1.0");
     repoVersionDao.create(repoVersionEntity2110);
 
     repoVersionEntity2111 = new RepositoryVersionEntity();
     repoVersionEntity2111.setDisplayName("My New Version 2 for minor upgrade");
-    repoVersionEntity2111.setOperatingSystems("");
+    repoVersionEntity2111.setOperatingSystems(operatingSystems);
     repoVersionEntity2111.setStack(stackEntity211);
     repoVersionEntity2111.setVersion("2.1.1.1");
     repoVersionDao.create(repoVersionEntity2111);
 
     repoVersionEntity2112 = new RepositoryVersionEntity();
     repoVersionEntity2112.setDisplayName("My New Version 3 for patch upgrade");
-    repoVersionEntity2112.setOperatingSystems("");
+    repoVersionEntity2112.setOperatingSystems(operatingSystems);
     repoVersionEntity2112.setStack(stackEntity211);
     repoVersionEntity2112.setVersion("2.1.1.2");
     repoVersionEntity2112.setType(RepositoryType.PATCH);
@@ -239,7 +241,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
 
     repoVersionEntity2200 = new RepositoryVersionEntity();
     repoVersionEntity2200.setDisplayName("My New Version 4 for major upgrade");
-    repoVersionEntity2200.setOperatingSystems("");
+    repoVersionEntity2200.setOperatingSystems(operatingSystems);
     repoVersionEntity2200.setStack(stackEntity220);
     repoVersionEntity2200.setVersion("2.2.0.0");
     repoVersionDao.create(repoVersionEntity2200);
@@ -1931,7 +1933,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
     StackEntity stackEntity = stackDAO.find("HDP", "2.1.1");
     RepositoryVersionEntity repoVersionEntity = new RepositoryVersionEntity();
     repoVersionEntity.setDisplayName("My New Version 3");
-    repoVersionEntity.setOperatingSystems("");
+    repoVersionEntity.setOperatingSystems("[{\"OperatingSystems/ambari_managed_repositories\":\"true\",\"repositories\":[{\"Repositories/repo_id\":\"HDP\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP\"},{\"Repositories/repo_id\":\"HDP-UTILS\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP-UTILS\"}],\"OperatingSystems/os_type\":\"redhat6\"}]");
     repoVersionEntity.setStack(stackEntity);
     repoVersionEntity.setVersion("2.2.2.3");
     repoVersionDao.create(repoVersionEntity);

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
index bd8be3b..9da66f2 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
@@ -670,8 +670,10 @@ public class OrmTestHelper {
 
     if (repositoryVersion == null) {
       try {
+        String operatingSystems = "[{\"OperatingSystems/ambari_managed_repositories\":\"true\",\"repositories\":[{\"Repositories/repo_id\":\"HDP\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP\"},{\"Repositories/repo_id\":\"HDP-UTILS\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP-UTILS\"}],\"OperatingSystems/os_type\":\"redhat6\"}]";
+
         repositoryVersion = repositoryVersionDAO.create(stackEntity, version,
-            String.valueOf(System.currentTimeMillis()) + uniqueCounter.incrementAndGet(), "");
+            String.valueOf(System.currentTimeMillis()) + uniqueCounter.incrementAndGet(), operatingSystems);
       } catch (Exception ex) {
         LOG.error("Caught exception", ex);
 


[47/49] ambari git commit: AMBARI-22521. Log Search: Adding new dynamic field for service logs (oleewere)

Posted by rl...@apache.org.
AMBARI-22521. Log Search: Adding new dynamic field for service logs (oleewere)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 74bc7401cdeeec5fed8f0ba28f68d4e05d83af62
Parents: 1d9985c
Author: Oliver Szabo <ol...@gmail.com>
Authored: Mon Nov 27 17:40:04 2017 +0100
Committer: Oliver Szabo <ol...@gmail.com>
Committed: Mon Nov 27 18:06:16 2017 +0100

----------------------------------------------------------------------
 .../configsets/hadoop_logs/conf/managed-schema     |  2 ++
 .../ambari/logsearch/solr/SolrConstants.java       |  1 +
 .../logsearch/solr/model/SolrServiceLogData.java   | 17 +++++++++++++++++
 3 files changed, 20 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/74bc7401/ambari-logsearch/ambari-logsearch-server/src/main/configsets/hadoop_logs/conf/managed-schema
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/configsets/hadoop_logs/conf/managed-schema b/ambari-logsearch/ambari-logsearch-server/src/main/configsets/hadoop_logs/conf/managed-schema
index c6f498b..93b2d6b 100644
--- a/ambari-logsearch/ambari-logsearch-server/src/main/configsets/hadoop_logs/conf/managed-schema
+++ b/ambari-logsearch/ambari-logsearch-server/src/main/configsets/hadoop_logs/conf/managed-schema
@@ -115,6 +115,8 @@
   <dynamicField name='std_*' type="text_std_token_lower_case" multiValued="false" stored="false"/>
   <dynamicField name='key_*' type="key_lower_case" multiValued="false" stored="false"/>
   <dynamicField name="ws_*" type="text_ws" multiValued="false" omitNorms="false" stored="false"/>
+  <dynamicField name="sdi_*" type="text_ws" omitNorms="false" multiValued="false" stored="true"/>
+
   <copyField source="log_message" dest="key_log_message"/>
 
 </schema>

http://git-wip-us.apache.org/repos/asf/ambari/blob/74bc7401/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/solr/SolrConstants.java
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/solr/SolrConstants.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/solr/SolrConstants.java
index 60fc1a3..6554bcf 100644
--- a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/solr/SolrConstants.java
+++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/solr/SolrConstants.java
@@ -66,6 +66,7 @@ public class SolrConstants {
     public static final String STORED_TOKEN_DYNAMIC_FIELDS = "std_*";
     public static final String KEY_DYNAMIC_FIELDS = "key_*";
     public static final String WS_DYNAMIC_FIELDS = "ws_*";
+    public static final String SDI_DYNAMIC_FIELDS = "sdi_*";
   }
 
   public class AuditLogConstants {

http://git-wip-us.apache.org/repos/asf/ambari/blob/74bc7401/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/solr/model/SolrServiceLogData.java
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/solr/model/SolrServiceLogData.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/solr/model/SolrServiceLogData.java
index c6fdba3..224ed8c 100644
--- a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/solr/model/SolrServiceLogData.java
+++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/solr/model/SolrServiceLogData.java
@@ -22,6 +22,7 @@ import org.apache.ambari.logsearch.model.response.ServiceLogData;
 import org.apache.solr.client.solrj.beans.Field;
 
 import java.util.Date;
+import java.util.Map;
 
 import static org.apache.ambari.logsearch.solr.SolrConstants.ServiceLogConstants.*;
 
@@ -48,6 +49,9 @@ public class SolrServiceLogData extends SolrCommonLogData implements ServiceLogD
   @Field(HOST)
   private String host;
 
+  @Field(SDI_DYNAMIC_FIELDS)
+  private Map<String, Object> sdiDynamicFields;
+
   @Override
   public String getPath() {
     return path;
@@ -117,4 +121,17 @@ public class SolrServiceLogData extends SolrCommonLogData implements ServiceLogD
   public void setLevel(String level) {
     this.level = level;
   }
+
+  public void setSdiDynamicFields(Map<String, Object> sdiDynamicFields) {
+    this.sdiDynamicFields = sdiDynamicFields;
+  }
+
+  @Override
+  public Map<String, Object> getAllDynamicFields() {
+    Map<String, Object> dynamicFieldsMap = super.getAllDynamicFields();
+    if (sdiDynamicFields != null) {
+      dynamicFieldsMap.putAll(sdiDynamicFields);
+    }
+    return dynamicFieldsMap;
+  }
 }


[04/49] ambari git commit: AMBARI-22464. disable hive.auto.convert.sortmerge.join in Hive configs in Ambari.(vbrodetskyi)

Posted by rl...@apache.org.
AMBARI-22464. disable hive.auto.convert.sortmerge.join in Hive configs in Ambari.(vbrodetskyi)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: e95d34300225b57bdba141ec085173c4e8f41314
Parents: 1d1c556
Author: Vitaly Brodetskyi <vb...@hortonworks.com>
Authored: Fri Nov 17 15:15:48 2017 +0200
Committer: Vitaly Brodetskyi <vb...@hortonworks.com>
Committed: Fri Nov 17 15:15:48 2017 +0200

----------------------------------------------------------------------
 .../common-services/HIVE/0.12.0.2.0/configuration/hive-site.xml    | 2 +-
 .../stacks/HDP/2.1/services/HIVE/configuration/hive-site.xml       | 2 +-
 .../stacks/HDP/2.2/services/HIVE/configuration/hive-site.xml       | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/e95d3430/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/configuration/hive-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/configuration/hive-site.xml b/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/configuration/hive-site.xml
index 5520c10..b7af252 100644
--- a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/configuration/hive-site.xml
+++ b/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/configuration/hive-site.xml
@@ -287,7 +287,7 @@ limitations under the License.
   </property>
   <property>
     <name>hive.auto.convert.sortmerge.join</name>
-    <value>true</value>
+    <value>false</value>
     <description>Will the join be automatically converted to a sort-merge join, if the joined tables pass
       the criteria for sort-merge join.
     </description>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e95d3430/ambari-server/src/main/resources/stacks/HDP/2.1/services/HIVE/configuration/hive-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.1/services/HIVE/configuration/hive-site.xml b/ambari-server/src/main/resources/stacks/HDP/2.1/services/HIVE/configuration/hive-site.xml
index 1c8f475..ea6ad25 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.1/services/HIVE/configuration/hive-site.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.1/services/HIVE/configuration/hive-site.xml
@@ -258,7 +258,7 @@ limitations under the License.
   </property>
   <property>
     <name>hive.auto.convert.sortmerge.join</name>
-    <value>true</value>
+    <value>false</value>
     <description>Will the join be automatically converted to a sort-merge join, if the joined tables pass
       the criteria for sort-merge join.
     </description>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e95d3430/ambari-server/src/main/resources/stacks/HDP/2.2/services/HIVE/configuration/hive-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/HIVE/configuration/hive-site.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/HIVE/configuration/hive-site.xml
index 2073832..0944252 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/HIVE/configuration/hive-site.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/HIVE/configuration/hive-site.xml
@@ -696,7 +696,7 @@ limitations under the License.
   </property>
   <property>
     <name>hive.auto.convert.sortmerge.join</name>
-    <value>true</value>
+    <value>false</value>
     <description>Will the join be automatically converted to a sort-merge join, if the joined tables pass the criteria for sort-merge join.</description>
     <on-ambari-upgrade add="true"/>
   </property>


[23/49] ambari git commit: AMBARI-22500. Modify AMBARI-22387 to Check for LZO + No Opt-in (dlysnichenko)

Posted by rl...@apache.org.
AMBARI-22500. Modify AMBARI-22387 to Check for LZO + No Opt-in (dlysnichenko)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: cadbf3542ce9e8ffad2aa32668518cb07464234d
Parents: b1acd1d
Author: Lisnichenko Dmitro <dl...@hortonworks.com>
Authored: Wed Nov 22 17:44:07 2017 +0200
Committer: Lisnichenko Dmitro <dl...@hortonworks.com>
Committed: Wed Nov 22 17:44:36 2017 +0200

----------------------------------------------------------------------
 .../java/org/apache/ambari/server/checks/LZOCheck.java |  6 +++++-
 .../org/apache/ambari/server/checks/LZOCheckTest.java  | 13 ++++++++++---
 2 files changed, 15 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/cadbf354/ambari-server/src/main/java/org/apache/ambari/server/checks/LZOCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/LZOCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/LZOCheck.java
index 9c0286b..1eaacea 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/LZOCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/LZOCheck.java
@@ -52,6 +52,9 @@ public class LZOCheck extends AbstractCheckDescriptor {
    */
   @Override
   public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) throws AmbariException {
+    if (config.getGplLicenseAccepted()){
+      return;
+    }
     List<String> errorMessages = new ArrayList<>();
     PrereqCheckStatus checkStatus = PrereqCheckStatus.WARNING;
 
@@ -66,7 +69,8 @@ public class LZOCheck extends AbstractCheckDescriptor {
     }
 
     if (!errorMessages.isEmpty()) {
-      prerequisiteCheck.setFailReason(StringUtils.join(errorMessages, "You have LZO codec enabled in the core-site config of your cluster. LZO is no longer installed automatically. " +
+      prerequisiteCheck.setFailReason(StringUtils.join(errorMessages, "You have LZO codec enabled in the core-site config of your cluster. " +
+          "You have to accept GPL license during ambari-server setup to have LZO installed automatically. " +
           "If any hosts require LZO, it should be installed before starting the upgrade. " +
           "Consult Ambari documentation for instructions on how to do this."));
       prerequisiteCheck.getFailedOn().add("LZO");

http://git-wip-us.apache.org/repos/asf/ambari/blob/cadbf354/ambari-server/src/test/java/org/apache/ambari/server/checks/LZOCheckTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/LZOCheckTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/LZOCheckTest.java
index e50e936..13f52a5 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/checks/LZOCheckTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/LZOCheckTest.java
@@ -60,6 +60,9 @@ public class LZOCheckTest {
   @Mock
   private RepositoryVersionEntity m_repositoryVersion;
 
+  @Mock
+  private Configuration configuration;
+
   final Map<String, Service> m_services = new HashMap<>();
 
   @Before
@@ -70,8 +73,7 @@ public class LZOCheckTest {
         return clusters;
       }
     };
-    Configuration config = Mockito.mock(Configuration.class);
-    lZOCheck.config = config;
+    lZOCheck.config = configuration;
 
     m_services.clear();
 
@@ -99,7 +101,6 @@ public class LZOCheckTest {
   public void testPerform() throws Exception {
     final Cluster cluster = Mockito.mock(Cluster.class);
     final Map<String, Service> services = new HashMap<>();
-    final Service service = Mockito.mock(Service.class);
 
     Mockito.when(cluster.getServices()).thenReturn(services);
     Mockito.when(cluster.getClusterId()).thenReturn(1L);
@@ -115,6 +116,7 @@ public class LZOCheckTest {
     Mockito.when(cluster.getConfig(Mockito.anyString(), Mockito.anyString())).thenReturn(config);
     final Map<String, String> properties = new HashMap<>();
     Mockito.when(config.getProperties()).thenReturn(properties);
+    Mockito.when(configuration.getGplLicenseAccepted()).thenReturn(false);
 
     PrerequisiteCheck check = new PrerequisiteCheck(null, null);
     lZOCheck.perform(check, new PrereqCheckRequest("cluster"));
@@ -141,5 +143,10 @@ public class LZOCheckTest {
     check = new PrerequisiteCheck(null, null);
     lZOCheck.perform(check, new PrereqCheckRequest("cluster"));
     Assert.assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
+
+    Mockito.when(configuration.getGplLicenseAccepted()).thenReturn(true);
+    check = new PrerequisiteCheck(null, null);
+    lZOCheck.perform(check, new PrereqCheckRequest("cluster"));
+    Assert.assertEquals(PrereqCheckStatus.PASS, check.getStatus());
   }
 }


[31/49] ambari git commit: AMBARI-22496. Admin View - Manage Versions page should show HDP-GPL repo if necessary (vsubramanian)

Posted by rl...@apache.org.
AMBARI-22496. Admin View - Manage Versions page should show HDP-GPL repo if necessary (vsubramanian)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 9fc7223df9a50fe69f4d8884939718b3f3bcf31b
Parents: 1d4cbc8
Author: Vivek Ratnavel Subramanian <vi...@gmail.com>
Authored: Wed Nov 22 17:01:15 2017 -0800
Committer: Vivek Ratnavel Subramanian <vi...@gmail.com>
Committed: Wed Nov 22 17:01:15 2017 -0800

----------------------------------------------------------------------
 .../stackVersions/StackVersionsEditCtrl.js      | 27 ++++++++++++++++++-
 .../ui/admin-web/app/scripts/services/Stack.js  | 14 ++++++++++
 .../views/stackVersions/stackVersionPage.html   | 28 +++++++++++---------
 3 files changed, 55 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9fc7223d/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js
index 09e3c28..542772e 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js
@@ -33,6 +33,15 @@ angular.module('ambariAdminConsole')
     display_name: ''
   };
   $scope.defaulfOSRepos = {}; // a copy of initial loaded repo info for "changed" check later
+  $scope.isGPLAccepted = false;
+
+  $scope.isGPLRepo = function (repository) {
+    return repository.Repositories.tags.indexOf('GPL') >= 0;
+  };
+
+  $scope.showRepo = function (repository) {
+    return $scope.isGPLAccepted || !$scope.isGPLRepo(repository);
+  };
 
   $scope.loadStackVersionInfo = function () {
     return Stack.getRepo($routeParams.versionId, $routeParams.stackName).then(function (response) {
@@ -67,6 +76,9 @@ angular.module('ambariAdminConsole')
       // load supported os type base on stack version
       $scope.afterStackVersionRead();
 
+      // Load GPL license accepted value
+      $scope.fetchGPLLicenseAccepted();
+
       // if user reach here from UI click, repo status should be cached
       // otherwise re-fetch repo status from cluster end point.
       $scope.repoStatus = Cluster.repoStatusCache[$scope.id];
@@ -85,6 +97,15 @@ angular.module('ambariAdminConsole')
   };
 
   /**
+   * Load GPL License Accepted value
+   */
+  $scope.fetchGPLLicenseAccepted = function () {
+    Stack.getGPLLicenseAccepted().then(function (data) {
+      $scope.isGPLAccepted = data === 'true';
+    })
+  };
+
+  /**
    * Load supported OS list
    */
   $scope.afterStackVersionRead = function () {
@@ -170,7 +191,11 @@ angular.module('ambariAdminConsole')
 
   $scope.updateRepoVersions = function () {
     var skip = $scope.skipValidation || $scope.useRedhatSatellite;
-    return Stack.validateBaseUrls(skip, $scope.osList, $scope.upgradeStack).then(function (invalidUrls) {
+    // Filter out repositories that are not shown in the UI
+    var osList = Object.assign([], $scope.osList).map(function(os) {
+      return Object.assign({}, os, {repositories: os.repositories.filter(function(repo) { return $scope.showRepo(repo); })});
+    });
+    return Stack.validateBaseUrls(skip, osList, $scope.upgradeStack).then(function (invalidUrls) {
       if (invalidUrls.length === 0) {
         Stack.updateRepo($scope.upgradeStack.stack_name, $scope.upgradeStack.stack_version, $scope.id, $scope.updateObj).then(function () {
           Alert.success($t('versions.alerts.versionEdited', {

http://git-wip-us.apache.org/repos/asf/ambari/blob/9fc7223d/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js
index 8003dd1..90f4f48 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js
@@ -87,6 +87,20 @@ angular.module('ambariAdminConsole')
       return deferred.promise;
     },
 
+    getGPLLicenseAccepted: function() {
+      var deferred = $q.defer();
+
+      $http.get(Settings.baseUrl + '/services/AMBARI/components/AMBARI_SERVER?fields=RootServiceComponents/properties/gpl.license.accepted&minimal_response=true', {mock: 'true'})
+        .then(function(data) {
+          deferred.resolve(data.data.RootServiceComponents.properties['gpl.license.accepted']);
+        })
+        .catch(function(data) {
+          deferred.reject(data);
+        });
+
+      return deferred.promise;
+    },
+    
     allPublicStackVersions: function() {
       var self = this;
       var url = '/version_definitions?fields=VersionDefinition/stack_default,VersionDefinition/type,' +

http://git-wip-us.apache.org/repos/asf/ambari/blob/9fc7223d/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
index ea30824..da1ab3f 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
@@ -181,20 +181,22 @@
                 <div class="col-sm-9">
                   <div class="form-group repo-name-url {{repository.Repositories.repo_name}}"
                        ng-class="{'has-error': repository.hasError }" ng-repeat="repository in os.repositories">
-                    <span class="repo-name-label control-label col-sm-3">{{repository.Repositories.repo_id}}</span>
-                    <div class="col-sm-7 repo-url">
-                      <input type="text" class="form-control"
-                             placeholder="{{(repository.Repositories.repo_name.indexOf('UTILS') < 0 )?('versions.repository.placeholder' | translate) : ''}}"
-                             ng-model="repository.Repositories.base_url"
-                             ng-change="onRepoUrlChange(repository)" ng-disabled="useRedhatSatellite">
+                    <div ng-if="showRepo(repository)">
+                      <span class="repo-name-label control-label col-sm-3">{{repository.Repositories.repo_id}}</span>
+                      <div class="col-sm-7 repo-url">
+                        <input type="text" class="form-control"
+                               placeholder="{{(repository.Repositories.repo_name.indexOf('UTILS') < 0 )?('versions.repository.placeholder' | translate) : ''}}"
+                               ng-model="repository.Repositories.base_url"
+                               ng-change="onRepoUrlChange(repository)" ng-disabled="useRedhatSatellite">
+                      </div>
+                      <i class="fa fa-undo orange-icon cursor-pointer"
+                         ng-if="selectedOption.index == 1 && repository.Repositories.base_url != repository.Repositories.initial_base_url
+                         || selectedOption.index == 2 && repository.Repositories.base_url != ''
+                         || editController && repository.Repositories.base_url != repository.Repositories.initial_base_url"
+                         ng-click="undoChange(repository)"
+                         tooltip-html-unsafe="{{'common.undo' | translate}}"
+                         aria-hidden="true"></i>
                     </div>
-                    <i class="fa fa-undo orange-icon cursor-pointer"
-                       ng-if="selectedOption.index == 1 && repository.Repositories.base_url != repository.Repositories.initial_base_url
-                       || selectedOption.index == 2 && repository.Repositories.base_url != ''
-                       || editController && repository.Repositories.base_url != repository.Repositories.initial_base_url"
-                       ng-click="undoChange(repository)"
-                       tooltip-html-unsafe="{{'common.undo' | translate}}"
-                       aria-hidden="true"></i>
                   </div>
                 </div>
                 <div class="col-sm-1 remove-icon" ng-click="removeOS()" ng-class="{'disabled' : useRedhatSatellite}"><i


[11/49] ambari git commit: AMBARI-22478 Ambari 3.0: Implement new design for Admin View: Edit cluster name. (atkach)

Posted by rl...@apache.org.
AMBARI-22478 Ambari 3.0: Implement new design for Admin View: Edit cluster name. (atkach)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: af8c40178f4caf56404d688ec56c252e25de3aef
Parents: cc535c8
Author: Andrii Tkach <at...@apache.org>
Authored: Mon Nov 20 16:18:27 2017 +0200
Committer: Andrii Tkach <at...@apache.org>
Committed: Mon Nov 20 16:18:27 2017 +0200

----------------------------------------------------------------------
 .../controllers/ClusterInformationCtrl.js       |  45 +++++++-
 .../app/styles/cluster-information.css          |  13 ++-
 .../admin-web/app/views/clusterInformation.html |  29 +++++-
 .../controllers/ClusterInformationCtrl_test.js  | 102 +++++++++++++++++++
 4 files changed, 176 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/af8c4017/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ClusterInformationCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ClusterInformationCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ClusterInformationCtrl.js
index 60a610c..059f399 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ClusterInformationCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ClusterInformationCtrl.js
@@ -18,16 +18,22 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('ClusterInformationCtrl', ['$scope', '$http', '$location', 'Cluster', '$routeParams', '$translate', '$rootScope',
-function($scope, $http, $location, Cluster, $routeParams, $translate, $rootScope) {
+.controller('ClusterInformationCtrl',
+['$scope', '$http', '$location', 'Cluster', '$routeParams', '$translate', '$rootScope', 'ConfirmationModal', 'Alert',
+function($scope, $http, $location, Cluster, $routeParams, $translate, $rootScope, ConfirmationModal, Alert) {
   var $t = $translate.instant;
   $scope.isDataLoaded = false;
+  $scope.edit = {
+    clusterName: null
+  };
+  $scope.isClusterNameEdited = false;
 
   $scope.$watch(function() {
     return $rootScope.cluster;
   }, function() {
     $scope.cluster = $rootScope.cluster;
     if ($scope.cluster) {
+      $scope.edit.clusterName = $scope.cluster.Clusters.cluster_name;
       $scope.getBlueprint();
     }
   }, true);
@@ -62,4 +68,39 @@ function($scope, $http, $location, Cluster, $routeParams, $translate, $rootScope
       a.click();
     }
   };
+
+  $scope.toggleSaveButton = function() {
+    var value = $scope.edit.clusterName;
+    $scope.isClusterNameEdited = (value !== null && $scope.cluster.Clusters.cluster_name !== value);
+  };
+
+  $scope.confirmClusterNameChange = function() {
+    ConfirmationModal.show(
+      $t('common.clusterNameChangeConfirmation.title'),
+      $t('common.clusterNameChangeConfirmation.message', {
+        clusterName: $scope.edit.clusterName
+      })
+    )
+      .then(function () {
+        $scope.saveClusterName();
+      }).catch(function () {
+      // user clicked cancel
+      $scope.edit.clusterName = $scope.cluster.Clusters.cluster_name;
+      $scope.toggleSaveButton();
+    });
+  };
+
+  $scope.saveClusterName = function() {
+    var oldClusterName = $scope.cluster.Clusters.cluster_name,
+        newClusterName = $scope.edit.clusterName;
+
+    Cluster.editName(oldClusterName, newClusterName).then(function(data) {
+      $scope.cluster.Clusters.cluster_name = newClusterName;
+      $scope.edit.clusterName = newClusterName;
+      $scope.toggleSaveButton();
+      Alert.success($t('common.alerts.clusterRenamed', {clusterName: newClusterName}));
+    }).catch(function(data) {
+      Alert.error($t('common.alerts.cannotRenameCluster', {clusterName: newClusterName}), data.data.message);
+    });
+  };
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/af8c4017/ambari-admin/src/main/resources/ui/admin-web/app/styles/cluster-information.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/cluster-information.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/cluster-information.css
index 63f4150..64e9ecb 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/cluster-information.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/cluster-information.css
@@ -28,19 +28,18 @@
   vertical-align: text-top;
 }
 
-#cluster-information .cluster-name label {
-  font-weight: normal;
+#cluster-information .cluster-name input {
+  width: 75%;
 }
 
-#cluster-information .dev-blueprint {
-  line-height: 35px;
+#cluster-information .cluster-name button {
+  margin-top: -34px;
 }
 
-#cluster-information .dev-blueprint span {
-  vertical-align: text-top;
+#cluster-information .cluster-name input.edited {
+  background-color: #fdfbdd;
 }
 
-
 #cluster-information .welcome-header {
   margin: -15px;
   padding: 15px 15px 40px 15px;

http://git-wip-us.apache.org/repos/asf/ambari/blob/af8c4017/ambari-admin/src/main/resources/ui/admin-web/app/views/clusterInformation.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/clusterInformation.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/clusterInformation.html
index 6334d06..ead73c3 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/clusterInformation.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/clusterInformation.html
@@ -39,12 +39,33 @@
   </div>
 
   <div ng-show="cluster.Clusters.provisioning_state === 'INSTALLED'">
-    <div class="row">
-      <div class="form-group col-xs-3 cluster-name">
+    <form class="row" name="editClusterNameForm" ng-submit="confirmClusterNameChange()">
+      <div class="form-group col-xs-4 cluster-name"
+           ng-class="{'has-error': editClusterNameForm.clusterName.$invalid}">
         <label for="clusterName">{{'views.clusterName' | translate}}*</label>
-        <input type="text" class="form-control" id="clusterName" ng-model="cluster.Clusters.cluster_name">
+        <input type="text"
+               class="form-control"
+               id="clusterName"
+               name="clusterName"
+               ng-change="toggleSaveButton()"
+               ng-model="edit.clusterName"
+               required
+               autofocus
+               ng-pattern="/^\w*$/"
+               ng-maxlength="80"
+               tooltip="{{'common.renameClusterTip' | translate}}"
+               tooltip-trigger="focus"
+               tooltip-placement="bottom"
+               ng-class="{edited: isClusterNameEdited}">
+        <button
+          type="submit"
+          ng-class="{'disabled': editClusterNameForm.clusterName.$invalid}"
+          class="btn btn-default pull-right"
+          ng-show="isClusterNameEdited">
+          {{'common.controls.save' | translate}}
+        </button>
       </div>
-    </div>
+    </form>
     <div>
       <div class="row dev-blueprint">
         <div class="col-sm-11"><span>{{'clusters.devBlueprint' | translate}}</span></div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/af8c4017/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/ClusterInformationCtrl_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/ClusterInformationCtrl_test.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/ClusterInformationCtrl_test.js
new file mode 100644
index 0000000..2972e7f
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/ClusterInformationCtrl_test.js
@@ -0,0 +1,102 @@
+/**
+ * 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.
+ */
+
+describe('ClusterInformationCtrl', function() {
+  beforeEach(module('ambariAdminConsole'));
+
+  var ctrl, $scope, Cluster, deferred, ConfirmationModal;
+
+  beforeEach(inject(function($controller, $rootScope, _Cluster_, _$q_, _ConfirmationModal_){
+    // The injector unwraps the underscores (_) from around the parameter names when matching
+    Cluster = _Cluster_;
+    ConfirmationModal = _ConfirmationModal_;
+    deferred = _$q_.defer();
+    $scope = $rootScope.$new();
+    $scope.$apply();
+    ctrl = $controller('ClusterInformationCtrl', {
+      $scope: $scope
+    });
+
+    spyOn(Cluster, 'getBlueprint').andReturn(deferred.promise);
+    spyOn(Cluster, 'editName').andReturn(deferred.promise);
+    spyOn(ConfirmationModal, 'show').andReturn(deferred.promise);
+  }));
+
+  describe('#getBlueprint', function() {
+    it('Cluster.getBlueprint should be called', function() {
+      $scope.cluster = {
+        Clusters: {
+          cluster_name: 'c1'
+        }
+      };
+      $scope.getBlueprint();
+      expect(Cluster.getBlueprint).toHaveBeenCalled();
+    });
+  });
+
+  describe('#toggleSaveButton', function() {
+    beforeEach(function() {
+      $scope.cluster = {
+        Clusters: {
+          cluster_name: 'c1'
+        }
+      };
+    });
+
+    it('isClusterNameEdited should be true', function() {
+      $scope.edit = {
+        clusterName: 'c2'
+      };
+      $scope.toggleSaveButton();
+      expect($scope.isClusterNameEdited).toBeTruthy();
+    });
+
+    it('isClusterNameEdited should be false', function() {
+      $scope.edit = {
+        clusterName: 'c1'
+      };
+      $scope.toggleSaveButton();
+      expect($scope.isClusterNameEdited).toBeFalsy();
+    });
+  });
+
+  describe('#confirmClusterNameChange', function() {
+    it('ConfirmationModal.show should be called', function() {
+      $scope.edit = {
+        clusterName: 'c1'
+      };
+      $scope.confirmClusterNameChange();
+      expect(ConfirmationModal.show).toHaveBeenCalled();
+    });
+  });
+
+  describe('#saveClusterName', function() {
+    it('Cluster.editName should be called', function() {
+      $scope.edit = {
+        clusterName: 'c1'
+      };
+      $scope.cluster = {
+        Clusters: {
+          cluster_name: 'c2'
+        }
+      };
+      $scope.saveClusterName();
+      expect(Cluster.editName).toHaveBeenCalledWith('c2', 'c1');
+    });
+  });
+});


[48/49] ambari git commit: AMBARI-22524 : Journal Node start failing when AMS is installed during BP deploy. (avijayan)

Posted by rl...@apache.org.
AMBARI-22524 : Journal Node start failing when AMS is installed during BP deploy. (avijayan)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 0b98ccd75c54c147638c7380d59a067afbea8145
Parents: 74bc740
Author: Aravindan Vijayan <av...@hortonworks.com>
Authored: Mon Nov 27 11:45:40 2017 -0800
Committer: Aravindan Vijayan <av...@hortonworks.com>
Committed: Mon Nov 27 11:45:40 2017 -0800

----------------------------------------------------------------------
 .../ambari-metrics-hadoop-sink/pom.xml          |  3 ++-
 .../timeline/HadoopTimelineMetricsSink.java     |  6 +++---
 .../timeline/HadoopTimelineMetricsSinkTest.java | 21 ++++++++++----------
 3 files changed, 16 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/0b98ccd7/ambari-metrics/ambari-metrics-hadoop-sink/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-hadoop-sink/pom.xml b/ambari-metrics/ambari-metrics-hadoop-sink/pom.xml
index 23f9ba9..a9d342f 100644
--- a/ambari-metrics/ambari-metrics-hadoop-sink/pom.xml
+++ b/ambari-metrics/ambari-metrics-hadoop-sink/pom.xml
@@ -31,6 +31,7 @@ limitations under the License.
   <packaging>jar</packaging>
   <properties>
     <sinkJarName>${project.artifactId}-with-common-${project.version}.jar</sinkJarName>
+    <hadoop.version>3.0.0-beta1</hadoop.version>
   </properties>
 
 
@@ -141,7 +142,7 @@ limitations under the License.
     <dependency>
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-common</artifactId>
-      <version>2.4.0</version>
+      <version>${hadoop.version}</version>
       <scope>compile</scope>
     </dependency>
     <dependency>

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b98ccd7/ambari-metrics/ambari-metrics-hadoop-sink/src/main/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSink.java
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-hadoop-sink/src/main/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSink.java b/ambari-metrics/ambari-metrics-hadoop-sink/src/main/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSink.java
index a290ced..bbc9617 100644
--- a/ambari-metrics/ambari-metrics-hadoop-sink/src/main/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSink.java
+++ b/ambari-metrics/ambari-metrics-hadoop-sink/src/main/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSink.java
@@ -17,7 +17,8 @@
  */
 package org.apache.hadoop.metrics2.sink.timeline;
 
-import org.apache.commons.configuration.SubsetConfiguration;
+import org.apache.commons.configuration2.SubsetConfiguration;
+import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
 import org.apache.commons.lang.StringUtils;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
@@ -34,7 +35,6 @@ import java.io.IOException;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -143,7 +143,7 @@ public class HadoopTimelineMetricsSink extends AbstractTimelineMetricsSink imple
     metricsCache = new TimelineMetricsCache(maxRowCacheSize,
       metricsSendInterval, conf.getBoolean(SKIP_COUNTER_TRANSFROMATION, true));
 
-    conf.setListDelimiter(',');
+    conf.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
     Iterator<String> it = (Iterator<String>) conf.getKeys();
     while (it.hasNext()) {
       String propertyName = it.next();

http://git-wip-us.apache.org/repos/asf/ambari/blob/0b98ccd7/ambari-metrics/ambari-metrics-hadoop-sink/src/test/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSinkTest.java
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-hadoop-sink/src/test/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSinkTest.java b/ambari-metrics/ambari-metrics-hadoop-sink/src/test/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSinkTest.java
index 30c5c23..6bb6454 100644
--- a/ambari-metrics/ambari-metrics-hadoop-sink/src/test/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSinkTest.java
+++ b/ambari-metrics/ambari-metrics-hadoop-sink/src/test/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSinkTest.java
@@ -19,7 +19,8 @@
 package org.apache.hadoop.metrics2.sink.timeline;
 
 import com.google.gson.Gson;
-import org.apache.commons.configuration.SubsetConfiguration;
+import org.apache.commons.configuration2.SubsetConfiguration;
+import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
 import org.apache.commons.io.IOUtils;
 import org.apache.hadoop.metrics2.AbstractMetric;
 import org.apache.hadoop.metrics2.MetricType;
@@ -74,7 +75,7 @@ import static org.powermock.api.easymock.PowerMock.replayAll;
 import static org.powermock.api.easymock.PowerMock.verifyAll;
 
 @RunWith(PowerMockRunner.class)
-@PrepareForTest({AbstractTimelineMetricsSink.class, HttpURLConnection.class})
+@PrepareForTest({AbstractTimelineMetricsSink.class, HttpURLConnection.class, SubsetConfiguration.class})
 public class HadoopTimelineMetricsSinkTest {
   Gson gson = new Gson();
 
@@ -84,7 +85,7 @@ public class HadoopTimelineMetricsSinkTest {
   }
 
   @Test
-  @PrepareForTest({URL.class, OutputStream.class, AbstractTimelineMetricsSink.class, HttpURLConnection.class, TimelineMetric.class, HadoopTimelineMetricsSink.class})
+  @PrepareForTest({URL.class, OutputStream.class, AbstractTimelineMetricsSink.class, HttpURLConnection.class, TimelineMetric.class, HadoopTimelineMetricsSink.class, SubsetConfiguration.class})
   public void testPutMetrics() throws Exception {
     HadoopTimelineMetricsSink sink = new HadoopTimelineMetricsSink();
 
@@ -102,7 +103,7 @@ public class HadoopTimelineMetricsSinkTest {
     OutputStream os = PowerMock.createNiceMock(OutputStream.class);
     expect(connection.getOutputStream()).andReturn(os).anyTimes();
 
-    SubsetConfiguration conf = createNiceMock(SubsetConfiguration.class);
+    SubsetConfiguration conf = PowerMock.createNiceMock(SubsetConfiguration.class);
     expect(conf.getString("slave.host.name")).andReturn("localhost").anyTimes();
     expect(conf.getParent()).andReturn(null).anyTimes();
     expect(conf.getPrefix()).andReturn("service").anyTimes();
@@ -116,7 +117,7 @@ public class HadoopTimelineMetricsSinkTest {
     expect(conf.getBoolean(eq(SET_INSTANCE_ID_PROPERTY), eq(false))).andReturn(true).anyTimes();
     expect(conf.getString(eq(INSTANCE_ID_PROPERTY), anyString())).andReturn("instanceId").anyTimes();
 
-    conf.setListDelimiter(eq(','));
+    conf.setListDelimiterHandler(new DefaultListDelimiterHandler(eq(',')));
     expectLastCall().anyTimes();
 
     expect(conf.getKeys()).andReturn(new Iterator() {
@@ -157,7 +158,7 @@ public class HadoopTimelineMetricsSinkTest {
     timelineMetric.setInstanceId(eq("instanceId"));
     EasyMock.expectLastCall();
 
-    replay(conf, record, metric);
+    replay(record, metric);
     replayAll();
 
     sink.init(conf);
@@ -179,7 +180,7 @@ public class HadoopTimelineMetricsSinkTest {
         .addMockedMethod("findLiveCollectorHostsFromKnownCollector")
         .addMockedMethod("emitMetrics").createNiceMock();
 
-    SubsetConfiguration conf = createNiceMock(SubsetConfiguration.class);
+    SubsetConfiguration conf = PowerMock.createNiceMock(SubsetConfiguration.class);
     expect(conf.getString("slave.host.name")).andReturn("localhost").anyTimes();
     expect(conf.getParent()).andReturn(null).anyTimes();
     expect(conf.getPrefix()).andReturn("service").anyTimes();
@@ -198,7 +199,7 @@ public class HadoopTimelineMetricsSinkTest {
     expect(sink.findLiveCollectorHostsFromKnownCollector("localhost2", "6188"))
             .andReturn(Collections.singletonList("localhost2")).anyTimes();
 
-    conf.setListDelimiter(eq(','));
+    conf.setListDelimiterHandler(new DefaultListDelimiterHandler(eq(',')));
     expectLastCall().anyTimes();
 
     expect(conf.getKeys()).andReturn(new Iterator() {
@@ -309,7 +310,7 @@ public class HadoopTimelineMetricsSinkTest {
         .addMockedMethod("findLiveCollectorHostsFromKnownCollector")
         .addMockedMethod("emitMetrics").createNiceMock();
 
-    SubsetConfiguration conf = createNiceMock(SubsetConfiguration.class);
+    SubsetConfiguration conf = PowerMock.createNiceMock(SubsetConfiguration.class);
     expect(conf.getString("slave.host.name")).andReturn("localhost").anyTimes();
     expect(conf.getParent()).andReturn(null).anyTimes();
     expect(conf.getPrefix()).andReturn("service").anyTimes();
@@ -326,7 +327,7 @@ public class HadoopTimelineMetricsSinkTest {
     expect(conf.getInt(eq(MAX_METRIC_ROW_CACHE_SIZE), anyInt())).andReturn(10).anyTimes();
     expect(conf.getInt(eq(METRICS_SEND_INTERVAL), anyInt())).andReturn(10).anyTimes();
 
-    conf.setListDelimiter(eq(','));
+    conf.setListDelimiterHandler(new DefaultListDelimiterHandler(eq(',')));
     expectLastCall().anyTimes();
 
     Set<String> rpcPortSuffixes = new HashSet<String>() {{


[25/49] ambari git commit: AMBARI-22472. Ambari Upgrade 2.5 -> 2.6 : Update NodeManager's HSI identity 'llap_zk_hive' and 'llap_task_hive' to use '/HIVE/HIVE_SERVER/hive_server_hive' reference instead of creating the same identity again.

Posted by rl...@apache.org.
AMBARI-22472. Ambari Upgrade 2.5 -> 2.6 : Update NodeManager's HSI identity 'llap_zk_hive' and 'llap_task_hive' to use '/HIVE/HIVE_SERVER/hive_server_hive' reference instead of creating the same identity again.


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 65ca08455f05b7c7e9352723f2bea21e86bc43e8
Parents: f343e8c
Author: Swapan Shridhar <ss...@hortonworks.com>
Authored: Tue Nov 21 15:57:44 2017 -0800
Committer: Swapan Shridhar <ss...@hortonworks.com>
Committed: Wed Nov 22 10:20:02 2017 -0800

----------------------------------------------------------------------
 .../server/upgrade/UpgradeCatalog260.java       | 142 +++++++++
 .../stacks/HDP/2.5/services/YARN/kerberos.json  |  12 +-
 .../stacks/HDP/2.6/services/YARN/kerberos.json  |  24 +-
 .../server/upgrade/UpgradeCatalog260Test.java   | 136 ++++++++-
 .../test_kerberos_descriptor_ranger_kms.json    | 286 +++++++++++++++++++
 5 files changed, 564 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/65ca0845/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
index 25635b6..a7e0654 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
@@ -45,7 +45,9 @@ import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
 import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosPrincipalType;
 import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -135,6 +137,20 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog {
   private static final String CORE_SITE = "core-site";
   public static final String AMS_SSL_CLIENT = "ams-ssl-client";
   public static final String METRIC_TRUSTSTORE_ALIAS = "ssl.client.truststore.alias";
+
+  private static final String HIVE_INTERACTIVE_SITE = "hive-interactive-site";
+  public static final String HIVE_LLAP_DAEMON_KEYTAB_FILE = "hive.llap.daemon.keytab.file";
+  public static final String HIVE_LLAP_ZK_SM_KEYTAB_FILE = "hive.llap.zk.sm.keytab.file";
+  public static final String HIVE_LLAP_TASK_KEYTAB_FILE = "hive.llap.task.keytab.file";
+  public static final String HIVE_SERVER_KERBEROS_PREFIX = "/HIVE/HIVE_SERVER/";
+  public static final String YARN_LLAP_ZK_HIVE_KERBEROS_IDENTITY = "llap_zk_hive";
+  public static final String YARN_LLAP_TASK_HIVE_KERBEROS_IDENTITY = "llap_task_hive";
+  public static final String HIVE_SERVER_HIVE_KERBEROS_IDENTITY = "hive_server_hive";
+
+  // Used to track whether YARN -> NODEMANAGER -> 'llap_zk_hive' kerberos descriptor was updated or not.
+  private List<String> yarnKerberosDescUpdatedList = new ArrayList<>();
+
+
   /**
    * Logger.
    */
@@ -497,6 +513,7 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog {
     ensureZeppelinProxyUserConfigs();
     updateKerberosDescriptorArtifacts();
     updateAmsConfigs();
+    updateHiveConfigs();
     updateHDFSWidgetDefinition();
     updateExistingRepositoriesToBeResolved();
   }
@@ -636,6 +653,7 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog {
         if (kerberosDescriptor != null) {
           fixRangerKMSKerberosDescriptor(kerberosDescriptor);
           fixIdentityReferences(getCluster(artifactEntity), kerberosDescriptor);
+          fixYarnHsiKerberosDescriptorAndSiteConfig(getCluster(artifactEntity), kerberosDescriptor);
 
           artifactEntity.setArtifactData(kerberosDescriptor.toMap());
           artifactDAO.merge(artifactEntity);
@@ -662,6 +680,130 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog {
     }
   }
 
+  /**
+   * Updates YARN's NM 'llap_zk_hive' kerberos descriptor as reference and the associated config
+   * hive-interactive-site/hive.llap.zk.sm.keytab.file
+   */
+  protected void fixYarnHsiKerberosDescriptorAndSiteConfig(Cluster cluster, KerberosDescriptor kerberosDescriptor) {
+    LOG.info("Updating YARN's HSI Kerberos Descriptor ....");
+
+    // Step 1. Get Hive -> HIVE_SERVER -> 'hive_server_hive' kerberos description for referencing later
+    KerberosServiceDescriptor hiveServiceDescriptor = kerberosDescriptor.getService("HIVE");
+    KerberosIdentityDescriptor hsh_identityDescriptor = null;
+    KerberosPrincipalDescriptor hsh_principalDescriptor = null;
+    KerberosKeytabDescriptor hsh_keytabDescriptor = null;
+    if (hiveServiceDescriptor != null) {
+      KerberosComponentDescriptor hiveServerKerberosDescriptor = hiveServiceDescriptor.getComponent("HIVE_SERVER");
+      if (hiveServerKerberosDescriptor != null) {
+        hsh_identityDescriptor = hiveServerKerberosDescriptor.getIdentity(HIVE_SERVER_HIVE_KERBEROS_IDENTITY);
+        if (hsh_identityDescriptor != null) {
+          LOG.info("  Retrieved HIVE->HIVE_SERVER kerberos descriptor. Name = " + hsh_identityDescriptor.getName());
+          hsh_principalDescriptor = hsh_identityDescriptor.getPrincipalDescriptor();
+          hsh_keytabDescriptor = hsh_identityDescriptor.getKeytabDescriptor();
+        }
+      }
+
+      // Step 2. Update YARN -> NODEMANAGER's : (1). 'llap_zk_hive' and (2). 'llap_task_hive' kerberos descriptor as reference to
+      // HIVE -> HIVE_SERVER -> 'hive_server_hive' (Same as YARN -> NODEMANAGER -> 'yarn_nodemanager_hive_server_hive')
+      if (hsh_principalDescriptor != null && hsh_keytabDescriptor != null) {
+        KerberosServiceDescriptor yarnServiceDescriptor = kerberosDescriptor.getService("YARN");
+        if (yarnServiceDescriptor != null) {
+          KerberosComponentDescriptor yarnNmKerberosDescriptor = yarnServiceDescriptor.getComponent("NODEMANAGER");
+          if (yarnNmKerberosDescriptor != null) {
+            String[] identities = {YARN_LLAP_ZK_HIVE_KERBEROS_IDENTITY, YARN_LLAP_TASK_HIVE_KERBEROS_IDENTITY};
+            for (String identity : identities) {
+              KerberosIdentityDescriptor identityDescriptor = yarnNmKerberosDescriptor.getIdentity(identity);
+
+              KerberosPrincipalDescriptor principalDescriptor = null;
+              KerberosKeytabDescriptor keytabDescriptor = null;
+              if (identityDescriptor != null) {
+                LOG.info("  Retrieved YARN->NODEMANAGER kerberos descriptor to be updated. Name = " + identityDescriptor.getName());
+                principalDescriptor = identityDescriptor.getPrincipalDescriptor();
+                keytabDescriptor = identityDescriptor.getKeytabDescriptor();
+
+                identityDescriptor.setReference(HIVE_SERVER_KERBEROS_PREFIX + hsh_identityDescriptor.getName());
+                LOG.info("    Updated '" + YARN_LLAP_ZK_HIVE_KERBEROS_IDENTITY + "' identity descriptor reference = '"
+                        + identityDescriptor.getReference() + "'");
+                principalDescriptor.setValue(null);
+                LOG.info("    Updated '" + YARN_LLAP_ZK_HIVE_KERBEROS_IDENTITY + "' principal descriptor value = '"
+                        + principalDescriptor.getValue() + "'");
+
+                // Updating keytabs now
+                keytabDescriptor.setFile(null);
+                LOG.info("    Updated '" + YARN_LLAP_ZK_HIVE_KERBEROS_IDENTITY + "' keytab descriptor file = '"
+                        + keytabDescriptor.getFile() + "'");
+                keytabDescriptor.setOwnerName(null);
+                LOG.info("    Updated '" + YARN_LLAP_ZK_HIVE_KERBEROS_IDENTITY + "' keytab descriptor owner name = '" + keytabDescriptor.getOwnerName() + "'");
+                keytabDescriptor.setOwnerAccess(null);
+                LOG.info("    Updated '" + YARN_LLAP_ZK_HIVE_KERBEROS_IDENTITY + "' keytab descriptor owner access = '" + keytabDescriptor.getOwnerAccess() + "'");
+                keytabDescriptor.setGroupName(null);
+                LOG.info("    Updated '" + YARN_LLAP_ZK_HIVE_KERBEROS_IDENTITY + "' keytab descriptor group name = '" + keytabDescriptor.getGroupName() + "'");
+                keytabDescriptor.setGroupAccess(null);
+                LOG.info("    Updated '" + YARN_LLAP_ZK_HIVE_KERBEROS_IDENTITY + "' keytab descriptor group access = '" + keytabDescriptor.getGroupAccess() + "'");
+
+                // Need this as trigger to update the HIVE_LLAP_ZK_SM_KEYTAB_FILE configs later.
+
+                // Get the keytab file 'config name'.
+                String[] splits = keytabDescriptor.getConfiguration().split("/");
+                if (splits != null && splits.length == 2) {
+                  updateYarnKerberosDescUpdatedList(splits[1]);
+                  LOG.info("    Updated 'yarnKerberosDescUpdatedList' = " + getYarnKerberosDescUpdatedList());
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  public void updateYarnKerberosDescUpdatedList(String val) {
+    yarnKerberosDescUpdatedList.add(val);
+  }
+
+  public List<String> getYarnKerberosDescUpdatedList() {
+    return yarnKerberosDescUpdatedList;
+  }
+
+  protected void updateHiveConfigs() throws AmbariException {
+    AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
+    Clusters clusters = ambariManagementController.getClusters();
+    if (clusters != null) {
+      Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
+      if (clusterMap != null && !clusterMap.isEmpty()) {
+        for (final Cluster cluster : clusterMap.values()) {
+          // Updating YARN->NodeManager kerebros descriptor : (1). 'llap_zk_hive' and (2). 'llap_task_hive''s associated configs
+          // hive-interactive-site/hive.llap.zk.sm.keytab.file and hive-interactive-site/hive.llap.task.keytab.file respectively,
+          // based on what hive-interactive-site/hive.llap.daemon.keytab.file has.
+          Config hsiSiteConfig = cluster.getDesiredConfigByType(HIVE_INTERACTIVE_SITE);
+          Map<String, String> hsiSiteConfigProperties = hsiSiteConfig.getProperties();
+          if (hsiSiteConfigProperties != null &&
+                  hsiSiteConfigProperties.containsKey(HIVE_LLAP_DAEMON_KEYTAB_FILE)) {
+            String[] identities = {HIVE_LLAP_ZK_SM_KEYTAB_FILE, HIVE_LLAP_TASK_KEYTAB_FILE};
+            Map<String, String> newProperties = new HashMap<>();
+            for (String identity : identities) {
+              // Update only if we were able to modify the corresponding kerberos descriptor,
+              // reflected in list 'getYarnKerberosDescUpdatedList'.
+              if (getYarnKerberosDescUpdatedList().contains(identity) && hsiSiteConfigProperties.containsKey(identity)) {
+                newProperties.put(identity, hsiSiteConfigProperties.get(HIVE_LLAP_DAEMON_KEYTAB_FILE));
+              }
+            }
+
+            // Update step.
+            if (newProperties.size() > 0) {
+              try {
+                updateConfigurationPropertiesForCluster(cluster, HIVE_INTERACTIVE_SITE, newProperties, true, false);
+                LOG.info("Updated HSI config(s) : " + newProperties.keySet() + " with value(s) = " + newProperties.values()+" respectively.");
+              } catch (AmbariException e) {
+                e.printStackTrace();
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
   protected void updateAmsConfigs() throws AmbariException {
     AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
     Clusters clusters = ambariManagementController.getClusters();

http://git-wip-us.apache.org/repos/asf/ambari/blob/65ca0845/ambari-server/src/main/resources/stacks/HDP/2.5/services/YARN/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.5/services/YARN/kerberos.json b/ambari-server/src/main/resources/stacks/HDP/2.5/services/YARN/kerberos.json
index fca14ab..8e285e9 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/services/YARN/kerberos.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/services/YARN/kerberos.json
@@ -102,21 +102,11 @@
             },
             {
               "name": "llap_zk_hive",
+              "reference": "/HIVE/HIVE_SERVER/hive_server_hive",
               "principal": {
-                "value": "hive/_HOST@${realm}",
-                "type" : "service",
                 "configuration": "hive-interactive-site/hive.llap.zk.sm.principal"
               },
               "keytab": {
-                "file": "${keytab_dir}/hive.llap.zk.sm.keytab",
-                "owner": {
-                  "name": "${yarn-env/yarn_user}",
-                  "access": "r"
-                },
-                "group": {
-                  "name": "${cluster-env/user_group}",
-                  "access": "r"
-                },
                 "configuration": "hive-interactive-site/hive.llap.zk.sm.keytab.file"
               },
               "when" : {

http://git-wip-us.apache.org/repos/asf/ambari/blob/65ca0845/ambari-server/src/main/resources/stacks/HDP/2.6/services/YARN/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.6/services/YARN/kerberos.json b/ambari-server/src/main/resources/stacks/HDP/2.6/services/YARN/kerberos.json
index e0417bf..bd6798c 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.6/services/YARN/kerberos.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.6/services/YARN/kerberos.json
@@ -107,21 +107,11 @@
             },
             {
               "name": "llap_task_hive",
+              "reference": "/HIVE/HIVE_SERVER/hive_server_hive",
               "principal": {
-                "value": "hive/_HOST@${realm}",
-                "type" : "service",
                 "configuration": "hive-interactive-site/hive.llap.task.principal"
               },
               "keytab": {
-                "file": "${keytab_dir}/hive.llap.task.keytab",
-                "owner": {
-                  "name": "${yarn-env/yarn_user}",
-                  "access": "r"
-                },
-                "group": {
-                  "name": "${cluster-env/user_group}",
-                  "access": "r"
-                },
                 "configuration": "hive-interactive-site/hive.llap.task.keytab.file"
               },
               "when" : {
@@ -130,21 +120,11 @@
             },
             {
               "name": "llap_zk_hive",
+              "reference": "/HIVE/HIVE_SERVER/hive_server_hive",
               "principal": {
-                "value": "hive/_HOST@${realm}",
-                "type" : "service",
                 "configuration": "hive-interactive-site/hive.llap.zk.sm.principal"
               },
               "keytab": {
-                "file": "${keytab_dir}/hive.llap.zk.sm.keytab",
-                "owner": {
-                  "name": "${yarn-env/yarn_user}",
-                  "access": "r"
-                },
-                "group": {
-                  "name": "${cluster-env/user_group}",
-                  "access": "r"
-                },
                 "configuration": "hive-interactive-site/hive.llap.zk.sm.keytab.file"
               },
               "when" : {

http://git-wip-us.apache.org/repos/asf/ambari/blob/65ca0845/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java
index cc58988..22e8ccc 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java
@@ -75,6 +75,9 @@ import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
 import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosPrincipalType;
 import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
 import org.apache.ambari.server.state.stack.OsFamily;
 import org.apache.commons.io.FileUtils;
@@ -648,7 +651,7 @@ public class UpgradeCatalog260Test {
     expect(artifactEntity.getArtifactData()).andReturn(kerberosDescriptor.toMap()).once();
 
     Capture<Map<String, Object>> captureMap = newCapture();
-    expect(artifactEntity.getForeignKeys()).andReturn(Collections.singletonMap("cluster", "2"));
+    expect(artifactEntity.getForeignKeys()).andReturn(Collections.singletonMap("cluster", "2")).times(2);
     artifactEntity.setArtifactData(capture(captureMap));
     expectLastCall().once();
 
@@ -665,11 +668,26 @@ public class UpgradeCatalog260Test {
     expect(config.getTag()).andReturn("version1").anyTimes();
     expect(config.getType()).andReturn("ranger-kms-audit").anyTimes();
 
+    Map<String, String> hsiProperties = new HashMap<>();
+    hsiProperties.put("hive.llap.daemon.keytab.file", "/etc/security/keytabs/hive.service.keytab");
+    hsiProperties.put("hive.llap.zk.sm.keytab.file", "/etc/security/keytabs/hive.llap.zk.sm.keytab");
+
+    Config hsiConfig = createMock(Config.class);
+    expect(hsiConfig.getProperties()).andReturn(hsiProperties).anyTimes();
+    expect(hsiConfig.getPropertiesAttributes()).andReturn(Collections.<String, Map<String, String>>emptyMap()).anyTimes();
+    expect(hsiConfig.getTag()).andReturn("version1").anyTimes();
+    expect(hsiConfig.getType()).andReturn("hive-interactive-site").anyTimes();
+
     Config newConfig = createMock(Config.class);
     expect(newConfig.getTag()).andReturn("version2").anyTimes();
     expect(newConfig.getType()).andReturn("ranger-kms-audit").anyTimes();
 
+    Config newHsiConfig = createMock(Config.class);
+    expect(newHsiConfig.getTag()).andReturn("version2").anyTimes();
+    expect(newHsiConfig.getType()).andReturn("hive-interactive-site").anyTimes();
+
     ServiceConfigVersionResponse response = createMock(ServiceConfigVersionResponse.class);
+    ServiceConfigVersionResponse response1 = createMock(ServiceConfigVersionResponse.class);
 
     StackId stackId = createMock(StackId.class);
 
@@ -683,6 +701,14 @@ public class UpgradeCatalog260Test {
     expect(cluster.getConfig(eq("ranger-kms-audit"), anyString())).andReturn(newConfig).once();
     expect(cluster.addDesiredConfig("ambari-upgrade", Collections.singleton(newConfig), "Updated ranger-kms-audit during Ambari Upgrade from 2.5.2 to 2.6.0.")).andReturn(response).once();
 
+    //HIVE
+    expect(cluster.getDesiredConfigByType("hive-site")).andReturn(hsiConfig).anyTimes();
+    expect(cluster.getDesiredConfigByType("hive-interactive-site")).andReturn(hsiConfig).anyTimes();
+    expect(cluster.getConfigsByType("hive-interactive-site")).andReturn(Collections.singletonMap("version1", hsiConfig)).anyTimes();
+    expect(cluster.getServiceByConfigType("hive-interactive-site")).andReturn("HIVE").anyTimes();
+    expect(cluster.getConfig(eq("hive-interactive-site"), anyString())).andReturn(newHsiConfig).anyTimes();
+  
+
     final Clusters clusters = injector.getInstance(Clusters.class);
     expect(clusters.getCluster(2L)).andReturn(cluster).anyTimes();
 
@@ -693,12 +719,17 @@ public class UpgradeCatalog260Test {
         .andReturn(null)
         .once();
 
-    replay(artifactDAO, artifactEntity, cluster, clusters, config, newConfig, response, controller, stackId);
+    Capture<? extends Map<String, String>> captureHsiProperties = newCapture();
+
+    expect(controller.createConfig(eq(cluster), eq(stackId), eq("hive-interactive-site"), capture(captureHsiProperties), anyString(), anyObject(Map.class)))
+            .andReturn(null)
+            .anyTimes();
+
+    replay(artifactDAO, artifactEntity, cluster, clusters, config, newConfig, hsiConfig, newHsiConfig, response, response1, controller, stackId);
 
     UpgradeCatalog260 upgradeCatalog260 = injector.getInstance(UpgradeCatalog260.class);
     upgradeCatalog260.updateKerberosDescriptorArtifact(artifactDAO, artifactEntity);
     verify(artifactDAO, artifactEntity, cluster, clusters, config, newConfig, response, controller, stackId);
-
     KerberosDescriptor kerberosDescriptorUpdated = new KerberosDescriptorFactory().createInstance(captureMap.getValue());
     Assert.assertNotNull(kerberosDescriptorUpdated);
 
@@ -722,6 +753,39 @@ public class UpgradeCatalog260Test {
     Assert.assertTrue(captureProperties.hasCaptured());
     Map<String, String> newProperties = captureProperties.getValue();
     Assert.assertEquals("correct_value@EXAMPLE.COM", newProperties.get("xasecure.audit.jaas.Client.option.principal"));
+
+    // YARN's NodeManager identities (1). 'llap_zk_hive' and (2). 'llap_task_hive' checks after modifications.
+    Map<String, List<String>> identitiesMap = new HashMap<>();
+    identitiesMap.put("llap_zk_hive", new ArrayList<String>() {{
+      add("hive-interactive-site/hive.llap.zk.sm.keytab.file");
+      add("hive-interactive-site/hive.llap.zk.sm.principal");
+    }});
+    identitiesMap.put("llap_task_hive", new ArrayList<String>() {{
+      add("hive-interactive-site/hive.llap.task.keytab.file");
+      add("hive-interactive-site/hive.llap.task.principal");
+    }});
+    for (String llapIdentity : identitiesMap.keySet()) {
+      KerberosIdentityDescriptor yarnKerberosIdentityDescriptor = kerberosDescriptorUpdated.getService("YARN").getComponent("NODEMANAGER").getIdentity(llapIdentity);
+      Assert.assertNotNull(yarnKerberosIdentityDescriptor);
+      Assert.assertEquals("/HIVE/HIVE_SERVER/hive_server_hive", yarnKerberosIdentityDescriptor.getReference());
+
+      KerberosKeytabDescriptor yarnKerberosKeytabDescriptor = yarnKerberosIdentityDescriptor.getKeytabDescriptor();
+      Assert.assertNotNull(yarnKerberosKeytabDescriptor);
+
+      Assert.assertEquals(null, yarnKerberosKeytabDescriptor.getGroupAccess());
+      Assert.assertEquals(null, yarnKerberosKeytabDescriptor.getGroupName());
+      Assert.assertEquals(null, yarnKerberosKeytabDescriptor.getOwnerAccess());
+      Assert.assertEquals(null, yarnKerberosKeytabDescriptor.getOwnerName());
+      Assert.assertEquals(null, yarnKerberosKeytabDescriptor.getFile());
+      Assert.assertEquals(identitiesMap.get(llapIdentity).get(0), yarnKerberosKeytabDescriptor.getConfiguration());
+
+      KerberosPrincipalDescriptor yarnKerberosPrincipalDescriptor = yarnKerberosIdentityDescriptor.getPrincipalDescriptor();
+      Assert.assertNotNull(yarnKerberosPrincipalDescriptor);
+      Assert.assertEquals(null, yarnKerberosPrincipalDescriptor.getName());
+      Assert.assertEquals(KerberosPrincipalType.SERVICE, yarnKerberosPrincipalDescriptor.getType());
+      Assert.assertEquals(null, yarnKerberosPrincipalDescriptor.getValue());
+      Assert.assertEquals(identitiesMap.get(llapIdentity).get(1), yarnKerberosPrincipalDescriptor.getConfiguration());
+    }
   }
 
   @Test
@@ -781,6 +845,72 @@ public class UpgradeCatalog260Test {
   }
 
   @Test
+  public void testUpdateHiveConfigs() throws Exception {
+
+    Map<String, String> oldProperties = new HashMap<String, String>() {
+      {
+        put("hive.llap.zk.sm.keytab.file", "/etc/security/keytabs/hive.llap.zk.sm.keytab");
+        put("hive.llap.daemon.keytab.file", "/etc/security/keytabs/hive.service.keytab");
+        put("hive.llap.task.keytab.file", "/etc/security/keytabs/hive.llap.task.keytab");
+      }
+    };
+    Map<String, String> newProperties = new HashMap<String, String>() {
+      {
+        put("hive.llap.zk.sm.keytab.file", "/etc/security/keytabs/hive.service.keytab");
+        put("hive.llap.daemon.keytab.file", "/etc/security/keytabs/hive.service.keytab");
+        put("hive.llap.task.keytab.file", "/etc/security/keytabs/hive.service.keytab");
+      }
+    };
+
+    EasyMockSupport easyMockSupport = new EasyMockSupport();
+
+    Clusters clusters = easyMockSupport.createNiceMock(Clusters.class);
+    final Cluster cluster = easyMockSupport.createNiceMock(Cluster.class);
+    Config mockHsiConfigs = easyMockSupport.createNiceMock(Config.class);
+
+    expect(clusters.getClusters()).andReturn(new HashMap<String, Cluster>() {{
+      put("normal", cluster);
+    }}).once();
+    expect(cluster.getDesiredConfigByType("hive-interactive-site")).andReturn(mockHsiConfigs).atLeastOnce();
+    expect(mockHsiConfigs.getProperties()).andReturn(oldProperties).anyTimes();
+
+    Injector injector = easyMockSupport.createNiceMock(Injector.class);
+    expect(injector.getInstance(Gson.class)).andReturn(null).anyTimes();
+    expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null).anyTimes();
+
+    replay(injector, clusters, mockHsiConfigs, cluster);
+
+    AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class)
+            .addMockedMethod("createConfiguration")
+            .addMockedMethod("getClusters", new Class[] { })
+            .addMockedMethod("createConfig")
+            .withConstructor(createNiceMock(ActionManager.class), clusters, injector)
+            .createNiceMock();
+
+    Injector injector2 = easyMockSupport.createNiceMock(Injector.class);
+    Capture<Map> propertiesCapture = EasyMock.newCapture();
+
+    expect(injector2.getInstance(AmbariManagementController.class)).andReturn(controller).anyTimes();
+    expect(controller.getClusters()).andReturn(clusters).anyTimes();
+    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(propertiesCapture), anyString(),
+            anyObject(Map.class))).andReturn(createNiceMock(Config.class)).once();
+    replay(controller, injector2);
+
+    // This tests the update of HSI config 'hive.llap.daemon.keytab.file'.
+    UpgradeCatalog260  upgradeCatalog260 = new UpgradeCatalog260(injector2);
+    // Set 'isYarnKerberosDescUpdated' value to true, implying kerberos descriptor was updated.
+    upgradeCatalog260.updateYarnKerberosDescUpdatedList("hive.llap.zk.sm.keytab.file");
+    upgradeCatalog260.updateYarnKerberosDescUpdatedList("hive.llap.task.keytab.file");
+
+    upgradeCatalog260.updateHiveConfigs();
+
+    easyMockSupport.verifyAll();
+
+    Map<String, String> updatedProperties = propertiesCapture.getValue();
+    assertTrue(Maps.difference(newProperties, updatedProperties).areEqual());
+  }
+
+  @Test
    public void testHDFSWidgetUpdate() throws Exception {
          final Clusters clusters = createNiceMock(Clusters.class);
          final Cluster cluster = createNiceMock(Cluster.class);

http://git-wip-us.apache.org/repos/asf/ambari/blob/65ca0845/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_ranger_kms.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_ranger_kms.json b/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_ranger_kms.json
index e17e121..8c27a9a 100644
--- a/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_ranger_kms.json
+++ b/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_ranger_kms.json
@@ -104,6 +104,292 @@
           ]
         }
       ]
+    },
+    {
+      "name": "YARN",
+      "identities": [
+        {
+          "name": "yarn_spnego",
+          "reference": "/spnego"
+        },
+        {
+          "name": "yarn_smokeuser",
+          "reference": "/smokeuser"
+        }
+      ],
+      "configurations": [
+        {
+          "yarn-site": {
+            "yarn.timeline-service.enabled": "true",
+            "yarn.timeline-service.http-authentication.type": "kerberos",
+            "yarn.acl.enable": "true",
+            "yarn.admin.acl": "${yarn-env/yarn_user},dr.who",
+            "yarn.timeline-service.http-authentication.signature.secret": "",
+            "yarn.timeline-service.http-authentication.signature.secret.file": "",
+            "yarn.timeline-service.http-authentication.signer.secret.provider": "",
+            "yarn.timeline-service.http-authentication.signer.secret.provider.object": "",
+            "yarn.timeline-service.http-authentication.token.validity": "",
+            "yarn.timeline-service.http-authentication.cookie.domain": "",
+            "yarn.timeline-service.http-authentication.cookie.path": "",
+            "yarn.timeline-service.http-authentication.proxyuser.*.hosts": "",
+            "yarn.timeline-service.http-authentication.proxyuser.*.users": "",
+            "yarn.timeline-service.http-authentication.proxyuser.*.groups": "",
+            "yarn.timeline-service.http-authentication.kerberos.name.rules": "",
+            "yarn.resourcemanager.proxyuser.*.groups": "",
+            "yarn.resourcemanager.proxyuser.*.hosts": "",
+            "yarn.resourcemanager.proxyuser.*.users": "",
+            "yarn.resourcemanager.proxy-user-privileges.enabled": "true",
+            "yarn.resourcemanager.zk-acl" : "sasl:${principals/YARN/RESOURCEMANAGER/resource_manager_rm|principalPrimary()}:rwcda",
+            "hadoop.registry.secure" : "true",
+            "hadoop.registry.system.accounts" : "sasl:${principals/YARN/APP_TIMELINE_SERVER/app_timeline_server_yarn|principalPrimary()},sasl:${principals/MAPREDUCE2/HISTORYSERVER/history_server_jhs|principalPrimary()},sasl:${principals/HDFS/NAMENODE/hdfs|principalPrimary()},sasl:${principals/YARN/RESOURCEMANAGER/resource_manager_rm|principalPrimary()},sasl:${principals/HIVE/HIVE_SERVER/hive_server_hive|principalPrimary()}",
+            "hadoop.registry.client.auth" : "kerberos",
+            "hadoop.registry.jaas.context" : "Client"
+          }
+        },
+        {
+          "core-site": {
+            "hadoop.proxyuser.${yarn-env/yarn_user}.groups": "*",
+            "hadoop.proxyuser.${yarn-env/yarn_user}.hosts": "${clusterHostInfo/rm_host}"
+          }
+        },
+        {
+          "capacity-scheduler": {
+            "yarn.scheduler.capacity.root.acl_administer_queue": "${yarn-env/yarn_user}",
+            "yarn.scheduler.capacity.root.default.acl_administer_queue": "${yarn-env/yarn_user}",
+            "yarn.scheduler.capacity.root.acl_administer_jobs": "${yarn-env/yarn_user}",
+            "yarn.scheduler.capacity.root.default.acl_administer_jobs": "${yarn-env/yarn_user}",
+            "yarn.scheduler.capacity.root.default.acl_submit_applications": "${yarn-env/yarn_user}"
+          }
+        },
+        {
+          "ranger-yarn-audit": {
+            "xasecure.audit.jaas.Client.loginModuleName": "com.sun.security.auth.module.Krb5LoginModule",
+            "xasecure.audit.jaas.Client.loginModuleControlFlag": "required",
+            "xasecure.audit.jaas.Client.option.useKeyTab": "true",
+            "xasecure.audit.jaas.Client.option.storeKey": "false",
+            "xasecure.audit.jaas.Client.option.serviceName": "solr",
+            "xasecure.audit.destination.solr.force.use.inmemory.jaas.config": "true"
+          }
+        }
+      ],
+      "components": [
+        {
+          "name": "NODEMANAGER",
+          "identities": [
+            {
+              "name": "nodemanager_nm",
+              "principal": {
+                "value": "nm/_HOST@${realm}",
+                "type" : "service",
+                "configuration": "yarn-site/yarn.nodemanager.principal",
+                "local_username": "${yarn-env/yarn_user}"
+              },
+              "keytab": {
+                "file": "${keytab_dir}/nm.service.keytab",
+                "owner": {
+                  "name": "${yarn-env/yarn_user}",
+                  "access": "r"
+                },
+                "group": {
+                  "name": "${cluster-env/user_group}",
+                  "access": ""
+                },
+                "configuration": "yarn-site/yarn.nodemanager.keytab"
+              }
+            },
+            {
+              "name": "yarn_nodemanager_hive_server_hive",
+              "reference": "/HIVE/HIVE_SERVER/hive_server_hive",
+              "principal": {
+                "configuration": "hive-interactive-site/hive.llap.daemon.service.principal"
+              },
+              "keytab": {
+                "configuration": "hive-interactive-site/hive.llap.daemon.keytab.file"
+              },
+              "when" : {
+                "contains" : ["services", "HIVE"]
+              }
+            },
+            {
+              "name": "llap_task_hive",
+              "principal": {
+                "value": "hive/_HOST@${realm}",
+                "type" : "service",
+                "configuration": "hive-interactive-site/hive.llap.task.principal"
+              },
+              "keytab": {
+                "file": "${keytab_dir}/hive.llap.task.keytab",
+                "owner": {
+                  "name": "${yarn-env/yarn_user}",
+                  "access": "r"
+                },
+                "group": {
+                  "name": "${cluster-env/user_group}",
+                  "access": "r"
+                },
+                "configuration": "hive-interactive-site/hive.llap.task.keytab.file"
+              },
+              "when" : {
+                "contains" : ["services", "HIVE"]
+              }
+            },
+            {
+              "name": "llap_zk_hive",
+              "principal": {
+                "value": "hive/_HOST@${realm}",
+                "type" : "service",
+                "configuration": "hive-interactive-site/hive.llap.zk.sm.principal"
+              },
+              "keytab": {
+                "file": "${keytab_dir}/hive.llap.zk.sm.keytab",
+                "owner": {
+                  "name": "${yarn-env/yarn_user}",
+                  "access": "r"
+                },
+                "group": {
+                  "name": "${cluster-env/user_group}",
+                  "access": "r"
+                },
+                "configuration": "hive-interactive-site/hive.llap.zk.sm.keytab.file"
+              },
+              "when" : {
+                "contains" : ["services", "HIVE"]
+              }
+            },
+            {
+              "name": "yarn_nodemanager_spnego",
+              "reference": "/spnego",
+              "principal": {
+                "configuration": "yarn-site/yarn.nodemanager.webapp.spnego-principal"
+              },
+              "keytab": {
+                "configuration": "yarn-site/yarn.nodemanager.webapp.spnego-keytab-file"
+              }
+            }
+          ],
+          "configurations": [
+            {
+              "yarn-site": {
+                "yarn.nodemanager.container-executor.class": "org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "HIVE",
+      "identities": [
+        {
+          "name": "hive_spnego",
+          "reference": "/spnego"
+        },
+        {
+          "name": "hive_smokeuser",
+          "reference": "/smokeuser"
+        }
+      ],
+      "configurations": [
+        {
+          "hive-site": {
+            "hive.metastore.sasl.enabled": "true",
+            "hive.server2.authentication": "KERBEROS"
+          }
+        },
+        {
+          "ranger-hive-audit": {
+            "xasecure.audit.jaas.Client.loginModuleName": "com.sun.security.auth.module.Krb5LoginModule",
+            "xasecure.audit.jaas.Client.loginModuleControlFlag": "required",
+            "xasecure.audit.jaas.Client.option.useKeyTab": "true",
+            "xasecure.audit.jaas.Client.option.storeKey": "false",
+            "xasecure.audit.jaas.Client.option.serviceName": "solr",
+            "xasecure.audit.destination.solr.force.use.inmemory.jaas.config": "true"
+          }
+        }
+      ],
+      "components": [
+        {
+          "name": "HIVE_SERVER",
+          "identities": [
+            {
+              "name": "hive_hive_server_hdfs",
+              "reference": "/HDFS/NAMENODE/hdfs"
+            },
+            {
+              "name": "hive_server_hive",
+              "principal": {
+                "value": "hive/_HOST@${realm}",
+                "type": "service",
+                "configuration": "hive-site/hive.server2.authentication.kerberos.principal",
+                "local_username": "${hive-env/hive_user}"
+              },
+              "keytab": {
+                "file": "${keytab_dir}/hive.service.keytab",
+                "owner": {
+                  "name": "${hive-env/hive_user}",
+                  "access": "r"
+                },
+                "group": {
+                  "name": "${cluster-env/user_group}",
+                  "access": "r"
+                },
+                "configuration": "hive-site/hive.server2.authentication.kerberos.keytab"
+              }
+            },
+            {
+              "name": "atlas_kafka",
+              "reference": "/HIVE/HIVE_SERVER/hive_server_hive",
+              "principal": {
+                "configuration": "hive-atlas-application.properties/atlas.jaas.KafkaClient.option.principal"
+              },
+              "keytab": {
+                "configuration": "hive-atlas-application.properties/atlas.jaas.KafkaClient.option.keyTab"
+              }
+            },
+            {
+              "name": "hive_hive_server_spnego",
+              "reference": "/spnego",
+              "principal": {
+                "configuration": "hive-site/hive.server2.authentication.spnego.principal"
+              },
+              "keytab": {
+                "configuration": "hive-site/hive.server2.authentication.spnego.keytab"
+              }
+            },
+            {
+              "name": "ranger_audit",
+              "reference": "/HIVE/HIVE_SERVER/hive_server_hive",
+              "principal": {
+                "configuration": "ranger-hive-audit/xasecure.audit.jaas.Client.option.principal"
+              },
+              "keytab": {
+                "configuration": "ranger-hive-audit/xasecure.audit.jaas.Client.option.keyTab"
+              }
+            }
+          ]
+        },
+        {
+          "name": "HIVE_SERVER_INTERACTIVE",
+          "identities": [
+            {
+              "name": "hive_hive_server_interactive_hdfs",
+              "reference": "/HDFS/NAMENODE/hdfs"
+            },
+            {
+              "name": "hive_hive_server_interactive_hive_server_hive",
+              "reference": "/HIVE/HIVE_SERVER/hive_server_hive"
+            },
+            {
+              "name": "hive_hive_server_interactive_spnego",
+              "reference": "/HIVE/HIVE_SERVER/spnego"
+            },
+            {
+              "name": "hive_hive_server_interactive_llap_zk_hive",
+              "reference": "/YARN/NODEMANAGER/llap_zk_hive"
+            }
+          ]
+        }
+      ]
     }
   ]
 }
\ No newline at end of file


[39/49] ambari git commit: AMBARI-22508 Ambari 3.0: Implement new design for Admin View: User Management. (atkach)

Posted by rl...@apache.org.
AMBARI-22508 Ambari 3.0: Implement new design for Admin View: User Management. (atkach)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 99b19e5805cf3ac291eca9c8e6a1290637b08ab6
Parents: 8e36662
Author: Andrii Tkach <at...@apache.org>
Authored: Thu Nov 23 14:02:00 2017 +0200
Committer: Andrii Tkach <at...@apache.org>
Committed: Thu Nov 23 14:02:00 2017 +0200

----------------------------------------------------------------------
 .../main/resources/ui/admin-web/app/index.html  |  17 +-
 .../resources/ui/admin-web/app/scripts/app.js   |   3 +-
 .../controllers/ClusterInformationCtrl.js       | 106 ---
 .../controllers/ambariViews/ViewsListCtrl.js    |   4 +-
 .../clusters/ClusterInformationCtrl.js          | 106 +++
 .../clusters/ClustersManageAccessCtrl.js        |  97 ---
 .../controllers/clusters/UserAccessListCtrl.js  | 351 --------
 .../controllers/groups/GroupsCreateCtrl.js      |  65 --
 .../controllers/groups/GroupsEditCtrl.js        | 180 ----
 .../controllers/groups/GroupsListCtrl.js        | 106 ---
 .../userManagement/GroupCreateCtrl.js           | 112 +++
 .../controllers/userManagement/GroupEditCtrl.js | 182 ++++
 .../userManagement/GroupsListCtrl.js            | 170 ++++
 .../userManagement/UserCreateCtrl.js            | 108 +++
 .../controllers/userManagement/UserEditCtrl.js  | 290 +++++++
 .../userManagement/UserManagementCtrl.js        |  23 +
 .../controllers/userManagement/UsersListCtrl.js | 178 ++++
 .../controllers/users/UsersCreateCtrl.js        |  75 --
 .../scripts/controllers/users/UsersListCtrl.js  | 122 ---
 .../scripts/controllers/users/UsersShowCtrl.js  | 290 -------
 .../ui/admin-web/app/scripts/i18n.config.js     |   9 +-
 .../ui/admin-web/app/scripts/routes.js          |  61 +-
 .../ui/admin-web/app/scripts/services/User.js   |   5 +-
 .../resources/ui/admin-web/app/styles/main.css  |  46 +-
 .../ui/admin-web/app/styles/user-management.css |  30 +
 .../resources/ui/admin-web/app/styles/views.css |  18 -
 .../app/views/ambariViews/viewsList.html        |  26 +-
 .../admin-web/app/views/clusterInformation.html |  87 --
 .../app/views/clusters/clusterInformation.html  |  87 ++
 .../app/views/clusters/manageAccess.html        |  63 --
 .../app/views/clusters/userAccessList.html      | 102 ---
 .../ui/admin-web/app/views/groups/create.html   |  43 -
 .../ui/admin-web/app/views/groups/edit.html     |  98 ---
 .../ui/admin-web/app/views/groups/list.html     |  80 --
 .../ui/admin-web/app/views/sideNav.html         |  22 +-
 .../app/views/userManagement/groupEdit.html     |  99 +++
 .../app/views/userManagement/groupsList.html    |  94 +++
 .../app/views/userManagement/main.html          |  36 +
 .../userManagement/modals/changePassword.html   |  46 ++
 .../userManagement/modals/groupCreate.html      |  86 ++
 .../views/userManagement/modals/userCreate.html | 147 ++++
 .../app/views/userManagement/userEdit.html      | 122 +++
 .../app/views/userManagement/usersList.html     | 119 +++
 .../ui/admin-web/app/views/users/create.html    |  82 --
 .../ui/admin-web/app/views/users/list.html      |  97 ---
 .../app/views/users/modals/changePassword.html  |  46 --
 .../ui/admin-web/app/views/users/show.html      | 122 ---
 .../clusters/UserAccessListCtrl_test.js         | 820 -------------------
 .../controllers/groups/GroupsListCtrl_test.js   | 129 ---
 .../userManagement/GroupsListCtrl_test.js       | 129 +++
 .../userManagement/UsersListCtrl_test.js        | 344 ++++++++
 .../controllers/users/UsersListCtrl_test.js     | 383 ---------
 .../test/unit/services/Utility_test.js          |  10 +-
 53 files changed, 2591 insertions(+), 3682 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/index.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/index.html b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
index 4a77e62..e3b817e 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/index.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
@@ -121,26 +121,25 @@
 <script src="scripts/app.js"></script>
 <script src="scripts/routes.js"></script>
 <script src="scripts/i18n.config.js"></script>
-<script src="scripts/controllers/ClusterInformationCtrl.js"></script>
+<script src="scripts/controllers/clusters/ClusterInformationCtrl.js"></script>
 <script src="scripts/controllers/AppCtrl.js"></script>
 <script src="scripts/controllers/SideNavCtrl.js"></script>
 <script src="scripts/controllers/authentication/AuthenticationMainCtrl.js"></script>
 <script src="scripts/controllers/loginActivities/LoginActivitiesMainCtrl.js"></script>
 <script src="scripts/controllers/loginActivities/LoginMessageMainCtrl.js"></script>
 <script src="scripts/controllers/loginActivities/HomeDirectoryCtrl.js"></script>
-<script src="scripts/controllers/users/UsersCreateCtrl.js"></script>
-<script src="scripts/controllers/users/UsersListCtrl.js"></script>
-<script src="scripts/controllers/users/UsersShowCtrl.js"></script>
-<script src="scripts/controllers/groups/GroupsListCtrl.js"></script>
-<script src="scripts/controllers/groups/GroupsCreateCtrl.js"></script>
-<script src="scripts/controllers/groups/GroupsEditCtrl.js"></script>
+<script src="scripts/controllers/userManagement/UserManagementCtrl.js"></script>
+<script src="scripts/controllers/userManagement/UserCreateCtrl.js"></script>
+<script src="scripts/controllers/userManagement/UsersListCtrl.js"></script>
+<script src="scripts/controllers/userManagement/UserEditCtrl.js"></script>
+<script src="scripts/controllers/userManagement/GroupsListCtrl.js"></script>
+<script src="scripts/controllers/userManagement/GroupCreateCtrl.js"></script>
+<script src="scripts/controllers/userManagement/GroupEditCtrl.js"></script>
 <script src="scripts/controllers/ambariViews/ViewsListCtrl.js"></script>
 <script src="scripts/controllers/ambariViews/ViewsEditCtrl.js"></script>
 <script src="scripts/controllers/ambariViews/ViewUrlCtrl.js"></script>
 <script src="scripts/controllers/ambariViews/ViewUrlEditCtrl.js"></script>
 <script src="scripts/controllers/ambariViews/CreateViewInstanceCtrl.js"></script>
-<script src="scripts/controllers/clusters/ClustersManageAccessCtrl.js"></script>
-<script src="scripts/controllers/clusters/UserAccessListCtrl.js"></script>
 <script src="scripts/controllers/stackVersions/StackVersionsCreateCtrl.js"></script>
 <script src="scripts/controllers/stackVersions/StackVersionsListCtrl.js"></script>
 <script src="scripts/controllers/stackVersions/StackVersionsEditCtrl.js"></script>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/app.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/app.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/app.js
index 80e2813..225eb12 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/app.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/app.js
@@ -33,7 +33,8 @@ angular.module('ambariAdminConsole', [
   isLDAPConfigurationSupported: false,
   isLoginActivitiesSupported: false,
   maxStackTraceLength: 1000,
-  errorStorageSize: 500000
+  errorStorageSize: 500000,
+  minRowsToShowPagination: 10
 })
 .config(['RestangularProvider', '$httpProvider', '$provide', 'Settings', function(RestangularProvider, $httpProvider, $provide, Settings) {
   // Config Ajax-module

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ClusterInformationCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ClusterInformationCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ClusterInformationCtrl.js
deleted file mode 100644
index 059f399..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ClusterInformationCtrl.js
+++ /dev/null
@@ -1,106 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-.controller('ClusterInformationCtrl',
-['$scope', '$http', '$location', 'Cluster', '$routeParams', '$translate', '$rootScope', 'ConfirmationModal', 'Alert',
-function($scope, $http, $location, Cluster, $routeParams, $translate, $rootScope, ConfirmationModal, Alert) {
-  var $t = $translate.instant;
-  $scope.isDataLoaded = false;
-  $scope.edit = {
-    clusterName: null
-  };
-  $scope.isClusterNameEdited = false;
-
-  $scope.$watch(function() {
-    return $rootScope.cluster;
-  }, function() {
-    $scope.cluster = $rootScope.cluster;
-    if ($scope.cluster) {
-      $scope.edit.clusterName = $scope.cluster.Clusters.cluster_name;
-      $scope.getBlueprint();
-    }
-  }, true);
-
-  $scope.getBlueprint = function () {
-    Cluster.getBlueprint({
-      clusterName: $scope.cluster.Clusters.cluster_name
-    }).then(function (data) {
-      console.debug($t('exportBlueprint.dataLoaded'), data);
-      $scope.isDataLoaded = true;
-      var response = JSON.stringify(data, null, 4),
-        lt = /&lt;/g,
-        gt = /&gt;/g,
-        ap = /&#39;/g,
-        ic = /&#34;/g;
-      $scope.blueprint = response ? response.toString().replace(lt, "<").replace(gt, ">").replace(ap, "'").replace(ic, '"') : "";
-    });
-  };
-
-  $scope.downloadBlueprint = function () {
-    if (window.navigator.msSaveOrOpenBlob) {
-      var blob = new Blob([decodeURIComponent(encodeURI($scope.blueprint))], {
-        type: "text/csv;charset=utf-8;"
-      });
-      navigator.msSaveBlob(blob, 'blueprint.json');
-    } else {
-      var a = document.createElement('a');
-      a.href = 'data:attachment/csv;charset=utf-8,' + encodeURI($scope.blueprint);
-      a.target = '_blank';
-      a.download = 'blueprint.json';
-      document.body.appendChild(a);
-      a.click();
-    }
-  };
-
-  $scope.toggleSaveButton = function() {
-    var value = $scope.edit.clusterName;
-    $scope.isClusterNameEdited = (value !== null && $scope.cluster.Clusters.cluster_name !== value);
-  };
-
-  $scope.confirmClusterNameChange = function() {
-    ConfirmationModal.show(
-      $t('common.clusterNameChangeConfirmation.title'),
-      $t('common.clusterNameChangeConfirmation.message', {
-        clusterName: $scope.edit.clusterName
-      })
-    )
-      .then(function () {
-        $scope.saveClusterName();
-      }).catch(function () {
-      // user clicked cancel
-      $scope.edit.clusterName = $scope.cluster.Clusters.cluster_name;
-      $scope.toggleSaveButton();
-    });
-  };
-
-  $scope.saveClusterName = function() {
-    var oldClusterName = $scope.cluster.Clusters.cluster_name,
-        newClusterName = $scope.edit.clusterName;
-
-    Cluster.editName(oldClusterName, newClusterName).then(function(data) {
-      $scope.cluster.Clusters.cluster_name = newClusterName;
-      $scope.edit.clusterName = newClusterName;
-      $scope.toggleSaveButton();
-      Alert.success($t('common.alerts.clusterRenamed', {clusterName: newClusterName}));
-    }).catch(function(data) {
-      Alert.error($t('common.alerts.cannotRenameCluster', {clusterName: newClusterName}), data.data.message);
-    });
-  };
-}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
index aa77b63..8b37dca 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
@@ -18,11 +18,11 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('ViewsListCtrl',['$scope', 'View','$modal', 'Alert', 'ConfirmationModal', '$translate', function($scope, View, $modal, Alert, ConfirmationModal, $translate) {
+.controller('ViewsListCtrl',['$scope', 'View','$modal', 'Alert', 'ConfirmationModal', '$translate', 'Settings', function($scope, View, $modal, Alert, ConfirmationModal, $translate, Settings) {
   var $t = $translate.instant;
   var VIEWS_VERSION_STATUS_TIMEOUT = 5000;
   $scope.isLoading = false;
-  $scope.minInstanceForPagination = 10;
+  $scope.minInstanceForPagination = Settings.minRowsToShowPagination;
 
   function checkViewVersionStatus(view, versionObj, versionNumber) {
     var deferred = View.checkViewVersionStatus(view.view_name, versionNumber);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/ClusterInformationCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/ClusterInformationCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/ClusterInformationCtrl.js
new file mode 100644
index 0000000..059f399
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/ClusterInformationCtrl.js
@@ -0,0 +1,106 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('ClusterInformationCtrl',
+['$scope', '$http', '$location', 'Cluster', '$routeParams', '$translate', '$rootScope', 'ConfirmationModal', 'Alert',
+function($scope, $http, $location, Cluster, $routeParams, $translate, $rootScope, ConfirmationModal, Alert) {
+  var $t = $translate.instant;
+  $scope.isDataLoaded = false;
+  $scope.edit = {
+    clusterName: null
+  };
+  $scope.isClusterNameEdited = false;
+
+  $scope.$watch(function() {
+    return $rootScope.cluster;
+  }, function() {
+    $scope.cluster = $rootScope.cluster;
+    if ($scope.cluster) {
+      $scope.edit.clusterName = $scope.cluster.Clusters.cluster_name;
+      $scope.getBlueprint();
+    }
+  }, true);
+
+  $scope.getBlueprint = function () {
+    Cluster.getBlueprint({
+      clusterName: $scope.cluster.Clusters.cluster_name
+    }).then(function (data) {
+      console.debug($t('exportBlueprint.dataLoaded'), data);
+      $scope.isDataLoaded = true;
+      var response = JSON.stringify(data, null, 4),
+        lt = /&lt;/g,
+        gt = /&gt;/g,
+        ap = /&#39;/g,
+        ic = /&#34;/g;
+      $scope.blueprint = response ? response.toString().replace(lt, "<").replace(gt, ">").replace(ap, "'").replace(ic, '"') : "";
+    });
+  };
+
+  $scope.downloadBlueprint = function () {
+    if (window.navigator.msSaveOrOpenBlob) {
+      var blob = new Blob([decodeURIComponent(encodeURI($scope.blueprint))], {
+        type: "text/csv;charset=utf-8;"
+      });
+      navigator.msSaveBlob(blob, 'blueprint.json');
+    } else {
+      var a = document.createElement('a');
+      a.href = 'data:attachment/csv;charset=utf-8,' + encodeURI($scope.blueprint);
+      a.target = '_blank';
+      a.download = 'blueprint.json';
+      document.body.appendChild(a);
+      a.click();
+    }
+  };
+
+  $scope.toggleSaveButton = function() {
+    var value = $scope.edit.clusterName;
+    $scope.isClusterNameEdited = (value !== null && $scope.cluster.Clusters.cluster_name !== value);
+  };
+
+  $scope.confirmClusterNameChange = function() {
+    ConfirmationModal.show(
+      $t('common.clusterNameChangeConfirmation.title'),
+      $t('common.clusterNameChangeConfirmation.message', {
+        clusterName: $scope.edit.clusterName
+      })
+    )
+      .then(function () {
+        $scope.saveClusterName();
+      }).catch(function () {
+      // user clicked cancel
+      $scope.edit.clusterName = $scope.cluster.Clusters.cluster_name;
+      $scope.toggleSaveButton();
+    });
+  };
+
+  $scope.saveClusterName = function() {
+    var oldClusterName = $scope.cluster.Clusters.cluster_name,
+        newClusterName = $scope.edit.clusterName;
+
+    Cluster.editName(oldClusterName, newClusterName).then(function(data) {
+      $scope.cluster.Clusters.cluster_name = newClusterName;
+      $scope.edit.clusterName = newClusterName;
+      $scope.toggleSaveButton();
+      Alert.success($t('common.alerts.clusterRenamed', {clusterName: newClusterName}));
+    }).catch(function(data) {
+      Alert.error($t('common.alerts.cannotRenameCluster', {clusterName: newClusterName}), data.data.message);
+    });
+  };
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/ClustersManageAccessCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/ClustersManageAccessCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/ClustersManageAccessCtrl.js
deleted file mode 100644
index 3a9ad67..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/ClustersManageAccessCtrl.js
+++ /dev/null
@@ -1,97 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-.controller('ClustersManageAccessCtrl', ['$scope', '$location', 'Cluster', '$routeParams', 'Alert', 'PermissionLoader', 'PermissionSaver', '$translate', 'RoleDetailsModal', '$timeout', function($scope, $location, Cluster, $routeParams, Alert, PermissionLoader, PermissionSaver, $translate, RoleDetailsModal, $timeout) {
-  var $t = $translate.instant;
-  $scope.getConstant = function (key) {
-    return $t(key).toLowerCase();
-  };
-  $scope.identity = angular.identity;
-  function reloadClusterData(){
-    PermissionLoader.getClusterPermissions({
-      clusterId: $routeParams.id
-    }).then(function(permissions) {
-      // Refresh data for rendering
-      $scope.permissionsEdit = permissions;
-      $scope.permissions = angular.copy(permissions);
-      //"$scope.isDataLoaded" should be set to true on initial load after "$scope.permissionsEdit" watcher
-      $timeout(function() {
-        $scope.isDataLoaded = true;
-      });
-      var orderedRoles = Cluster.orderedRoles;
-      var pms = [];
-      for (var key=0;key<orderedRoles.length;key++) {
-        pms.push($scope.permissions[orderedRoles[key]]);
-      }
-      $scope.permissions = pms;
-    })
-    .catch(function(data) {
-      Alert.error($t('clusters.alerts.cannotLoadClusterData'), data.data.message);
-    });
-  }
-
-  $scope.isDataLoaded = false;
-  reloadClusterData();
-  $scope.isEditMode = false;
-  $scope.permissions = {};
-  $scope.clusterName = $routeParams.id;
-
-
-  $scope.toggleEditMode = function() {
-    $scope.isEditMode = !$scope.isEditMode;
-  };
-
-  $scope.cancel = function() {
-    $scope.isEditMode = false;
-    $scope.permissionsEdit = angular.copy($scope.permissions); // Reset textedit areaes
-  };
-
-  $scope.save = function() {
-    PermissionSaver.saveClusterPermissions(
-      $scope.permissionsEdit,
-      {
-        clusterId: $routeParams.id
-      }
-    ).then(reloadClusterData)
-    .catch(function(data) {
-      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
-      reloadClusterData();
-    });
-    $scope.isEditMode = false;
-  };
-
-  $scope.$watch(function() {
-    return $scope.permissionsEdit;
-  }, function(newValue) {
-    if (newValue && $scope.isDataLoaded) {
-      $scope.save();
-    }
-  }, true);
-
-  $scope.switchToList = function() {
-    $location.url('/clusters/' + $routeParams.id + '/userAccessList');
-  };
-
-  $scope.showHelpPage = function() {
-    Cluster.getRolesWithAuthorizations().then(function(roles) {
-      RoleDetailsModal.show(roles);
-    });
-  };
-}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/UserAccessListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/UserAccessListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/UserAccessListCtrl.js
deleted file mode 100644
index 9e83b91..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/clusters/UserAccessListCtrl.js
+++ /dev/null
@@ -1,351 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-.controller('UserAccessListCtrl',['$scope', '$location', 'Cluster', '$modal', '$rootScope', '$routeParams', 'PermissionSaver', 'Alert', '$translate', 'RoleDetailsModal',
-function($scope, $location, Cluster, $modal, $rootScope, $routeParams, PermissionSaver, Alert, $translate, RoleDetailsModal) {
-  var $t = $translate.instant;
-  $scope.constants = {
-    users: $t('common.users').toLowerCase(),
-    groups: $t('common.groups').toLowerCase()
-  };
-  $scope.users = [];
-  $scope.usersPerPage = 10;
-  $scope.currentPage = 1;
-  $scope.totalUsers = 1;
-  $scope.currentNameFilter = '';
-  $scope.maxVisiblePages = 20;
-  $scope.roles = [];
-  $scope.clusterId = $routeParams.id;
-  $scope.tableInfo = {
-    total: 0,
-    showed: 0,
-    filtered: 0
-  };
-  $scope.isNotEmptyFilter = true;
-  $scope.NONE_ROLE = {
-    "permission_label" : $t('common.none'),
-    "permission_name" : "CLUSTER.NONE"
-  };
-  $scope.ALL_ROLE = {
-    "permission_label" : $t('common.all'),
-    "permission_name" : ""
-  };
-  $scope.AMBARI_ADMIN_ROLE = {
-    "permission_label" : $t('users.roles.ambariAdmin'),
-    "permission_name" : "AMBARI.ADMINISTRATOR"
-  };
-
-  $scope.pageChanged = function() {
-    $scope.loadUsers();
-  };
-  $scope.usersPerPageChanges = function() {
-    $scope.resetPagination();
-  };
-
-  $scope.loadUsers = function(){
-    Cluster.getPrivilegesWithFilters({
-      nameFilter: $scope.currentNameFilter,
-      typeFilter: $scope.currentTypeFilter,
-      roleFilter: $scope.currentRoleFilter,
-      currentPage: $scope.currentPage,
-      usersPerPage: $scope.usersPerPage
-    }).then(function(data) {
-      $scope.totalUsers = data.itemTotal;
-      $scope.users = data.items.map(function (user) {
-        var privilege = $scope.pickEffectivePrivilege(user.privileges);
-        // Redefine principal_name and principal type in case of None
-        privilege.principal_name = user.Users? user.Users.user_name : user.Groups.group_name;
-        if (privilege.permission_label === $t('users.roles.none')) {
-          privilege.principal_type = user.Users ? 'USER' : 'GROUP';
-        }
-        var name = encodeURIComponent(privilege.principal_name);
-        privilege.encoded_name = name;
-        privilege.original_perm = privilege.permission_name;
-        privilege.url = user.Users? ('users/' + name) : ('groups/' + name + '/edit');
-        privilege.editable = Cluster.ineditableRoles.indexOf(privilege.permission_name) == -1;
-        return privilege;
-      });
-      $scope.tableInfo.total = data.itemTotal;
-      $scope.tableInfo.showed = data.items.length;
-    });
-  };
-
-  $scope.pickEffectivePrivilege = function(privileges) {
-    if (privileges && privileges.length > 1) {
-      return privileges.reduce(function(prev, cur) {
-        var prevIndex = $scope.getRoleRank(prev.PrivilegeInfo.permission_name);
-        var curIndex = $scope.getRoleRank(cur.PrivilegeInfo.permission_name)
-        return (prevIndex < curIndex) ? prev : cur;
-      }).PrivilegeInfo;
-    } else if (privileges && privileges.length == 1 && privileges[0].PrivilegeInfo.permission_name !== "VIEW.USER") {
-      return privileges[0].PrivilegeInfo;
-    } else {
-      return angular.copy($scope.NONE_ROLE);
-    }
-  };
-
-  $scope.loadRoles = function() {
-    Cluster.getPermissions().then(function(data) {
-      $scope.roles = data.map(function(item) {
-        return item.PermissionInfo;
-      });
-      // [All, Administrator, ...roles..., None]
-      $scope.roles.unshift(angular.copy($scope.AMBARI_ADMIN_ROLE));
-      $scope.roles.unshift(angular.copy($scope.ALL_ROLE));
-      $scope.roles.push(angular.copy($scope.NONE_ROLE));
-
-      // create filter select list
-      $scope.roleFilterOptions = angular.copy($scope.roles);
-      $scope.roleFilterOptions.pop();  // filter does not support None
-      $scope.roleFilterOptions = $scope.roleFilterOptions.map(function(o) {
-        return {label: o.permission_label, value: o.permission_name};
-      });
-      $scope.currentRoleFilter = $scope.roleFilterOptions[0];
-
-      // create value select list
-      $scope.roleValueOptions = angular.copy($scope.roles)
-      $scope.roleValueOptions.shift(); // value change does not support all/administrator
-      $scope.roleValueOptions.shift();
-    });
-  };
-
-  $scope.getRoleRank = function(permission_name) {
-    var orderedRoles = Cluster.orderedRoles.concat(['VIEW.USER','CLUSTER.NONE']);
-    var index = orderedRoles.indexOf(permission_name);
-    return index;
-  };
-
-  $scope.save = function(user) {
-    var fromNone = (user.original_perm === $scope.NONE_ROLE.permission_name);
-    if (fromNone) {
-      $scope.addPrivilege(user);
-      return;
-    }
-
-    if ($scope.isUserActive) {
-      Cluster.getPrivilegesForResource({
-          nameFilter : user.user_name,
-          typeFilter : $scope.currentTypeFilter
-      }).then(function(data) {
-        var arrayOfPrivileges = data.items[0].privileges;
-        var privilegesOfTypeUser = [];
-        var privilegesOfTypeGroup = [];
-        for (var i = 0; i < arrayOfPrivileges.length; i++) {
-          if(arrayOfPrivileges[i].PrivilegeInfo.permission_name != "VIEW.USER") {
-            if(arrayOfPrivileges[i].PrivilegeInfo.principal_type === "GROUP"){
-              privilegesOfTypeGroup.push(arrayOfPrivileges[i]);
-            } else {
-              privilegesOfTypeUser.push(arrayOfPrivileges[i].PrivilegeInfo);
-            }
-          }
-        }
-
-        var effectivePrivilege = $scope.pickEffectivePrivilege(arrayOfPrivileges);
-        var effectivePrivilegeFromGroups = $scope.pickEffectivePrivilege(privilegesOfTypeGroup);
-        user.principal_type = 'USER';
-        user.original_perm = effectivePrivilege.permission_name;
-        user.editable = (Cluster.ineditableRoles.indexOf(effectivePrivilege.permission_name) === -1);
-
-        var userIndex = $scope.getRoleRank(user.permission_name);
-        var groupIndex = $scope.getRoleRank(effectivePrivilegeFromGroups.permission_name);
-
-        // Process when it's NONE privilege or higher than current effective group privilege
-        if (userIndex <= groupIndex || user.permission_name == $scope.NONE_ROLE.permission_name) {
-          var privilege_ids = privilegesOfTypeUser.filter(function(privilegeOfTypeUser) {
-            return privilegeOfTypeUser.principal_type !== 'ROLE';
-          }).map(function (privilegeOfTypeUser) {
-            return privilegeOfTypeUser.privilege_id;
-          });
-
-          // Purge existing user level privileges if there is any
-          if(privilege_ids.length !== 0) {
-            Cluster.deleteMultiplePrivileges(
-                $routeParams.id,
-                privilege_ids
-            )
-            .then(function() {
-              $scope.addPrivilege(user);
-            });
-          } else {
-            $scope.addPrivilege(user);
-          }
-        } else {
-          Alert.error($t('common.alerts.cannotSavePermissions'),
-              $t('users.alerts.usersEffectivePrivilege', {user_name : user.user_name})
-          );
-          $scope.loadUsers();
-        }
-      });
-    } else {
-      Cluster.getPrivilegesForResource({
-          nameFilter : user.group_name,
-          typeFilter : $scope.currentTypeFilter
-      }).then(function(data) {
-        var arrayOfPrivileges = data.items[0].privileges;
-        var privilegesOfTypeGroup = [];
-        var privilege = $scope.pickEffectivePrivilege(arrayOfPrivileges);
-        user.principal_type = 'GROUP';
-        user.original_perm = privilege.permission_name;
-        user.editable = (Cluster.ineditableRoles.indexOf(privilege.permission_name) === -1);
-
-        arrayOfPrivileges.forEach(function(privilegeOfTypeGroup) {
-          if(privilegeOfTypeGroup.PrivilegeInfo.permission_name != "VIEW.USER") {
-            if (privilegeOfTypeGroup.PrivilegeInfo.principal_type === "GROUP") {
-              privilegesOfTypeGroup.push(privilegeOfTypeGroup.PrivilegeInfo);
-            }
-          }
-        });
-
-        var privilege_ids = [];
-        privilegesOfTypeGroup.forEach(function(privilegeOfTypeGroup) {
-          privilege_ids.push(privilegeOfTypeGroup.privilege_id);
-        });
-
-        //delete all privileges of type GROUP, if they exist
-        //then add the privilege for the group, after which the group displays the effective privilege
-        if(privilege_ids.length !== 0) {
-          Cluster.deleteMultiplePrivileges(
-              $routeParams.id,
-              privilege_ids
-          )
-          .then(function() {
-            $scope.addPrivilege(user);
-          });
-        } else {
-          $scope.addPrivilege(user);
-        }
-      });
-    }
-  };
-
-  $scope.cancel = function(user) {
-    user.permission_name = user.original_perm;
-  };
-
-  $scope.addPrivilege = function(user) {
-    var changeToNone = user.permission_name == $scope.NONE_ROLE.permission_name;
-    if (changeToNone) {
-      if ($scope.isUserActive) {
-        Alert.success($t('users.alerts.roleChangedToNone', {
-            user_name : user.user_name
-        }));
-      } else {
-        $scope.showSuccess(user);
-      }
-      $scope.loadUsers();
-      return;
-    }
-    Cluster.createPrivileges(
-      {
-        clusterId: $routeParams.id
-      },
-      [{PrivilegeInfo: {
-        permission_name: user.permission_name,
-        principal_name: user.principal_name,
-        principal_type: user.principal_type
-      }}]
-    ).then(function() {
-        $scope.showSuccess(user);
-        $scope.loadUsers();
-      })
-      .catch(function(data) {
-        Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
-        $scope.loadUsers();
-      });
-  };
-
-  $scope.showSuccess = function(user) {
-    Alert.success($t('users.alerts.roleChanged', {
-      name: user.principal_name,
-      role: $scope.roles.filter(function(r){
-          return r.permission_name == user.permission_name}
-      )[0].permission_label
-    }));
-  };
-
-  $scope.resetPagination = function() {
-    $scope.currentPage = 1;
-    $scope.loadUsers();
-  };
-  $scope.currentRoleFilter = { label:$t('common.all'), value: '' };
-
-
-  $scope.typeFilterOptions = [
-    {label: $t('common.user'), value: 'USER'},
-    {label: $t('common.group'), value: 'GROUP'}
-  ];
-
-  $scope.isUserActive = true;
-
-  $scope.currentTypeFilter = $scope.typeFilterOptions[0];
-
-  $scope.switchToUser = function() {
-    if (!$scope.isUserActive) {
-      $scope.currentTypeFilter = $scope.typeFilterOptions[0];
-      $scope.isUserActive = true;
-      $scope.resetPagination();
-    }
-  };
-
-  $scope.switchToGroup = function() {
-    if ($scope.isUserActive) {
-      $scope.currentTypeFilter = $scope.typeFilterOptions[1];
-      $scope.isUserActive = false;
-      $scope.resetPagination();
-    }
-  };
-
-  $scope.clearFilters = function() {
-    $scope.currentNameFilter = '';
-    $scope.currentRoleFilter = $scope.roleFilterOptions[0];
-    $scope.resetPagination();
-  };
-
-  $scope.loadRoles();
-  $scope.loadUsers();
-
-  $scope.$watch(
-    function (scope) {
-      return Boolean(scope.currentNameFilter || (scope.currentRoleFilter && scope.currentRoleFilter.value));
-    },
-    function (newValue, oldValue, scope) {
-      scope.isNotEmptyFilter = newValue;
-    }
-  );
-
-  $rootScope.$watch(function(scope) {
-    return scope.LDAPSynced;
-  }, function(LDAPSynced) {
-    if(LDAPSynced === true){
-      $rootScope.LDAPSynced = false;
-      $scope.loadUsers();
-    }
-  });
-
-  $scope.switchToBlock = function() {
-    $location.url('/clusters/' + $routeParams.id + '/manageAccess');
-  };
-
-  $scope.showHelpPage = function() {
-    Cluster.getRolesWithAuthorizations().then(function(roles) {
-      RoleDetailsModal.show(roles);
-    });
-  };
-}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsCreateCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsCreateCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsCreateCtrl.js
deleted file mode 100644
index 67743a0..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsCreateCtrl.js
+++ /dev/null
@@ -1,65 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-.controller('GroupsCreateCtrl',['$scope', 'Group', '$location', 'Alert', 'UnsavedDialog', '$translate', function($scope, Group, $location, Alert, UnsavedDialog, $translate) {
-  var $t = $translate.instant;
-  $scope.group = new Group();
-  var targetUrl = '/groups';
-
-  $scope.createGroup = function() {
-    $scope.form.submitted = true;
-    if ($scope.form.$valid){
-      $scope.group.save().then(function() {
-        Alert.success($t('groups.alerts.groupCreated', {groupName: $scope.group.group_name}));
-        $scope.form.$setPristine();
-        $location.path(targetUrl);
-      })
-      .catch(function(data) {
-        Alert.error($t('groups.alerts.groupCreationError'), data.data.message);
-      });
-    }
-  };
-
-  $scope.cancel = function() {
-    $scope.form.$setPristine();
-    $location.path('/groups');
-  };
-
-  $scope.$on('$locationChangeStart', function(event, __targetUrl) {
-    if( $scope.form.$dirty ){
-      UnsavedDialog().then(function(action) {
-        targetUrl = __targetUrl.split('#').pop();
-        switch(action){
-          case 'save':
-            $scope.createGroup();
-            break;
-          case 'discard':
-            $scope.form.$setPristine();
-            $location.path(targetUrl);
-            break;
-          case 'cancel':
-            targetUrl = '/groups';
-            break;
-        }
-      });
-      event.preventDefault();
-    }
-  });
-}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsEditCtrl.js
deleted file mode 100644
index a63ebe2..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsEditCtrl.js
+++ /dev/null
@@ -1,180 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-.controller('GroupsEditCtrl',['$scope', 'Group', '$routeParams', 'Cluster', 'View', 'Alert', 'ConfirmationModal', '$location', 'GroupConstants', '$translate', function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $location, GroupConstants, $translate) {
-  var $t = $translate.instant;
-  $scope.constants = {
-    group: $t('common.group'),
-    view: $t('common.view').toLowerCase(),
-    cluster: $t('common.cluster').toLowerCase()
-  };
-  $scope.editMode = false;
-  $scope.group = new Group($routeParams.id);
-  $scope.group.editingUsers = [];
-  $scope.groupMembers = [];
-  $scope.dataLoaded = false;
-  
-  $scope.isMembersEditing = false;
-
-  $scope.$watch(function() {
-    return $scope.group.editingUsers;
-  }, function(newValue) {
-    if(newValue && !angular.equals(newValue, $scope.groupMembers)){
-      $scope.updateMembers();  
-    }
-  }, true);
-  
-  $scope.enableMembersEditing = function() {
-    $scope.isMembersEditing = true;
-    $scope.group.editingUsers = angular.copy($scope.groupMembers);
-  };
-  $scope.cancelUpdate = function() {
-    $scope.isMembersEditing = false;
-    $scope.group.editingUsers = '';
-  };
-  $scope.updateMembers = function() {
-    var newMembers = $scope.group.editingUsers.toString().split(',').filter(function(item) {
-      return item.trim();}
-    ).map(function(item) {
-        return item.trim()
-      }
-    );
-    $scope.group.members = newMembers;
-    $scope.group.saveMembers().catch(function(data) {
-        Alert.error($t('groups.alerts.cannotUpdateGroupMembers'), "<div class='break-word'>" + data.message + "</div>");
-      }).finally(function() {
-        loadMembers();
-      });
-    $scope.isMembersEditing = false;
-  };
-
-
-  function loadMembers(){
-    $scope.group.getMembers().then(function(members) {
-      $scope.group.groupTypeName = $t(GroupConstants.TYPES[$scope.group.group_type].LABEL_KEY);
-      $scope.groupMembers = members;
-      $scope.group.editingUsers = angular.copy($scope.groupMembers);
-    });
-  }    
-  
-  $scope.group.isLDAP().then(function(isLDAP) {
-    $scope.group.ldap_group = isLDAP;
-    $scope.group.getGroupType().then(function() {
-      $scope.group.groupTypeName = $t(GroupConstants.TYPES[$scope.group.group_type].LABEL_KEY);
-    });
-    loadMembers();
-  });
-
-  $scope.group.getGroupType();
-
-  $scope.deleteGroup = function(group) {
-    ConfirmationModal.show(
-      $t('common.delete', {
-        term: $t('common.group')
-      }),
-      $t('common.deleteConfirmation', {
-        instanceType: $t('common.group').toLowerCase(),
-        instanceName: '"' + group.group_name + '"'
-      })
-    ).then(function() {
-      Cluster.getPrivilegesForResource({
-        nameFilter : group.group_name,
-        typeFilter : {value: 'GROUP'}
-      }).then(function(data) {
-        var clusterPrivilegesIds = [];
-        var viewsPrivileges = [];
-        if (data.items && data.items.length) {
-          angular.forEach(data.items[0].privileges, function(privilege) {
-            if (privilege.PrivilegeInfo.principal_type === 'GROUP') {
-              if (privilege.PrivilegeInfo.type === 'VIEW') {
-                viewsPrivileges.push({
-                  id: privilege.PrivilegeInfo.privilege_id,
-                  view_name: privilege.PrivilegeInfo.view_name,
-                  version: privilege.PrivilegeInfo.version,
-                  instance_name: privilege.PrivilegeInfo.instance_name
-                });
-              } else {
-                clusterPrivilegesIds.push(privilege.PrivilegeInfo.privilege_id);
-              }
-            }
-          });
-        }
-        group.destroy().then(function() {
-          $location.path('/groups');
-          if (clusterPrivilegesIds.length) {
-            Cluster.getAllClusters().then(function (clusters) {
-              var clusterName = clusters[0].Clusters.cluster_name;
-              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
-            });
-          }
-          angular.forEach(viewsPrivileges, function(privilege) {
-            View.deletePrivilege(privilege);
-          });
-        });
-      });
-    });
-  };
-
-
-  $scope.removePrivilege = function(name, privilege) {
-    var privilegeObject = {
-        id: privilege.privilege_id,
-        view_name: privilege.view_name,
-        version: privilege.version,
-        instance_name: name
-    };
-    View.deletePrivilege(privilegeObject).then(function() {
-      loadPrivileges();
-    });
-  };
-
-function loadPrivileges() {
-  // Load privileges
-  Group.getPrivileges($routeParams.id).then(function(data) {
-    var privileges = {
-      clusters: {},
-      views: {}
-    };
-    angular.forEach(data.data.items, function(privilege) {
-      privilege = privilege.PrivilegeInfo;
-      if(privilege.type === 'CLUSTER'){
-        // This is cluster
-        privileges.clusters[privilege.cluster_name] = privileges.clusters[privilege.cluster_name] || [];
-        privileges.clusters[privilege.cluster_name].push(privilege.permission_label);
-      } else if ( privilege.type === 'VIEW'){
-        privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || { privileges:[]};
-        privileges.views[privilege.instance_name].version = privilege.version;
-        privileges.views[privilege.instance_name].view_name = privilege.view_name;
-        privileges.views[privilege.instance_name].privilege_id = privilege.privilege_id;
-        privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
-      }
-    });
-
-    $scope.privileges = data.data.items.length ? privileges : null;
-    $scope.noClusterPriv = $.isEmptyObject(privileges.clusters);
-    $scope.noViewPriv = $.isEmptyObject(privileges.views);
-    $scope.hidePrivileges = $scope.noClusterPriv && $scope.noViewPriv;
-    $scope.dataLoaded = true;
-  }).catch(function(data) {
-    Alert.error($t('common.alerts.cannotLoadPrivileges'), data.data.message);
-  });
-}
-loadPrivileges();
-}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsListCtrl.js
deleted file mode 100644
index 7cc590e..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/groups/GroupsListCtrl.js
+++ /dev/null
@@ -1,106 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-.controller('GroupsListCtrl',['$scope', 'Group', '$modal', 'ConfirmationModal', '$rootScope', 'GroupConstants', '$translate', function($scope, Group, $modal, ConfirmationModal, $rootScope, GroupConstants, $translate) {
-  var $t = $translate.instant;
-  $scope.constants = {
-    groups: $t('common.groups').toLowerCase()
-  };
-  $scope.isLoading = false;
-  $scope.groups = [];
-
-  $scope.groupsPerPage = 10;
-  $scope.currentPage = 1;
-  $scope.totalGroups = 1;
-  $scope.currentNameFilter = '';
-  $scope.maxVisiblePages=20;
-  $scope.tableInfo = {
-    total: 0,
-    showed: 0
-  };
-  $scope.isNotEmptyFilter = true;
-
-  $scope.pageChanged = function() {
-    loadGroups();
-  };
-  $scope.groupsPerPageChanges = function() {
-    loadGroups();
-  };
-
-  $scope.resetPagination = function() {
-    $scope.currentPage = 1;
-    loadGroups();
-  };
-
-  function loadGroups(){
-    $scope.isLoading = true;
-    Group.all({
-      currentPage: $scope.currentPage, 
-      groupsPerPage: $scope.groupsPerPage, 
-      searchString: $scope.currentNameFilter,
-      group_type: $scope.currentTypeFilter.value
-    }).then(function(groups) {
-      $scope.isLoading = false;
-      $scope.totalGroups = groups.itemTotal;
-      $scope.groups = groups.map(Group.makeGroup);
-      $scope.tableInfo.total = groups.itemTotal;
-      $scope.tableInfo.showed = groups.length;
-    })
-    .catch(function(data) {
-      console.error($t('groups.alerts.getGroupsListError'));
-    });
-  }
-
-  $scope.typeFilterOptions = [{ label: $t('common.all'), value: '*'}]
-    .concat(Object.keys(GroupConstants.TYPES).map(function(key) {
-      return {
-        label: $t(GroupConstants.TYPES[key].LABEL_KEY),
-        value: GroupConstants.TYPES[key].VALUE
-      };
-  }));
-  $scope.currentTypeFilter = $scope.typeFilterOptions[0];
-
-  $scope.clearFilters = function () {
-    $scope.currentNameFilter = '';
-    $scope.currentTypeFilter = $scope.typeFilterOptions[0];
-    $scope.resetPagination();
-  };
-  
-  loadGroups();
-
-  $scope.$watch(
-    function (scope) {
-      return Boolean(scope.currentNameFilter || (scope.currentTypeFilter && scope.currentTypeFilter.value !== '*'));
-    },
-    function (newValue, oldValue, scope) {
-      scope.isNotEmptyFilter = newValue;
-    }
-  );
-
-  $rootScope.$watch(function(scope) {
-    return scope.LDAPSynced;
-  }, function(LDAPSynced) {
-    if(LDAPSynced === true){
-      $rootScope.LDAPSynced = false;
-      loadGroups();
-    }
-  });
-
-}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
new file mode 100644
index 0000000..94a2c9f
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
@@ -0,0 +1,112 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('GroupCreateCtrl',
+['$scope', '$rootScope', 'Group', '$location', 'Alert', 'UnsavedDialog', '$translate', '$modalInstance', 'Cluster',
+function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate, $modalInstance, Cluster) {
+  var $t = $translate.instant;
+
+  $scope.form = {};
+  $scope.formData = {
+    groupName: '',
+    members: [],
+    role: ''
+  };
+  $scope.roleOptions = [];
+
+
+  function loadRoles() {
+    Cluster.getPermissions().then(function(data) {
+      $scope.roleOptions = data.map(function(item) {
+        return item.PermissionInfo;
+      });
+    });
+  }
+
+  function unsavedChangesCheck() {
+    if ($scope.form.groupCreateForm.$dirty) {
+      UnsavedDialog().then(function (action) {
+        switch (action) {
+          case 'save':
+            $scope.save();
+            break;
+          case 'discard':
+            $modalInstance.close('discard');
+            break;
+          case 'cancel':
+            break;
+        }
+      });
+    } else {
+      $modalInstance.close('discard');
+    }
+  }
+
+  function saveMembers(group, members) {
+    group.members = members.filter(function(item) {
+      return item.trim();
+    }).map(function(item) {
+      return item.trim();
+    });
+    group.saveMembers().catch(function(data) {
+      Alert.error($t('groups.alerts.cannotUpdateGroupMembers'), "<div class='break-word'>" + data.message + "</div>");
+    });
+  }
+
+  $scope.save = function () {
+    $scope.form.groupCreateForm.submitted = true;
+    if ($scope.form.groupCreateForm.$valid) {
+      var group = new Group($scope.formData.groupName);
+      group.save().then(function () {
+        saveMembers(group, $scope.formData.members);
+        saveRole();
+        $modalInstance.dismiss('created');
+        Alert.success($t('groups.alerts.groupCreated', {groupName: $scope.formData.groupName}));
+      })
+      .catch(function (data) {
+        Alert.error($t('groups.alerts.groupCreationError'), data.data.message);
+      });
+    }
+  };
+
+  function saveRole() {
+    Cluster.createPrivileges(
+      {
+        clusterId: $rootScope.cluster.Clusters.cluster_name
+      },
+      [{PrivilegeInfo: {
+        permission_name: $scope.roleOptions.filter(function(role) {
+          return role.permission_id == Number($scope.formData.role);
+        })[0].permission_name,
+        principal_name: $scope.formData.groupName,
+        principal_type: 'GROUP'
+      }}]
+    )
+      .catch(function(data) {
+        Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+      });
+  }
+
+  $scope.cancel = function () {
+    unsavedChangesCheck();
+  };
+
+  loadRoles();
+}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
new file mode 100644
index 0000000..ff705eb
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
@@ -0,0 +1,182 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('GroupEditCtrl',
+['$scope', 'Group', '$routeParams', 'Cluster', 'View', 'Alert', 'ConfirmationModal', '$location', 'GroupConstants', '$translate',
+function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $location, GroupConstants, $translate) {
+  var $t = $translate.instant;
+  $scope.constants = {
+    group: $t('common.group'),
+    view: $t('common.view').toLowerCase(),
+    cluster: $t('common.cluster').toLowerCase()
+  };
+  $scope.editMode = false;
+  $scope.group = new Group($routeParams.id);
+  $scope.group.editingUsers = [];
+  $scope.groupMembers = [];
+  $scope.dataLoaded = false;
+  
+  $scope.isMembersEditing = false;
+
+  $scope.$watch(function() {
+    return $scope.group.editingUsers;
+  }, function(newValue) {
+    if(newValue && !angular.equals(newValue, $scope.groupMembers)){
+      $scope.updateMembers();  
+    }
+  }, true);
+  
+  $scope.enableMembersEditing = function() {
+    $scope.isMembersEditing = true;
+    $scope.group.editingUsers = angular.copy($scope.groupMembers);
+  };
+  $scope.cancelUpdate = function() {
+    $scope.isMembersEditing = false;
+    $scope.group.editingUsers = '';
+  };
+  $scope.updateMembers = function() {
+    var newMembers = $scope.group.editingUsers.toString().split(',').filter(function(item) {
+      return item.trim();}
+    ).map(function(item) {
+        return item.trim()
+      }
+    );
+    $scope.group.members = newMembers;
+    $scope.group.saveMembers().catch(function(data) {
+        Alert.error($t('groups.alerts.cannotUpdateGroupMembers'), "<div class='break-word'>" + data.message + "</div>");
+      }).finally(function() {
+        loadMembers();
+      });
+    $scope.isMembersEditing = false;
+  };
+
+
+  function loadMembers(){
+    $scope.group.getMembers().then(function(members) {
+      $scope.group.groupTypeName = $t(GroupConstants.TYPES[$scope.group.group_type].LABEL_KEY);
+      $scope.groupMembers = members;
+      $scope.group.editingUsers = angular.copy($scope.groupMembers);
+    });
+  }    
+  
+  $scope.group.isLDAP().then(function(isLDAP) {
+    $scope.group.ldap_group = isLDAP;
+    $scope.group.getGroupType().then(function() {
+      $scope.group.groupTypeName = $t(GroupConstants.TYPES[$scope.group.group_type].LABEL_KEY);
+    });
+    loadMembers();
+  });
+
+  $scope.group.getGroupType();
+
+  $scope.deleteGroup = function(group) {
+    ConfirmationModal.show(
+      $t('common.delete', {
+        term: $t('common.group')
+      }),
+      $t('common.deleteConfirmation', {
+        instanceType: $t('common.group').toLowerCase(),
+        instanceName: '"' + group.group_name + '"'
+      })
+    ).then(function() {
+      Cluster.getPrivilegesForResource({
+        nameFilter : group.group_name,
+        typeFilter : {value: 'GROUP'}
+      }).then(function(data) {
+        var clusterPrivilegesIds = [];
+        var viewsPrivileges = [];
+        if (data.items && data.items.length) {
+          angular.forEach(data.items[0].privileges, function(privilege) {
+            if (privilege.PrivilegeInfo.principal_type === 'GROUP') {
+              if (privilege.PrivilegeInfo.type === 'VIEW') {
+                viewsPrivileges.push({
+                  id: privilege.PrivilegeInfo.privilege_id,
+                  view_name: privilege.PrivilegeInfo.view_name,
+                  version: privilege.PrivilegeInfo.version,
+                  instance_name: privilege.PrivilegeInfo.instance_name
+                });
+              } else {
+                clusterPrivilegesIds.push(privilege.PrivilegeInfo.privilege_id);
+              }
+            }
+          });
+        }
+        group.destroy().then(function() {
+          $location.path('/userManagement');
+          if (clusterPrivilegesIds.length) {
+            Cluster.getAllClusters().then(function (clusters) {
+              var clusterName = clusters[0].Clusters.cluster_name;
+              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
+            });
+          }
+          angular.forEach(viewsPrivileges, function(privilege) {
+            View.deletePrivilege(privilege);
+          });
+        });
+      });
+    });
+  };
+
+
+  $scope.removePrivilege = function(name, privilege) {
+    var privilegeObject = {
+        id: privilege.privilege_id,
+        view_name: privilege.view_name,
+        version: privilege.version,
+        instance_name: name
+    };
+    View.deletePrivilege(privilegeObject).then(function() {
+      loadPrivileges();
+    });
+  };
+
+function loadPrivileges() {
+  // Load privileges
+  Group.getPrivileges($routeParams.id).then(function(data) {
+    var privileges = {
+      clusters: {},
+      views: {}
+    };
+    angular.forEach(data.data.items, function(privilege) {
+      privilege = privilege.PrivilegeInfo;
+      if(privilege.type === 'CLUSTER'){
+        // This is cluster
+        privileges.clusters[privilege.cluster_name] = privileges.clusters[privilege.cluster_name] || [];
+        privileges.clusters[privilege.cluster_name].push(privilege.permission_label);
+      } else if ( privilege.type === 'VIEW'){
+        privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || { privileges:[]};
+        privileges.views[privilege.instance_name].version = privilege.version;
+        privileges.views[privilege.instance_name].view_name = privilege.view_name;
+        privileges.views[privilege.instance_name].privilege_id = privilege.privilege_id;
+        privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
+      }
+    });
+
+    $scope.privileges = data.data.items.length ? privileges : null;
+    $scope.noClusterPriv = $.isEmptyObject(privileges.clusters);
+    $scope.noViewPriv = $.isEmptyObject(privileges.views);
+    $scope.hidePrivileges = $scope.noClusterPriv && $scope.noViewPriv;
+    $scope.dataLoaded = true;
+  }).catch(function(data) {
+    Alert.error($t('common.alerts.cannotLoadPrivileges'), data.data.message);
+  });
+}
+loadPrivileges();
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
new file mode 100644
index 0000000..af77ba9
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
@@ -0,0 +1,170 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('GroupsListCtrl',
+['$scope', 'Group', '$modal', 'ConfirmationModal', '$rootScope', 'GroupConstants', '$translate', 'Settings', 'Cluster', 'View', '$location',
+function($scope, Group, $modal, ConfirmationModal, $rootScope, GroupConstants, $translate, Settings, Cluster, View, $location) {
+  var $t = $translate.instant;
+  $scope.constants = {
+    groups: $t('common.groups').toLowerCase()
+  };
+  $scope.minRowsToShowPagination = Settings.minRowsToShowPagination;
+  $scope.isLoading = false;
+  $scope.groups = [];
+
+  $scope.groupsPerPage = 10;
+  $scope.currentPage = 1;
+  $scope.totalGroups = 0;
+  $scope.filter = {
+    name: '',
+    type: null
+  };
+  $scope.maxVisiblePages=20;
+  $scope.tableInfo = {
+    total: 0,
+    showed: 0
+  };
+  $scope.isNotEmptyFilter = true;
+
+  $scope.pageChanged = function() {
+    loadGroups();
+  };
+  $scope.groupsPerPageChanges = function() {
+    loadGroups();
+  };
+
+  $scope.resetPagination = function() {
+    $scope.currentPage = 1;
+    loadGroups();
+  };
+
+  function loadGroups(){
+    $scope.isLoading = true;
+    Group.all({
+      currentPage: $scope.currentPage, 
+      groupsPerPage: $scope.groupsPerPage, 
+      searchString: $scope.filter.name,
+      group_type: $scope.filter.type.value
+    }).then(function(groups) {
+      $scope.isLoading = false;
+      $scope.totalGroups = groups.itemTotal;
+      $scope.groups = groups.map(Group.makeGroup);
+      $scope.tableInfo.total = groups.itemTotal;
+      $scope.tableInfo.showed = groups.length;
+    })
+    .catch(function(data) {
+      console.error($t('groups.alerts.getGroupsListError'));
+    });
+  }
+
+  $scope.typeFilterOptions = [{ label: $t('common.all'), value: '*'}]
+    .concat(Object.keys(GroupConstants.TYPES).map(function(key) {
+      return {
+        label: $t(GroupConstants.TYPES[key].LABEL_KEY),
+        value: GroupConstants.TYPES[key].VALUE
+      };
+  }));
+  $scope.filter.type = $scope.typeFilterOptions[0];
+
+  $scope.clearFilters = function () {
+    $scope.filter.name = '';
+    $scope.filter.type = $scope.typeFilterOptions[0];
+    $scope.resetPagination();
+  };
+  
+  loadGroups();
+
+  $scope.$watch(
+    function (scope) {
+      return Boolean(scope.filter.name || (scope.filter.type && scope.filter.type.value !== '*'));
+    },
+    function (newValue, oldValue, scope) {
+      scope.isNotEmptyFilter = newValue;
+    }
+  );
+
+  $rootScope.$watch(function(scope) {
+    return scope.LDAPSynced;
+  }, function(LDAPSynced) {
+    if(LDAPSynced === true){
+      $rootScope.LDAPSynced = false;
+      loadGroups();
+    }
+  });
+
+  $scope.createGroup = function () {
+    var modalInstance = $modal.open({
+      templateUrl: 'views/userManagement/modals/groupCreate.html',
+      controller: 'GroupCreateCtrl',
+      backdrop: 'static'
+    });
+
+    modalInstance.result.catch(loadGroups);
+  };
+
+  $scope.deleteGroup = function(group) {
+    ConfirmationModal.show(
+      $t('common.delete', {
+        term: $t('common.group')
+      }),
+      $t('common.deleteConfirmation', {
+        instanceType: $t('common.group').toLowerCase(),
+        instanceName: '"' + group.group_name + '"'
+      })
+    ).then(function() {
+      Cluster.getPrivilegesForResource({
+        nameFilter : group.group_name,
+        typeFilter : {value: 'GROUP'}
+      }).then(function(data) {
+        var clusterPrivilegesIds = [];
+        var viewsPrivileges = [];
+        if (data.items && data.items.length) {
+          angular.forEach(data.items[0].privileges, function(privilege) {
+            if (privilege.PrivilegeInfo.principal_type === 'GROUP') {
+              if (privilege.PrivilegeInfo.type === 'VIEW') {
+                viewsPrivileges.push({
+                  id: privilege.PrivilegeInfo.privilege_id,
+                  view_name: privilege.PrivilegeInfo.view_name,
+                  version: privilege.PrivilegeInfo.version,
+                  instance_name: privilege.PrivilegeInfo.instance_name
+                });
+              } else {
+                clusterPrivilegesIds.push(privilege.PrivilegeInfo.privilege_id);
+              }
+            }
+          });
+        }
+        group.destroy().then(function() {
+          if (clusterPrivilegesIds.length) {
+            Cluster.getAllClusters().then(function (clusters) {
+              var clusterName = clusters[0].Clusters.cluster_name;
+              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
+            });
+          }
+          angular.forEach(viewsPrivileges, function(privilege) {
+            View.deletePrivilege(privilege);
+          });
+          loadGroups();
+        });
+      });
+    });
+  };
+
+}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
new file mode 100644
index 0000000..34637ae
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
@@ -0,0 +1,108 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('UserCreateCtrl',
+['$scope', '$rootScope', 'User', '$location', 'Alert', 'UnsavedDialog', '$translate', 'Cluster', '$modalInstance',
+function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate, Cluster, $modalInstance) {
+  var $t = $translate.instant;
+
+  $scope.form = {};
+  $scope.formData = {
+    userName: '',
+    password: '',
+    confirmPassword: '',
+    role: null,
+    isAdmin: false,
+    isActive: true
+  };
+  $scope.roleOptions = [];
+
+  function loadRoles() {
+    Cluster.getPermissions().then(function(data) {
+      $scope.roleOptions = data.map(function(item) {
+        return item.PermissionInfo;
+      });
+    });
+  }
+
+  function unsavedChangesCheck() {
+    if ($scope.form.userCreateForm.$dirty) {
+      UnsavedDialog().then(function (action) {
+        switch (action) {
+          case 'save':
+            $scope.save();
+            break;
+          case 'discard':
+            $modalInstance.close('discard');
+            break;
+          case 'cancel':
+            break;
+        }
+      });
+    } else {
+      $modalInstance.close('discard');
+    }
+  }
+
+  $scope.save = function () {
+    $scope.form.userCreateForm.submitted = true;
+    if ($scope.form.userCreateForm.$valid) {
+      User.create({
+        'Users/user_name': $scope.formData.userName,
+        'Users/password': $scope.formData.password,
+        'Users/active': Boolean($scope.formData.isActive),
+        'Users/admin': Boolean($scope.formData.isAdmin)
+      }).then(function () {
+        saveRole();
+        $modalInstance.dismiss('created');
+        Alert.success($t('users.alerts.userCreated', {
+          userName: $scope.formData.userName,
+          encUserName: encodeURIComponent($scope.formData.userName)
+        }));
+      }).catch(function (data) {
+        Alert.error($t('users.alerts.userCreationError'), data.data.message);
+      });
+    }
+  };
+
+  function saveRole() {
+    Cluster.createPrivileges(
+      {
+        clusterId: $rootScope.cluster.Clusters.cluster_name
+      },
+      [{PrivilegeInfo: {
+        permission_name: $scope.roleOptions.filter(function(role) {
+          return role.permission_id == Number($scope.formData.role);
+        })[0].permission_name,
+        principal_name: $scope.formData.userName,
+        principal_type: 'USER'
+      }}]
+    )
+    .catch(function(data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
+  }
+
+  $scope.cancel = function () {
+    unsavedChangesCheck();
+  };
+
+  loadRoles();
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
new file mode 100644
index 0000000..001bb1b
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
@@ -0,0 +1,290 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('UserEditCtrl', ['$scope', '$routeParams', 'Cluster', 'User', 'View', '$modal', '$location', 'ConfirmationModal', 'Alert', 'Auth', 'getDifference', 'Group', '$q', 'UserConstants', '$translate', function($scope, $routeParams, Cluster, User, View, $modal, $location, ConfirmationModal, Alert, Auth, getDifference, Group, $q, UserConstants, $translate) {
+
+  var $t = $translate.instant;
+
+  $scope.constants = {
+    user: $t('common.user'),
+    status: $t('users.status'),
+    admin: $t('users.admin'),
+    password: $t('users.password'),
+    view: $t('common.view').toLowerCase(),
+    cluster: $t('common.cluster').toLowerCase()
+  };
+
+  function loadUserInfo(){
+    User.get($routeParams.id).then(function(data) {
+      $scope.user = User.makeUser(data).Users;
+      $scope.isCurrentUser = $scope.user.user_name === Auth.getCurrentUser();
+      $scope.editingGroupsList = angular.copy($scope.user.groups);
+    });
+  }
+
+  loadUserInfo();
+  $scope.user;
+  $scope.isCurrentUser = true;
+  $scope.dataLoaded = false;
+
+  $scope.isGroupEditing = false;
+  $scope.enableGroupEditing = function() {
+    $scope.isGroupEditing = true;
+    $scope.editingGroupsList = angular.copy($scope.user.groups);
+  };
+
+  $scope.$watch(function() {
+    return $scope.editingGroupsList;
+  }, function(newValue) {
+    if(newValue){
+      if( !angular.equals(newValue, $scope.user.groups) ){
+        $scope.updateGroups();
+      }
+    }
+  }, true);
+
+  $scope.updateGroups = function() {
+    var groups = $scope.editingGroupsList.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()});
+    var diff = getDifference($scope.user.groups, groups);
+    var promises = [];
+    // Remove user from groups
+    angular.forEach(diff.del, function(groupName) {
+      promises.push(Group.removeMemberFromGroup(groupName, $scope.user.user_name).catch(function(data) {
+        Alert.error($t('users.alerts.removeUserError'), data.data.message);
+      }));
+    });
+    // Add user to groups
+    angular.forEach(diff.add, function(groupName) {
+      promises.push(Group.addMemberToGroup(groupName, $scope.user.user_name).catch(function(data) {
+        Alert.error($t('users.alerts.cannotAddUser'), data.data.message);
+      }));
+    });
+    $q.all(promises).then(function() {
+      loadUserInfo();
+    });
+    $scope.isGroupEditing = false;
+  };
+
+  $scope.getUserMembership = function(userType) {
+    if(userType) {
+	return $t(UserConstants.TYPES[userType].LABEL_KEY) + " " + $t('users.groupMembership');
+    }
+  };
+
+  $scope.cancelUpdate = function() {
+    $scope.isGroupEditing = false;
+    $scope.editingGroupsList = '';
+  };
+
+  $scope.openChangePwdDialog = function() {
+    var modalInstance = $modal.open({
+      templateUrl: 'views/userManagement/modals/changePassword.html',
+      resolve: {
+        userName: function() {
+          return $scope.user.user_name;
+        }
+      },
+      controller: ['$scope', 'userName', function($scope, userName) {
+        $scope.passwordData = {
+          password: '',
+          currentUserPassword: ''
+        };
+
+        $scope.form = {};
+        $scope.userName = userName;
+
+        $scope.ok = function() {
+          $scope.form.passwordChangeForm.submitted = true;
+          if($scope.form.passwordChangeForm.$valid){
+
+            modalInstance.close({
+              password: $scope.passwordData.password, 
+              currentUserPassword: $scope.passwordData.currentUserPassword
+            });
+          }
+        };
+        $scope.cancel = function() {
+          modalInstance.dismiss('cancel');
+        };
+      }]
+    });
+
+    modalInstance.result.then(function(data) {
+      User.setPassword($scope.user, data.password, data.currentUserPassword).then(function() {
+        Alert.success($t('users.alerts.passwordChanged'));
+      }).catch(function(data) {
+        Alert.error($t('users.alerts.cannotChangePassword'), data.data.message);
+      });
+    }); 
+  };
+
+  $scope.toggleUserActive = function() {
+    if(!$scope.isCurrentUser){
+      var newStatusKey = $scope.user.active ? 'inactive' : 'active',
+        newStatus = $t('users.' + newStatusKey).toLowerCase();
+      ConfirmationModal.show(
+        $t('users.changeStatusConfirmation.title'),
+        $t('users.changeStatusConfirmation.message', {
+          userName: $scope.user.user_name,
+          status: newStatus
+        })
+      ).then(function() {
+        User.setActive($scope.user.user_name, $scope.user.active)
+          .catch(function(data) {
+            Alert.error($t('common.alerts.cannotUpdateStatus'), data.data.message);
+            $scope.user.active = !$scope.user.active;
+          });
+      })
+      .catch(function() {
+        $scope.user.active = !$scope.user.active;
+      });
+    }
+  };    
+  $scope.toggleUserAdmin = function() {
+    if(!$scope.isCurrentUser){
+      var action = $scope.user.admin ?
+        $t('users.changePrivilegeConfirmation.revoke') : $t('users.changePrivilegeConfirmation.grant');
+      ConfirmationModal.show(
+        $t('users.changePrivilegeConfirmation.title'),
+        $t('users.changePrivilegeConfirmation.message', {
+          action: action,
+          userName: $scope.user.user_name
+        })
+      ).then(function() {
+        User.setAdmin($scope.user.user_name, $scope.user.admin)
+        .then(function() {
+          loadPrivileges();
+        })
+        .catch(function (data) {
+          Alert.error($t('common.alerts.cannotUpdateAdminStatus'), data.data.message);
+          $scope.user.admin = !$scope.user.admin;
+        });
+      })
+      .catch(function() {
+        $scope.user.admin = !$scope.user.admin;
+      });
+
+    }
+  };
+
+  $scope.removePrivilege = function(name, privilege) {
+    var privilegeObject = {
+        id: privilege.privilege_id,
+        view_name: privilege.view_name,
+        version: privilege.version,
+        instance_name: name
+    };
+    View.deletePrivilege(privilegeObject).then(function() {
+      loadPrivileges();
+    });
+  };
+
+  $scope.deleteUser = function() {
+    ConfirmationModal.show(
+      $t('common.delete', {
+        term: $t('common.user')
+      }),
+      $t('common.deleteConfirmation', {
+        instanceType: $t('common.user').toLowerCase(),
+        instanceName: '"' + $scope.user.user_name + '"'
+      })
+    ).then(function() {
+      Cluster.getPrivilegesForResource({
+        nameFilter : $scope.user.user_name,
+        typeFilter : {value: 'USER'}
+      }).then(function(data) {
+        var clusterPrivilegesIds = [];
+        var viewsPrivileges = [];
+        if (data.items && data.items.length) {
+          angular.forEach(data.items[0].privileges, function(privilege) {
+            if (privilege.PrivilegeInfo.principal_type === 'USER') {
+              if (privilege.PrivilegeInfo.type === 'VIEW') {
+                viewsPrivileges.push({
+                  id: privilege.PrivilegeInfo.privilege_id,
+                  view_name: privilege.PrivilegeInfo.view_name,
+                  version: privilege.PrivilegeInfo.version,
+                  instance_name: privilege.PrivilegeInfo.instance_name
+                });
+              } else {
+                clusterPrivilegesIds.push(privilege.PrivilegeInfo.privilege_id);
+              }
+            }
+          });
+        }
+        User.delete($scope.user.user_name).then(function() {
+          $location.path('/userManagement');
+          if (clusterPrivilegesIds.length) {
+            Cluster.getAllClusters().then(function (clusters) {
+              var clusterName = clusters[0].Clusters.cluster_name;
+              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
+            });
+          }
+          angular.forEach(viewsPrivileges, function(privilege) {
+            View.deletePrivilege(privilege);
+          });
+        });
+      });
+    });
+  };
+
+  // Load privileges
+  function loadPrivileges(){
+    User.getPrivileges($routeParams.id).then(function(data) {
+      var privileges = {
+        clusters: {},
+        views: {}
+      };
+      angular.forEach(data.data.items, function(privilege) {
+        privilege = privilege.PrivilegeInfo;
+        if(privilege.type === 'CLUSTER'){
+          // This is cluster
+          if (privileges.clusters[privilege.cluster_name]) {
+            var preIndex = Cluster.orderedRoles.indexOf(privileges.clusters[privilege.cluster_name].permission_name);
+            var curIndex = Cluster.orderedRoles.indexOf(privilege.permission_name);
+            // replace when cur is a more powerful role
+            if (curIndex < preIndex) {
+              privileges.clusters[privilege.cluster_name] = privilege;
+            }
+          } else {
+            privileges.clusters[privilege.cluster_name] = privilege;
+          }
+        } else if ( privilege.type === 'VIEW'){
+          privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || { privileges:[]};
+          privileges.views[privilege.instance_name].version = privilege.version;
+          privileges.views[privilege.instance_name].view_name = privilege.view_name;
+          privileges.views[privilege.instance_name].privilege_id = privilege.privilege_id;
+          if (privileges.views[privilege.instance_name].privileges.indexOf(privilege.permission_label) == -1) {
+            privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
+          }
+        }
+      });
+
+      $scope.privileges = data.data.items.length ? privileges : null;
+      $scope.noClusterPriv = $.isEmptyObject(privileges.clusters);
+      $scope.noViewPriv = $.isEmptyObject(privileges.views);
+      $scope.hidePrivileges = $scope.noClusterPriv && $scope.noViewPriv;
+      $scope.dataLoaded = true;
+
+    }).catch(function(data) {
+      Alert.error($t('common.alerts.cannotLoadPrivileges'), data.data.message);
+    });
+  }
+  loadPrivileges();
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
new file mode 100644
index 0000000..e9ec6ab
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('UserManagementCtrl', ['$scope', function($scope) {
+  $scope.activeTab = 'USERS';
+}]);


[24/49] ambari git commit: AMBARI-22501. stack advisor error while adding Druid service (alexantonenko)

Posted by rl...@apache.org.
AMBARI-22501. stack advisor error while adding Druid service (alexantonenko)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: f343e8c0f596d9bd3610c23b387c370dbf6f6028
Parents: cadbf35
Author: Alex Antonenko <aa...@hortonworks.com>
Authored: Wed Nov 22 21:19:23 2017 +0300
Committer: Alex Antonenko <aa...@hortonworks.com>
Committed: Wed Nov 22 21:19:23 2017 +0300

----------------------------------------------------------------------
 ambari-web/app/mixins/wizard/addSecurityConfigs.js | 7 +++++++
 1 file changed, 7 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f343e8c0/ambari-web/app/mixins/wizard/addSecurityConfigs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/wizard/addSecurityConfigs.js b/ambari-web/app/mixins/wizard/addSecurityConfigs.js
index 89d3cf7..bd6fa89 100644
--- a/ambari-web/app/mixins/wizard/addSecurityConfigs.js
+++ b/ambari-web/app/mixins/wizard/addSecurityConfigs.js
@@ -657,6 +657,13 @@ App.AddSecurityConfigs = Em.Mixin.create({
       return p;
     }, {});
 
+    if (this.get('isWithinAddService')) {
+      this.get('content.masterComponentHosts').filterProperty('isInstalled', false).forEach(function(item) {
+        var hostGroupName = blueprintUtils.getHostGroupByFqdn(recommendations, item.hostName);
+        blueprintUtils.addComponentToHostGroup(recommendations, item.component, hostGroupName);
+      }, this);
+    }
+
     return recommendations;
   },
 


[34/49] ambari git commit: AMBARI-22502.Workflow Manager View - FS node will overwrite internal commands and replace them with blank "move" commands when reopening the node(Venkata Sairam)

Posted by rl...@apache.org.
AMBARI-22502.Workflow Manager View - FS node will overwrite internal commands and replace them with blank "move" commands when reopening the node(Venkata Sairam)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 51360219866386d8103326def2a1d412348414ed
Parents: 20dee7f
Author: Venkata Sairam <ve...@gmail.com>
Authored: Thu Nov 23 15:36:57 2017 +0530
Committer: Venkata Sairam <ve...@gmail.com>
Committed: Thu Nov 23 15:36:57 2017 +0530

----------------------------------------------------------------------
 .../src/main/resources/ui/app/domain/workflow-importer.js         | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/51360219/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js
index 84a789d..2afc304 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js
@@ -112,7 +112,8 @@ var WorkflowImporter= Ember.Object.extend({
       if (nodeHandler){
         if (Ember.isArray(workflowAppJson[key])){
           workflowAppJson[key].forEach(function(jsonObj){
-            var node=nodeHandler.handleImportNode(key,jsonObj,workflow,xmlDoc);
+            var actionDom = xmlDoc.find("action[name='" + jsonObj._name + "']");
+            var node = nodeHandler.handleImportNode(key,jsonObj,workflow,actionDom);
             nodeMap.set(jsonObj._name,{json:jsonObj,node:node});
           });
         }else{


[30/49] ambari git commit: AMBARI-22499. Ambari server becomes unusable when config properties are misconfigured (adoroszlai)

Posted by rl...@apache.org.
AMBARI-22499. Ambari server becomes unusable when config properties are misconfigured (adoroszlai)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 1d4cbc8aca2eddd0294b27755ec5769c66bf6b80
Parents: bce0bd8
Author: Attila Doroszlai <ad...@hortonworks.com>
Authored: Wed Nov 22 13:30:05 2017 +0100
Committer: Doroszlai, Attila <ad...@hortonworks.com>
Committed: Thu Nov 23 00:35:09 2017 +0100

----------------------------------------------------------------------
 .../ambari/server/state/ConfigHelper.java       | 28 ++++++------
 .../ambari/server/state/ConfigHelperTest.java   | 47 ++++++++++++++++++++
 2 files changed, 61 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/1d4cbc8a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
index eade914..6813fc0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
@@ -1503,22 +1503,22 @@ public class ConfigHelper {
   }
 
   /**
-   * Compares values as double in case they are numbers.
-   * @param actualValue
-   * @param newValue
-   * @return
+   * Checks for equality of parsed numbers if both values are numeric,
+   * otherwise using regular equality.
    */
-  private  boolean valuesAreEqual(String actualValue, String newValue) {
-    boolean actualValueIsNumber = NumberUtils.isNumber(actualValue);
-    boolean newValueIsNumber = NumberUtils.isNumber(newValue);
-    if (actualValueIsNumber && newValueIsNumber) {
-      Double ab = Double.parseDouble(actualValue);
-      Double bb = Double.parseDouble(newValue);
-      return ab.equals(bb);
-    } else if (!actualValueIsNumber && !newValueIsNumber) {
-      return actualValue.equals(newValue);
+  static boolean valuesAreEqual(String value1, String value2) { // exposed for unit test
+    if (NumberUtils.isNumber(value1) && NumberUtils.isNumber(value2)) {
+      try {
+        Number number1 = NumberUtils.createNumber(value1);
+        Number number2 = NumberUtils.createNumber(value2);
+        return Objects.equal(number1, number2) ||
+          number1.doubleValue() == number2.doubleValue();
+      } catch (NumberFormatException e) {
+        // fall back to regular equality
+      }
     }
-    return false;
+
+    return Objects.equal(value1, value2);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/1d4cbc8a/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java
index 8a0a782..ff0bf59 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java
@@ -22,6 +22,8 @@ import static org.easymock.EasyMock.createStrictMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import java.sql.SQLException;
 import java.util.ArrayList;
@@ -1212,4 +1214,49 @@ public class ConfigHelperTest {
       verify(mockAmbariMetaInfo, mockStackVersion, mockServiceInfo, mockPropertyInfo1, mockPropertyInfo2);
     }
   }
+
+  public static class RunWithoutModules {
+    @Test
+    public void nullsAreEqual() {
+      assertTrue(ConfigHelper.valuesAreEqual(null, null));
+    }
+
+    @Test
+    public void equalStringsAreEqual() {
+      assertTrue(ConfigHelper.valuesAreEqual("asdf", "asdf"));
+      assertTrue(ConfigHelper.valuesAreEqual("qwerty", "qwerty"));
+    }
+
+    @Test
+    public void nullIsNotEqualWithNonNull() {
+      assertFalse(ConfigHelper.valuesAreEqual(null, "asdf"));
+      assertFalse(ConfigHelper.valuesAreEqual("asdf", null));
+    }
+
+    @Test
+    public void equalNumbersInDifferentFormsAreEqual() {
+      assertTrue(ConfigHelper.valuesAreEqual("1.234", "1.2340"));
+      assertTrue(ConfigHelper.valuesAreEqual("12.34", "1.234e1"));
+      assertTrue(ConfigHelper.valuesAreEqual("123L", "123l"));
+      assertTrue(ConfigHelper.valuesAreEqual("-1.234", "-1.2340"));
+      assertTrue(ConfigHelper.valuesAreEqual("-12.34", "-1.234e1"));
+      assertTrue(ConfigHelper.valuesAreEqual("-123L", "-123l"));
+      assertTrue(ConfigHelper.valuesAreEqual("1f", "1.0f"));
+      assertTrue(ConfigHelper.valuesAreEqual("0", "000"));
+
+      // these are treated as different by NumberUtils (due to different types not being equal)
+      assertTrue(ConfigHelper.valuesAreEqual("123", "123L"));
+      assertTrue(ConfigHelper.valuesAreEqual("0", "0.0"));
+    }
+
+    @Test
+    public void differentNumbersAreNotEqual() {
+      assertFalse(ConfigHelper.valuesAreEqual("1.234", "1.2341"));
+      assertFalse(ConfigHelper.valuesAreEqual("123L", "124L"));
+      assertFalse(ConfigHelper.valuesAreEqual("-1.234", "1.234"));
+      assertFalse(ConfigHelper.valuesAreEqual("-123L", "123L"));
+      assertFalse(ConfigHelper.valuesAreEqual("-1.234", "-1.2341"));
+      assertFalse(ConfigHelper.valuesAreEqual("-123L", "-124L"));
+    }
+  }
 }


[10/49] ambari git commit: AMBARI-22477 Log Search UI: implement access logs table. (ababiichuk)

Posted by rl...@apache.org.
AMBARI-22477 Log Search UI: implement access logs table. (ababiichuk)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: cc535c841f28ea50cf659ada8e573e84141146ac
Parents: 786d4b6
Author: ababiichuk <ab...@hortonworks.com>
Authored: Mon Nov 20 13:33:47 2017 +0200
Committer: ababiichuk <ab...@hortonworks.com>
Committed: Mon Nov 20 13:33:47 2017 +0200

----------------------------------------------------------------------
 .../ambari-logsearch-web/src/app/app.module.ts  |   6 +-
 .../components/logs-table-component.spec.ts     |  61 +++++++
 .../classes/components/logs-table-component.ts  |  51 ++++++
 .../src/app/classes/models/audit-log.ts         |   2 +-
 .../audit-logs-table.component.html             |  54 +++++++
 .../audit-logs-table.component.less             |  21 +++
 .../audit-logs-table.component.spec.ts          | 157 +++++++++++++++++++
 .../audit-logs-table.component.ts               |  55 +++++++
 .../filters-panel/filters-panel.component.ts    |   2 +-
 .../logs-container.component.html               |  15 +-
 .../logs-container/logs-container.component.ts  |  62 ++------
 .../logs-list/logs-list.component.html          |  72 ---------
 .../logs-list/logs-list.component.less          |  97 ------------
 .../logs-list/logs-list.component.spec.ts       | 110 -------------
 .../components/logs-list/logs-list.component.ts | 151 ------------------
 .../service-logs-table.component.html           |  76 +++++++++
 .../service-logs-table.component.less           |  97 ++++++++++++
 .../service-logs-table.component.spec.ts        | 126 +++++++++++++++
 .../service-logs-table.component.ts             | 135 ++++++++++++++++
 .../ambari-logsearch-web/src/app/mock-data.ts   |   4 +-
 .../src/app/services/auth.service.spec.ts       |   2 +-
 .../src/app/services/logs-container.service.ts  |  95 +++++++++--
 .../src/app/services/mock-api-data.service.ts   |  22 +++
 23 files changed, 970 insertions(+), 503 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts b/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts
index 805f8e2..5e43582 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/app.module.ts
@@ -67,7 +67,6 @@ import {DropdownListComponent} from '@app/components/dropdown-list/dropdown-list
 import {FilterButtonComponent} from '@app/components/filter-button/filter-button.component';
 import {AccordionPanelComponent} from '@app/components/accordion-panel/accordion-panel.component';
 import {CollapsiblePanelComponent} from '@app/components/collapsible-panel/collapsible-panel.component';
-import {LogsListComponent} from '@app/components/logs-list/logs-list.component';
 import {LogMessageComponent} from '@app/components/log-message/log-message.component';
 import {LogLevelComponent} from '@app/components/log-level/log-level.component';
 import {DropdownButtonComponent} from '@app/components/dropdown-button/dropdown-button.component';
@@ -85,6 +84,8 @@ import {DatePickerComponent} from '@app/components/date-picker/date-picker.compo
 import {LogContextComponent} from '@app/components/log-context/log-context.component';
 import {LogFileEntryComponent} from '@app/components/log-file-entry/log-file-entry.component';
 import {TabsComponent} from '@app/components/tabs/tabs.component';
+import {ServiceLogsTableComponent} from '@app/components/service-logs-table/service-logs-table.component';
+import {AuditLogsTableComponent} from '@app/components/audit-logs-table/audit-logs-table.component';
 
 import {TimeZoneAbbrPipe} from '@app/pipes/timezone-abbr.pipe';
 import {TimerSecondsPipe} from '@app/pipes/timer-seconds.pipe';
@@ -122,7 +123,6 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR
     FilterButtonComponent,
     AccordionPanelComponent,
     CollapsiblePanelComponent,
-    LogsListComponent,
     LogLevelComponent,
     LogMessageComponent,
     DropdownButtonComponent,
@@ -140,6 +140,8 @@ export function getXHRBackend(injector: Injector, browser: BrowserXhr, xsrf: XSR
     LogContextComponent,
     LogFileEntryComponent,
     TabsComponent,
+    ServiceLogsTableComponent,
+    AuditLogsTableComponent,
     TimeZoneAbbrPipe,
     TimerSecondsPipe
   ],

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.spec.ts
new file mode 100644
index 0000000..05f80a7
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.spec.ts
@@ -0,0 +1,61 @@
+/**
+ * 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 {LogsTableComponent} from './logs-table-component';
+
+describe('LogsTableComponent', () => {
+  let component;
+
+  beforeEach(() => {
+    component = new LogsTableComponent();
+  });
+
+  describe('#isColumnDisplayed()', () => {
+    const cases = [
+      {
+        name: 'v1',
+        result: true,
+        title: 'column is displayed'
+      },
+      {
+        name: 'l1',
+        result: false,
+        title: 'column is not displayed'
+      }
+    ];
+
+    beforeEach(() => {
+      component.displayedColumns = [
+        {
+          label: 'l0',
+          value: 'v0'
+        },
+        {
+          label: 'l1',
+          value: 'v1'
+        }
+      ];
+    });
+
+    cases.forEach(test => {
+      it(test.title, () => {
+        expect(component.isColumnDisplayed(test.name)).toEqual(test.result);
+      });
+    });
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.ts
new file mode 100644
index 0000000..0b8866a
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/logs-table-component.ts
@@ -0,0 +1,51 @@
+/**
+ * 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 {OnChanges, SimpleChanges, Input} from '@angular/core';
+import {FormGroup} from '@angular/forms';
+import {ListItem} from '@app/classes/list-item';
+import {ServiceLog} from '@app/classes/models/service-log';
+import {AuditLog} from '@app/classes/models/audit-log';
+
+export class LogsTableComponent implements OnChanges {
+
+  ngOnChanges(changes: SimpleChanges) {
+    if (changes.hasOwnProperty('columns')) {
+      this.displayedColumns = this.columns.filter((column: ListItem): boolean => column.isChecked);
+    }
+  }
+
+  @Input()
+  logs: ServiceLog[] | AuditLog[] = [];
+
+  @Input()
+  columns: ListItem[] = [];
+
+  @Input()
+  filtersForm: FormGroup;
+
+  @Input()
+  totalCount: number = 0;
+
+  displayedColumns: ListItem[] = [];
+
+  isColumnDisplayed(key: string): boolean {
+    return this.displayedColumns.some((column: ListItem): boolean => column.value === key);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/audit-log.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/audit-log.ts b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/audit-log.ts
index fbe0e46..380f14f 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/audit-log.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/classes/models/audit-log.ts
@@ -35,7 +35,7 @@ export interface AuditLog extends Log {
   repoType: number;
   repo: string;
   proxyUsers?: string[];
-  evtTime: string;
+  evtTime: number;
   enforcer: string;
   reqContext?: string;
   cliType?: string;

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html
new file mode 100644
index 0000000..d6e9091
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.html
@@ -0,0 +1,54 @@
+<!--
+  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.
+-->
+
+<dropdown-button class="pull-right" label="logs.columns" [options]="columns" [isRightAlign]="true"
+                 [isMultipleChoice]="true" action="updateSelectedColumns"
+                 [additionalArgs]="logsTypeMapObject.fieldsModel"></dropdown-button>
+<form *ngIf="logs && logs.length" [formGroup]="filtersForm" class="row pull-right">
+  <filter-dropdown class="col-md-12" [label]="filters.auditLogsSorting.label" formControlName="auditLogsSorting"
+                   [options]="filters.auditLogsSorting.options" [isRightAlign]="true"></filter-dropdown></form>
+<div class="panel panel-default">
+  <div class="panel-body">
+    <table class="table">
+      <thead>
+        <tr>
+          <th *ngIf="isColumnDisplayed('evtTime')">{{getColumnByName('evtTime').label | translate}}</th>
+          <ng-container *ngFor="let column of displayedColumns">
+            <th *ngIf="customProcessedColumns.indexOf(column.value) === -1">{{column.label | translate}}</th>
+          </ng-container>
+        </tr>
+      </thead>
+      <tbody>
+        <tr *ngFor="let log of logs">
+          <td *ngIf="isColumnDisplayed('evtTime')">{{log.evtTime | amTz: timeZone | amDateFormat: timeFormat}}</td>
+          <ng-container *ngFor="let column of displayedColumns">
+            <td *ngIf="customProcessedColumns.indexOf(column.value) === -1">{{log[column.value]}}</td>
+          </ng-container>
+        </tr>
+      </tbody>
+      <tfoot>
+        <tr>
+          <td attr.colspan="{{displayedColumns.length + 1}}">
+            <pagination class="col-md-12" *ngIf="logs && logs.length" [totalCount]="totalCount"
+                        [filtersForm]="filtersForm" [filterInstance]="filters.pageSize"
+                        [currentCount]="logs.length"></pagination>
+          </td>
+        </tr>
+      </tfoot>
+    </table>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less
new file mode 100644
index 0000000..d9b0a10
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.less
@@ -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.
+ */
+
+th {
+  text-transform: uppercase;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts
new file mode 100644
index 0000000..b6206db
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.spec.ts
@@ -0,0 +1,157 @@
+/**
+ * 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 {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
+import {StoreModule} from '@ngrx/store';
+import {MomentModule} from 'angular2-moment';
+import {MomentTimezoneModule} from 'angular-moment-timezone';
+import {TranslationModules} from '@app/test-config.spec';
+import {AuditLogsService, auditLogs} from '@app/services/storage/audit-logs.service';
+import {ServiceLogsService, serviceLogs} from '@app/services/storage/service-logs.service';
+import {AuditLogsFieldsService, auditLogsFields} from '@app/services/storage/audit-logs-fields.service';
+import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
+import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
+import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
+import {AppStateService, appState} from '@app/services/storage/app-state.service';
+import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
+import {TabsService, tabs} from '@app/services/storage/tabs.service';
+import {ClustersService, clusters} from '@app/services/storage/clusters.service';
+import {ComponentsService, components} from '@app/services/storage/components.service';
+import {HostsService, hosts} from '@app/services/storage/hosts.service';
+import {LogsContainerService} from '@app/services/logs-container.service';
+import {UtilsService} from '@app/services/utils.service';
+import {HttpClientService} from '@app/services/http-client.service';
+import {PaginationComponent} from '@app/components/pagination/pagination.component';
+import {DropdownListComponent} from '@app/components/dropdown-list/dropdown-list.component';
+
+import {AuditLogsTableComponent} from './audit-logs-table.component';
+
+describe('AuditLogsTableComponent', () => {
+  let component: AuditLogsTableComponent;
+  let fixture: ComponentFixture<AuditLogsTableComponent>;
+  const httpClient = {
+    get: () => {
+      return {
+        subscribe: () => {
+        }
+      };
+    }
+  };
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [
+        AuditLogsTableComponent,
+        PaginationComponent,
+        DropdownListComponent
+      ],
+      imports: [
+        FormsModule,
+        ReactiveFormsModule,
+        MomentModule,
+        MomentTimezoneModule,
+        ...TranslationModules,
+        StoreModule.provideStore({
+          auditLogs,
+          serviceLogs,
+          auditLogsFields,
+          serviceLogsFields,
+          serviceLogsHistogramData,
+          serviceLogsTruncated,
+          appState,
+          appSettings,
+          tabs,
+          clusters,
+          components,
+          hosts
+        })
+      ],
+      providers: [
+        LogsContainerService,
+        UtilsService,
+        {
+          provide: HttpClientService,
+          useValue: httpClient
+        },
+        AuditLogsService,
+        ServiceLogsService,
+        AuditLogsFieldsService,
+        ServiceLogsFieldsService,
+        ServiceLogsHistogramDataService,
+        ServiceLogsTruncatedService,
+        AppStateService,
+        AppSettingsService,
+        TabsService,
+        ClustersService,
+        ComponentsService,
+        HostsService
+      ],
+      schemas: [CUSTOM_ELEMENTS_SCHEMA]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(AuditLogsTableComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create component', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('#getColumnByName()', () => {
+    const cases = [
+      {
+        name: 'v1',
+        result: {
+          label: 'l1',
+          value: 'v1'
+        },
+        title: 'item is present'
+      },
+      {
+        name: 'l1',
+        result: undefined,
+        title: 'item is absent'
+      }
+    ];
+
+    beforeEach(() => {
+      component.columns = [
+        {
+          label: 'l0',
+          value: 'v0'
+        },
+        {
+          label: 'l1',
+          value: 'v1'
+        }
+      ];
+    });
+
+    cases.forEach(test => {
+      it(test.title, () => {
+        expect(component.getColumnByName(test.name)).toEqual(test.result);
+      });
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts
new file mode 100644
index 0000000..0e578ab
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/audit-logs-table/audit-logs-table.component.ts
@@ -0,0 +1,55 @@
+/**
+ * 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 {Component} from '@angular/core';
+import {ListItem} from '@app/classes/list-item';
+import {LogsTableComponent} from '@app/classes/components/logs-table-component';
+import {LogsContainerService} from '@app/services/logs-container.service';
+
+@Component({
+  selector: 'audit-logs-table',
+  templateUrl: './audit-logs-table.component.html',
+  styleUrls: ['./audit-logs-table.component.less']
+})
+export class AuditLogsTableComponent extends LogsTableComponent {
+
+  constructor(private logsContainer: LogsContainerService) {
+    super();
+  }
+
+  readonly customProcessedColumns: string[] = ['evtTime'];
+
+  readonly timeFormat: string = 'YYYY-MM-DD HH:mm:ss,SSS';
+
+  get logsTypeMapObject(): object {
+    return this.logsContainer.logsTypeMap.auditLogs;
+  }
+
+  get filters(): any {
+    return this.logsContainer.filters;
+  }
+
+  get timeZone(): string {
+    return this.logsContainer.timeZone;
+  }
+
+  getColumnByName(name: string): ListItem | undefined {
+    return this.columns.find((column: ListItem): boolean => column.value === name);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.ts
index 3314252..b41f7cd 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/filters-panel/filters-panel.component.ts
@@ -97,7 +97,7 @@ export class FiltersPanelComponent {
   }
 
   isFilterConditionDisplayed(key: string): boolean {
-    return this.logsContainer.filtersFormItemsMap[this.logsType].indexOf(key) > -1
+    return this.logsContainer.logsTypeMap[this.logsType].listFilters.indexOf(key) > -1
       && Boolean(this.filtersForm.controls[key]);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
index 2c3a3b9..f34dd15 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
@@ -44,11 +44,12 @@
     <time-histogram [data]="histogramData" [customOptions]="histogramOptions" svgId="service-logs-histogram"
                     (selectArea)="setCustomTimeRange($event[0], $event[1])"></time-histogram>
   </collapsible-panel>
-  <dropdown-button *ngIf="!isServiceLogsFileView" class="pull-right" label="logs.columns"
-                   [options]="availableColumns | async" [isRightAlign]="true" [isMultipleChoice]="true"
-                   action="updateSelectedColumns" [additionalArgs]="logsTypeMapObject.fieldsModel"></dropdown-button>
-  <logs-list [logs]="logs | async" [totalCount]="totalCount" [displayedColumns]="displayedColumns"
-             [isServiceLogsFileView]="isServiceLogsFileView" [filtersForm]="filtersForm"></logs-list>
-  <log-context *ngIf="isServiceLogContextView" [hostName]="activeLog.host_name" [componentName]="activeLog.component_name"
-               [id]="activeLog.id"></log-context>
+  <ng-container [ngSwitch]="logsType">
+    <service-logs-table *ngSwitchCase="'serviceLogs'" [totalCount]="totalCount" [logs]="serviceLogs | async"
+                        [columns]="serviceLogsColumns | async" [filtersForm]="filtersForm"></service-logs-table>
+    <audit-logs-table *ngSwitchCase="'auditLogs'" [totalCount]="totalCount" [logs]="auditLogs | async"
+                      [columns]="auditLogsColumns | async" [filtersForm]="filtersForm"></audit-logs-table>
+  </ng-container>
+  <log-context *ngIf="isServiceLogContextView" [id]="activeLog.id" [hostName]="activeLog.host_name"
+               [componentName]="activeLog.component_name"></log-context>
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
index f8acd50..b06cfa4 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
@@ -19,16 +19,12 @@
 import {Component} from '@angular/core';
 import {FormGroup} from '@angular/forms';
 import {Observable} from 'rxjs/Observable';
-import {Subject} from 'rxjs/Subject';
-import 'rxjs/add/operator/map';
-import 'rxjs/add/operator/takeUntil';
 import {LogsContainerService} from '@app/services/logs-container.service';
 import {ServiceLogsHistogramDataService} from '@app/services/storage/service-logs-histogram-data.service';
 import {AppStateService} from '@app/services/storage/app-state.service';
 import {TabsService} from '@app/services/storage/tabs.service';
 import {AuditLog} from '@app/classes/models/audit-log';
 import {ServiceLog} from '@app/classes/models/service-log';
-import {LogField} from '@app/classes/models/log-field';
 import {Tab} from '@app/classes/models/tab';
 import {BarGraph} from '@app/classes/models/bar-graph';
 import {ActiveServiceLogEntry} from '@app/classes/active-service-log-entry';
@@ -47,35 +43,7 @@ export class LogsContainerComponent {
     private tabsStorage: TabsService, private logsContainer: LogsContainerService
   ) {
     this.logsContainer.loadColumnsNames();
-    appState.getParameter('activeLogsType').subscribe((value: string): void => {
-      this.logsType = value;
-      this.logsTypeChange.next();
-      const fieldsModel = this.logsTypeMapObject.fieldsModel,
-        logsModel = this.logsTypeMapObject.logsModel;
-      this.availableColumns = fieldsModel.getAll().takeUntil(this.logsTypeChange).map((fields: LogField[]): ListItem[] => {
-        return fields.filter((field: LogField): boolean => field.isAvailable).map((field: LogField): ListItem => {
-          return {
-            value: field.name,
-            label: field.displayName || field.name,
-            isChecked: field.isDisplayed
-          };
-        });
-      });
-      fieldsModel.getAll().takeUntil(this.logsTypeChange).subscribe(columns => {
-        const availableFields = columns.filter((field: LogField): boolean => field.isAvailable),
-          availableNames = availableFields.map((field: LogField): string => field.name);
-        if (availableNames.length) {
-          this.logs = logsModel.getAll().map((logs: (AuditLog | ServiceLog)[]): (AuditLog | ServiceLog)[] => {
-            return logs.map((log: AuditLog | ServiceLog): AuditLog | ServiceLog => {
-              return availableNames.reduce((obj, key) => Object.assign(obj, {
-                [key]: log[key]
-              }), {});
-            });
-          });
-        }
-        this.displayedColumns = columns.filter((column: LogField): boolean => column.isAvailable && column.isDisplayed);
-      });
-    });
+    appState.getParameter('activeLogsType').subscribe((value: string) => this.logsType = value);
     serviceLogsHistogramStorage.getAll().subscribe((data: BarGraph[]): void => {
       this.histogramData = this.logsContainer.getHistogramData(data);
     });
@@ -90,22 +58,10 @@ export class LogsContainerComponent {
 
   private logsType: string;
 
-  private logsTypeChange: Subject<any> = new Subject();
-
-  get logsTypeMapObject(): any {
-    return this.logsContainer.logsTypeMap[this.logsType];
-  }
-
   get totalCount(): number {
     return this.logsContainer.totalCount;
   }
 
-  logs: Observable<AuditLog[] | ServiceLog[]>;
-
-  availableColumns: Observable<LogField[]>;
-
-  displayedColumns: any[] = [];
-
   histogramData: {[key: string]: number};
 
   readonly histogramOptions: HistogramOptions = {
@@ -142,6 +98,22 @@ export class LogsContainerComponent {
     return this.logsContainer.activeLog;
   }
 
+  get auditLogs(): Observable<AuditLog[]> {
+    return this.logsContainer.auditLogs;
+  }
+
+  get auditLogsColumns(): Observable<ListItem[]> {
+    return this.logsContainer.auditLogsColumns;
+  }
+
+  get serviceLogs(): Observable<ServiceLog[]> {
+    return this.logsContainer.serviceLogs;
+  }
+
+  get serviceLogsColumns(): Observable<ListItem[]> {
+    return this.logsContainer.serviceLogsColumns;
+  }
+
   setCustomTimeRange(startTime: number, endTime: number): void {
     this.logsContainer.setCustomTimeRange(startTime, endTime);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.html
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.html
deleted file mode 100644
index 7de0b96..0000000
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.html
+++ /dev/null
@@ -1,72 +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.
--->
-
-<form *ngIf="logs && logs.length" [formGroup]="filtersForm" class="row pull-right">
-  <filter-dropdown [label]="filters.sorting.label" formControlName="sorting" [options]="filters.sorting.options"
-                   [isRightAlign]="true" class="col-md-12"></filter-dropdown>
-</form>
-<div class="panel panel-default">
- <div class="panel-body">
-   <table class="table table-hover">
-     <tbody>
-     <ng-container *ngFor="let log of logs; let i = index">
-         <tr *ngIf="!isServiceLogsFileView && (i === 0 || isDifferentDates(log.logtime, logs[i - 1].logtime))"
-                              class="log-date-row" >
-           <th attr.colspan="{{displayedColumns.length + 1}}">
-             {{log.logtime | amTz: timeZone | amDateFormat: dateFormat}}
-           </th>
-         </tr>
-         <tr class="log-item-row">
-           <td class="log-action">
-             <dropdown-button iconClass="fa fa-ellipsis-h action" [hideCaret]="true" [options]="logActions"
-                [additionalArgs]="[log]"></dropdown-button>
-           </td>
-           <td *ngIf="isColumnDisplayed('logtime')" class="log-time">
-             <time>
-               {{log.logtime | amTz: timeZone | amDateFormat: timeFormat}}
-             </time>
-           </td>
-           <td *ngIf="isColumnDisplayed('level')" [ngClass]="'log-level ' + log.level.toLowerCase()">
-             <log-level [logEntry]="log"></log-level>
-           </td>
-           <td *ngIf="isColumnDisplayed('type')" [ngClass]="'log-type'">
-             {{log.type}}
-           </td>
-           <td *ngIf="isColumnDisplayed('log_message')" [ngClass]="'log-message'" width="*"
-               (contextmenu)="openMessageContextMenu($event)">
-             <log-message [listenChangesOn]="displayedColumns">{{log.log_message}}</log-message>
-           </td>
-           <ng-container *ngFor="let column of displayedColumns">
-             <td *ngIf="customStyledColumns.indexOf(column.name) === -1"
-               [ngClass]="'log-' + column.name">{{log[column.name]}}</td>
-           </ng-container>
-         </tr>
-       </ng-container>
-   </tbody>
-     <tfoot>
-     <tr>
-         <td attr.colspan="{{displayedColumns.length + 1}}">
-           <pagination class="col-md-12" *ngIf="logs && logs.length" [totalCount]="totalCount"
-             [filtersForm]="filtersForm" [filterInstance]="filters.pageSize" [currentCount]="logs.length"></pagination>
-         </td>
-       </tr>
-   </tfoot>
-   </table>
-   <ul #contextmenu data-component="dropdown-list" class="dropdown-menu context-menu" [items]="contextMenuItems"
-                  (selectedItemChange)="updateQuery($event)"></ul>
- </div>
-</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.less
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.less
deleted file mode 100644
index c5c4c5a..0000000
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.less
+++ /dev/null
@@ -1,97 +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 '../mixins';
-
-:host {
-  /deep/ filter-dropdown {
-    justify-content: flex-end;
-  }
-
-  .panel-body {
-    overflow: hidden;
-    width: 100%;
-  }
-
-  table {
-    width: 100%;
-  }
-
-  tr.log-date-row, tr.log-date-row:hover {
-    background: @list-header-background-color;
-    border: none transparent;
-    th {
-      border: none transparent;
-    }
-  }
-  tr.log-item-row td {
-    background: none transparent;
-  }
-
-  td {
-    &.log-action {
-      min-width: 3em;
-      /deep/ .btn, /deep/ .filter-label {
-        font-size: 1em;
-        height: auto;
-        line-height: 1em;
-        padding: 0;
-      }
-    }
-    &.log-time {
-      color: @grey-color;
-      min-width: 7em;
-      text-align: right;
-    }
-    &.log-level {
-      text-transform: uppercase;
-      min-width: 8em;
-      .log-colors;
-    }
-    &.log-type {
-      color: @link-color;
-    }
-    &.log-message, &.log-path {
-      width: 100%;
-    }
-  }
-
-  tr:hover td.log-action {
-    /deep/ .btn {
-      display: inline-block;
-    }
-  }
-
-  .table.table-hover>tbody>tr{
-    box-sizing: border-box;
-    border-width: 1px;
-    >td {
-      border-top: 0 none;
-    }
-    &:first-of-type {
-      border-top-color: transparent;
-    }
-    &:last-of-type {
-      border-bottom-color: transparent;
-    }
-  }
-
-  .context-menu {
-    position: fixed;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.spec.ts
deleted file mode 100644
index 21c4f02..0000000
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.spec.ts
+++ /dev/null
@@ -1,110 +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 {NO_ERRORS_SCHEMA} from '@angular/core';
-import {async, ComponentFixture, TestBed} from '@angular/core/testing';
-import {TranslationModules} from '@app/test-config.spec';
-import {StoreModule} from '@ngrx/store';
-import {MomentModule} from 'angular2-moment';
-import {MomentTimezoneModule} from 'angular-moment-timezone';
-import {AuditLogsService, auditLogs} from '@app/services/storage/audit-logs.service';
-import {ServiceLogsService, serviceLogs} from '@app/services/storage/service-logs.service';
-import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
-import {AppStateService, appState} from '@app/services/storage/app-state.service';
-import {ClustersService, clusters} from '@app/services/storage/clusters.service';
-import {ComponentsService, components} from '@app/services/storage/components.service';
-import {HostsService, hosts} from '@app/services/storage/hosts.service';
-import {AuditLogsFieldsService, auditLogsFields} from '@app/services/storage/audit-logs-fields.service';
-import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
-import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
-import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
-import {TabsService, tabs} from '@app/services/storage/tabs.service';
-import {HttpClientService} from '@app/services/http-client.service';
-import {LogsContainerService} from '@app/services/logs-container.service';
-import {UtilsService} from '@app/services/utils.service';
-
-import {LogsListComponent} from './logs-list.component';
-
-describe('LogsListComponent', () => {
-  let component: LogsListComponent;
-  let fixture: ComponentFixture<LogsListComponent>;
-  const httpClient = {
-    get: () => {
-      return {
-        subscribe: () => {
-        }
-      };
-    }
-  };
-
-  beforeEach(async(() => {
-    TestBed.configureTestingModule({
-      declarations: [LogsListComponent],
-      imports: [
-        StoreModule.provideStore({
-          auditLogs,
-          serviceLogs,
-          appSettings,
-          appState,
-          clusters,
-          components,
-          hosts,
-          auditLogsFields,
-          serviceLogsFields,
-          serviceLogsHistogramData,
-          serviceLogsTruncated,
-          tabs
-        }),
-        MomentModule,
-        MomentTimezoneModule,
-        ...TranslationModules
-      ],
-      providers: [
-        {
-          provide: HttpClientService,
-          useValue: httpClient
-        },
-        AuditLogsService,
-        ServiceLogsService,
-        AppSettingsService,
-        AppStateService,
-        ClustersService,
-        ComponentsService,
-        HostsService,
-        AuditLogsFieldsService,
-        ServiceLogsFieldsService,
-        ServiceLogsHistogramDataService,
-        ServiceLogsTruncatedService,
-        TabsService,
-        LogsContainerService,
-        UtilsService
-      ],
-      schemas: [NO_ERRORS_SCHEMA]
-    })
-    .compileComponents();
-  }));
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(LogsListComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create component', () => {
-    expect(component).toBeTruthy();
-  });
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.ts
deleted file mode 100644
index 3a56fca..0000000
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-list/logs-list.component.ts
+++ /dev/null
@@ -1,151 +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 {Component, AfterViewInit, Input, ViewChild, ElementRef} from '@angular/core';
-import {FormGroup} from '@angular/forms';
-import 'rxjs/add/operator/map';
-import {LogsContainerService} from '@app/services/logs-container.service';
-import {UtilsService} from '@app/services/utils.service';
-import {AuditLog} from '@app/classes/models/audit-log';
-import {ServiceLog} from '@app/classes/models/service-log';
-import {LogField} from '@app/classes/models/log-field';
-
-@Component({
-  selector: 'logs-list',
-  templateUrl: './logs-list.component.html',
-  styleUrls: ['./logs-list.component.less']
-})
-export class LogsListComponent implements AfterViewInit {
-
-  constructor(private logsContainer: LogsContainerService, private utils: UtilsService) {
-  }
-
-  ngAfterViewInit() {
-    if (this.contextMenu) {
-      this.contextMenuElement = this.contextMenu.nativeElement;
-    }
-  }
-
-  @Input()
-  logs: (AuditLog| ServiceLog)[] = [];
-
-  @Input()
-  totalCount: number = 0;
-
-  @Input()
-  displayedColumns: LogField[] = [];
-
-  @Input()
-  isServiceLogsFileView: boolean = false;
-
-  @Input()
-  filtersForm: FormGroup;
-
-  @ViewChild('contextmenu', {
-    read: ElementRef
-  })
-  contextMenu: ElementRef;
-
-  private contextMenuElement: HTMLElement;
-
-  private selectedText: string = '';
-
-  private readonly messageFilterParameterName = 'log_message';
-
-  readonly customStyledColumns = ['level', 'type', 'logtime', 'log_message'];
-
-  readonly contextMenuItems = [
-    {
-      label: 'logs.addToQuery',
-      iconClass: 'fa fa-search-plus',
-      value: false // 'isExclude' is false
-    },
-    {
-      label: 'logs.excludeFromQuery',
-      iconClass: 'fa fa-search-minus',
-      value: true // 'isExclude' is true
-    }
-  ];
-
-  readonly logActions = [
-    {
-      label: 'logs.copy',
-      iconClass: 'fa fa-files-o',
-      action: 'copyLog'
-    },
-    {
-      label: 'logs.open',
-      iconClass: 'fa fa-external-link',
-      action: 'openLog'
-    },
-    {
-      label: 'logs.context',
-      iconClass: 'fa fa-crosshairs',
-      action: 'openContext'
-    }
-  ];
-
-  readonly dateFormat: string = 'dddd, MMMM Do';
-
-  readonly timeFormat: string = 'h:mm:ss A';
-
-  get timeZone(): string {
-    return this.logsContainer.timeZone;
-  }
-
-  get filters(): any {
-    return this.logsContainer.filters;
-  }
-
-  isDifferentDates(dateA, dateB): boolean {
-    return this.utils.isDifferentDates(dateA, dateB, this.timeZone);
-  }
-
-  isColumnDisplayed(key: string): boolean {
-    return this.displayedColumns.some((column: LogField): boolean  => column.name === key);
-  }
-
-  openMessageContextMenu(event: MouseEvent): void {
-    const selectedText = getSelection().toString();
-    if (selectedText) {
-      let contextMenuStyle = this.contextMenuElement.style;
-      Object.assign(contextMenuStyle, {
-        left: `${event.clientX}px`,
-        top: `${event.clientY}px`,
-        display: 'block'
-      });
-      this.selectedText = selectedText;
-      document.body.addEventListener('click', this.dismissContextMenu);
-      event.preventDefault();
-    }
-  }
-
-  updateQuery(event: any) {
-    this.logsContainer.queryParameterAdd.next({
-      name: this.messageFilterParameterName,
-      value: this.selectedText,
-      isExclude: event.value
-    });
-  }
-
-  private dismissContextMenu = (): void => {
-    this.selectedText = '';
-    this.contextMenuElement.style.display = 'none';
-    document.body.removeEventListener('click', this.dismissContextMenu);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.html
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.html
new file mode 100644
index 0000000..a2e666e
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.html
@@ -0,0 +1,76 @@
+<!--
+  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.
+-->
+
+<dropdown-button class="pull-right" label="logs.columns" [options]="columns" [isRightAlign]="true"
+                 [isMultipleChoice]="true" action="updateSelectedColumns"
+                 [additionalArgs]="logsTypeMapObject.fieldsModel"></dropdown-button>
+<form *ngIf="logs && logs.length" [formGroup]="filtersForm" class="row pull-right">
+  <filter-dropdown class="col-md-12" [label]="filters.serviceLogsSorting.label" formControlName="serviceLogsSorting"
+                   [options]="filters.serviceLogsSorting.options" [isRightAlign]="true"></filter-dropdown>
+</form>
+<div class="panel panel-default">
+  <div class="panel-body">
+    <table class="table table-hover">
+      <tbody>
+        <ng-container *ngFor="let log of logs; let i = index">
+          <tr *ngIf="i === 0 || isDifferentDates(log.logtime, logs[i - 1].logtime)" class="log-date-row">
+            <th attr.colspan="{{displayedColumns.length + 1}}">
+              {{log.logtime | amTz: timeZone | amDateFormat: dateFormat}}
+            </th>
+          </tr>
+          <tr class="log-item-row">
+            <td class="log-action">
+              <dropdown-button iconClass="fa fa-ellipsis-h action" [hideCaret]="true" [options]="logActions"
+                               [additionalArgs]="[log]"></dropdown-button>
+            </td>
+            <td *ngIf="isColumnDisplayed('logtime')" class="log-time">
+              <time>
+                {{log.logtime | amTz: timeZone | amDateFormat: timeFormat}}
+              </time>
+            </td>
+            <td *ngIf="isColumnDisplayed('level')" [ngClass]="'log-level ' + log.level.toLowerCase()">
+              <log-level [logEntry]="log"></log-level>
+            </td>
+            <td *ngIf="isColumnDisplayed('type')" [ngClass]="'log-type'">
+              {{log.type}}
+            </td>
+            <td *ngIf="isColumnDisplayed('log_message')" [ngClass]="'log-message'" width="*"
+                (contextmenu)="openMessageContextMenu($event)">
+              <log-message [listenChangesOn]="displayedColumns">{{log.log_message}}</log-message>
+            </td>
+            <ng-container *ngFor="let column of displayedColumns">
+              <td *ngIf="customStyledColumns.indexOf(column.value) === -1" [ngClass]="'log-' + column.value">
+                {{log[column.value]}}
+              </td>
+            </ng-container>
+          </tr>
+        </ng-container>
+      </tbody>
+      <tfoot>
+        <tr>
+          <td attr.colspan="{{displayedColumns.length + 1}}">
+            <pagination class="col-md-12" *ngIf="logs && logs.length" [totalCount]="totalCount"
+                        [filtersForm]="filtersForm" [filterInstance]="filters.pageSize"
+                        [currentCount]="logs.length"></pagination>
+          </td>
+        </tr>
+      </tfoot>
+    </table>
+    <ul #contextmenu data-component="dropdown-list" class="dropdown-menu context-menu" [items]="contextMenuItems"
+        (selectedItemChange)="updateQuery($event)"></ul>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less
new file mode 100644
index 0000000..bd6d012
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less
@@ -0,0 +1,97 @@
+/**
+ * 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 '../mixins';
+
+:host {
+  /deep/ filter-dropdown {
+    justify-content: flex-end;
+  }
+
+  .panel-body {
+    overflow: hidden;
+    width: 100%;
+  }
+
+  table {
+    width: 100%;
+  }
+
+  tr.log-date-row, tr.log-date-row:hover {
+    background: @list-header-background-color;
+    border: none transparent;
+    th {
+      border: none transparent;
+    }
+  }
+  tr.log-item-row td {
+    background: none transparent;
+  }
+
+  td {
+    &.log-action {
+      min-width: 3em;
+      /deep/ .btn, /deep/ .filter-label {
+        font-size: 1em;
+        height: auto;
+        line-height: 1em;
+        padding: 0;
+      }
+    }
+    &.log-time {
+      color: @grey-color;
+      min-width: 7em;
+      text-align: right;
+    }
+    &.log-level {
+      text-transform: uppercase;
+      min-width: 8em;
+      .log-colors;
+    }
+    &.log-type {
+      color: @link-color;
+    }
+    &.log-message, &.log-path {
+      width: 100%;
+    }
+  }
+
+  tr:hover td.log-action {
+    /deep/ .btn {
+      display: inline-block;
+    }
+  }
+
+  .table.table-hover > tbody > tr {
+    box-sizing: border-box;
+    border-width: 1px;
+    > td {
+      border-top: 0 none;
+    }
+    &:first-of-type {
+      border-top-color: transparent;
+    }
+    &:last-of-type {
+      border-bottom-color: transparent;
+    }
+  }
+
+  .context-menu {
+    position: fixed;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.spec.ts
new file mode 100644
index 0000000..0c323f7
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.spec.ts
@@ -0,0 +1,126 @@
+/**
+ * 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 {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
+import {StoreModule} from '@ngrx/store';
+import {MomentModule} from 'angular2-moment';
+import {MomentTimezoneModule} from 'angular-moment-timezone';
+import {TranslationModules} from '@app/test-config.spec';
+import {AuditLogsService, auditLogs} from '@app/services/storage/audit-logs.service';
+import {ServiceLogsService, serviceLogs} from '@app/services/storage/service-logs.service';
+import {AuditLogsFieldsService, auditLogsFields} from '@app/services/storage/audit-logs-fields.service';
+import {ServiceLogsFieldsService, serviceLogsFields} from '@app/services/storage/service-logs-fields.service';
+import {ServiceLogsHistogramDataService, serviceLogsHistogramData} from '@app/services/storage/service-logs-histogram-data.service';
+import {ServiceLogsTruncatedService, serviceLogsTruncated} from '@app/services/storage/service-logs-truncated.service';
+import {AppStateService, appState} from '@app/services/storage/app-state.service';
+import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
+import {TabsService, tabs} from '@app/services/storage/tabs.service';
+import {ClustersService, clusters} from '@app/services/storage/clusters.service';
+import {ComponentsService, components} from '@app/services/storage/components.service';
+import {HostsService, hosts} from '@app/services/storage/hosts.service';
+import {LogsContainerService} from '@app/services/logs-container.service';
+import {UtilsService} from '@app/services/utils.service';
+import {HttpClientService} from '@app/services/http-client.service';
+import {ComponentGeneratorService} from '@app/services/component-generator.service';
+import {ComponentActionsService} from '@app/services/component-actions.service';
+import {AuthService} from '@app/services/auth.service';
+import {PaginationComponent} from '@app/components/pagination/pagination.component';
+import {DropdownListComponent} from '@app/components/dropdown-list/dropdown-list.component';
+
+import {ServiceLogsTableComponent} from './service-logs-table.component';
+
+describe('ServiceLogsTableComponent', () => {
+  let component: ServiceLogsTableComponent;
+  let fixture: ComponentFixture<ServiceLogsTableComponent>;
+  const httpClient = {
+    get: () => {
+      return {
+        subscribe: () => {
+        }
+      };
+    }
+  };
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [
+        ServiceLogsTableComponent,
+        PaginationComponent,
+        DropdownListComponent
+      ],
+      imports: [
+        FormsModule,
+        ReactiveFormsModule,
+        MomentModule,
+        MomentTimezoneModule,
+        ...TranslationModules,
+        StoreModule.provideStore({
+          auditLogs,
+          serviceLogs,
+          auditLogsFields,
+          serviceLogsFields,
+          serviceLogsHistogramData,
+          serviceLogsTruncated,
+          appState,
+          appSettings,
+          tabs,
+          clusters,
+          components,
+          hosts
+        })
+      ],
+      providers: [
+        LogsContainerService,
+        UtilsService,
+        {
+          provide: HttpClientService,
+          useValue: httpClient
+        },
+        AuditLogsService,
+        ServiceLogsService,
+        AuditLogsFieldsService,
+        ServiceLogsFieldsService,
+        ServiceLogsHistogramDataService,
+        ServiceLogsTruncatedService,
+        AppStateService,
+        AppSettingsService,
+        TabsService,
+        ClustersService,
+        ComponentsService,
+        HostsService,
+        ComponentGeneratorService,
+        ComponentActionsService,
+        AuthService
+      ],
+      schemas: [CUSTOM_ELEMENTS_SCHEMA]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ServiceLogsTableComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create component', () => {
+    expect(component).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
new file mode 100644
index 0000000..9f38371
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
@@ -0,0 +1,135 @@
+/**
+ * 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 {Component, AfterViewInit, ViewChild, ElementRef} from '@angular/core';
+import {ListItem} from '@app/classes/list-item';
+import {LogsTableComponent} from '@app/classes/components/logs-table-component';
+import {LogsContainerService} from '@app/services/logs-container.service';
+import {UtilsService} from '@app/services/utils.service';
+
+@Component({
+  selector: 'service-logs-table',
+  templateUrl: './service-logs-table.component.html',
+  styleUrls: ['./service-logs-table.component.less']
+})
+export class ServiceLogsTableComponent extends LogsTableComponent implements AfterViewInit {
+
+  constructor(private logsContainer: LogsContainerService, private utils: UtilsService) {
+    super();
+  }
+
+  ngAfterViewInit() {
+    if (this.contextMenu) {
+      this.contextMenuElement = this.contextMenu.nativeElement;
+    }
+  }
+
+  @ViewChild('contextmenu', {
+    read: ElementRef
+  })
+  contextMenu: ElementRef;
+
+  readonly dateFormat: string = 'dddd, MMMM Do';
+
+  readonly timeFormat: string = 'h:mm:ss A';
+
+  readonly logActions = [
+    {
+      label: 'logs.copy',
+      iconClass: 'fa fa-files-o',
+      action: 'copyLog'
+    },
+    {
+      label: 'logs.open',
+      iconClass: 'fa fa-external-link',
+      action: 'openLog'
+    },
+    {
+      label: 'logs.context',
+      iconClass: 'fa fa-crosshairs',
+      action: 'openContext'
+    }
+  ];
+
+  readonly customStyledColumns: string[] = ['level', 'type', 'logtime', 'log_message'];
+
+  readonly contextMenuItems: ListItem[] = [
+    {
+      label: 'logs.addToQuery',
+      iconClass: 'fa fa-search-plus',
+      value: false // 'isExclude' is false
+    },
+    {
+      label: 'logs.excludeFromQuery',
+      iconClass: 'fa fa-search-minus',
+      value: true // 'isExclude' is true
+    }
+  ];
+
+  private readonly messageFilterParameterName: string = 'log_message';
+
+  private contextMenuElement: HTMLElement;
+
+  private selectedText: string = '';
+
+  get timeZone(): string {
+    return this.logsContainer.timeZone;
+  }
+
+  get filters(): any {
+    return this.logsContainer.filters;
+  }
+
+  get logsTypeMapObject(): object {
+    return this.logsContainer.logsTypeMap.serviceLogs;
+  }
+
+  isDifferentDates(dateA, dateB): boolean {
+    return this.utils.isDifferentDates(dateA, dateB, this.timeZone);
+  }
+
+  openMessageContextMenu(event: MouseEvent): void {
+    const selectedText = getSelection().toString();
+    if (selectedText) {
+      let contextMenuStyle = this.contextMenuElement.style;
+      Object.assign(contextMenuStyle, {
+        left: `${event.clientX}px`,
+        top: `${event.clientY}px`,
+        display: 'block'
+      });
+      this.selectedText = selectedText;
+      document.body.addEventListener('click', this.dismissContextMenu);
+      event.preventDefault();
+    }
+  }
+
+  updateQuery(event: ListItem): void {
+    this.logsContainer.queryParameterAdd.next({
+      name: this.messageFilterParameterName,
+      value: this.selectedText,
+      isExclude: event.value
+    });
+  }
+
+  private dismissContextMenu = (): void => {
+    this.selectedText = '';
+    this.contextMenuElement.style.display = 'none';
+    document.body.removeEventListener('click', this.dismissContextMenu);
+  };
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts b/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts
index 147efef..7578867 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/mock-data.ts
@@ -47,7 +47,7 @@ export const mockData = {
               proxyUsers: [
                 'admin'
               ],
-              evtTime: '2017-05-29T11:30:22.531Z',
+              evtTime: 1496057422531,
               enforcer: 'ambari-acl',
               reqContext: 'ambari',
               cliType: 'GET',
@@ -94,7 +94,7 @@ export const mockData = {
               proxyUsers: [
                 'user'
               ],
-              evtTime: '2017-05-29T11:30:22.531Z',
+              evtTime: 1496057422531,
               enforcer: 'hdfs',
               reqContext: 'ambari_server',
               cliType: 'PUT',

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.spec.ts
index fd5a83e..65f0936 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/auth.service.spec.ts
@@ -55,7 +55,7 @@ describe('AuthService', () => {
     isError: false,
     postFormData: function () {
       const isError = this.isError;
-      return Observable.create(observer => observer.next(isError ? errorResponse : successResponse)).delay(1000);
+      return Observable.create(observer => observer.next(isError ? errorResponse : successResponse)).delay(1);
     }
   };
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
index f45887b..90ab9b7 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
@@ -22,6 +22,9 @@ import {Response} from '@angular/http';
 import {Subject} from 'rxjs/Subject';
 import {Observable} from 'rxjs/Observable';
 import 'rxjs/add/observable/timer';
+import 'rxjs/add/observable/combineLatest';
+import 'rxjs/add/operator/first';
+import 'rxjs/add/operator/map';
 import 'rxjs/add/operator/takeUntil';
 import * as moment from 'moment-timezone';
 import {HttpClientService} from '@app/services/http-client.service';
@@ -41,7 +44,10 @@ import {ActiveServiceLogEntry} from '@app/classes/active-service-log-entry';
 import {FilterCondition, TimeUnitListItem, SortingListItem} from '@app/classes/filtering';
 import {ListItem} from '@app/classes/list-item';
 import {Tab} from '@app/classes/models/tab';
+import {LogField} from '@app/classes/models/log-field';
+import {AuditLog} from '@app/classes/models/audit-log';
 import {AuditLogField} from '@app/classes/models/audit-log-field';
+import {ServiceLog} from '@app/classes/models/service-log';
 import {ServiceLogField} from '@app/classes/models/service-log-field';
 import {BarGraph} from '@app/classes/models/bar-graph';
 import {NodeItem} from '@app/classes/models/node-item';
@@ -383,7 +389,35 @@ export class LogsContainerService {
       options: [],
       defaultSelection: []
     },
-    sorting: {
+    auditLogsSorting: {
+      label: 'sorting.title',
+      options: [
+        {
+          label: 'sorting.time.asc',
+          value: {
+            key: 'evtTime',
+            type: 'asc'
+          }
+        },
+        {
+          label: 'sorting.time.desc',
+          value: {
+            key: 'evtTime',
+            type: 'desc'
+          }
+        }
+      ],
+      defaultSelection: [
+        {
+          label: 'sorting.time.desc',
+          value: {
+            key: 'evtTime',
+            type: 'desc'
+          }
+        }
+      ]
+    },
+    serviceLogsSorting: {
       label: 'sorting.title',
       options: [
         {
@@ -432,11 +466,6 @@ export class LogsContainerService {
     query: {}
   };
 
-  readonly filtersFormItemsMap: {[key: string]: string[]} = {
-    serviceLogs: ['clusters', 'timeRange', 'components', 'levels', 'hosts', 'sorting', 'pageSize', 'page', 'query'],
-    auditLogs: ['clusters', 'timeRange', 'sorting', 'pageSize', 'page', 'query'] // TODO add all the required fields
-  };
-
   readonly colors = {
     WARN: '#FF8916',
     ERROR: '#E81D1D',
@@ -447,13 +476,14 @@ export class LogsContainerService {
     UNKNOWN: '#BDBDBD'
   };
 
-  private readonly listFilters = {
+  private readonly filtersMapping = {
     clusters: ['clusters'],
     timeRange: ['to', 'from'],
     components: ['mustBe'],
     levels: ['level'],
     hosts: ['hostList'],
-    sorting: ['sortType', 'sortBy'],
+    auditLogsSorting: ['sortType', 'sortBy'],
+    serviceLogsSorting: ['sortType', 'sortBy'],
     pageSize: ['pageSize'],
     page: ['page'],
     query: ['includeQuery', 'excludeQuery']
@@ -471,11 +501,16 @@ export class LogsContainerService {
   readonly logsTypeMap = {
     auditLogs: {
       logsModel: this.auditLogsStorage,
-      fieldsModel: this.auditLogsFieldsStorage
+      fieldsModel: this.auditLogsFieldsStorage,
+      // TODO add all the required fields
+      listFilters: ['clusters', 'timeRange', 'auditLogsSorting', 'pageSize', 'page', 'query'],
+      histogramFilters: ['clusters', 'timeRange', 'query']
     },
     serviceLogs: {
       logsModel: this.serviceLogsStorage,
-      fieldsModel: this.serviceLogsFieldsStorage
+      fieldsModel: this.serviceLogsFieldsStorage,
+      listFilters: ['clusters', 'timeRange', 'components', 'levels', 'hosts', 'serviceLogsSorting', 'pageSize', 'page', 'query'],
+      histogramFilters: ['clusters', 'timeRange', 'components', 'levels', 'hosts', 'query']
     }
   };
 
@@ -502,6 +537,38 @@ export class LogsContainerService {
 
   private filtersFormChange: Subject<any> = new Subject();
 
+  private columnsMapper<FieldT extends LogField>(fields: FieldT[]): ListItem[] {
+    return fields.filter((field: FieldT): boolean => field.isAvailable).map((field: FieldT): ListItem => {
+      return {
+        value: field.name,
+        label: field.displayName || field.name,
+        isChecked: field.isDisplayed
+      };
+    });
+  }
+
+  private logsMapper<LogT extends AuditLog & ServiceLog>(result: [LogT[], ListItem[]]): LogT[] {
+    const [logs, fields] = result;
+    if (fields.length) {
+      const names = fields.map((field: ListItem): string => field.value);
+      return logs.map((log: LogT): LogT => {
+        return names.reduce((currentObject: object, key: string) => Object.assign(currentObject, {
+          [key]: log[key]
+        }), {}) as LogT;
+      });
+    } else {
+      return [];
+    }
+  }
+
+  auditLogsColumns: Observable<ListItem[]> = this.auditLogsFieldsStorage.getAll().map(this.columnsMapper);
+
+  serviceLogsColumns: Observable<ListItem[]> = this.serviceLogsFieldsStorage.getAll().map(this.columnsMapper);
+
+  serviceLogs: Observable<ServiceLog[]> = Observable.combineLatest(this.serviceLogsStorage.getAll(), this.serviceLogsColumns).map(this.logsMapper);
+
+  auditLogs: Observable<AuditLog[]> = Observable.combineLatest(this.auditLogsStorage.getAll(), this.auditLogsColumns).map(this.logsMapper);
+
   /**
    * Get instance for dropdown list from string
    * @param name {string}
@@ -604,11 +671,11 @@ export class LogsContainerService {
     });
   }
 
-  private getParams(filtersMapName: string): {[key: string]: string} {
+  private getParams(filtersMapName: string, logsType: string = this.activeLogsType): {[key: string]: string} {
     let params = {};
-    Object.keys(this[filtersMapName]).forEach((key: string): void => {
+    this.logsTypeMap[logsType][filtersMapName].forEach((key: string): void => {
       const inputValue = this.filtersForm.getRawValue()[key],
-        paramNames = this[filtersMapName][key];
+        paramNames = this.filtersMapping[key];
       paramNames.forEach((paramName: string): void => {
         let value;
         const valueGetter = this.valueGetters[paramName] || this.defaultValueGetter;
@@ -845,7 +912,7 @@ export class LogsContainerService {
   }
 
   getFiltersData(listType: string): object {
-    const itemsList = this.filtersFormItemsMap[listType],
+    const itemsList = this.logsTypeMap[listType].listFilters,
       keys = Object.keys(this.filters).filter((key: string): boolean => itemsList.indexOf(key) > -1);
     return keys.reduce((currentObject: object, key: string): object => {
       return Object.assign(currentObject, {

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc535c84/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
index 8b157df..985b52f 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
@@ -65,6 +65,28 @@ export class mockApiDataService implements InMemoryDbService {
           isValuesList: true
         }
       }
+    },
+    'api/v1/audit/logs': {
+      pathToCollection: 'logList',
+      totalCountKey: 'totalCount',
+      filters: {
+        clusters: {
+          key: 'cluster',
+          isValuesList: true
+        },
+        iMessage: {
+          key: 'log_message',
+          filterFunction: (value, filterValue) => value.toLowerCase().indexOf(filterValue.toLowerCase()) > -1
+        },
+        from: {
+          key: 'evtTime',
+          filterFunction: (value, filterValue) => value >= moment(filterValue).valueOf()
+        },
+        to: {
+          key: 'evtTime',
+          filterFunction: (value, filterValue) => value < moment(filterValue).valueOf()
+        }
+      }
     }
   };
 


[19/49] ambari git commit: AMBARI-22467. YARN, MapReduce2, Hive, and Oozie Should Conditionally Install LZO (aonishuk)

Posted by rl...@apache.org.
AMBARI-22467. YARN, MapReduce2, Hive, and Oozie Should Conditionally Install LZO (aonishuk)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: b902c133035cc952a9081f5c0ffc8e967c2e6f44
Parents: 8dd9acc
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Wed Nov 22 14:50:33 2017 +0200
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Wed Nov 22 14:52:43 2017 +0200

----------------------------------------------------------------------
 .../main/python/ambari_server/serverConfiguration.py    | 12 ++++++++++++
 .../HDFS/2.1.0.2.0/package/scripts/hdfs.py              |  1 -
 .../HDFS/3.0.0.3.0/package/scripts/hdfs.py              |  1 -
 .../OOZIE/4.0.0.2.0/package/scripts/oozie.py            |  1 -
 4 files changed, 12 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b902c133/ambari-server/src/main/python/ambari_server/serverConfiguration.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/serverConfiguration.py b/ambari-server/src/main/python/ambari_server/serverConfiguration.py
index 5eb12e1..f744fa0 100644
--- a/ambari-server/src/main/python/ambari_server/serverConfiguration.py
+++ b/ambari-server/src/main/python/ambari_server/serverConfiguration.py
@@ -40,6 +40,7 @@ from ambari_server.properties import Properties
 from ambari_server.userInput import get_validated_string_input
 from ambari_server.utils import compare_versions, locate_file, on_powerpc
 from ambari_server.ambariPath import AmbariPath
+from ambari_server.userInput import get_YN_input
 
 
 OS_VERSION = OSCheck().get_os_major_version()
@@ -195,6 +196,15 @@ SETUP_OR_UPGRADE_MSG = "- If this is a new setup, then run the \"ambari-server s
                        "- If this is an upgrade of an existing setup, run the \"ambari-server upgrade\" command.\n" \
                        "Refer to the Ambari documentation for more information on setup and upgrade."
 
+GPL_LICENSE_PROMPT_TEXT = """To download GPL licensed products like lzo you must accept the license terms below:
+LICENSE_LINE_1
+LICENSE_LINE_2
+LICENSE_LINE_3
+LICENSE_LINE_4
+LICENSE_LINE_5
+LICENSE_LINE_6
+Do you accept the GPL License Agreement [y/n] (y)?"""
+
 DEFAULT_DB_NAME = "ambari"
 
 SECURITY_KEYS_DIR = "security.server.keys_dir"
@@ -209,6 +219,8 @@ BOOTSTRAP_SETUP_AGENT_SCRIPT = 'bootstrap.setup_agent.script'
 STACKADVISOR_SCRIPT = 'stackadvisor.script'
 PID_DIR_PROPERTY = 'pid.dir'
 SERVER_TMP_DIR_PROPERTY = "server.tmp.dir"
+GPL_LICENSE_ACCEPTED_PROPERTY = 'gpl.license.accepted'
+
 REQUIRED_PROPERTIES = [OS_FAMILY_PROPERTY, OS_TYPE_PROPERTY, COMMON_SERVICES_PATH_PROPERTY, SERVER_VERSION_FILE_PATH,
                        WEBAPP_DIR_PROPERTY, STACK_LOCATION_KEY, SECURITY_KEYS_DIR, JDBC_DATABASE_NAME_PROPERTY,
                        NR_USER_PROPERTY, JAVA_HOME_PROPERTY, JDBC_PASSWORD_PROPERTY, SHARED_RESOURCES_DIR,

http://git-wip-us.apache.org/repos/asf/ambari/blob/b902c133/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/hdfs.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/hdfs.py b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/hdfs.py
index bc80ba6..d3d0cf8 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/hdfs.py
+++ b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/hdfs.py
@@ -26,7 +26,6 @@ from resource_management.core.source import Template
 from resource_management.core.resources.service import ServiceConfig
 from resource_management.libraries.resources.xml_config import XmlConfig
 
-from resource_management.libraries.functions.get_lzo_packages import get_lzo_packages
 from resource_management.core.exceptions import Fail
 from resource_management.core.logger import Logger
 from resource_management.libraries.functions.format import format

http://git-wip-us.apache.org/repos/asf/ambari/blob/b902c133/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/hdfs.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/hdfs.py b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/hdfs.py
index bc80ba6..d3d0cf8 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/hdfs.py
+++ b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/hdfs.py
@@ -26,7 +26,6 @@ from resource_management.core.source import Template
 from resource_management.core.resources.service import ServiceConfig
 from resource_management.libraries.resources.xml_config import XmlConfig
 
-from resource_management.libraries.functions.get_lzo_packages import get_lzo_packages
 from resource_management.core.exceptions import Fail
 from resource_management.core.logger import Logger
 from resource_management.libraries.functions.format import format

http://git-wip-us.apache.org/repos/asf/ambari/blob/b902c133/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py b/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
index 2306108..e9d48c0 100644
--- a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
+++ b/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
@@ -38,7 +38,6 @@ from resource_management.libraries.resources.xml_config import XmlConfig
 from resource_management.libraries.functions.lzo_utils import install_lzo_if_needed
 from resource_management.libraries.script.script import Script
 from resource_management.libraries.functions.security_commons import update_credential_provider_path
-from resource_management.libraries.functions.get_lzo_packages import get_lzo_packages
 from resource_management.core.resources.packaging import Package
 from resource_management.core.shell import as_user, as_sudo, call, checked_call
 from resource_management.core.exceptions import Fail


[06/49] ambari git commit: AMBARI-22461. VDF defined HDP-GPL repo should be tagged appropriately (ncole)

Posted by rl...@apache.org.
AMBARI-22461. VDF defined HDP-GPL repo should be tagged appropriately (ncole)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 5f8dcda67122dae7a7792a808d8548230c12af94
Parents: 430127b
Author: Nate Cole <nc...@hortonworks.com>
Authored: Fri Nov 17 15:14:09 2017 -0500
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Fri Nov 17 15:14:09 2017 -0500

----------------------------------------------------------------------
 .../AmbariManagementControllerImpl.java         |  8 +-
 .../server/controller/RepositoryResponse.java   | 26 +++++-
 .../internal/RepositoryResourceProvider.java    |  3 +
 .../VersionDefinitionResourceProvider.java      |  9 ++
 .../server/orm/entities/RepositoryEntity.java   | 56 +++++++++----
 .../apache/ambari/server/stack/RepoUtil.java    |  1 +
 .../ambari/server/state/RepositoryInfo.java     | 28 ++++++-
 .../ambari/server/state/stack/RepoTag.java      | 34 ++++++++
 .../server/state/stack/RepositoryXml.java       | 13 +++
 .../stack/upgrade/RepositoryVersionHelper.java  | 21 ++++-
 .../src/main/resources/version_definition.xsd   | 23 +++++-
 .../RepositoryResourceProviderTest.java         |  6 +-
 .../state/repository/VersionDefinitionTest.java | 35 +++++++-
 .../upgrade/RepositoryVersionHelperTest.java    |  2 +-
 .../resources/version_definition_with_tags.xml  | 86 ++++++++++++++++++++
 contrib/version-builder/version_builder.py      | 13 ++-
 16 files changed, 334 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 7f7271f..3d09154 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -191,6 +191,7 @@ import org.apache.ambari.server.state.quicklinksprofile.QuickLinksProfile;
 import org.apache.ambari.server.state.repository.VersionDefinitionXml;
 import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
 import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.state.stack.RepoTag;
 import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.ambari.server.state.stack.WidgetLayout;
 import org.apache.ambari.server.state.stack.WidgetLayoutInfo;
@@ -4445,8 +4446,10 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
         for (OperatingSystemEntity operatingSystem: repositoryVersion.getOperatingSystems()) {
           if (operatingSystem.getOsType().equals(osType)) {
             for (RepositoryEntity repository: operatingSystem.getRepositories()) {
+
               final RepositoryResponse response = new RepositoryResponse(repository.getBaseUrl(), osType, repository.getRepositoryId(),
-                      repository.getName(), repository.getDistribution(), repository.getComponents(), "", "");
+                      repository.getName(), repository.getDistribution(), repository.getComponents(), "", "",
+                      repository.getTags());
               if (null != versionDefinitionId) {
                 response.setVersionDefinitionId(versionDefinitionId);
               } else {
@@ -4454,6 +4457,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
               }
               response.setStackName(repositoryVersion.getStackName());
               response.setStackVersion(repositoryVersion.getStackVersion());
+
               responses.add(response);
             }
             break;
@@ -4475,7 +4479,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
         for (RepositoryXml.Repo repo : os.getRepos()) {
           RepositoryResponse resp = new RepositoryResponse(repo.getBaseUrl(), os.getFamily(),
               repo.getRepoId(), repo.getRepoName(), repo.getDistribution(), repo.getComponents(), repo.getMirrorsList(),
-              repo.getBaseUrl());
+              repo.getBaseUrl(), Collections.<RepoTag>emptySet());
 
           resp.setVersionDefinitionId(versionDefinitionId);
           resp.setStackName(stackId.getStackName());

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
index 8c68f41..8a0e45d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
@@ -18,6 +18,13 @@
 
 package org.apache.ambari.server.controller;
 
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.annotations.Experimental;
+import org.apache.ambari.annotations.ExperimentalFeature;
+import org.apache.ambari.server.state.stack.RepoTag;
+
 public class RepositoryResponse {
 
   private String stackName;
@@ -34,10 +41,11 @@ public class RepositoryResponse {
   private String versionDefinitionId;
   private Long clusterVersionId;
   private boolean unique;
+  private Set<RepoTag> tags;
 
   public RepositoryResponse(String baseUrl, String osType, String repoId,
                             String repoName, String distribution, String components,
-                            String mirrorsList, String defaultBaseUrl) {
+                            String mirrorsList, String defaultBaseUrl, Set<RepoTag> repoTags) {
     setBaseUrl(baseUrl);
     setOsType(osType);
     setRepoId(repoId);
@@ -46,6 +54,7 @@ public class RepositoryResponse {
     setComponents(components);
     setMirrorsList(mirrorsList);
     setDefaultBaseUrl(defaultBaseUrl);
+    setTags(repoTags);
   }
 
   public String getStackName() {
@@ -177,4 +186,19 @@ public class RepositoryResponse {
   public void setUnique(boolean unique) {
     this.unique = unique;
   }
+
+
+  /**
+   * @return the repo tags
+   */
+  public Set<RepoTag> getTags() {
+    return tags;
+  }
+
+  /**
+   * @param repoTags    the repo tags
+   */
+  public void setTags(Set<RepoTag> repoTags) {
+    tags = repoTags;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
index 4814a33..a2c3c49 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
@@ -61,6 +61,7 @@ public class RepositoryResourceProvider extends AbstractControllerResourceProvid
   public static final String REPOSITORY_REPOSITORY_VERSION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("Repositories", "repository_version_id");
   public static final String REPOSITORY_VERSION_DEFINITION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("Repositories", "version_definition_id");
   public static final String REPOSITORY_UNIQUE_PROPERTY_ID                = PropertyHelper.getPropertyId("Repositories", "unique");
+  public static final String REPOSITORY_TAGS_PROPERTY_ID                  = PropertyHelper.getPropertyId("Repositories", "tags");
 
   @SuppressWarnings("serial")
   private static Set<String> pkPropertyIds = new HashSet<String>() {
@@ -90,6 +91,7 @@ public class RepositoryResourceProvider extends AbstractControllerResourceProvid
       add(REPOSITORY_VERSION_DEFINITION_ID_PROPERTY_ID);
       add(REPOSITORY_CLUSTER_STACK_VERSION_PROPERTY_ID);
       add(REPOSITORY_UNIQUE_PROPERTY_ID);
+      add(REPOSITORY_TAGS_PROPERTY_ID);
     }
   };
 
@@ -166,6 +168,7 @@ public class RepositoryResourceProvider extends AbstractControllerResourceProvid
         setResourceProperty(resource, REPOSITORY_MIRRORS_LIST_PROPERTY_ID, response.getMirrorsList(), requestedIds);
         setResourceProperty(resource, REPOSITORY_DEFAULT_BASE_URL_PROPERTY_ID, response.getDefaultBaseUrl(), requestedIds);
         setResourceProperty(resource, REPOSITORY_UNIQUE_PROPERTY_ID, response.isUnique(), requestedIds);
+        setResourceProperty(resource, REPOSITORY_TAGS_PROPERTY_ID, response.getTags(), requestedIds);
         if (null != response.getClusterVersionId()) {
           setResourceProperty(resource, REPOSITORY_CLUSTER_STACK_VERSION_PROPERTY_ID, response.getClusterVersionId(), requestedIds);
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java
index b8c956f..c34c94d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java
@@ -61,6 +61,7 @@ import org.apache.ambari.server.state.RepositoryType;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.repository.VersionDefinitionXml;
+import org.apache.ambari.server.state.stack.RepoTag;
 import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
@@ -782,6 +783,14 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
             entity.getStackName());
         repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_STACK_VERSION_PROPERTY_ID),
             entity.getStackVersion());
+
+        ArrayNode tagsNode = factory.arrayNode();
+        for (RepoTag repoTag : repo.getTags()) {
+          tagsNode.add(repoTag.toString());
+        }
+        repoElement.put(PropertyHelper.getPropertyName(
+            RepositoryResourceProvider.REPOSITORY_TAGS_PROPERTY_ID), tagsNode);
+
         repoBase.put(PropertyHelper.getPropertyCategory(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID),
             repoElement);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java
index 6d7498b..09701dd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java
@@ -17,6 +17,14 @@
  */
 package org.apache.ambari.server.orm.entities;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.annotations.Experimental;
+import org.apache.ambari.annotations.ExperimentalFeature;
+import org.apache.ambari.server.state.stack.RepoTag;
+
 /**
  * Emulates entity to provide a quick way to change it to real entity in future.
  */
@@ -30,6 +38,8 @@ public class RepositoryEntity {
   private String mirrorsList;
   private boolean unique;
 
+  private Set<RepoTag> tags;
+
   public String getName() {
     return name;
   }
@@ -70,6 +80,36 @@ public class RepositoryEntity {
     this.repositoryId = repositoryId;
   }
 
+  public String getMirrorsList() {
+    return mirrorsList;
+  }
+
+  public void setMirrorsList(String mirrorsList) {
+    this.mirrorsList = mirrorsList;
+  }
+
+  public boolean isUnique() {
+    return unique;
+  }
+
+  public void setUnique(boolean unique) {
+    this.unique = unique;
+  }
+
+  /**
+   * @return the repo tags
+   */
+  public Set<RepoTag> getTags() {
+    return tags == null ? Collections.<RepoTag>emptySet() : tags;
+  }
+
+  /**
+   * @param repoTags the tags to set
+   */
+  public void setTags(Set<RepoTag> repoTags) {
+    tags = repoTags;
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
@@ -95,20 +135,4 @@ public class RepositoryEntity {
     result = 31 * result + (repositoryId != null ? repositoryId.hashCode() : 0);
     return result;
   }
-
-  public String getMirrorsList() {
-    return mirrorsList;
-  }
-
-  public void setMirrorsList(String mirrorsList) {
-    this.mirrorsList = mirrorsList;
-  }
-
-  public boolean isUnique() {
-    return unique;
-  }
-
-  public void setUnique(boolean unique) {
-    this.unique = unique;
-  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java
index 073fd82..eaddb2e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java
@@ -191,6 +191,7 @@ public class RepoUtil {
     re.setRepositoryId(repoInfo.getRepoId());
     re.setDistribution(repoInfo.getDistribution());
     re.setComponents(repoInfo.getComponents());
+    re.setTags(repoInfo.getTags());
     return re;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
index 8ab1fe9..3cc8521 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
@@ -18,7 +18,16 @@
 
 package org.apache.ambari.server.state;
 
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.annotations.Experimental;
+import org.apache.ambari.annotations.ExperimentalFeature;
 import org.apache.ambari.server.controller.RepositoryResponse;
+import org.apache.ambari.server.state.stack.RepoTag;
+import org.apache.commons.lang.StringUtils;
 
 import com.google.common.base.Function;
 import com.google.common.base.Objects;
@@ -36,6 +45,7 @@ public class RepositoryInfo {
   private boolean repoSaved = false;
   private boolean unique = false;
   private boolean ambariManagedRepositories = true;
+  private Set<RepoTag> tags = new HashSet<>();
 
   /**
    * @return the baseUrl
@@ -207,7 +217,8 @@ public class RepositoryInfo {
   public RepositoryResponse convertToResponse()
   {
     return new RepositoryResponse(getBaseUrl(), getOsType(), getRepoId(),
-            getRepoName(), getDistribution(), getComponents(), getMirrorsList(), getDefaultBaseUrl());
+            getRepoName(), getDistribution(), getComponents(), getMirrorsList(), getDefaultBaseUrl(),
+            getTags());
   }
 
   /**
@@ -259,4 +270,19 @@ public class RepositoryInfo {
   public void setAmbariManagedRepositories(boolean ambariManagedRepositories) {
     this.ambariManagedRepositories = ambariManagedRepositories;
   }
+
+  /**
+   * @return the tags for this repository
+   */
+  public Set<RepoTag> getTags() {
+    return tags;
+  }
+
+  /**
+   * @param repoTags the tags for this repository
+   */
+  public void setTags(Set<RepoTag> repoTags) {
+    tags = repoTags;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepoTag.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepoTag.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepoTag.java
new file mode 100644
index 0000000..08a2635
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepoTag.java
@@ -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.
+ */
+package org.apache.ambari.server.state.stack;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+/**
+ * A Repo tag is a way to allow Ambari to place logic surrounding repository details.
+ * This is used instead of random strings to tightly control how tags are used.
+ */
+@XmlEnum
+public enum RepoTag {
+
+  /**
+   * The repository may contain GPL-Licensed software
+   */
+  GPL
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java
index c2209bb..ccb25e8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java
@@ -27,6 +27,7 @@ import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 
@@ -150,6 +151,10 @@ public class RepositoryXml implements Validable{
     private String components = null;
     private boolean unique = false;
 
+    @XmlElementWrapper(name="tags")
+    @XmlElement(name="tag")
+    private Set<RepoTag> tags = new HashSet<>();
+
     private Repo() {
     }
 
@@ -201,6 +206,13 @@ public class RepositoryXml implements Validable{
     public void setUnique(boolean unique) {
       this.unique = unique;
     }
+
+    /**
+     * @return the repo tags
+     */
+    public Set<RepoTag> getTags() {
+      return tags;
+    }
   }
 
   /**
@@ -224,6 +236,7 @@ public class RepositoryXml implements Validable{
           ri.setDistribution(r.getDistribution());
           ri.setComponents(r.getComponents());
           ri.setUnique(r.isUnique());
+          ri.setTags(r.tags);
 
           repos.add(ri);
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
index 8276f4a..138f566 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
@@ -20,6 +20,8 @@ package org.apache.ambari.server.state.stack.upgrade;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -54,6 +56,7 @@ import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.repository.ClusterVersionSummary;
 import org.apache.ambari.server.state.repository.VersionDefinitionXml;
 import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.state.stack.RepoTag;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -191,6 +194,17 @@ public class RepositoryVersionHelper {
         if (repositoryJson.getAsJsonObject().get(RepositoryResourceProvider.REPOSITORY_UNIQUE_PROPERTY_ID) != null) {
           repositoryEntity.setUnique(repositoryJson.getAsJsonObject().get(RepositoryResourceProvider.REPOSITORY_UNIQUE_PROPERTY_ID).getAsBoolean());
         }
+
+        if (null != repositoryJson.get(RepositoryResourceProvider.REPOSITORY_TAGS_PROPERTY_ID)) {
+          Set<RepoTag> tags = new HashSet<>();
+
+          JsonArray jsonArray = repositoryJson.get(RepositoryResourceProvider.REPOSITORY_TAGS_PROPERTY_ID).getAsJsonArray();
+          for(JsonElement je : jsonArray) {
+            tags.add(RepoTag.valueOf(je.getAsString()));
+          }
+          repositoryEntity.setTags(tags);
+        }
+
         operatingSystemEntity.getRepositories().add(repositoryEntity);
       }
       operatingSystems.add(operatingSystemEntity);
@@ -242,6 +256,11 @@ public class RepositoryVersionHelper {
         repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_COMPONENTS_PROPERTY_ID, repository.getComponents());
         repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_MIRRORS_LIST_PROPERTY_ID, repository.getMirrorsList());
         repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_UNIQUE_PROPERTY_ID, repository.isUnique());
+
+        // add the tags even if there are none
+        JsonArray tags = gson.toJsonTree(repository.getTags()).getAsJsonArray();
+        repositoryJson.add(RepositoryResourceProvider.REPOSITORY_TAGS_PROPERTY_ID, tags);
+
         repositoriesJson.add(repositoryJson);
         operatingSystemJson.addProperty(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS, repository.isAmbariManagedRepositories());
       }
@@ -651,4 +670,4 @@ public class RepositoryVersionHelper {
   }
 
 
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/main/resources/version_definition.xsd
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/version_definition.xsd b/ambari-server/src/main/resources/version_definition.xsd
index eaed31d..db10d67 100644
--- a/ambari-server/src/main/resources/version_definition.xsd
+++ b/ambari-server/src/main/resources/version_definition.xsd
@@ -63,7 +63,13 @@
       <xs:enumeration value="suse12" />
     </xs:restriction>
   </xs:simpleType>
-
+  
+  <xs:simpleType name="tag-type">
+    <xs:restriction base="xs:NMTOKEN">
+      <xs:enumeration value="GPL" />
+    </xs:restriction>
+  </xs:simpleType>
+  
   <xs:complexType name="manifest-service-type">
     <xs:annotation>
       <xs:documentation>
@@ -113,6 +119,20 @@
       </xs:element>
     </xs:sequence>
   </xs:complexType>
+  
+  <xs:complexType name="tags-type">
+    <xs:annotation>
+      <xs:documentation>
+      Tags are a way to mark a repository for special purposes.  There
+      may be logic surrounding a tag in the code, or used by agents.
+      
+      Tags are NOT meant to be random strings, they must be defined
+      </xs:documentation>
+    </xs:annotation>
+    <xs:sequence>
+      <xs:element name="tag" type="tag-type" minOccurs="0" maxOccurs="unbounded" />
+    </xs:sequence>
+  </xs:complexType>
 
   <xs:complexType name="repository-info-type">
     <xs:sequence>
@@ -130,6 +150,7 @@
                   <xs:element name="components" type="xs:string" minOccurs="0" maxOccurs="1" />
                   <xs:element name="mirrorslist" type="xs:string" minOccurs="0" maxOccurs="1" />
                   <xs:element name="unique" type="xs:boolean" minOccurs="0" maxOccurs="1" />
+                  <xs:element name="tags" type="tags-type" minOccurs="0" maxOccurs="1" />
                 </xs:sequence>
               </xs:complexType>
             </xs:element>

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryResourceProviderTest.java
index ca5cde0..abdef9b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryResourceProviderTest.java
@@ -23,6 +23,7 @@ import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -36,6 +37,7 @@ import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.state.stack.RepoTag;
 import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Test;
@@ -56,7 +58,7 @@ public class RepositoryResourceProviderTest {
     AmbariManagementController managementController = EasyMock.createMock(AmbariManagementController.class);
 
     RepositoryResponse rr = new RepositoryResponse(VAL_BASE_URL, VAL_OS,
-        VAL_REPO_ID, VAL_REPO_NAME, VAL_DISTRIBUTION, VAL_COMPONENT_NAME, null, null);
+        VAL_REPO_ID, VAL_REPO_NAME, VAL_DISTRIBUTION, VAL_COMPONENT_NAME, null, null, Collections.<RepoTag>emptySet());
     rr.setStackName(VAL_STACK_NAME);
     rr.setStackVersion(VAL_STACK_VERSION);
     Set<RepositoryResponse> allResponse = new HashSet<>();
@@ -168,7 +170,7 @@ public class RepositoryResourceProviderTest {
     AmbariManagementController managementController = EasyMock.createMock(AmbariManagementController.class);
 
     RepositoryResponse rr = new RepositoryResponse(VAL_BASE_URL, VAL_OS,
-        VAL_REPO_ID, VAL_REPO_NAME, null, null, null, null);
+        VAL_REPO_ID, VAL_REPO_NAME, null, null, null, null , Collections.<RepoTag>emptySet());
     Set<RepositoryResponse> allResponse = new HashSet<>();
     allResponse.add(rr);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
index 6f33c7e..9fe6146 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
@@ -40,7 +40,10 @@ import org.apache.ambari.server.state.RepositoryType;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackInfo;
+import org.apache.ambari.server.state.stack.RepoTag;
 import org.apache.ambari.server.state.stack.RepositoryXml;
+import org.apache.ambari.server.state.stack.RepositoryXml.Os;
+import org.apache.ambari.server.state.stack.RepositoryXml.Repo;
 import org.apache.commons.io.FileUtils;
 import org.junit.Test;
 
@@ -186,15 +189,41 @@ public class VersionDefinitionTest {
   public void testSerialization() throws Exception {
 
     File f = new File("src/test/resources/version_definition_test_all_services.xml");
-
     VersionDefinitionXml xml = VersionDefinitionXml.load(f.toURI().toURL());
-
     String xmlString = xml.toXml();
-
     xml = VersionDefinitionXml.load(xmlString);
 
     assertNotNull(xml.release.build);
     assertEquals("1234", xml.release.build);
+
+    f = new File("src/test/resources/version_definition_with_tags.xml");
+    xml = VersionDefinitionXml.load(f.toURI().toURL());
+    xmlString = xml.toXml();
+
+    xml = VersionDefinitionXml.load(xmlString);
+
+    assertEquals(2, xml.repositoryInfo.getOses().size());
+    List<Repo> repos = null;
+    for (Os os : xml.repositoryInfo.getOses()) {
+      if (os.getFamily().equals("redhat6")) {
+        repos = os.getRepos();
+      }
+    }
+    assertNotNull(repos);
+    assertEquals(3, repos.size());
+
+    Repo found = null;
+    for (Repo repo : repos) {
+      if (repo.getRepoName().equals("HDP-GPL")) {
+        found = repo;
+        break;
+      }
+    }
+
+    assertNotNull(found);
+    assertNotNull(found.getTags());
+    assertEquals(1, found.getTags().size());
+    assertEquals(RepoTag.GPL, found.getTags().iterator().next());
   }
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/test/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelperTest.java
index 422c0ec..ead035c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelperTest.java
@@ -53,6 +53,6 @@ public class RepositoryVersionHelperTest {
     repositories.add(repository);
 
     final String serialized = helper.serializeOperatingSystems(repositories);
-    Assert.assertEquals("[{\"OperatingSystems/ambari_managed_repositories\":true,\"repositories\":[{\"Repositories/base_url\":\"baseurl\",\"Repositories/repo_id\":\"repoId\",\"Repositories/unique\":true}],\"OperatingSystems/os_type\":\"os\"}]", serialized);
+    Assert.assertEquals("[{\"OperatingSystems/ambari_managed_repositories\":true,\"repositories\":[{\"Repositories/base_url\":\"baseurl\",\"Repositories/repo_id\":\"repoId\",\"Repositories/unique\":true,\"Repositories/tags\":[]}],\"OperatingSystems/os_type\":\"os\"}]", serialized);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/ambari-server/src/test/resources/version_definition_with_tags.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/version_definition_with_tags.xml b/ambari-server/src/test/resources/version_definition_with_tags.xml
new file mode 100644
index 0000000..fe4266b
--- /dev/null
+++ b/ambari-server/src/test/resources/version_definition_with_tags.xml
@@ -0,0 +1,86 @@
+<?xml version="1.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.
+-->
+
+<repository-version xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:noNamespaceSchemaLocation="version_definition.xsd">
+  
+  <release>
+    <type>PATCH</type>
+    <stack-id>HDP-2.3</stack-id>
+    <version>2.3.4.1</version>
+    <build>1234</build>
+    <compatible-with>2.3.4.[1-9]</compatible-with>
+    <release-notes>http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.3.4/</release-notes>
+  </release>
+  
+  <manifest>
+    <service id="HDFS-271" name="HDFS" version="2.7.1" version-id="10" />
+    <service id="HIVE-110" name="HIVE" version="1.1.0" />
+    <service id="HIVE-200" name="HIVE" version="2.0.0" />
+    <service id="HBASE-899" name="HBASE" version="8.9.9" />
+  </manifest>
+  
+  <available-services />
+  
+  <repository-info>
+    <os family="redhat6">
+      <repo>
+        <baseurl>http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.3.0.0</baseurl>
+        <repoid>HDP-2.3</repoid>
+        <reponame>HDP</reponame>
+        <unique>true</unique>
+      </repo>
+      <repo>
+        <baseurl>http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6</baseurl>
+        <repoid>HDP-UTILS-1.1.0.20</repoid>
+        <reponame>HDP-UTILS</reponame>
+        <unique>false</unique>
+      </repo>
+      <repo>
+        <baseurl>http://public-repo-1.hortonworks.com/HDP-GPL/repos/centos6</baseurl>
+        <repoid>HDP-GPL</repoid>
+        <reponame>HDP-GPL</reponame>
+        <unique>false</unique>
+        <tags>
+          <tag>GPL</tag>
+        </tags>
+      </repo>
+    </os>
+    <os family="redhat7">
+      <repo>
+        <baseurl>http://public-repo-1.hortonworks.com/HDP/centos7/2.x/updates/2.3.0.0</baseurl>
+        <repoid>HDP-2.3</repoid>
+        <reponame>HDP</reponame>
+        <unique>true</unique>
+      </repo>
+      <repo>
+        <baseurl>http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos7</baseurl>
+        <repoid>HDP-UTILS-1.1.0.20</repoid>
+        <reponame>HDP-UTILS</reponame>
+        <unique>false</unique>
+      </repo>
+    </os>
+
+  </repository-info>
+  
+  <upgrade>
+    <configuration type="hdfs-site">
+      <set key="foo" value="bar" />
+    </configuration>
+  </upgrade>
+</repository-version>

http://git-wip-us.apache.org/repos/asf/ambari/blob/5f8dcda6/contrib/version-builder/version_builder.py
----------------------------------------------------------------------
diff --git a/contrib/version-builder/version_builder.py b/contrib/version-builder/version_builder.py
index 5bf5430..ac7ddd4 100644
--- a/contrib/version-builder/version_builder.py
+++ b/contrib/version-builder/version_builder.py
@@ -176,7 +176,7 @@ class VersionBuilder:
         e = ET.SubElement(service_element, 'component')
         e.text = component
 
-  def add_repo(self, os_family, repo_id, repo_name, base_url, unique):
+  def add_repo(self, os_family, repo_id, repo_name, base_url, unique, tags):
     """
     Adds a repository
     """
@@ -211,6 +211,13 @@ class VersionBuilder:
       e = ET.SubElement(repo_element, 'unique')
       e.text = unique
 
+    if tags is not None:
+      e = ET.SubElement(repo_element, 'tags')
+      tag_names = tags.split(',')
+      for tag in tag_names:
+        t = ET.SubElement(e, 'tag')
+        t.text = tag
+
 
   def _check_xmllint(self):
     """
@@ -326,7 +333,8 @@ def process_repo(vb, options):
   if not options.repo:
     return
 
-  vb.add_repo(options.repo_os, options.repo_id, options.repo_name, options.repo_url, options.unique)
+  vb.add_repo(options.repo_os, options.repo_id, options.repo_name, options.repo_url,
+    options.unique, options.repo_tags)
 
 def validate_manifest(parser, options):
   """
@@ -444,6 +452,7 @@ def main(argv):
                     help="Indicates base url should be unique")
   parser.add_option('--repo-id', dest='repo_id', help="The ID of the repo")
   parser.add_option('--repo-name', dest='repo_name', help="The name of the repo")
+  parser.add_option('--repo-tags', dest='repo_tags', help="The CSV tags for the repo")
 
   (options, args) = parser.parse_args()
 


[18/49] ambari git commit: AMBARI-22494 Unable to install the cluster. (atkach)

Posted by rl...@apache.org.
AMBARI-22494 Unable to install the cluster. (atkach)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 8dd9acc64f4411db96ed0582433e0d44f012c916
Parents: 7eb14a0
Author: Andrii Tkach <at...@apache.org>
Authored: Wed Nov 22 12:27:11 2017 +0200
Committer: Andrii Tkach <at...@apache.org>
Committed: Wed Nov 22 14:18:39 2017 +0200

----------------------------------------------------------------------
 ambari-web/app/mixins/main/host/details/actions/check_host.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/8dd9acc6/ambari-web/app/mixins/main/host/details/actions/check_host.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/main/host/details/actions/check_host.js b/ambari-web/app/mixins/main/host/details/actions/check_host.js
index 66baf5a..5eff19f 100644
--- a/ambari-web/app/mixins/main/host/details/actions/check_host.js
+++ b/ambari-web/app/mixins/main/host/details/actions/check_host.js
@@ -216,7 +216,7 @@ App.CheckHostMixin = Em.Mixin.create({
           return {
             hostName: Em.get(task, 'Tasks.host_name'),
             transparentHugePage: Em.get(task, 'Tasks.structured_out.transparentHugePage.message'),
-            installedPackages: installed_packages ? installed_packages : []
+            installedPackages: installed_packages && Array.isArray(installed_packages) ? installed_packages : []
           };
         }));
 


[08/49] ambari git commit: AMBARI-22463 Removing secure reference configs entries from stack for Ranger KMS service (mugdha)

Posted by rl...@apache.org.
AMBARI-22463 Removing secure reference configs entries from stack for Ranger KMS service (mugdha)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 8b820346ca2902016ee2d5d7d5d3ff5d60126933
Parents: 2d9fd41
Author: Mugdha Varadkar <mu...@apache.org>
Authored: Mon Nov 20 10:27:46 2017 +0530
Committer: Mugdha Varadkar <mu...@apache.org>
Committed: Mon Nov 20 10:57:23 2017 +0530

----------------------------------------------------------------------
 .../0.5.0.2.3/configuration/kms-site.xml        | 26 --------------------
 .../1.0.0.3.0/configuration/kms-site.xml        | 26 --------------------
 2 files changed, 52 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/8b820346/ambari-server/src/main/resources/common-services/RANGER_KMS/0.5.0.2.3/configuration/kms-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/RANGER_KMS/0.5.0.2.3/configuration/kms-site.xml b/ambari-server/src/main/resources/common-services/RANGER_KMS/0.5.0.2.3/configuration/kms-site.xml
index 59a6952..5dcdd82 100644
--- a/ambari-server/src/main/resources/common-services/RANGER_KMS/0.5.0.2.3/configuration/kms-site.xml
+++ b/ambari-server/src/main/resources/common-services/RANGER_KMS/0.5.0.2.3/configuration/kms-site.xml
@@ -65,19 +65,6 @@
     <on-ambari-upgrade add="true"/>
   </property>
   <property>
-    <name>hadoop.kms.authentication.kerberos.keytab</name>
-    <value>${user.home}/kms.keytab</value>
-    <description>Path to the keytab with credentials for the configured Kerberos principal.</description>
-    <on-ambari-upgrade add="true"/>
-  </property>
-  <property>
-    <name>hadoop.kms.authentication.kerberos.principal</name>
-    <value>HTTP/localhost</value>
-    <description>The Kerberos principal to use for the HTTP endpoint. The principal must start with 'HTTP/' as per the Kerberos HTTP SPNEGO specification.</description>
-    <property-type>KERBEROS_PRINCIPAL</property-type>
-    <on-ambari-upgrade add="true"/>
-  </property>
-  <property>
     <name>hadoop.kms.authentication.kerberos.name.rules</name>
     <value>DEFAULT</value>
     <description>Rules used to resolve Kerberos principal names.</description>
@@ -112,19 +99,6 @@
     <on-ambari-upgrade add="true"/>
   </property>
   <property>
-    <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.kerberos.keytab</name>
-    <value>/etc/hadoop/conf/kms.keytab</value>
-    <description>The absolute path for the Kerberos keytab with the credentials to connect to Zookeeper.</description>
-    <on-ambari-upgrade add="true"/>
-  </property>
-  <property>
-    <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.kerberos.principal</name>
-    <value>kms/#HOSTNAME#</value>
-    <description>The Kerberos service principal used to connect to Zookeeper.</description>
-    <property-type>KERBEROS_PRINCIPAL</property-type>
-    <on-ambari-upgrade add="true"/>
-  </property>
-  <property>
     <name>hadoop.kms.security.authorization.manager</name>
     <value>org.apache.ranger.authorization.kms.authorizer.RangerKmsAuthorizer</value>
     <description/>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8b820346/ambari-server/src/main/resources/common-services/RANGER_KMS/1.0.0.3.0/configuration/kms-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/RANGER_KMS/1.0.0.3.0/configuration/kms-site.xml b/ambari-server/src/main/resources/common-services/RANGER_KMS/1.0.0.3.0/configuration/kms-site.xml
index 1e6f7b5..19ce76f 100644
--- a/ambari-server/src/main/resources/common-services/RANGER_KMS/1.0.0.3.0/configuration/kms-site.xml
+++ b/ambari-server/src/main/resources/common-services/RANGER_KMS/1.0.0.3.0/configuration/kms-site.xml
@@ -65,19 +65,6 @@
     <on-ambari-upgrade add="false"/>
   </property>
   <property>
-    <name>hadoop.kms.authentication.kerberos.keytab</name>
-    <value>${user.home}/kms.keytab</value>
-    <description>Path to the keytab with credentials for the configured Kerberos principal.</description>
-    <on-ambari-upgrade add="false"/>
-  </property>
-  <property>
-    <name>hadoop.kms.authentication.kerberos.principal</name>
-    <value>HTTP/localhost</value>
-    <description>The Kerberos principal to use for the HTTP endpoint. The principal must start with 'HTTP/' as per the Kerberos HTTP SPNEGO specification.</description>
-    <property-type>KERBEROS_PRINCIPAL</property-type>
-    <on-ambari-upgrade add="false"/>
-  </property>
-  <property>
     <name>hadoop.kms.authentication.kerberos.name.rules</name>
     <value>DEFAULT</value>
     <description>Rules used to resolve Kerberos principal names.</description>
@@ -112,19 +99,6 @@
     <on-ambari-upgrade add="false"/>
   </property>
   <property>
-    <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.kerberos.keytab</name>
-    <value>/etc/hadoop/conf/kms.keytab</value>
-    <description>The absolute path for the Kerberos keytab with the credentials to connect to Zookeeper.</description>
-    <on-ambari-upgrade add="false"/>
-  </property>
-  <property>
-    <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.kerberos.principal</name>
-    <value>kms/#HOSTNAME#</value>
-    <description>The Kerberos service principal used to connect to Zookeeper.</description>
-    <property-type>KERBEROS_PRINCIPAL</property-type>
-    <on-ambari-upgrade add="false"/>
-  </property>
-  <property>
     <name>hadoop.kms.security.authorization.manager</name>
     <value>org.apache.ranger.authorization.kms.authorizer.RangerKmsAuthorizer</value>
     <description/>


[37/49] ambari git commit: AMBARI-22508 Ambari 3.0: Implement new design for Admin View: User Management. (atkach)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
new file mode 100644
index 0000000..e0c1144
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
@@ -0,0 +1,86 @@
+<!--
+* 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.
+-->
+
+<form id="create-group-form" role="form" novalidate name="form.groupCreateForm">
+  <div class="modal-header">
+    <h1 class="modal-title">
+      {{'groups.createLocal' | translate}}
+    </h1>
+  </div>
+  <div class="modal-body">
+    <div class="form-group"
+         ng-class="{ 'has-error': (form.groupCreateForm.groupName.$error.required || form.groupCreateForm.groupName.$error.pattern) && form.groupCreateForm.submitted }">
+      <label for="groupName">
+        {{'groups.name' | translate}}<span>&nbsp;*</span>&nbsp;
+      </label>
+      <input type="text"
+             placeholder="{{'groups.name' | translate}}"
+             ng-pattern="/^([a-zA-Z0-9._\s]+)$/"
+             autofocus
+             ng-maxlength="80"
+             autocomplete="off"
+             class="form-control"
+             ng-model="formData.groupName"
+             name="groupName"
+             id="groupName"
+             ng-change="checkIfInstanceExist()"
+             required>
+      <span class="help-block validation-block"
+            ng-show='form.groupCreateForm.groupName.$error.required && form.groupCreateForm.submitted'>
+        {{'common.alerts.fieldRequired' | translate}}
+      </span>
+      <span class="help-block validation-block"
+            ng-show='form.groupCreateForm.groupName.$error.pattern && form.groupCreateForm.submitted'>
+        {{'common.alerts.noSpecialChars' | translate}}
+      </span>
+    </div>
+
+    <div class="form-group">
+      <label>{{'groups.addUsers' | translate}}</label>
+      <div>
+        <editable-list items-source="formData.members" resource-type="User" editable="true"></editable-list>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="form-group col-sm-6"
+           ng-class="{ 'has-error': form.groupCreateForm.role.$error.required && form.groupCreateForm.submitted }">
+        <label for="role" class="nowrap">
+          {{'groups.role' | translate}}
+          <i class="fa fa-question-circle" aria-hidden="true"></i>
+        </label>
+        <select
+          class="form-control"
+          id="role"
+          name="role"
+          ng-model="formData.role">
+          <option value="" disabled selected>{{'common.select' | translate}}</option>
+          <option ng-repeat="role in roleOptions" value="{{role.permission_id}}">{{role.permission_label}}</option>
+        </select>
+        <span class="help-block validation-block" ng-show='form.groupCreateForm.role.$error.required && form.groupCreateForm.submitted'>
+          {{'common.alerts.fieldRequired' | translate}}
+        </span>
+      </div>
+    </div>
+
+  </div>
+  <div class="modal-footer">
+    <button class="btn btn-default" ng-click="cancel()">{{'common.controls.cancel' | translate}}</button>
+    <button class="btn btn-primary" ng-click="save()" type="submit">{{'common.controls.save' | translate}}</button>
+  </div>
+</form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
new file mode 100644
index 0000000..0af26eb
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
@@ -0,0 +1,147 @@
+<!--
+* 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.
+-->
+
+<form id="create-user-form" role="form" novalidate name="form.userCreateForm">
+  <div class="modal-header">
+    <h1 class="modal-title">
+      {{'users.create' | translate}}
+    </h1>
+  </div>
+  <div class="modal-body">
+    <div class="form-group"
+         ng-class="{ 'has-error': (form.userCreateForm.userName.$error.required || form.userCreateForm.userName.$error.pattern) && form.userCreateForm.submitted }">
+      <label for="userName">
+        {{'users.username' | translate}}<span>&nbsp;*</span>&nbsp;
+        <i class="fa fa-question-circle" aria-hidden="true"></i>
+      </label>
+      <input type="text"
+             autofocus
+             placeholder="{{'users.user.name' | translate}}"
+             ng-pattern="/^[^<>&`|\\]+$/"
+             ng-maxlength="80"
+             tooltip="{{'users.userNameTip' | translate}}"
+             autocomplete="off"
+             tooltip-trigger="focus"
+             class="form-control"
+             ng-model="formData.userName"
+             name="userName"
+             id="userName"
+             ng-change="checkIfInstanceExist()"
+             required>
+      <span class="help-block validation-block"
+            ng-show='form.userCreateForm.userName.$error.required && form.userCreateForm.submitted'>
+        {{'common.alerts.fieldRequired' | translate}}
+      </span>
+      <span class="help-block validation-block"
+            ng-show='form.userCreateForm.userName.$error.pattern && form.userCreateForm.submitted'>
+        {{'common.alerts.noSpecialChars' | translate}}
+      </span>
+    </div>
+
+    <div class="row">
+      <div class="form-group col-sm-6"
+           ng-class="{ 'has-error': form.userCreateForm.password.$error.required && form.userCreateForm.submitted }">
+        <label for="password">
+          {{'users.password' | translate}}<span>&nbsp;*</span>
+        </label>
+        <input type="password"
+               id="password"
+               class="form-control"
+               name="password"
+               placeholder="{{'users.password' | translate}}"
+               required
+               ng-model="formData.password"
+               autocomplete="off">
+        <span class="help-block validation-block"
+              ng-show='form.userCreateForm.password.$error.required && form.userCreateForm.submitted'>
+          {{'common.alerts.fieldRequired' | translate}}
+        </span>
+      </div>
+      <div class="form-group col-sm-6"
+           ng-class="{ 'has-error': form.userCreateForm.confirmPassword.$error.passwordVerify || (form.userCreateForm.confirmPassword.$error.required && form.userCreateForm.submitted) }">
+        <label for="confirmPassword">
+          {{'users.confirmPassword' | translate}}<span>&nbsp;*</span>
+        </label>
+        <input type="password"
+               id="confirmPassword"
+               class="form-control"
+               name="confirmPassword"
+               placeholder="{{'users.confirmPassword' | translate}}"
+               required
+               password-verify="formData.password"
+               ng-model="formData.confirmPassword"
+               autocomplete="off">
+        <span class="help-block validation-block"
+              ng-show='form.userCreateForm.confirmPassword.$error.required && form.userCreateForm.submitted'>
+          {{'common.alerts.fieldRequired' | translate}}
+        </span>
+        <span class="help-block validation-block"
+              ng-show='form.userCreateForm.confirmPassword.$error.passwordVerify'>
+          {{'users.alerts.wrongPassword' | translate}}
+        </span>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="form-group col-sm-6"
+           ng-class="{ 'has-error': form.userCreateForm.role.$error.required && form.userCreateForm.submitted }">
+        <label for="role" class="nowrap">
+          {{'users.role' | translate}}<span>&nbsp;*</span>&nbsp;
+          <i class="fa fa-question-circle" aria-hidden="true"></i>
+        </label>
+        <select
+          class="form-control"
+          id="role"
+          name="role"
+          ng-model="formData.role"
+          required>
+          <option value="" disabled selected>{{'common.select' | translate}}</option>
+          <option ng-repeat="role in roleOptions" value="{{role.permission_id}}">{{role.permission_label}}</option>
+        </select>
+        <span class="help-block validation-block" ng-show='form.userCreateForm.role.$error.required && form.userCreateForm.submitted'>
+          {{'common.alerts.fieldRequired' | translate}}
+        </span>
+      </div>
+    </div>
+
+    <div class="form-group">
+      <label>
+        {{'users.isAmbariAdmin' | translate}}<span>&nbsp;*</span>
+        <i class="fa fa-question-circle" aria-hidden="true"></i>
+      </label>
+      <div>
+        <toggle-switch model="formData.isAdmin" on-label="{{'common.yes' | translate}}" off-label="{{'common.no' | translate}}" class="switch-primary" data-off-color="danger"></toggle-switch>
+      </div>
+    </div>
+
+    <div class="form-group">
+      <label>
+        {{'users.isActive' | translate}}<span>&nbsp;*</span>
+        <i class="fa fa-question-circle" aria-hidden="true"></i>
+      </label>
+      <div>
+        <toggle-switch model="formData.isActive" on-label="{{'users.active' | translate}}" off-label="{{'users.inactive' | translate}}" class="switch-primary" data-off-color="danger"></toggle-switch>
+      </div>
+    </div>
+
+  </div>
+  <div class="modal-footer">
+    <button class="btn btn-default" ng-click="cancel()">{{'common.controls.cancel' | translate}}</button>
+    <button class="btn btn-primary" ng-click="save()" type="submit">{{'common.controls.save' | translate}}</button>
+  </div>
+</form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html
new file mode 100644
index 0000000..0372a11
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html
@@ -0,0 +1,122 @@
+<!--
+* 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 ng-show="user" class="user-edit-panel">
+  <div class="clearfix">
+    <ol class="breadcrumb pull-left">
+      <li><a href="#/userManagement">{{'common.users' | translate}}</a></li>
+      <li class="active"><span class="glyphicon glyphicon-flash" ng-show="user.admin"></span>{{user.user_name}}</li>
+    </ol>
+    <div class="pull-right top-margin-4">
+      <div ng-switch="isCurrentUser || user.user_type != 'LOCAL'">
+        <button class="btn deleteuser-btn disabled btn-default" ng-switch-when="true" tooltip="{{'common.cannotDelete' | translate: '{term: constants.user}'}}">{{'common.delete' | translate: '{term: constants.user}'}}</button>
+        <button class="btn deleteuser-btn btn-danger" ng-switch-when="false" ng-click="deleteUser()">{{'common.delete' | translate: '{term: constants.user}'}}</button>
+      </div>
+    </div>
+  </div>
+  <hr>
+  <form class="form-horizontal" role="form" >
+    <div class="form-group">
+      <label for="" class="col-sm-2 control-label">{{'common.type' | translate}}</label>
+      <div class="col-sm-10">
+        <label for="" class="control-label">{{user.userTypeName}}</label>
+      </div>
+    </div>
+    <div class="form-group">
+      <label for="" class="col-sm-2 control-label">{{'users.status' | translate}}</label>
+      <div class="col-sm-10">
+        <toggle-switch on-change="toggleUserActive()" disabled-tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.status}'}}" ng-disabled="isCurrentUser" model="user.active" on-label="{{'users.active' | translate}}" off-label="{{'users.inactive' | translate}}" class="switch-primary userstatus {{user ? '' : 'no-animation'}}" data-off-color="danger"></toggle-switch>
+      </div>
+    </div>
+    <div class="form-group">
+      <label for="" class="col-sm-2 control-label"><span class="glyphicon glyphicon-flash"></span> {{'users.ambariAdmin' | translate}}</label>
+      <div class="col-sm-10">
+        <toggle-switch on-change="toggleUserAdmin()" disabled-tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.admin}'}}" ng-disabled="isCurrentUser" model="user.admin" on-label="{{'common.yes' | translate}}" off-label="{{'common.no' | translate}}" class="switch-primary userstatus {{user ? '' : 'no-animation'}}" data-off-color="danger"></toggle-switch>
+      </div>
+    </div>
+    <div class="form-group">
+      <label for="password" class="col-sm-2 control-label">{{'users.password' | translate}}</label>
+      <div class="col-sm-10">
+        <div ng-switch="user.user_type != 'LOCAL'">
+          <button class="btn deleteuser-btn disabled btn-default" ng-switch-when="true" tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.password}'}}">{{'users.changePassword' | translate}}</button>
+          <a href ng-click="openChangePwdDialog()" ng-switch-when="false" class="btn btn-default changepassword">{{'users.changePassword' | translate}}</a>
+        </div>
+          
+      </div>
+    </div>
+    <div class="form-group">
+      <label for="groups" class="col-sm-2 control-label">{{getUserMembership(user.user_type)}}</label>
+      <div class="col-sm-10">
+        <editable-list items-source="editingGroupsList" resource-type="Group" editable="user.user_type == 'LOCAL'"></editable-list>
+      </div>
+        
+    </div>
+    <div class="form-group" >
+      <label for="" class="col-sm-2 control-label">{{'common.privileges' | translate}}</label>
+      <div class="col-sm-10">
+        <table class="table" ng-hide="hidePrivileges || user.admin">
+          <thead>
+            <tr>
+              <th>{{'common.cluster' | translate}}</th>
+              <th>{{'common.clusterRole' | translate}}</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr ng-repeat="(name, privilege) in privileges.clusters">
+              <td>
+                <span class="glyphicon glyphicon-cloud"></span> 
+                <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
+              </td>
+              <td>
+                <span tooltip="{{privilege.permission_label}}">{{privilege.permission_label}}</span>
+              </td>
+            </tr>
+            <tr>
+              <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
+            </tr>
+          </tbody>
+          <thead class="view-permission-header">
+            <tr>
+              <th>{{'common.view' | translate}}</th>
+              <th>{{'common.viewPermissions' | translate}}</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr ng-repeat="(name, privilege) in privileges.views">
+              <td>
+                <span class="glyphicon glyphicon-th"></span>
+                <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
+              </td>
+              <td>
+                <span tooltip="{{item}}" ng-repeat="item in privilege.privileges track by $index">{{item | translate}}{{$last ? '' : ', '}}</span>
+              </td>
+              <td>
+                <i class="fa fa-trash-o" aria-hidden="true" ng-click="removePrivilege(name, privilege);"></i>
+              </td>
+            </tr>
+            <tr>
+              <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
+            </tr>
+          </tbody>
+        </table>
+        <div class="alert alert-info" ng-show="!privileges && !user.admin">{{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.user}'}}</div>
+        <div class="alert alert-info" ng-show="user.admin">{{'users.userIsAdmin' | translate}}</div>
+      </div>
+    </div>
+  </form>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html
new file mode 100644
index 0000000..cc4789b
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html
@@ -0,0 +1,119 @@
+<!--
+* 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="users-pane">
+  <div class="clearfix panel">
+    <button class="btn btn-default createuser-btn pull-right" ng-click="createUser();">
+      {{'users.create' | translate}}
+    </button>
+  </div>
+  <table class="table table-striped table-hover">
+    <thead>
+      <tr class="fix-bottom">
+        <th>
+          <span>{{'users.username' | translate}}</span>
+        </th>
+        <th>
+          <span>{{'clusters.role' | translate}}</span>
+        </th>
+        <th>
+          <span>{{'users.status' | translate}}</span>
+        </th>
+        <th>
+          <span>{{'common.type' | translate}}</span>
+        </th>
+        <th>
+          <span>{{'common.group' | translate}}</span>
+        </th>
+        <th class="entity-actions">
+          <span>{{'common.actions' | translate}}</span>
+        </th>
+      </tr>
+      <tr class="fix-top">
+        <th>
+          <div class="search-container">
+            <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="filters.name" ng-change="resetPagination()">
+            <button type="button" class="close clearfilter" ng-show="filters.name" ng-click="filters.name=''; resetPagination()">
+              <span aria-hidden="true">&times;</span><span class="sr-only">{{'common.controls.close' | translate}}</span>
+            </button>
+          </div>
+        </th>
+        <th></th>
+        <th>
+          <select class="form-control statusfilter"
+                  ng-model="filters.status"
+                  ng-options="item.label for item in activeFilterOptions"
+                  ng-change="resetPagination()">
+          </select>
+        </th>
+        <th>
+          <select class="form-control typefilter"
+                  ng-model="filters.type"
+                  ng-options="item.label for item in typeFilterOptions"
+                  ng-change="resetPagination()">
+          </select>
+        </th>
+        <th></th>
+        <th></th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr ng-repeat="user in users">
+        <td>
+          <span>{{user.Users.user_name}}</span>
+        </td>
+        <td>
+          <span>{{user.Users.role}}</span>
+        </td>
+        <td>
+          <span>
+            {{(user.Users.active ? 'users.active' : 'users.inactive') | translate}}
+          </span>
+        </td>
+        <td><span>{{user.Users.userTypeName}}</span></td>
+        <td><span>{{user.Users.groups.length ? user.Users.groups.join(' ') : '-'}}</span></td>
+        <td class="entity-actions">
+          <a href="#/users/{{user.Users.encodedName}}/edit">
+            <i class="fa fa-pencil"></i>
+          </a>
+          <a href ng-click="deleteUser(user.Users)">
+            <i class="fa fa-trash-o"></i>
+          </a>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+  <div ng-if="isLoading" class="spinner-container">
+    <i class="fa fa-2x fa-spinner fa-spin" aria-hidden="true"></i>
+  </div>
+  <div class="alert empty-table-alert col-sm-12" ng-show="!users.length && !isLoading">
+    {{'common.alerts.nothingToDisplay' | translate: '{term: constants.users}'}}
+  </div>
+  <div class="col-sm-12 table-bar" ng-show="totalUsers > minRowsToShowPagination">
+    <div class="pull-left filtered-info">
+      <span>{{'common.filterInfo' | translate: '{showed: tableInfo.showed, total: tableInfo.total, term: constants.users}'}}</span>
+      <span ng-show="isNotEmptyFilter">- <a href ng-click="clearFilters()">{{'common.controls.clearFilters' | translate}}</a></span>
+    </div>
+    <div class="pull-right left-margin">
+      <pagination class="paginator" total-items="totalUsers" max-size="maxVisiblePages" items-per-page="usersPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
+    </div>
+    <div class="pull-right">
+      <select class="form-control" ng-model="usersPerPage" ng-change="usersPerPageChanges()" ng-options="currOption for currOption in [10, 25, 50, 100]"></select>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/users/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/users/create.html
deleted file mode 100644
index 80a3b04..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/create.html
+++ /dev/null
@@ -1,82 +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.
--->
-<ol class="breadcrumb">
-  <li><a href="#/users">{{'common.users' | translate}}</a></li>
-  <li class="active">{{'users.create' | translate}}</li>
-</ol>
-<hr>
-<form class="form-horizontal create-user-form" role="form" novalidate name="form" autocomplete="off">
-  <div class="form-group" ng-class="{'has-error' : form.user_name.$error.required && form.submitted}">
-    <label for="username" class="col-sm-2 control-label">{{'users.username' | translate}}</label>
-    <div class="col-sm-10"
-         ng-class="{'has-error': form.user_name.$error.pattern}">
-      <input
-        autofocus
-        type="text"
-        id="username"
-        class="form-control username-input"
-        name="user_name"
-        placeholder="{{'users.userName' | translate}}"
-        ng-model="user.user_name"
-        ng-required="true"
-        ng-pattern="/^[^<>&`|\\]+$/"
-        ng-maxlength="80"
-        tooltip="{{'users.userNameTip' | translate}}"
-        autocomplete="off"
-        tooltip-trigger="focus">
-      <div class="alert alert-danger top-margin" ng-show="form.user_name.$error.required && form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
-    </div>
-  </div>
-  <div class="form-group">
-    <label for="" class="col-sm-2 control-label">{{'common.type' | translate}}</label>
-    <div class="col-sm-10">
-      <label for="" class="control-label">{{'common.local' | translate}}</label>
-    </div>
-  </div>
-  <div class="form-group">
-    <label for="" class="col-sm-2 control-label">{{'users.status' | translate}}</label>
-    <div class="col-sm-10">
-      <toggle-switch model="user.active" on-label="{{'users.active' | translate}}" off-label="{{'users.inactive' | translate}}" class="switch-primary userstatus" data-off-color="danger"></toggle-switch>
-    </div>
-  </div>
-  <div class="form-group">
-    <label for="" class="col-sm-2 control-label"><span class="glyphicon glyphicon-flash"></span>{{'users.ambariAdmin' | translate}}</label>
-    <div class="col-sm-10">
-      <toggle-switch ng-disabled="isCurrentUser" model="user.admin" on-label="{{'common.yes' | translate}}" off-label="{{'common.no' | translate}}" class="switch-primary userstatus" data-off-color="danger"></toggle-switch>
-    </div>
-    </div>
-  <div class="form-group" ng-class="{'has-error' : (form.password.$error.required && form.submitted) || form.confirmPassword.$error.passwordVerify}">
-    <label for="password" class="col-sm-2 control-label">{{'users.password' | translate}}</label>
-    <div class="col-sm-10">
-      <input type="password" class="form-control bottom-margin userpassword" name="password" placeholder="{{'users.password' | translate}}" required ng-model="user.password" autocomplete="off">
-      <input type="password" class="form-control bottom-margin userpasswordconfirm" name="confirmPassword" placeholder="{{'users.passwordConfirmation' | translate}}" required ng-model="user.passwordConfirmation"
-        password-verify="user.password" autocomplete="off">
-
-      <div class="alert alert-danger" ng-show='form.confirmPassword.$error.passwordVerify'>{{'users.alerts.wrongPassword' | translate}}</div>
-      <div class="alert alert-danger" ng-show='form.password.$error.required && form.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
-      
-    </div>
-  </div>
-  <div class="form-group">
-    <div class="col-sm-offset-2 col-sm-10">
-      <button class="btn btn-primary pull-right left-margin saveuser" ng-click="createUser()">{{'common.controls.save' | translate}}</button>
-      <a class="btn btn-default pull-right cancel" href ng-click="cancel()">{{'common.controls.cancel' | translate}}</a>
-    </div>
-  </div>
-      
-</form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/users/list.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/list.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/users/list.html
deleted file mode 100644
index 12227c3..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/list.html
+++ /dev/null
@@ -1,97 +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.
--->
-
-<div class="users-pane">
-  <div class="clearfix">
-    <ol class="breadcrumb pull-left">
-      <li class="active">{{'common.users' | translate}}</li>
-    </ol>
-    <div class="pull-right top-margin-4">
-      <link-to route="users.create" class="btn btn-default createuser-btn">
-        </span> {{'users.create' | translate}}
-      </link-to>
-    </div>
-  </div>
-  <table class="table table-striped table-hover">
-    <thead>
-      <tr>
-        <th width="30">
-          <span class="bottom-margin admin-filter glyphicon glyphicon-flash" 
-            ng-class="{'no-filter' : !adminFilter}" 
-            ng-click="toggleAdminFilter()"
-            tooltip="{{(adminFilter ? 'users.showAll' : 'users.showAdmin') | translate}}"
-          ></span>
-        </th>
-        <th>
-          <div class="search-container">
-            <label for="">{{'users.username' | translate}}</label>
-            <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="currentNameFilter" ng-change="resetPagination()">
-            <button type="button" class="close clearfilter" ng-show="currentNameFilter" ng-click="currentNameFilter=''; resetPagination()"><span aria-hidden="true">&times;</span><span class="sr-only">{{'common.controls.close' | translate}}</span></button>
-          </div>
-        </th>
-        <th>
-          <label for="">{{'common.type' | translate}}</label>
-          <select class="form-control typefilter"
-            ng-model="currentTypeFilter"
-            ng-options="item.label for item in typeFilterOptions"
-            ng-change="resetPagination()">
-          </select>
-
-        </th>
-        <th>
-          <label for="">{{'users.status' | translate}}</label>
-          <select class="form-control statusfilter" 
-            ng-model="currentActiveFilter"
-            ng-options="item.label for item in activeFilterOptions"
-            ng-change="resetPagination()">
-          </select>
-        </th>
-      </tr>
-    </thead>
-    <tbody>
-      <tr ng-repeat="user in users">
-        <td>
-          <span class="glyphicon" tooltip="{{user.Users.admin ? constants.admin : ''}}" ng-class="{'glyphicon-flash' : user.Users.admin}"></span>
-        </td>
-        <td>
-           <a href="#/users/{{user.Users.encoded_name}}">{{user.Users.user_name}}</a>
-        </td>
-        <td>{{user.Users.userTypeName}}</td>
-        <td><span ng-class="user.Users.active ? 'text-success' : 'text-danger'">{{(user.Users.active ? 'users.active' : 'users.inactive') | translate}}</span></td>
-      </tr>
-    </tbody>
-  </table>
-  <div ng-if="isLoading" class="spinner-container">
-    <i class="fa fa-2x fa-spinner fa-spin" aria-hidden="true"></i>
-  </div>
-  <div class="alert empty-table-alert col-sm-12" ng-show="!users.length && !isLoading">
-    {{'common.alerts.nothingToDisplay' | translate: '{term: constants.users}'}}
-  </div>
-  <div class="col-sm-12 table-bar">
-    <div class="pull-left filtered-info">
-      <span>{{'common.filterInfo' | translate: '{showed: tableInfo.showed, total: tableInfo.total, term: constants.users}'}}</span>
-      <span ng-show="isNotEmptyFilter">- <a href ng-click="clearFilters()">{{'common.controls.clearFilters' | translate}}</a></span>
-    </div>
-    <div class="pull-right left-margin">
-      <pagination class="paginator" total-items="totalUsers" max-size="maxVisiblePages" items-per-page="usersPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
-    </div>
-    <div class="pull-right">
-      <select class="form-control" ng-model="usersPerPage" ng-change="usersPerPageChanges()" ng-options="currOption for currOption in [10, 25, 50, 100]"></select>
-    </div>
-  </div>
-</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/users/modals/changePassword.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/modals/changePassword.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/users/modals/changePassword.html
deleted file mode 100644
index f29d315..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/modals/changePassword.html
+++ /dev/null
@@ -1,46 +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.
--->
-<div class="modal-header">
-  <h3 class="modal-title">{{'users.changePasswordFor' | translate: '{userName: userName}'}}</h3>
-</div>
-<div class="modal-body">
-  <form class="form-horizontal" novalidate name="form.passwordChangeForm" role="form" >
-    <div class="form-group" ng-class="{'has-error' : (form.passwordChangeForm.currentPassword.$error.required && form.passwordChangeForm.submitted)}">
-      <label for="" class="col-sm-4 control-label" >{{'users.yourPassword' | translate}}</label>
-      <div class="col-sm-8">
-        <input type="password" name="currentPassword" class="form-control bottom-margin" placeholder="{{'users.yourPassword' | translate}}" required ng-model="passwordData.currentUserPassword" autocomplete="off">
-        <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
-      </div>
-    </div>
-    <div class="form-group no-margin-bottom" ng-class="{'has-error' : (form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted) || form.passwordChangeForm.confirmPassword.$error.passwordVerify}">
-      <label for="" class="col-sm-4 control-label">{{'users.newPassword' | translate}}:</label>
-      <div class="col-sm-8">
-        <input type="password" class="form-control bottom-margin" name="password" placeholder="{{'users.newPassword' | translate}}" required ng-model="passwordData.password" autocomplete="off">
-        <input type="password" class="form-control bottom-margin" name="confirmPassword" placeholder="{{'users.newPasswordConfirmation' | translate}}" required ng-model="passwordData.passwordConfirmation"
-          password-verify="passwordData.password" autocomplete="off">
-        <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.confirmPassword.$error.passwordVerify'>{{'users.alerts.wrongPassword' | translate}}</div>
-        <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
-      </div>
-
-    </div>
-  </form>
-</div>
-<div class="modal-footer">
-  <button class="btn btn-default" ng-click="cancel()">{{'common.controls.cancel' | translate}}</button>
-  <button class="btn btn-primary" ng-click="ok()">{{'common.controls.ok' | translate}}</button>
-</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/users/show.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/show.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/users/show.html
deleted file mode 100644
index f965c5d..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/show.html
+++ /dev/null
@@ -1,122 +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.
--->
-    
-<div ng-show="user" class="user-edit-panel">
-  <div class="clearfix">
-    <ol class="breadcrumb pull-left">
-      <li><a href="#/users">{{'common.users' | translate}}</a></li>
-      <li class="active"><span class="glyphicon glyphicon-flash" ng-show="user.admin"></span>{{user.user_name}}</li>
-    </ol>
-    <div class="pull-right top-margin-4">
-      <div ng-switch="isCurrentUser || user.user_type != 'LOCAL'">
-        <button class="btn deleteuser-btn disabled btn-default" ng-switch-when="true" tooltip="{{'common.cannotDelete' | translate: '{term: constants.user}'}}">{{'common.delete' | translate: '{term: constants.user}'}}</button>
-        <button class="btn deleteuser-btn btn-danger" ng-switch-when="false" ng-click="deleteUser()">{{'common.delete' | translate: '{term: constants.user}'}}</button>
-      </div>
-    </div>
-  </div>
-  <hr>
-  <form class="form-horizontal" role="form" >
-    <div class="form-group">
-      <label for="" class="col-sm-2 control-label">{{'common.type' | translate}}</label>
-      <div class="col-sm-10">
-        <label for="" class="control-label">{{user.userTypeName}}</label>
-      </div>
-    </div>
-    <div class="form-group">
-      <label for="" class="col-sm-2 control-label">{{'users.status' | translate}}</label>
-      <div class="col-sm-10">
-        <toggle-switch on-change="toggleUserActive()" disabled-tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.status}'}}" ng-disabled="isCurrentUser" model="user.active" on-label="{{'users.active' | translate}}" off-label="{{'users.inactive' | translate}}" class="switch-primary userstatus {{user ? '' : 'no-animation'}}" data-off-color="danger"></toggle-switch>
-      </div>
-    </div>
-    <div class="form-group">
-      <label for="" class="col-sm-2 control-label"><span class="glyphicon glyphicon-flash"></span> {{'users.ambariAdmin' | translate}}</label>
-      <div class="col-sm-10">
-        <toggle-switch on-change="toggleUserAdmin()" disabled-tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.admin}'}}" ng-disabled="isCurrentUser" model="user.admin" on-label="{{'common.yes' | translate}}" off-label="{{'common.no' | translate}}" class="switch-primary userstatus {{user ? '' : 'no-animation'}}" data-off-color="danger"></toggle-switch>
-      </div>
-    </div>
-    <div class="form-group">
-      <label for="password" class="col-sm-2 control-label">{{'users.password' | translate}}</label>
-      <div class="col-sm-10">
-        <div ng-switch="user.user_type != 'LOCAL'">
-          <button class="btn deleteuser-btn disabled btn-default" ng-switch-when="true" tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.password}'}}">{{'users.changePassword' | translate}}</button>
-          <a href ng-click="openChangePwdDialog()" ng-switch-when="false" class="btn btn-default changepassword">{{'users.changePassword' | translate}}</a>
-        </div>
-          
-      </div>
-    </div>
-    <div class="form-group">
-      <label for="groups" class="col-sm-2 control-label">{{getUserMembership(user.user_type)}}</label>
-      <div class="col-sm-10">
-        <editable-list items-source="editingGroupsList" resource-type="Group" editable="user.user_type == 'LOCAL'"></editable-list>
-      </div>
-        
-    </div>
-    <div class="form-group" >
-      <label for="" class="col-sm-2 control-label">{{'common.privileges' | translate}}</label>
-      <div class="col-sm-10">
-        <table class="table" ng-hide="hidePrivileges || user.admin">
-          <thead>
-            <tr>
-              <th>{{'common.cluster' | translate}}</th>
-              <th>{{'common.clusterRole' | translate}}</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr ng-repeat="(name, privilege) in privileges.clusters">
-              <td>
-                <span class="glyphicon glyphicon-cloud"></span> 
-                <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
-              </td>
-              <td>
-                <span tooltip="{{privilege.permission_label}}">{{privilege.permission_label}}</span>
-              </td>
-            </tr>
-            <tr>
-              <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
-            </tr>
-          </tbody>
-          <thead class="view-permission-header">
-            <tr>
-              <th>{{'common.view' | translate}}</th>
-              <th>{{'common.viewPermissions' | translate}}</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr ng-repeat="(name, privilege) in privileges.views">
-              <td>
-                <span class="glyphicon glyphicon-th"></span>
-                <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
-              </td>
-              <td>
-                <span tooltip="{{item}}" ng-repeat="item in privilege.privileges track by $index">{{item | translate}}{{$last ? '' : ', '}}</span>
-              </td>
-              <td>
-                <i class="fa fa-trash-o" aria-hidden="true" ng-click="removePrivilege(name, privilege);"></i>
-              </td>
-            </tr>
-            <tr>
-              <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
-            </tr>
-          </tbody>
-        </table>
-        <div class="alert alert-info" ng-show="!privileges && !user.admin">{{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.user}'}}</div>
-        <div class="alert alert-info" ng-show="user.admin">{{'users.userIsAdmin' | translate}}</div>
-      </div>
-    </div>
-  </form>
-</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/clusters/UserAccessListCtrl_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/clusters/UserAccessListCtrl_test.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/clusters/UserAccessListCtrl_test.js
deleted file mode 100644
index 14c0975..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/clusters/UserAccessListCtrl_test.js
+++ /dev/null
@@ -1,820 +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.
- */
-
-describe('#Cluster', function () {
-
-  describe('UserAccessListCtrl', function() {
-
-    var scope, ctrl, $t, $httpBackend, Cluster, deferred, Alert, mock;
-
-    beforeEach(module('ambariAdminConsole', function () {}));
-
-    beforeEach(inject(function($rootScope, $controller, _$translate_, _$httpBackend_, _Cluster_, _$q_, _Alert_) {
-      scope = $rootScope.$new();
-      $t = _$translate_.instant;
-      $httpBackend = _$httpBackend_;
-      Cluster = _Cluster_;
-      Alert = _Alert_;
-      deferred = {
-        createPrivileges: _$q_.defer(),
-        getPrivilegesForResource: _$q_.defer(),
-        getPrivilegesWithFilters: _$q_.defer(),
-        deletePrivileges: _$q_.defer(),
-        deleteMultiplePrivileges: _$q_.defer()
-      };
-      ctrl = $controller('UserAccessListCtrl', {
-        $scope: scope
-      });
-      mock = {
-        Cluster: Cluster,
-        Alert: Alert,
-        scope: scope
-      };
-      spyOn(Cluster, 'createPrivileges').andReturn(deferred.createPrivileges.promise);
-      spyOn(Cluster, 'deletePrivileges').andReturn(deferred.deletePrivileges.promise);
-      spyOn(Cluster, 'getPrivilegesForResource').andReturn(deferred.getPrivilegesForResource.promise);
-      spyOn(Cluster, 'getPrivilegesWithFilters').andReturn(deferred.getPrivilegesWithFilters.promise);
-      spyOn(Alert, 'success').andCallFake(angular.noop);
-      spyOn(Alert, 'error').andCallFake(angular.noop);
-      spyOn(scope, 'loadRoles').andCallFake(angular.noop);
-
-      $httpBackend.expectGET(/\/api\/v1\/permissions/).respond(200, {
-        items: []
-      });
-      $httpBackend.expectGET(/\/api\/v1\/users?.*/).respond(200, {
-        items:[]
-      });
-      $httpBackend.flush();
-    }));
-
-    describe('#clearFilters()', function () {
-
-      it('should clear filters and reset pagination', function () {
-        scope.currentPage = 2;
-        scope.currentNameFilter = 'a';
-        scope.roleFilterOptions = [
-          {
-            label: $t('common.all'),
-            value: ''
-          },
-          {
-            label: $t('users.roles.clusterUser'),
-            value: 'CLUSTER.USER'
-          }
-        ];
-        scope.currentRoleFilter = scope.roleFilterOptions[1];
-        scope.clearFilters();
-        expect(scope.currentNameFilter).toEqual('');
-        expect(scope.currentRoleFilter).toEqual({
-          label: $t('common.all'),
-          value: ''
-        });
-        expect(scope.currentPage).toEqual(1);
-      });
-
-    });
-
-    describe('#isNotEmptyFilter', function () {
-
-      var cases = [
-        {
-          currentNameFilter: '',
-          currentRoleFilter: null,
-          isNotEmptyFilter: false,
-          title: 'no filters'
-        },
-        {
-          currentNameFilter: '',
-          currentRoleFilter: {
-            value: ''
-          },
-          isNotEmptyFilter: false,
-          title: 'empty filters'
-        },
-        {
-          currentNameFilter: 'a',
-          currentRoleFilter: {
-            value: ''
-          },
-          isNotEmptyFilter: true,
-          title: 'name filter'
-        },
-        {
-          currentNameFilter: '0',
-          currentRoleFilter: {
-            value: ''
-          },
-          isNotEmptyFilter: true,
-          title: 'name filter with "0" as string'
-        },
-        {
-          currentNameFilter: '',
-          currentRoleFilter: {
-            value: 'CLUSTER.USER'
-          },
-          isNotEmptyFilter: true,
-          title: 'role filter'
-        },
-        {
-          currentNameFilter: 'a',
-          currentRoleFilter: {
-            value: 'GROUP'
-          },
-          isNotEmptyFilter: true,
-          title: 'all filters'
-        },
-        {
-          currentNameFilter: '0',
-          currentRoleFilter: {
-            value: 'GROUP'
-          },
-          isNotEmptyFilter: true,
-          title: 'all filters with "0" as string'
-        }
-      ];
-
-      cases.forEach(function (item) {
-        it(item.title, function () {
-          scope.currentNameFilter = item.currentNameFilter;
-          scope.currentRoleFilter = item.currentRoleFilter;
-          scope.$digest();
-          expect(scope.isNotEmptyFilter).toEqual(item.isNotEmptyFilter);
-        });
-      });
-
-    });
-
-    describe('#save() for Users', function(){
-      var user = {};
-
-      beforeEach(function() {
-        items1 = {
-            "href" : "http://abc.com:8080/api/v1/users/user1",
-            "Users" : { "user_name" : "user1" },
-            "privileges" : [
-              {
-                "href" : "http://abc.com:8080/api/v1/users/user1/privileges/222",
-                "PrivilegeInfo" : {
-                  "cluster_name" : "myCluster",
-                  "permission_label" : "Service Administrator",
-                  "permission_name" : "SERVICE.ADMINISTRATOR",
-                  "principal_name" : "mygroup2",
-                  "principal_type" : "GROUP",
-                  "privilege_id" : 222,
-                  "type" : "CLUSTER",
-                  "user_name" : "user1"
-                }
-              }, {
-                "href" : "http://abc.com:8080/api/v1/users/user1/privileges/111",
-                "PrivilegeInfo" : {
-                  "cluster_name" : "myCluster",
-                  "permission_label" : "Service Administrator",
-                  "permission_name" : "SERVICE.ADMINISTRATOR",
-                  "principal_name" : "mygroup",
-                  "principal_type" : "GROUP",
-                  "privilege_id" : 111,
-                  "type" : "CLUSTER",
-                  "user_name" : "user1"
-                }
-              }, {
-                "href" : "http://abc.com:8080/api/v1/users/user1/privileges/11",
-                "PrivilegeInfo" : {
-                  "cluster_name" : "myCluster",
-                  "permission_label" : "Cluster Administrator",
-                  "permission_name" : "CLUSTER.ADMINISTRATOR",
-                  "principal_name" : "user1",
-                  "principal_type" : "USER",
-                  "privilege_id" : 11,
-                  "type" : "CLUSTER",
-                  "user_name" : "user1"
-                }
-              }
-            ]
-          };
-
-        items2 =
-          {
-            "href" : "http://abc.com:8080/api/v1/users/user2",
-            "Users" : { "user_name" : "user2" },
-            "privileges" : [
-              {
-                "href" : "http://abc.com:8080/api/v1/users/user2/privileges/111",
-                "PrivilegeInfo" : {
-                  "cluster_name" : "myCluster",
-                  "permission_label" : "Service Administrator",
-                  "permission_name" : "SERVICE.ADMINISTRATOR",
-                  "principal_name" : "mygroup",
-                  "principal_type" : "GROUP",
-                  "privilege_id" : 111,
-                  "type" : "CLUSTER",
-                  "user_name" : "user2"
-                }
-              }, {
-                "href" : "http://abc.com:8080/api/v1/users/user2/privileges/22",
-                "PrivilegeInfo" : {
-                  "cluster_name" : "myCluster",
-                  "permission_label" : "Service Administrator",
-                  "permission_name" : "SERVICE.ADMINISTRATOR",
-                  "principal_name" : "user2",
-                  "principal_type" : "USER",
-                  "privilege_id" : 22,
-                  "type" : "CLUSTER",
-                  "user_name" : "user2"
-                }
-              }
-            ]
-          };
-
-        all_items = { "items": [items1, items2]};
-
-        scope.loadUsers();
-
-        spyOn(Cluster, 'deleteMultiplePrivileges').andCallFake(function(clusterId, privilege_ids) {
-          privilege_ids.forEach(function(privilege_id) {
-            items1.privileges.forEach(function(p, index) {
-              if (p.PrivilegeInfo.privilege_id === privilege_id) {
-                //Remove from array
-                items1.privileges.splice(index, 1);
-              }
-            });
-          });
-        });
-        spyOn(scope, 'addPrivilege').andCallFake(function(user) {
-          var p = {};
-          p.PrivilegeInfo = {};
-          p.PrivilegeInfo.privilege_id = user.privilege_id + 1;
-          p.PrivilegeInfo.permission_name = user.permission_name;
-          p.PrivilegeInfo.principal_type = 'USER';
-
-          items1.privileges.push(p);
-          scope.loadUsers();
-        });
-
-        deferred.getPrivilegesWithFilters.resolve(all_items);
-        deferred.getPrivilegesForResource.promise.then(function(data) {
-          var arrayOfPrivileges = data.items[0].privileges;
-          var privilegesOfTypeUser = [];
-          var privilegesOfTypeGroup = [];
-          for (var i = 0; i < arrayOfPrivileges.length; i++) {
-            if(arrayOfPrivileges[i].PrivilegeInfo.principal_type === "GROUP"){
-              privilegesOfTypeGroup.push(arrayOfPrivileges[i]);
-            } else {
-              privilegesOfTypeUser.push(arrayOfPrivileges[i].PrivilegeInfo);
-            }
-          }
-
-          var effectivePrivilege = scope.pickEffectivePrivilege(arrayOfPrivileges);
-          var effectivePrivilegeFromGroups = scope.pickEffectivePrivilege(privilegesOfTypeGroup);
-          user.principal_type = 'USER';
-          user.original_perm = effectivePrivilege.permission_name;
-          user.editable = (Cluster.ineditableRoles.indexOf(effectivePrivilege.permission_name) === -1);
-
-          //add a new privilege of type USER only if it is also the effective privilege considering the user's Group privileges
-          var curIndex = scope.getRoleRank(user.permission_name);
-          var prevIndex = -1;
-          if (privilegesOfTypeGroup.length !== 0) {
-            prevIndex = scope.getRoleRank(effectivePrivilegeFromGroups.permission_name);
-          }
-          if ((curIndex === 6) || (curIndex <= prevIndex)) {
-            var privilege_ids = [];
-            privilegesOfTypeUser.forEach(function(privilegeOfTypeUser) {
-              privilege_ids.push(privilegeOfTypeUser.privilege_id);
-            });
-
-            //delete all privileges of type USER, if they exist
-            //then add the privilege for the user, after which the user displays the effective privilege
-            if(privilege_ids.length !== 0) {
-              Cluster.deleteMultiplePrivileges(
-                123,
-                privilege_ids
-              );
-            }
-            scope.addPrivilege(user);
-          } else {
-            Alert.error($t('common.alerts.cannotSavePermissions'), "User's effective privilege through its Group(s) is higher than your selected privilege.");
-            scope.loadUsers();
-          }
-        });
-
-        scope.$apply();
-      });
-
-      it('Should save the Privilege equal to the user\'s group privileges. Should also remove any individual user privileges', function() {
-        //using 'user1' for updating the new privilege
-        user.principal_name = scope.users[0].principal_name;
-        user.principal_type = scope.users[0].principal_type;
-        user.privilege_id = scope.users[0].privilege_id;
-        user.permission_name = "SERVICE.ADMINISTRATOR";
-
-        deferred.getPrivilegesForResource.resolve({ "items" : [items1] });
-
-        scope.$apply();
-
-        expect(scope.users[0].permission_name).toEqual(user.permission_name);
-        expect(scope.users[0].privilege_id).toEqual(user.privilege_id + 1);
-
-        var oldPrivilege = {
-          "href" : "http://abc.com:8080/api/v1/users/user1/privileges/11",
-          "PrivilegeInfo" : {
-            "cluster_name" : "myCluster",
-            "permission_label" : "Cluster Administrator",
-            "permission_name" : "CLUSTER.ADMINISTRATOR",
-            "principal_name" : "user1",
-            "principal_type" : "USER",
-            "privilege_id" : 11,
-            "type" : "CLUSTER",
-            "user_name" : "user1"
-          }
-        };
-        var newPrivilege = {
-          "PrivilegeInfo" : {
-            "permission_name" : user.permission_name,
-            "privilege_id" : user.privilege_id+1,
-            "principal_type" : "USER",
-            "principal_name" : "user1",
-            "encoded_name" : "user1",
-            "original_perm" : user.permission_name,
-            "url" : "users/user1",
-            "editable" : true
-          }
-        };
-
-        //test if the individual user privilege CLUSTER.ADMINISTRATOR is removed from 'items1' by deletePrivilege()
-        expect(items1.privileges).toNotContain(oldPrivilege);
-
-        //test if the new privilege got added to 'items1' by addPrivilege()
-        expect(items1.privileges).toContain(newPrivilege);
-      });
-
-      it('Should save the Privilege greater than the user\'s group privileges. Should also remove any individual user privileges', function() {
-        //using 'user1' for updating the new privilege
-        user.principal_name = scope.users[0].principal_name;
-        user.principal_type = scope.users[0].principal_type;
-        user.privilege_id = scope.users[0].privilege_id;
-        user.permission_name = "CLUSTER.OPERATOR";
-
-        deferred.getPrivilegesForResource.resolve({ "items" : [items1] });
-        scope.$apply();
-
-        expect(scope.users[0].permission_name).toEqual(user.permission_name);
-        expect(scope.users[0].privilege_id).toEqual(user.privilege_id + 1);
-
-        var oldPrivilege = {
-          "href" : "http://abc.com:8080/api/v1/users/user1/privileges/11",
-          "PrivilegeInfo" : {
-            "cluster_name" : "myCluster",
-            "permission_label" : "Cluster Administrator",
-            "permission_name" : "CLUSTER.ADMINISTRATOR",
-            "principal_name" : "user1",
-            "principal_type" : "USER",
-            "privilege_id" : 11,
-            "type" : "CLUSTER",
-            "user_name" : "user1"
-          }
-        };
-        var newPrivilege = {
-          "PrivilegeInfo" : {
-            "permission_name" : user.permission_name,
-            "principal_name" : "user1",
-            "principal_type" : "USER",
-            "privilege_id" : user.privilege_id + 1,
-            "encoded_name" : "user1",
-            "original_perm" : user.permission_name,
-            "url" : "users/user1",
-            "editable" : true
-          }
-        };
-
-        //test if the individual user privilege CLUSTER.ADMINISTRATOR is removed from 'items1' by deletePrivilege()
-        expect(items1.privileges).toNotContain(oldPrivilege);
-
-        //test if the new privilege got added to 'items1' by addPrivilege()
-        expect(items1.privileges).toContain(newPrivilege);
-      });
-
-      it('Should NOT save the Privilege smaller than the user\'s group privileges. Should keep the user\'s original privileges intact', function() {
-        //using 'user1' for updating the new privilege
-        user.principal_name = scope.users[0].principal_name;
-        user.principal_type = scope.users[0].principal_type;
-        user.privilege_id = scope.users[0].privilege_id;
-        user.permission_name = "CLUSTER.USER";
-
-        deferred.getPrivilegesForResource.resolve({ "items" : [items1] });
-        scope.$apply();
-
-        expect(scope.users[0].permission_name).toEqual(user.original_perm);
-        expect(scope.users[0].privilege_id).toEqual(user.privilege_id);
-
-        var oldPrivilege = {
-          "href" : "http://abc.com:8080/api/v1/users/user1/privileges/11",
-          "PrivilegeInfo" : {
-            "cluster_name" : "myCluster",
-            "permission_label" : "Cluster Administrator",
-            "permission_name" : "CLUSTER.ADMINISTRATOR",
-            "principal_name" : "user1",
-            "principal_type" : "USER",
-            "privilege_id" : 11,
-            "type" : "CLUSTER",
-            "user_name" : "user1",
-            "encoded_name" : "user1",
-            "original_perm" : "CLUSTER.ADMINISTRATOR",
-            "url" : "users/user1",
-            "editable" : true
-          }
-        };
-        var newPrivilege = {
-          "PrivilegeInfo" : {
-            "permission_name" : user.permission_name,
-            "principal_name" : "user1",
-            "principal_type" : "USER",
-            "privilege_id" : user.privilege_id+1,
-            "encoded_name" : "user1",
-            "original_perm" : user.permission_name,
-            "url" : "users/user1",
-            "editable" : true
-          }
-        };
-
-        //test if the individual user privilege CLUSTER.ADMINISTRATOR is NOT removed from 'items1'
-        expect(items1.privileges).toContain(oldPrivilege);
-
-        //test if the new privilege is NOT added to 'items1'
-        expect(items1.privileges).toNotContain(newPrivilege);
-      });
-
-    });
-
-    describe('#save() for Groups', function() {
-      var user = {};
-
-      beforeEach(function() {
-        items1 = {
-          "href" : "http://abc.com:8080/api/v1/groups/mygroup",
-          "Groups" : { "group_name" : "mygroup" },
-          "privileges" : [
-            {
-              "href" : "http://abc.com:8080/api/v1/groups/mygroup/privileges/3359",
-              "PrivilegeInfo" : {
-                "cluster_name" : "myCluster",
-                "group_name" : "mygroup",
-                "permission_label" : "Service Administrator",
-                "permission_name" : "SERVICE.ADMINISTRATOR",
-                "principal_name" : "mygroup",
-                "principal_type" : "GROUP",
-                "privilege_id" : 3359,
-                "type" : "CLUSTER"
-              }
-            }
-          ]
-        };
-
-        items2 = {
-          "href" : "http://abc.com:8080/api/v1/groups/mygroup2",
-          "Groups" : { "group_name" : "mygroup2" },
-          "privileges" : [
-            {
-              "href" : "http://abc.com:8080/api/v1/groups/mygroup2/privileges/3356",
-              "PrivilegeInfo" : {
-                "cluster_name" : "myCluster",
-                "group_name" : "mygroup2",
-                "permission_label" : "Service Administrator",
-                "permission_name" : "SERVICE.ADMINISTRATOR",
-                "principal_name" : "mygroup2",
-                "principal_type" : "GROUP",
-                "privilege_id" : 3356,
-                "type" : "CLUSTER"
-              }
-            }
-          ]
-        };
-
-        all_items = { "items": [items1, items2]};
-
-        scope.loadUsers();
-
-        spyOn(Cluster, 'deleteMultiplePrivileges').andCallFake(function(clusterId, privilege_ids) {
-          privilege_ids.forEach(function(privilege_id) {
-            items1.privileges.forEach(function(p, index) {
-              if (p.PrivilegeInfo.privilege_id === privilege_id) {
-                //Remove from array
-                items1.privileges.splice(index, 1);
-              }
-            });
-          });
-        });
-        spyOn(scope, 'addPrivilege').andCallFake(function(user) {
-          var p = {};
-          p.PrivilegeInfo = {};
-          p.PrivilegeInfo.privilege_id = user.privilege_id + 1;
-          p.PrivilegeInfo.permission_name = user.permission_name;
-          p.PrivilegeInfo.principal_type = 'GROUP';
-
-          items1.privileges.push(p);
-          scope.loadUsers();
-        });
-
-        deferred.getPrivilegesWithFilters.resolve(all_items);
-        deferred.getPrivilegesForResource.promise.then(function(data) {
-          var arrayOfPrivileges = data.items[0].privileges;
-          var privilegesOfTypeGroup = [];
-          var privilege = scope.pickEffectivePrivilege(arrayOfPrivileges);
-          user.principal_type = 'GROUP';
-          user.original_perm = privilege.permission_name;
-          user.editable = (Cluster.ineditableRoles.indexOf(privilege.permission_name) === -1);
-
-          arrayOfPrivileges.forEach(function(privilegeOfTypeGroup){
-            if (privilegeOfTypeGroup.PrivilegeInfo.principal_type === "GROUP") {
-              privilegesOfTypeGroup.push(privilegeOfTypeGroup.PrivilegeInfo);
-            }
-          });
-
-          var privilege_ids = [];
-          privilegesOfTypeGroup.forEach(function(privilegeOfTypeGroup) {
-            privilege_ids.push(privilegeOfTypeGroup.privilege_id);
-          });
-
-          //delete all privileges of type GROUP, if they exist
-          //then add the privilege for the group, after which the group displays the effective privilege
-          if(privilege_ids.length !== 0) {
-            Cluster.deleteMultiplePrivileges(
-                123,
-                privilege_ids
-            );
-          }
-          scope.addPrivilege(user);
-        });
-
-        scope.$apply();
-      });
-
-      it('Should save the Privilege equal to the group\'s effective privilege. Should remove any other privileges of the group',function(){
-        //using 'mygroup' for updating the new privilege
-        user.principal_name = scope.users[0].principal_name;
-        user.principal_type = scope.users[0].principal_type;
-        user.privilege_id = scope.users[0].privilege_id;
-        user.permission_name = "SERVICE.ADMINISTRATOR";
-
-        deferred.getPrivilegesForResource.resolve({ "items" : [items1] });
-
-        scope.$apply();
-
-        expect(scope.users[0].permission_name).toEqual(user.permission_name);
-        expect(scope.users[0].privilege_id).toEqual(user.privilege_id + 1);
-
-        var oldPrivilege = {
-          "PrivilegeInfo" : {
-            "cluster_name" : "myCluster",
-            "group_name" : "mygroup",
-            "permission_label" : "Service Administrator",
-            "permission_name" : "SERVICE.ADMINISTRATOR",
-            "principal_name" : "mygroup",
-            "principal_type" : "GROUP",
-            "privilege_id" : 3359,
-            "type" : "CLUSTER"
-          }
-        };
-        var newPrivilege = {
-          "PrivilegeInfo" : {
-            "privilege_id" : user.privilege_id + 1,
-            "permission_name" : user.permission_name,
-            "principal_type" : "GROUP",
-            "principal_name" : "mygroup",
-            "encoded_name" : "mygroup",
-            "original_perm" : user.permission_name,
-            "url" : "groups/mygroup/edit",
-            "editable" : true
-          }
-        };
-
-        //test if the older privilege is no longer present in 'items1'
-        expect(items1.privileges).toNotContain(oldPrivilege);
-
-        //test if the new privilege is added to 'items1'
-        expect(items1.privileges).toContain(newPrivilege);
-      });
-
-      it('Should save the Privilege greater than the group\'s effective privilege. Should remove any other privileges of the group',function(){
-        //using 'mygroup' for updating the new privilege
-        user.principal_name = scope.users[0].principal_name;
-        user.principal_type = scope.users[0].principal_type;
-        user.privilege_id = scope.users[0].privilege_id;
-        user.permission_name = "CLUSTER.ADMINISTRATOR";
-
-        deferred.getPrivilegesForResource.resolve({ "items" : [items1] });
-
-        scope.$apply();
-
-        expect(scope.users[0].permission_name).toEqual(user.permission_name);
-        expect(scope.users[0].privilege_id).toEqual(user.privilege_id + 1);
-
-        var oldPrivilege = {
-          "PrivilegeInfo" : {
-            "cluster_name" : "myCluster",
-            "group_name" : "mygroup",
-            "permission_label" : "Service Administrator",
-            "permission_name" : "SERVICE.ADMINISTRATOR",
-            "principal_name" : "mygroup",
-            "principal_type" : "GROUP",
-            "privilege_id" : 3359,
-            "type" : "CLUSTER"
-          }
-        };
-        var newPrivilege = {
-          "PrivilegeInfo" : {
-            "privilege_id" : user.privilege_id + 1,
-            "permission_name" : user.permission_name,
-            "principal_type" : "GROUP",
-            "principal_name" : "mygroup",
-            "encoded_name" : "mygroup",
-            "original_perm" : user.permission_name,
-            "url" : "groups/mygroup/edit",
-            "editable" : true
-          }
-        };
-
-        //test if the older privilege is no longer present in 'items1'
-        expect(items1.privileges).toNotContain(oldPrivilege);
-
-        //test if the new privilege is added to 'items1'
-        expect(items1.privileges).toContain(newPrivilege);
-      });
-
-      it('Should save the Privilege lesser than the group\'s effective privilege. Should remove any other privileges of the group', function() {
-        //using 'mygroup' for updating the new privilege
-        user.principal_name = scope.users[0].principal_name;
-        user.principal_type = scope.users[0].principal_type;
-        user.privilege_id = scope.users[0].privilege_id;
-        user.permission_name = "CLUSTER.USER";
-
-        deferred.getPrivilegesForResource.resolve({ "items" : [items1] });
-
-        scope.$apply();
-
-        expect(scope.users[0].permission_name).toEqual(user.permission_name);
-        expect(scope.users[0].privilege_id).toEqual(user.privilege_id + 1);
-
-        var oldPrivilege = {
-          "PrivilegeInfo" : {
-            "cluster_name" : "myCluster",
-            "group_name" : "mygroup",
-            "permission_label" : "Service Administrator",
-            "permission_name" : "SERVICE.ADMINISTRATOR",
-            "principal_name" : "mygroup",
-            "principal_type" : "GROUP",
-            "privilege_id" : 3359,
-            "type" : "CLUSTER"
-          }
-        };
-        var newPrivilege = {
-          "PrivilegeInfo" : {
-            "privilege_id" : user.privilege_id + 1,
-            "permission_name" : user.permission_name,
-            "principal_type" : "GROUP",
-            "principal_name" : "mygroup",
-            "encoded_name" : "mygroup",
-            "original_perm" : user.permission_name,
-            "url" : "groups/mygroup/edit",
-            "editable" : true
-          }
-        };
-
-        //test if the older privilege is no longer present in 'items1'
-        expect(items1.privileges).toNotContain(oldPrivilege);
-
-        //test if the new privilege is added to 'items1'
-        expect(items1.privileges).toContain(newPrivilege);
-      });
-
-    });
-
-    describe('#pickEffectivePrivilege()', function() {
-      var cases = [{
-          "test" : [{
-            "href" : "http://abc.com:8080/api/v1/groups/mygroup1",
-            "PrivilegeInfo" : {
-              "instance_name" : "jobs_view",
-              "permission_label" : "View User",
-              "permission_name" : "VIEW.USER",
-              "principal_name" : "mygroup1",
-              "principal_type" : "GROUP",
-              "privilege_id" : 111,
-              "type" : "VIEW",
-              "user_name" : "mygroup1",
-              "view_name" : "JOBS"
-            }
-          }],
-          "result":{
-            "permission_name": "CLUSTER.NONE"
-          }
-        }, {
-          "test": [{
-            "href" : "http://abc.com:8080/api/v1/groups/mygroup2",
-            "PrivilegeInfo" : {
-              "cluster_name":"mycluster",
-              "permission_label" : "Cluster User",
-              "permission_name" : "CLUSTER.USER",
-              "principal_name" : "mygroup2",
-              "principal_type" : "GROUP",
-              "privilege_id" : 222,
-              "type" : "CLUSTER",
-              "user_name":"mygroup2"
-            }
-          }],
-          "result":{
-            "permission_name": "CLUSTER.USER"
-          }
-        }, {
-          "test":[{
-            "href" : "http://abc.com:8080/api/v1/groups/mygroup3",
-            "PrivilegeInfo" : {
-              "cluster_name":"mycluster",
-              "permission_label" : "Cluster User",
-              "permission_name" : "CLUSTER.USER",
-              "principal_name" : "mygroup3",
-              "principal_type" : "GROUP",
-              "privilege_id" : 333,
-              "type" : "CLUSTER",
-              "user_name":"mygroup3"
-            }
-          }, {
-            "href" : "http://abc.com:8080/api/v1/groups/mygroup3",
-            "PrivilegeInfo" : {
-              "instance_name": "jobs_view",
-              "permission_label" : "View User",
-              "permission_name" : "VIEW.USER",
-              "principal_name" : "mygroup3",
-              "principal_type" : "GROUP",
-              "privilege_id" : 3333,
-              "type" : "VIEW",
-              "user_name":"mygroup3",
-              "view_name":"JOBS"
-            }
-          }],
-          "result":{
-            "permission_name": "CLUSTER.USER"
-          }
-        }, {
-          "test": [{
-            "href" : "http://abc.com:8080/api/v1/users/myuser1/privileges/11",
-            "PrivilegeInfo" : {
-              "instance_name": "jobs_view",
-              "permission_label" : "View User",
-              "permission_name" : "VIEW.USER",
-              "principal_name" : "myuser1",
-              "principal_type" : "USER",
-              "privilege_id" : 11,
-              "type" : "VIEW",
-              "user_name":"myuser1",
-              "view_name":"JOBS"
-            }
-          }],
-          "result":{
-            "permission_name": "CLUSTER.NONE"
-          }
-        }, {
-          "test":[{
-            "href" : "http://abc.com:8080/api/v1/users/myuser2/privileges/22",
-            "PrivilegeInfo" : {
-              "cluster_name":"mycluster",
-              "permission_label" : "Cluster Administrator",
-              "permission_name" : "CLUSTER.ADMINISTRATOR",
-              "principal_name" : "myuser2",
-              "principal_type" : "USER",
-              "privilege_id" : 22,
-              "type" : "CLUSTER",
-              "user_name":"myuser2"
-            }
-          }],
-          "result":{
-            "permission_name": "CLUSTER.ADMINISTRATOR"
-          }
-        }
-      ];
-
-      it('User/Group with only View User permission must show \'None\' as the Cluster Permission, otherwise show the effective privilege', function(){
-        var effectivePrivilege;
-        cases.forEach(function (item){
-          effectivePrivilege = scope.pickEffectivePrivilege(item.test);
-          scope.$apply();
-          expect(effectivePrivilege.permission_name).toEqual(item.result.permission_name);
-        });
-      });
-    });
-
-  });
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/groups/GroupsListCtrl_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/groups/GroupsListCtrl_test.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/groups/GroupsListCtrl_test.js
deleted file mode 100644
index 8ed228b..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/groups/GroupsListCtrl_test.js
+++ /dev/null
@@ -1,129 +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.
- */
-
-describe('#Cluster', function () {
-
-  describe('GroupsListCtrl', function() {
-
-    var scope, ctrl, $t, $httpBackend;
-
-    beforeEach(module('ambariAdminConsole', function () {}));
-
-    beforeEach(inject(function($rootScope, $controller, _$translate_, _$httpBackend_) {
-      scope = $rootScope.$new();
-      $t = _$translate_.instant;
-      $httpBackend = _$httpBackend_;
-      ctrl = $controller('GroupsListCtrl', {
-        $scope: scope
-      });
-    }));
-
-    describe('#clearFilters()', function () {
-
-      it('should clear filters and reset pagination', function () {
-        scope.currentPage = 2;
-        scope.currentNameFilter = 'a';
-        scope.currentTypeFilter = {
-          label: $t('common.local'),
-          value: false
-        };
-        scope.clearFilters();
-        expect(scope.currentNameFilter).toEqual('');
-        expect(scope.currentTypeFilter).toEqual({
-          label: $t('common.all'),
-          value: '*'
-        });
-        expect(scope.currentPage).toEqual(1);
-      });
-
-    });
-
-    describe('#isNotEmptyFilter', function () {
-
-      var cases = [
-        {
-          currentNameFilter: '',
-          currentTypeFilter: null,
-          isNotEmptyFilter: false,
-          title: 'no filters'
-        },
-        {
-          currentNameFilter: '',
-          currentTypeFilter: {
-            value: '*'
-          },
-          isNotEmptyFilter: false,
-          title: 'empty filters'
-        },
-        {
-          currentNameFilter: 'a',
-          currentTypeFilter: {
-            value: '*'
-          },
-          isNotEmptyFilter: true,
-          title: 'name filter'
-        },
-        {
-          currentNameFilter: '0',
-          currentTypeFilter: {
-            value: '*'
-          },
-          isNotEmptyFilter: true,
-          title: 'name filter with "0" as string'
-        },
-        {
-          currentNameFilter: '',
-          currentTypeFilter: {
-            value: false
-          },
-          isNotEmptyFilter: true,
-          title: 'type filter'
-        },
-        {
-          currentNameFilter: 'a',
-          currentTypeFilter: {
-            value: false
-          },
-          isNotEmptyFilter: true,
-          title: 'both filters'
-        },
-        {
-          currentNameFilter: '0',
-          currentTypeFilter: {
-            value: false
-          },
-          isNotEmptyFilter: true,
-          title: 'both filters with "0" as string'
-        }
-      ];
-
-      cases.forEach(function (item) {
-        it(item.title, function () {
-          $httpBackend.expectGET(/\/api\/v1\/groups/).respond(200);
-          scope.currentNameFilter = item.currentNameFilter;
-          scope.currentTypeFilter = item.currentTypeFilter;
-          scope.$digest();
-          expect(scope.isNotEmptyFilter).toEqual(item.isNotEmptyFilter);
-        });
-      });
-
-    });
-
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/userManagement/GroupsListCtrl_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/userManagement/GroupsListCtrl_test.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/userManagement/GroupsListCtrl_test.js
new file mode 100644
index 0000000..8d04757
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/userManagement/GroupsListCtrl_test.js
@@ -0,0 +1,129 @@
+/**
+ * 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.
+ */
+
+describe('#Cluster', function () {
+
+  describe('GroupsListCtrl', function() {
+
+    var scope, ctrl, $t, $httpBackend;
+
+    beforeEach(module('ambariAdminConsole', function () {}));
+
+    beforeEach(inject(function($rootScope, $controller, _$translate_, _$httpBackend_) {
+      scope = $rootScope.$new();
+      $t = _$translate_.instant;
+      $httpBackend = _$httpBackend_;
+      ctrl = $controller('GroupsListCtrl', {
+        $scope: scope
+      });
+    }));
+
+    describe('#clearFilters()', function () {
+
+      it('should clear filters and reset pagination', function () {
+        scope.currentPage = 2;
+        scope.filter.name = 'a';
+        scope.filter.type = {
+          label: $t('common.local'),
+          value: false
+        };
+        scope.clearFilters();
+        expect(scope.filter.name).toEqual('');
+        expect(scope.filter.type).toEqual({
+          label: $t('common.all'),
+          value: '*'
+        });
+        expect(scope.currentPage).toEqual(1);
+      });
+
+    });
+
+    describe('#isNotEmptyFilter', function () {
+
+      var cases = [
+        {
+          currentNameFilter: '',
+          currentTypeFilter: null,
+          isNotEmptyFilter: false,
+          title: 'no filters'
+        },
+        {
+          currentNameFilter: '',
+          currentTypeFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: false,
+          title: 'empty filters'
+        },
+        {
+          currentNameFilter: 'a',
+          currentTypeFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'name filter'
+        },
+        {
+          currentNameFilter: '0',
+          currentTypeFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'name filter with "0" as string'
+        },
+        {
+          currentNameFilter: '',
+          currentTypeFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'type filter'
+        },
+        {
+          currentNameFilter: 'a',
+          currentTypeFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'both filters'
+        },
+        {
+          currentNameFilter: '0',
+          currentTypeFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'both filters with "0" as string'
+        }
+      ];
+
+      cases.forEach(function (item) {
+        it(item.title, function () {
+          $httpBackend.expectGET(/\/api\/v1\/groups/).respond(200);
+          scope.filter.name = item.currentNameFilter;
+          scope.filter.type = item.currentTypeFilter;
+          scope.$digest();
+          expect(scope.isNotEmptyFilter).toEqual(item.isNotEmptyFilter);
+        });
+      });
+
+    });
+
+  });
+
+});


[21/49] ambari git commit: AMBARI-22467. YARN, MapReduce2, Hive, and Oozie Should Conditionally Install LZO (aonishuk)

Posted by rl...@apache.org.
AMBARI-22467. YARN, MapReduce2, Hive, and Oozie Should Conditionally Install LZO (aonishuk)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 5dd334c513435717a7264f2092f5b281f5d2ce8f
Parents: 9572882
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Wed Nov 22 16:36:51 2017 +0200
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Wed Nov 22 16:37:06 2017 +0200

----------------------------------------------------------------------
 .../common-services/DRUID/0.10.1/package/scripts/druid.py       | 3 +--
 .../common-services/DRUID/0.10.1/package/scripts/params.py      | 5 ++---
 2 files changed, 3 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5dd334c5/ambari-server/src/main/resources/common-services/DRUID/0.10.1/package/scripts/druid.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/DRUID/0.10.1/package/scripts/druid.py b/ambari-server/src/main/resources/common-services/DRUID/0.10.1/package/scripts/druid.py
index ec98c3c..bb872b9 100644
--- a/ambari-server/src/main/resources/common-services/DRUID/0.10.1/package/scripts/druid.py
+++ b/ambari-server/src/main/resources/common-services/DRUID/0.10.1/package/scripts/druid.py
@@ -115,8 +115,7 @@ def druid(upgrade_type=None, nodeType=None):
          )
     Logger.info(format("Created druid-{node_type_lowercase} jvm.config"))
     # Handling hadoop Lzo jars if enable and node type is hadoop related eg Overlords and MMs
-    if ['middleManager', 'overlord'].__contains__(node_type_lowercase) and params.lzo_enabled and len(
-            params.lzo_packages) > 0:
+    if ['middleManager', 'overlord'].__contains__(node_type_lowercase) and params.lzo_enabled:
         try:
             Logger.info(
                 format(

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dd334c5/ambari-server/src/main/resources/common-services/DRUID/0.10.1/package/scripts/params.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/DRUID/0.10.1/package/scripts/params.py b/ambari-server/src/main/resources/common-services/DRUID/0.10.1/package/scripts/params.py
index fd1cde6..519dfbf 100644
--- a/ambari-server/src/main/resources/common-services/DRUID/0.10.1/package/scripts/params.py
+++ b/ambari-server/src/main/resources/common-services/DRUID/0.10.1/package/scripts/params.py
@@ -18,7 +18,6 @@ limitations under the License.
 
 """
 from ambari_commons import OSCheck
-from resource_management.libraries.functions.get_lzo_packages import get_lzo_packages
 from resource_management.libraries.functions import conf_select
 from resource_management.libraries.functions import stack_select
 from resource_management.libraries.resources.hdfs_resource import HdfsResource
@@ -27,6 +26,7 @@ from resource_management.libraries.script.script import Script
 from resource_management.libraries.functions import format
 from resource_management.libraries.functions.get_not_managed_resources import get_not_managed_resources
 from resource_management.libraries.functions.default import default
+from resource_management.libraries.functions.lzo_utils import should_install_lzo
 from ambari_commons.constants import AMBARI_SUDO_BINARY
 
 import status_params
@@ -195,6 +195,5 @@ if has_metric_collector:
 # Create current Hadoop Clients  Libs
 stack_version_unformatted = str(config['hostLevelParams']['stack_version'])
 io_compression_codecs = default("/configurations/core-site/io.compression.codecs", None)
-lzo_enabled = io_compression_codecs is not None and "com.hadoop.compression.lzo" in io_compression_codecs.lower()
-lzo_packages = get_lzo_packages(stack_version_unformatted)
+lzo_enabled = should_install_lzo()
 hadoop_lib_home = stack_root + '/' + stack_version + '/hadoop/lib'


[15/49] ambari git commit: AMBARI-22454. ambari-server upgrade to 2.6.1 should surface the GPL agreement (aonishuk)

Posted by rl...@apache.org.
AMBARI-22454. ambari-server upgrade to 2.6.1 should surface the GPL agreement (aonishuk)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 930c7d5004cb03e28de4cd24b15c2aaabb66b1ce
Parents: f331f86
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Wed Nov 22 13:15:29 2017 +0200
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Wed Nov 22 13:15:29 2017 +0200

----------------------------------------------------------------------
 .../server/upgrade/AbstractUpgradeCatalog.java  |   8 ++
 .../server/upgrade/SchemaUpgradeHelper.java     |  27 +++++
 .../ambari/server/upgrade/UpgradeCatalog.java   |   7 ++
 .../server/upgrade/UpgradeCatalog261.java       | 118 +++++++++++++++++++
 .../main/python/ambari_server/serverSetup.py    |  20 +---
 .../main/python/ambari_server/serverUpgrade.py  |  18 ++-
 .../src/test/python/TestAmbariServer.py         |   2 +-
 7 files changed, 181 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/930c7d50/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
index a2e2f6f..2ef0591 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
@@ -143,6 +143,7 @@ public abstract class AbstractUpgradeCatalog implements UpgradeCatalog {
     new HashMap<>();
 
   protected String ambariUpgradeConfigUpdatesFileName;
+  private Map<String,String> upgradeJsonOutput = new HashMap<>();
 
   @Inject
   public AbstractUpgradeCatalog(Injector injector) {
@@ -261,6 +262,13 @@ public abstract class AbstractUpgradeCatalog implements UpgradeCatalog {
   }
 
   /**
+   * {@inheritDoc}
+   */
+  public Map<String,String> getUpgradeJsonOutput() {
+    return upgradeJsonOutput;
+  }
+
+  /**
    * Update metainfo to new version.
    */
   @Transactional

http://git-wip-us.apache.org/repos/asf/ambari/blob/930c7d50/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
index 9c77129..2d0e4ce 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
@@ -29,7 +29,11 @@ import java.util.Date;
 import java.util.List;
 import java.util.Properties;
 import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
 
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.audit.AuditLoggerModule;
 import org.apache.ambari.server.configuration.Configuration;
@@ -57,6 +61,7 @@ public class SchemaUpgradeHelper {
   private DBAccessor dbAccessor;
   private Configuration configuration;
   private static final String[] rcaTableNames = {"workflow", "job", "task", "taskAttempt", "hdfsEvent", "mapreduceEvent", "clusterEvent"};
+  static final Gson gson = new GsonBuilder().create();
 
   @Inject
   public SchemaUpgradeHelper(Set<UpgradeCatalog> allUpgradeCatalogs,
@@ -180,6 +185,7 @@ public class SchemaUpgradeHelper {
       catalogBinder.addBinding().to(UpgradeCatalog251.class);
       catalogBinder.addBinding().to(UpgradeCatalog252.class);
       catalogBinder.addBinding().to(UpgradeCatalog260.class);
+      catalogBinder.addBinding().to(UpgradeCatalog261.class);
       catalogBinder.addBinding().to(UpgradeCatalog300.class);
       catalogBinder.addBinding().to(FinalUpgradeCatalog.class);
 
@@ -250,6 +256,26 @@ public class SchemaUpgradeHelper {
     }
   }
 
+  public void outputUpgradeJsonOutput(List<UpgradeCatalog> upgradeCatalogs)
+      throws AmbariException {
+    LOG.info("Combining upgrade json output.");
+    Map<String,String> combinedUpgradeJsonOutput = new HashMap<>();
+
+    if (upgradeCatalogs != null && !upgradeCatalogs.isEmpty()) {
+      for (UpgradeCatalog upgradeCatalog : upgradeCatalogs) {
+        try {
+          combinedUpgradeJsonOutput.putAll(upgradeCatalog.getUpgradeJsonOutput());
+
+        } catch (Exception e) {
+          LOG.error("Upgrade failed. ", e);
+          throw new AmbariException(e.getMessage(), e);
+        }
+      }
+    }
+    String content = gson.toJson(combinedUpgradeJsonOutput);
+    System.out.println(content);
+  }
+
   public void resetUIState() throws AmbariException {
     LOG.info("Resetting UI state.");
     try {
@@ -420,6 +446,7 @@ public class SchemaUpgradeHelper {
       schemaUpgradeHelper.executeDMLUpdates(upgradeCatalogs, ambariUpgradeConfigUpdatesFileName);
 
       schemaUpgradeHelper.executeOnPostUpgrade(upgradeCatalogs);
+      schemaUpgradeHelper.outputUpgradeJsonOutput(upgradeCatalogs);
 
       schemaUpgradeHelper.resetUIState();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/930c7d50/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog.java
index 21273fd..a005951 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog.java
@@ -18,6 +18,8 @@
 package org.apache.ambari.server.upgrade;
 
 import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.ambari.server.AmbariException;
 
@@ -88,4 +90,9 @@ public interface UpgradeCatalog {
    * Update schema version in the database to the Target one
    */
   void updateDatabaseSchemaVersion();
+
+  /*
+  Get upgrade json output, which is sent to python executing process.
+   */
+  Map<String,String> getUpgradeJsonOutput();
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/930c7d50/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog261.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog261.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog261.java
new file mode 100644
index 0000000..7f463aa
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog261.java
@@ -0,0 +1,118 @@
+/**
+ * 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.
+ */
+package org.apache.ambari.server.upgrade;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.SQLException;
+import java.util.Map;
+
+/**
+ * The {@link UpgradeCatalog261} upgrades Ambari from 2.6.0 to 2.6.1.
+ */
+public class UpgradeCatalog261 extends AbstractUpgradeCatalog {
+  private static final String CORE_SITE = "core-site";
+  private static final String COMPRESSION_CODECS_PROPERTY = "io.compression.codecs";
+  private static final String COMPRESSION_CODECS_LZO = "com.hadoop.compression.lzo";
+  private static final String LZO_ENABLED_JSON_KEY = "lzo_enabled";
+
+  private static final Logger LOG = LoggerFactory.getLogger(UpgradeCatalog261.class);
+
+  /**
+   * Constructor.
+   *
+   * @param injector
+   */
+  @Inject
+  public UpgradeCatalog261(Injector injector) {
+    super(injector);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getSourceVersion() {
+      return "2.6.0";
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getTargetVersion() {
+      return "2.6.1";
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected void executeDDLUpdates() throws AmbariException, SQLException {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected void executePreDMLUpdates() throws AmbariException, SQLException {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected void executeDMLUpdates() throws AmbariException, SQLException {
+    // TODO: make this map with clusterids as keys
+    this.getUpgradeJsonOutput().put(LZO_ENABLED_JSON_KEY, isLzoEnabled().toString());
+  }
+
+  protected Boolean isLzoEnabled() throws AmbariException {
+    AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
+    Clusters clusters = ambariManagementController.getClusters();
+    if (clusters != null) {
+      Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
+      if (clusterMap != null && !clusterMap.isEmpty()) {
+        for (final Cluster cluster : clusterMap.values()) {
+
+          Config coreSite = cluster.getDesiredConfigByType(CORE_SITE);
+          if (coreSite != null) {
+            Map<String, String> coreSiteProperties = coreSite.getProperties();
+
+            if (coreSiteProperties.containsKey(COMPRESSION_CODECS_PROPERTY)) {
+              String compressionCodecs = coreSiteProperties.get(COMPRESSION_CODECS_PROPERTY);
+
+              if(compressionCodecs.contains(COMPRESSION_CODECS_LZO)) {
+                return true;
+              }
+            }
+          }
+        }
+      }
+    }
+    return false;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/930c7d50/ambari-server/src/main/python/ambari_server/serverSetup.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/serverSetup.py b/ambari-server/src/main/python/ambari_server/serverSetup.py
index 7063175..ad6dc4f 100644
--- a/ambari-server/src/main/python/ambari_server/serverSetup.py
+++ b/ambari-server/src/main/python/ambari_server/serverSetup.py
@@ -38,7 +38,7 @@ from ambari_commons.str_utils import compress_backslashes
 from ambari_server.dbConfiguration import DBMSConfigFactory, TAR_GZ_ARCHIVE_TYPE, default_connectors_map, check_jdbc_drivers
 from ambari_server.serverConfiguration import configDefaults, JDKRelease, \
   get_ambari_properties, get_is_secure, get_is_persisted, get_java_exe_path, get_JAVA_HOME, get_missing_properties, \
-  get_resources_location, get_value_from_properties, read_ambari_user, update_properties, validate_jdk, write_property, prompt_gpl_agreement,\
+  get_resources_location, get_value_from_properties, read_ambari_user, update_properties, validate_jdk, write_property, write_gpl_license_accepted,\
   JAVA_HOME, JAVA_HOME_PROPERTY, JCE_NAME_PROPERTY, JDBC_RCA_URL_PROPERTY, JDBC_URL_PROPERTY, \
   JDK_NAME_PROPERTY, JDK_RELEASES, NR_USER_PROPERTY, OS_FAMILY, OS_FAMILY_PROPERTY, OS_TYPE, OS_TYPE_PROPERTY, OS_VERSION, \
   VIEWS_DIR_PROPERTY, JDBC_DATABASE_PROPERTY, JDK_DOWNLOAD_SUPPORTED_PROPERTY, JCE_DOWNLOAD_SUPPORTED_PROPERTY, SETUP_DONE_PROPERTIES, \
@@ -1135,20 +1135,6 @@ def check_setup_already_done():
 
   return not bool(get_missing_properties(properties, property_set=SETUP_DONE_PROPERTIES))
 
-def write_gpl_license_accepted(options):
-  properties = get_ambari_properties()
-  if properties == -1:
-    err = "Error getting ambari properties"
-    raise FatalException(-1, err)
-
-  if get_silent():
-    result = str(options.accept_gpl).lower()
-  else:
-    result = prompt_gpl_agreement()
-
-  properties.process_pair(GPL_LICENSE_ACCEPTED_PROPERTY, result)
-  update_properties(properties)
-
 #
 # Setup the Ambari Server.
 #
@@ -1196,8 +1182,8 @@ def setup(options):
     err = 'Downloading or installing JDK failed: {0}. Exiting.'.format(e)
     raise FatalException(e.code, err)
 
-  print 'Prompting GPL software agreement...'
-  write_gpl_license_accepted(options)
+  print 'Checking GPL software agreement...'
+  write_gpl_license_accepted(is_silent=get_silent())
 
   print 'Completing setup...'
   retcode = configure_os_settings()

http://git-wip-us.apache.org/repos/asf/ambari/blob/930c7d50/ambari-server/src/main/python/ambari_server/serverUpgrade.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/serverUpgrade.py b/ambari-server/src/main/python/ambari_server/serverUpgrade.py
index b0e0128..57a1ae0 100644
--- a/ambari-server/src/main/python/ambari_server/serverUpgrade.py
+++ b/ambari-server/src/main/python/ambari_server/serverUpgrade.py
@@ -28,6 +28,7 @@ import re
 import glob
 import optparse
 import logging
+import ambari_simplejson as json
 
 from ambari_commons.exceptions import FatalException
 from ambari_commons.logging_utils import print_info_msg, print_warning_msg, print_error_msg, get_verbose
@@ -41,7 +42,7 @@ from ambari_server.serverConfiguration import configDefaults, get_resources_loca
   update_database_name_property, get_admin_views_dir, get_views_dir, get_views_jars, \
   AMBARI_PROPERTIES_FILE, IS_LDAP_CONFIGURED, LDAP_PRIMARY_URL_PROPERTY, RESOURCES_DIR_PROPERTY, \
   SETUP_OR_UPGRADE_MSG, update_krb_jaas_login_properties, AMBARI_KRB_JAAS_LOGIN_FILE, get_db_type, update_ambari_env, \
-  AMBARI_ENV_FILE, JDBC_DATABASE_PROPERTY, get_default_views_dir
+  AMBARI_ENV_FILE, JDBC_DATABASE_PROPERTY, get_default_views_dir, write_gpl_license_accepted
 from ambari_server.setupSecurity import adjust_directory_permissions, \
   generate_env, ensure_can_start_under_current_user
 from ambari_server.utils import compare_versions
@@ -73,6 +74,11 @@ SCHEMA_UPGRADE_DEBUG = False
 
 SUSPEND_START_MODE = False
 
+INSALLED_LZO_WITHOUT_GPL_TEXT = "By saying no, Ambari will not automatically install LZO on any  new host in the cluster." + \
+"It is up to you to ensure LZO is installed and configured appropriately." + \
+"Without LZO being installed and configured data compressed with LZO will not be readable. " + \
+"Are you sure you want to proceed? [y/n] (n)?"
+
 def load_stack_values(version, filename):
   import xml.etree.ElementTree as ET
   values = {}
@@ -146,6 +152,10 @@ def run_schema_upgrade(args):
   environ = generate_env(args, ambari_user, current_user)
 
   (retcode, stdout, stderr) = run_os_command(command, env=environ)
+  upgrade_response = json.loads(stdout)
+
+  check_gpl_license_approved(upgrade_response)
+
   print_info_msg("Return code from schema upgrade command, retcode = {0}".format(str(retcode)), True)
   if stdout:
     print_info_msg("Console output from schema upgrade command:", True)
@@ -161,6 +171,12 @@ def run_schema_upgrade(args):
     print_info_msg('Schema upgrade completed', True)
   return retcode
 
+def check_gpl_license_approved(upgrade_response):
+  if 'lzo_enabled' not in upgrade_response or upgrade_response['lzo_enabled'].lower() != "true":
+    return
+
+  while not write_gpl_license_accepted() and not get_YN_input(INSALLED_LZO_WITHOUT_GPL_TEXT, False):
+    pass
 
 #
 # Upgrades the Ambari Server.

http://git-wip-us.apache.org/repos/asf/ambari/blob/930c7d50/ambari-server/src/test/python/TestAmbariServer.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/TestAmbariServer.py b/ambari-server/src/test/python/TestAmbariServer.py
index f71e0f3..ad4e371 100644
--- a/ambari-server/src/test/python/TestAmbariServer.py
+++ b/ambari-server/src/test/python/TestAmbariServer.py
@@ -4972,7 +4972,7 @@ class TestAmbariServer(TestCase):
                               ensure_can_start_under_current_user_mock, get_jdbc_mock,
                               ensure_jdbc_driver_is_installed_mock):
     java_exe_path_mock.return_value = "/usr/lib/java/bin/java"
-    run_os_command_mock.return_value = (0, None, None)
+    run_os_command_mock.return_value = (0, '{"lzo_enabled":"false"}', None)
     get_conf_dir_mock.return_value = '/etc/conf'
     command = '/usr/lib/java/bin/java -cp /etc/conf' + os.pathsep + 'test' + os.pathsep + 'path12' + \
               os.pathsep +'/path/to/jdbc.jar ' \


[33/49] ambari git commit: AMBARI-22467. YARN, MapReduce2, Hive, and Oozie Should Conditionally Install LZO (aonishuk)

Posted by rl...@apache.org.
AMBARI-22467. YARN, MapReduce2, Hive, and Oozie Should Conditionally Install LZO (aonishuk)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 20dee7f817d412088e1ba41a341a9fb5bbf33080
Parents: 6b17d01
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Thu Nov 23 10:38:35 2017 +0200
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Thu Nov 23 10:38:35 2017 +0200

----------------------------------------------------------------------
 .../common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py        | 1 -
 .../common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py        | 1 -
 2 files changed, 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/20dee7f8/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py b/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
index e9d48c0..29813d3 100644
--- a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
+++ b/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
@@ -193,7 +193,6 @@ def oozie(is_server=False, upgrade_type=None):
   if params.lzo_enabled:
     install_lzo_if_needed()
     Execute(format('{sudo} cp {hadoop_lib_home}/hadoop-lzo*.jar {oozie_lib_dir}'),
-      not_if  = no_op_test,
     )
   
   if is_server:

http://git-wip-us.apache.org/repos/asf/ambari/blob/20dee7f8/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py b/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py
index 1db16a9..96f1f1a 100644
--- a/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py
+++ b/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py
@@ -193,7 +193,6 @@ def oozie(is_server=False):
   if params.lzo_enabled:
     install_lzo_if_needed()
     Execute(format('{sudo} cp {hadoop_lib_home}/hadoop-lzo*.jar {oozie_lib_dir}'),
-      not_if  = no_op_test,
     )
   
   if is_server:      


[27/49] ambari git commit: AMBARI-22486 - Conditionally Rebuild MapReduce and Tez Tarballs with LZO if Enabled (jonathanhurley)

Posted by rl...@apache.org.
AMBARI-22486 - Conditionally Rebuild MapReduce and Tez Tarballs with LZO if Enabled (jonathanhurley)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 2c46bb3ea9b7868ddc087acc320e624cfa601436
Parents: 9d3eeaa
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Nov 20 14:23:20 2017 -0500
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Wed Nov 22 14:31:38 2017 -0500

----------------------------------------------------------------------
 .../libraries/functions/copy_tarball.py         | 99 +++++++++++++++++++-
 .../TEZ/0.4.0.2.1/package/scripts/tez.py        |  5 +-
 .../TEZ/0.9.0.3.0/configuration/tez-site.xml    |  4 +-
 .../TEZ/0.9.0.3.0/package/scripts/tez.py        |  4 +
 .../configuration-mapred/mapred-site.xml        |  2 +-
 .../configuration-mapred/mapred-site.xml        |  2 +-
 .../2.2/services/TEZ/configuration/tez-site.xml |  4 +-
 .../YARN/configuration-mapred/mapred-site.xml   |  2 +-
 .../stacks/HDP/2.6/upgrades/config-upgrade.xml  |  6 +-
 9 files changed, 113 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2c46bb3e/ambari-common/src/main/python/resource_management/libraries/functions/copy_tarball.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/copy_tarball.py b/ambari-common/src/main/python/resource_management/libraries/functions/copy_tarball.py
index dda1a18..c15fbd1 100644
--- a/ambari-common/src/main/python/resource_management/libraries/functions/copy_tarball.py
+++ b/ambari-common/src/main/python/resource_management/libraries/functions/copy_tarball.py
@@ -28,6 +28,8 @@ from contextlib import closing
 
 from resource_management.libraries.script.script import Script
 from resource_management.libraries.resources.hdfs_resource import HdfsResource
+from resource_management.libraries.functions import component_version
+from resource_management.libraries.functions import lzo_utils
 from resource_management.libraries.functions.default import default
 from resource_management.core import shell
 from resource_management.core import sudo
@@ -45,6 +47,9 @@ STACK_VERSION_PATTERN = "{{ stack_version }}"
 def _prepare_tez_tarball():
   """
   Prepares the Tez tarball by adding the Hadoop native libraries found in the mapreduce tarball.
+  It's very important to use the version of mapreduce which matches tez here.
+  Additionally, this will also copy native LZO to the tez tarball if LZO is enabled and the
+  GPL license has been accepted.
   :return:  the full path of the newly created tez tarball to use
   """
   import tempfile
@@ -79,12 +84,31 @@ def _prepare_tez_tarball():
   if not os.path.exists(tez_lib_dir):
     raise Fail("Unable to seed the Tez tarball with native libraries since the target Tez lib directory {0} does not exist".format(tez_lib_dir))
 
-  # ensure that the tez/lib directory is readable by non-root (which it typically is not)
-  sudo.chmod(tez_lib_dir, 0755)
-
   # copy native libraries from hadoop to tez
   Execute(("cp", "-a", hadoop_lib_native_dir, tez_lib_dir), sudo = True)
 
+  # if enabled, LZO GPL libraries must be copied as well
+  if lzo_utils.should_install_lzo():
+    stack_root = Script.get_stack_root()
+    tez_version = component_version.get_component_repository_version("TEZ")
+    hadoop_lib_native_lzo_dir = os.path.join(stack_root, tez_version, "hadoop", "lib", "native")
+
+    if not sudo.path_isdir(hadoop_lib_native_lzo_dir):
+      Logger.warning("Unable to located native LZO libraries at {0}, falling back to hadoop home".format(hadoop_lib_native_lzo_dir))
+      hadoop_lib_native_lzo_dir = os.path.join(stack_root, "current", "hadoop-client", "lib", "native")
+
+    if not sudo.path_isdir(hadoop_lib_native_lzo_dir):
+      raise Fail("Unable to seed the Tez tarball with native libraries since LZO is enabled but the native LZO libraries could not be found at {0}".format(hadoop_lib_native_lzo_dir))
+
+    Execute(("cp", "-a", hadoop_lib_native_lzo_dir, tez_lib_dir), sudo = True)
+
+
+  # ensure that the tez/lib directory is readable by non-root (which it typically is not)
+  Directory(tez_lib_dir,
+    mode = 0755,
+    cd_access = 'a',
+    recursive_ownership = True)
+
   # create the staging directory so that non-root agents can write to it
   tez_native_tarball_staging_dir = os.path.join(temp_dir, "tez-native-tarball-staging")
   if not os.path.exists(tez_native_tarball_staging_dir):
@@ -111,6 +135,72 @@ def _prepare_tez_tarball():
   return tez_tarball_with_native_lib
 
 
+def _prepare_mapreduce_tarball():
+  """
+  Prepares the mapreduce tarball by including the native LZO libraries if necessary. If LZO is
+  not enabled or has not been opted-in, then this will do nothing and return the original
+  tarball to upload to HDFS.
+  :return:  the full path of the newly created mapreduce tarball to use or the original path
+  if no changes were made
+  """
+  # get the mapreduce tarball to crack open and add LZO libraries to
+  _, mapreduce_source_file, _, _ = get_tarball_paths("mapreduce")
+
+  if not lzo_utils.should_install_lzo():
+    return mapreduce_source_file
+
+  Logger.info("Preparing the mapreduce tarball with native LZO libraries...")
+
+  temp_dir = Script.get_tmp_dir()
+
+  # create the temp staging directories ensuring that non-root agents using tarfile can work with them
+  mapreduce_temp_dir = tempfile.mkdtemp(prefix="mapreduce-tarball-", dir=temp_dir)
+  sudo.chmod(mapreduce_temp_dir, 0777)
+
+  # calculate the source directory for LZO
+  hadoop_lib_native_source_dir = os.path.join(os.path.dirname(mapreduce_source_file), "lib", "native")
+  if not sudo.path_exists(hadoop_lib_native_source_dir):
+    raise Fail("Unable to seed the mapreduce tarball with native LZO libraries since the source Hadoop native lib directory {0} does not exist".format(hadoop_lib_native_source_dir))
+
+  Logger.info("Extracting {0} to {1}".format(mapreduce_source_file, mapreduce_temp_dir))
+  tar_archive.extract_archive(mapreduce_source_file, mapreduce_temp_dir)
+
+  mapreduce_lib_dir = os.path.join(mapreduce_temp_dir, "hadoop", "lib")
+
+  # copy native libraries from source hadoop to target
+  Execute(("cp", "-af", hadoop_lib_native_source_dir, mapreduce_lib_dir), sudo = True)
+
+  # ensure that the hadoop/lib/native directory is readable by non-root (which it typically is not)
+  Directory(mapreduce_lib_dir,
+    mode = 0755,
+    cd_access = 'a',
+    recursive_ownership = True)
+
+  # create the staging directory so that non-root agents can write to it
+  mapreduce_native_tarball_staging_dir = os.path.join(temp_dir, "mapreduce-native-tarball-staging")
+  if not os.path.exists(mapreduce_native_tarball_staging_dir):
+    Directory(mapreduce_native_tarball_staging_dir,
+      mode = 0777,
+      cd_access = 'a',
+      create_parents = True,
+      recursive_ownership = True)
+
+  mapreduce_tarball_with_native_lib = os.path.join(mapreduce_native_tarball_staging_dir, "mapreduce-native.tar.gz")
+  Logger.info("Creating a new mapreduce tarball at {0}".format(mapreduce_tarball_with_native_lib))
+
+  # tar up mapreduce, making sure to specify nothing for the arcname so that it does not include an absolute path
+  with closing(tarfile.open(mapreduce_tarball_with_native_lib, "w:gz")) as new_tarball:
+    new_tarball.add(mapreduce_temp_dir, arcname = os.path.sep)
+
+  # ensure that the tarball can be read and uploaded
+  sudo.chmod(mapreduce_tarball_with_native_lib, 0744)
+
+  # cleanup
+  sudo.rmtree(mapreduce_temp_dir)
+
+  return mapreduce_tarball_with_native_lib
+
+
 # TODO, in the future, each stack can define its own mapping of tarballs
 # inside the stack definition directory in some sort of xml file.
 # PLEASE DO NOT put this in cluster-env since it becomes much harder to change,
@@ -163,7 +253,8 @@ TARBALL_MAP = {
   "mapreduce": {
     "dirs": ("{0}/{1}/hadoop/mapreduce.tar.gz".format(STACK_ROOT_PATTERN, STACK_VERSION_PATTERN),
                 "/{0}/apps/{1}/mapreduce/mapreduce.tar.gz".format(STACK_NAME_PATTERN, STACK_VERSION_PATTERN)),
-    "service": "MAPREDUCE2"
+    "service": "MAPREDUCE2",
+    "prepare_function": _prepare_mapreduce_tarball
   },
 
   "spark": {

http://git-wip-us.apache.org/repos/asf/ambari/blob/2c46bb3e/ambari-server/src/main/resources/common-services/TEZ/0.4.0.2.1/package/scripts/tez.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/TEZ/0.4.0.2.1/package/scripts/tez.py b/ambari-server/src/main/resources/common-services/TEZ/0.4.0.2.1/package/scripts/tez.py
index dfa6501..35647e4 100644
--- a/ambari-server/src/main/resources/common-services/TEZ/0.4.0.2.1/package/scripts/tez.py
+++ b/ambari-server/src/main/resources/common-services/TEZ/0.4.0.2.1/package/scripts/tez.py
@@ -23,8 +23,8 @@ import os
 
 # Local Imports
 from resource_management.core.resources.system import Directory, File
+from resource_management.libraries.functions import lzo_utils
 from resource_management.libraries.resources.xml_config import XmlConfig
-from resource_management.libraries.functions.format import format
 from resource_management.core.source import InlineTemplate
 from ambari_commons import OSConst
 from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl
@@ -37,6 +37,9 @@ def tez(config_dir):
   """
   import params
 
+  # ensure that matching LZO libraries are installed for Tez
+  lzo_utils.install_lzo_if_needed()
+
   Directory(params.tez_etc_dir, mode=0755)
 
   Directory(config_dir,

http://git-wip-us.apache.org/repos/asf/ambari/blob/2c46bb3e/ambari-server/src/main/resources/common-services/TEZ/0.9.0.3.0/configuration/tez-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/TEZ/0.9.0.3.0/configuration/tez-site.xml b/ambari-server/src/main/resources/common-services/TEZ/0.9.0.3.0/configuration/tez-site.xml
index 58558af..ac5683e 100644
--- a/ambari-server/src/main/resources/common-services/TEZ/0.9.0.3.0/configuration/tez-site.xml
+++ b/ambari-server/src/main/resources/common-services/TEZ/0.9.0.3.0/configuration/tez-site.xml
@@ -78,7 +78,7 @@
   </property>
   <property>
     <name>tez.am.launch.env</name>
-    <value>LD_LIBRARY_PATH=./tezlib/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64</value>
+    <value>LD_LIBRARY_PATH=./tezlib/lib/native:./tezlib/lib/native/Linux-{{architecture}}-64:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64</value>
     <description>
         Additional execution environment entries for tez. This is not an additive property. You must preserve the original value if
         you want to have access to native libraries.
@@ -124,7 +124,7 @@
   </property>
   <property>
     <name>tez.task.launch.env</name>
-    <value>LD_LIBRARY_PATH=/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64</value>
+    <value>LD_LIBRARY_PATH=./tezlib/lib/native:./tezlib/lib/native/Linux-{{architecture}}-64:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64</value>
     <description>
       Additional execution environment entries for tez. This is not an additive property. You must preserve the original value if
       you want to have access to native libraries.

http://git-wip-us.apache.org/repos/asf/ambari/blob/2c46bb3e/ambari-server/src/main/resources/common-services/TEZ/0.9.0.3.0/package/scripts/tez.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/TEZ/0.9.0.3.0/package/scripts/tez.py b/ambari-server/src/main/resources/common-services/TEZ/0.9.0.3.0/package/scripts/tez.py
index dfa6501..f819940 100644
--- a/ambari-server/src/main/resources/common-services/TEZ/0.9.0.3.0/package/scripts/tez.py
+++ b/ambari-server/src/main/resources/common-services/TEZ/0.9.0.3.0/package/scripts/tez.py
@@ -23,6 +23,7 @@ import os
 
 # Local Imports
 from resource_management.core.resources.system import Directory, File
+from resource_management.libraries.functions import lzo_utils
 from resource_management.libraries.resources.xml_config import XmlConfig
 from resource_management.libraries.functions.format import format
 from resource_management.core.source import InlineTemplate
@@ -37,6 +38,9 @@ def tez(config_dir):
   """
   import params
 
+  # ensure that matching LZO libraries are installed for Tez
+  lzo_utils.install_lzo_if_needed()
+
   Directory(params.tez_etc_dir, mode=0755)
 
   Directory(config_dir,

http://git-wip-us.apache.org/repos/asf/ambari/blob/2c46bb3e/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/configuration-mapred/mapred-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/configuration-mapred/mapred-site.xml b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/configuration-mapred/mapred-site.xml
index 3438c45..398c9d7 100644
--- a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/configuration-mapred/mapred-site.xml
+++ b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/configuration-mapred/mapred-site.xml
@@ -438,7 +438,7 @@
   </property>
   <property>
     <name>mapreduce.admin.user.env</name>
-    <value>LD_LIBRARY_PATH=./mr-framework/hadoop/lib/native:{{hadoop_lib_home}}/native/Linux-{{architecture}}-64</value>
+    <value>LD_LIBRARY_PATH=./mr-framework/hadoop/lib/native:./mr-framework/hadoop/lib/native/Linux-{{architecture}}-64:{{hadoop_lib_home}}/native/Linux-{{architecture}}-64</value>
     <description>
       Additional execution environment entries for map and reduce task processes.
       This is not an additive property. You must preserve the original value if

http://git-wip-us.apache.org/repos/asf/ambari/blob/2c46bb3e/ambari-server/src/main/resources/common-services/YARN/3.0.0.3.0/configuration-mapred/mapred-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/YARN/3.0.0.3.0/configuration-mapred/mapred-site.xml b/ambari-server/src/main/resources/common-services/YARN/3.0.0.3.0/configuration-mapred/mapred-site.xml
index 882cf83..3b31db1 100644
--- a/ambari-server/src/main/resources/common-services/YARN/3.0.0.3.0/configuration-mapred/mapred-site.xml
+++ b/ambari-server/src/main/resources/common-services/YARN/3.0.0.3.0/configuration-mapred/mapred-site.xml
@@ -438,7 +438,7 @@
   </property>
   <property>
     <name>mapreduce.admin.user.env</name>
-    <value>LD_LIBRARY_PATH=./mr-framework/hadoop/lib/native:/usr/lib/hadoop/lib/native:/usr/lib/hadoop/lib/native/Linux-amd64-64</value>
+    <value>LD_LIBRARY_PATH=./mr-framework/hadoop/lib/native:./mr-framework/hadoop/lib/native/Linux-{{architecture}}-64:{{hadoop_lib_home}}/native/Linux-{{architecture}}-64</value>
     <description>
       Additional execution environment entries for map and reduce task processes.
       This is not an additive property. You must preserve the original value if

http://git-wip-us.apache.org/repos/asf/ambari/blob/2c46bb3e/ambari-server/src/main/resources/stacks/HDP/2.2/services/TEZ/configuration/tez-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/TEZ/configuration/tez-site.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/TEZ/configuration/tez-site.xml
index 4ffb7a4..5513ab1 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/TEZ/configuration/tez-site.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/TEZ/configuration/tez-site.xml
@@ -78,7 +78,7 @@
   </property>
   <property>
     <name>tez.am.launch.env</name>
-    <value>LD_LIBRARY_PATH=./tezlib/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64</value>
+    <value>LD_LIBRARY_PATH=./tezlib/lib/native:./tezlib/lib/native/Linux-{{architecture}}-64:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64</value>
     <description>
         Additional execution environment entries for tez. This is not an additive property. You must preserve the original value if
         you want to have access to native libraries.
@@ -124,7 +124,7 @@
   </property>
   <property>
     <name>tez.task.launch.env</name>
-    <value>LD_LIBRARY_PATH=./tezlib/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64</value>
+    <value>LD_LIBRARY_PATH=./tezlib/lib/native:./tezlib/lib/native/Linux-{{architecture}}-64:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64</value>
     <description>
       Additional execution environment entries for tez. This is not an additive property. You must preserve the original value if
       you want to have access to native libraries.

http://git-wip-us.apache.org/repos/asf/ambari/blob/2c46bb3e/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/configuration-mapred/mapred-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/configuration-mapred/mapred-site.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/configuration-mapred/mapred-site.xml
index 084e912..099e388 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/configuration-mapred/mapred-site.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/YARN/configuration-mapred/mapred-site.xml
@@ -20,7 +20,7 @@
 <configuration xmlns:xi="http://www.w3.org/2001/XInclude" supports_final="true">
   <property>
     <name>mapreduce.admin.user.env</name>
-    <value>LD_LIBRARY_PATH=./mr-framework/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64</value>
+    <value>LD_LIBRARY_PATH=./mr-framework/hadoop/lib/native:./mr-framework/hadoop/lib/native/Linux-{{architecture}}-64:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64</value>
     <description>
       Additional execution environment entries for map and reduce task processes.
       This is not an additive property. You must preserve the original value if

http://git-wip-us.apache.org/repos/asf/ambari/blob/2c46bb3e/ambari-server/src/main/resources/stacks/HDP/2.6/upgrades/config-upgrade.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.6/upgrades/config-upgrade.xml b/ambari-server/src/main/resources/stacks/HDP/2.6/upgrades/config-upgrade.xml
index 45b1707..bcb13bc 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.6/upgrades/config-upgrade.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.6/upgrades/config-upgrade.xml
@@ -263,8 +263,8 @@
         <changes>
           <definition xsi:type="configure" id="hdp_2_6_tez_tarball_ld_library">
             <type>tez-site</type>
-            <set key="tez.am.launch.env" value="LD_LIBRARY_PATH=./tezlib/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64"/>
-            <set key="tez.task.launch.env" value="LD_LIBRARY_PATH=./tezlib/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64"/>
+            <set key="tez.am.launch.env" value="LD_LIBRARY_PATH=./tezlib/lib/native:./tezlib/lib/native/Linux-{{architecture}}-64:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64"/>
+            <set key="tez.task.launch.env" value="LD_LIBRARY_PATH=./tezlib/lib/native:./tezlib/lib/native/Linux-{{architecture}}-64:/usr/hdp/${hdp.version}/hadoop/lib/native:/usr/hdp/${hdp.version}/hadoop/lib/native/Linux-{{architecture}}-64"/>
           </definition>
         </changes>
       </component>
@@ -275,7 +275,7 @@
         <changes>
           <definition xsi:type="configure" id="hdp_2_6_mapreduce_tarball_ld_library">
             <type>mapred-site</type>
-            <set key="mapreduce.admin.user.env" value="LD_LIBRARY_PATH=./mr-framework/hadoop/lib/native:{{hadoop_lib_home}}/native/Linux-{{architecture}}-64"/>
+            <set key="mapreduce.admin.user.env" value="LD_LIBRARY_PATH=./mr-framework/hadoop/lib/native:./mr-framework/hadoop/lib/native/Linux-{{architecture}}-64:{{hadoop_lib_home}}/native/Linux-{{architecture}}-64"/>
           </definition>
         </changes>
       </component>


[07/49] ambari git commit: AMBARI-22461. VDF defined HDP-GPL repo should be tagged appropriately - remove unused imports

Posted by rl...@apache.org.
AMBARI-22461. VDF defined HDP-GPL repo should be tagged appropriately - remove unused imports


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 2d9fd418abee49b4c5410cc85b8e8520e3702c39
Parents: 5f8dcda
Author: Attila Doroszlai <ad...@hortonworks.com>
Authored: Sat Nov 18 20:42:12 2017 +0100
Committer: Attila Doroszlai <ad...@hortonworks.com>
Committed: Sat Nov 18 20:42:12 2017 +0100

----------------------------------------------------------------------
 .../org/apache/ambari/server/controller/RepositoryResponse.java | 3 ---
 .../org/apache/ambari/server/orm/entities/RepositoryEntity.java | 3 ---
 .../java/org/apache/ambari/server/state/RepositoryInfo.java     | 5 -----
 .../server/state/stack/upgrade/RepositoryVersionHelper.java     | 1 -
 4 files changed, 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2d9fd418/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
index 8a0e45d..6d0f3fb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
@@ -18,11 +18,8 @@
 
 package org.apache.ambari.server.controller;
 
-import java.util.List;
 import java.util.Set;
 
-import org.apache.ambari.annotations.Experimental;
-import org.apache.ambari.annotations.ExperimentalFeature;
 import org.apache.ambari.server.state.stack.RepoTag;
 
 public class RepositoryResponse {

http://git-wip-us.apache.org/repos/asf/ambari/blob/2d9fd418/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java
index 09701dd..18c7bee 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java
@@ -18,11 +18,8 @@
 package org.apache.ambari.server.orm.entities;
 
 import java.util.Collections;
-import java.util.List;
 import java.util.Set;
 
-import org.apache.ambari.annotations.Experimental;
-import org.apache.ambari.annotations.ExperimentalFeature;
 import org.apache.ambari.server.state.stack.RepoTag;
 
 /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/2d9fd418/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
index 3cc8521..a7bbc1b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
@@ -19,15 +19,10 @@
 package org.apache.ambari.server.state;
 
 import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Set;
 
-import org.apache.ambari.annotations.Experimental;
-import org.apache.ambari.annotations.ExperimentalFeature;
 import org.apache.ambari.server.controller.RepositoryResponse;
 import org.apache.ambari.server.state.stack.RepoTag;
-import org.apache.commons.lang.StringUtils;
 
 import com.google.common.base.Function;
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/ambari/blob/2d9fd418/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
index 138f566..39e5d5c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
@@ -21,7 +21,6 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;


[26/49] ambari git commit: AMBARI-22498. Remove trailing lines (if any) from llapstatus command before converting the o/p to JSON.

Posted by rl...@apache.org.
AMBARI-22498. Remove trailing lines (if any) from llapstatus command before converting the o/p to JSON.


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 9d3eeaaa9eca4cda1b3c675da9341516d9d19706
Parents: 65ca084
Author: Swapan Shridhar <ss...@hortonworks.com>
Authored: Wed Nov 22 10:24:38 2017 -0800
Committer: Swapan Shridhar <ss...@hortonworks.com>
Committed: Wed Nov 22 10:24:38 2017 -0800

----------------------------------------------------------------------
 .../package/scripts/hive_server_interactive.py  | 20 +++++++--
 .../HIVE/running_withMOTDmsg_andTrailingMsg.txt | 46 ++++++++++++++++++++
 .../stacks/2.5/HIVE/test_hive_server_int.py     | 21 +++++++++
 3 files changed, 84 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9d3eeaaa/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive_server_interactive.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive_server_interactive.py b/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive_server_interactive.py
index c0b152e..caa3e9b 100644
--- a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive_server_interactive.py
+++ b/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive_server_interactive.py
@@ -415,13 +415,14 @@ class HiveServerInteractiveDefault(HiveServerInteractive):
 
 
     """
-    Remove extra lines from 'llapstatus' status output (eg: because of MOTD logging) so as to have a valid JSON data to be passed in
-    to JSON converter.
+    Remove extra lines (begginning/end) from 'llapstatus' status output (eg: because of MOTD logging) so as to have 
+    a valid JSON data to be passed in to JSON converter.
     """
     def _make_valid_json(self, output):
       '''
 
-      Note: It is assumed right now that extra lines will be only at the start and not at the end.
+      Note: Extra lines (eg: because of MOTD) may be at the start or the end (some other logging getting appended)
+      of the passed-in data.
 
       Sample expected JSON to be passed for 'loads' is either of the form :
 
@@ -457,6 +458,19 @@ class HiveServerInteractiveDefault(HiveServerInteractive):
       if (len_splits < 3):
         raise Fail ("Malformed JSON data received from 'llapstatus' command. Exiting ....")
 
+      # Firstly, remove extra lines from the END.
+      updated_splits = []
+      for itr, line in enumerate(reversed(splits)):
+        if line == "}": # Our assumption of end of JSON data.
+          updated_splits = splits[:-itr]
+          break
+
+      if len(updated_splits) > 0:
+        splits = updated_splits
+        len_splits = len(splits)
+
+
+      # Secondly, remove extra lines from the BEGGINNING.
       marker_idx = None # To detect where from to start reading for JSON data
       for idx, split in enumerate(splits):
         curr_elem = split.strip()

http://git-wip-us.apache.org/repos/asf/ambari/blob/9d3eeaaa/ambari-server/src/test/python/stacks/2.5/HIVE/running_withMOTDmsg_andTrailingMsg.txt
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/2.5/HIVE/running_withMOTDmsg_andTrailingMsg.txt b/ambari-server/src/test/python/stacks/2.5/HIVE/running_withMOTDmsg_andTrailingMsg.txt
new file mode 100644
index 0000000..394faef
--- /dev/null
+++ b/ambari-server/src/test/python/stacks/2.5/HIVE/running_withMOTDmsg_andTrailingMsg.txt
@@ -0,0 +1,46 @@
+######## Hortonworks #############
+This is MOTD message, added for testing in qe infra
+{
+  "amInfo" : {
+    "appName" : "llap",
+    "appType" : "org-apache-slider",
+    "appId" : "application_1455662455106_10882",
+    "containerId" : "container_e14_1455662455106_10882_01_000001",
+    "hostname" : "HOST_REPLACED",
+    "amWebUrl" : "http://HOST_REPLACED:1025/"
+  },
+  "state" : "RUNNING_ALL",
+  "originalConfigurationPath" : "hdfs://HOST_REPLACED:8020/user/USER_REPLACED/.slider/cluster/llap/snapshot",
+  "generatedConfigurationPath" : "hdfs://HOST_REPLACED:8020/user/USER_REPLACED/.slider/cluster/llap/generated",
+  "desiredInstances" : 3,
+  "liveInstances" : 3,
+  "appStartTime" : 1459625802169,
+  "llapInstances" : [ {
+    "hostname" : "HOST_REPLACED",
+    "containerId" : "container_e14_1455662455106_10882_01_000003",
+    "statusUrl" : "http://HOST_REPLACED:15002/status",
+    "webUrl" : "http://HOST_REPLACED:15002",
+    "rpcPort" : 15001,
+    "mgmtPort" : 15004,
+    "shufflePort" : 15551
+  }, {
+    "hostname" : "HOST_REPLACED",
+    "containerId" : "container_e14_1455662455106_10882_01_000002",
+    "statusUrl" : "http://HOST_REPLACED:15002/status",
+    "webUrl" : "http://HOST_REPLACED:15002",
+    "rpcPort" : 15001,
+    "mgmtPort" : 15004,
+    "shufflePort" : 15551
+  }, {
+    "hostname" : "HOST_REPLACED",
+    "containerId" : "container_e14_1455662455106_10882_01_000004",
+    "statusUrl" : "http://HOST_REPLACED:15002/status",
+    "webUrl" : "http://HOST_REPLACED:15002",
+    "rpcPort" : 15001,
+    "mgmtPort" : 15004,
+    "shufflePort" : 15551
+  } ]
+}
+
+# THIS IS A DUMMY TRAILING MESSAGE 1
+# THIS IS A DUMMY TRAILING MESSAGE 2
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9d3eeaaa/ambari-server/src/test/python/stacks/2.5/HIVE/test_hive_server_int.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/2.5/HIVE/test_hive_server_int.py b/ambari-server/src/test/python/stacks/2.5/HIVE/test_hive_server_int.py
index cf79ec7..4eb16c2 100644
--- a/ambari-server/src/test/python/stacks/2.5/HIVE/test_hive_server_int.py
+++ b/ambari-server/src/test/python/stacks/2.5/HIVE/test_hive_server_int.py
@@ -915,6 +915,27 @@ class TestHiveServerInteractive(RMFTestCase):
 
 
 
+  # Tests for function '_make_valid_json()' : will be passed in with 'llapstatus' output which will be :
+  #     (1). A string parseable as JSON, but has 2 and 3.
+  #     (2). Has extra lines in beginning (eg: from MOTD logging embedded)
+  #          AND/OR
+  #     (3). Extra lines at the end.
+
+  # Begginning and end lines need to be removed before parsed as JSON
+  def test_make_valid_json_11(self):
+      # Setting up input for fn. '_make_valid_json()'
+      input_file_handle = open(self.get_src_folder() + "/test/python/stacks/2.5/HIVE/running_withMOTDmsg_andTrailingMsg.txt","r")
+      llap_app_info = input_file_handle.read()
+      llap_app_info_as_json = self.hsi._make_valid_json(llap_app_info)
+
+      # Set up expected output
+      expected_ouput_file_handle = open(self.get_src_folder() + "/test/python/stacks/2.5/HIVE/running.json","r")
+      expected_ouput_data = expected_ouput_file_handle.read()
+      expected_ouput_data_as_json = json.loads(expected_ouput_data)
+
+      # Verification
+      self.assertEqual(llap_app_info_as_json, expected_ouput_data_as_json)
+
 
   # Tests for fn : 'check_llap_app_status_in_hdp_tp()'
 


[41/49] ambari git commit: AMBARI-22510. Handle new error type from Stack Advisor (akovalenko)

Posted by rl...@apache.org.
AMBARI-22510. Handle new error type from Stack Advisor (akovalenko)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: c5fe6cb96a6530d0fc44c4ffced2ec46db97233b
Parents: 0249073
Author: Aleksandr Kovalenko <ak...@hortonworks.com>
Authored: Fri Nov 24 11:37:07 2017 +0200
Committer: Aleksandr Kovalenko <ak...@hortonworks.com>
Committed: Fri Nov 24 17:59:19 2017 +0200

----------------------------------------------------------------------
 ambari-web/app/messages.js                      |   5 +-
 ambari-web/app/mixins/common/serverValidator.js |  41 +++++---
 ambari-web/app/styles/application.less          |   3 +-
 .../config_recommendation_popup.hbs             | 102 +++++++++++++------
 .../config_validation_popup.js                  |   7 +-
 .../test/mixins/common/serverValidator_test.js  |  15 +--
 6 files changed, 112 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/c5fe6cb9/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 390f803..b294877 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -359,6 +359,7 @@ Em.I18n.translations = {
   'common.rolling.downgrade': 'Rolling Downgrade',
   'common.express.downgrade': 'Express Downgrade',
   'common.views': 'Views',
+  'common.critical.error': 'Critical',
 
   'models.alert_instance.tiggered.verbose': "Occurred on {0} <br> Checked on {1}",
   'models.alert_definition.triggered.verbose': "Occurred on {0}",
@@ -951,8 +952,8 @@ Em.I18n.translations = {
   'installer.step7.popup.validation.failed.body': 'Some services are not properly configured. You have to change the highlighted configs according to the recommended values.',
   'installer.step7.popup.validation.request.failed.body': 'The configuration changes could not be validated for consistency due to an unknown error.  Your changes have not been saved yet.  Would you like to proceed and save the changes?',
   'installer.step7.popup.validation.warning.header': 'Configurations',
-  'installer.step7.popup.validation.warning.body': 'Some service configurations are not configured properly. We recommend you review and change the highlighted configuration values. Are you sure you want to proceed without correcting configurations?',
-  'installer.step7.popup.validation.error.body': 'Service configurations resulted in validation errors. Please address them before proceeding.',
+  'installer.step7.popup.validation.issues.body': 'The following configuration changes are highly recommended, but can be skipped.',
+  'installer.step7.popup.validation.criticalIssues.body': 'You must correct the following critical issues before proceeding:',
   'installer.step7.popup.oozie.derby.warning': 'Derby is not recommended for production use. With Derby, Oozie Server HA and concurrent connection support will not be available.',
   'installer.step7.oozie.database.new': 'New Derby Database',
   'installer.step7.hive.database.new.mysql': 'New MySQL Database',

http://git-wip-us.apache.org/repos/asf/ambari/blob/c5fe6cb9/ambari-web/app/mixins/common/serverValidator.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/serverValidator.js b/ambari-web/app/mixins/common/serverValidator.js
index 319c281..65f43b7 100644
--- a/ambari-web/app/mixins/common/serverValidator.js
+++ b/ambari-web/app/mixins/common/serverValidator.js
@@ -57,7 +57,10 @@ App.ServerValidatorMixin = Em.Mixin.create({
    *
    * @type {Object[]}
    */
-  configErrorList: [],
+  configErrorList: Em.Object.create({
+    issues: [],
+    criticalIssues: []
+  }),
 
   /**
    * Map with allowed error types
@@ -65,6 +68,7 @@ App.ServerValidatorMixin = Em.Mixin.create({
    * @type {Object}
    */
   errorTypes: {
+    CRITICAL_ERROR: 'NOT_APPLICABLE',
     ERROR: 'ERROR',
     WARN: 'WARN',
     GENERAL: 'GENERAL'
@@ -113,10 +117,13 @@ App.ServerValidatorMixin = Em.Mixin.create({
       self = this,
       primary = function() { deferred.resolve(); },
       secondary = function() { deferred.reject('invalid_configs'); };
-    this.set('configErrorList', []);
+    this.set('configErrorList', Em.Object.create({
+      issues: [],
+      criticalIssues: []
+    }));
 
     this.runServerSideValidation().done(function() {
-      if (self.get('configErrorList.length')) {
+      if (self.get('configErrorList.issues.length') || self.get('configErrorList.criticalIssues.length')) {
         App.showConfigValidationPopup(self.get('configErrorList'), primary, secondary);
       } else {
         deferred.resolve();
@@ -228,13 +235,14 @@ App.ServerValidatorMixin = Em.Mixin.create({
     var errorTypes = this.get('errorTypes');
     var error = {
       type: type,
+      isCriticalError: type === errorTypes.CRITICAL_ERROR,
       isError: type === errorTypes.ERROR,
       isWarn: type === errorTypes.WARN,
       isGeneral: type === errorTypes.GENERAL,
       messages: Em.makeArray(messages)
     };
 
-    Em.assert('Unknown config error type ' + type, error.isError || error.isWarn || error.isGeneral);
+    Em.assert('Unknown config error type ' + type, error.isError || error.isWarn || error.isGeneral || error.isCriticalError);
     if (property) {
       error.id = Em.get(property, 'id');
       error.serviceName = Em.get(property, 'serviceDisplayName') || App.StackService.find(Em.get(property, 'serviceName')).get('displayName');
@@ -298,29 +306,33 @@ App.ServerValidatorMixin = Em.Mixin.create({
    */
   collectAllIssues: function(configErrorsMap, generalErrors)  {
     var errorTypes = this.get('errorTypes');
-    var configErrorList = [];
+    var configErrorList = {};
+    configErrorList[errorTypes.WARN] = [];
+    configErrorList[errorTypes.ERROR] = [];
+    configErrorList[errorTypes.CRITICAL_ERROR] = [];
+    configErrorList[errorTypes.GENERAL] = [];
 
     this.get('stepConfigs').forEach(function(service) {
       service.get('configs').forEach(function(property) {
         if (property.get('isVisible') && !property.get('hiddenBySection')) {
           var serverIssue = configErrorsMap[property.get('id')];
           if (serverIssue) {
-            configErrorList.push(this.createErrorMessage(serverIssue.type, property, serverIssue.messages));
+            configErrorList[serverIssue.type].push(this.createErrorMessage(serverIssue.type, property, serverIssue.messages));
           } else if (property.get('warnMessage')) {
-            configErrorList.push(this.createErrorMessage(errorTypes.WARN, property, [property.get('warnMessage')]));
+            configErrorList[errorTypes.WARN].push(this.createErrorMessage(errorTypes.WARN, property, [property.get('warnMessage')]));
           }
         }
       }, this);
     }, this);
 
     generalErrors.forEach(function(serverIssue) {
-      configErrorList.push(this.createErrorMessage(errorTypes.GENERAL, null, serverIssue.messages));
+      configErrorList[errorTypes.GENERAL].push(this.createErrorMessage(errorTypes.GENERAL, null, serverIssue.messages));
     }, this);
 
     Em.keys(configErrorsMap).forEach(function (id) {
-      if (!configErrorList.someProperty('id', id)) {
-        var serverIssue = configErrorsMap[id],
-          filename = Em.get(serverIssue, 'filename'),
+      var serverIssue = configErrorsMap[id];
+      if (!configErrorList[serverIssue.type].someProperty('id', id)) {
+        var filename = Em.get(serverIssue, 'filename'),
           service = App.config.get('serviceByConfigTypeMap')[filename],
           property = {
             id: id,
@@ -328,11 +340,14 @@ App.ServerValidatorMixin = Em.Mixin.create({
             filename: App.config.getOriginalFileName(filename),
             serviceDisplayName: service && Em.get(service, 'displayName')
           };
-        configErrorList.push(this.createErrorMessage(serverIssue.type, property, serverIssue.messages));
+        configErrorList[serverIssue.type].push(this.createErrorMessage(serverIssue.type, property, serverIssue.messages));
       }
     }, this);
 
-    return configErrorList;
+    return Em.Object.create({
+      criticalIssues: configErrorList[errorTypes.CRITICAL_ERROR],
+      issues: configErrorList[errorTypes.ERROR].concat(configErrorList[errorTypes.WARN], configErrorList[errorTypes.GENERAL])
+    });
   },
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/c5fe6cb9/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index df86c7f..2a908b3 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -2308,7 +2308,7 @@ input[type="radio"].align-checkbox, input[type="checkbox"].align-checkbox {
 .table td.error { background-color: @error-background; }
 .table td.warning { background-color: @warning-background; }
 
-#config-validation-warnings {
+.config-validation-warnings {
   table {
     tbody{
       tr {
@@ -2332,7 +2332,6 @@ input[type="radio"].align-checkbox, input[type="checkbox"].align-checkbox {
   }
 }
 
-
 @config-dependency-t-name-width: 180px;
 @config-dependency-t-service-width: 100px;
 @config-dependency-t-group-width: 140px;

http://git-wip-us.apache.org/repos/asf/ambari/blob/c5fe6cb9/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs b/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
index 1fe4d39..07125ac 100644
--- a/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
+++ b/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
@@ -16,34 +16,25 @@
 * limitations under the License.
 }}
 
-<p>{{view.messageBody}}</p>
-<div id="config-validation-warnings" class="limited-height-2">
-  <table class="table table-hover">
-    <thead>
-    <tr>
-      <th>{{t common.type}}</th>
-      <th>{{t common.service}}</th>
-      <th>{{t common.property}}</th>
-      <th>{{t common.value}}</th>
-      <th>{{t common.description}}</th>
-    </tr>
-    </thead>
-    <tbody>
-    {{#each error in view.configErrors}}
-      <tr {{bindAttr class="error.isError:error:warning"}}>
-        <td>
-          {{#if error.isError}}
-            {{t common.error}}
-          {{else}}
-            {{t common.warning}}
-          {{/if}}
-        </td>
-
-        {{#if error.isGeneral}}
-          {{#each message in error.messages}}
-            <td colspan="4">{{error.message}}</td>
-          {{/each}}
-        {{else}}
+{{#if view.configErrors.criticalIssues.length}}
+  <p>{{t installer.step7.popup.validation.criticalIssues.body}}</p>
+  <div class="limited-height-2 config-validation-warnings">
+    <table class="table table-hover">
+      <thead>
+      <tr>
+        <th>{{t common.type}}</th>
+        <th>{{t common.service}}</th>
+        <th>{{t common.property}}</th>
+        <th>{{t common.value}}</th>
+        <th>{{t common.description}}</th>
+      </tr>
+      </thead>
+      <tbody>
+      {{#each error in view.configErrors.criticalIssues}}
+        <tr class="error">
+          <td>
+            {{t common.critical}}
+          </td>
           <td>{{error.serviceName}}</td>
           <td>{{error.propertyName}}</td>
           <td>{{error.value}}</td>
@@ -53,9 +44,54 @@
             {{/each}}
             <div class="property-description">{{error.description}}</div>
           </td>
-        {{/if}}
+        </tr>
+      {{/each}}
+      </tbody>
+    </table>
+  </div>
+{{/if}}
+{{#if view.configErrors.issues.length}}
+  <p>{{t installer.step7.popup.validation.issues.body}}</p>
+  <div class="limited-height-2 config-validation-warnings">
+    <table class="table table-hover">
+      <thead>
+      <tr>
+        <th>{{t common.type}}</th>
+        <th>{{t common.service}}</th>
+        <th>{{t common.property}}</th>
+        <th>{{t common.value}}</th>
+        <th>{{t common.description}}</th>
       </tr>
-    {{/each}}
-    </tbody>
-  </table>
-</div>
+      </thead>
+      <tbody>
+      {{#each error in view.configErrors.issues}}
+        <tr {{bindAttr class="error.isError:error:warning"}}>
+          <td>
+            {{#if error.isError}}
+              {{t common.error}}
+            {{else}}
+              {{t common.warning}}
+            {{/if}}
+          </td>
+
+          {{#if error.isGeneral}}
+            {{#each message in error.messages}}
+              <td colspan="4">{{error.message}}</td>
+            {{/each}}
+          {{else}}
+            <td>{{error.serviceName}}</td>
+            <td>{{error.propertyName}}</td>
+            <td>{{error.value}}</td>
+            <td>
+              {{#each message in error.messages}}
+                <div class="property-message">{{message}}</div>
+              {{/each}}
+              <div class="property-description">{{error.description}}</div>
+            </td>
+          {{/if}}
+        </tr>
+      {{/each}}
+      </tbody>
+    </table>
+  </div>
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c5fe6cb9/ambari-web/app/views/common/modal_popups/config_validation/config_validation_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/modal_popups/config_validation/config_validation_popup.js b/ambari-web/app/views/common/modal_popups/config_validation/config_validation_popup.js
index 2fe7b62..07c891e 100644
--- a/ambari-web/app/views/common/modal_popups/config_validation/config_validation_popup.js
+++ b/ambari-web/app/views/common/modal_popups/config_validation/config_validation_popup.js
@@ -43,13 +43,10 @@ App.showConfigValidationPopup = function (configErrors, primary, secondary) {
       this._super();
       secondary();
     },
+    disablePrimary: !!configErrors.get('criticalIssues.length'),
     bodyClass: Em.View.extend({
       templateName: require('templates/common/modal_popups/config_recommendation_popup'),
-      configErrors: configErrors,
-      configValidationError: Em.computed.someBy('configErrors', 'isError', true),
-      messageBody: Em.I18n.t(this.get('configValidationError')
-        ? 'installer.step7.popup.validation.error.body'
-        : 'installer.step7.popup.validation.warning.body')
+      configErrors: configErrors
     })
   });
 };

http://git-wip-us.apache.org/repos/asf/ambari/blob/c5fe6cb9/ambari-web/test/mixins/common/serverValidator_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mixins/common/serverValidator_test.js b/ambari-web/test/mixins/common/serverValidator_test.js
index cdd69fb..4a12a69 100644
--- a/ambari-web/test/mixins/common/serverValidator_test.js
+++ b/ambari-web/test/mixins/common/serverValidator_test.js
@@ -94,35 +94,35 @@ describe('App.ServerValidatorMixin', function () {
     });
 
     it('should add server warnings', function () {
-      var error = result.find(function(r) { return r.propertyName === 'c1' && r.filename === 'f1'; });
+      var error = result.issues.find(function(r) { return r.propertyName === 'c1' && r.filename === 'f1'; });
       expect(error.type).to.equal('WARN');
       expect(error.messages).to.eql(['warn1']);
     });
 
     it('should add server errors', function () {
-      var error = result.find(function(r) { return r.propertyName === 'c2' && r.filename === 'f2'; });
+      var error = result.issues.find(function(r) { return r.propertyName === 'c2' && r.filename === 'f2'; });
       expect(error.type).to.equal('ERROR');
       expect(error.messages).to.eql(['error2']);
     });
 
     it('should add ui warning', function () {
-      var error = result.find(function(r) { return r.propertyName === 'c3' && r.filename === 'f3'; });
+      var error = result.issues.find(function(r) { return r.propertyName === 'c3' && r.filename === 'f3'; });
       expect(error.type).to.equal('WARN');
       expect(error.messages).to.eql(['warn3']);
     });
 
     it('should add general issues', function () {
-      var error = result.findProperty('type', 'GENERAL');
+      var error = result.issues.findProperty('type', 'GENERAL');
       expect(error.messages).to.eql(['general issue']);
     });
 
     it('should ignore issues for hidden configs', function () {
-      var error = result.find(function(r) { return r.propertyName === 'c4' && r.filename === 'f4'; });
+      var error = result.issues.find(function(r) { return r.propertyName === 'c4' && r.filename === 'f4'; });
       expect(error).to.be.undefined;
     });
 
     it('should add issues for deleted properties', function () {
-      var error = result.find(function(r) { return r.id === 'c5_f5'; });
+      var error = result.issues.find(function(r) { return r.id === 'c5_f5'; });
       expect(error.messages).to.eql(['error5']);
     });
   });
@@ -150,6 +150,7 @@ describe('App.ServerValidatorMixin', function () {
     it('creates warn object', function() {
       expect(instanceObject.createErrorMessage('WARN', property, ['msg1'])).to.eql({
         type: 'WARN',
+        isCriticalError: false,
         isError: false,
         isWarn: true,
         isGeneral: false,
@@ -166,6 +167,7 @@ describe('App.ServerValidatorMixin', function () {
     it('creates error object', function() {
       expect(instanceObject.createErrorMessage('ERROR', $.extend({}, property, {serviceDisplayName: 'S Name'}), ['msg2'])).to.eql({
         type: 'ERROR',
+        isCriticalError: false,
         isError: true,
         isWarn: false,
         isGeneral: false,
@@ -182,6 +184,7 @@ describe('App.ServerValidatorMixin', function () {
     it('creates general issue object', function() {
       expect(instanceObject.createErrorMessage('GENERAL', null, ['msg3'])).to.eql({
         type: 'GENERAL',
+        isCriticalError: false,
         isError: false,
         isWarn: false,
         isGeneral: true,


[14/49] ambari git commit: AMBARI-22453. ambari-server setup should surface GPL software agreement (aonishuk)

Posted by rl...@apache.org.
AMBARI-22453. ambari-server setup should surface GPL software agreement (aonishuk)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: f331f86d1b3d4414d3ccfe4102c1fde31b517830
Parents: 3f836c0
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Wed Nov 22 13:11:10 2017 +0200
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Wed Nov 22 13:11:10 2017 +0200

----------------------------------------------------------------------
 .../ambari/server/agent/ExecutionCommand.java   |    1 +
 .../server/configuration/Configuration.java     |   12 +
 .../AmbariCustomCommandExecutionHelper.java     |    2 +
 .../internal/ClientConfigResourceProvider.java  |    2 +
 ambari-server/src/main/python/ambari-server.py  |    2 +
 .../python/ambari_server/serverConfiguration.py | 1515 ------------------
 .../main/python/ambari_server/serverSetup.py    |   21 +-
 .../AmbariManagementControllerImplTest.java     |    3 +-
 .../ClientConfigResourceProviderTest.java       |    2 +
 .../src/test/python/TestAmbariServer.py         |    5 +-
 10 files changed, 45 insertions(+), 1520 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f331f86d/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
index e475c05..5ee4bf6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
@@ -456,6 +456,7 @@ public class ExecutionCommand extends AgentCommand {
     String PACKAGE_LIST = "package_list";
     String JDK_LOCATION = "jdk_location";
     String JAVA_HOME = "java_home";
+    String GPL_LICENSE_ACCEPTED = "gpl_license_accepted";
     String AMBARI_JAVA_HOME = "ambari_java_home";
     String AMBARI_JDK_NAME = "ambari_jdk_name";
     String AMBARI_JCE_NAME = "ambari_jce_name";

http://git-wip-us.apache.org/repos/asf/ambari/blob/f331f86d/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index 3b2baad..a53aebd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -730,6 +730,14 @@ public class Configuration {
       "server.version.file", null);
 
   /**
+   * Whether user accepted GPL license
+   */
+  @Markdown(
+      description = "Whether user accepted GPL license.")
+  public static final ConfigurationProperty<Boolean> GPL_LICENSE_ACCEPTED = new ConfigurationProperty<>(
+      "gpl.license.accepted", false);
+
+  /**
    * The location of the JDK on the Ambari Agent hosts.
    */
   @Markdown(
@@ -5437,6 +5445,10 @@ public class Configuration {
     return NumberUtils.toInt(getProperty(VERSION_DEFINITION_READ_TIMEOUT));
   }
 
+  public Boolean getGplLicenseAccepted(){
+    return Boolean.valueOf(getProperty(GPL_LICENSE_ACCEPTED));
+  }
+
   public String getAgentStackRetryOnInstallCount(){
     return getProperty(AGENT_STACK_RETRY_COUNT);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f331f86d/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
index 9f95f7a..7c52877 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
@@ -28,6 +28,7 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_DRIVER
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_NAME;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GROUP_LIST;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOST_SYS_PREPPED;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GPL_LICENSE_ACCEPTED;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.MYSQL_JDBC_URL;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.NOT_MANAGED_HDFS_PATH_LIST;
@@ -1303,6 +1304,7 @@ public class AmbariCustomCommandExecutionHelper {
     hostLevelParams.put(HOST_SYS_PREPPED, configs.areHostsSysPrepped());
     hostLevelParams.put(AGENT_STACK_RETRY_ON_UNAVAILABILITY, configs.isAgentStackRetryOnInstallEnabled());
     hostLevelParams.put(AGENT_STACK_RETRY_COUNT, configs.getAgentStackRetryOnInstallCount());
+    hostLevelParams.put(GPL_LICENSE_ACCEPTED, configs.getGplLicenseAccepted().toString());
 
     Map<String, DesiredConfig> desiredConfigs = cluster.getDesiredConfigs();
     Map<PropertyInfo, String> notManagedHdfsPathMap = configHelper.getPropertiesWithPropertyType(stackId, PropertyType.NOT_MANAGED_HDFS_PATH, cluster, desiredConfigs);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f331f86d/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProvider.java
index a2a49d7..993da1b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProvider.java
@@ -33,6 +33,7 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAM
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.USER_GROUPS;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.USER_LIST;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GPL_LICENSE_ACCEPTED;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -369,6 +370,7 @@ public class ClientConfigResourceProvider extends AbstractControllerResourceProv
         hostLevelParams.putAll(managementController.getRcaParameters());
         hostLevelParams.put(AGENT_STACK_RETRY_ON_UNAVAILABILITY, configs.isAgentStackRetryOnInstallEnabled());
         hostLevelParams.put(AGENT_STACK_RETRY_COUNT, configs.getAgentStackRetryOnInstallCount());
+        hostLevelParams.put(GPL_LICENSE_ACCEPTED, configs.getGplLicenseAccepted().toString());
 
         // Write down os specific info for the service
         ServiceOsSpecific anyOs = null;

http://git-wip-us.apache.org/repos/asf/ambari/blob/f331f86d/ambari-server/src/main/python/ambari-server.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py
index 8fcde77..188910e 100755
--- a/ambari-server/src/main/python/ambari-server.py
+++ b/ambari-server/src/main/python/ambari-server.py
@@ -412,6 +412,7 @@ def init_action_parser(action, parser):
   parser.add_option('--skip-database-check', action="store_true", default=False, help="Skip database consistency check", dest="skip_database_check")
   parser.add_option('--skip-view-extraction', action="store_true", default=False, help="Skip extraction of system views", dest="skip_view_extraction")
   parser.add_option('--auto-fix-database', action="store_true", default=False, help="Automatically fix database consistency issues", dest="fix_database_consistency")
+  parser.add_option('--enable-lzo-under-gpl-license', action="store_true", default=False, help="Automatically accepts GPL license", dest="accept_gpl")
   add_parser_options('--mpack',
       default=None,
       help="Specify the path for management pack to be installed/upgraded",
@@ -490,6 +491,7 @@ def init_setup_parser_options(parser):
   other_group.add_option('--sqla-server-name', default=None, help="SQL Anywhere server name", dest="sqla_server_name")
   other_group.add_option('--sidorsname', default="sname", help="Oracle database identifier type, Service ID/Service "
                                                                "Name sid|sname", dest="sid_or_sname")
+  other_group.add_option('--enable-lzo-under-gpl-license', action="store_true", default=False, help="Automatically accepts GPL license", dest="accept_gpl")
 
   parser.add_option_group(other_group)
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f331f86d/ambari-server/src/main/python/ambari_server/serverConfiguration.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/serverConfiguration.py b/ambari-server/src/main/python/ambari_server/serverConfiguration.py
deleted file mode 100644
index df89f79..0000000
--- a/ambari-server/src/main/python/ambari_server/serverConfiguration.py
+++ /dev/null
@@ -1,1515 +0,0 @@
-#!/usr/bin/env python
-
-'''
-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 datetime
-import glob
-import os
-import re
-import shutil
-import stat
-import string
-import sys
-import tempfile
-import getpass
-import ambari_server.serverClassPath
-
-from ambari_commons.exceptions import FatalException
-from ambari_commons.os_check import OSCheck, OSConst
-from ambari_commons.os_family_impl import OsFamilyImpl
-from ambari_commons.os_utils import run_os_command, search_file, set_file_permissions, parse_log4j_file
-from ambari_commons.logging_utils import get_debug_mode, print_info_msg, print_warning_msg, print_error_msg, \
-  set_debug_mode
-from ambari_server.properties import Properties
-from ambari_server.userInput import get_validated_string_input
-from ambari_server.utils import compare_versions, locate_file, on_powerpc
-from ambari_server.ambariPath import AmbariPath
-
-
-OS_VERSION = OSCheck().get_os_major_version()
-OS_TYPE = OSCheck.get_os_type()
-OS_FAMILY = OSCheck.get_os_family()
-
-PID_NAME = "ambari-server.pid"
-
-# Non-root user setup commands
-NR_USER_PROPERTY = "ambari-server.user"
-
-BLIND_PASSWORD = "*****"
-
-# Common messages
-PRESS_ENTER_MSG = "Press <enter> to continue."
-
-OS_FAMILY_PROPERTY = "server.os_family"
-OS_TYPE_PROPERTY = "server.os_type"
-
-BOOTSTRAP_DIR_PROPERTY = "bootstrap.dir"
-RECOMMENDATIONS_DIR_PROPERTY = 'recommendations.dir'
-
-AMBARI_CONF_VAR = "AMBARI_CONF_DIR"
-AMBARI_PROPERTIES_FILE = "ambari.properties"
-AMBARI_ENV_FILE = "ambari-env.sh"
-AMBARI_KRB_JAAS_LOGIN_FILE = "krb5JAASLogin.conf"
-GET_FQDN_SERVICE_URL = "server.fqdn.service.url"
-
-SERVER_OUT_FILE_KEY = "ambari.output.file.path"
-VERBOSE_OUTPUT_KEY = "ambari.output.verbose"
-
-DEBUG_MODE_KEY = "ambari.server.debug"
-SUSPEND_START_MODE_KEY = "ambari.server.debug.suspend.start"
-
-# Environment variables
-AMBARI_SERVER_LIB = "AMBARI_SERVER_LIB"
-JAVA_HOME = "JAVA_HOME"
-
-AMBARI_VERSION_VAR = "AMBARI_VERSION_VAR"
-
-# JDK
-JAVA_HOME_PROPERTY = "java.home"
-JDK_NAME_PROPERTY = "jdk.name"
-JCE_NAME_PROPERTY = "jce.name"
-JDK_DOWNLOAD_SUPPORTED_PROPERTY = "jdk.download.supported"
-JCE_DOWNLOAD_SUPPORTED_PROPERTY = "jce.download.supported"
-
-# Stack JDK
-STACK_JAVA_HOME_PROPERTY = "stack.java.home"
-STACK_JDK_NAME_PROPERTY = "stack.jdk.name"
-STACK_JCE_NAME_PROPERTY = "stack.jce.name"
-STACK_JAVA_VERSION = "stack.java.version"
-
-
-#TODO property used incorrectly in local case, it was meant to be dbms name, not postgres database name,
-# has workaround for now, as we don't need dbms name if persistence_type=local
-JDBC_DATABASE_PROPERTY = "server.jdbc.database"                 # E.g., embedded|oracle|mysql|mssql|postgres
-JDBC_DATABASE_NAME_PROPERTY = "server.jdbc.database_name"       # E.g., ambari. Not used on Windows.
-JDBC_HOSTNAME_PROPERTY = "server.jdbc.hostname"
-JDBC_PORT_PROPERTY = "server.jdbc.port"
-JDBC_POSTGRES_SCHEMA_PROPERTY = "server.jdbc.postgres.schema"   # Only for postgres, defaults to same value as DB name
-JDBC_SQLA_SERVER_NAME = "server.jdbc.sqla.server_name"
-
-JDBC_USER_NAME_PROPERTY = "server.jdbc.user.name"
-JDBC_PASSWORD_PROPERTY = "server.jdbc.user.passwd"
-JDBC_PASSWORD_FILENAME = "password.dat"
-JDBC_RCA_PASSWORD_FILENAME = "rca_password.dat"
-
-CLIENT_API_PORT_PROPERTY = "client.api.port"
-CLIENT_API_PORT = "8080"
-
-SERVER_VERSION_FILE_PATH = "server.version.file"
-
-PERSISTENCE_TYPE_PROPERTY = "server.persistence.type"
-JDBC_DRIVER_PROPERTY = "server.jdbc.driver"
-JDBC_URL_PROPERTY = "server.jdbc.url"
-
-# connection pool (age and time are in seconds)
-JDBC_CONNECTION_POOL_TYPE = "server.jdbc.connection-pool"
-JDBC_CONNECTION_POOL_ACQUISITION_SIZE = "server.jdbc.connection-pool.acquisition-size"
-JDBC_CONNECTION_POOL_MAX_AGE = "server.jdbc.connection-pool.max-age"
-JDBC_CONNECTION_POOL_MAX_IDLE_TIME = "server.jdbc.connection-pool.max-idle-time"
-JDBC_CONNECTION_POOL_MAX_IDLE_TIME_EXCESS = "server.jdbc.connection-pool.max-idle-time-excess"
-JDBC_CONNECTION_POOL_IDLE_TEST_INTERVAL = "server.jdbc.connection-pool.idle-test-interval"
-
-JDBC_RCA_DATABASE_PROPERTY = "server.jdbc.database"
-JDBC_RCA_HOSTNAME_PROPERTY = "server.jdbc.hostname"
-JDBC_RCA_PORT_PROPERTY = "server.jdbc.port"
-JDBC_RCA_SCHEMA_PROPERTY = "server.jdbc.schema"
-
-JDBC_RCA_DRIVER_PROPERTY = "server.jdbc.rca.driver"
-JDBC_RCA_URL_PROPERTY = "server.jdbc.rca.url"
-JDBC_RCA_USER_NAME_PROPERTY = "server.jdbc.rca.user.name"
-JDBC_RCA_PASSWORD_FILE_PROPERTY = "server.jdbc.rca.user.passwd"
-
-DEFAULT_DBMS_PROPERTY = "server.setup.default.dbms"
-
-JDBC_RCA_PASSWORD_ALIAS = "ambari.db.password"
-
-### # Windows-specific # ###
-
-JDBC_USE_INTEGRATED_AUTH_PROPERTY = "server.jdbc.use.integrated.auth"
-
-JDBC_RCA_USE_INTEGRATED_AUTH_PROPERTY = "server.jdbc.rca.use.integrated.auth"
-
-### # End Windows-specific # ###
-# The user which will bootstrap embedded postgres database setup by creating the default schema and ambari user.
-LOCAL_DATABASE_ADMIN_PROPERTY = "local.database.user"
-
-# resources repo configuration
-RESOURCES_DIR_PROPERTY = "resources.dir"
-
-# stack repo upgrade
-STACK_LOCATION_KEY = 'metadata.path'
-
-# LDAP security
-IS_LDAP_CONFIGURED = "ambari.ldap.isConfigured"
-LDAP_MGR_PASSWORD_ALIAS = "ambari.ldap.manager.password"
-LDAP_MGR_PASSWORD_PROPERTY = "authentication.ldap.managerPassword"
-LDAP_MGR_PASSWORD_FILENAME = "ldap-password.dat"
-LDAP_MGR_USERNAME_PROPERTY = "authentication.ldap.managerDn"
-LDAP_PRIMARY_URL_PROPERTY = "authentication.ldap.primaryUrl"
-
-# SSL truststore
-SSL_TRUSTSTORE_PASSWORD_ALIAS = "ambari.ssl.trustStore.password"
-SSL_TRUSTSTORE_PATH_PROPERTY = "ssl.trustStore.path"
-SSL_TRUSTSTORE_PASSWORD_PROPERTY = "ssl.trustStore.password"
-SSL_TRUSTSTORE_TYPE_PROPERTY = "ssl.trustStore.type"
-
-# SSL common
-SSL_API = 'api.ssl'
-SSL_API_PORT = 'client.api.ssl.port'
-DEFAULT_SSL_API_PORT = 8443
-
-# Kerberos
-CHECK_AMBARI_KRB_JAAS_CONFIGURATION_PROPERTY = "kerberos.check.jaas.configuration"
-
-# JDK
-JDK_RELEASES="java.releases"
-
-if on_powerpc():
-  JDK_RELEASES += ".ppc64le"
-
-VIEWS_DIR_PROPERTY = "views.dir"
-
-ACTIVE_INSTANCE_PROPERTY = "active.instance"
-
-# web server startup timeout
-WEB_SERVER_STARTUP_TIMEOUT = "server.startup.web.timeout"
-
-#Common setup or upgrade message
-SETUP_OR_UPGRADE_MSG = "- If this is a new setup, then run the \"ambari-server setup\" command to create the user\n" \
-                       "- If this is an upgrade of an existing setup, run the \"ambari-server upgrade\" command.\n" \
-                       "Refer to the Ambari documentation for more information on setup and upgrade."
-
-DEFAULT_DB_NAME = "ambari"
-
-SECURITY_KEYS_DIR = "security.server.keys_dir"
-EXTENSION_PATH_PROPERTY = 'extensions.path'
-COMMON_SERVICES_PATH_PROPERTY = 'common.services.path'
-MPACKS_STAGING_PATH_PROPERTY = 'mpacks.staging.path'
-WEBAPP_DIR_PROPERTY = 'webapp.dir'
-SHARED_RESOURCES_DIR = 'shared.resources.dir'
-BOOTSTRAP_SCRIPT = 'bootstrap.script'
-CUSTOM_ACTION_DEFINITIONS = 'custom.action.definitions'
-BOOTSTRAP_SETUP_AGENT_SCRIPT = 'bootstrap.setup_agent.script'
-STACKADVISOR_SCRIPT = 'stackadvisor.script'
-PID_DIR_PROPERTY = 'pid.dir'
-SERVER_TMP_DIR_PROPERTY = "server.tmp.dir"
-REQUIRED_PROPERTIES = [OS_FAMILY_PROPERTY, OS_TYPE_PROPERTY, COMMON_SERVICES_PATH_PROPERTY, SERVER_VERSION_FILE_PATH,
-                       WEBAPP_DIR_PROPERTY, STACK_LOCATION_KEY, SECURITY_KEYS_DIR, JDBC_DATABASE_NAME_PROPERTY,
-                       NR_USER_PROPERTY, JAVA_HOME_PROPERTY, JDBC_PASSWORD_PROPERTY, SHARED_RESOURCES_DIR,
-                       JDBC_USER_NAME_PROPERTY, BOOTSTRAP_SCRIPT, RESOURCES_DIR_PROPERTY, CUSTOM_ACTION_DEFINITIONS,
-                       BOOTSTRAP_SETUP_AGENT_SCRIPT, STACKADVISOR_SCRIPT, BOOTSTRAP_DIR_PROPERTY, PID_DIR_PROPERTY,
-                       MPACKS_STAGING_PATH_PROPERTY]
-
-# if these properties are available 'ambari-server setup -s' is not triggered again.
-SETUP_DONE_PROPERTIES = [OS_FAMILY_PROPERTY, OS_TYPE_PROPERTY, JDK_NAME_PROPERTY, JDBC_DATABASE_PROPERTY,
-                         NR_USER_PROPERTY, PERSISTENCE_TYPE_PROPERTY
-]
-
-def get_default_views_dir():
-  return AmbariPath.get("/var/lib/ambari-server/resources/views")
-
-def get_conf_dir():
-  try:
-    conf_dir = os.environ[AMBARI_CONF_VAR]
-    return conf_dir
-  except KeyError:
-    default_conf_dir = AmbariPath.get("/etc/ambari-server/conf")
-    print_info_msg("{0} is not set, using default {1}".format(AMBARI_CONF_VAR, default_conf_dir))
-    return default_conf_dir
-
-def find_properties_file():
-  conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
-  if conf_file is None:
-    err = 'File %s not found in search path $%s: %s' % (AMBARI_PROPERTIES_FILE,
-          AMBARI_CONF_VAR, get_conf_dir())
-    print_error_msg (err)
-    raise FatalException(1, err)
-  else:
-    print_info_msg('Loading properties from {0}'.format(conf_file))
-  return conf_file
-
-# Load ambari properties and return dict with values
-def get_ambari_properties():
-  conf_file = find_properties_file()
-
-  # Try to read ambari properties file. It is OK to fail.
-  # Return -1 on failure.
-  properties = None
-  try:
-    properties = Properties()
-    with open(conf_file) as hfR:
-      properties.load(hfR)
-  except (Exception), e:
-    print_error_msg ('Could not read "%s": %s' % (conf_file, str(e)))
-    return -1
-
-  # Try to replace $ROOT with the value from the OS environment.
-  # OK to fail. Just print the exception and return the properties
-  # dictionary read above
-  try:
-    root_env = 'ROOT'
-    if root_env in os.environ:
-      root = os.environ["ROOT"].rstrip("/")
-    else:
-      root = ''
-
-    for k,v in properties.iteritems():
-      properties.__dict__[k] = v.replace("$ROOT", root)
-      properties._props[k] = v.replace("$ROOT", root)
-  except (Exception), e:
-    print_error_msg ('Could not replace %s in "%s": %s' %(conf_file, root_env, str(e)))
-  return properties
-
-class ServerDatabaseType(object):
-  internal = 0
-  remote = 1
-
-
-class ServerDatabaseEntry(object):
-  def __init__(self, name, title, db_type, aliases=None):
-    """
-    :type name str
-    :type title str
-    :type db_type int
-    :type aliases list
-    """
-    self.__name = name
-    self.__title = title
-    self.__type = db_type
-    if aliases is None:
-      aliases = []
-
-    self.__aliases = aliases
-
-  @property
-  def name(self):
-    return self.__name
-
-  @property
-  def title(self):
-    return self.__title
-
-  @property
-  def dbtype(self):
-    return self.__type
-
-  def __str__(self):
-    return self.name
-
-  def __eq__(self, other):
-    if other is None:
-      return False
-
-    if isinstance(other, ServerDatabaseEntry):
-      return self.name == other.name and self.dbtype == other.dbtype
-    elif isinstance(other, str):
-      return self.name == other or other in self.__aliases
-
-    raise RuntimeError("Not compatible type")
-
-
-class ServerDatabases(object):
-  postgres = ServerDatabaseEntry("postgres", "Postgres", ServerDatabaseType.remote)
-  oracle = ServerDatabaseEntry("oracle", "Oracle", ServerDatabaseType.remote)
-  mysql = ServerDatabaseEntry("mysql", "MySQL", ServerDatabaseType.remote)
-  mssql = ServerDatabaseEntry("mssql", "MSSQL", ServerDatabaseType.remote)
-  derby = ServerDatabaseEntry("derby", "Derby", ServerDatabaseType.remote)
-  sqlanywhere = ServerDatabaseEntry("sqlanywhere", "SQL Anywhere", ServerDatabaseType.remote)
-  postgres_internal = ServerDatabaseEntry("postgres", "Embedded Postgres", ServerDatabaseType.internal, aliases=['embedded'])
-
-  @staticmethod
-  def databases():
-    props = ServerDatabases.__dict__
-    r_props = []
-    for p in props:
-      if isinstance(props[p], ServerDatabaseEntry):
-        r_props.append(props[p].name)
-
-    return set(r_props)
-
-  @staticmethod
-  def match(name):
-    """
-    :type name str
-    :rtype ServerDatabaseEntry
-    """
-    props = ServerDatabases.__dict__
-
-    for p in props:
-      if isinstance(props[p], ServerDatabaseEntry):
-        if name == props[p]:
-          return props[p]
-
-    return None
-
-class ServerConfigDefaults(object):
-  def __init__(self):
-    properties = get_ambari_properties()
-    if properties == -1:
-      print_error_msg("Error getting ambari properties")
-  
-    self.JAVA_SHARE_PATH = "/usr/share/java"
-    self.SHARE_PATH = "/usr/share"
-    self.OUT_DIR = parse_log4j_file(get_conf_dir() + "/log4j.properties")['ambari.log.dir'].replace("//", "/")
-    self.SERVER_OUT_FILE = os.path.join(self.OUT_DIR, "ambari-server.out")
-    self.SERVER_LOG_FILE = os.path.join(self.OUT_DIR, "ambari-server.log")
-    self.DB_CHECK_LOG = os.path.join(self.OUT_DIR, "ambari-server-check-database.log")
-    self.ROOT_FS_PATH = os.sep
-
-    self.JDK_INSTALL_DIR = ""
-    self.JDK_SEARCH_PATTERN = ""
-    self.JAVA_EXE_SUBPATH = ""
-    self.JDK_SECURITY_DIR = os.path.join("jre", "lib", "security")
-    self.SERVER_RESOURCES_DIR = ""
-
-    # Configuration defaults
-    self.DEFAULT_CONF_DIR = ""
-    if properties == -1:
-      self.PID_DIR = AmbariPath.get(os.sep + os.path.join("var", "run", "ambari-server"))
-      self.BOOTSTRAP_DIR = AmbariPath.get(os.sep + os.path.join("var", "run", "ambari-server", "bootstrap"))
-      self.RECOMMENDATIONS_DIR = AmbariPath.get(os.sep + os.path.join("var", "run", "ambari-server", "stack-recommendations"))
-    else:
-      self.PID_DIR = properties.get_property(PID_DIR_PROPERTY)
-      self.BOOTSTRAP_DIR = properties.get_property(BOOTSTRAP_DIR_PROPERTY)
-      self.RECOMMENDATIONS_DIR = properties.get_property(RECOMMENDATIONS_DIR_PROPERTY)
-    
-    # this directories should be pre-created by user and be writable.
-    self.check_if_directories_writable([self.OUT_DIR, self.PID_DIR])
-    
-    self.DEFAULT_LIBS_DIR = ""
-    self.DEFAULT_VLIBS_DIR = ""
-
-    self.AMBARI_PROPERTIES_BACKUP_FILE = ""
-    self.AMBARI_ENV_BACKUP_FILE = ""
-    self.AMBARI_KRB_JAAS_LOGIN_BACKUP_FILE = ""
-
-    # ownership/permissions mapping
-    # path - permissions - user - group - recursive
-    # Rules are executed in the same order as they are listed
-    # {0} in user/group will be replaced by customized ambari-server username
-    self.NR_ADJUST_OWNERSHIP_LIST = []
-    self.NR_CHANGE_OWNERSHIP_LIST = []
-    self.NR_USERADD_CMD = ""
-
-    self.MASTER_KEY_FILE_PERMISSIONS = "640"
-    self.CREDENTIALS_STORE_FILE_PERMISSIONS = "640"
-    self.TRUST_STORE_LOCATION_PERMISSIONS = "640"
-
-    self.DEFAULT_DB_NAME = "ambari"
-
-    self.STACK_LOCATION_DEFAULT = ""
-    self.EXTENSION_LOCATION_DEFAULT = ""
-    self.COMMON_SERVICES_LOCATION_DEFAULT = ""
-    self.MPACKS_STAGING_LOCATION_DEFAULT = ""
-    self.SERVER_TMP_DIR_DEFAULT = ""
-    self.DASHBOARD_DIRNAME = "dashboards"
-
-    self.DEFAULT_VIEWS_DIR = ""
-
-    #keytool commands
-    self.keytool_bin_subpath = ""
-
-    #Standard messages
-    self.MESSAGE_SERVER_RUNNING_AS_ROOT = ""
-    self.MESSAGE_WARN_SETUP_NOT_ROOT = ""
-    self.MESSAGE_ERROR_RESET_NOT_ROOT = ""
-    self.MESSAGE_ERROR_UPGRADE_NOT_ROOT = ""
-    self.MESSAGE_CHECK_FIREWALL = ""
-    
-  def check_if_directories_writable(self, directories):
-    for directory in directories:
-      if not os.path.isdir(directory):
-        try:
-          os.makedirs(directory, 0755)
-        except Exception as ex:
-          # permission denied here is expected when ambari runs as non-root
-          print_error_msg("Could not create {0}. Reason: {1}".format(directory, str(ex)))
-      
-      if not os.path.isdir(directory) or not os.access(directory, os.W_OK):
-        raise FatalException(-1, "Unable to access {0} directory. Confirm the directory is created and is writable by Ambari Server user account '{1}'".format(directory, getpass.getuser()))
-
-@OsFamilyImpl(os_family=OSConst.WINSRV_FAMILY)
-class ServerConfigDefaultsWindows(ServerConfigDefaults):
-  def __init__(self):
-    super(ServerConfigDefaultsWindows, self).__init__()
-    self.JDK_INSTALL_DIR = "C:\\"
-    self.JDK_SEARCH_PATTERN = "j[2se|dk|re]*"
-    self.JAVA_EXE_SUBPATH = "bin\\java.exe"
-
-    # Configuration defaults
-    self.DEFAULT_CONF_DIR = "conf"
-    self.DEFAULT_LIBS_DIR = "lib"
-
-    self.AMBARI_PROPERTIES_BACKUP_FILE = "ambari.properties.backup"
-    self.AMBARI_KRB_JAAS_LOGIN_BACKUP_FILE = ""  # ToDo: should be adjusted later
-    # ownership/permissions mapping
-    # path - permissions - user - group - recursive
-    # Rules are executed in the same order as they are listed
-    # {0} in user/group will be replaced by customized ambari-server username
-    # The permissions are icacls
-    self.NR_ADJUST_OWNERSHIP_LIST = [
-      (self.OUT_DIR, "M", "{0}", True),  #0110-0100-0100 rw-r-r
-      (self.OUT_DIR, "F", "{0}", False), #0111-0101-0101 rwx-rx-rx
-      (self.PID_DIR, "M", "{0}", True),
-      (self.PID_DIR, "F", "{0}", False),
-      ("bootstrap", "F", "{0}", False),
-      ("ambari-env.cmd", "F", "{0}", False),
-      ("keystore", "M", "{0}", True),
-      ("keystore", "F", "{0}", False),
-      ("keystore\\db", "700", "{0}", False),
-      ("keystore\\db\\newcerts", "700", "{0}", False),
-      ("resources\\stacks", "755", "{0}", True),
-      ("resources\\custom_actions", "755", "{0}", True),
-      ("conf", "644", "{0}", True),
-      ("conf", "755", "{0}", False),
-      ("conf\\password.dat", "640", "{0}", False),
-      # Also, /etc/ambari-server/conf/password.dat
-      # is generated later at store_password_file
-    ]
-    self.NR_USERADD_CMD = "cmd /C net user {0} {1} /ADD"
-
-    self.SERVER_RESOURCES_DIR = "resources"
-    self.STACK_LOCATION_DEFAULT = "resources\\stacks"
-    self.EXTENSION_LOCATION_DEFAULT = "resources\\extensions"
-    self.COMMON_SERVICES_LOCATION_DEFAULT = "resources\\common-services"
-    self.MPACKS_STAGING_LOCATION_DEFAULT = "resources\\mpacks"
-    self.SERVER_TMP_DIR_DEFAULT = "data\\tmp"
-
-    self.DEFAULT_VIEWS_DIR = "resources\\views"
-
-    #keytool commands
-    self.keytool_bin_subpath = "bin\\keytool.exe"
-
-    #Standard messages
-    self.MESSAGE_SERVER_RUNNING_AS_ROOT = "Ambari Server running with 'root' privileges."
-    self.MESSAGE_WARN_SETUP_NOT_ROOT = "Ambari-server setup is run with root-level privileges, passwordless sudo access for some commands commands may be required"
-    self.MESSAGE_ERROR_RESET_NOT_ROOT = "Ambari-server reset must be run with administrator-level privileges"
-    self.MESSAGE_ERROR_UPGRADE_NOT_ROOT = "Ambari-server upgrade must be run with administrator-level privileges"
-    self.MESSAGE_CHECK_FIREWALL = "Checking firewall status..."
-
-@OsFamilyImpl(os_family=OsFamilyImpl.DEFAULT)
-class ServerConfigDefaultsLinux(ServerConfigDefaults):
-  def __init__(self):
-    super(ServerConfigDefaultsLinux, self).__init__()
-    # JDK
-    self.JDK_INSTALL_DIR = AmbariPath.get("/usr/jdk64")
-    self.JDK_SEARCH_PATTERN = "jdk*"
-    self.JAVA_EXE_SUBPATH = "bin/java"
-
-    # Configuration defaults
-    self.DEFAULT_CONF_DIR = AmbariPath.get("/etc/ambari-server/conf")
-    self.DEFAULT_LIBS_DIR = AmbariPath.get("/usr/lib/ambari-server")
-    self.DEFAULT_VLIBS_DIR = AmbariPath.get("/var/lib/ambari-server")
-
-    self.AMBARI_PROPERTIES_BACKUP_FILE = "ambari.properties.rpmsave"
-    self.AMBARI_ENV_BACKUP_FILE = "ambari-env.sh.rpmsave"
-    self.AMBARI_KRB_JAAS_LOGIN_BACKUP_FILE = "krb5JAASLogin.conf.rpmsave"
-    # ownership/permissions mapping
-    # path - permissions - user - group - recursive
-    # Rules are executed in the same order as they are listed
-    # {0} in user/group will be replaced by customized ambari-server username
-    self.NR_ADJUST_OWNERSHIP_LIST = [
-      (self.OUT_DIR + "/*", "644", "{0}", True),
-      (self.OUT_DIR, "755", "{0}", False),
-      (self.PID_DIR + "/*", "644", "{0}", True),
-      (self.PID_DIR, "755", "{0}", False),
-      (self.BOOTSTRAP_DIR, "755", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/ambari-env.sh"), "700", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/ambari-sudo.sh"), "700", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/keys/*"), "600", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/keys/"), "700", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/keys/db/"), "700", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/keys/db/newcerts/"), "700", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/keys/.ssh"), "700", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/resources/common-services/"), "755", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/resources/stacks/"), "755", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/resources/extensions/"), "755", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/resources/dashboards/"), "755", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/resources/mpacks/"), "755", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/resources/custom_actions/"), "755", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/resources/host_scripts/"), "755", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/resources/views/*"), "644", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/resources/views/"), "755", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/resources/views/work/"), "755", "{0}", True),
-      (AmbariPath.get("/etc/ambari-server/conf/*"), "644", "{0}", True),
-      (AmbariPath.get("/etc/ambari-server/conf/"), "755", "{0}", False),
-      (AmbariPath.get("/etc/ambari-server/conf/password.dat"), "640", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/keys/pass.txt"), "600", "{0}", False),
-      (AmbariPath.get("/etc/ambari-server/conf/ldap-password.dat"), "640", "{0}", False),
-      (self.RECOMMENDATIONS_DIR, "744", "{0}", True),
-      (self.RECOMMENDATIONS_DIR, "755", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/resources/data/"), "644", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/resources/data/"), "755", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/data/tmp/*"), "644", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/data/tmp/"), "755", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/data/cache/"), "600", "{0}", True),
-      (AmbariPath.get("/var/lib/ambari-server/data/cache/"), "700", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/resources/common-services/STORM/0.9.1/package/files/wordCount.jar"), "644", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/resources/stacks/HDP/2.1.GlusterFS/services/STORM/package/files/wordCount.jar"), "644", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/resources/stack-hooks/before-START/files/fast-hdfs-resource.jar"), "644", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/resources/stacks/HDP/2.1/services/SMARTSENSE/package/files/view/smartsense-ambari-view-1.4.0.0.60.jar"), "644", "{0}", False),
-      (AmbariPath.get("/var/lib/ambari-server/resources/stacks/HDP/3.0/hooks/before-START/files/fast-hdfs-resource.jar"), "644", "{0}", False),
-      # Also, /etc/ambari-server/conf/password.dat
-      # is generated later at store_password_file
-    ]
-    self.NR_CHANGE_OWNERSHIP_LIST = [
-      (AmbariPath.get("/var/lib/ambari-server"), "{0}", True),
-      (AmbariPath.get("/usr/lib/ambari-server"), "{0}", True),
-      (self.OUT_DIR, "{0}", True),
-      (self.PID_DIR, "{0}", True),
-      (AmbariPath.get("/etc/ambari-server"), "{0}", True),
-    ]
-    self.NR_USERADD_CMD = 'useradd -M --comment "{1}" ' \
-                 '--shell %s ' % locate_file('nologin', '/sbin') + ' -d ' + AmbariPath.get('/var/lib/ambari-server/keys/') + ' {0}'
-
-    self.SERVER_RESOURCES_DIR = AmbariPath.get("/var/lib/ambari-server/resources")
-    self.STACK_LOCATION_DEFAULT = AmbariPath.get("/var/lib/ambari-server/resources/stacks")
-    self.EXTENSION_LOCATION_DEFAULT = AmbariPath.get("/var/lib/ambari-server/resources/extensions")
-    self.COMMON_SERVICES_LOCATION_DEFAULT = AmbariPath.get("/var/lib/ambari-server/resources/common-services")
-    self.MPACKS_STAGING_LOCATION_DEFAULT = AmbariPath.get("/var/lib/ambari-server/resources/mpacks")
-    self.SERVER_TMP_DIR_DEFAULT = AmbariPath.get("/var/lib/ambari-server/data/tmp")
-
-    self.DEFAULT_VIEWS_DIR = AmbariPath.get("/var/lib/ambari-server/resources/views")
-
-    #keytool commands
-    self.keytool_bin_subpath = "bin/keytool"
-
-    #Standard messages
-    self.MESSAGE_SERVER_RUNNING_AS_ROOT = "Ambari Server running with administrator privileges."
-    self.MESSAGE_WARN_SETUP_NOT_ROOT = "Ambari-server setup is run with root-level privileges, passwordless sudo access for some commands commands may be required"
-    self.MESSAGE_ERROR_RESET_NOT_ROOT = "Ambari-server reset should be run with root-level privileges"
-    self.MESSAGE_ERROR_UPGRADE_NOT_ROOT = "Ambari-server upgrade must be run with root-level privileges"
-    self.MESSAGE_CHECK_FIREWALL = "Checking firewall status..."
-
-configDefaults = ServerConfigDefaults()
-
-# Security
-SECURITY_MASTER_KEY_LOCATION = "security.master.key.location"
-SECURITY_KEY_IS_PERSISTED = "security.master.key.ispersisted"
-SECURITY_KEY_ENV_VAR_NAME = "AMBARI_SECURITY_MASTER_KEY"
-SECURITY_MASTER_KEY_FILENAME = "master"
-SECURITY_IS_ENCRYPTION_ENABLED = "security.passwords.encryption.enabled"
-SECURITY_KERBEROS_JASS_FILENAME = "krb5JAASLogin.conf"
-
-SECURITY_PROVIDER_GET_CMD = "{0} -cp {1} " + \
-                            "org.apache.ambari.server.security.encryption" + \
-                            ".CredentialProvider GET {2} {3} {4} " + \
-                            "> " + configDefaults.SERVER_OUT_FILE + " 2>&1"
-
-SECURITY_PROVIDER_PUT_CMD = "{0} -cp {1} " + \
-                            "org.apache.ambari.server.security.encryption" + \
-                            ".CredentialProvider PUT {2} {3} {4} " + \
-                            "> " + configDefaults.SERVER_OUT_FILE + " 2>&1"
-
-SECURITY_PROVIDER_KEY_CMD = "{0} -cp {1} " + \
-                            "org.apache.ambari.server.security.encryption" + \
-                            ".MasterKeyServiceImpl {2} {3} {4} " + \
-                            "> " + configDefaults.SERVER_OUT_FILE + " 2>&1"
-
-
-
-def read_ambari_user():
-  '''
-  Reads ambari user from properties file
-  '''
-  properties = get_ambari_properties()
-  if properties != -1:
-    user = properties[NR_USER_PROPERTY]
-    if user:
-      return user
-  return None
-
-def get_is_active_instance():
-  # active.instance, if missing, will be considered to be true;
-  # if present, it should be explicitly set to "true" to set this as the active instance;
-  # any other value will be taken as a "false"
-  properties = get_ambari_properties()
-  # Get the value of active.instance.
-  active_instance_value = None
-  if properties != -1:
-    if ACTIVE_INSTANCE_PROPERTY in properties.propertyNames():
-      active_instance_value = properties[ACTIVE_INSTANCE_PROPERTY]
-
-  if active_instance_value is None:  # property is missing
-    is_active_instance = True
-  elif (active_instance_value == 'true'): # property is explicitly set to true
-    is_active_instance = True
-  else:  # any other value
-    is_active_instance = False
-
-  return is_active_instance
-
-def get_value_from_properties(properties, key, default=""):
-  try:
-    value = properties.get_property(key)
-    if not value:
-      value = default
-  except:
-    return default
-  return value
-
-def get_views_dir(properties):
-  views_dir = properties.get_property(VIEWS_DIR_PROPERTY)
-  if views_dir is None or views_dir == "":
-    views_dirs = glob.glob(AmbariPath.get("/var/lib/ambari-server/resources/views/work"))
-  else:
-    views_dirs = glob.glob(views_dir + "/work")
-  return views_dirs
-
-def get_admin_views_dir(properties):
-  views_dir = properties.get_property(VIEWS_DIR_PROPERTY)
-  if views_dir is None or views_dir == "":
-    views_dirs = glob.glob(AmbariPath.get("/var/lib/ambari-server/resources/views/work/ADMIN_VIEW*"))
-  else:
-    views_dirs = glob.glob(views_dir + "/work/ADMIN_VIEW*")
-  return views_dirs
-
-def get_views_jars(properties):
-  views_dir = properties.get_property(VIEWS_DIR_PROPERTY)
-  if views_dir is None or views_dir == "":
-    views_jars = glob.glob(AmbariPath.get("/var/lib/ambari-server/resources/views/*.jar"))
-  else:
-    views_jars = glob.glob(views_dir + "/*.jar")
-  return views_jars
-
-def get_is_secure(properties):
-  isSecure = properties.get_property(SECURITY_IS_ENCRYPTION_ENABLED)
-  isSecure = True if isSecure and isSecure.lower() == 'true' else False
-  return isSecure
-
-def get_is_persisted(properties):
-  keyLocation = get_master_key_location(properties)
-  masterKeyFile = search_file(SECURITY_MASTER_KEY_FILENAME, keyLocation)
-  isPersisted = True if masterKeyFile else False
-
-  return (isPersisted, masterKeyFile)
-
-def get_credential_store_location(properties):
-  store_loc = properties[SECURITY_KEYS_DIR]
-  if store_loc is None or store_loc == "":
-    store_loc = AmbariPath.get("/var/lib/ambari-server/keys/credentials.jceks")
-  else:
-    store_loc += os.sep + "credentials.jceks"
-  return store_loc
-
-def get_master_key_location(properties):
-  keyLocation = properties[SECURITY_MASTER_KEY_LOCATION]
-  if keyLocation is None or keyLocation == "":
-    keyLocation = properties[SECURITY_KEYS_DIR]
-  return keyLocation
-
-def get_ambari_server_ui_port(properties):
-  ambari_server_ui_port = CLIENT_API_PORT
-  client_api_port = properties.get_property(CLIENT_API_PORT_PROPERTY)
-  if client_api_port:
-    ambari_server_ui_port = client_api_port
-  api_ssl = properties.get_property(SSL_API)
-  if api_ssl and str(api_ssl).lower() == "true":
-    ambari_server_ui_port = DEFAULT_SSL_API_PORT
-    ssl_api_port = properties.get_property(SSL_API_PORT)
-    if ssl_api_port:
-      ambari_server_ui_port = ssl_api_port
-  return ambari_server_ui_port
-
-# Copy file to /tmp and save with file.# (largest # is latest file)
-def backup_file_in_temp(filePath):
-  if filePath is not None:
-    tmpDir = tempfile.gettempdir()
-    back_up_file_count = len(glob.glob1(tmpDir, AMBARI_PROPERTIES_FILE + "*"))
-    try:
-      shutil.copyfile(filePath, tmpDir + os.sep +
-                      AMBARI_PROPERTIES_FILE + "." + str(back_up_file_count + 1))
-    except (Exception), e:
-      print_error_msg('Could not backup file in temp "%s": %s' % (
-        back_up_file_count, str(e)))
-  return 0
-
-def get_ambari_version(properties):
-  """
-  :param properties: Ambari properties
-  :return: Return a string of the ambari version. When comparing versions, please use "compare_versions" function.
-  """
-  version = None
-  try:
-    server_version_file_path = properties[SERVER_VERSION_FILE_PATH]
-    if server_version_file_path and os.path.exists(server_version_file_path):
-      with open(server_version_file_path, 'r') as file:
-        version = file.read().strip()
-  except:
-    print_error_msg("Error getting ambari version")
-  return version
-
-def get_db_type(properties):
-  """
-  :rtype ServerDatabaseEntry
-  """
-  db_type = None
-  persistence_type = properties[PERSISTENCE_TYPE_PROPERTY]
-
-  if properties[JDBC_DATABASE_PROPERTY]:
-    db_type = ServerDatabases.match(properties[JDBC_DATABASE_PROPERTY])
-    if db_type == ServerDatabases.postgres and persistence_type == "local":
-      db_type = ServerDatabases.postgres_internal
-
-  if properties[JDBC_URL_PROPERTY] and db_type is None:
-    jdbc_url = properties[JDBC_URL_PROPERTY].lower()
-    if str(ServerDatabases.postgres) in jdbc_url:
-      db_type = ServerDatabases.postgres
-    elif str(ServerDatabases.oracle) in jdbc_url:
-      db_type = ServerDatabases.oracle
-    elif str(ServerDatabases.mysql) in jdbc_url:
-      db_type = ServerDatabases.mysql
-    elif str(ServerDatabases.mssql) in jdbc_url:
-      db_type = ServerDatabases.mssql
-    elif str(ServerDatabases.derby) in jdbc_url:
-      db_type = ServerDatabases.derby
-    elif str(ServerDatabases.sqlanywhere) in jdbc_url:
-      db_type = ServerDatabases.sqlanywhere
-
-  if persistence_type == "local" and db_type is None:
-    db_type = ServerDatabases.postgres_internal
-
-  return db_type
-
-def check_database_name_property(upgrade=False):
-  """
-  :param upgrade: If Ambari is being upgraded.
-  :return:
-  """
-  properties = get_ambari_properties()
-  if properties == -1:
-    print_error_msg("Error getting ambari properties")
-    return -1
-
-  version = get_ambari_version(properties)
-  if upgrade and (properties[JDBC_DATABASE_PROPERTY] not in ServerDatabases.databases()
-                    or properties.has_key(JDBC_RCA_SCHEMA_PROPERTY)):
-    # This code exists for historic reasons in which property names changed from Ambari 1.6.1 to 1.7.0
-    persistence_type = properties[PERSISTENCE_TYPE_PROPERTY]
-    if persistence_type == "remote":
-      db_name = properties[JDBC_RCA_SCHEMA_PROPERTY]  # this was a property in Ambari 1.6.1, but not after 1.7.0
-      if db_name:
-        write_property(JDBC_DATABASE_NAME_PROPERTY, db_name)
-
-      # If DB type is missing, attempt to reconstruct it from the JDBC URL
-      db_type = properties[JDBC_DATABASE_PROPERTY]
-      if db_type is None or db_type.strip().lower() not in ServerDatabases.databases():
-        db_type = get_db_type(properties).name
-        if db_type:
-          write_property(JDBC_DATABASE_PROPERTY, db_type)
-
-      properties = get_ambari_properties()
-    elif persistence_type == "local":
-      # Ambari 1.6.1, had "server.jdbc.database" as the DB name, and the
-      # DB type was assumed to be "postgres" if was embedded ("local")
-      db_name = properties[JDBC_DATABASE_PROPERTY]
-      if db_name:
-        write_property(JDBC_DATABASE_NAME_PROPERTY, db_name)
-        write_property(JDBC_DATABASE_PROPERTY, "postgres")
-        properties = get_ambari_properties()
-
-  dbname = properties[JDBC_DATABASE_NAME_PROPERTY]
-  if dbname is None or dbname == "":
-    err = "DB Name property not set in config file.\n" + SETUP_OR_UPGRADE_MSG
-    raise FatalException(-1, err)
-
-def update_database_name_property(upgrade=False):
-  try:
-    check_database_name_property(upgrade)
-  except FatalException:
-    properties = get_ambari_properties()
-    if properties == -1:
-      err = "Error getting ambari properties"
-      raise FatalException(-1, err)
-    print_warning_msg("{0} property isn't set in {1} . Setting it to default value - {3}".format(JDBC_DATABASE_NAME_PROPERTY, AMBARI_PROPERTIES_FILE, configDefaults.DEFAULT_DB_NAME))
-    properties.process_pair(JDBC_DATABASE_NAME_PROPERTY, configDefaults.DEFAULT_DB_NAME)
-    conf_file = find_properties_file()
-    try:
-      with open(conf_file, "w") as hfW:
-        properties.store(hfW)
-    except Exception, e:
-      err = 'Could not write ambari config file "%s": %s' % (conf_file, e)
-      raise FatalException(-1, err)
-
-
-def encrypt_password(alias, password, options):
-  properties = get_ambari_properties()
-  if properties == -1:
-    raise FatalException(1, None)
-  return get_encrypted_password(alias, password, properties, options)
-
-def get_encrypted_password(alias, password, properties, options):
-  isSecure = get_is_secure(properties)
-  (isPersisted, masterKeyFile) = get_is_persisted(properties)
-  if isSecure:
-    masterKey = None
-    if not masterKeyFile:
-      # Encryption enabled but no master key file found
-      masterKey = get_original_master_key(properties, options)
-
-    retCode = save_passwd_for_alias(alias, password, masterKey)
-    if retCode != 0:
-      print_error_msg ('Failed to save secure password!')
-      return password
-    else:
-      return get_alias_string(alias)
-
-  return password
-
-
-def is_alias_string(passwdStr):
-  regex = re.compile("\$\{alias=[\w\.]+\}")
-  # Match implies string at beginning of word
-  r = regex.match(passwdStr)
-  if r is not None:
-    return True
-  else:
-    return False
-
-def get_alias_string(alias):
-  return "${alias=" + alias + "}"
-
-def get_alias_from_alias_string(aliasStr):
-  return aliasStr[8:-1]
-
-def read_passwd_for_alias(alias, masterKey="", options=None):
-  if alias:
-    jdk_path = find_jdk()
-    if jdk_path is None:
-      print_error_msg("No JDK found, please run the \"setup\" "
-                      "command to install a JDK automatically or install any "
-                      "JDK manually to {0}".format(configDefaults.JDK_INSTALL_DIR))
-      return 1
-
-    tempFileName = "ambari.passwd"
-    passwd = ""
-    tempDir = tempfile.gettempdir()
-    #create temporary file for writing
-    tempFilePath = tempDir + os.sep + tempFileName
-    with open(tempFilePath, 'w+'):
-      os.chmod(tempFilePath, stat.S_IREAD | stat.S_IWRITE)
-
-    if options is not None and options.master_key is not None and options.master_key:
-      masterKey = options.master_key
-    if masterKey is None or masterKey == "":
-      masterKey = "None"
-
-    serverClassPath = ambari_server.serverClassPath.ServerClassPath(get_ambari_properties(), None)
-    command = SECURITY_PROVIDER_GET_CMD.format(get_java_exe_path(),
-                                               serverClassPath.get_full_ambari_classpath_escaped_for_shell(), alias, tempFilePath, masterKey)
-    (retcode, stdout, stderr) = run_os_command(command)
-    print_info_msg("Return code from credential provider get passwd: {0}".format(str(retcode)))
-    if retcode != 0:
-      print_error_msg ('ERROR: Unable to read password from store. alias = {0}'.format(alias))
-    else:
-      with open(tempFilePath, 'r') as hfRTemp:
-        passwd = hfRTemp.read()
-      # Remove temporary file
-    os.remove(tempFilePath)
-    return passwd
-  else:
-    print_error_msg("Alias is unreadable.")
-
-def decrypt_password_for_alias(properties, alias, options=None):
-  isSecure = get_is_secure(properties)
-  if isSecure:
-    masterKey = None
-    (isPersisted, masterKeyFile) = get_is_persisted(properties)
-    if not masterKeyFile:
-      # Encryption enabled but no master key file found
-      masterKey = get_original_master_key(properties, options)
-    return read_passwd_for_alias(alias, masterKey, options)
-  else:
-    return alias
-
-def save_passwd_for_alias(alias, passwd, masterKey=""):
-  if alias and passwd:
-    jdk_path = find_jdk()
-    if jdk_path is None:
-      print_error_msg("No JDK found, please run the \"setup\" "
-                      "command to install a JDK automatically or install any "
-                      "JDK manually to {0}".format(configDefaults.JDK_INSTALL_DIR))
-      return 1
-
-    if masterKey is None or masterKey == "":
-      masterKey = "None"
-
-    serverClassPath = ambari_server.serverClassPath.ServerClassPath(get_ambari_properties(), None)
-    command = SECURITY_PROVIDER_PUT_CMD.format(get_java_exe_path(),
-                                               serverClassPath.get_full_ambari_classpath_escaped_for_shell(), alias, passwd, masterKey)
-    (retcode, stdout, stderr) = run_os_command(command)
-    print_info_msg("Return code from credential provider save passwd: {0}".format(str(retcode)))
-    return retcode
-  else:
-    print_error_msg("Alias or password is unreadable.")
-
-
-def get_pass_file_path(conf_file, filename):
-  return os.path.join(os.path.dirname(conf_file), filename)
-
-def store_password_file(password, filename):
-  conf_file = find_properties_file()
-  passFilePath = get_pass_file_path(conf_file, filename)
-
-  with open(passFilePath, 'w+') as passFile:
-    passFile.write(password)
-  print_info_msg("Adjusting filesystem permissions")
-  ambari_user = read_ambari_user()
-  if ambari_user: # at the first install ambari_user can be None. Which is fine since later on password.dat is chowned with the correct ownership.
-    set_file_permissions(passFilePath, "660", ambari_user, False)
-
-  #Windows paths need double backslashes, otherwise the Ambari server deserializer will think the single \ are escape markers
-  return passFilePath.replace('\\', '\\\\')
-
-def remove_password_file(filename):
-  conf_file = find_properties_file()
-  passFilePath = os.path.join(os.path.dirname(conf_file),
-                              filename)
-
-  if os.path.exists(passFilePath):
-    try:
-      os.remove(passFilePath)
-    except Exception, e:
-      print_warning_msg('Unable to remove password file: {0}'.format(str(e)))
-      return 1
-  pass
-  return 0
-
-
-def get_web_server_startup_timeout(properties):
-  """
-  Gets the time, in seconds, that the startup script should wait for the web server to bind to
-  the configured port. If this value is too low, then the startup script will return an
-  error code even though Ambari is actually starting up.
-  :param properties:
-  :return: The timeout value, in seconds. The default is 50.
-  """
-  # get the timeout property and strip it if it exists
-  timeout = properties[WEB_SERVER_STARTUP_TIMEOUT]
-  timeout = None if timeout is None else timeout.strip()
-
-  if timeout is None or timeout == "":
-    timeout = 50
-  else:
-    timeout = int(timeout)
-  return timeout
-
-
-def get_original_master_key(properties, options = None):
-  input = True
-  masterKey = None
-  while(input):
-    try:
-      if options is not None and options.master_key is not None and options.master_key:
-        masterKey = options.master_key
-      if masterKey is None:
-        masterKey = get_validated_string_input('Enter current Master Key: ',
-                                               "", ".*", "", True, False)
-    except KeyboardInterrupt:
-      print_warning_msg('Exiting...')
-      sys.exit(1)
-
-    # Find an alias that exists
-    alias = None
-    property = properties.get_property(JDBC_PASSWORD_PROPERTY)
-    if property and is_alias_string(property):
-      alias = JDBC_RCA_PASSWORD_ALIAS
-
-    if not alias:
-      property = properties.get_property(LDAP_MGR_PASSWORD_PROPERTY)
-      if property and is_alias_string(property):
-        alias = LDAP_MGR_PASSWORD_ALIAS
-
-    if not alias:
-      property = properties.get_property(SSL_TRUSTSTORE_PASSWORD_PROPERTY)
-      if property and is_alias_string(property):
-        alias = SSL_TRUSTSTORE_PASSWORD_ALIAS
-
-    # Decrypt alias with master to validate it, if no master return
-    if alias and masterKey:
-      password = read_passwd_for_alias(alias, masterKey, options)
-      if not password:
-        print_error_msg ("ERROR: Master key does not match.")
-        continue
-
-    input = False
-
-  return masterKey
-
-
-# Load database connection properties from conf file
-def parse_properties_file(args):
-  properties = get_ambari_properties()
-  if properties == -1:
-    print_error_msg("Error getting ambari properties")
-    return -1
-
-  args.server_version_file_path = properties[SERVER_VERSION_FILE_PATH]
-  args.persistence_type = properties[PERSISTENCE_TYPE_PROPERTY]
-  args.jdbc_url = properties[JDBC_URL_PROPERTY]
-
-  args.dbms = properties[JDBC_DATABASE_PROPERTY]
-  if not args.persistence_type:
-    args.persistence_type = "local"
-
-  if args.persistence_type == 'remote':
-    args.database_host = properties[JDBC_HOSTNAME_PROPERTY]
-    args.database_port = properties[JDBC_PORT_PROPERTY]
-
-  args.database_name = properties[JDBC_DATABASE_NAME_PROPERTY]
-  args.database_username = properties[JDBC_USER_NAME_PROPERTY]
-  args.postgres_schema = properties[JDBC_POSTGRES_SCHEMA_PROPERTY] \
-    if JDBC_POSTGRES_SCHEMA_PROPERTY in properties.propertyNames() else None
-  args.database_password_file = properties[JDBC_PASSWORD_PROPERTY]
-  if args.database_password_file:
-    if not is_alias_string(args.database_password_file):
-      with open(properties[JDBC_PASSWORD_PROPERTY]) as hfDbPwd:
-        args.database_password = hfDbPwd.read()
-    else:
-      args.database_password = args.database_password_file
-  return 0
-
-def is_jaas_keytab_exists(conf_file):
-  with open(conf_file, "r") as f:
-    lines = f.read()
-
-  match = re.search("keyTab=(.*)$", lines, re.MULTILINE)
-  return os.path.exists(match.group(1).strip("\"").strip())
-
-def update_krb_jaas_login_properties():
-  """
-  Update configuration files
-  :return: int -2 - skipped, -1 - error, 0 - successful
-  """
-  prev_conf_file = search_file(configDefaults.AMBARI_KRB_JAAS_LOGIN_BACKUP_FILE, get_conf_dir())
-  conf_file = search_file(AMBARI_KRB_JAAS_LOGIN_FILE, get_conf_dir())
-
-  # check if source and target files exists, if not - skip copy action
-  if prev_conf_file is None or conf_file is None:
-    return -2
-
-  # if rpmsave file contains invalid keytab, we can skip restoring
-  if not is_jaas_keytab_exists(prev_conf_file):
-    return -2
-
-  try:
-    # restore original file, destination arg for rename func shouldn't exists
-    os.remove(conf_file)
-    os.rename(prev_conf_file, conf_file)
-    print_warning_msg("Original file %s kept" % AMBARI_KRB_JAAS_LOGIN_FILE)
-  except OSError as e:
-    print_error_msg ("Couldn't move %s file: %s" % (prev_conf_file, str(e)))
-    return -1
-
-  return 0
-
-def update_ambari_env():
-  prev_env_file = search_file(configDefaults.AMBARI_ENV_BACKUP_FILE, configDefaults.DEFAULT_VLIBS_DIR)
-  env_file = search_file(AMBARI_ENV_FILE, configDefaults.DEFAULT_VLIBS_DIR)
-
-  # Previous env file does not exist
-  if (not prev_env_file) or (prev_env_file is None):
-    print ("INFO: Can not find %s file from previous version, skipping restore of environment settings. "
-           "%s may not include any user customization.") % (configDefaults.AMBARI_ENV_BACKUP_FILE, AMBARI_ENV_FILE)
-    return 0
-
-  try:
-    if env_file is not None:
-      os.remove(env_file)
-      os.rename(prev_env_file, env_file)
-      print ("INFO: Original file %s kept") % (AMBARI_ENV_FILE)
-  except OSError as e:
-    print_error_msg ( "Couldn't move %s file: %s" % (prev_env_file, str(e)))
-    return -1
-
-  return 0
-
-def update_ambari_properties():
-  prev_conf_file = search_file(configDefaults.AMBARI_PROPERTIES_BACKUP_FILE, get_conf_dir())
-  conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
-
-  # Previous config file does not exist
-  if (not prev_conf_file) or (prev_conf_file is None):
-    print_warning_msg("Can not find %s file from previous version, skipping import of settings" % configDefaults.AMBARI_PROPERTIES_BACKUP_FILE)
-    return 0
-
-  # ambari.properties file does not exists
-  if conf_file is None:
-    print_error_msg("Can't find %s file" % AMBARI_PROPERTIES_FILE)
-    return -1
-
-  with open(prev_conf_file) as hfOld:
-    try:
-      old_properties = Properties()
-      old_properties.load(hfOld)
-    except Exception, e:
-      print_error_msg ('Could not read "%s": %s' % (prev_conf_file, str(e)))
-      return -1
-
-  try:
-    new_properties = Properties()
-    with open(conf_file) as hfNew:
-      new_properties.load(hfNew)
-
-    for prop_key, prop_value in old_properties.getPropertyDict().items():
-      if "agent.fqdn.service.url" == prop_key:
-        # what is agent.fqdn property in ambari.props?
-        new_properties.process_pair(GET_FQDN_SERVICE_URL, prop_value)
-      elif "server.os_type" == prop_key:
-        new_properties.process_pair(OS_TYPE_PROPERTY, OS_FAMILY + OS_VERSION)
-      elif JDK_RELEASES == prop_key:
-        # don't replace new jdk releases with old releases, because they can be updated
-        pass
-      else:
-        new_properties.process_pair(prop_key, prop_value)
-
-    # Adding custom user name property if it is absent
-    # In previous versions without custom user support server was started as
-    # "root" anyway so it's a reasonable default
-    if NR_USER_PROPERTY not in new_properties.keys():
-      new_properties.process_pair(NR_USER_PROPERTY, "root")
-
-    # update the os. In case os detection routine changed
-    new_properties.process_pair(OS_FAMILY_PROPERTY, OS_FAMILY + OS_VERSION)
-
-    with open(conf_file, 'w') as hfW:
-      new_properties.store(hfW)
-
-  except Exception, e:
-    print_error_msg ('Could not write "%s": %s' % (conf_file, str(e)))
-    return -1
-
-  timestamp = datetime.datetime.now()
-  fmt = '%Y%m%d%H%M%S'
-  new_conf_file = prev_conf_file + '.' + timestamp.strftime(fmt)
-  try:
-    os.rename(prev_conf_file, new_conf_file)
-  except Exception, e:
-    print_error_msg ('Could not rename "%s" to "%s": %s' % (prev_conf_file, new_conf_file, str(e)))
-    #Not critical, move on
-
-  return 0
-
-# update properties in a section-less properties file
-# Cannot use ConfigParser due to bugs in version 2.6
-def update_properties(propertyMap):
-  conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
-  backup_file_in_temp(conf_file)
-  if propertyMap is not None and conf_file is not None:
-    properties = Properties()
-    try:
-      with open(conf_file, 'r') as file:
-        properties.load(file)
-    except (Exception), e:
-      print_error_msg('Could not read "%s": %s' % (conf_file, e))
-      return -1
-
-    for key in propertyMap.keys():
-      properties.removeOldProp(key)
-      properties.process_pair(key, str(propertyMap[key]))
-
-    for key in properties.keys():
-      if not propertyMap.has_key(key):
-        properties.removeOldProp(key)
-
-    with open(conf_file, 'w') as file:
-      properties.store_ordered(file)
-
-  return 0
-
-def update_properties_2(properties, propertyMap):
-  conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
-  backup_file_in_temp(conf_file)
-  if conf_file is not None:
-    if propertyMap is not None:
-      for key in propertyMap.keys():
-        properties.removeOldProp(key)
-        properties.process_pair(key, str(propertyMap[key]))
-      pass
-
-    with open(conf_file, 'w') as file:
-      properties.store_ordered(file)
-    pass
-  pass
-
-def write_property(key, value):
-  conf_file = find_properties_file()
-  properties = Properties()
-  try:
-    with open(conf_file, "r") as hfR:
-      properties.load(hfR)
-  except Exception, e:
-    print_error_msg('Could not read ambari config file "%s": %s' % (conf_file, e))
-    return -1
-  properties.process_pair(key, value)
-  try:
-    with open(conf_file, 'w') as hfW:
-      properties.store(hfW)
-  except Exception, e:
-    print_error_msg('Could not write ambari config file "%s": %s' % (conf_file, e))
-    return -1
-  return 0
-
-#
-# Checks if options determine local DB configuration
-#
-def is_local_database(args):
-  try:
-    return args.persistence_type == 'local'
-  except AttributeError:
-    return False
-
-
-def update_debug_mode():
-  debug_mode = get_debug_mode()
-  # The command-line settings supersede the ones in ambari.properties
-  if not debug_mode & 1:
-    properties = get_ambari_properties()
-    if properties == -1:
-      print_error_msg("Error getting ambari properties")
-      return -1
-
-    if get_value_from_properties(properties, DEBUG_MODE_KEY, False):
-      debug_mode = debug_mode | 1
-    if get_value_from_properties(properties, SUSPEND_START_MODE_KEY, False):
-      debug_mode = debug_mode | 2
-
-    set_debug_mode(debug_mode)
-
-#
-### JDK ###
-#
-
-#
-# Describes the JDK configuration data, necessary for download and installation
-#
-class JDKRelease:
-  name = ""
-  desc = ""
-  url = ""
-  dest_file = ""
-  jcpol_url = "http://public-repo-1.hortonworks.com/ARTIFACTS/UnlimitedJCEPolicyJDK7.zip"
-  dest_jcpol_file = ""
-  inst_dir = ""
-
-  def __init__(self, i_name, i_desc, i_url, i_dest_file, i_jcpol_url, i_dest_jcpol_file, i_inst_dir, i_reg_exp):
-    if i_name is None or i_name is "":
-      raise FatalException(-1, "Invalid JDK name: " + (i_desc or ""))
-    self.name = i_name
-    if i_desc is None or i_desc is "":
-      self.desc = self.name
-    else:
-      self.desc = i_desc
-    if i_url is None or i_url is "":
-      raise FatalException(-1, "Invalid URL for JDK " + i_name)
-    self.url = i_url
-    if i_dest_file is None or i_dest_file is "":
-      self.dest_file = i_name + ".exe"
-    else:
-      self.dest_file = i_dest_file
-    if not (i_jcpol_url is None or i_jcpol_url is ""):
-      self.jcpol_url = i_jcpol_url
-    if i_dest_jcpol_file is None or i_dest_jcpol_file is "":
-      self.dest_jcpol_file = "jcpol-" + i_name + ".zip"
-    else:
-      self.dest_jcpol_file = i_dest_jcpol_file
-    if i_inst_dir is None or i_inst_dir is "":
-      self.inst_dir = os.path.join(configDefaults.JDK_INSTALL_DIR, i_desc)
-    else:
-      self.inst_dir = i_inst_dir
-    if i_reg_exp is None or i_reg_exp is "":
-      raise FatalException(-1, "Invalid output parsing regular expression for JDK " + i_name)
-    self.reg_exp = i_reg_exp
-
-  @classmethod
-  def from_properties(cls, properties, section_name):
-    (desc, url, dest_file, jcpol_url, jcpol_file, inst_dir, reg_exp) = JDKRelease.__load_properties(properties, section_name)
-    cls = JDKRelease(section_name, desc, url, dest_file, jcpol_url, jcpol_file, inst_dir, reg_exp)
-    return cls
-
-  @staticmethod
-  def __load_properties(properties, section_name):
-    if section_name is None or section_name is "":
-      raise FatalException(-1, "Invalid properties section: " + ("(empty)" if section_name is None else ""))
-    if(properties.has_key(section_name + ".desc")):   #Not critical
-      desc = properties[section_name + ".desc"]
-    else:
-      desc = section_name
-    if not properties.has_key(section_name + ".url"):
-      raise FatalException(-1, "Invalid JDK URL in the properties section: " + section_name)
-    url = properties[section_name + ".url"]      #Required
-    if not properties.has_key(section_name + ".re"):
-      raise FatalException(-1, "Invalid JDK output parsing regular expression in the properties section: " + section_name)
-    reg_exp = properties[section_name + ".re"]      #Required
-    if(properties.has_key(section_name + ".dest-file")):   #Not critical
-      dest_file = properties[section_name + ".dest-file"]
-    else:
-      dest_file = section_name + ".exe"
-    if(properties.has_key(section_name + ".jcpol-url")):   #Not critical
-      jcpol_url = properties[section_name + ".jcpol-url"]
-    else:
-      jcpol_url = None
-    if(properties.has_key(section_name + ".jcpol-file")):   #Not critical
-      jcpol_file = properties[section_name + ".jcpol-file"]
-    else:
-      jcpol_file = None
-    if(properties.has_key(section_name + ".home")):   #Not critical
-      inst_dir = properties[section_name + ".home"]
-    else:
-      inst_dir = "C:\\" + section_name
-    return (desc, url, dest_file, jcpol_url, jcpol_file, inst_dir, reg_exp)
-  pass
-
-def get_JAVA_HOME():
-  properties = get_ambari_properties()
-  if properties == -1:
-    print_error_msg("Error getting ambari properties")
-    return None
-
-  java_home = properties[JAVA_HOME_PROPERTY]
-
-  if (not 0 == len(java_home)) and (os.path.exists(java_home)):
-    return java_home
-
-  return None
-
-#
-# Checks jdk path for correctness
-#
-def validate_jdk(jdk_path):
-  if jdk_path:
-    if os.path.exists(jdk_path):
-      java_exe_path = os.path.join(jdk_path, configDefaults.JAVA_EXE_SUBPATH)
-      if os.path.exists(java_exe_path) and os.path.isfile(java_exe_path):
-        return True
-  return False
-
-#
-# Finds the available JDKs.
-#
-def find_jdk():
-  jdkPath = get_JAVA_HOME()
-  if jdkPath:
-    if validate_jdk(jdkPath):
-      return jdkPath
-  print("INFO: Looking for available JDKs at {0}".format(configDefaults.JDK_INSTALL_DIR))
-  jdks = glob.glob(os.path.join(configDefaults.JDK_INSTALL_DIR, configDefaults.JDK_SEARCH_PATTERN))
-  #[fbarca] Use the newest JDK
-  jdks.sort(None, None, True)
-  print_info_msg("Found: {0}".format(str(jdks)))
-  if len(jdks) == 0:
-    return
-  for jdkPath in jdks:
-    print "INFO: Trying to use JDK {0}".format(jdkPath)
-    if validate_jdk(jdkPath):
-      print "INFO: Selected JDK {0}".format(jdkPath)
-      return jdkPath
-    else:
-      print_error_msg ("JDK {0} is invalid".format(jdkPath))
-  return
-
-def get_java_exe_path():
-  jdkPath = find_jdk()
-  if jdkPath:
-    java_exe = os.path.join(jdkPath, configDefaults.JAVA_EXE_SUBPATH)
-    return java_exe
-  return
-
-
-#
-# Server resource files location
-#
-def get_resources_location(properties):
-  err = 'Invalid directory'
-  try:
-    resources_dir = properties[RESOURCES_DIR_PROPERTY]
-    if not resources_dir:
-      resources_dir = configDefaults.SERVER_RESOURCES_DIR
-  except (KeyError), e:
-    err = 'Property ' + str(e) + ' is not defined at ' + properties.fileName
-    resources_dir = configDefaults.SERVER_RESOURCES_DIR
-
-  if not os.path.exists(os.path.abspath(resources_dir)):
-    msg = 'Resources dir ' + resources_dir + ' is incorrectly configured: ' + err
-    raise FatalException(1, msg)
-
-  return resources_dir
-
-#
-# Stack location
-#
-def get_stack_location(properties):
-  stack_location = properties[STACK_LOCATION_KEY]
-  if not stack_location:
-    stack_location = configDefaults.STACK_LOCATION_DEFAULT
-  return stack_location
-
-#
-# Extension location
-#
-def get_extension_location(properties):
-  extension_location = properties[EXTENSION_PATH_PROPERTY]
-  if not extension_location:
-    extension_location = configDefaults.EXTENSION_LOCATION_DEFAULT
-  return extension_location
-
-#
-# Common services location
-#
-def get_common_services_location(properties):
-  common_services_location = properties[COMMON_SERVICES_PATH_PROPERTY]
-  if not common_services_location:
-    common_services_location = configDefaults.COMMON_SERVICES_LOCATION_DEFAULT
-  return common_services_location
-
-#
-# Management packs staging location
-#
-def get_mpacks_staging_location(properties):
-  mpacks_staging_location = properties[MPACKS_STAGING_PATH_PROPERTY]
-  if not mpacks_staging_location:
-    mpacks_staging_location = configDefaults.MPACKS_STAGING_LOCATION_DEFAULT
-  return mpacks_staging_location
-
-
-#
-# Dashboard location
-#
-def get_dashboard_location(properties):
-  resources_dir = get_resources_location(properties)
-  dashboard_location = os.path.join(resources_dir, configDefaults.DASHBOARD_DIRNAME)
-  return dashboard_location
-
-#
-# Server temp location
-#
-def get_server_temp_location(properties):
-  server_tmp_dir = properties[SERVER_TMP_DIR_PROPERTY]
-  if not server_tmp_dir:
-    server_tmp_dir = configDefaults.SERVER_TMP_DIR_DEFAULT
-  return server_tmp_dir
-
-def get_missing_properties(properties, property_set=REQUIRED_PROPERTIES):
-  missing_propertiers = []
-  for property in property_set:
-    value = properties[property]
-    if not value:
-      missing_propertiers.append(property)
-
-  return missing_propertiers

http://git-wip-us.apache.org/repos/asf/ambari/blob/f331f86d/ambari-server/src/main/python/ambari_server/serverSetup.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/serverSetup.py b/ambari-server/src/main/python/ambari_server/serverSetup.py
index 5c016c5..7063175 100644
--- a/ambari-server/src/main/python/ambari_server/serverSetup.py
+++ b/ambari-server/src/main/python/ambari_server/serverSetup.py
@@ -38,11 +38,11 @@ from ambari_commons.str_utils import compress_backslashes
 from ambari_server.dbConfiguration import DBMSConfigFactory, TAR_GZ_ARCHIVE_TYPE, default_connectors_map, check_jdbc_drivers
 from ambari_server.serverConfiguration import configDefaults, JDKRelease, \
   get_ambari_properties, get_is_secure, get_is_persisted, get_java_exe_path, get_JAVA_HOME, get_missing_properties, \
-  get_resources_location, get_value_from_properties, read_ambari_user, update_properties, validate_jdk, write_property, \
+  get_resources_location, get_value_from_properties, read_ambari_user, update_properties, validate_jdk, write_property, prompt_gpl_agreement,\
   JAVA_HOME, JAVA_HOME_PROPERTY, JCE_NAME_PROPERTY, JDBC_RCA_URL_PROPERTY, JDBC_URL_PROPERTY, \
   JDK_NAME_PROPERTY, JDK_RELEASES, NR_USER_PROPERTY, OS_FAMILY, OS_FAMILY_PROPERTY, OS_TYPE, OS_TYPE_PROPERTY, OS_VERSION, \
   VIEWS_DIR_PROPERTY, JDBC_DATABASE_PROPERTY, JDK_DOWNLOAD_SUPPORTED_PROPERTY, JCE_DOWNLOAD_SUPPORTED_PROPERTY, SETUP_DONE_PROPERTIES, \
-  STACK_JAVA_HOME_PROPERTY, STACK_JDK_NAME_PROPERTY, STACK_JCE_NAME_PROPERTY, STACK_JAVA_VERSION
+  STACK_JAVA_HOME_PROPERTY, STACK_JDK_NAME_PROPERTY, STACK_JCE_NAME_PROPERTY, STACK_JAVA_VERSION, GPL_LICENSE_ACCEPTED_PROPERTY
 from ambari_server.serverUtils import is_server_runing
 from ambari_server.setupSecurity import adjust_directory_permissions
 from ambari_server.userInput import get_YN_input, get_validated_string_input
@@ -1135,6 +1135,20 @@ def check_setup_already_done():
 
   return not bool(get_missing_properties(properties, property_set=SETUP_DONE_PROPERTIES))
 
+def write_gpl_license_accepted(options):
+  properties = get_ambari_properties()
+  if properties == -1:
+    err = "Error getting ambari properties"
+    raise FatalException(-1, err)
+
+  if get_silent():
+    result = str(options.accept_gpl).lower()
+  else:
+    result = prompt_gpl_agreement()
+
+  properties.process_pair(GPL_LICENSE_ACCEPTED_PROPERTY, result)
+  update_properties(properties)
+
 #
 # Setup the Ambari Server.
 #
@@ -1182,6 +1196,9 @@ def setup(options):
     err = 'Downloading or installing JDK failed: {0}. Exiting.'.format(e)
     raise FatalException(e.code, err)
 
+  print 'Prompting GPL software agreement...'
+  write_gpl_license_accepted(options)
+
   print 'Completing setup...'
   retcode = configure_os_settings()
   if not retcode == 0:

http://git-wip-us.apache.org/repos/asf/ambari/blob/f331f86d/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
index 94c5ebe..b774436 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
@@ -2093,6 +2093,7 @@ public class AmbariManagementControllerImplTest {
     expect(configuration.getServerDBName()).andReturn(SERVER_DB_NAME);
     expect(configuration.getJavaVersion()).andReturn(8);
     expect(configuration.areHostsSysPrepped()).andReturn("true");
+    expect(configuration.getGplLicenseAccepted()).andReturn(false);
     expect(configuration.getDatabaseConnectorNames()).andReturn(new HashMap<>()).anyTimes();
     expect(configuration.getPreviousDatabaseConnectorNames()).andReturn(new HashMap<>()).anyTimes();
     expect(repositoryVersionEntity.getVersion()).andReturn("1234").anyTimes();
@@ -2140,7 +2141,7 @@ public class AmbariManagementControllerImplTest {
 
     Map<String, String> defaultHostParams = helper.createDefaultHostParams(cluster, repositoryVersionEntity.getStackId());
 
-    assertEquals(15, defaultHostParams.size());
+    assertEquals(16, defaultHostParams.size());
     assertEquals(MYSQL_JAR, defaultHostParams.get(DB_DRIVER_FILENAME));
     assertEquals(SOME_STACK_NAME, defaultHostParams.get(STACK_NAME));
     assertEquals(SOME_STACK_VERSION, defaultHostParams.get(STACK_VERSION));

http://git-wip-us.apache.org/repos/asf/ambari/blob/f331f86d/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProviderTest.java
index 833be5d..6779e26f 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProviderTest.java
@@ -278,6 +278,7 @@ public class ClientConfigResourceProviderTest {
     expect(configuration.areHostsSysPrepped()).andReturn("false");
     expect(configuration.isAgentStackRetryOnInstallEnabled()).andReturn("false");
     expect(configuration.getAgentStackRetryOnInstallCount()).andReturn("5");
+    expect(configuration.getGplLicenseAccepted()).andReturn(Configuration.GPL_LICENSE_ACCEPTED.getDefaultValue());
     expect(configuration.getExternalScriptThreadPoolSize()).andReturn(Configuration.THREAD_POOL_SIZE_FOR_EXTERNAL_SCRIPT.getDefaultValue());
     expect(configuration.getExternalScriptTimeout()).andReturn(Configuration.EXTERNAL_SCRIPT_TIMEOUT.getDefaultValue());
     Map<String,String> props = new HashMap<>();
@@ -535,6 +536,7 @@ public class ClientConfigResourceProviderTest {
     expect(configuration.areHostsSysPrepped()).andReturn("false");
     expect(configuration.isAgentStackRetryOnInstallEnabled()).andReturn("false");
     expect(configuration.getAgentStackRetryOnInstallCount()).andReturn("5");
+    expect(configuration.getGplLicenseAccepted()).andReturn(Configuration.GPL_LICENSE_ACCEPTED.getDefaultValue());
     expect(configuration.getExternalScriptThreadPoolSize()).andReturn(Configuration.THREAD_POOL_SIZE_FOR_EXTERNAL_SCRIPT.getDefaultValue());
     expect(configuration.getExternalScriptTimeout()).andReturn(Configuration.EXTERNAL_SCRIPT_TIMEOUT.getDefaultValue());
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f331f86d/ambari-server/src/test/python/TestAmbariServer.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/TestAmbariServer.py b/ambari-server/src/test/python/TestAmbariServer.py
index 66df2d8..f71e0f3 100644
--- a/ambari-server/src/test/python/TestAmbariServer.py
+++ b/ambari-server/src/test/python/TestAmbariServer.py
@@ -3718,7 +3718,8 @@ class TestAmbariServer(TestCase):
   @patch("ambari_server.serverSetup.service_setup")
   @patch("ambari_server.serverSetup.read_ambari_user")
   @patch("ambari_server.serverSetup.expand_jce_zip_file")
-  def test_setup_linux(self, expand_jce_zip_file_mock, read_ambari_user_mock,
+  @patch("ambari_server.serverSetup.write_gpl_license_accepted")
+  def test_setup_linux(self, write_gpl_license_accepted_mock, expand_jce_zip_file_mock, read_ambari_user_mock,
                  service_setup_mock, adjust_dirs_mock, extract_views_mock, proceedJDBCProperties_mock, is_root_mock,
                  disable_security_enhancements_mock, check_jdbc_drivers_mock, check_ambari_user_mock,
                  download_jdk_mock, configure_os_settings_mock, get_ambari_properties_mock,
@@ -3831,6 +3832,7 @@ class TestAmbariServer(TestCase):
     check_jdbc_drivers_mock.return_value = 0
     download_jdk_mock.return_value = 0
     configure_os_settings_mock.return_value = 0
+    write_gpl_license_accepted_mock.return_value = 0
 
     result = setup(args)
 
@@ -6834,7 +6836,6 @@ class TestAmbariServer(TestCase):
                                     read_ambari_user_method, read_master_key_method,
                                     get_is_persisted_method, get_is_secure_method, exists_mock,
                                     save_passwd_for_alias_method):
-
     is_root_method.return_value = True
 
     p = Properties()


[20/49] ambari git commit: AMBARI-22497 Disk usage is not updated (dgrinenko)

Posted by rl...@apache.org.
AMBARI-22497 Disk usage is not updated (dgrinenko)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 9572882fdd345ac35a2b509d7e616579734d4fde
Parents: b902c13
Author: Dmytro Grinenko <ha...@apache.org>
Authored: Wed Nov 22 15:55:56 2017 +0200
Committer: Dmytro Grinenko <ha...@apache.org>
Committed: Wed Nov 22 15:55:56 2017 +0200

----------------------------------------------------------------------
 .../src/main/python/ambari_agent/Hardware.py    | 130 +++++++++++--------
 .../src/main/python/ambari_agent/Heartbeat.py   |   8 +-
 .../src/main/python/ambari_agent/HostInfo.py    |  83 ++++++------
 .../test/python/ambari_agent/TestHardware.py    |  56 ++++++--
 .../python/ambari_agent/TestRegistration.py     |   5 +-
 5 files changed, 165 insertions(+), 117 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9572882f/ambari-agent/src/main/python/ambari_agent/Hardware.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/Hardware.py b/ambari-agent/src/main/python/ambari_agent/Hardware.py
index 696438e..56ce872 100644
--- a/ambari-agent/src/main/python/ambari_agent/Hardware.py
+++ b/ambari-agent/src/main/python/ambari_agent/Hardware.py
@@ -44,55 +44,72 @@ class Hardware:
   IGNORE_DEVICES = ["proc", "tmpfs", "cgroup", "mqueue", "shm"]
   LINUX_PATH_SEP = "/"
 
-  def __init__(self, config):
+  def __init__(self, config=None, cache_info=True):
+    """
+    Initialize hardware object with available metrics. Metrics cache could be
+     disabled by setting cache_info to False
+
+    :param config Ambari Agent Configuration
+    :param cache_info initialize hardware dictionary with available metrics
+
+    :type config AmbariConfig
+    :type cache_info bool
+    """
+    self.config = config
+    self._hardware = None
+
+    if cache_info:
+      self._cache_hardware_info()
+
+  def _cache_hardware_info(self):
+    """
+    Creating cache with hardware information
+    """
     logger.info("Initializing host system information.")
-    self.hardware = {
-      'mounts': Hardware.osdisks()
+    self._hardware = {
+      'mounts': self.osdisks()
     }
-    self.config = config
-    self.hardware.update(Facter(self.config).facterInfo())
-    logger.info("Host system information: %s", self.hardware)
+    self._hardware.update(Facter(self.config).facterInfo())
+    logger.info("Host system information: %s", self._hardware)
 
-  @classmethod
-  def _parse_df_line(cls, line):
+  def _parse_df(self, lines):
     """
-      Initialize data-structure from string in specific 'df' command output format
+      Generator, which parses df command output and yields parsed entities
 
       Expected string format:
        device fs_type disk_size used_size available_size capacity_used_percents mount_point
 
-    :type line str
+    :type lines list[str]
+    :rtype collections.Iterable
     """
+    titles = ["device", "type", "size", "used", "available", "percent", "mountpoint"]
 
-    line_split = line.split()
-    if len(line_split) != 7:
-      return None
+    for line in lines:
+      line_split = line.split()
+      if len(line_split) != 7:
+        continue
 
-    titles = ["device", "type", "size", "used", "available", "percent", "mountpoint"]
-    return dict(zip(titles, line_split))
+      yield dict(zip(titles, line_split))
 
-  @classmethod
-  def _get_mount_check_timeout(cls, config=None):
+  def _get_mount_check_timeout(self):
     """Return timeout for df call command"""
-    if config and config.has_option(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_TIMEOUT_KEY) \
-      and config.get(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_TIMEOUT_KEY) != "0":
+    if self.config and self.config.has_option(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_TIMEOUT_KEY) \
+      and self.config.get(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_TIMEOUT_KEY) != "0":
 
-      return config.get(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_TIMEOUT_KEY)
+      return self.config.get(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_TIMEOUT_KEY)
 
     return Hardware.CHECK_REMOTE_MOUNTS_TIMEOUT_DEFAULT
 
-  @classmethod
-  def _check_remote_mounts(cls, config=None):
+  def _check_remote_mounts(self):
     """Verify if remote mount allowed to be processed or not"""
-    if config and config.has_option(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_KEY) and \
-       config.get(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_KEY).lower() == "false":
+    if self.config and self.config.has_option(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_KEY) and \
+      self.config.get(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_KEY).lower() == "false":
 
       return False
 
     return True
 
-  @classmethod
-  def _is_mount_blacklisted(cls, blacklist, mount_point):
+  def _is_mount_blacklisted(self, blacklist, mount_point):
     """
     Verify if particular mount point is in the black list.
 
@@ -111,49 +128,44 @@ class Hardware:
     if not blacklist or not mount_point:
       return False
 
-    mount_point_elements = mount_point.split(cls.LINUX_PATH_SEP)
+    # in this way we excluding possibility
+    mount_point_elements = mount_point.split(self.LINUX_PATH_SEP)
 
     for el in blacklist:
-      el_list = el.split(cls.LINUX_PATH_SEP)
+      el_list = el.split(self.LINUX_PATH_SEP)
       # making patch elements comparision
       if el_list == mount_point_elements[:len(el_list)]:
         return True
 
     return False
 
-
-  @classmethod
   @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
-  def osdisks(cls, config=None):
+  def osdisks(self):
     """ Run df to find out the disks on the host. Only works on linux
     platforms. Note that this parser ignores any filesystems with spaces
     and any mounts with spaces. """
-    timeout = cls._get_mount_check_timeout(config)
+    timeout = self._get_mount_check_timeout()
     command = ["timeout", timeout, "df", "-kPT"]
     blacklisted_mount_points = []
 
-    if config:
-      ignore_mount_value = config.get("agent", "ignore_mount_points", default="")
-      blacklisted_mount_points = [item.strip() for item in ignore_mount_value.split(",")]
+    if self.config:
+      ignore_mount_value = self.config.get("agent", "ignore_mount_points", default="")
+      blacklisted_mount_points = [item.strip() for item in ignore_mount_value.split(",") if len(item.strip()) != 0]
 
-    if not cls._check_remote_mounts(config):
+    if not self._check_remote_mounts():
       command.append("-l")
 
     try:
-      code, out, err = shell.call(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, timeout = int(timeout), quiet = True)
+      code, out, err = shell.call(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=int(timeout), quiet=True)
       dfdata = out
     except Exception as ex:
       logger.warn("Checking disk usage failed: " + str(ex))
       dfdata = ''
 
-    mounts = [cls._parse_df_line(line) for line in dfdata.splitlines() if line]
     result_mounts = []
     ignored_mounts = []
 
-    for mount in mounts:
-      if not mount:
-        continue
-
+    for mount in self._parse_df(dfdata.splitlines()):
       """
       We need to filter mounts by several parameters:
        - mounted device is not in the ignored list
@@ -161,11 +173,11 @@ class Hardware:
        - it is not file-mount (docker environment)
        - mount path or a part of mount path is not in the blacklist
       """
-      if mount["device"] not in cls.IGNORE_DEVICES and\
-         mount["mountpoint"].split("/")[0] not in cls.IGNORE_ROOT_MOUNTS and\
-         cls._chk_writable_mount(mount['mountpoint']) and\
+      if mount["device"] not in self.IGNORE_DEVICES and\
+         mount["mountpoint"].split("/")[0] not in self.IGNORE_ROOT_MOUNTS and\
+         self._chk_writable_mount(mount['mountpoint']) and\
          not path_isfile(mount["mountpoint"]) and\
-         not cls._is_mount_blacklisted(blacklisted_mount_points, mount["mountpoint"]):
+         not self._is_mount_blacklisted(blacklisted_mount_points, mount["mountpoint"]):
 
         result_mounts.append(mount)
       else:
@@ -177,8 +189,7 @@ class Hardware:
 
     return result_mounts
 
-  @classmethod
-  def _chk_writable_mount(cls, mount_point):
+  def _chk_writable_mount(self, mount_point):
     if os.geteuid() == 0:
       return os.access(mount_point, os.W_OK)
     else:
@@ -196,9 +207,8 @@ class Hardware:
         logger.exception("Exception happened while checking mount {0}".format(mount_point))
         return False
     
-  @classmethod
   @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY)
-  def osdisks(cls, config=None):
+  def osdisks(self):
     mounts = []
     runner = shellRunner()
     command_result = runner.runPowershell(script_block=Hardware.WINDOWS_GET_DRIVES_CMD)
@@ -216,16 +226,28 @@ class Hardware:
 
     return mounts
 
-  def get(self):
-    return self.hardware
+  def get(self, invalidate_cache=False):
+    """
+    Getting cached hardware information
+
+    :param invalidate_cache resets hardware metrics cache
+    :type invalidate_cache bool
+    """
+    if invalidate_cache:
+      self._hardware = None
+
+    if not self._hardware:
+      self._cache_hardware_info()
+
+    return self._hardware
 
 
 def main():
   from resource_management.core.logger import Logger
   Logger.initialize_logger()
 
-  config = None
-  print Hardware(config).get()
+  print Hardware().get()
+
 
 if __name__ == '__main__':
   main()

http://git-wip-us.apache.org/repos/asf/ambari/blob/9572882f/ambari-agent/src/main/python/ambari_agent/Heartbeat.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/Heartbeat.py b/ambari-agent/src/main/python/ambari_agent/Heartbeat.py
index 1e05aae..d7c0325 100644
--- a/ambari-agent/src/main/python/ambari_agent/Heartbeat.py
+++ b/ambari-agent/src/main/python/ambari_agent/Heartbeat.py
@@ -75,14 +75,11 @@ class Heartbeat:
     if int(id) == 0:
       componentsMapped = False
 
-
-
     logger.debug("Building Heartbeat: {responseId = %s, timestamp = %s, "
                 "commandsInProgress = %s, componentsMapped = %s,"
                 "recoveryTimestamp = %s}",
         str(id), str(timestamp), repr(commandsInProgress), repr(componentsMapped), str(recovery_timestamp))
 
-
     logger.debug("Heartbeat: %s", pformat(heartbeat))
 
     hostInfo = HostInfo(self.config)
@@ -93,10 +90,9 @@ class Heartbeat:
       # this must be the last step before returning heartbeat
       hostInfo.register(nodeInfo, componentsMapped, commandsInProgress)
       heartbeat['agentEnv'] = nodeInfo
-      mounts = Hardware.osdisks(self.config)
+      mounts = Hardware(config=self.config, cache_info=False).osdisks()
       heartbeat['mounts'] = mounts
 
-
       logger.debug("agentEnv: %s", str(nodeInfo))
       logger.debug("mounts: %s", str(mounts))
 
@@ -105,6 +101,7 @@ class Heartbeat:
     
     return heartbeat
 
+
 def main(argv=None):
   from ambari_agent.ActionQueue import ActionQueue
   from ambari_agent.AmbariConfig import AmbariConfig
@@ -122,5 +119,6 @@ def main(argv=None):
   heartbeat = Heartbeat(actionQueue)
   print json.dumps(heartbeat.build('3',3))
 
+
 if __name__ == '__main__':
   main()

http://git-wip-us.apache.org/repos/asf/ambari/blob/9572882f/ambari-agent/src/main/python/ambari_agent/HostInfo.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/HostInfo.py b/ambari-agent/src/main/python/ambari_agent/HostInfo.py
index b8545cc..4a752fc 100644
--- a/ambari-agent/src/main/python/ambari_agent/HostInfo.py
+++ b/ambari-agent/src/main/python/ambari_agent/HostInfo.py
@@ -57,6 +57,9 @@ class HostInfo(object):
     self.config = config
     self.reportFileHandler = HostCheckReportFileHandler(config)
 
+  def register(self, dict_obj, componentsMapped=True, commandsInProgress=True):
+    raise NotImplementedError()
+
   def dirType(self, path):
     if not os.path.exists(path):
       return 'not_exist'
@@ -245,21 +248,20 @@ class HostInfoLinux(HostInfo):
         cmd = cmd.replace('\0', ' ')
         if not 'AmbariServer' in cmd:
           if 'java' in cmd:
-            dict = {}
-            dict['pid'] = int(pid)
-            dict['hadoop'] = False
+            metrics = {}
+            metrics['pid'] = int(pid)
+            metrics['hadoop'] = False
             for filter in self.PROC_FILTER:
               if filter in cmd:
-                dict['hadoop'] = True
-            dict['command'] = unicode(cmd.strip(), errors='ignore')
+                metrics['hadoop'] = True
+            metrics['command'] = unicode(cmd.strip(), errors='ignore')
             for line in open(os.path.join('/proc', pid, 'status')):
               if line.startswith('Uid:'):
                 uid = int(line.split()[1])
-                dict['user'] = pwd.getpwuid(uid).pw_name
-            list.append(dict)
+                metrics['user'] = pwd.getpwuid(uid).pw_name
+            list.append(metrics)
     except:
       logger.exception("Checking java processes failed")
-    pass
 
   def getTransparentHugePage(self):
     thp_regex = "\[(.+)\]"
@@ -312,54 +314,54 @@ class HostInfoLinux(HostInfo):
       logger.exception('Unable to get information about JCE')
       return None
 
-  def register(self, dict, componentsMapped=True, commandsInProgress=True):
+  def register(self, metrics, componentsMapped=True, commandsInProgress=True):
     """ Return various details about the host
     componentsMapped: indicates if any components are mapped to this host
     commandsInProgress: indicates if any commands are in progress
     """
 
-    dict['hostHealth'] = {}
+    metrics['hostHealth'] = {}
 
     java = []
     self.javaProcs(java)
-    dict['hostHealth']['activeJavaProcs'] = java
+    metrics['hostHealth']['activeJavaProcs'] = java
 
     liveSvcs = []
     self.checkLiveServices(self.DEFAULT_LIVE_SERVICES, liveSvcs)
-    dict['hostHealth']['liveServices'] = liveSvcs
+    metrics['hostHealth']['liveServices'] = liveSvcs
 
-    dict['umask'] = str(self.getUMask())
+    metrics['umask'] = str(self.getUMask())
 
-    dict['transparentHugePage'] = self.getTransparentHugePage()
-    dict['firewallRunning'] = self.checkFirewall()
-    dict['firewallName'] = self.getFirewallName()
-    dict['reverseLookup'] = self.checkReverseLookup()
-    dict['hasUnlimitedJcePolicy'] = self.checkUnlimitedJce()
+    metrics['transparentHugePage'] = self.getTransparentHugePage()
+    metrics['firewallRunning'] = self.checkFirewall()
+    metrics['firewallName'] = self.getFirewallName()
+    metrics['reverseLookup'] = self.checkReverseLookup()
+    metrics['hasUnlimitedJcePolicy'] = self.checkUnlimitedJce()
     # If commands are in progress or components are already mapped to this host
     # Then do not perform certain expensive host checks
     if componentsMapped or commandsInProgress:
-      dict['alternatives'] = []
-      dict['stackFoldersAndFiles'] = []
-      dict['existingUsers'] = []
+      metrics['alternatives'] = []
+      metrics['stackFoldersAndFiles'] = []
+      metrics['existingUsers'] = []
 
     else:
       etcs = []
       self.etcAlternativesConf(self.DEFAULT_PROJECT_NAMES, etcs)
-      dict['alternatives'] = etcs
+      metrics['alternatives'] = etcs
 
       existingUsers = []
       self.checkUsers(self.DEFAULT_USERS, existingUsers)
-      dict['existingUsers'] = existingUsers
+      metrics['existingUsers'] = existingUsers
 
       dirs = []
       self.checkFolders(self.DEFAULT_BASEDIRS, self.DEFAULT_PROJECT_NAMES, self.EXACT_DIRECTORIES, existingUsers, dirs)
-      dict['stackFoldersAndFiles'] = dirs
+      metrics['stackFoldersAndFiles'] = dirs
 
-      self.reportFileHandler.writeHostCheckFile(dict)
+      self.reportFileHandler.writeHostCheckFile(metrics)
       pass
 
     # The time stamp must be recorded at the end
-    dict['hostHealth']['agentTimeStampAtReporting'] = int(time.time() * 1000)
+    metrics['hostHealth']['agentTimeStampAtReporting'] = int(time.time() * 1000)
 
     pass
 
@@ -434,43 +436,42 @@ class HostInfoWindows(HostInfo):
     code, out, err = run_powershell_script(self.SERVICE_STATUS_CMD.format(serivce_name))
     return out, err, code
 
-  def register(self, dict, componentsMapped=True, commandsInProgress=True):
+  def register(self, metrics, componentsMapped=True, commandsInProgress=True):
     """ Return various details about the host
     componentsMapped: indicates if any components are mapped to this host
     commandsInProgress: indicates if any commands are in progress
     """
-    dict['hostHealth'] = {}
+    metrics['hostHealth'] = {}
 
     java = []
     self.javaProcs(java)
-    dict['hostHealth']['activeJavaProcs'] = java
+    metrics['hostHealth']['activeJavaProcs'] = java
 
     liveSvcs = []
     self.checkLiveServices(self.DEFAULT_LIVE_SERVICES, liveSvcs)
-    dict['hostHealth']['liveServices'] = liveSvcs
+    metrics['hostHealth']['liveServices'] = liveSvcs
 
-    dict['umask'] = str(self.getUMask())
+    metrics['umask'] = str(self.getUMask())
 
-    dict['firewallRunning'] = self.checkFirewall()
-    dict['firewallName'] = self.getFirewallName()
-    dict['reverseLookup'] = self.checkReverseLookup()
+    metrics['firewallRunning'] = self.checkFirewall()
+    metrics['firewallName'] = self.getFirewallName()
+    metrics['reverseLookup'] = self.checkReverseLookup()
     # If commands are in progress or components are already mapped to this host
     # Then do not perform certain expensive host checks
     if componentsMapped or commandsInProgress:
-      dict['alternatives'] = []
-      dict['stackFoldersAndFiles'] = []
-      dict['existingUsers'] = []
+      metrics['alternatives'] = []
+      metrics['stackFoldersAndFiles'] = []
+      metrics['existingUsers'] = []
     else:
       existingUsers = []
       self.checkUsers(self.DEFAULT_USERS, existingUsers)
-      dict['existingUsers'] = existingUsers
+      metrics['existingUsers'] = existingUsers
       # TODO check HDP stack and folders here
-      self.reportFileHandler.writeHostCheckFile(dict)
+      self.reportFileHandler.writeHostCheckFile(metrics)
       pass
 
     # The time stamp must be recorded at the end
-    dict['hostHealth']['agentTimeStampAtReporting'] = int(time.time() * 1000)
-
+    metrics['hostHealth']['agentTimeStampAtReporting'] = int(time.time() * 1000)
 
 
 def main(argv=None):

http://git-wip-us.apache.org/repos/asf/ambari/blob/9572882f/ambari-agent/src/test/python/ambari_agent/TestHardware.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestHardware.py b/ambari-agent/src/test/python/ambari_agent/TestHardware.py
index 5400e26..e78f8f2 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestHardware.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestHardware.py
@@ -26,14 +26,12 @@ import unittest
 import platform
 import socket
 import subprocess
-import os
 from only_for_platform import not_for_platform, PLATFORM_WINDOWS
 from ambari_agent import hostname
 from ambari_agent.Hardware import Hardware
 from ambari_agent.AmbariConfig import AmbariConfig
 from ambari_agent.Facter import Facter, FacterLinux
 from ambari_commons import OSCheck
-from resource_management.core import shell
 
 
 @not_for_platform(PLATFORM_WINDOWS)
@@ -61,10 +59,10 @@ class TestHardware(TestCase):
   def test_build(self, get_os_version_mock, get_os_type_mock):
     get_os_type_mock.return_value = "suse"
     get_os_version_mock.return_value = "11"
-    config = None
-    hardware = Hardware(config)
+    hardware = Hardware()
     result = hardware.get()
     osdisks = hardware.osdisks()
+
     for dev_item in result['mounts']:
       self.assertTrue(dev_item['available'] >= 0)
       self.assertTrue(dev_item['used'] >= 0)
@@ -113,7 +111,33 @@ class TestHardware(TestCase):
     chk_writable_mount_mock.side_effect = chk_writable_mount_side_effect
     shell_call_mock.return_value = (0, df_output, '')
 
-    result = Hardware.osdisks()
+    result = Hardware(cache_info=False).osdisks()
+
+    self.assertEquals(1, len(result))
+
+    expected_mounts_left = ["/"]
+    mounts_left = [item["mountpoint"] for item in result]
+
+    self.assertEquals(expected_mounts_left, mounts_left)
+
+  @patch.object(Hardware, "_chk_writable_mount")
+  @patch("ambari_agent.Hardware.path_isfile")
+  @patch("resource_management.core.shell.call")
+  def test_osdisks_no_ignore_property(self, shell_call_mock, isfile_mock, chk_writable_mount_mock):
+    df_output = \
+      """Filesystem                                                                                        Type  1024-blocks     Used Available Capacity Mounted on
+      /dev/mapper/docker-253:0-4980899-d45c264d37ab18c8ed14f890f4d59ac2b81e1c52919eb36a79419787209515f3 xfs      31447040  1282384  30164656       5% /
+      """
+
+    isfile_mock.return_value = False
+    chk_writable_mount_mock.return_value = True
+    shell_call_mock.return_value = (0, df_output, '')
+    config = AmbariConfig()
+
+    # check, that config do not define ignore_mount_points property
+    self.assertEquals("test", config.get('agent', 'ignore_mount_points', default="test"))
+
+    result = Hardware(config=config, cache_info=False).osdisks()
 
     self.assertEquals(1, len(result))
 
@@ -128,35 +152,35 @@ class TestHardware(TestCase):
   def test_osdisks_remote(self, shell_call_mock, get_os_version_mock, get_os_type_mock):
     get_os_type_mock.return_value = "suse"
     get_os_version_mock.return_value = "11"
-    Hardware.osdisks()
+    Hardware(cache_info=False).osdisks()
     timeout = 10
     shell_call_mock.assert_called_with(['timeout', str(timeout), "df", "-kPT"], stdout = subprocess.PIPE, stderr = subprocess.PIPE, timeout = timeout, quiet = True)
 
     config = AmbariConfig()
-    Hardware.osdisks(config)
+    Hardware(config=config, cache_info=False).osdisks()
     shell_call_mock.assert_called_with(['timeout', str(timeout), "df", "-kPT"], stdout = subprocess.PIPE, stderr = subprocess.PIPE, timeout = timeout, quiet = True)
 
     config.add_section(AmbariConfig.AMBARI_PROPERTIES_CATEGORY)
     config.set(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_KEY, "true")
-    Hardware.osdisks(config)
+    Hardware(config=config, cache_info=False).osdisks()
     shell_call_mock.assert_called_with(['timeout', str(timeout), "df", "-kPT"], stdout = subprocess.PIPE, stderr = subprocess.PIPE, timeout = timeout, quiet = True)
 
     config.set(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_KEY, "false")
-    Hardware.osdisks(config)
+    Hardware(config=config, cache_info=False).osdisks()
     shell_call_mock.assert_called_with(['timeout', str(timeout), "df", "-kPT", "-l"], stdout = subprocess.PIPE, stderr = subprocess.PIPE, timeout = timeout, quiet = True)
 
     config.set(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_TIMEOUT_KEY, "0")
-    Hardware.osdisks(config)
+    Hardware(config=config, cache_info=False).osdisks()
     shell_call_mock.assert_called_with(['timeout', str(timeout), "df", "-kPT", "-l"], stdout = subprocess.PIPE, stderr = subprocess.PIPE, timeout = timeout, quiet = True)
 
     timeout = 1
     config.set(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_TIMEOUT_KEY, str(timeout))
-    Hardware.osdisks(config)
+    Hardware(config=config, cache_info=False).osdisks()
     shell_call_mock.assert_called_with(['timeout', str(timeout), "df", "-kPT", "-l"], stdout = subprocess.PIPE, stderr = subprocess.PIPE, timeout = timeout, quiet = True)
 
     timeout = 2
     config.set(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_TIMEOUT_KEY, str(timeout))
-    Hardware.osdisks(config)
+    Hardware(config=config, cache_info=False).osdisks()
     shell_call_mock.assert_called_with(['timeout', str(timeout), "df", "-kPT", "-l"], stdout = subprocess.PIPE, stderr = subprocess.PIPE, timeout = timeout, quiet = True)
 
   def test_parse_df_line(self):
@@ -182,7 +206,11 @@ class TestHardware(TestCase):
     ]
 
     for sample in samples:
-      result = Hardware._parse_df_line(sample["sample"])
+      try:
+        result = Hardware(cache_info=False)._parse_df([sample["sample"]]).next()
+      except StopIteration:
+        result = None
+
       self.assertEquals(result, sample["expected"], "Failed with sample: '{0}', expected: {1}, got: {2}".format(
         sample["sample"],
         sample["expected"],
@@ -430,7 +458,7 @@ SwapFree:        1598676 kB
     }
     conf.configure_mock(**attr)
 
-    result = Hardware.osdisks(conf)
+    result = Hardware(config=conf, cache_info=False).osdisks()
 
     self.assertEquals(1, len(result))
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/9572882f/ambari-agent/src/test/python/ambari_agent/TestRegistration.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestRegistration.py b/ambari-agent/src/test/python/ambari_agent/TestRegistration.py
index a5c23fa..fada29c 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestRegistration.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestRegistration.py
@@ -19,7 +19,6 @@ limitations under the License.
 '''
 
 from unittest import TestCase
-import os
 import tempfile
 from mock.mock import patch
 from mock.mock import MagicMock
@@ -35,13 +34,14 @@ class TestRegistration(TestCase):
 
   @patch("subprocess.Popen")
   @patch.object(Hardware, "_chk_writable_mount", new = MagicMock(return_value=True))
+  @patch("__builtin__.open", new=MagicMock())
   @patch.object(FacterLinux, "facterInfo", new = MagicMock(return_value={}))
   @patch.object(FacterLinux, "__init__", new = MagicMock(return_value = None))
   @patch("resource_management.core.shell.call")
   @patch.object(OSCheck, "get_os_type")
   @patch.object(OSCheck, "get_os_version")
   def test_registration_build(self, get_os_version_mock, get_os_type_mock, run_os_cmd_mock, Popen_mock):
-    config = AmbariConfig().getConfig()
+    config = AmbariConfig()
     tmpdir = tempfile.gettempdir()
     config.set('agent', 'prefix', tmpdir)
     config.set('agent', 'current_ping_port', '33777')
@@ -58,7 +58,6 @@ class TestRegistration(TestCase):
     self.assertEquals(data['timestamp'] > 1353678475465L, True, "timestamp should not be empty")
     self.assertEquals(len(data['agentEnv']) > 0, True, "agentEnv should not be empty")
     self.assertEquals(data['agentVersion'], reference_version, "agentVersion should not be empty")
-    print data['agentEnv']['umask']
     self.assertEquals(not data['agentEnv']['umask']== "", True, "agents umask should not be empty")
     self.assertEquals(data['currentPingPort'] == 33777, True, "current ping port should be 33777")
     self.assertEquals(data['prefix'], config.get('agent', 'prefix'), 'The prefix path does not match')


[28/49] ambari git commit: AMBARI-22454. ambari-server upgrade to 2.6.1 should surface the GPL agreement. Fix checkstyle. (Attila Doroszlai via mpapyrkovskyy)

Posted by rl...@apache.org.
AMBARI-22454. ambari-server upgrade to 2.6.1 should surface the GPL agreement. Fix checkstyle. (Attila Doroszlai via mpapyrkovskyy)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 5d421b7abd557a0ab915e03cee8df59cd4760178
Parents: 2c46bb3
Author: Myroslav Papirkovskyi <mp...@hortonworks.com>
Authored: Wed Nov 22 21:57:15 2017 +0200
Committer: Myroslav Papirkovskyi <mp...@hortonworks.com>
Committed: Wed Nov 22 22:14:39 2017 +0200

----------------------------------------------------------------------
 .../controller/AmbariCustomCommandExecutionHelper.java   |  2 +-
 .../internal/ClientConfigResourceProvider.java           |  2 +-
 .../ambari/server/upgrade/SchemaUpgradeHelper.java       |  8 ++++----
 .../org/apache/ambari/server/upgrade/UpgradeCatalog.java |  1 -
 .../apache/ambari/server/upgrade/UpgradeCatalog260.java  |  1 -
 .../apache/ambari/server/upgrade/UpgradeCatalog261.java  | 11 ++++++-----
 6 files changed, 12 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5d421b7a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
index 7c52877..c4df0b1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
@@ -26,9 +26,9 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMPONENT
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.CUSTOM_COMMAND;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_DRIVER_FILENAME;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_NAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GPL_LICENSE_ACCEPTED;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GROUP_LIST;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOST_SYS_PREPPED;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GPL_LICENSE_ACCEPTED;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.MYSQL_JDBC_URL;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.NOT_MANAGED_HDFS_PATH_LIST;

http://git-wip-us.apache.org/repos/asf/ambari/blob/5d421b7a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProvider.java
index 993da1b..f0ede5d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClientConfigResourceProvider.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.controller.internal;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AGENT_STACK_RETRY_COUNT;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AGENT_STACK_RETRY_ON_UNAVAILABILITY;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_NAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GPL_LICENSE_ACCEPTED;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GROUP_LIST;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOST_SYS_PREPPED;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
@@ -33,7 +34,6 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAM
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.USER_GROUPS;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.USER_LIST;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GPL_LICENSE_ACCEPTED;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;

http://git-wip-us.apache.org/repos/asf/ambari/blob/5d421b7a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
index 2d0e4ce..039e041 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
@@ -26,14 +26,12 @@ import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import java.util.Map;
-import java.util.HashMap;
 
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.audit.AuditLoggerModule;
 import org.apache.ambari.server.configuration.Configuration;
@@ -46,6 +44,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.jdbc.support.JdbcUtils;
 
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.google.inject.Guice;
 import com.google.inject.Inject;
 import com.google.inject.Injector;

http://git-wip-us.apache.org/repos/asf/ambari/blob/5d421b7a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog.java
index a005951..37a3b5e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog.java
@@ -18,7 +18,6 @@
 package org.apache.ambari.server.upgrade;
 
 import java.sql.SQLException;
-import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.ambari.server.AmbariException;

http://git-wip-us.apache.org/repos/asf/ambari/blob/5d421b7a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
index a7e0654..33b62f8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
@@ -47,7 +47,6 @@ import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
 import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor;
-import org.apache.ambari.server.state.kerberos.KerberosPrincipalType;
 import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/ambari/blob/5d421b7a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog261.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog261.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog261.java
index 7f463aa..ba95833 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog261.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog261.java
@@ -17,8 +17,9 @@
  */
 package org.apache.ambari.server.upgrade;
 
-import com.google.inject.Inject;
-import com.google.inject.Injector;
+import java.sql.SQLException;
+import java.util.Map;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.state.Cluster;
@@ -27,8 +28,8 @@ import org.apache.ambari.server.state.Config;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.sql.SQLException;
-import java.util.Map;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
 
 /**
  * The {@link UpgradeCatalog261} upgrades Ambari from 2.6.0 to 2.6.1.
@@ -115,4 +116,4 @@ public class UpgradeCatalog261 extends AbstractUpgradeCatalog {
     }
     return false;
   }
-}
\ No newline at end of file
+}


[36/49] ambari git commit: AMBARI-22508 Ambari 3.0: Implement new design for Admin View: User Management. (atkach)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/userManagement/UsersListCtrl_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/userManagement/UsersListCtrl_test.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/userManagement/UsersListCtrl_test.js
new file mode 100644
index 0000000..fcafa59
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/userManagement/UsersListCtrl_test.js
@@ -0,0 +1,344 @@
+/**
+ * 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.
+ */
+
+describe('#Cluster', function () {
+
+  describe('UsersListCtrl', function() {
+
+    var scope, ctrl, $t, $httpBackend;
+
+    beforeEach(module('ambariAdminConsole', function () {}));
+
+    beforeEach(inject(function($rootScope, $controller, _$translate_, _$httpBackend_) {
+      scope = $rootScope.$new();
+      $t = _$translate_.instant;
+      $httpBackend = _$httpBackend_;
+      ctrl = $controller('UsersListCtrl', {
+        $scope: scope
+      });
+    }));
+
+    describe('#clearFilters()', function () {
+
+      it('should clear filters and reset pagination', function () {
+        scope.currentPage = 2;
+        scope.filters.name = 'a';
+        scope.filters.status = {
+          label: $t('common.local'),
+          value: false
+        };
+        scope.filters.type = {
+          label: $t('common.local'),
+          value: 'LOCAL'
+        };
+        scope.clearFilters();
+        expect(scope.filters.name).toEqual('');
+        expect(scope.filters.status).toEqual({
+          label: $t('common.all'),
+          value: '*'
+        });
+        expect(scope.filters.type).toEqual({
+          label: $t('common.all'),
+          value: '*'
+        });
+        expect(scope.currentPage).toEqual(1);
+      });
+
+    });
+
+    describe('#isNotEmptyFilter', function () {
+
+      var cases = [
+        {
+          currentNameFilter: '',
+          currentTypeFilter: null,
+          currentActiveFilter: null,
+          isNotEmptyFilter: false,
+          title: 'no filters'
+        },
+        {
+          currentNameFilter: '',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: false,
+          title: 'empty filters'
+        },
+        {
+          currentNameFilter: 'a',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'name filter'
+        },
+        {
+          currentNameFilter: '0',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'name filter with "0" as string'
+        },
+        {
+          currentNameFilter: '',
+          currentTypeFilter: {
+            value: 'LOCAL'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'type filter'
+        },
+        {
+          currentNameFilter: '',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'activity filter'
+        },
+        {
+          currentNameFilter: 'a',
+          currentTypeFilter: {
+            value: 'LOCAL'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'name and type filters'
+        },
+        {
+          currentNameFilter: 'a',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'name and activity filters'
+        },
+        {
+          currentNameFilter: 'a',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'name and admin filters'
+        },
+        {
+          currentNameFilter: '0',
+          currentTypeFilter: {
+            value: 'LOCAL'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'name and type filters with "0" as string'
+        },
+        {
+          currentNameFilter: '0',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'name and activity filters with "0" as string'
+        },
+        {
+          currentNameFilter: '0',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'name and admin filters with "0" as string'
+        },
+        {
+          currentNameFilter: '',
+          currentTypeFilter: {
+            value: 'LOCAL'
+          },
+          currentActiveFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'type and activity filters'
+        },
+        {
+          currentNameFilter: '',
+          currentTypeFilter: {
+            value: 'LOCAL'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'type and admin filters'
+        },
+        {
+          currentNameFilter: '',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'activity and admin filters'
+        },
+        {
+          currentNameFilter: '',
+          currentTypeFilter: {
+            value: 'LOCAL'
+          },
+          currentActiveFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'all filters except name one'
+        },
+        {
+          currentNameFilter: 'a',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'all filters except type one'
+        },
+        {
+          currentNameFilter: 'a',
+          currentTypeFilter: {
+            value: 'LOCAL'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'all filters except activity one'
+        },
+        {
+          currentNameFilter: 'a',
+          currentTypeFilter: {
+            value: 'LOCAL'
+          },
+          currentActiveFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'all filters except admin one'
+        },
+        {
+          currentNameFilter: '0',
+          currentTypeFilter: {
+            value: '*'
+          },
+          currentActiveFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'all filters with "0" as string except type one'
+        },
+        {
+          currentNameFilter: '0',
+          currentTypeFilter: {
+            value: 'LOCAL'
+          },
+          currentActiveFilter: {
+            value: '*'
+          },
+          isNotEmptyFilter: true,
+          title: 'all filters with "0" as string except activity one'
+        },
+        {
+          currentNameFilter: '0',
+          currentTypeFilter: {
+            value: 'LOCAL'
+          },
+          currentActiveFilter: {
+            value: false
+          },
+          isNotEmptyFilter: true,
+          title: 'all filters with "0" as string except admin one'
+        },
+        {
+          currentNameFilter: 'a',
+          currentTypeFilter: {
+            value: false
+          },
+          currentActiveFilter: {
+            value: 'LOCAL'
+          },
+          isNotEmptyFilter: true,
+          title: 'all filters'
+        },
+        {
+          currentNameFilter: '0',
+          currentTypeFilter: {
+            value: false
+          },
+          currentActiveFilter: {
+            value: 'LOCAL'
+          },
+          isNotEmptyFilter: true,
+          title: 'all filters with "0" as string'
+        }
+      ];
+
+      cases.forEach(function (item) {
+        it(item.title, function () {
+          $httpBackend.expectGET(/\/api\/v1\/users/).respond(200);
+          scope.filters.name = item.currentNameFilter;
+          scope.filters.status = item.currentActiveFilter;
+          scope.filters.type = item.currentTypeFilter;
+          scope.$digest();
+          expect(scope.isNotEmptyFilter).toEqual(item.isNotEmptyFilter);
+        });
+      });
+
+    });
+
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/users/UsersListCtrl_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/users/UsersListCtrl_test.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/users/UsersListCtrl_test.js
deleted file mode 100644
index 9d6cd54..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/users/UsersListCtrl_test.js
+++ /dev/null
@@ -1,383 +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.
- */
-
-describe('#Cluster', function () {
-
-  describe('UsersListCtrl', function() {
-
-    var scope, ctrl, $t, $httpBackend;
-
-    beforeEach(module('ambariAdminConsole', function () {}));
-
-    beforeEach(inject(function($rootScope, $controller, _$translate_, _$httpBackend_) {
-      scope = $rootScope.$new();
-      $t = _$translate_.instant;
-      $httpBackend = _$httpBackend_;
-      ctrl = $controller('UsersListCtrl', {
-        $scope: scope
-      });
-    }));
-
-    describe('#clearFilters()', function () {
-
-      it('should clear filters and reset pagination', function () {
-        scope.currentPage = 2;
-        scope.currentNameFilter = 'a';
-        scope.currentActiveFilter = {
-          label: $t('common.local'),
-          value: false
-        };
-        scope.currentTypeFilter = {
-          label: $t('common.local'),
-          value: 'LOCAL'
-        };
-        scope.adminFilter = true;
-        scope.clearFilters();
-        expect(scope.currentNameFilter).toEqual('');
-        expect(scope.currentActiveFilter).toEqual({
-          label: $t('common.all'),
-          value: '*'
-        });
-        expect(scope.currentTypeFilter).toEqual({
-          label: $t('common.all'),
-          value: '*'
-        });
-        expect(scope.currentPage).toEqual(1);
-        expect(scope.adminFilter).toBe(false);
-      });
-
-    });
-
-    describe('#isNotEmptyFilter', function () {
-
-      var cases = [
-        {
-          currentNameFilter: '',
-          currentTypeFilter: null,
-          currentActiveFilter: null,
-          isNotEmptyFilter: false,
-          adminFilter: false,
-          title: 'no filters'
-        },
-        {
-          currentNameFilter: '',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: false,
-          isNotEmptyFilter: false,
-          title: 'empty filters'
-        },
-        {
-          currentNameFilter: 'a',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'name filter'
-        },
-        {
-          currentNameFilter: '0',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'name filter with "0" as string'
-        },
-        {
-          currentNameFilter: '',
-          currentTypeFilter: {
-            value: 'LOCAL'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'type filter'
-        },
-        {
-          currentNameFilter: '',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: false
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'activity filter'
-        },
-        {
-          currentNameFilter: '',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'admin filter'
-        },
-        {
-          currentNameFilter: 'a',
-          currentTypeFilter: {
-            value: 'LOCAL'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'name and type filters'
-        },
-        {
-          currentNameFilter: 'a',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: false
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'name and activity filters'
-        },
-        {
-          currentNameFilter: 'a',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'name and admin filters'
-        },
-        {
-          currentNameFilter: '0',
-          currentTypeFilter: {
-            value: 'LOCAL'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'name and type filters with "0" as string'
-        },
-        {
-          currentNameFilter: '0',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: false
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'name and activity filters with "0" as string'
-        },
-        {
-          currentNameFilter: '0',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'name and admin filters with "0" as string'
-        },
-        {
-          currentNameFilter: '',
-          currentTypeFilter: {
-            value: 'LOCAL'
-          },
-          currentActiveFilter: {
-            value: false
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'type and activity filters'
-        },
-        {
-          currentNameFilter: '',
-          currentTypeFilter: {
-            value: 'LOCAL'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'type and admin filters'
-        },
-        {
-          currentNameFilter: '',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: false
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'activity and admin filters'
-        },
-        {
-          currentNameFilter: '',
-          currentTypeFilter: {
-            value: 'LOCAL'
-          },
-          currentActiveFilter: {
-            value: false
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'all filters except name one'
-        },
-        {
-          currentNameFilter: 'a',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: false
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'all filters except type one'
-        },
-        {
-          currentNameFilter: 'a',
-          currentTypeFilter: {
-            value: 'LOCAL'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'all filters except activity one'
-        },
-        {
-          currentNameFilter: 'a',
-          currentTypeFilter: {
-            value: 'LOCAL'
-          },
-          currentActiveFilter: {
-            value: false
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'all filters except admin one'
-        },
-        {
-          currentNameFilter: '0',
-          currentTypeFilter: {
-            value: '*'
-          },
-          currentActiveFilter: {
-            value: false
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'all filters with "0" as string except type one'
-        },
-        {
-          currentNameFilter: '0',
-          currentTypeFilter: {
-            value: 'LOCAL'
-          },
-          currentActiveFilter: {
-            value: '*'
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'all filters with "0" as string except activity one'
-        },
-        {
-          currentNameFilter: '0',
-          currentTypeFilter: {
-            value: 'LOCAL'
-          },
-          currentActiveFilter: {
-            value: false
-          },
-          adminFilter: false,
-          isNotEmptyFilter: true,
-          title: 'all filters with "0" as string except admin one'
-        },
-        {
-          currentNameFilter: 'a',
-          currentTypeFilter: {
-            value: false
-          },
-          currentActiveFilter: {
-            value: 'LOCAL'
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'all filters'
-        },
-        {
-          currentNameFilter: '0',
-          currentTypeFilter: {
-            value: false
-          },
-          currentActiveFilter: {
-            value: 'LOCAL'
-          },
-          adminFilter: true,
-          isNotEmptyFilter: true,
-          title: 'all filters with "0" as string'
-        }
-      ];
-
-      cases.forEach(function (item) {
-        it(item.title, function () {
-          $httpBackend.expectGET(/\/api\/v1\/users/).respond(200);
-          scope.currentNameFilter = item.currentNameFilter;
-          scope.currentActiveFilter = item.currentActiveFilter;
-          scope.currentTypeFilter = item.currentTypeFilter;
-          scope.adminFilter = item.adminFilter;
-          scope.$digest();
-          expect(scope.isNotEmptyFilter).toEqual(item.isNotEmptyFilter);
-        });
-      });
-
-    });
-
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/test/unit/services/Utility_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/services/Utility_test.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/services/Utility_test.js
index 1b76dcf..7f67de4 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/test/unit/services/Utility_test.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/test/unit/services/Utility_test.js
@@ -25,7 +25,13 @@ describe('Utility Service', function () {
 
   beforeEach(function () {
     module('ambariAdminConsole', function ($provide) {
-      $provide.value('$window', {});
+      $provide.value('$window', {
+        localStorage: {
+          getItem: function() {return '{}';},
+          setItem: function() {}
+        },
+        location: {}
+      });
     });
     inject(function (_Utility_, _$httpBackend_, $rootScope, $controller, _Cluster_, _$q_) {
       Utility = _Utility_;
@@ -54,7 +60,7 @@ describe('Utility Service', function () {
       httpBackend.whenGET(/\/api\/v1\/views.+/).respond(200, {
         items: []
       });
-      httpBackend.whenGET("views/clusterInformation.html").respond(200, {});
+      httpBackend.whenGET("views/clusters/clusterInformation.html").respond(200, {});
     });
   });
 


[44/49] ambari git commit: AMBARI-22519 Admin View: add ability to change roles. (atkach)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html
index 0372a11..cc46173 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html
@@ -16,13 +16,13 @@
 * limitations under the License.
 -->
     
-<div ng-show="user" class="user-edit-panel">
+<div ng-show="user" id="user-edit">
   <div class="clearfix">
     <ol class="breadcrumb pull-left">
-      <li><a href="#/userManagement">{{'common.users' | translate}}</a></li>
+      <li><a href="#/userManagement?tab=users">{{'common.users' | translate}}</a></li>
       <li class="active"><span class="glyphicon glyphicon-flash" ng-show="user.admin"></span>{{user.user_name}}</li>
     </ol>
-    <div class="pull-right top-margin-4">
+    <div class="pull-right">
       <div ng-switch="isCurrentUser || user.user_type != 'LOCAL'">
         <button class="btn deleteuser-btn disabled btn-default" ng-switch-when="true" tooltip="{{'common.cannotDelete' | translate: '{term: constants.user}'}}">{{'common.delete' | translate: '{term: constants.user}'}}</button>
         <button class="btn deleteuser-btn btn-danger" ng-switch-when="false" ng-click="deleteUser()">{{'common.delete' | translate: '{term: constants.user}'}}</button>
@@ -32,25 +32,25 @@
   <hr>
   <form class="form-horizontal" role="form" >
     <div class="form-group">
-      <label for="" class="col-sm-2 control-label">{{'common.type' | translate}}</label>
+      <label class="col-sm-2 ">{{'common.type' | translate}}</label>
       <div class="col-sm-10">
-        <label for="" class="control-label">{{user.userTypeName}}</label>
+        <label>{{user.userTypeName}}</label>
       </div>
     </div>
     <div class="form-group">
-      <label for="" class="col-sm-2 control-label">{{'users.status' | translate}}</label>
+      <label class="col-sm-2 ">{{'users.status' | translate}}</label>
       <div class="col-sm-10">
         <toggle-switch on-change="toggleUserActive()" disabled-tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.status}'}}" ng-disabled="isCurrentUser" model="user.active" on-label="{{'users.active' | translate}}" off-label="{{'users.inactive' | translate}}" class="switch-primary userstatus {{user ? '' : 'no-animation'}}" data-off-color="danger"></toggle-switch>
       </div>
     </div>
     <div class="form-group">
-      <label for="" class="col-sm-2 control-label"><span class="glyphicon glyphicon-flash"></span> {{'users.ambariAdmin' | translate}}</label>
+      <label class="col-sm-2 "><span class="glyphicon glyphicon-flash"></span> {{'users.ambariAdmin' | translate}}</label>
       <div class="col-sm-10">
         <toggle-switch on-change="toggleUserAdmin()" disabled-tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.admin}'}}" ng-disabled="isCurrentUser" model="user.admin" on-label="{{'common.yes' | translate}}" off-label="{{'common.no' | translate}}" class="switch-primary userstatus {{user ? '' : 'no-animation'}}" data-off-color="danger"></toggle-switch>
       </div>
     </div>
     <div class="form-group">
-      <label for="password" class="col-sm-2 control-label">{{'users.password' | translate}}</label>
+      <label class="col-sm-2 ">{{'users.password' | translate}}</label>
       <div class="col-sm-10">
         <div ng-switch="user.user_type != 'LOCAL'">
           <button class="btn deleteuser-btn disabled btn-default" ng-switch-when="true" tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.password}'}}">{{'users.changePassword' | translate}}</button>
@@ -60,14 +60,32 @@
       </div>
     </div>
     <div class="form-group">
-      <label for="groups" class="col-sm-2 control-label">{{getUserMembership(user.user_type)}}</label>
+      <label class="col-sm-2 ">{{getUserMembership(user.user_type)}}</label>
       <div class="col-sm-10">
         <editable-list items-source="editingGroupsList" resource-type="Group" editable="user.user_type == 'LOCAL'"></editable-list>
       </div>
-        
     </div>
+
+    <div class="form-group">
+      <label for="role" class="col-sm-2 roles-label">
+        {{'users.role' | translate}}
+        <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
+      </label>
+      <div class="col-sm-3">
+        <select ng-hide="user.admin"
+                class="form-control"
+                id="role"
+                name="role"
+                ng-options="item as item.permission_label for item in roleOptions track by item.permission_name"
+                ng-change="updateRole()"
+                ng-model="currentRole">
+        </select>
+        <span ng-show="user.admin" class="roles-label">{{user.roles[0].permission_label}}</span>
+      </div>
+    </div>
+
     <div class="form-group" >
-      <label for="" class="col-sm-2 control-label">{{'common.privileges' | translate}}</label>
+      <label class="col-sm-2 ">{{'common.privileges' | translate}}</label>
       <div class="col-sm-10">
         <table class="table" ng-hide="hidePrivileges || user.admin">
           <thead>
@@ -77,7 +95,7 @@
             </tr>
           </thead>
           <tbody>
-            <tr ng-repeat="(name, privilege) in privileges.clusters">
+            <tr ng-repeat="(name, privilege) in privilegesView.clusters">
               <td>
                 <span class="glyphicon glyphicon-cloud"></span> 
                 <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
@@ -97,7 +115,7 @@
             </tr>
           </thead>
           <tbody>
-            <tr ng-repeat="(name, privilege) in privileges.views">
+            <tr ng-repeat="(name, privilege) in privilegesView.views">
               <td>
                 <span class="glyphicon glyphicon-th"></span>
                 <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
@@ -106,7 +124,7 @@
                 <span tooltip="{{item}}" ng-repeat="item in privilege.privileges track by $index">{{item | translate}}{{$last ? '' : ', '}}</span>
               </td>
               <td>
-                <i class="fa fa-trash-o" aria-hidden="true" ng-click="removePrivilege(name, privilege);"></i>
+                <i class="fa fa-trash-o" aria-hidden="true" ng-click="removeViewPrivilege(name, privilege);"></i>
               </td>
             </tr>
             <tr>
@@ -114,7 +132,7 @@
             </tr>
           </tbody>
         </table>
-        <div class="alert alert-info" ng-show="!privileges && !user.admin">{{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.user}'}}</div>
+        <div class="alert alert-info" ng-show="hidePrivileges && !user.admin">{{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.user}'}}</div>
         <div class="alert alert-info" ng-show="user.admin">{{'users.userIsAdmin' | translate}}</div>
       </div>
     </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html
index cc4789b..4a33a31 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html
@@ -78,7 +78,7 @@
           <span>{{user.Users.user_name}}</span>
         </td>
         <td>
-          <span>{{user.Users.role}}</span>
+          <span>{{user.Users.roles[0].permission_label}}</span>
         </td>
         <td>
           <span>


[49/49] ambari git commit: Merge branch 'trunk' into branch-feature-AMBARI-20859

Posted by rl...@apache.org.
 Merge branch 'trunk' into branch-feature-AMBARI-20859


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 167b4829413d5119f11fd0bb12c8db340a78b540
Parents: d173011 0b98ccd
Author: Robert Levas <rl...@hortonworks.com>
Authored: Mon Nov 27 15:23:58 2017 -0500
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Mon Nov 27 15:23:58 2017 -0500

----------------------------------------------------------------------
 .../main/resources/ui/admin-web/app/index.html  |  19 +-
 .../resources/ui/admin-web/app/scripts/app.js   |   3 +-
 .../controllers/ClusterInformationCtrl.js       |  65 --
 .../ambariViews/CloneViewInstanceCtrl.js        | 274 -------
 .../ambariViews/CreateViewInstanceCtrl.js       | 103 ++-
 .../controllers/ambariViews/ViewsListCtrl.js    |  25 +-
 .../clusters/ClusterInformationCtrl.js          | 106 +++
 .../clusters/ClustersManageAccessCtrl.js        |  97 ---
 .../controllers/clusters/UserAccessListCtrl.js  | 351 --------
 .../controllers/groups/GroupsCreateCtrl.js      |  65 --
 .../controllers/groups/GroupsEditCtrl.js        | 180 ----
 .../controllers/groups/GroupsListCtrl.js        | 106 ---
 .../stackVersions/StackVersionsEditCtrl.js      |  27 +-
 .../userManagement/GroupCreateCtrl.js           | 120 +++
 .../controllers/userManagement/GroupEditCtrl.js | 248 ++++++
 .../userManagement/GroupsListCtrl.js            | 167 ++++
 .../userManagement/UserCreateCtrl.js            | 113 +++
 .../controllers/userManagement/UserEditCtrl.js  | 364 ++++++++
 .../userManagement/UserManagementCtrl.js        |  23 +
 .../controllers/userManagement/UsersListCtrl.js | 177 ++++
 .../controllers/users/UsersCreateCtrl.js        |  75 --
 .../scripts/controllers/users/UsersListCtrl.js  | 122 ---
 .../scripts/controllers/users/UsersShowCtrl.js  | 294 -------
 .../ui/admin-web/app/scripts/i18n.config.js     |  17 +-
 .../ui/admin-web/app/scripts/routes.js          |  67 +-
 .../admin-web/app/scripts/services/Cluster.js   |  90 +-
 .../ui/admin-web/app/scripts/services/Group.js  | 144 ++--
 .../app/scripts/services/GroupConstants.js      |  38 -
 .../app/scripts/services/RoleDetailsModal.js    |   5 +-
 .../ui/admin-web/app/scripts/services/Stack.js  |  14 +
 .../ui/admin-web/app/scripts/services/User.js   |  20 +-
 .../ui/admin-web/app/scripts/services/View.js   |   8 +-
 .../app/styles/cluster-information.css          |  13 +-
 .../resources/ui/admin-web/app/styles/main.css  | 121 +--
 .../ui/admin-web/app/styles/user-management.css |  43 +
 .../resources/ui/admin-web/app/styles/views.css |  90 +-
 .../admin-web/app/views/ambariViews/create.html | 200 -----
 .../app/views/ambariViews/modals/create.html    | 261 +++---
 .../app/views/ambariViews/viewsList.html        |  65 +-
 .../admin-web/app/views/clusterInformation.html |  66 --
 .../app/views/clusters/clusterInformation.html  |  87 ++
 .../app/views/clusters/manageAccess.html        |  63 --
 .../app/views/clusters/userAccessList.html      | 102 ---
 .../ui/admin-web/app/views/groups/create.html   |  43 -
 .../ui/admin-web/app/views/groups/edit.html     |  98 ---
 .../ui/admin-web/app/views/groups/list.html     |  80 --
 .../app/views/remoteClusters/list.html          |   5 +-
 .../ui/admin-web/app/views/sideNav.html         |  22 +-
 .../admin-web/app/views/stackVersions/list.html |   7 +-
 .../views/stackVersions/stackVersionPage.html   |  28 +-
 .../ui/admin-web/app/views/urls/create.html     |   2 -
 .../ui/admin-web/app/views/urls/edit.html       |   2 -
 .../app/views/userManagement/groupEdit.html     | 122 +++
 .../app/views/userManagement/groupsList.html    |  94 +++
 .../app/views/userManagement/main.html          |  36 +
 .../userManagement/modals/changePassword.html   |  46 ++
 .../userManagement/modals/groupCreate.html      |  86 ++
 .../views/userManagement/modals/userCreate.html | 147 ++++
 .../app/views/userManagement/userEdit.html      | 140 ++++
 .../app/views/userManagement/usersList.html     | 119 +++
 .../ui/admin-web/app/views/users/create.html    |  82 --
 .../ui/admin-web/app/views/users/list.html      |  97 ---
 .../app/views/users/modals/changePassword.html  |  46 --
 .../ui/admin-web/app/views/users/show.html      | 135 ---
 .../unit/controllers/CloneViewInstanceCtrl.js   | 135 ---
 .../controllers/ClusterInformationCtrl_test.js  | 102 +++
 .../clusters/UserAccessListCtrl_test.js         | 820 -------------------
 .../controllers/groups/GroupsListCtrl_test.js   | 129 ---
 .../userManagement/GroupsListCtrl_test.js       | 129 +++
 .../userManagement/UsersListCtrl_test.js        | 344 ++++++++
 .../controllers/users/UsersListCtrl_test.js     | 383 ---------
 .../test/unit/services/Utility_test.js          |  10 +-
 .../src/main/python/ambari_agent/Hardware.py    | 130 +--
 .../src/main/python/ambari_agent/Heartbeat.py   |   8 +-
 .../src/main/python/ambari_agent/HostInfo.py    |  83 +-
 .../test/python/ambari_agent/TestHardware.py    |  56 +-
 .../python/ambari_agent/TestRegistration.py     |   5 +-
 .../core/providers/package/yumrpm.py            |   4 +-
 .../libraries/functions/__init__.py             |   2 +-
 .../libraries/functions/copy_tarball.py         |  99 ++-
 .../libraries/functions/get_lzo_packages.py     |  50 --
 .../libraries/functions/lzo_utils.py            |  93 +++
 .../libraries/functions/package_conditions.py   |   8 +-
 .../configsets/hadoop_logs/conf/managed-schema  |   2 +
 .../ambari/logsearch/solr/SolrConstants.java    |   1 +
 .../solr/model/SolrServiceLogData.java          |  17 +
 .../ambari-logsearch-web/src/app/app.module.ts  |   6 +-
 .../components/logs-table-component.spec.ts     |  61 ++
 .../classes/components/logs-table-component.ts  |  51 ++
 .../src/app/classes/models/audit-log.ts         |   2 +-
 .../audit-logs-table.component.html             |  54 ++
 .../audit-logs-table.component.less             |  21 +
 .../audit-logs-table.component.spec.ts          | 157 ++++
 .../audit-logs-table.component.ts               |  55 ++
 .../date-picker/date-picker.component.spec.ts   |   2 +
 .../date-picker/date-picker.component.ts        |  35 +-
 .../filters-panel/filters-panel.component.ts    |   2 +-
 .../logs-container.component.html               |  15 +-
 .../logs-container/logs-container.component.ts  |  62 +-
 .../logs-list/logs-list.component.html          |  72 --
 .../logs-list/logs-list.component.less          |  97 ---
 .../logs-list/logs-list.component.spec.ts       | 110 ---
 .../components/logs-list/logs-list.component.ts | 151 ----
 .../service-logs-table.component.html           |  76 ++
 .../service-logs-table.component.less           |  97 +++
 .../service-logs-table.component.spec.ts        | 126 +++
 .../service-logs-table.component.ts             | 135 +++
 .../time-range-picker.component.html            |   6 +-
 .../time-range-picker.component.ts              |  12 +-
 .../ambari-logsearch-web/src/app/mock-data.ts   |   4 +-
 .../src/app/services/auth.service.spec.ts       |   2 +-
 .../src/app/services/logs-container.service.ts  | 115 ++-
 .../src/app/services/mock-api-data.service.ts   |  22 +
 .../src/assets/i18n/en.json                     |   4 +-
 ambari-metrics/ambari-metrics-assembly/pom.xml  |   1 -
 .../ambari-metrics-hadoop-sink/pom.xml          |   3 +-
 .../timeline/HadoopTimelineMetricsSink.java     |   6 +-
 .../timeline/HadoopTimelineMetricsSinkTest.java |  21 +-
 .../actionmanager/ExecutionCommandWrapper.java  |  42 +-
 .../ambari/server/agent/CommandRepository.java  |   2 +-
 .../ambari/server/agent/ExecutionCommand.java   |   1 +
 .../ambari/server/agent/HeartbeatMonitor.java   |   3 +-
 .../commands/StackAdvisorCommand.java           |  15 +-
 .../apache/ambari/server/checks/LZOCheck.java   |   6 +-
 .../server/configuration/Configuration.java     |  19 +
 .../controller/ActionExecutionContext.java      |   6 +-
 .../controller/AmbariActionExecutionHelper.java |  72 +-
 .../AmbariCustomCommandExecutionHelper.java     | 259 +-----
 .../AmbariManagementControllerImpl.java         |  21 +-
 .../server/controller/KerberosHelperImpl.java   |   6 +-
 .../server/controller/RepositoryResponse.java   |  23 +-
 .../internal/ClientConfigResourceProvider.java  |   2 +
 .../ClusterStackVersionResourceProvider.java    |  16 +-
 .../HostStackVersionResourceProvider.java       |   3 +-
 .../internal/RepositoryResourceProvider.java    |   3 +
 ...eComponentConfigurationResourceProvider.java |   8 +-
 .../internal/UpgradeResourceProvider.java       |   3 +-
 .../VersionDefinitionResourceProvider.java      |   9 +
 .../server/orm/entities/RepositoryEntity.java   |  53 +-
 .../AbstractPrepareKerberosServerAction.java    |   6 +-
 .../PrepareKerberosIdentitiesServerAction.java  |   5 +-
 .../apache/ambari/server/stack/RepoUtil.java    |   1 +
 .../ambari/server/stack/StackManager.java       |   5 -
 .../ambari/server/state/ConfigHelper.java       |  28 +-
 .../ambari/server/state/RepositoryInfo.java     |  23 +-
 .../ambari/server/state/stack/RepoTag.java      |  34 +
 .../server/state/stack/RepositoryXml.java       |  13 +
 .../stack/upgrade/RepositoryVersionHelper.java  | 330 +++++++-
 .../ambari/server/topology/AmbariContext.java   |   3 +-
 .../server/topology/BlueprintFactory.java       |   3 +-
 .../validators/RequiredPasswordValidator.java   |   3 +-
 .../server/upgrade/AbstractUpgradeCatalog.java  |   8 +
 .../server/upgrade/SchemaUpgradeHelper.java     |  27 +
 .../ambari/server/upgrade/UpgradeCatalog.java   |   6 +
 .../server/upgrade/UpgradeCatalog260.java       | 182 +++-
 .../server/upgrade/UpgradeCatalog261.java       | 119 +++
 ambari-server/src/main/python/ambari-server.py  |   2 +
 .../python/ambari_server/serverConfiguration.py |  29 +
 .../main/python/ambari_server/serverSetup.py    |   8 +-
 .../main/python/ambari_server/serverUpgrade.py  |  18 +-
 .../DRUID/0.10.1/package/scripts/druid.py       |   3 +-
 .../DRUID/0.10.1/package/scripts/params.py      |   5 +-
 .../common-services/HDFS/2.1.0.2.0/metainfo.xml |  30 -
 .../HDFS/2.1.0.2.0/package/scripts/hdfs.py      |   8 +-
 .../2.1.0.2.0/package/scripts/install_params.py |   4 -
 .../2.1.0.2.0/package/scripts/params_linux.py   |   5 -
 .../common-services/HDFS/3.0.0.3.0/metainfo.xml |  30 -
 .../HDFS/3.0.0.3.0/package/scripts/hdfs.py      |   8 +-
 .../3.0.0.3.0/package/scripts/install_params.py |   4 -
 .../3.0.0.3.0/package/scripts/params_linux.py   |   4 -
 .../HIVE/0.12.0.2.0/configuration/hive-site.xml |   2 +-
 .../HIVE/0.12.0.2.0/package/scripts/hive.py     |  15 +-
 .../package/scripts/hive_server_interactive.py  |  20 +-
 .../HIVE/2.1.0.3.0/package/scripts/hive.py      |   3 +
 .../OOZIE/4.0.0.2.0/package/scripts/oozie.py    |  38 +-
 .../4.0.0.2.0/package/scripts/params_linux.py   |   5 +-
 .../OOZIE/4.2.0.3.0/package/scripts/oozie.py    |  15 +-
 .../4.2.0.3.0/package/scripts/params_linux.py   |   5 +-
 .../0.5.0.2.3/configuration/kms-site.xml        |  26 -
 .../1.0.0.3.0/configuration/kms-site.xml        |  26 -
 .../TEZ/0.4.0.2.1/package/scripts/tez.py        |   5 +-
 .../TEZ/0.9.0.3.0/configuration/tez-site.xml    |   4 +-
 .../TEZ/0.9.0.3.0/package/scripts/tez.py        |   4 +
 .../configuration-mapred/mapred-site.xml        |   2 +-
 .../YARN/2.1.0.2.0/package/scripts/yarn.py      |   3 +
 .../configuration-mapred/mapred-site.xml        |   2 +-
 .../YARN/3.0.0.3.0/package/scripts/yarn.py      |   3 +
 .../HDP/2.0.6/properties/stack_packages.json    |   2 +-
 .../services/HIVE/configuration/hive-site.xml   |   2 +-
 .../stacks/HDP/2.2/services/HDFS/metainfo.xml   |  35 -
 .../services/HIVE/configuration/hive-site.xml   |   2 +-
 .../2.2/services/TEZ/configuration/tez-site.xml |   4 +-
 .../YARN/configuration-mapred/mapred-site.xml   |   2 +-
 .../stacks/HDP/2.3/services/HDFS/metainfo.xml   |  30 -
 .../stacks/HDP/2.5/services/YARN/kerberos.json  |  12 +-
 .../stacks/HDP/2.6/services/YARN/kerberos.json  |  24 +-
 .../stacks/HDP/2.6/upgrades/config-upgrade.xml  |   6 +-
 .../HDP/3.0/properties/stack_packages.json      |   2 +-
 .../stacks/HDP/3.0/services/HDFS/metainfo.xml   |  30 -
 .../src/main/resources/version_definition.xsd   |  23 +-
 .../ambari/server/checks/LZOCheckTest.java      |  13 +-
 .../AmbariCustomCommandExecutionHelperTest.java |  13 +-
 .../AmbariManagementControllerImplTest.java     |   3 +-
 .../AmbariManagementControllerTest.java         | 176 ++--
 .../ClientConfigResourceProviderTest.java       |   2 +
 ...ClusterStackVersionResourceProviderTest.java |  51 +-
 .../RepositoryResourceProviderTest.java         |   6 +-
 .../internal/UpgradeResourceProviderTest.java   |  12 +-
 .../apache/ambari/server/orm/OrmTestHelper.java |   4 +-
 .../ambari/server/state/ConfigHelperTest.java   |  47 ++
 .../state/repository/VersionDefinitionTest.java |  35 +-
 .../upgrade/RepositoryVersionHelperTest.java    |   2 +-
 .../server/upgrade/UpgradeCatalog260Test.java   | 136 ++-
 .../src/test/python/TestAmbariServer.py         |   7 +-
 .../stacks/2.2/configs/oozie-upgrade.json       |   3 +-
 .../HIVE/running_withMOTDmsg_andTrailingMsg.txt |  46 ++
 .../stacks/2.5/HIVE/test_hive_server_int.py     |  21 +
 .../test_kerberos_descriptor_ranger_kms.json    | 286 +++++++
 .../resources/version_definition_with_tags.xml  |  86 ++
 ambari-web/app/controllers/installer.js         |  53 +-
 .../main/service/reassign/step3_controller.js   |   3 +
 .../main/service/reassign/step4_controller.js   |  12 +-
 .../app/controllers/wizard/step8_controller.js  |  12 +-
 .../app/mappers/repository_version_mapper.js    |   3 +-
 ambari-web/app/mappers/stack_mapper.js          |   3 +-
 ambari-web/app/messages.js                      |   5 +-
 ambari-web/app/mixins/common/serverValidator.js |  41 +-
 .../main/host/details/actions/check_host.js     |   2 +-
 .../app/mixins/wizard/addSecurityConfigs.js     |   7 +
 ambari-web/app/models/repository.js             |  17 +
 .../app/models/stack_version/repository.js      |   3 +-
 ambari-web/app/styles/application.less          |   3 +-
 .../config_recommendation_popup.hbs             | 102 ++-
 ambari-web/app/templates/wizard/step1.hbs       |  36 +
 .../config_validation_popup.js                  |   7 +-
 ambari-web/test/controllers/installer_test.js   |  14 +-
 .../service/reassign/step4_controller_test.js   |   9 +-
 .../test/mixins/common/serverValidator_test.js  |  15 +-
 contrib/utils/perf/deploy-gce-perf-cluster.py   |   1 +
 contrib/version-builder/version_builder.py      |  13 +-
 .../apache/ambari/view/utils/hdfs/HdfsApi.java  |  16 +-
 .../apache/ambari/view/utils/hdfs/HdfsUtil.java |  17 +-
 .../ui/app/domain/workflow-importer.js          |   3 +-
 243 files changed, 7123 insertions(+), 6369 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/167b4829/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/167b4829/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/167b4829/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/167b4829/ambari-server/src/main/python/ambari-server.py
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/167b4829/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/167b4829/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
----------------------------------------------------------------------


[46/49] ambari git commit: AMBARI-22522 - Livy server fails to start during downgrade due to absence of 'conf' directory (jonathanhurley)

Posted by rl...@apache.org.
AMBARI-22522 - Livy server fails to start during downgrade due to absence of 'conf' directory (jonathanhurley)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 1d9985cf5727bd4b8085ee0afe477b759875b348
Parents: 32e25b8
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Nov 27 09:03:23 2017 -0500
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Nov 27 12:04:02 2017 -0500

----------------------------------------------------------------------
 .../main/resources/stacks/HDP/2.0.6/properties/stack_packages.json | 2 +-
 .../main/resources/stacks/HDP/3.0/properties/stack_packages.json   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/1d9985cf/ambari-server/src/main/resources/stacks/HDP/2.0.6/properties/stack_packages.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/properties/stack_packages.json b/ambari-server/src/main/resources/stacks/HDP/2.0.6/properties/stack_packages.json
index 245449c..794d2b0 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/properties/stack_packages.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/properties/stack_packages.json
@@ -1069,7 +1069,7 @@
       "livy": [
         {
           "conf_dir": "/etc/livy/conf",
-          "current_dir": "{0}/current/livy"
+          "current_dir": "{0}/current/livy-client/conf"
         }
       ],
       "mahout": [

http://git-wip-us.apache.org/repos/asf/ambari/blob/1d9985cf/ambari-server/src/main/resources/stacks/HDP/3.0/properties/stack_packages.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/3.0/properties/stack_packages.json b/ambari-server/src/main/resources/stacks/HDP/3.0/properties/stack_packages.json
index 5603c0c..5fb61c8 100644
--- a/ambari-server/src/main/resources/stacks/HDP/3.0/properties/stack_packages.json
+++ b/ambari-server/src/main/resources/stacks/HDP/3.0/properties/stack_packages.json
@@ -946,7 +946,7 @@
       "livy": [
         {
           "conf_dir": "/etc/livy/conf",
-          "current_dir": "{0}/current/livy"
+          "current_dir": "{0}/current/livy-client/conf"
         }
       ],
       "mahout": [


[12/49] ambari git commit: AMBARI-22471 : 'yum remove snappy' deletes ambari-metrics-collector. (avijayan)

Posted by rl...@apache.org.
AMBARI-22471 : 'yum remove snappy' deletes ambari-metrics-collector. (avijayan)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 9910c49716d3d31eae665ab1ba0f8fbafd33c1bf
Parents: af8c401
Author: Aravindan Vijayan <av...@hortonworks.com>
Authored: Mon Nov 20 10:44:50 2017 -0800
Committer: Aravindan Vijayan <av...@hortonworks.com>
Committed: Mon Nov 20 10:44:50 2017 -0800

----------------------------------------------------------------------
 ambari-metrics/ambari-metrics-assembly/pom.xml | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9910c497/ambari-metrics/ambari-metrics-assembly/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-assembly/pom.xml b/ambari-metrics/ambari-metrics-assembly/pom.xml
index 9925947..43ff285 100644
--- a/ambari-metrics/ambari-metrics-assembly/pom.xml
+++ b/ambari-metrics/ambari-metrics-assembly/pom.xml
@@ -226,7 +226,6 @@
                   <description>Maven Recipe: RPM Package.</description>
                   <autoRequires>false</autoRequires>
                   <requires>
-                    <require>snappy</require>
                     <require>${python.ver}</require>
                   </requires>
 


[38/49] ambari git commit: AMBARI-22508 Ambari 3.0: Implement new design for Admin View: User Management. (atkach)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
new file mode 100644
index 0000000..abe1780
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
@@ -0,0 +1,178 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('UsersListCtrl',
+['$scope', 'User', '$modal', '$rootScope', 'UserConstants', '$translate', 'Cluster', 'View', 'ConfirmationModal', 'Settings',
+function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, View, ConfirmationModal, Settings) {
+  var $t = $translate.instant;
+  $scope.constants = {
+    admin: $t('users.ambariAdmin'),
+    users: $t('common.users').toLowerCase()
+  };
+  $scope.minRowsToShowPagination = Settings.minRowsToShowPagination;
+  $scope.isLoading = false;
+  $scope.users = [];
+  $scope.usersPerPage = 10;
+  $scope.currentPage = 1;
+  $scope.totalUsers = 0;
+  $scope.filters = {
+    name: '',
+    status: null,
+    type: null
+  };
+  $scope.maxVisiblePages = 20;
+  $scope.tableInfo = {
+    total: 0,
+    showed: 0
+  };
+  $scope.isNotEmptyFilter = true;
+
+  $scope.pageChanged = function() {
+    $scope.loadUsers();
+  };
+  $scope.usersPerPageChanges = function() {
+    $scope.resetPagination();
+  };
+
+  $scope.loadUsers = function(){
+    $scope.isLoading = true;
+    User.list({
+      currentPage: $scope.currentPage,
+      usersPerPage: $scope.usersPerPage,
+      searchString: $scope.filters.name,
+      user_type: $scope.filters.type.value,
+      active: $scope.filters.status.value
+    }).then(function(data) {
+      $scope.isLoading = false;
+      $scope.totalUsers = data.data.itemTotal;
+      $scope.users = data.data.items.map(User.makeUser);
+      $scope.tableInfo.showed = data.data.items.length;
+      $scope.tableInfo.total = data.data.itemTotal;
+    });
+  };
+
+  $scope.resetPagination = function() {
+    $scope.currentPage = 1;
+    $scope.loadUsers();
+  };
+
+  $scope.activeFilterOptions = [
+    {label: $t('common.all'), value: '*'},
+    {label: $t('users.active'), value: true},
+    {label: $t('users.inactive'), value:false}
+  ];
+  $scope.filters.status = $scope.activeFilterOptions[0];
+
+  $scope.typeFilterOptions = [{ label: $t('common.all'), value: '*'}]
+    .concat(Object.keys(UserConstants.TYPES).map(function(key) {
+      return {
+        label: $t(UserConstants.TYPES[key].LABEL_KEY),
+        value: UserConstants.TYPES[key].VALUE
+      };
+    }));
+
+  $scope.filters.type = $scope.typeFilterOptions[0];
+
+  $scope.clearFilters = function () {
+    $scope.filters.name = '';
+    $scope.filters.type = $scope.typeFilterOptions[0];
+    $scope.filters.status = $scope.activeFilterOptions[0];
+    $scope.resetPagination();
+  };
+
+  $scope.loadUsers();
+
+  $scope.$watch(
+    function (scope) {
+      return Boolean(scope.filters.name || (scope.filters.status && scope.filters.status.value !== '*')
+        || (scope.filters.type && scope.filters.type.value !== '*'));
+    },
+    function (newValue, oldValue, scope) {
+      scope.isNotEmptyFilter = newValue;
+    }
+  );
+
+  $rootScope.$watch(function(scope) {
+    return scope.LDAPSynced;
+  }, function(LDAPSynced) {
+    if(LDAPSynced === true){
+      $rootScope.LDAPSynced = false;
+      $scope.loadUsers();
+    }
+  });
+
+  $scope.createUser = function () {
+    var modalInstance = $modal.open({
+      templateUrl: 'views/userManagement/modals/userCreate.html',
+      controller: 'UserCreateCtrl',
+      backdrop: 'static'
+    });
+
+    modalInstance.result.finally($scope.loadUsers);
+  };
+
+  $scope.deleteUser = function(user) {
+    ConfirmationModal.show(
+      $t('common.delete', {
+        term: $t('common.user')
+      }),
+      $t('common.deleteConfirmation', {
+        instanceType: $t('common.user').toLowerCase(),
+        instanceName: '"' + user.user_name + '"'
+      })
+    ).then(function() {
+      Cluster.getPrivilegesForResource({
+        nameFilter : user.user_name,
+        typeFilter : {value: 'USER'}
+      }).then(function(data) {
+        var clusterPrivilegesIds = [];
+        var viewsPrivileges = [];
+        if (data.items && data.items.length) {
+          angular.forEach(data.items[0].privileges, function(privilege) {
+            if (privilege.PrivilegeInfo.principal_type === 'USER') {
+              if (privilege.PrivilegeInfo.type === 'VIEW') {
+                viewsPrivileges.push({
+                  id: privilege.PrivilegeInfo.privilege_id,
+                  view_name: privilege.PrivilegeInfo.view_name,
+                  version: privilege.PrivilegeInfo.version,
+                  instance_name: privilege.PrivilegeInfo.instance_name
+                });
+              } else {
+                clusterPrivilegesIds.push(privilege.PrivilegeInfo.privilege_id);
+              }
+            }
+          });
+        }
+        User.delete(user.user_name).then(function() {
+          if (clusterPrivilegesIds.length) {
+            Cluster.getAllClusters().then(function (clusters) {
+              var clusterName = clusters[0].Clusters.cluster_name;
+              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
+            });
+          }
+          angular.forEach(viewsPrivileges, function(privilege) {
+            View.deletePrivilege(privilege);
+          });
+          $scope.loadUsers();
+        });
+      });
+    });
+  };
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersCreateCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersCreateCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersCreateCtrl.js
deleted file mode 100644
index bcb7bfc..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersCreateCtrl.js
+++ /dev/null
@@ -1,75 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-.controller('UsersCreateCtrl',['$scope', '$routeParams', 'User', '$location', 'Alert', 'UnsavedDialog', '$translate', function($scope, $routeParams, User, $location, Alert, UnsavedDialog, $translate) {
-  var $t = $translate.instant;
-  $scope.user = {
-    active: true
-  };
-  var targetUrl = '/users';
-
-  $scope.createUser = function() {
-    $scope.form.submitted = true;
-    if ($scope.form.$valid){
-      User.create({
-        'Users/user_name': $scope.user.user_name,
-        'Users/password': $scope.user.password,
-        'Users/active': !!$scope.user.active,
-        'Users/admin': !!$scope.user.admin
-      }).then(function() {
-        Alert.success($t('users.alerts.userCreated', {
-          userName: $scope.user.user_name,
-          encUserName: encodeURIComponent($scope.user.user_name)
-        }));
-        $scope.form.$setPristine();
-        $location.path(targetUrl);
-      }).catch(function(data) {
-        Alert.error($t('users.alerts.userCreationError'), data.data.message);
-      });
-    }
-  };
-
-  $scope.cancel = function() {
-    $scope.form.$setPristine();
-    $location.path('/users');
-  };
-
-  $scope.$on('$locationChangeStart', function(event, __targetUrl) {
-        
-    if( $scope.form.$dirty ){
-      UnsavedDialog().then(function(action) {
-        targetUrl = __targetUrl.split('#').pop();
-        switch(action){
-          case 'save':
-            $scope.createUser();
-            break;
-          case 'discard':
-            $scope.form.$setPristine();
-            $location.path(targetUrl);
-            break;
-          case 'cancel':
-          targetUrl = '/users';
-            break;
-        }
-      });
-      event.preventDefault();
-    }
-  });
-}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersListCtrl.js
deleted file mode 100644
index 8146163..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersListCtrl.js
+++ /dev/null
@@ -1,122 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-  .controller('UsersListCtrl',['$scope', 'User', '$modal', '$rootScope', 'UserConstants', '$translate', 'Settings', function($scope, User, $modal, $rootScope, UserConstants, $translate, Settings) {
-  var $t = $translate.instant;
-  $scope.constants = {
-    admin: $t('users.ambariAdmin'),
-    users: $t('common.users').toLowerCase()
-  };
-  $scope.isLoading = false;
-  $scope.users = [];
-  $scope.usersPerPage = 10;
-  $scope.currentPage = 1;
-  $scope.totalUsers = 1;
-  $scope.currentNameFilter = '';
-  $scope.maxVisiblePages=20;
-  $scope.tableInfo = {
-    total: 0,
-    showed: 0
-  };
-  $scope.isNotEmptyFilter = true;
-
-  $scope.pageChanged = function() {
-    $scope.loadUsers();
-  };
-  $scope.usersPerPageChanges = function() {
-    $scope.resetPagination();
-  };
-
-  $scope.loadUsers = function(){
-    $scope.isLoading = true;
-    User.list({
-      currentPage: $scope.currentPage,
-      usersPerPage: $scope.usersPerPage,
-      searchString: $scope.currentNameFilter,
-      user_type: $scope.currentTypeFilter.value,
-      active: $scope.currentActiveFilter.value,
-      admin: $scope.adminFilter
-    }).then(function(data) {
-      $scope.isLoading = false;
-      $scope.totalUsers = data.data.itemTotal;
-      $scope.users = data.data.items.map(User.makeUser);
-      $scope.tableInfo.showed = data.data.items.length;
-      $scope.tableInfo.total = data.data.itemTotal;
-    });
-  };
-
-  $scope.resetPagination = function() {
-    $scope.currentPage = 1;
-    $scope.loadUsers();
-  };
-
-  $scope.activeFilterOptions = [
-    {label: $t('common.all'), value: '*'},
-    {label: $t('users.active'), value: true},
-    {label: $t('users.inactive'), value:false}
-  ];
-  $scope.currentActiveFilter = $scope.activeFilterOptions[0];
-
-  $scope.typeFilterOptions = [{ label: $t('common.all'), value: '*'}]
-    .concat(Object.keys(UserConstants.TYPES).map(function(key) {
-      return {
-        label: $t(UserConstants.TYPES[key].LABEL_KEY),
-        value: UserConstants.TYPES[key].VALUE
-      };
-    }));
-
-  $scope.currentTypeFilter = $scope.typeFilterOptions[0];
-
-  $scope.adminFilter = false;
-  $scope.toggleAdminFilter = function() {
-    $scope.adminFilter = !$scope.adminFilter;
-    $scope.resetPagination();
-    $scope.loadUsers();
-  };
-
-  $scope.clearFilters = function () {
-    $scope.currentNameFilter = '';
-    $scope.currentTypeFilter = $scope.typeFilterOptions[0];
-    $scope.currentActiveFilter = $scope.activeFilterOptions[0];
-    $scope.adminFilter = false;
-    $scope.resetPagination();
-  };
-
-  $scope.loadUsers();
-
-  $scope.$watch(
-    function (scope) {
-      return Boolean(scope.currentNameFilter || (scope.currentActiveFilter && scope.currentActiveFilter.value !== '*')
-        || (scope.currentTypeFilter && scope.currentTypeFilter.value !== '*') || $scope.adminFilter);
-    },
-    function (newValue, oldValue, scope) {
-      scope.isNotEmptyFilter = newValue;
-    }
-  );
-
-  $rootScope.$watch(function(scope) {
-    return scope.LDAPSynced;
-  }, function(LDAPSynced) {
-    if(LDAPSynced === true){
-      $rootScope.LDAPSynced = false;
-      $scope.loadUsers();
-    }
-  });
-}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersShowCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersShowCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersShowCtrl.js
deleted file mode 100644
index 200872e..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/users/UsersShowCtrl.js
+++ /dev/null
@@ -1,290 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-.controller('UsersShowCtrl', ['$scope', '$routeParams', 'Cluster', 'User', 'View', '$modal', '$location', 'ConfirmationModal', 'Alert', 'Auth', 'getDifference', 'Group', '$q', 'UserConstants', '$translate', function($scope, $routeParams, Cluster, User, View, $modal, $location, ConfirmationModal, Alert, Auth, getDifference, Group, $q, UserConstants, $translate) {
-
-  var $t = $translate.instant;
-
-  $scope.constants = {
-    user: $t('common.user'),
-    status: $t('users.status'),
-    admin: $t('users.admin'),
-    password: $t('users.password'),
-    view: $t('common.view').toLowerCase(),
-    cluster: $t('common.cluster').toLowerCase()
-  };
-
-  function loadUserInfo(){
-    User.get($routeParams.id).then(function(data) {
-      $scope.user = User.makeUser(data).Users;
-      $scope.isCurrentUser = $scope.user.user_name === Auth.getCurrentUser();
-      $scope.editingGroupsList = angular.copy($scope.user.groups);
-    });
-  }
-
-  loadUserInfo();
-  $scope.user;
-  $scope.isCurrentUser = true;
-  $scope.dataLoaded = false;
-
-  $scope.isGroupEditing = false;
-  $scope.enableGroupEditing = function() {
-    $scope.isGroupEditing = true;
-    $scope.editingGroupsList = angular.copy($scope.user.groups);
-  };
-
-  $scope.$watch(function() {
-    return $scope.editingGroupsList;
-  }, function(newValue) {
-    if(newValue){
-      if( !angular.equals(newValue, $scope.user.groups) ){
-        $scope.updateGroups();
-      }
-    }
-  }, true);
-
-  $scope.updateGroups = function() {
-    var groups = $scope.editingGroupsList.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()});
-    var diff = getDifference($scope.user.groups, groups);
-    var promises = [];
-    // Remove user from groups
-    angular.forEach(diff.del, function(groupName) {
-      promises.push(Group.removeMemberFromGroup(groupName, $scope.user.user_name).catch(function(data) {
-        Alert.error($t('users.alerts.removeUserError'), data.data.message);
-      }));
-    });
-    // Add user to groups
-    angular.forEach(diff.add, function(groupName) {
-      promises.push(Group.addMemberToGroup(groupName, $scope.user.user_name).catch(function(data) {
-        Alert.error($t('users.alerts.cannotAddUser'), data.data.message);
-      }));
-    });
-    $q.all(promises).then(function() {
-      loadUserInfo();
-    });
-    $scope.isGroupEditing = false;
-  };
-
-  $scope.getUserMembership = function(userType) {
-    if(userType) {
-	return $t(UserConstants.TYPES[userType].LABEL_KEY) + " " + $t('users.groupMembership');
-    }
-  };
-
-  $scope.cancelUpdate = function() {
-    $scope.isGroupEditing = false;
-    $scope.editingGroupsList = '';
-  };
-
-  $scope.openChangePwdDialog = function() {
-    var modalInstance = $modal.open({
-      templateUrl: 'views/users/modals/changePassword.html',
-      resolve: {
-        userName: function() {
-          return $scope.user.user_name;
-        }
-      },
-      controller: ['$scope', 'userName', function($scope, userName) {
-        $scope.passwordData = {
-          password: '',
-          currentUserPassword: ''
-        };
-
-        $scope.form = {};
-        $scope.userName = userName;
-
-        $scope.ok = function() {
-          $scope.form.passwordChangeForm.submitted = true;
-          if($scope.form.passwordChangeForm.$valid){
-
-            modalInstance.close({
-              password: $scope.passwordData.password, 
-              currentUserPassword: $scope.passwordData.currentUserPassword
-            });
-          }
-        };
-        $scope.cancel = function() {
-          modalInstance.dismiss('cancel');
-        };
-      }]
-    });
-
-    modalInstance.result.then(function(data) {
-      User.setPassword($scope.user, data.password, data.currentUserPassword).then(function() {
-        Alert.success($t('users.alerts.passwordChanged'));
-      }).catch(function(data) {
-        Alert.error($t('users.alerts.cannotChangePassword'), data.data.message);
-      });
-    }); 
-  };
-
-  $scope.toggleUserActive = function() {
-    if(!$scope.isCurrentUser){
-      var newStatusKey = $scope.user.active ? 'inactive' : 'active',
-        newStatus = $t('users.' + newStatusKey).toLowerCase();
-      ConfirmationModal.show(
-        $t('users.changeStatusConfirmation.title'),
-        $t('users.changeStatusConfirmation.message', {
-          userName: $scope.user.user_name,
-          status: newStatus
-        })
-      ).then(function() {
-        User.setActive($scope.user.user_name, $scope.user.active)
-          .catch(function(data) {
-            Alert.error($t('common.alerts.cannotUpdateStatus'), data.data.message);
-            $scope.user.active = !$scope.user.active;
-          });
-      })
-      .catch(function() {
-        $scope.user.active = !$scope.user.active;
-      });
-    }
-  };    
-  $scope.toggleUserAdmin = function() {
-    if(!$scope.isCurrentUser){
-      var action = $scope.user.admin ?
-        $t('users.changePrivilegeConfirmation.revoke') : $t('users.changePrivilegeConfirmation.grant');
-      ConfirmationModal.show(
-        $t('users.changePrivilegeConfirmation.title'),
-        $t('users.changePrivilegeConfirmation.message', {
-          action: action,
-          userName: $scope.user.user_name
-        })
-      ).then(function() {
-        User.setAdmin($scope.user.user_name, $scope.user.admin)
-        .then(function() {
-          loadPrivileges();
-        })
-        .catch(function (data) {
-          Alert.error($t('common.alerts.cannotUpdateAdminStatus'), data.data.message);
-          $scope.user.admin = !$scope.user.admin;
-        });
-      })
-      .catch(function() {
-        $scope.user.admin = !$scope.user.admin;
-      });
-
-    }
-  };
-
-  $scope.removePrivilege = function(name, privilege) {
-    var privilegeObject = {
-        id: privilege.privilege_id,
-        view_name: privilege.view_name,
-        version: privilege.version,
-        instance_name: name
-    };
-    View.deletePrivilege(privilegeObject).then(function() {
-      loadPrivileges();
-    });
-  };
-
-  $scope.deleteUser = function() {
-    ConfirmationModal.show(
-      $t('common.delete', {
-        term: $t('common.user')
-      }),
-      $t('common.deleteConfirmation', {
-        instanceType: $t('common.user').toLowerCase(),
-        instanceName: '"' + $scope.user.user_name + '"'
-      })
-    ).then(function() {
-      Cluster.getPrivilegesForResource({
-        nameFilter : $scope.user.user_name,
-        typeFilter : {value: 'USER'}
-      }).then(function(data) {
-        var clusterPrivilegesIds = [];
-        var viewsPrivileges = [];
-        if (data.items && data.items.length) {
-          angular.forEach(data.items[0].privileges, function(privilege) {
-            if (privilege.PrivilegeInfo.principal_type === 'USER') {
-              if (privilege.PrivilegeInfo.type === 'VIEW') {
-                viewsPrivileges.push({
-                  id: privilege.PrivilegeInfo.privilege_id,
-                  view_name: privilege.PrivilegeInfo.view_name,
-                  version: privilege.PrivilegeInfo.version,
-                  instance_name: privilege.PrivilegeInfo.instance_name
-                });
-              } else {
-                clusterPrivilegesIds.push(privilege.PrivilegeInfo.privilege_id);
-              }
-            }
-          });
-        }
-        User.delete($scope.user.user_name).then(function() {
-          $location.path('/users');
-          if (clusterPrivilegesIds.length) {
-            Cluster.getAllClusters().then(function (clusters) {
-              var clusterName = clusters[0].Clusters.cluster_name;
-              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
-            });
-          }
-          angular.forEach(viewsPrivileges, function(privilege) {
-            View.deletePrivilege(privilege);
-          });
-        });
-      });
-    });
-  };
-
-  // Load privileges
-  function loadPrivileges(){
-    User.getPrivileges($routeParams.id).then(function(data) {
-      var privileges = {
-        clusters: {},
-        views: {}
-      };
-      angular.forEach(data.data.items, function(privilege) {
-        privilege = privilege.PrivilegeInfo;
-        if(privilege.type === 'CLUSTER'){
-          // This is cluster
-          if (privileges.clusters[privilege.cluster_name]) {
-            var preIndex = Cluster.orderedRoles.indexOf(privileges.clusters[privilege.cluster_name].permission_name);
-            var curIndex = Cluster.orderedRoles.indexOf(privilege.permission_name);
-            // replace when cur is a more powerful role
-            if (curIndex < preIndex) {
-              privileges.clusters[privilege.cluster_name] = privilege;
-            }
-          } else {
-            privileges.clusters[privilege.cluster_name] = privilege;
-          }
-        } else if ( privilege.type === 'VIEW'){
-          privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || { privileges:[]};
-          privileges.views[privilege.instance_name].version = privilege.version;
-          privileges.views[privilege.instance_name].view_name = privilege.view_name;
-          privileges.views[privilege.instance_name].privilege_id = privilege.privilege_id;
-          if (privileges.views[privilege.instance_name].privileges.indexOf(privilege.permission_label) == -1) {
-            privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
-          }
-        }
-      });
-
-      $scope.privileges = data.data.items.length ? privileges : null;
-      $scope.noClusterPriv = $.isEmptyObject(privileges.clusters);
-      $scope.noViewPriv = $.isEmptyObject(privileges.views);
-      $scope.hidePrivileges = $scope.noClusterPriv && $scope.noViewPriv;
-      $scope.dataLoaded = true;
-
-    }).catch(function(data) {
-      Alert.error($t('common.alerts.cannotLoadPrivileges'), data.data.message);
-    });
-  }
-  loadPrivileges();
-}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
index 1967dfa..de3968d 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
@@ -101,6 +101,7 @@ angular.module('ambariAdminConsole')
     'common.admin': 'Admin',
     'common.actions': 'Actions',
     'common.error': 'Error',
+    'common.select': 'Select',
 
     'common.clusterNameChangeConfirmation.title': 'Confirm Cluster Name Change',
     'common.clusterNameChangeConfirmation.message': 'Are you sure you want to change the cluster name to {{clusterName}}?',
@@ -276,6 +277,8 @@ angular.module('ambariAdminConsole')
 
     'groups.createLocal': 'Add Groups',
     'groups.name': 'Group name',
+    'groups.role': 'Add roles to this group',
+    'groups.addUsers': 'Add users to this group',
     'groups.members': 'Members',
     'groups.membersPlural': '{{n}} member{{n == 1 ? "" : "s"}}',
 
@@ -285,7 +288,7 @@ angular.module('ambariAdminConsole')
     'groups.alerts.getGroupsListError': 'Get groups list error',
 
     'users.username': 'Username',
-    'users.userName': 'User name',
+    'users.user.name': 'User name',
     'users.admin': 'Admin',
     'users.ambariAdmin': 'Ambari Admin',
     'users.ambariClusterURL': 'Ambari Cluster URL',
@@ -300,7 +303,11 @@ angular.module('ambariAdminConsole')
     'users.inactive': 'Inactive',
     'users.status': 'Status',
     'users.password': 'Password',
+    'users.role': 'Add roles for this user (Cluster Operator/Service Admin)',
+    'users.confirmPassword': 'Confirm Password',
     'users.passwordConfirmation': 'Password сonfirmation',
+    'users.isAmbariAdmin': 'Is this user an Ambari Admin?',
+    'users.isActive': 'Deactivate this user?',
     'users.userIsAdmin': 'This user is an Ambari Admin and has all privileges.',
     'users.showAll': 'Show all users',
     'users.showAdmin': 'Show only admin users',

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
index dabc57a..c8d0e96 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
@@ -38,51 +38,25 @@ angular.module('ambariAdminConsole')
       controller: 'LoginActivitiesMainCtrl'
     }
   },
-  users: {
-    list: {
-      url: '/users',
-      templateUrl: 'views/users/list.html',
-      controller: 'UsersListCtrl',
+  userManagement: {
+    main: {
+      url: '/userManagement',
+      templateUrl: 'views/userManagement/main.html',
+      controller: 'UserManagementCtrl',
       label: 'Users'
     },
-    edit: {
+    editUser: {
       url: '/users/:id/edit',
-      templateUrl: 'views/users/create.html',
-      controller: 'UsersCreateCtrl',
+      templateUrl: 'views/userManagement/userEdit.html',
+      controller: 'UserEditCtrl',
       label: 'Users'
     },
-    create: {
-      url: '/users/new',
-      templateUrl: 'views/users/create.html',
-      controller: 'UsersCreateCtrl',
-      label: 'Users'
-    },
-    show: {
-      url: '/users/:id*',
-      templateUrl: 'views/users/show.html',
-      controller: 'UsersShowCtrl',
-      label: 'Users'
-    }
-  },
-  groups: {
-    list: {
-      url: '/groups',
-      templateUrl: 'views/groups/list.html',
-      controller: 'GroupsListCtrl',
-      label: 'Groups'
-    },
-    edit: {
+    editGroup: {
       url: '/groups/:id/edit',
-      templateUrl: 'views/groups/edit.html',
-      controller: 'GroupsEditCtrl',
+      templateUrl: 'views/userManagement/groupEdit.html',
+      controller: 'GroupEditCtrl',
       label: 'Groups'
     },
-    create: {
-      url: '/groups/new',
-      templateUrl: 'views/groups/create.html',
-      controller: 'GroupsCreateCtrl',
-      label: 'Groups'
-    }
   },
   views: {
     list: {
@@ -157,20 +131,9 @@ angular.module('ambariAdminConsole')
     }
   },
   clusters: {
-    manageAccess: {
-      url: '/clusters/:id/manageAccess',
-      templateUrl: 'views/clusters/manageAccess.html',
-      controller: 'ClustersManageAccessCtrl',
-      label: 'Roles'
-    },
-    userAccessList: {
-      url: '/clusters/:id/userAccessList',
-      templateUrl: 'views/clusters/userAccessList.html',
-      controller: 'UserAccessListCtrl'
-    },
     clusterInformation: {
       url: '/clusterInformation',
-      templateUrl: 'views/clusterInformation.html',
+      templateUrl: 'views/clusters/clusterInformation.html',
       controller: 'ClusterInformationCtrl',
       label: 'Cluster Information'
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
index ac50653..47015d1 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
@@ -94,9 +94,10 @@ angular.module('ambariAdminConsole')
      * @returns {Object}
      */
     makeUser: function(user) {
-      user.Users.encoded_name = encodeURIComponent(user.Users.user_name);
+      user.Users.encodedName = encodeURIComponent(user.Users.user_name);
       user.Users.userTypeName = $t(UserConstants.TYPES[user.Users.user_type].LABEL_KEY);
-      user.Users.ldap_user = user.Users.user_type === UserConstants.TYPES.LDAP.VALUE;
+      user.Users.ldapUser = user.Users.user_type === UserConstants.TYPES.LDAP.VALUE;
+      user.Users.role = user.privileges.length ? user.privileges[0].PrivilegeInfo.privilege_id : null;
 
       return user;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
index 94bdf11..91b2fb1 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
@@ -247,6 +247,9 @@ a.gotoinstance{
 .hide-soft{
   display: none;
 }
+.nowrap {
+  white-space: nowrap;
+}
 .visible{
   display: block;
 }
@@ -386,16 +389,6 @@ a.gotoinstance{
 .search-container input {
   font-weight: normal;
 }
-.groups-pane .search-container .close{
-  top: 32px;
-}
-
-.groups-pane table thead th{
-  border-top: 0;
-}
-.groups-pane table thead tr:first-child th{
-  border: 0;
-}
 
 ul.nav li > a{
   cursor: pointer;
@@ -464,16 +457,6 @@ table.no-border tr td{
   margin-top: 0;
 }
 
-.groups-pane table ul{
-  list-style-type: none;
-  margin: 0;
-  padding: 0;
-}
-.groups-pane table ul li {
-  margin: 0;
-  padding: 0;
-}
-
 .property-form label{
   word-wrap: break-word;
   text-overflow: ellipsis;
@@ -539,6 +522,7 @@ button.btn.btn-xs{
   font-size: 12px;
   line-height: 1.5;
   border-radius: 3px;
+  height: 24px;
 }
 
 a.btn-primary, a.btn-primary:focus {
@@ -617,13 +601,13 @@ a.alert-link, a.alert-link:hover, a.alert-link:visited{
   box-sizing: border-box;
 }
 
-.fix-bottom{
+.fix-bottom th {
   border-bottom: none !important;;
   border-top: none !important;
   border-width: 0;
 }
 
-.fix-top{
+.fix-top th {
   border-top: none !important;
   border-width: 0;
 }
@@ -1334,3 +1318,21 @@ body {
 .navigation-bar-fit-height {
   z-index: 1001;
 }
+
+.entity-actions a {
+  color: inherit;
+  font-size: 16px;
+  cursor: pointer;
+  padding: 0 5px;
+}
+
+td.entity-actions,
+th.entity-actions {
+  width: 10%;
+}
+
+.entity-actions a:hover,
+.entity-actions a:visited:hover,
+.entity-actions a:focus:hover {
+  text-decoration: none;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
new file mode 100644
index 0000000..77c94ac
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
@@ -0,0 +1,30 @@
+/**
+ * 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.
+ */
+
+#user-management .table th {
+  vertical-align: baseline;
+}
+
+#user-management .nav.nav-tabs {
+  margin-bottom: 0;
+}
+
+#user-management .users-pane,
+#user-management .groups-pane {
+  margin-top: -35px;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css
index 58583de..9bb84df 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css
@@ -16,24 +16,6 @@
  * limitations under the License.
  */
 
-.view-instance-actions a {
-  color: inherit;
-  font-size: 16px;
-  cursor: pointer;
-  padding: 0 5px;
-}
-
-td.view-instance-actions,
-th.view-instance-actions {
-  width: 10%;
-}
-
-.view-instance-actions a:hover,
-.view-instance-actions a:visited:hover,
-.view-instance-actions a:focus:hover {
-  text-decoration: none;
-}
-
 #create-instance-form i {
   cursor: pointer;
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/viewsList.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/viewsList.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/viewsList.html
index 2ff0fc4..04901f1 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/viewsList.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/viewsList.html
@@ -29,24 +29,24 @@
     <table class="table table-striped table-hover">
         <thead>
         <tr class="fix-bottom">
-            <th class="fix-bottom col-md-2">
+            <th class="col-md-2">
                 <span>{{'common.name' | translate}}</span>
             </th>
-            <th class="fix-bottom col-md-3">
+            <th class="col-md-3">
                 <span>{{'urls.url' | translate}}</span>
             </th>
-            <th class="fix-bottom col-md-2">
+            <th class="col-md-2">
                 <span>{{'views.table.viewType' | translate}}</span>
             </th>
-            <th class="fix-bottom col-md-2">
+            <th class="col-md-2">
                 <span>{{'urls.viewInstance' | translate}}</span>
             </th>
-            <th class="fix-bottom col-md-2 view-instance-actions">
+            <th class="col-md-2 entity-actions">
                 <span>{{'common.actions' | translate}}</span>
             </th>
         </tr>
-        <tr>
-            <th class="fix-top">
+        <tr class="fix-top">
+            <th>
                 <div class="search-container">
                     <input type="text" class="form-control" placeholder="{{'common.any' | translate}}"
                            ng-model="instanceNameFilter" ng-change="filterInstances()">
@@ -57,7 +57,7 @@
                     </button>
                 </div>
             </th>
-            <th class="fix-top">
+            <th>
                 <div class="search-container">
                     <input type="text" class="form-control" placeholder="{{'common.any' | translate}}"
                            ng-model="instanceUrlFilter" ng-change="filterInstances()">
@@ -68,17 +68,15 @@
                     </button>
                 </div>
             </th>
-            <th class="fix-top">
+            <th>
                 <select class="form-control typefilter v-small-input"
                         ng-model="instanceTypeFilter"
                         ng-options="item.label for item in typeFilterOptions"
                         ng-change="filterInstances()">
                 </select>
             </th>
-            <th class="fix-top">
-            </th>
-            <th class="fix-top">
-            </th>
+            <th></th>
+            <th></th>
         </tr>
         </thead>
 
@@ -98,7 +96,7 @@
             <td>
                 <span>{{instance.instance_name}}</span>
             </td>
-            <td class="view-instance-actions" ng-switch="instance.versionObj.status">
+            <td class="entity-actions" ng-switch="instance.versionObj.status">
                 <span ng-switch-when="PENDING">
                     <i class="viewstatus pending"></i>
                     {{'views.pending' | translate}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/clusterInformation.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/clusterInformation.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/clusterInformation.html
deleted file mode 100644
index ead73c3..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/clusterInformation.html
+++ /dev/null
@@ -1,87 +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.
--->
-
-<div id="cluster-information">
-  <div ng-show="cluster.Clusters.provisioning_state !== 'INSTALLED'">
-    <div class="welcome-header">
-      <h1>{{'main.title' | translate}}</h1>
-      <span>{{'main.noClusterDescription' | translate}}</span>
-    </div>
-    <div class="create-cluster-section">
-      <h2>{{'main.createCluster.title' | translate}}</h2>
-      <div>
-        <span>
-          {{'main.createCluster.description' | translate}}
-        </span>
-      </div>
-      <div><i class="fa fa-cloud" aria-hidden="true"></i></div>
-      <div>
-        <a href="{{fromSiteRoot('/#/installer/step0')}}" class="btn btn-primary">
-          {{'main.createCluster.launchInstallWizard' | translate}}
-        </a>
-      </div>
-    </div>
-  </div>
-
-  <div ng-show="cluster.Clusters.provisioning_state === 'INSTALLED'">
-    <form class="row" name="editClusterNameForm" ng-submit="confirmClusterNameChange()">
-      <div class="form-group col-xs-4 cluster-name"
-           ng-class="{'has-error': editClusterNameForm.clusterName.$invalid}">
-        <label for="clusterName">{{'views.clusterName' | translate}}*</label>
-        <input type="text"
-               class="form-control"
-               id="clusterName"
-               name="clusterName"
-               ng-change="toggleSaveButton()"
-               ng-model="edit.clusterName"
-               required
-               autofocus
-               ng-pattern="/^\w*$/"
-               ng-maxlength="80"
-               tooltip="{{'common.renameClusterTip' | translate}}"
-               tooltip-trigger="focus"
-               tooltip-placement="bottom"
-               ng-class="{edited: isClusterNameEdited}">
-        <button
-          type="submit"
-          ng-class="{'disabled': editClusterNameForm.clusterName.$invalid}"
-          class="btn btn-default pull-right"
-          ng-show="isClusterNameEdited">
-          {{'common.controls.save' | translate}}
-        </button>
-      </div>
-    </form>
-    <div>
-      <div class="row dev-blueprint">
-        <div class="col-sm-11"><span>{{'clusters.devBlueprint' | translate}}</span></div>
-        <div class="col-sm-1">
-          <div class="btn btn-default pull-right" ng-click="downloadBlueprint()">{{"common.download" | translate}}
-          </div>
-        </div>
-      </div>
-      <textarea type="text"
-                rows="20"
-                class="form-control"
-                name="blueprint_text"
-                ng-model="blueprint"
-                ng-disabled="true"
-                ng-readonly="true">
-      </textarea>
-    </div>
-  </div>
-</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/clusterInformation.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/clusterInformation.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/clusterInformation.html
new file mode 100644
index 0000000..ead73c3
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/clusterInformation.html
@@ -0,0 +1,87 @@
+<!--
+* 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 id="cluster-information">
+  <div ng-show="cluster.Clusters.provisioning_state !== 'INSTALLED'">
+    <div class="welcome-header">
+      <h1>{{'main.title' | translate}}</h1>
+      <span>{{'main.noClusterDescription' | translate}}</span>
+    </div>
+    <div class="create-cluster-section">
+      <h2>{{'main.createCluster.title' | translate}}</h2>
+      <div>
+        <span>
+          {{'main.createCluster.description' | translate}}
+        </span>
+      </div>
+      <div><i class="fa fa-cloud" aria-hidden="true"></i></div>
+      <div>
+        <a href="{{fromSiteRoot('/#/installer/step0')}}" class="btn btn-primary">
+          {{'main.createCluster.launchInstallWizard' | translate}}
+        </a>
+      </div>
+    </div>
+  </div>
+
+  <div ng-show="cluster.Clusters.provisioning_state === 'INSTALLED'">
+    <form class="row" name="editClusterNameForm" ng-submit="confirmClusterNameChange()">
+      <div class="form-group col-xs-4 cluster-name"
+           ng-class="{'has-error': editClusterNameForm.clusterName.$invalid}">
+        <label for="clusterName">{{'views.clusterName' | translate}}*</label>
+        <input type="text"
+               class="form-control"
+               id="clusterName"
+               name="clusterName"
+               ng-change="toggleSaveButton()"
+               ng-model="edit.clusterName"
+               required
+               autofocus
+               ng-pattern="/^\w*$/"
+               ng-maxlength="80"
+               tooltip="{{'common.renameClusterTip' | translate}}"
+               tooltip-trigger="focus"
+               tooltip-placement="bottom"
+               ng-class="{edited: isClusterNameEdited}">
+        <button
+          type="submit"
+          ng-class="{'disabled': editClusterNameForm.clusterName.$invalid}"
+          class="btn btn-default pull-right"
+          ng-show="isClusterNameEdited">
+          {{'common.controls.save' | translate}}
+        </button>
+      </div>
+    </form>
+    <div>
+      <div class="row dev-blueprint">
+        <div class="col-sm-11"><span>{{'clusters.devBlueprint' | translate}}</span></div>
+        <div class="col-sm-1">
+          <div class="btn btn-default pull-right" ng-click="downloadBlueprint()">{{"common.download" | translate}}
+          </div>
+        </div>
+      </div>
+      <textarea type="text"
+                rows="20"
+                class="form-control"
+                name="blueprint_text"
+                ng-model="blueprint"
+                ng-disabled="true"
+                ng-readonly="true">
+      </textarea>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/manageAccess.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/manageAccess.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/manageAccess.html
deleted file mode 100644
index a399eff..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/manageAccess.html
+++ /dev/null
@@ -1,63 +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.
--->
-    
-<div class="cluster-manage-access-pane">
-  <div class="clearfix">
-    <ol class="breadcrumb pull-left">
-      <li class="active">{{clusterName}} {{'common.roles' | translate}}</li>
-    </ol>
-  </div>
-  <hr>
-  <div class="pull-right">
-    <div class="layout-switch-icon-wrapper">
-      <i class="glyphicon glyphicon-th-large layout-switch-icon"></i>
-      <p class="label-block">{{'common.blockViewLabel' | translate}}</p>
-    </div>
-    <div class="layout-switch-icon-wrapper disabled">
-      <i class="glyphicon glyphicon-list layout-switch-icon" ng-click="switchToList()" tooltip-html-unsafe="{{'clusters.switchToList' | translate}}"></i>
-      <p class="label-list">{{'common.listViewLabel' | translate}}</p>
-    </div>
-  </div>
-  <table class="table">
-    <thead>
-      <tr>
-        <th class="col-sm-2" width="20%">
-          <label>{{'common.roles' | translate}}</label>&nbsp;
-          <i class="glyphicon glyphicon-question-sign green-icon cursor-pointer" ng-click="showHelpPage()"></i>
-        </th>
-        <th class="col-sm-5" width="40%"><label>{{'clusters.assignRoles' | translate: '{term: getConstant("common.users")}'}}</label></th>
-        <th class="col-sm-5" width="40%"><label>{{'clusters.assignRoles' | translate: '{term: getConstant("common.groups")}'}}</label></th>
-      </tr>
-    </thead>
-    <tbody>
-      <tr ng-repeat="permission in permissions">
-        <td><label class="" tooltip="{{permission.PermissionInfo.permission_name}}">{{permission.PermissionInfo.permission_label}}</label></td>
-        <td>
-          <div class="" ng-switch="isEditMode">
-            <editable-list items-source="permissionsEdit[permission.PermissionInfo.permission_name].USER" resource-type="User" editable="true"></editable-list>
-          </div>
-        </td>
-        <td>
-          <div class="" ng-switch="isEditMode">
-            <editable-list items-source="permissionsEdit[permission.PermissionInfo.permission_name].GROUP" resource-type="Group" editable="true"></editable-list>
-          </div>
-        </td>
-      </tr>
-    </tbody>
-  </table>
-</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/userAccessList.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/userAccessList.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/userAccessList.html
deleted file mode 100644
index 8b29157..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/clusters/userAccessList.html
+++ /dev/null
@@ -1,102 +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.
--->
-
-<div class="users-pane">
-  <div class="clearfix">
-    <ol class="breadcrumb pull-left">
-      <li class="active">{{clusterId}} {{'common.roles' | translate}}</li>
-    </ol>
-  </div>
-  <hr>
-  <div class="pull-right">
-    <div class="layout-switch-icon-wrapper disabled">
-      <i class="glyphicon glyphicon-th-large layout-switch-icon" ng-click="switchToBlock()" tooltip-html-unsafe="{{'clusters.switchToBlock' | translate}}"></i>
-      <p class="label-block">{{'common.blockViewLabel' | translate}}</p>
-    </div>
-    <div class="layout-switch-icon-wrapper">
-      <i class="glyphicon glyphicon-list layout-switch-icon"></i>
-      <p class="label-list">{{'common.listViewLabel' | translate}}</p>
-    </div>
-  </div>
-  <ul class="nav nav-pills">
-    <li ng-class="{'active': isUserActive}"><a ng-click="switchToUser()">{{'common.users' | translate}}</a></li>
-    <li ng-class="{'active': !isUserActive}"><a ng-click="switchToGroup()">{{'common.groups' | translate}}</a></li>
-  </ul>
-  <br/>
-  <table class="table table-striped table-hover">
-    <thead>
-    <tr>
-      <th class="role-name-column">
-        <div class="search-container">
-          <label for="">{{'common.name' | translate}}</label>
-          <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="currentNameFilter" ng-change="resetPagination()">
-          <button type="button" class="close clearfilter" ng-show="currentNameFilter" ng-click="currentNameFilter=''; resetPagination()">
-            <span aria-hidden="true">&times;</span><span class="sr-only">{{'common.controls.close' | translate}}</span>
-          </button>
-        </div>
-      </th>
-      <th>
-        <label for="">{{'clusters.role' | translate}}</label>&nbsp;
-        <i class="glyphicon glyphicon-question-sign green-icon cursor-pointer" ng-click="showHelpPage()"></i>
-        <select class="form-control statusfilter"
-                ng-model="currentRoleFilter"
-                ng-options="item.label for item in roleFilterOptions"
-                ng-change="resetPagination()">
-        </select>
-      </th>
-    </tr>
-    </thead>
-    <tbody>
-    <tr ng-repeat="user in users">
-      <td>
-        <a href="#/{{user.url}}">{{user.principal_name}}</a>
-      </td>
-      <td>
-        <div ng-show="!user.editable">{{user.permission_label}}</div>
-        <select class="form-control role-select" ng-show="user.editable" ng-model="user.permission_name"
-                ng-options="role.permission_name as role.permission_label for role in roleValueOptions">
-        </select>
-        <span ng-show="user.principal_type != $parent.currentTypeFilter.value">&nbsp;{{'common.fromGroupMark' | translate}}</span>
-        <span ng-show="user.permission_name != user.original_perm">
-          <button class="btn btn-default btn-xs cancel" ng-click="cancel(user)">
-            <span class="glyphicon glyphicon-remove cancel"></span>
-          </button>
-          <button class="btn btn-primary btn-xs" ng-click="save(user)">
-            <span class="glyphicon glyphicon-ok"></span>
-          </button>
-        </span>
-      </td>
-    </tr>
-    </tbody>
-  </table>
-  <div class="alert alert-info col-sm-12" ng-show="!users.length">
-    {{'common.alerts.nothingToDisplay' | translate: '{term: (isUserActive ? constants.users : constants.groups)}'}}
-  </div>
-  <div class="col-sm-12 table-bar">
-    <div class="pull-left filtered-info">
-      <span>{{'common.filterInfo' | translate: '{showed: tableInfo.showed, total: tableInfo.total, term: (isUserActive ? constants.users : constants.groups)}'}}</span>
-      <span ng-show="isNotEmptyFilter">- <a href ng-click="clearFilters()">{{'common.controls.clearFilters' | translate}}</a></span>
-    </div>
-    <div class="pull-right left-margin">
-      <pagination class="paginator" total-items="totalUsers" max-size="maxVisiblePages" items-per-page="usersPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
-    </div>
-    <div class="pull-right">
-      <select class="form-control" ng-model="usersPerPage" ng-change="usersPerPageChanges()" ng-options="currOption for currOption in [10, 25, 50, 100]"></select>
-    </div>
-  </div>
-</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/create.html
deleted file mode 100644
index 9a0e0fb..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/create.html
+++ /dev/null
@@ -1,43 +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.
--->
-<ol class="breadcrumb">
-  <li><a href="#/groups">{{'common.groups' | translate}}</a></li>
-  <li class="active">{{'groups.createLocal' | translate}}</li>
-</ol>
-<hr>
-<form class="form-horizontal" role="form" novalidate name="form" autocomplete="off">
-  <div class="form-group" ng-class="{'has-error' : (form.group_name.$error.required || form.group_name.$error.pattern) && form.submitted}">
-    <label for="groupname" class="col-sm-2 control-label">{{'groups.name' | translate}}</label>
-    <div class="col-sm-10">
-      <input type="text" id="groupname" class="form-control groupname-input" name="group_name" placeholder="{{'groups.name' | translate}}" ng-model="group.group_name" required ng-pattern="/^([a-zA-Z0-9._\s]+)$/" autocomplete="off">
-      <div class="alert alert-danger top-margin" ng-show="form.group_name.$error.required && form.submitted">
-        {{'common.alerts.fieldIsRequired' | translate}}
-      </div>
-      <div class="alert alert-danger top-margin" ng-show="form.group_name.$error.pattern && form.submitted">
-        {{'common.alerts.onlySimpleChars' | translate}}
-      </div>
-    </div>
-  </div>
-  <div class="form-group">
-    <div class="col-sm-offset-2 col-sm-10">
-      <button class="btn btn-primary groupcreate-btn pull-right left-margin" ng-click="createGroup()">{{'common.controls.save' | translate}}</button>
-      <a href ng-click="cancel()" class="btn btn-default pull-right cancel-button">{{'common.controls.cancel' | translate}}</a>
-    </div>
-  </div>
-      
-</form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/edit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/edit.html
deleted file mode 100644
index 1aafd03..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/edit.html
+++ /dev/null
@@ -1,98 +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.
--->
-  
-<div class="clearfix">
-  <ol class="breadcrumb pull-left">
-    <li><a href="#/groups">{{'common.groups' | translate}}</a></li>
-    <li class="active">{{group.group_name}}</li>
-  </ol>
-  <div class="pull-right top-margin-4">
-  <div ng-switch="group.group_type != 'LOCAL'">
-      <button ng-switch-when="true" class="btn disabled deletegroup-btn deleteuser-btn" tooltip="{{'common.cannotDelete' | translate: '{term: constants.group}'}}">{{'common.delete' | translate: '{term: constants.group}'}}</button>
-      <button ng-switch-when="false" class="btn btn-danger deletegroup-btn" ng-click="deleteGroup(group)">{{'common.delete' | translate: '{term: constants.group}'}}</button>
-    </div>
-      
-  </div>
-</div>
-<hr>
-<form class="form-horizontal group-edit" role="form" novalidate name="form" >
-  <div class="form-group">
-    <label for="" class="col-sm-2 control-label">{{'common.type' | translate}}</label>
-    <div class="col-sm-10">
-      <label for="" class="control-label">{{group.groupTypeName | translate}}</label>
-    </div>
-  </div>
-  <div class="form-group">
-    <label for="members" class="col-sm-2 control-label">{{group.groupTypeName | translate}} {{'groups.members' | translate}}</label>
-    <div class="col-sm-10">
-      <editable-list items-source="group.editingUsers" resource-type="User" editable="group.group_type == 'LOCAL'"></editable-list>
-    </div>
-  </div>
-
-  <div class="form-group">
-      <label for="" class="col-sm-2 control-label">{{'common.privileges' | translate}}</label>
-      <div class="col-sm-10">
-        <table class="table" ng-hide="hidePrivileges">
-          <thead>
-            <tr>
-              <th>{{'common.cluster' | translate}}</th>
-              <th>{{'common.clusterRole' | translate}}</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr ng-repeat="(name, privilege) in privileges.clusters">
-              <td>
-                <span class="glyphicon glyphicon-cloud"></span> 
-                <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
-              </td>
-              <td>
-                <span tooltip="{{item}}" ng-repeat="item in privilege">{{item | translate}}{{$last ? '' : ', '}}</span>
-              </td>
-            </tr>
-            <tr>
-              <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
-            </tr>
-          </tbody>
-          <thead class="view-permission-header">
-            <tr>
-              <th>{{'common.view' | translate}}</th>
-              <th>{{'common.viewPermissions' | translate}}</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr ng-repeat="(name, privilege) in privileges.views">
-              <td>
-                <span class="glyphicon glyphicon-th"></span>
-                <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
-              </td>
-              <td>
-                <span tooltip="{{item}}" ng-repeat="item in privilege.privileges">{{item | translate}}{{$last ? '' : ', '}}</span>
-              </td>
-              <td>
-                <i class="fa fa-trash-o" aria-hidden="true" ng-click="removePrivilege(name, privilege);"></i>
-              </td>
-            </tr>
-            <tr>
-              <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
-            </tr>
-          </tbody>
-        </table>
-        <div class="alert alert-info hide-soft" ng-class="{'visible' : !privileges}">{{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.group.toLowerCase()}'}}</div>
-      </div>
-    </div>
-</form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/list.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/list.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/list.html
deleted file mode 100644
index b39f55d..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/groups/list.html
+++ /dev/null
@@ -1,80 +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.
--->
-<div class="groups-pane">
-  <div class="clearfix">
-    <ol class="breadcrumb pull-left">
-      <li class="active">{{'common.groups' | translate}}</li>
-    </ol>
-    <div class="pull-right top-margin-4">
-      <link-to route="groups.create" class="btn btn-default creategroup-btn">
-        {{'groups.createLocal' | translate}}
-      </link-to>
-    </div>
-  </div>
-  <table class="table table-striped table-hover col-sm-12">
-    <thead>
-      <tr>
-        <th class="col-sm-8">
-          <div class="search-container">
-            <label for="">{{'groups.name' | translate}}</label>
-            <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="currentNameFilter" ng-change="resetPagination()">
-            <button type="button" class="close" ng-show="currentNameFilter" ng-click="currentNameFilter=''; resetPagination()"><span aria-hidden="true">&times;</span><span class="sr-only">{{'common.controls.close' | translate}}</span></button>
-          </div>
-        </th>
-        <th class="col-sm-2">
-          <label for="">{{'common.type' | translate}}</label>
-          <select class="form-control typefilter"
-            ng-model="currentTypeFilter"
-            ng-options="item.label for item in typeFilterOptions"
-            ng-change="resetPagination();">
-          </select>
-        </th>
-        <th class="col-sm-2 vertical-top">
-          <label for="">{{'groups.members' | translate}}</label>
-        </th>
-      </tr>
-    </thead>
-    <tbody>
-      <tr ng-repeat="group in groups">
-        <td class="col-sm-8">
-          <link-to route="groups.edit" class="link-to-group" id="{{group.group_name}}">{{group.group_name}}</link-to>
-        </td>
-        <td class="col-sm-2">{{group.groupTypeName | translate}}</td>
-        <td class="col-sm-2">{{'groups.membersPlural' | translate: '{n: group.members && group.members.length || 0}'}}</td>
-      </tr>
-    </tbody>
-  </table>
-  <div ng-if="isLoading" class="spinner-container">
-    <i class="fa fa-2x fa-spinner fa-spin" aria-hidden="true"></i>
-  </div>
-  <div class="alert empty-table-alert col-sm-12" ng-show="!groups.length && !isLoading">
-    {{'common.alerts.nothingToDisplay' | translate: '{term: constants.groups}'}}
-  </div>
-  <div class="col-sm-12 table-bar">
-    <div class="pull-left filtered-info">
-      <span>{{'common.filterInfo' | translate: '{showed: tableInfo.showed, total: tableInfo.total, term: constants.groups}'}}</span>
-      <span ng-show="isNotEmptyFilter">- <a href ng-click="clearFilters()">{{'common.controls.clearFilters' | translate}}</a></span>
-    </div>
-    <div class="pull-right left-margin">
-      <pagination class="paginator" total-items="totalGroups" max-size="maxVisiblePages" items-per-page="groupsPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
-    </div>
-    <div class="pull-right">
-      <select class="form-control" ng-model="groupsPerPage" ng-change="groupsPerPageChanges()" ng-options="currOption for currOption in [10, 25, 50, 100]"></select>
-    </div>
-  </div>
-</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/sideNav.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/sideNav.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/sideNav.html
index 97dc5d3..98a95cd 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/sideNav.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/sideNav.html
@@ -59,25 +59,11 @@
           </li>
         </ul>
       </li>
-      <li class="mainmenu-li dropdown has-sub-menu">
-        <a title="{{'common.userManagement' | translate}}" rel="tooltip" data-placement="right" data-toggle="collapse-sub-menu">
-          <span class="toggle-icon glyphicon glyphicon-menu-down pull-right"></span>
+      <li class="mainmenu-li" ng-class="{active: isActive('userManagement.main')}">
+        <link-to route="userManagement.main" class="userslist-link" title="{{'common.users' | translate}}" rel="tooltip" data-placement="right">
           <i class="navigation-icon fa fa-users" aria-hidden="true"></i>
-          <span class="navigation-menu-item">{{'common.userManagement' | translate}}</span>
-        </a>
-        <ul class="sub-menu nav nav-pills nav-stacked">
-          <li class="submenu-li"
-              ng-class="{active: isActive('clusters.manageAccess') || isActive('clusters.userAccessList')}"
-              ng-show="cluster.Clusters.provisioning_state === 'INSTALLED'">
-            <a href="#/clusters/{{cluster.Clusters.cluster_name}}/manageAccess" class="roles">{{'common.roles' | translate}}</a>
-          </li>
-          <li class="submenu-li" ng-class="{active: isActive('users.list')}">
-            <link-to route="users.list" class="userslist-link">{{'common.users' | translate}}</link-to>
-          </li>
-          <li class="submenu-li" ng-class="{active: isActive('groups.list')}">
-            <link-to route="groups.list" class="groupslist-link">{{'common.groups' | translate}}</link-to>
-          </li>
-        </ul>
+          <span class="navigation-menu-item">{{'common.users' | translate}}</span>
+        </link-to>
       </li>
       <li class="mainmenu-li" ng-class="{active: isActive('views.list')}">
         <link-to route="views.list" class="viewslist-link" title="{{'common.views' | translate}}" rel="tooltip" data-placement="right">

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
new file mode 100644
index 0000000..90a1907
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
@@ -0,0 +1,99 @@
+<!--
+* 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="clearfix">
+  <div class="pull-right">
+    <div ng-switch="group.group_type != 'LOCAL'">
+      <button
+        ng-switch-when="true"
+        class="btn disabled deletegroup-btn"
+        tooltip="{{'common.cannotDelete' | translate: '{term: constants.group}'}}">
+        {{'common.delete' | translate: '{term: constants.group}'}}
+      </button>
+      <button ng-switch-when="false" class="btn btn-danger deletegroup-btn" ng-click="deleteGroup(group)">
+        {{'common.delete' | translate: '{term: constants.group}'}}
+      </button>
+    </div>
+  </div>
+</div>
+<form class="form-horizontal group-edit" role="form" novalidate name="form" >
+  <div class="form-group">
+    <label class="col-sm-2 control-label">{{'common.type' | translate}}</label>
+    <div class="col-sm-10">
+      <label class="control-label">{{group.groupTypeName | translate}}</label>
+    </div>
+  </div>
+  <div class="form-group">
+    <label class="col-sm-2 control-label">{{group.groupTypeName | translate}} {{'groups.members' | translate}}</label>
+    <div class="col-sm-10">
+      <editable-list items-source="group.editingUsers" resource-type="User" editable="group.group_type == 'LOCAL'"></editable-list>
+    </div>
+  </div>
+
+  <div class="form-group">
+      <label class="col-sm-2 control-label">{{'common.privileges' | translate}}</label>
+      <div class="col-sm-10">
+        <table class="table" ng-hide="hidePrivileges">
+          <thead>
+            <tr>
+              <th>{{'common.cluster' | translate}}</th>
+              <th>{{'common.clusterRole' | translate}}</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr ng-repeat="(name, privilege) in privileges.clusters">
+              <td>
+                <span class="glyphicon glyphicon-cloud"></span> 
+                <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
+              </td>
+              <td>
+                <span tooltip="{{item}}" ng-repeat="item in privilege">{{item | translate}}{{$last ? '' : ', '}}</span>
+              </td>
+            </tr>
+            <tr>
+              <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
+            </tr>
+          </tbody>
+          <thead class="view-permission-header">
+            <tr>
+              <th>{{'common.view' | translate}}</th>
+              <th>{{'common.viewPermissions' | translate}}</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr ng-repeat="(name, privilege) in privileges.views">
+              <td>
+                <span class="glyphicon glyphicon-th"></span>
+                <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
+              </td>
+              <td>
+                <span tooltip="{{item}}" ng-repeat="item in privilege.privileges">{{item | translate}}{{$last ? '' : ', '}}</span>
+              </td>
+              <td>
+                <i class="fa fa-trash-o" aria-hidden="true" ng-click="removePrivilege(name, privilege);"></i>
+              </td>
+            </tr>
+            <tr>
+              <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
+            </tr>
+          </tbody>
+        </table>
+        <div class="alert alert-info hide-soft" ng-class="{'visible' : !privileges}">{{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.group.toLowerCase()}'}}</div>
+      </div>
+    </div>
+</form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupsList.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupsList.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupsList.html
new file mode 100644
index 0000000..d79d14e
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupsList.html
@@ -0,0 +1,94 @@
+<!--
+* 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="groups-pane">
+  <div class="clearfix panel">
+    <button class="btn btn-default creategroup-btn pull-right" ng-click="createGroup()">
+      {{'groups.createLocal' | translate}}
+    </button>
+  </div>
+  <table class="table table-striped table-hover col-sm-12">
+    <thead>
+      <tr>
+        <th class="col-sm-6">
+          <span>{{'groups.name' | translate}}</span>
+        </th>
+        <th class="col-sm-2">
+          <span>{{'common.type' | translate}}</span>
+        </th>
+        <th class="col-sm-2">
+          <span>{{'groups.members' | translate}}</span>
+        </th>
+        <th class="col-sm-2">
+          <span>{{'common.actions' | translate}}</span>
+        </th>
+      </tr>
+      <tr>
+        <th class="col-sm-6">
+          <div class="search-container">
+            <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="filter.name" ng-change="resetPagination()">
+            <button type="button" class="close" ng-show="filter.name" ng-click="filter.name=''; resetPagination()"><span aria-hidden="true">&times;</span><span class="sr-only">{{'common.controls.close' | translate}}</span></button>
+          </div>
+        </th>
+        <th class="col-sm-2">
+          <select class="form-control typefilter"
+                  ng-model="filter.type"
+                  ng-options="item.label for item in typeFilterOptions"
+                  ng-change="resetPagination();">
+          </select>
+        </th>
+        <th class="col-sm-2"></th>
+        <th class="col-sm-2"></th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr ng-repeat="group in groups">
+        <td class="col-sm-8">
+          <span>{{group.group_name}}</span>
+        </td>
+        <td class="col-sm-2">{{group.groupTypeName | translate}}</td>
+        <td class="col-sm-2">{{'groups.membersPlural' | translate: '{n: group.members && group.members.length || 0}'}}</td>
+        <td class="entity-actions">
+          <link-to route="userManagement.editGroup" class="link-to-group" id="{{group.group_name}}">
+            <i class="fa fa-pencil"></i>
+          </link-to>
+          <a href ng-click="deleteGroup(group)">
+            <i class="fa fa-trash-o"></i>
+          </a>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+  <div ng-if="isLoading" class="spinner-container">
+    <i class="fa fa-2x fa-spinner fa-spin" aria-hidden="true"></i>
+  </div>
+  <div class="alert empty-table-alert col-sm-12" ng-show="!groups.length && !isLoading">
+    {{'common.alerts.nothingToDisplay' | translate: '{term: constants.groups}'}}
+  </div>
+  <div class="col-sm-12 table-bar" ng-show="totalGroups > minRowsToShowPagination">
+    <div class="pull-left filtered-info">
+      <span>{{'common.filterInfo' | translate: '{showed: tableInfo.showed, total: tableInfo.total, term: constants.groups}'}}</span>
+      <span ng-show="isNotEmptyFilter">- <a href ng-click="clearFilters()">{{'common.controls.clearFilters' | translate}}</a></span>
+    </div>
+    <div class="pull-right left-margin">
+      <pagination class="paginator" total-items="totalGroups" max-size="maxVisiblePages" items-per-page="groupsPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
+    </div>
+    <div class="pull-right">
+      <select class="form-control" ng-model="groupsPerPage" ng-change="groupsPerPageChanges()" ng-options="currOption for currOption in [10, 25, 50, 100]"></select>
+    </div>
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
new file mode 100644
index 0000000..079eefb
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
@@ -0,0 +1,36 @@
+<!--
+* 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 id="user-management">
+  <ul class="nav nav-tabs">
+    <li ng-class="{active: activeTab === 'USERS'}">
+      <a ng-click="activeTab = 'USERS'">{{'common.users' | translate}}</a>
+    </li>
+    <li ng-class="{active: activeTab === 'GROUPS'}">
+      <a ng-click="activeTab = 'GROUPS'">{{'common.groups' | translate}}</a>
+    </li>
+  </ul>
+  <div>
+    <div class="users" ng-if="activeTab === 'USERS'">
+      <div ng-include="'views/userManagement/usersList.html'" ng-controller="UsersListCtrl"></div>
+    </div>
+    <div class="groups" ng-if="activeTab === 'GROUPS'">
+      <div ng-include="'views/userManagement/groupsList.html'" ng-controller="GroupsListCtrl"></div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/99b19e58/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/changePassword.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/changePassword.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/changePassword.html
new file mode 100644
index 0000000..f29d315
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/changePassword.html
@@ -0,0 +1,46 @@
+<!--
+* 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="modal-header">
+  <h3 class="modal-title">{{'users.changePasswordFor' | translate: '{userName: userName}'}}</h3>
+</div>
+<div class="modal-body">
+  <form class="form-horizontal" novalidate name="form.passwordChangeForm" role="form" >
+    <div class="form-group" ng-class="{'has-error' : (form.passwordChangeForm.currentPassword.$error.required && form.passwordChangeForm.submitted)}">
+      <label for="" class="col-sm-4 control-label" >{{'users.yourPassword' | translate}}</label>
+      <div class="col-sm-8">
+        <input type="password" name="currentPassword" class="form-control bottom-margin" placeholder="{{'users.yourPassword' | translate}}" required ng-model="passwordData.currentUserPassword" autocomplete="off">
+        <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
+      </div>
+    </div>
+    <div class="form-group no-margin-bottom" ng-class="{'has-error' : (form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted) || form.passwordChangeForm.confirmPassword.$error.passwordVerify}">
+      <label for="" class="col-sm-4 control-label">{{'users.newPassword' | translate}}:</label>
+      <div class="col-sm-8">
+        <input type="password" class="form-control bottom-margin" name="password" placeholder="{{'users.newPassword' | translate}}" required ng-model="passwordData.password" autocomplete="off">
+        <input type="password" class="form-control bottom-margin" name="confirmPassword" placeholder="{{'users.newPasswordConfirmation' | translate}}" required ng-model="passwordData.passwordConfirmation"
+          password-verify="passwordData.password" autocomplete="off">
+        <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.confirmPassword.$error.passwordVerify'>{{'users.alerts.wrongPassword' | translate}}</div>
+        <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
+      </div>
+
+    </div>
+  </form>
+</div>
+<div class="modal-footer">
+  <button class="btn btn-default" ng-click="cancel()">{{'common.controls.cancel' | translate}}</button>
+  <button class="btn btn-primary" ng-click="ok()">{{'common.controls.ok' | translate}}</button>
+</div>
\ No newline at end of file


[03/49] ambari git commit: AMBARI-22318 repositoryFile entity populating for wrong repository for RU. Unused imports check fix (dgrinenko)

Posted by rl...@apache.org.
AMBARI-22318 repositoryFile entity populating for wrong repository for RU. Unused imports check fix (dgrinenko)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 1d1c55644d77ea0e63683001cdb7303c4d379d8b
Parents: 18c4af4
Author: Dmytro Grinenko <ha...@apache.org>
Authored: Fri Nov 17 11:25:15 2017 +0200
Committer: Dmytro Grinenko <ha...@apache.org>
Committed: Fri Nov 17 11:25:15 2017 +0200

----------------------------------------------------------------------
 .../ambari/server/controller/AmbariActionExecutionHelper.java     | 3 ---
 .../ambari/server/controller/AmbariManagementControllerImpl.java  | 1 -
 2 files changed, 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/1d1c5564/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
index 23c2297..c0a7a7b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
@@ -43,10 +43,7 @@ import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.internal.RequestResourceFilter;
-import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.customactions.ActionDefinition;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.ComponentInfo;

http://git-wip-us.apache.org/repos/asf/ambari/blob/1d1c5564/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index fd91e9d..7f7271f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -89,7 +89,6 @@ import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.RequestFactory;
 import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.actionmanager.StageFactory;
-import org.apache.ambari.server.agent.CommandRepository;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;


[35/49] ambari git commit: AMBARI-21569.Users randomly getting "HDFS020 Could not write file" exceptions while running query from Hive View(Venkata Sairam)

Posted by rl...@apache.org.
AMBARI-21569.Users randomly getting "HDFS020 Could not write file" exceptions while running query from Hive View(Venkata Sairam)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 8e36662ae1dffe7cb637b3d1edb38278f0111012
Parents: 5136021
Author: Venkata Sairam <ve...@gmail.com>
Authored: Thu Nov 23 15:48:52 2017 +0530
Committer: Venkata Sairam <ve...@gmail.com>
Committed: Thu Nov 23 15:48:52 2017 +0530

----------------------------------------------------------------------
 .../org/apache/ambari/view/utils/hdfs/HdfsApi.java | 16 +++++++++++++++-
 .../apache/ambari/view/utils/hdfs/HdfsUtil.java    | 17 ++++++++++++-----
 2 files changed, 27 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/8e36662a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/HdfsApi.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/HdfsApi.java b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/HdfsApi.java
index 3db2081..812cd54 100644
--- a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/HdfsApi.java
+++ b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/HdfsApi.java
@@ -485,7 +485,20 @@ public class HdfsApi {
    * @throws IOException
    * @throws InterruptedException
    */
-  public <T> T execute(PrivilegedExceptionAction<T> action)
+  public <T> T execute(PrivilegedExceptionAction<T> action) throws IOException, InterruptedException {
+    return this.execute(action, false);
+  }
+
+
+  /**
+   * Executes action on HDFS using doAs
+   * @param action strategy object
+   * @param <T> result type
+   * @return result of operation
+   * @throws IOException
+   * @throws InterruptedException
+   */
+  public <T> T execute(PrivilegedExceptionAction<T> action, boolean alwaysRetry)
       throws IOException, InterruptedException {
     T result = null;
 
@@ -508,6 +521,7 @@ public class HdfsApi {
         }
         LOG.info("HDFS threw 'IOException: Cannot obtain block length' exception. " +
             "Retrying... Try #" + (tryNumber + 1));
+        LOG.error("Retrying: " + ex.getMessage(),ex);
         Thread.sleep(1000);  //retry after 1 second
       }
     } while (!succeeded);

http://git-wip-us.apache.org/repos/asf/ambari/blob/8e36662a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/HdfsUtil.java
----------------------------------------------------------------------
diff --git a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/HdfsUtil.java b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/HdfsUtil.java
index 0670f1a..810129b 100644
--- a/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/HdfsUtil.java
+++ b/contrib/views/utils/src/main/java/org/apache/ambari/view/utils/hdfs/HdfsUtil.java
@@ -27,6 +27,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.security.PrivilegedExceptionAction;
 import java.util.Map;
 
 public class HdfsUtil {
@@ -38,13 +39,19 @@ public class HdfsUtil {
    * @param filePath path to file
    * @param content new content of file
    */
-  public static void putStringToFile(HdfsApi hdfs, String filePath, String content) throws HdfsApiException {
-    FSDataOutputStream stream;
+  public static void putStringToFile(final HdfsApi hdfs,final String filePath, final String content) throws HdfsApiException {
+
     try {
       synchronized (hdfs) {
-        stream = hdfs.create(filePath, true);
-        stream.write(content.getBytes());
-        stream.close();
+        hdfs.execute(new PrivilegedExceptionAction<Void>() {
+          @Override
+          public Void run() throws Exception {
+            final FSDataOutputStream stream = hdfs.create(filePath, true);
+            stream.write(content.getBytes());
+            stream.close();
+            return null;
+          }
+        }, true);
       }
     } catch (IOException e) {
       throw new HdfsApiException("HDFS020 Could not write file " + filePath, e);


[05/49] ambari git commit: AMBARI-22466 Ambari 3.0: Implement new design for Admin View: Views page tweaks. (atkach)

Posted by rl...@apache.org.
AMBARI-22466 Ambari 3.0: Implement new design for Admin View: Views page tweaks. (atkach)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 430127b4b03513931d3d240d958516e412ed05de
Parents: e95d343
Author: Andrii Tkach <at...@apache.org>
Authored: Fri Nov 17 16:30:34 2017 +0200
Committer: Andrii Tkach <at...@apache.org>
Committed: Fri Nov 17 16:30:34 2017 +0200

----------------------------------------------------------------------
 .../main/resources/ui/admin-web/app/index.html  |   1 -
 .../ambariViews/CloneViewInstanceCtrl.js        | 274 -------------------
 .../ambariViews/CreateViewInstanceCtrl.js       | 103 ++++++-
 .../controllers/ambariViews/ViewsListCtrl.js    |  21 +-
 .../ui/admin-web/app/scripts/i18n.config.js     |   2 +-
 .../ui/admin-web/app/scripts/routes.js          |   6 -
 .../ui/admin-web/app/scripts/services/View.js   |   8 +-
 .../resources/ui/admin-web/app/styles/main.css  |  70 +----
 .../resources/ui/admin-web/app/styles/views.css |  82 +++++-
 .../admin-web/app/views/ambariViews/create.html | 200 --------------
 .../app/views/ambariViews/modals/create.html    | 261 +++++++++++-------
 .../app/views/ambariViews/viewsList.html        |  41 ++-
 .../ui/admin-web/app/views/urls/create.html     |   2 -
 .../ui/admin-web/app/views/urls/edit.html       |   2 -
 .../unit/controllers/CloneViewInstanceCtrl.js   | 135 ---------
 15 files changed, 391 insertions(+), 817 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/index.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/index.html b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
index 2b350f0..4a77e62 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/index.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
@@ -139,7 +139,6 @@
 <script src="scripts/controllers/ambariViews/ViewUrlCtrl.js"></script>
 <script src="scripts/controllers/ambariViews/ViewUrlEditCtrl.js"></script>
 <script src="scripts/controllers/ambariViews/CreateViewInstanceCtrl.js"></script>
-<script src="scripts/controllers/ambariViews/CloneViewInstanceCtrl.js"></script>
 <script src="scripts/controllers/clusters/ClustersManageAccessCtrl.js"></script>
 <script src="scripts/controllers/clusters/UserAccessListCtrl.js"></script>
 <script src="scripts/controllers/stackVersions/StackVersionsCreateCtrl.js"></script>

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CloneViewInstanceCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CloneViewInstanceCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CloneViewInstanceCtrl.js
deleted file mode 100644
index cb37e63..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CloneViewInstanceCtrl.js
+++ /dev/null
@@ -1,274 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-.controller('CloneViewInstanceCtrl',['$scope', 'View','RemoteCluster' , 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', '$translate', function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, UnsavedDialog, $translate) {
-  var $t = $translate.instant;
-  $scope.form = {};
-  $scope.constants = {
-    props: $t('views.properties')
-  };
-  $scope.isClone = $routeParams.instanceId ? true : false;
-  var targetUrl = '';
-
-  function loadMeta(){
-    View.getMeta($routeParams.viewId, $scope.version).then(function(data) {
-      var viewVersion = data.data,
-        parameters;
-
-      $scope.view = viewVersion;
-      parameters = viewVersion.ViewVersionInfo.parameters;
-
-      angular.forEach(parameters, function (item) {
-        item.value = item['defaultValue'];
-        item.clusterConfig = !!item.clusterConfig;
-        item.displayName = item.name.replace(/\./g, '\.\u200B');
-        item.clusterConfig ? $scope.numberOfClusterConfigs++ : $scope.numberOfSettingConfigs++;
-      });
-
-      $scope.clusterConfigurable = viewVersion.ViewVersionInfo.cluster_configurable;
-      $scope.clusterConfigurableErrorMsg = $scope.clusterConfigurable ? "" : $t('views.alerts.cannotUseOption');
-
-      $scope.instance = {
-        view_name: viewVersion.ViewVersionInfo.view_name,
-        version: viewVersion.ViewVersionInfo.version,
-        instance_name: '',
-        label: '',
-        visible: true,
-        icon_path: '',
-        icon64_path: '',
-        properties: parameters,
-        description: '',
-        clusterType: 'NONE'
-      };
-
-      //if cloning view instance, then get the instance data and populate settings and properties
-      if($scope.isClone) {
-        View.getInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId)
-          .then(function(instance) {
-            $scope.instanceClone = instance;
-            $scope.instance.version = instance.ViewInstanceInfo.version;
-            $scope.version =  instance.ViewInstanceInfo.version;
-            $scope.instance.instance_name = instance.ViewInstanceInfo.instance_name + $t('common.copy');
-            $scope.instance.label = instance.ViewInstanceInfo.label + $t('common.copy');
-            $scope.instance.visible = instance.ViewInstanceInfo.visible;
-            $scope.instance.description = instance.ViewInstanceInfo.description;
-            $scope.instance.clusterType=instance.ViewInstanceInfo.cluster_type;
-
-            initConfigurations(parameters);
-          })
-          .catch(function(data) {
-            Alert.error($t('views.alerts.cannotLoadInstanceInfo'), data.data.message);
-          });
-      }
-
-      loadClusters();
-      loadRemoteClusters();
-
-    });
-  }
-
-  function initConfigurations(parameters) {
-    var configuration = angular.copy($scope.instanceClone.ViewInstanceInfo.properties);
-
-    //iterate through the view parameters and get the values from the instance being cloned
-    for (var i = 0; i < parameters.length; i++) {
-      parameters[i].value = configuration[parameters[i].name];
-      parameters[i].clusterConfig = !!parameters[i].clusterConfig;
-    }
-  }
-
-  $scope.$watch(function(scope) {
-    return scope.version;
-  }, function(version) {
-    if( version ){
-      loadMeta();
-    }
-  });
-
-  $scope.enableLocalCluster = function () {
-    if($scope.errorKeys.length > 0) {
-      $scope.errorKeys.forEach( function (key) {
-        try {
-          $scope.form.instanceCreateForm[key].validationError = false;
-          $scope.form.instanceCreateForm[key].validationMessage = '';
-        } catch (e) {
-          console.log($t('views.alerts.unableToResetErrorMessage', {key: key}));
-        }
-      });
-      $scope.errorKeys = [];
-    }
-  };
-
-  // $scope.view = viewVersion;
-  $scope.isAdvancedClosed = true;
-  $scope.instanceExists = false;
-  $scope.errorKeys = [];
-
-  $scope.clusterConfigurable = false;
-  $scope.clusterConfigurableErrorMsg = "";
-  $scope.clusters = [];
-  $scope.remoteClusters = [];
-  $scope.noLocalClusterAvailible = true;
-  $scope.noRemoteClusterAvailible = true;
-  $scope.cluster = null;
-  $scope.data = {};
-  $scope.data.remoteCluster = null;
-  $scope.numberOfClusterConfigs = 0;
-  $scope.numberOfSettingConfigs = 0;
-
-  function loadClusters() {
-    Cluster.getAllClusters().then(function (clusters) {
-      if(clusters.length >0){
-        clusters.forEach(function(cluster) {
-          $scope.clusters.push({
-            "name" : cluster.Clusters.cluster_name,
-            "id" : cluster.Clusters.cluster_id
-          })
-        });
-        $scope.noLocalClusterAvailible = false;
-        //do not set to default Local Cluster configuration when cloning instance
-        if($scope.clusterConfigurable && !$scope.isClone){
-          $scope.instance.clusterType = "LOCAL_AMBARI";
-        }
-      }else{
-        $scope.clusters.push($t('common.noClusters'));
-      }
-      $scope.cluster = $scope.clusters[0];
-    });
-  }
-
-  function loadRemoteClusters() {
-    RemoteCluster.listAll().then(function (clusters) {
-      if(clusters.length >0){
-        clusters.forEach(function(cluster) {
-          $scope.remoteClusters.push({
-            "name" : cluster.ClusterInfo.name,
-            "id" : cluster.ClusterInfo.cluster_id
-          })
-        });
-        $scope.noRemoteClusterAvailible = false;
-      }else{
-        $scope.remoteClusters.push($t('common.noClusters'));
-      }
-      $scope.data.remoteCluster = $scope.remoteClusters[0];
-    });
-  }
-
-
-  $scope.versions = [];
-  $scope.version = null;
-
-  View.getVersions($routeParams.viewId).then(function(versions) {
-    $scope.versions = versions;
-    $scope.version = $scope.versions[$scope.versions.length-1];
-  });
-
-
-  $scope.nameValidationPattern = /^\s*\w*\s*$/;
-
-  $scope.save = function() {
-    if (!$scope.form.instanceCreateForm.isSaving) {
-      $scope.form.instanceCreateForm.submitted = true;
-      if($scope.form.instanceCreateForm.$valid){
-        $scope.form.instanceCreateForm.isSaving = true;
-
-        switch($scope.instance.clusterType) {
-          case 'LOCAL_AMBARI':
-            console.log($scope.cluster);
-            $scope.instance.clusterId = $scope.cluster.id;
-            break;
-          case 'REMOTE_AMBARI':
-            console.log($scope.data.remoteCluster);
-            $scope.instance.clusterId = $scope.data.remoteCluster.id;
-
-            break;
-          default:
-            $scope.instance.clusterId = null;
-        }
-        console.log($scope.instance.clusterId);
-        View.createInstance($scope.instance)
-          .then(function(data) {
-            Alert.success($t('views.alerts.instanceCreated', {instanceName: $scope.instance.instance_name}));
-            $scope.form.instanceCreateForm.$setPristine();
-            if( targetUrl ){
-              $location.path(targetUrl);
-            } else {
-              $location.path('/views/' + $scope.instance.view_name + '/versions/' + $scope.instance.version + '/instances/' + $scope.instance.instance_name + '/edit');
-            }
-            $scope.form.instanceCreateForm.isSaving = false;
-            $scope.$root.$emit('instancesUpdate');
-          })
-          .catch(function (data) {
-            var errorMessage = data.message;
-            var showGeneralError = true;
-
-            if (data.status >= 400 && $scope.instance.clusterType == 'NONE') {
-              try {
-                var errorObject = JSON.parse(errorMessage);
-                errorMessage = errorObject.detail;
-                angular.forEach(errorObject.propertyResults, function (item, key) {
-                  $scope.form.instanceCreateForm[key].validationError = !item.valid;
-                  if (!item.valid) {
-                    showGeneralError = false;
-                    $scope.form.instanceCreateForm[key].validationMessage = item.detail;
-                    $scope.errorKeys.push(key);
-                  }
-                });
-
-                if (showGeneralError) {
-                  $scope.form.instanceCreateForm.generalValidationError = errorMessage;
-                }
-              } catch (e) {
-                console.error($t('views.alerts.unableToParseError', {message: data.message}));
-              }
-            }
-            Alert.error($t('views.alerts.cannotCreateInstance'), errorMessage);
-            $scope.form.instanceCreateForm.isSaving = false;
-          });
-      }
-    }
-  };
-
-  $scope.cancel = function() {
-    $scope.form.instanceCreateForm.$setPristine();
-    $location.path('/views');
-  };
-
-  $scope.$on('$locationChangeStart', function(event, __targetUrl) {
-    if( $scope.form.instanceCreateForm.$dirty ){
-      UnsavedDialog().then(function(action) {
-        targetUrl = __targetUrl.split('#').pop();
-        switch(action){
-          case 'save':
-            $scope.save();
-            break;
-          case 'discard':
-            $scope.form.instanceCreateForm.$setPristine();
-            $location.path(targetUrl);
-            break;
-          case 'cancel':
-            targetUrl = '';
-            break;
-        }
-      });
-      event.preventDefault();
-    }
-  });
-}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
index d5e3758..1199313 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
@@ -19,8 +19,8 @@
 
 angular.module('ambariAdminConsole')
 .controller('CreateViewInstanceCtrl',
-['$scope', 'View','RemoteCluster' , 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', '$translate', '$modalInstance', 'views', '$q',
-function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, UnsavedDialog, $translate, $modalInstance, views, $q) {
+['$scope', 'View','RemoteCluster' , 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', '$translate', '$modalInstance', 'views', 'instanceClone', '$q',
+function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, UnsavedDialog, $translate, $modalInstance, views, instanceClone, $q) {
 
   var $t = $translate.instant;
   var viewToVersionMap = {};
@@ -28,14 +28,20 @@ function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, U
   $scope.form = {};
   $scope.nameValidationPattern = /^\s*\w*\s*$/;
   $scope.isLoading = false;
-  $scope.isLocalTypeChosen = true;
+  $scope.clusterType = 'LOCAL_AMBARI'; // LOCAL_AMBARI, REMOTE_AMBARI, NONE
   $scope.views = views;
+  $scope.instanceClone = instanceClone;
   $scope.viewOptions = [];
   $scope.versionOptions = [];
   $scope.localClusters = [];
   $scope.remoteClusters = [];
   $scope.clusterOptions = [];
+  $scope.fieldsWithErrors = [];
   $scope.isInstanceExists = false;
+  $scope.clusterConfigurable = false;
+  $scope.clusterSettingsCount = 0;
+  $scope.nonClusterSettingsCount = 0;
+  $scope.instanceTemplate = null;
   $scope.formData = {
     view: null,
     version: null,
@@ -43,22 +49,52 @@ function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, U
     displayName: '',
     description: '',
     clusterName: null,
-    visible: true
+    visible: true,
+    settings: []
   };
 
   $scope.updateVersionOptions = function () {
     if (viewToVersionMap[$scope.formData.view.value]) {
       $scope.versionOptions = viewToVersionMap[$scope.formData.view.value];
       $scope.formData.version = $scope.versionOptions[0];
+      $scope.updateSettingsList();
     }
   };
 
-  $scope.switchClusterType = function(bool) {
-    $scope.isLocalTypeChosen = bool;
-    if ($scope.isLocalTypeChosen) {
+  $scope.updateSettingsList = function() {
+    $scope.formData.settings = [];
+    $scope.clusterSettingsCount = 0;
+    $scope.nonClusterSettingsCount = 0;
+    $scope.instanceTemplate = null;
+    angular.forEach($scope.views, function(view) {
+      if (view.view_name === $scope.formData.view.value) {
+        angular.forEach(view.versionsList, function(version) {
+          if (version.ViewVersionInfo.version === $scope.formData.version.value) {
+            $scope.formData.settings = version.ViewVersionInfo.parameters.map(function(param) {
+              param.value = param['defaultValue'];
+              param.clusterConfig = Boolean(param.clusterConfig);
+              param.displayName = param.name.replace(/\./g, '\.\u200B');
+              $scope.clusterSettingsCount += param.clusterConfig;
+              $scope.nonClusterSettingsCount += !param.clusterConfig;
+              return param;
+            });
+            $scope.clusterConfigurable = version.ViewVersionInfo.cluster_configurable;
+          }
+        });
+      }
+    });
+  };
+
+  $scope.switchClusterType = function(clusterType) {
+    $scope.clusterType = clusterType;
+    if (clusterType === 'LOCAL_AMBARI') {
       $scope.clusterOptions = $scope.localClusters;
-    } else {
+      resetErrors();
+    } else if (clusterType === 'REMOTE_AMBARI') {
       $scope.clusterOptions = $scope.remoteClusters;
+      resetErrors();
+    } else {
+      $scope.clusterOptions = [];
     }
     $scope.formData.clusterName = $scope.clusterOptions[0];
   };
@@ -76,9 +112,9 @@ function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, U
         description: $scope.form.instanceCreateForm.description.$viewValue,
         view_name: $scope.form.instanceCreateForm.view.$viewValue.value,
         version: $scope.form.instanceCreateForm.version.$viewValue.value,
-        properties: [],
-        clusterId: $scope.form.instanceCreateForm.clusterName.$viewValue.id,
-        clusterType: $scope.isLocalTypeChosen ? 'LOCAL_AMBARI': 'REMOTE_AMBARI'
+        properties: $scope.formData.settings,
+        clusterId: $scope.formData.clusterName ? $scope.formData.clusterName.id : null,
+        clusterType: $scope.clusterType
       })
         .then(function () {
           $modalInstance.dismiss('created');
@@ -92,7 +128,16 @@ function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, U
 
           if (data.status >= 400) {
             try {
-              errorMessage = JSON.parse(errorMessage).detail;
+              var errorObject = JSON.parse(errorMessage);
+              errorMessage = errorObject.detail;
+              angular.forEach(errorObject.propertyResults, function (item, key) {
+                $scope.form.instanceCreateForm[key].validationError = !item.valid;
+                if (!item.valid) {
+                  $scope.form.instanceCreateForm[key].validationMessage = item.detail;
+                  $scope.fieldsWithErrors.push(key);
+                }
+              });
+
             } catch (e) {
               console.warn(data.message, e);
             }
@@ -110,6 +155,14 @@ function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, U
     $scope.isInstanceExists = Boolean(instances[$scope.formData.instanceName]);
   };
 
+  function resetErrors() {
+    $scope.fieldsWithErrors.forEach(function(field) {
+      $scope.form.instanceCreateForm[field].validationError = false;
+      $scope.form.instanceCreateForm[field].validationMessage = '';
+    });
+    $scope.fieldsWithErrors = [];
+  }
+
   function initViewAndVersionSelect () {
     $scope.viewOptions = [];
     angular.forEach($scope.views, function(view) {
@@ -160,10 +213,34 @@ function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, U
     initViewAndVersionSelect();
     $q.all(loadClusters(), loadRemoteClusters()).then(function() {
       $scope.isLoading = false;
-      $scope.switchClusterType(true);
+      $scope.switchClusterType('LOCAL_AMBARI');
+      copyCloneInstanceInfo();
     });
   }
 
+  function copyCloneInstanceInfo() {
+    if ($scope.instanceClone) {
+      $scope.formData.view = $scope.viewOptions.filter(function(option) {
+        return option.value === $scope.instanceClone.view_name;
+      })[0];
+      $scope.updateVersionOptions();
+      $scope.formData.version = $scope.versionOptions.filter(function(option) {
+        return option.value === $scope.instanceClone.version;
+      })[0];
+      $scope.formData.instanceName = $scope.instanceClone.instance_name + $t('common.copy');
+      $scope.formData.displayName = $scope.instanceClone.label + $t('common.copy');
+      $scope.formData.description = $scope.instanceClone.description;
+      $scope.formData.visible = $scope.instanceClone.visible;
+      $scope.switchClusterType($scope.instanceClone.cluster_type);
+      $scope.updateSettingsList();
+      $scope.formData.settings.forEach(function (setting) {
+        if ($scope.instanceClone.properties[setting.name]) {
+          setting.value = $scope.instanceClone.properties[setting.name];
+        }
+      });
+    }
+  }
+
   function unsavedChangesCheck() {
     if ($scope.form.instanceCreateForm.$dirty) {
       UnsavedDialog().then(function (action) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
index aba5702..aa77b63 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
@@ -54,15 +54,15 @@ angular.module('ambariAdminConsole')
       $scope.views = views;
       $scope.instances = [];
       angular.forEach(views, function (view) {
-        // TODO uncomment if view need status update
-        // angular.forEach(view.versions, function (versionObj, versionNumber) {
-        //   if (versionNeedStatusUpdate(versionObj.status)) {
-        //     checkViewVersionStatus(view, versionObj, versionNumber);
-        //   }
-        // });
+        angular.forEach(view.versions, function (versionObj, versionNumber) {
+          if (versionNeedStatusUpdate(versionObj.status)) {
+            checkViewVersionStatus(view, versionObj, versionNumber);
+          }
+        });
         angular.forEach(view.instances, function (instance) {
           instance.ViewInstanceInfo.short_url_name = instance.ViewInstanceInfo.short_url_name || '';
           instance.ViewInstanceInfo.short_url = instance.ViewInstanceInfo.short_url || '';
+          instance.ViewInstanceInfo.versionObj = view.versions[instance.ViewInstanceInfo.version] || {};
           $scope.instances.push(instance.ViewInstanceInfo);
         });
       });
@@ -166,13 +166,20 @@ angular.module('ambariAdminConsole')
     }
   );
 
-  $scope.createInstance = function () {
+  $scope.cloneInstance = function(instanceClone) {
+    $scope.createInstance(instanceClone);
+  };
+
+  $scope.createInstance = function (instanceClone) {
     var modalInstance = $modal.open({
       templateUrl: 'views/ambariViews/modals/create.html',
       controller: 'CreateViewInstanceCtrl',
       resolve: {
         views: function() {
           return $scope.views;
+        },
+        instanceClone: function() {
+          return instanceClone;
         }
       },
       backdrop: 'static'

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
index 4ef3ee9..1967dfa 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
@@ -100,6 +100,7 @@ angular.module('ambariAdminConsole')
     'common.userManagement': 'User Management',
     'common.admin': 'Admin',
     'common.actions': 'Actions',
+    'common.error': 'Error',
 
     'common.clusterNameChangeConfirmation.title': 'Confirm Cluster Name Change',
     'common.clusterNameChangeConfirmation.message': 'Are you sure you want to change the cluster name to {{clusterName}}?',
@@ -180,7 +181,6 @@ angular.module('ambariAdminConsole')
     'views.viewInstance': 'View Instance',
     'views.create': 'Create Instance',
     'views.clone': 'Clone Instance',
-    'views.createViewInstance': 'Create Instance',
     'views.edit': 'Edit',
     'views.viewName': 'View Name',
     'views.instances': 'Instances',

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
index 486e598..dabc57a 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
@@ -91,12 +91,6 @@ angular.module('ambariAdminConsole')
       controller: 'ViewsListCtrl',
       label: 'Views'
     },
-    clone: {
-      url: '/views/:viewId/versions/:version/instances/:instanceId/clone',
-      templateUrl: 'views/ambariViews/create.html',
-      controller: 'CloneViewInstanceCtrl',
-      label: 'Views'
-    },
     edit: {
       url: '/views/:viewId/versions/:version/instances/:instanceId/edit',
       templateUrl: 'views/ambariViews/edit.html',

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
index b38b0c2..db3dab9 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
@@ -286,10 +286,10 @@ angular.module('ambariAdminConsole')
         description: instanceInfo.description
       };
 
-    angular.forEach(instanceInfo.properties, function(property) {
-      if(property.clusterConfig) {
+    angular.forEach(instanceInfo.properties, function (property) {
+      if (property.clusterConfig) {
         properties[property.name] = property.value
-      }else {
+      } else {
         settings[property.name] = property.value
       }
     });
@@ -297,7 +297,7 @@ angular.module('ambariAdminConsole')
     data.properties = settings;
     data.cluster_type = instanceInfo.clusterType;
 
-    if(instanceInfo.clusterId != null) {
+    if (instanceInfo.clusterId != null) {
       data.cluster_handle = instanceInfo.clusterId;
     } else {
       angular.extend(data.properties, properties);

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
index 9838227..94bdf11 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
@@ -665,7 +665,11 @@ a.alert-link, a.alert-link:hover, a.alert-link:visited{
   border-left: 3px solid #ef2427;
 }
 .ambariAlert.error .icon-box, .test-ldap-icon.fa-times-circle {
-  color: #ef2427;
+  color: #ef6162;
+}
+
+.error {
+  color: #ef6162;
 }
 
 .ambariAlert.success {
@@ -706,73 +710,9 @@ a.alert-link, a.alert-link:hover, a.alert-link:visited{
   transition: none!important;
 }
 
-
-.viewstatus{
-  display: inline-block;
-}
-.viewstatus.pending{
-  width: 12px;
-  height: 12px;
-  border: 2px solid black;
-  border-radius: 50%;
-  vertical-align: middle;
-  position: relative;
-}
-
-.viewstatus.pending:before, .viewstatus.pending:after{
-  content: '';
-  position: absolute;
-  left: 4px;
-  top: 3px;
-  width: 5px;
-  height: 2px;
-  background: black;
-}
-.viewstatus.pending:after{
-  top: -3px;
-  left: 3px;
-  width: 2px;
-  height: 2px;
-  border-radius: 100%;
-}
-.viewstatus.pending:before{
-  -webkit-transform-origin: 0% 50%;
-  -moz-transform-origin: 0% 50%;
-  -ms-transform-origin: 0% 50%;
-  -o-transform-origin: 0% 50%;
-  transform-origin: 0% 50%;
-
-  animation: rotate 2.0s infinite linear;
-  -webkit-animation: rotate 2.0s infinite linear;
-}
-
 @-webkit-keyframes rotate { 100% { -webkit-transform: rotate(360deg) }}
 @keyframes rotate { 100% { transform: rotate(360deg); -webkit-transform: rotate(360deg) }}
 
-
-.viewstatus.deploying{
-  width: 17px;
-  height: 12px;
-  text-align: center;
-  vertical-align: middle;
-}
-.viewstatus.deploying > div{
-  background: black;
-  height: 100%;
-  width: 3px;
-  display: inline-block;
-  -webkit-animation: stretchdelay 1.2s infinite ease-in-out;
-  animation: stretchdelay 1.2s infinite ease-in-out;
-}
-.viewstatus.deploying .rect2 {
-  -webkit-animation-delay: -1.1s;
-  animation-delay: -1.1s;
-}
-.viewstatus.deploying .rect3 {
-  -webkit-animation-delay: -1.0s;
-  animation-delay: -1.0s;
-}
-
 @-webkit-keyframes stretchdelay {
   0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
   20% { -webkit-transform: scaleY(1.0) }

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css
index 9ab66f5..58583de 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-.view-instance-actions>a {
+.view-instance-actions a {
   color: inherit;
   font-size: 16px;
   cursor: pointer;
@@ -28,9 +28,9 @@ th.view-instance-actions {
   width: 10%;
 }
 
-.view-instance-actions>a:hover,
-.view-instance-actions>a:visited:hover,
-.view-instance-actions>a:focus:hover {
+.view-instance-actions a:hover,
+.view-instance-actions a:visited:hover,
+.view-instance-actions a:focus:hover {
   text-decoration: none;
 }
 
@@ -38,6 +38,12 @@ th.view-instance-actions {
   cursor: pointer;
 }
 
+#create-instance-form .modal-body {
+  max-height: 600px;
+  overflow-y: auto;
+  overflow-x: hidden;
+}
+
 #create-instance-form button.active {
   color: #333;
   background-color: #e6e6e6;
@@ -47,3 +53,71 @@ th.view-instance-actions {
 input[type="checkbox"] + label {
   line-height: 18px;
 }
+
+.viewstatus {
+  display: inline-block;
+}
+
+.viewstatus.pending {
+  width: 12px;
+  height: 12px;
+  border: 2px solid black;
+  border-radius: 50%;
+  vertical-align: middle;
+  position: relative;
+}
+
+.viewstatus.pending:before, .viewstatus.pending:after {
+  content: '';
+  position: absolute;
+  left: 4px;
+  top: 3px;
+  width: 5px;
+  height: 2px;
+  background: black;
+}
+
+.viewstatus.pending:after {
+  top: -3px;
+  left: 3px;
+  width: 2px;
+  height: 2px;
+  border-radius: 100%;
+}
+
+.viewstatus.pending:before {
+  -webkit-transform-origin: 0% 50%;
+  -moz-transform-origin: 0% 50%;
+  -ms-transform-origin: 0% 50%;
+  -o-transform-origin: 0% 50%;
+  transform-origin: 0% 50%;
+
+  animation: rotate 2.0s infinite linear;
+  -webkit-animation: rotate 2.0s infinite linear;
+}
+
+.viewstatus.deploying {
+  width: 17px;
+  height: 12px;
+  text-align: center;
+  vertical-align: text-top;
+}
+
+.viewstatus.deploying > div {
+  background: black;
+  height: 100%;
+  width: 3px;
+  display: inline-block;
+  -webkit-animation: stretchdelay 1.2s infinite ease-in-out;
+  animation: stretchdelay 1.2s infinite ease-in-out;
+}
+
+.viewstatus.deploying .rect2 {
+  -webkit-animation-delay: -1.1s;
+  animation-delay: -1.1s;
+}
+
+.viewstatus.deploying .rect3 {
+  -webkit-animation-delay: -1.0s;
+  animation-delay: -1.0s;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
deleted file mode 100644
index 81171c1..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
+++ /dev/null
@@ -1,200 +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.
--->
-<ol class="breadcrumb">
-  <li><a href="#/views">{{'common.views' | translate}}</a></li>
-  <li class="active"> {{isClone ? 'views.clone' : 'views.create' | translate}}</li>
-</ol>
-<hr>
-<form class="form-horizontal create-view-form" role="form" name="form.instanceCreateForm" novalidate>
-  <div class="view-header">
-    <div class="form-group">
-      <div class="col-sm-2">
-        <label for="" class="control-label">{{'common.view' | translate}}</label>
-      </div>
-      <div class="col-sm-10"><label for="" class="control-label">{{view.ViewVersionInfo.view_name}}</label></div>
-    </div>
-    <div class="form-group">
-      <div class="col-sm-2"><label for="" class="control-label">{{'common.version' | translate}}</label></div>
-      <div class="col-sm-3">
-        <select ng-model="version" class="instanceversion-input form-control" ng-change="versionChanged()" ng-options="o as o for o in versions"></select>
-      </div>
-    </div>
-  </div>
-
-  <div class="panel panel-default">
-    <div class="panel-heading">
-      <h3 class="panel-title">{{'common.details' | translate}}</h3>
-    </div>
-    <div class="panel-body">
-      <div class="form-group"
-      ng-class="{'has-error' : ( (form.instanceCreateForm.instanceNameInput.$error.required || form.instanceCreateForm.instanceNameInput.$error.pattern) && form.instanceCreateForm.submitted) || instanceExists }"
-      >
-        <label for="" class="control-label col-sm-3">{{'views.instanceName' | translate}}*</label>
-        <div class="col-sm-9">
-          <input type="text" class="form-control instancename-input" name="instanceNameInput" ng-pattern="nameValidationPattern" required ng-model="instance.instance_name" autocomplete="off">
-
-          <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.instanceNameInput.$error.required && form.instanceCreateForm.submitted'>{{'common.alerts.fieldIsRequired' | translate}}</div>
-          <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.instanceNameInput.$error.pattern && form.instanceCreateForm.submitted'>{{'views.alerts.noSpecialCharsOrSpaces' | translate}}</div>
-          <div class="alert alert-danger no-margin-bottom top-margin" ng-show='instanceExists'>{{'views.alerts.instanceExists' | translate}}</div>
-        </div>
-      </div>
-      <div class="form-group"
-      ng-class="{'has-error' : ( (form.instanceCreateForm.displayLabel.$error.required || form.instanceCreateForm.displayLabel.$error.pattern) && form.instanceCreateForm.submitted)}">
-        <label for="" class="control-label col-sm-3">{{'views.displayName' | translate}}*</label>
-        <div class="col-sm-9">
-          <input type="text" class="form-control instancelabel-input" name="displayLabel" ng-model="instance.label" required ng-pattern="/^([a-zA-Z0-9._\s]+)$/" autocomplete="off">
-
-          <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.displayLabel.$error.required && form.instanceCreateForm.submitted'>
-            {{'common.alerts.fieldIsRequired' | translate}}
-          </div>
-          <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.displayLabel.$error.pattern && form.instanceCreateForm.submitted'>
-            {{'views.alerts.noSpecialChars' | translate}}
-          </div>
-        </div>
-      </div>
-      <div class="form-group" ng-class="{'has-error' : form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted }">
-        <label for="" class="control-label col-sm-3">{{'views.description' | translate}}*</label>
-        <div class="col-sm-9">
-          <input type="text" class="form-control" name="description" ng-model="instance.description" maxlength="140" required>
-          <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted'>
-            {{'common.alerts.fieldIsRequired' | translate}}
-          </div>
-        </div>
-      </div>
-
-      <div class="form-group">
-        <div class="col-sm-10 col-sm-offset-3">
-          <div class="checkbox">
-            <input type="checkbox" ng-model='instance.visible' id="visibility-checkbox" class="visibilityCheckbox">
-            <label for="visibility-checkbox">{{'views.visible' | translate}}</label>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <div class="panel panel-default" ng-hide="!numberOfSettingConfigs">
-    <div class="panel-heading">
-      <h3 class="panel-title">{{'views.settings' | translate}}</h3>
-    </div>
-    <div class="panel-body">
-      <div class="form-group" ng-repeat="parameter in instance.properties | filter:{clusterConfig:false}"
-           ng-class="{'has-error' : ((form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted) || form.instanceCreateForm[parameter.name].validationError)}" >
-        <label for="" class="col-sm-3 control-label" ng-class="{'not-required': !parameter.required}">{{parameter.label || parameter.displayName}}{{parameter.required ? '*' : ''}}</label>
-        <div ng-switch="parameter.type">
-          <div class="col-sm-9 checkbox" ng-switch-when="boolean">
-            <input type="checkbox" class="viewproperty-input" name="{{parameter.name}}" ng-required="parameter.required" ng-model="parameter.value" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter">
-          </div>
-          <div class="col-sm-9" ng-switch-default>
-            <input type="{{parameter.masked ? 'password' : 'text'}}" class="form-control viewproperty-input" name="{{parameter.name}}" ng-change="form.instanceCreateForm[parameter.name].validationError=''" ng-required="parameter.required" ng-model="parameter.value" autocomplete="off" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter" placeholder="{{parameter.placeholder}}">
-            <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted'>
-              {{'common.alerts.fieldIsRequired' | translate}}
-            </div>
-            <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].validationError'>
-              {{form.instanceCreateForm[parameter.name].validationMessage}}
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <div class="panel panel-default" ng-hide="!numberOfClusterConfigs && !clusterConfigurable">
-    <div class="panel-heading">
-      <h3 class="panel-title">{{'views.clusterConfiguration' | translate}}</h3>
-    </div>
-
-    <div class="panel-body property-form" popover="{{clusterConfigurableErrorMsg}}" popover-trigger="mouseenter">
-      <div class="checkbox create-checkbox-cluster">
-        <input type="radio" id="local-cluster" ng-disabled="!clusterConfigurable || noLocalClusterAvailible" ng-model="instance.clusterType" ng-change="enableLocalCluster()" value="LOCAL_AMBARI" class="visibilityCheckbox">
-        <label for="local-cluster">{{'views.localCluster' | translate}}</label>
-      </div>
-
-      <div class="form-horizontal property-form">
-        <div class="form-group">
-
-          <label for="" class="control-label col-sm-3 ng-binding not-required" >{{'views.clusterName' | translate}}</label>
-          <div>
-            <div class="col-sm-9">
-              <select ng-model="cluster" ng-disabled="instance.clusterType != 'LOCAL_AMBARI' || noLocalClusterAvailible" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o.name for o in clusters"></select>
-            </div>
-          </div>
-        </div>
-      </div>
-
-    </div>
-
-    <div class="panel-body property-form" popover="{{clusterConfigurableErrorMsg}}" popover-trigger="mouseenter">
-      <div class="checkbox create-checkbox-cluster">
-        <input type="radio" id="remote-cluster" ng-disabled="!clusterConfigurable || noRemoteClusterAvailible" ng-model="instance.clusterType" ng-change="enableLocalCluster()" value="REMOTE_AMBARI" class="visibilityCheckbox">
-        <label for="remote-cluster">{{'views.remoteCluster' | translate}}</label>
-      </div>
-
-      <div class="form-horizontal property-form">
-        <div class="form-group">
-
-          <label for="" class="control-label col-sm-3 ng-binding not-required" >{{'views.clusterName' | translate}}</label>
-          <div>
-            <div class="col-sm-9">
-              <select ng-model="data.remoteCluster" ng-disabled="instance.clusterType != 'REMOTE_AMBARI' || noRemoteClusterAvailable" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o.name for o in remoteClusters"></select>
-            </div>
-          </div>
-        </div>
-      </div>
-
-    </div>
-
-    <div class="panel-body property-form" ng-hide="!numberOfClusterConfigs">
-      <div class="checkbox">
-        <input type="radio" id="custom-view" ng-model="instance.clusterType" value="NONE" class="visibilityCheckbox">
-        <label for="custom-view">{{'views.custom' | translate}}</label>
-      </div>
-      <div class="alert alert-danger bottom-margin top-margin" ng-show='form.instanceCreateForm.generalValidationError'>
-        {{form.instanceCreateForm.generalValidationError}}
-      </div>
-      <div class="form-group" ng-repeat="parameter in instance.properties | filter:{clusterConfig:true}"
-        ng-class="{'has-error' : ((form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted) || form.instanceCreateForm[parameter.name].validationError)}" >
-        <label for="" class="col-sm-3 control-label" ng-class="{'not-required': !parameter.required}">{{parameter.label || parameter.displayName}}{{parameter.required ? '*' : ''}}</label>
-        <div ng-switch="parameter.type">
-          <div class="col-sm-9 checkbox" ng-switch-when="boolean">
-            <input type="checkbox" class="viewproperty-input" name="{{parameter.name}}" ng-disabled="instance.clusterType == 'NONE'" ng-required="parameter.required && (instance.clusterType == 'NONE')" ng-model="parameter.value" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter">
-          </div>
-          <div class="col-sm-9" ng-switch-default>
-            <input type="{{parameter.masked ? 'password' : 'text'}}" class="form-control viewproperty-input" name="{{parameter.name}}" ng-disabled="instance.clusterType != 'NONE'" ng-change="form.instanceCreateForm[parameter.name].validationError=''" ng-required="parameter.required && (instance.clusterType == 'NONE')" ng-model="parameter.value" autocomplete="off" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter" placeholder="{{parameter.placeholder}}">
-            <div class="alert alert-danger no-margin-bottom top-margin" ng-show="form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted && (instance.clusterType == 'NONE')">
-              {{'common.alerts.fieldIsRequired' | translate}}
-            </div>
-            <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].validationError'>
-              {{form.instanceCreateForm[parameter.name].validationMessage}}
-            </div>
-          </div>
-        </div>
-      </div>
-      <div ng-show="!instance.properties.length">
-        <div class="alert alert-info">{{'views.alerts.notDefined' | translate: '{term: constants.props}'}}</div>
-      </div>
-    </div>
-  </div>
-
-  <div class="col-sm-12 ">
-    <button class="btn btn-primary pull-right left-margin save-button"
-            ng-class="{'disabled' : (form.instanceCreateForm.isSaving)}" ng-click="save()" type="submit">{{'common.controls.save' | translate}}</button>
-    <a href ng-click="cancel()" class="btn btn-default pull-right cancel-button">{{'common.controls.cancel' | translate}}</a>
-  </div>
-
-</form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/create.html
index 48757d4..82f90b3 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/create.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/create.html
@@ -17,7 +17,14 @@
 -->
 <form role="form" id="create-instance-form" name="form.instanceCreateForm" novalidate>
 <div class="modal-header">
-  <h3 class="modal-title">{{'views.createViewInstance' | translate}}</h3>
+  <h1 class="modal-title">
+    <span ng-if="!instanceClone">
+      {{'views.create' | translate}}
+    </span>
+    <span ng-if="instanceClone">
+      {{'views.clone' | translate}}
+    </span>
+  </h1>
 </div>
 <div class="modal-body" ng-hide="isLoading">
 
@@ -29,6 +36,7 @@
         <i class="fa fa-question-circle" aria-hidden="true"></i>
       </label>
       <select
+        ng-disabled="instanceClone"
         class="form-control"
         id="view"
         name="view"
@@ -48,10 +56,12 @@
         <i class="fa fa-question-circle" aria-hidden="true"></i>
       </label>
       <select
+        ng-disabled="instanceClone"
         class="form-control"
         id="version"
         name="version"
         ng-model="formData.version"
+        ng-change="updateSettingsList()"
         ng-options="item.label for item in versionOptions">
       </select>
       <span class="help-block validation-block" ng-show='form.instanceCreateForm.version.$error.required && form.instanceCreateForm.submitted'>
@@ -60,112 +70,179 @@
     </div>
   </div>
 
-  <div class="h4">{{'common.details' | translate}}</div>
-  <div class="form-group"
-       ng-class="{ 'has-error': (form.instanceCreateForm.instanceName.$error.required || form.instanceCreateForm.instanceName.$error.pattern || isInstanceExists) && form.instanceCreateForm.submitted }">
-    <label for="instanceName">
-      {{'views.instanceName' | translate}}<span>*</span>&nbsp;
-      <i class="fa fa-question-circle" aria-hidden="true"></i>
-    </label>
-    <input type="text" class="form-control"
-           ng-model="formData.instanceName"
-           name="instanceName"
-           id="instanceName"
-           ng-change="checkIfInstanceExist()"
-           ng-pattern="nameValidationPattern" required>
-    <span class="help-block validation-block"
-         ng-show='form.instanceCreateForm.instanceName.$error.required && form.instanceCreateForm.submitted'>
-      {{'common.alerts.fieldRequired' | translate}}
-    </span>
-    <span class="help-block validation-block"
-         ng-show='form.instanceCreateForm.instanceName.$error.pattern && form.instanceCreateForm.submitted'>
+  <div class="details-section">
+    <h2>{{'common.details' | translate}}</h2>
+    <div class="form-group"
+         ng-class="{ 'has-error': (form.instanceCreateForm.instanceName.$error.required || form.instanceCreateForm.instanceName.$error.pattern || isInstanceExists) && form.instanceCreateForm.submitted }">
+      <label for="instanceName">
+        {{'views.instanceName' | translate}}<span>*</span>&nbsp;
+        <i class="fa fa-question-circle" aria-hidden="true"></i>
+      </label>
+      <input type="text" class="form-control"
+             ng-model="formData.instanceName"
+             name="instanceName"
+             id="instanceName"
+             ng-change="checkIfInstanceExist()"
+             ng-pattern="nameValidationPattern" required>
+      <span class="help-block validation-block"
+            ng-show='form.instanceCreateForm.instanceName.$error.required && form.instanceCreateForm.submitted'>
+        {{'common.alerts.fieldRequired' | translate}}
+      </span>
+      <span class="help-block validation-block"
+            ng-show='form.instanceCreateForm.instanceName.$error.pattern && form.instanceCreateForm.submitted'>
       {{'common.alerts.noSpecialChars' | translate}}
     </span>
-    <span class="help-block validation-block"
-         ng-show='isInstanceExists && form.instanceCreateForm.submitted'>
-      {{'views.alerts.instanceExists' | translate}}
-    </span>
-  </div>
+      <span class="help-block validation-block" ng-show='isInstanceExists && form.instanceCreateForm.submitted'>
+        {{'views.alerts.instanceExists' | translate}}
+      </span>
+    </div>
 
-  <div class="form-group" ng-class="{ 'has-error': form.instanceCreateForm.displayName.$error.required && form.instanceCreateForm.submitted }">
-    <label for="displayName">
-      {{'views.displayName' | translate}}<span>*</span>&nbsp;
-      <i class="fa fa-question-circle" aria-hidden="true"></i>
-    </label>
-    <input type="text" class="form-control" required
-           name="displayName"
-           ng-model="formData.displayName"
-           id="displayName">
-    <span class="help-block validation-block" ng-show='form.instanceCreateForm.displayName.$error.required && form.instanceCreateForm.submitted'>
-      {{'common.alerts.fieldRequired' | translate}}
-    </span>
-  </div>
+    <div class="form-group" ng-class="{ 'has-error': form.instanceCreateForm.displayName.$error.required && form.instanceCreateForm.submitted }">
+      <label for="displayName">
+        {{'views.displayName' | translate}}<span>*</span>&nbsp;
+        <i class="fa fa-question-circle" aria-hidden="true"></i>
+      </label>
+      <input type="text" class="form-control" required
+             name="displayName"
+             ng-model="formData.displayName"
+             id="displayName">
+      <span class="help-block validation-block" ng-show='form.instanceCreateForm.displayName.$error.required && form.instanceCreateForm.submitted'>
+        {{'common.alerts.fieldRequired' | translate}}
+      </span>
+    </div>
 
-  <div class="form-group" ng-class="{ 'has-error': form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted }">
-    <label for="description">
-      {{'views.description' | translate}}<span>*</span>&nbsp;
-      <i class="fa fa-question-circle" aria-hidden="true"></i>
-    </label>
-    <input type="text" class="form-control" required
-           name="description"
-           ng-model="formData.description"
-           id="description">
-    <span class="help-block validation-block" ng-show='form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted'>
-      {{'common.alerts.fieldRequired' | translate}}
-    </span>
-  </div>
+    <div class="form-group" ng-class="{ 'has-error': form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted }">
+      <label for="description">
+        {{'views.description' | translate}}<span>*</span>&nbsp;
+        <i class="fa fa-question-circle" aria-hidden="true"></i>
+      </label>
+      <input type="text" class="form-control" required
+             name="description"
+             ng-model="formData.description"
+             id="description">
+      <span class="help-block validation-block" ng-show='form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted'>
+        {{'common.alerts.fieldRequired' | translate}}
+      </span>
+    </div>
 
-  <div class="form-group checkbox">
-    <input type="checkbox" class="form-control"
-           name="visible"
-           ng-model="formData.visible"
-           id="visible">
-    <label for="visible">
-      {{'views.visible' | translate}}
-      <i class="fa fa-question-circle" aria-hidden="true"></i>
-    </label>
+    <div class="form-group checkbox">
+      <input type="checkbox" class="form-control"
+             name="visible"
+             ng-model="formData.visible"
+             id="visible">
+      <label for="visible">
+        {{'views.visible' | translate}}
+        <i class="fa fa-question-circle" aria-hidden="true"></i>
+      </label>
+    </div>
   </div>
 
-  <div class="h4">{{'views.clusterConfiguration' | translate}}</div>
-  <div class="form-group">
-    <label for="clusterType">
-      {{'views.createInstance.clusterType' | translate}}?&nbsp;
-      <i class="fa fa-question-circle" aria-hidden="true"></i>
-    </label>
-    <div>
-      <div class="btn-group" role="group" id="clusterType">
-        <button type="button" class="btn btn-default"
-                ng-class="isLocalTypeChosen && 'active'"
-                ng-click="switchClusterType(true)">
-          {{'common.local' | translate}}
-        </button>
-        <button type="button" class="btn btn-default"
-                ng-class="!isLocalTypeChosen && 'active'"
-                ng-click="switchClusterType(false)">
-          {{'common.remote' | translate}}
-        </button>
-      </div>
+  <div class="settings-section" ng-show="nonClusterSettingsCount">
+    <h2>{{'views.settings' | translate}}</h2>
+    <div class="form-group"
+         ng-repeat="parameter in formData.settings | filter: { clusterConfig: false }"
+         ng-class="{ 'has-error': (form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted) || form.instanceCreateForm[parameter.name].validationError }">
+      <label ng-attr-for="{{parameter.name}}">
+        {{parameter.label || parameter.displayName}}{{parameter.required ? '*' : ''}}
+      </label>
+      <input class="form-control"
+             type="{{parameter.masked ? 'password' : 'text'}}"
+             ng-required="parameter.required"
+             ng-change="form.instanceCreateForm[parameter.name].validationError=''"
+             ng-attr-name="{{parameter.name}}"
+             popover="{{parameter.description}}"
+             popover-title="{{parameter.name}}"
+             popover-trigger="mouseenter"
+             placeholder="{{parameter.placeholder}}"
+             ng-model="parameter.value"
+             ng-attr-id="{{parameter.name}}">
+      <span class="help-block validation-block" ng-show='form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted'>
+        {{'common.alerts.fieldRequired' | translate}}
+      </span>
+      <span class="help-block validation-block" ng-show='form.instanceCreateForm[parameter.name].validationError'>
+        {{form.instanceCreateForm[parameter.name].validationMessage}}
+      </span>
     </div>
   </div>
-  <div class="row">
-    <div class="form-group col-sm-6" ng-class="{ 'has-error': form.instanceCreateForm.clusterName.$error.required && form.instanceCreateForm.submitted }">
-      <label for="clusterName">
-        {{'views.clusterName' | translate}}<span>*</span>&nbsp;
+
+  <div class="cluster-type-section">
+    <h2>{{'views.clusterConfiguration' | translate}}</h2>
+    <div class="form-group">
+      <label for="clusterType">
+        {{'views.createInstance.clusterType' | translate}}?&nbsp;
         <i class="fa fa-question-circle" aria-hidden="true"></i>
       </label>
-      <select
-        required
-        name="clusterName"
-        ng-options="item.label for item in clusterOptions"
-        class="form-control"
-        ng-model="formData.clusterName"
-        id="clusterName">
-      </select>
-      <span class="help-block validation-block" ng-show='form.instanceCreateForm.clusterName.$error.required && form.instanceCreateForm.submitted'>
+      <div>
+        <div class="btn-group" role="group" id="clusterType">
+          <button type="button" class="btn btn-default"
+                  ng-class="clusterType === 'LOCAL_AMBARI' && 'active'"
+                  ng-click="switchClusterType('LOCAL_AMBARI')">
+            {{'common.local' | translate}}
+          </button>
+          <button type="button" class="btn btn-default"
+                  ng-class="clusterType === 'REMOTE_AMBARI' && 'active'"
+                  ng-click="switchClusterType('REMOTE_AMBARI')">
+            {{'common.remote' | translate}}
+          </button>
+          <button type="button" class="btn btn-default"
+                  ng-if="clusterSettingsCount && clusterConfigurable"
+                  ng-class="clusterType === 'NONE' && 'active'"
+                  ng-click="switchClusterType('NONE')">
+            {{'views.custom' | translate}}
+          </button>
+        </div>
+      </div>
+    </div>
+    <div class="row">
+      <div class="form-group col-sm-6" ng-class="{ 'has-error': form.instanceCreateForm.clusterName.$error.required && form.instanceCreateForm.submitted }">
+        <label for="clusterName">
+          {{'views.clusterName' | translate}}<span>*</span>&nbsp;
+          <i class="fa fa-question-circle" aria-hidden="true"></i>
+        </label>
+        <select
+          ng-required="clusterType !== 'NONE'"
+          ng-disabled="clusterType === 'NONE'"
+          name="clusterName"
+          ng-options="item.label for item in clusterOptions"
+          class="form-control"
+          ng-model="formData.clusterName"
+          id="clusterName">
+        </select>
+        <span class="help-block validation-block" ng-show='form.instanceCreateForm.clusterName.$error.required && form.instanceCreateForm.submitted'>
+        {{'common.alerts.fieldRequired' | translate}}
+      </span>
+      </div>
+    </div>
+    <div class="cluster-configurations-section" ng-show="clusterSettingsCount && clusterConfigurable">
+      <div class="form-group"
+           ng-repeat="parameter in formData.settings | filter: { clusterConfig: true }"
+           ng-class="{ 'has-error': (form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted) || form.instanceCreateForm[parameter.name].validationError }">
+        <label ng-attr-for="{{parameter.name}}">
+          {{parameter.label || parameter.displayName}}{{parameter.required ? '*' : ''}}
+        </label>
+        <input class="form-control"
+               ng-disabled="clusterType !== 'NONE'"
+               type="{{parameter.masked ? 'password' : 'text'}}"
+               ng-required="clusterType === 'NONE' && parameter.required"
+               ng-change="form.instanceCreateForm[parameter.name].validationError=''"
+               ng-attr-name="{{parameter.name}}"
+               popover="{{parameter.description}}"
+               popover-title="{{parameter.name}}"
+               popover-trigger="mouseenter"
+               placeholder="{{parameter.placeholder}}"
+               ng-model="parameter.value"
+               ng-attr-id="{{parameter.name}}">
+        <span class="help-block validation-block" ng-show="form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted && (clusterType === 'NONE')">
         {{'common.alerts.fieldRequired' | translate}}
       </span>
+        <span class="help-block validation-block" ng-show='form.instanceCreateForm[parameter.name].validationError'>
+        {{form.instanceCreateForm[parameter.name].validationMessage}}
+      </span>
+      </div>
     </div>
   </div>
+
+
 </div>
 <div ng-if="isLoading" class="spinner-container">
   <i class="fa fa-2x fa-spinner fa-spin" aria-hidden="true"></i>

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/viewsList.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/viewsList.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/viewsList.html
index 7aa25ab..2ff0fc4 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/viewsList.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/viewsList.html
@@ -20,7 +20,7 @@
 
     <div class="clearfix">
         <div class="pull-right">
-            <button ng-disabled="views.length === 0" ng-click="createInstance(views[0]);" class="btn btn-default">
+            <button ng-disabled="views.length === 0" ng-click="createInstance();" class="btn btn-default">
                 {{'views.create' | translate}}
             </button>
         </div>
@@ -98,16 +98,35 @@
             <td>
                 <span>{{instance.instance_name}}</span>
             </td>
-            <td class="view-instance-actions">
-                <a href="#/views/{{instance.view_name}}/versions/{{instance.version}}/instances/{{instance.instance_name}}/edit">
-                    <i class="fa fa-pencil"></i>
-                </a>
-                <a href="#/views/{{instance.view_name}}/versions/{{instance.version}}/instances/{{instance.instance_name}}/clone">
-                    <i class="fa fa-copy"></i>
-                </a>
-                <a href ng-click="deleteInstance(instance)">
-                    <i class="fa fa-trash-o"></i>
-                </a>
+            <td class="view-instance-actions" ng-switch="instance.versionObj.status">
+                <span ng-switch-when="PENDING">
+                    <i class="viewstatus pending"></i>
+                    {{'views.pending' | translate}}
+                </span>
+                <span ng-switch-when="DEPLOYING">
+                    <div class="viewstatus deploying">
+                        <div class="rect1"></div>
+                        <div class="rect2"></div>
+                        <div class="rect3"></div>
+                    </div>
+                    {{'views.deploying' | translate}}
+                </span>
+
+                <span ng-switch-when="DEPLOYED">
+                    <a  href="#/views/{{instance.view_name}}/versions/{{instance.version}}/instances/{{instance.instance_name}}/edit">
+                        <i class="fa fa-pencil"></i>
+                    </a>
+                    <a href ng-click="cloneInstance(instance);">
+                        <i class="fa fa-copy"></i>
+                    </a>
+                    <a href ng-click="deleteInstance(instance)">
+                        <i class="fa fa-trash-o"></i>
+                    </a>
+                </span>
+                <span ng-switch-when="ERROR" class="error" tooltip="{{'views.alerts.deployError' | translate}}">
+                    <i class="fa fa-exclamation-triangle"></i>
+                    {{'common.error' | translate}}
+                </span>
             </td>
         </tr>
         </tbody>

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
index c625475..dbd1021 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
@@ -16,7 +16,6 @@
 * limitations under the License.
 -->
 <ol class="breadcrumb">
-    <li> <link-to route="views.listViewUrls">{{'urls.viewUrls' | translate}}</link-to></li>
     <li class="active">{{'urls.createNewUrl' | translate}}</li>
 </ol>
 <hr>
@@ -68,7 +67,6 @@
                 <div class="form-group">
                     <div class="col-sm-offset-2 col-sm-10">
                         <button ng-disabled="stepTwoNotCompleted" class="btn btn-primary pull-right left-margin saveuser" ng-click="saveUrl()">{{'common.controls.save' | translate}}</button>
-                        <link-to route="views.listViewUrls" class="btn btn-default pull-right cancel">{{'common.controls.cancel' | translate}}</link-to>
 
                     </div>
                 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
index dd5f65a..61366db 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
@@ -16,7 +16,6 @@
 * limitations under the License.
 -->
 <ol class="breadcrumb">
-  <li> <link-to route="views.listViewUrls">{{'urls.viewUrls' | translate}}</link-to></li>
   <li class="active">{{'urls.edit' | translate}} {{url.url_name}}</li>
   <div class="pull-right top-margin-4">
     <button class="btn deleteuser-btn btn-danger" ng-click="deleteUrl()">{{'views.urlDelete' | translate}}</button>
@@ -70,7 +69,6 @@
   <div class="form-group">
     <div class="col-sm-offset-2 col-sm-10">
       <button ng-disabled="stepTwoNotCompleted" class="btn btn-primary pull-right left-margin saveuser" ng-click="updateUrl()">{{'common.controls.save' | translate}}</button>
-      <link-to route="views.listViewUrls" class="btn btn-default pull-right cancel">{{'common.controls.cancel' | translate}}</link-to>
     </div>
   </div>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/430127b4/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/CloneViewInstanceCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/CloneViewInstanceCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/CloneViewInstanceCtrl.js
deleted file mode 100644
index f78333a..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/CloneViewInstanceCtrl.js
+++ /dev/null
@@ -1,135 +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.
- */
-
-describe('#CloneViewInstanceCtrl', function () {
-  var scope, ctrl, $httpBackend, View;
-
-  beforeEach(module('ambariAdminConsole', function($provide){
-    $provide.value('$routeParams', {viewId: 'TestView'});
-  }));
-
-  afterEach(function() {
-    $httpBackend.verifyNoOutstandingExpectation();
-    $httpBackend.verifyNoOutstandingRequest();
-  });
-
-  beforeEach(inject(function (_$httpBackend_, $rootScope, $controller, _View_, $q) {
-    View = _View_;
-    spyOn(View, 'createInstance').andReturn($q.defer().promise);
-    spyOn(View, 'getInstance').andReturn($q.defer().promise);
-
-    $httpBackend = _$httpBackend_;
-    $httpBackend.whenGET(/\/api\/v1\/views\/TestView\?.+/).respond(200, {
-      "versions": [{"ViewVersionInfo": {}}]
-    });
-    $httpBackend.whenGET(/\/api\/v1\/views\/TestView\/versions\/1\.0\.0/).respond(200, {
-      "ViewVersionInfo": {"parameters": [{"name": "n", "defaultValue": "d"}]}
-    });
-    $httpBackend.whenGET('template/modal/backdrop.html').respond(200, '<div></div>');
-    $httpBackend.whenGET('template/modal/window.html').respond(200, '<div></div>');
-    scope = $rootScope.$new();
-    ctrl = $controller('CloneViewInstanceCtrl', {$scope: scope});
-  }));
-
-  it('it should invoke View.createInstance on save', function () {
-    scope.form = {
-      instanceCreateForm: {
-        submitted: false,
-        $valid: true
-      }
-    };
-    $httpBackend.flush();
-    scope.instance = {};
-    scope.save();
-    expect(View.createInstance).toHaveBeenCalled();
-  });
-
-  it('should set default property value before creating view instance', function () {
-    scope.form = {
-      instanceCreateForm: {
-        $dirty: true
-      }
-    };
-    scope.instance = {};
-    scope.version = '1.0.0';
-    scope.isClone=false;
-    $httpBackend.expectGET('template/modal/backdrop.html');
-    $httpBackend.expectGET('template/modal/window.html');
-    $httpBackend.whenGET(/\/api\/v1\/clusters\?fields=Clusters\/cluster_id&_=\d+/).respond(200, {
-      "items" : [
-        {
-          "Clusters" : {
-            "cluster_name" : "c1",
-            "version" : "HDP-2.2"
-          }
-        }
-      ]
-    });
-    $httpBackend.whenGET(/\/api\/v1\/remoteclusters\?fields=ClusterInfo\/services,ClusterInfo\/cluster_id&_=\d+/).respond(200, {
-      "items" : [
-         {
-           "ClusterInfo" : {
-            "name" : "c1",
-            "services" : ["HDFS"]
-          }
-        }
-      ]
-    });
-    scope.$digest();
-    $httpBackend.flush();
-    chai.expect(scope.view.ViewVersionInfo.parameters[0].value).to.equal('d');
-    expect(View.getInstance).not.toHaveBeenCalled();
-  });
-
-  it('before cloning view instance confirm that View.getInstance is called', function () {
-    scope.form = {
-      instanceCreateForm: {
-        $dirty: true
-      }
-    };
-    scope.instance = {};
-    scope.version = '1.0.0';
-    scope.isClone=true;
-    $httpBackend.expectGET('template/modal/backdrop.html');
-    $httpBackend.expectGET('template/modal/window.html');
-    $httpBackend.whenGET(/\/api\/v1\/clusters\?fields=Clusters\/cluster_id&_=\d+/).respond(200, {
-      "items" : [
-        {
-          "Clusters" : {
-            "cluster_name" : "c1",
-            "version" : "HDP-2.2"
-          }
-        }
-      ]
-    });
-    $httpBackend.whenGET(/\/api\/v1\/remoteclusters\?fields=ClusterInfo\/services,ClusterInfo\/cluster_id&_=\d+/).respond(200, {
-      "items" : [
-         {
-           "ClusterInfo" : {
-            "name" : "c1",
-            "services" : ["HDFS"]
-          }
-        }
-      ]
-    });
-    scope.$digest();
-    $httpBackend.flush();
-    expect(View.getInstance).toHaveBeenCalled(); 
-  });
-
-});


[42/49] ambari git commit: AMBARI-22517. NPE during Ambari schema upgrade while updating Hive configs.

Posted by rl...@apache.org.
AMBARI-22517. NPE during Ambari schema upgrade while updating Hive configs.


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: c9936ad349e3e703dcbf6f2a1644f8a3e45a23d0
Parents: c5fe6cb
Author: Swapan Shridhar <ss...@hortonworks.com>
Authored: Mon Nov 27 00:47:57 2017 -0800
Committer: Swapan Shridhar <ss...@hortonworks.com>
Committed: Mon Nov 27 00:47:57 2017 -0800

----------------------------------------------------------------------
 .../server/upgrade/UpgradeCatalog260.java       | 38 ++++++++++----------
 1 file changed, 20 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/c9936ad3/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
index 33b62f8..4d9a5da 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
@@ -775,26 +775,28 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog {
           // hive-interactive-site/hive.llap.zk.sm.keytab.file and hive-interactive-site/hive.llap.task.keytab.file respectively,
           // based on what hive-interactive-site/hive.llap.daemon.keytab.file has.
           Config hsiSiteConfig = cluster.getDesiredConfigByType(HIVE_INTERACTIVE_SITE);
-          Map<String, String> hsiSiteConfigProperties = hsiSiteConfig.getProperties();
-          if (hsiSiteConfigProperties != null &&
-                  hsiSiteConfigProperties.containsKey(HIVE_LLAP_DAEMON_KEYTAB_FILE)) {
-            String[] identities = {HIVE_LLAP_ZK_SM_KEYTAB_FILE, HIVE_LLAP_TASK_KEYTAB_FILE};
-            Map<String, String> newProperties = new HashMap<>();
-            for (String identity : identities) {
-              // Update only if we were able to modify the corresponding kerberos descriptor,
-              // reflected in list 'getYarnKerberosDescUpdatedList'.
-              if (getYarnKerberosDescUpdatedList().contains(identity) && hsiSiteConfigProperties.containsKey(identity)) {
-                newProperties.put(identity, hsiSiteConfigProperties.get(HIVE_LLAP_DAEMON_KEYTAB_FILE));
+          if (hsiSiteConfig != null) {
+            Map<String, String> hsiSiteConfigProperties = hsiSiteConfig.getProperties();
+            if (hsiSiteConfigProperties != null &&
+                    hsiSiteConfigProperties.containsKey(HIVE_LLAP_DAEMON_KEYTAB_FILE)) {
+              String[] identities = {HIVE_LLAP_ZK_SM_KEYTAB_FILE, HIVE_LLAP_TASK_KEYTAB_FILE};
+              Map<String, String> newProperties = new HashMap<>();
+              for (String identity : identities) {
+                // Update only if we were able to modify the corresponding kerberos descriptor,
+                // reflected in list 'getYarnKerberosDescUpdatedList'.
+                if (getYarnKerberosDescUpdatedList().contains(identity) && hsiSiteConfigProperties.containsKey(identity)) {
+                  newProperties.put(identity, hsiSiteConfigProperties.get(HIVE_LLAP_DAEMON_KEYTAB_FILE));
+                }
               }
-            }
 
-            // Update step.
-            if (newProperties.size() > 0) {
-              try {
-                updateConfigurationPropertiesForCluster(cluster, HIVE_INTERACTIVE_SITE, newProperties, true, false);
-                LOG.info("Updated HSI config(s) : " + newProperties.keySet() + " with value(s) = " + newProperties.values()+" respectively.");
-              } catch (AmbariException e) {
-                e.printStackTrace();
+              // Update step.
+              if (newProperties.size() > 0) {
+                try {
+                  updateConfigurationPropertiesForCluster(cluster, HIVE_INTERACTIVE_SITE, newProperties, true, false);
+                  LOG.info("Updated HSI config(s) : " + newProperties.keySet() + " with value(s) = " + newProperties.values() + " respectively.");
+                } catch (AmbariException e) {
+                  e.printStackTrace();
+                }
               }
             }
           }


[43/49] ambari git commit: AMBARI-22402. PERF stack: Deploy fails due to common hooks being used instead of one specific to PERF (aonishuk)

Posted by rl...@apache.org.
AMBARI-22402. PERF stack: Deploy fails due to common hooks being used instead of one specific to PERF (aonishuk)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 3dca5607d736f5d70ef0a48898c2e009fd60b50a
Parents: c9936ad
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Mon Nov 27 15:06:24 2017 +0200
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Mon Nov 27 15:06:24 2017 +0200

----------------------------------------------------------------------
 .../ambari/server/actionmanager/ExecutionCommandWrapper.java  | 7 +++++--
 .../java/org/apache/ambari/server/agent/HeartbeatMonitor.java | 3 +--
 .../org/apache/ambari/server/configuration/Configuration.java | 7 +++++++
 .../server/controller/internal/UpgradeResourceProvider.java   | 3 +--
 .../java/org/apache/ambari/server/stack/StackManager.java     | 5 -----
 contrib/utils/perf/deploy-gce-perf-cluster.py                 | 1 +
 6 files changed, 15 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3dca5607/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
index a0c5f26..7b693cd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
@@ -20,7 +20,6 @@ package org.apache.ambari.server.actionmanager;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.VERSION;
-import static org.apache.ambari.server.stack.StackManager.DEFAULT_HOOKS_FOLDER;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -34,6 +33,7 @@ import org.apache.ambari.server.agent.AgentCommand.AgentCommandType;
 import org.apache.ambari.server.agent.CommandRepository;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
 import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
@@ -93,6 +93,9 @@ public class ExecutionCommandWrapper {
   @Inject
   private AmbariMetaInfo ambariMetaInfo;
 
+  @Inject
+  private Configuration configuration;
+
   @AssistedInject
   public ExecutionCommandWrapper(@Assisted String jsonExecutionCommand) {
     this.jsonExecutionCommand = jsonExecutionCommand;
@@ -304,7 +307,7 @@ public class ExecutionCommandWrapper {
           stackId.getStackVersion());
 
         if (!commandParams.containsKey(HOOKS_FOLDER)) {
-          commandParams.put(HOOKS_FOLDER, DEFAULT_HOOKS_FOLDER);
+          commandParams.put(HOOKS_FOLDER,configuration.getProperty(Configuration.HOOKS_FOLDER));
         }
 
         if (!commandParams.containsKey(SERVICE_PACKAGE_FOLDER)) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/3dca5607/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
index c13df6b..d51364e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
@@ -25,7 +25,6 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT_TY
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAME;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
-import static org.apache.ambari.server.stack.StackManager.DEFAULT_HOOKS_FOLDER;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -341,7 +340,7 @@ public class HeartbeatMonitor implements Runnable {
     commandParams.put(COMMAND_TIMEOUT, commandTimeout);
     commandParams.put(SERVICE_PACKAGE_FOLDER,
        serviceInfo.getServicePackageFolder());
-    commandParams.put(HOOKS_FOLDER, DEFAULT_HOOKS_FOLDER);
+    commandParams.put(HOOKS_FOLDER, configuration.getProperty(Configuration.HOOKS_FOLDER));
     // Fill host level params
     Map<String, String> hostLevelParams = statusCmd.getHostLevelParams();
     hostLevelParams.put(JDK_LOCATION, ambariManagementController.getJdkResourceUrl());

http://git-wip-us.apache.org/repos/asf/ambari/blob/3dca5607/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index a53aebd..ea44a90 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -2045,6 +2045,13 @@ public class Configuration {
       "server.task.timeout", 1200);
 
   /**
+   * A location of hooks folder relative to resources folder.
+   */
+  @Markdown(description = "A location of hooks folder relative to resources folder.")
+  public static final ConfigurationProperty<String> HOOKS_FOLDER = new ConfigurationProperty<>(
+      "stack.hooks.folder", "stack-hooks");
+
+  /**
    * The location on the Ambari Server where custom actions are defined.
    */
   @Markdown(description = "The location on the Ambari Server where custom actions are defined.")

http://git-wip-us.apache.org/repos/asf/ambari/blob/3dca5607/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
index e4dd441..c5303cc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
@@ -19,7 +19,6 @@ package org.apache.ambari.server.controller.internal;
 
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
-import static org.apache.ambari.server.stack.StackManager.DEFAULT_HOOKS_FOLDER;
 
 import java.text.MessageFormat;
 import java.util.ArrayList;
@@ -977,7 +976,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
           effectiveStackId.getStackVersion(), serviceName);
 
       commandParams.put(SERVICE_PACKAGE_FOLDER, serviceInfo.getServicePackageFolder());
-      commandParams.put(HOOKS_FOLDER, DEFAULT_HOOKS_FOLDER);
+      commandParams.put(HOOKS_FOLDER, s_configuration.getProperty(Configuration.HOOKS_FOLDER));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/3dca5607/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java
index eb6737a..b11ecab 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java
@@ -79,11 +79,6 @@ public class StackManager {
   public static final String COMMON_SERVICES = "common-services";
 
   /**
-   * Prefix used for common stack hooks parent path string
-   */
-  public static final String DEFAULT_HOOKS_FOLDER = "stack-hooks";
-
-  /**
    * Prefix used for extension services parent path string
    */
   public static final String EXTENSIONS = "extensions";

http://git-wip-us.apache.org/repos/asf/ambari/blob/3dca5607/contrib/utils/perf/deploy-gce-perf-cluster.py
----------------------------------------------------------------------
diff --git a/contrib/utils/perf/deploy-gce-perf-cluster.py b/contrib/utils/perf/deploy-gce-perf-cluster.py
index 7431ae9..6084ce9 100644
--- a/contrib/utils/perf/deploy-gce-perf-cluster.py
+++ b/contrib/utils/perf/deploy-gce-perf-cluster.py
@@ -381,6 +381,7 @@ def create_server_script(server_host_name):
   "echo 'alerts.cache.size=100000' >> /etc/ambari-server/conf/ambari.properties\n" + \
   "echo 'alerts.execution.scheduler.maxThreads=4' >> /etc/ambari-server/conf/ambari.properties\n" + \
   "echo 'security.temporary.keystore.retention.minutes=180' >> /etc/ambari-server/conf/ambari.properties\n" + \
+  "echo 'stack.hooks.folder=stacks/PERF/1.0/hooks' >> /etc/ambari-server/conf/ambari.properties\n" + \
   "\n" + \
   "ambari-server start --skip-database-check\n" + \
   "exit 0"


[09/49] ambari git commit: AMBARI-22462 Remove hard-code from StackAdvisorCommand requests to another resources (dgrinenko)

Posted by rl...@apache.org.
AMBARI-22462 Remove hard-code from StackAdvisorCommand requests to another resources (dgrinenko)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 786d4b63349d2c0f18d8a06a29fe1cc5598cf8fc
Parents: 8b82034
Author: Dmytro Grinenko <ha...@apache.org>
Authored: Mon Nov 20 07:37:02 2017 +0200
Committer: Dmytro Grinenko <ha...@apache.org>
Committed: Mon Nov 20 07:37:02 2017 +0200

----------------------------------------------------------------------
 .../stackadvisor/commands/StackAdvisorCommand.java   | 15 +++++++++++----
 .../ambari/server/controller/KerberosHelperImpl.java |  6 +++---
 ...erviceComponentConfigurationResourceProvider.java |  8 ++++----
 .../AbstractPrepareKerberosServerAction.java         |  6 ++++--
 .../PrepareKerberosIdentitiesServerAction.java       |  5 ++++-
 .../apache/ambari/server/topology/AmbariContext.java |  3 ++-
 .../ambari/server/topology/BlueprintFactory.java     |  3 ++-
 .../validators/RequiredPasswordValidator.java        |  3 ++-
 8 files changed, 32 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/786d4b63/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
index 17591ec..1b89c4f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
@@ -47,6 +47,7 @@ import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorResponse;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
 import org.apache.ambari.server.controller.RootComponent;
 import org.apache.ambari.server.controller.RootService;
+import org.apache.ambari.server.controller.internal.RootServiceComponentConfigurationResourceProvider;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.utils.DateUtils;
@@ -77,6 +78,8 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend
 
   private static final String GET_HOSTS_INFO_URI = "/api/v1/hosts"
       + "?fields=Hosts/*&Hosts/host_name.in(%s)";
+  static final String LDAP_CONFIGURATION_PROPERTY = "ldap-configuration";
+
   private static final String GET_SERVICES_INFO_URI = "/api/v1/stacks/%s/versions/%s/"
       + "?fields=Versions/stack_name,Versions/stack_version,Versions/parent_stack_version"
       + ",services/StackServices/service_name,services/StackServices/service_version"
@@ -86,9 +89,14 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend
       + ",services/configurations/dependencies/StackConfigurationDependency/dependency_name"
       + ",services/configurations/dependencies/StackConfigurationDependency/dependency_type,services/configurations/StackConfigurations/type"
       + "&services/StackServices/service_name.in(%s)";
-  private static final String GET_AMBARI_LDAP_CONFIG_URI = "/api/v1/services/AMBARI/components/AMBARI_SERVER/configurations" +
-      "?Configuration/category=ldap-configuration" +
-      "&fields=Configuration/properties";
+
+  private static final String GET_AMBARI_LDAP_CONFIG_URI = String.format("/api/v1/services/%s/components/%s/configurations?%s=%s&fields=%s",
+    RootService.AMBARI.name(),
+    RootComponent.AMBARI_SERVER.name(),
+    RootServiceComponentConfigurationResourceProvider.CONFIGURATION_CATEGORY_PROPERTY_ID,
+    LDAP_CONFIGURATION_PROPERTY,
+    RootServiceComponentConfigurationResourceProvider.CONFIGURATION_PROPERTIES_PROPERTY_ID);
+
   private static final String SERVICES_PROPERTY = "services";
   private static final String SERVICES_COMPONENTS_PROPERTY = "components";
   private static final String CONFIG_GROUPS_PROPERTY = "config-groups";
@@ -100,7 +108,6 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend
   private static final String CHANGED_CONFIGURATIONS_PROPERTY = "changed-configurations";
   private static final String USER_CONTEXT_PROPERTY = "user-context";
   private static final String AMBARI_SERVER_CONFIGURATIONS_PROPERTY = "ambari-server-properties";
-  static final String LDAP_CONFIGURATION_PROPERTY = "ldap-configuration";
 
   private File recommendationsDir;
   private String recommendationsArtifactsLifetime;

http://git-wip-us.apache.org/repos/asf/ambari/blob/786d4b63/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
index 474c335..ab85aa1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
@@ -467,8 +467,8 @@ public class KerberosHelperImpl implements KerberosHelper {
     // If Ambari is managing it own identities then add AMBARI to the set of installed service so
     // that its Kerberos descriptor entries will be included.
     if (createAmbariIdentities(existingConfigurations.get(KERBEROS_ENV))) {
-      installedServices = new HashMap<String, Set<String>>(installedServices);
-      installedServices.put("AMBARI", Collections.singleton("AMBARI_SERVER"));
+      installedServices = new HashMap<>(installedServices);
+      installedServices.put(RootService.AMBARI.name(), Collections.singleton(RootComponent.AMBARI_SERVER.name()));
     }
 
     // Create the context to use for filtering Kerberos Identities based on the state of the cluster
@@ -1547,7 +1547,7 @@ public class KerberosHelperImpl implements KerberosHelper {
                 keytabFileGroupName,
                 keytabFileGroupAccess,
                 Sets.newHashSet(Pair.of(hostId, Pair.of(evaluatedPrincipal, principalType))),
-                serviceName.equalsIgnoreCase("AMBARI"),
+                serviceName.equalsIgnoreCase(RootService.AMBARI.name()),
                 componentName.equalsIgnoreCase("AMBARI_SERVER_SELF")
             );
             if (resolvedKeytabs.containsKey(keytabFilePath)) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/786d4b63/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProvider.java
index ea9cf4f..7807865 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProvider.java
@@ -59,10 +59,10 @@ public class RootServiceComponentConfigurationResourceProvider extends AbstractA
 
   static final String RESOURCE_KEY = "Configuration";
 
-  static final String CONFIGURATION_CATEGORY_PROPERTY_ID = PropertyHelper.getPropertyId(RESOURCE_KEY, "category");
-  static final String CONFIGURATION_PROPERTIES_PROPERTY_ID = PropertyHelper.getPropertyId(RESOURCE_KEY, "properties");
-  static final String CONFIGURATION_COMPONENT_NAME_PROPERTY_ID = PropertyHelper.getPropertyId(RESOURCE_KEY, "component_name");
-  static final String CONFIGURATION_SERVICE_NAME_PROPERTY_ID = PropertyHelper.getPropertyId(RESOURCE_KEY, "service_name");
+  public static final String CONFIGURATION_CATEGORY_PROPERTY_ID = PropertyHelper.getPropertyId(RESOURCE_KEY, "category");
+  public static final String CONFIGURATION_PROPERTIES_PROPERTY_ID = PropertyHelper.getPropertyId(RESOURCE_KEY, "properties");
+  public static final String CONFIGURATION_COMPONENT_NAME_PROPERTY_ID = PropertyHelper.getPropertyId(RESOURCE_KEY, "component_name");
+  public static final String CONFIGURATION_SERVICE_NAME_PROPERTY_ID = PropertyHelper.getPropertyId(RESOURCE_KEY, "service_name");
 
   private static final Set<String> PROPERTIES;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/786d4b63/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
index 4008620..b8affb4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
@@ -33,6 +33,8 @@ import java.util.Set;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.CommandReport;
 import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.controller.RootComponent;
+import org.apache.ambari.server.controller.RootService;
 import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.ServiceComponentHost;
@@ -192,11 +194,11 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
               // component.
               String componentName = KerberosHelper.AMBARI_SERVER_KERBEROS_IDENTITY_NAME.equals(identity.getName())
                   ? "AMBARI_SERVER_SELF"
-                  : "AMBARI_SERVER";
+                  : RootComponent.AMBARI_SERVER.name();
 
               List<KerberosIdentityDescriptor> componentIdentities = Collections.singletonList(identity);
               kerberosHelper.addIdentities(kerberosIdentityDataFileWriter, componentIdentities,
-                  identityFilter, StageUtils.getHostName(), ambariServerHostID(), "AMBARI", componentName, kerberosConfigurations, currentConfigurations,
+                  identityFilter, StageUtils.getHostName(), ambariServerHostID(), RootService.AMBARI.name(), componentName, kerberosConfigurations, currentConfigurations,
                   resolvedKeytabs, realm);
               propertiesToIgnore = gatherPropertiesToIgnore(componentIdentities, propertiesToIgnore);
             }

http://git-wip-us.apache.org/repos/asf/ambari/blob/786d4b63/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
index b0fca8d..83a2106 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
@@ -30,6 +30,8 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.agent.CommandReport;
 import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.controller.RootComponent;
+import org.apache.ambari.server.controller.RootService;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
@@ -110,7 +112,8 @@ public class PrepareKerberosIdentitiesServerAction extends AbstractPrepareKerber
     if (serviceComponentFilter != null) {
       // If we are including the Ambari identity; then ensure that if a service/component filter is set,
       // it contains the AMBARI/AMBARI_SERVER component; else do not include the Ambari service identity.
-      includeAmbariIdentity &= (serviceComponentFilter.get("AMBARI") != null) && serviceComponentFilter.get("AMBARI").contains("AMBARI_SERVER");
+      includeAmbariIdentity &= (serviceComponentFilter.get(RootService.AMBARI.name()) != null)
+        && serviceComponentFilter.get(RootService.AMBARI.name()).contains(RootComponent.AMBARI_SERVER.name());
 
       if((operationType != OperationType.DEFAULT)) {
         // Update the identity filter, if necessary

http://git-wip-us.apache.org/repos/asf/ambari/blob/786d4b63/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
index eb39562..933afa2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
@@ -49,6 +49,7 @@ import org.apache.ambari.server.controller.ClusterRequest;
 import org.apache.ambari.server.controller.ConfigGroupRequest;
 import org.apache.ambari.server.controller.ConfigurationRequest;
 import org.apache.ambari.server.controller.RequestStatusResponse;
+import org.apache.ambari.server.controller.RootComponent;
 import org.apache.ambari.server.controller.ServiceComponentHostRequest;
 import org.apache.ambari.server.controller.ServiceComponentRequest;
 import org.apache.ambari.server.controller.ServiceRequest;
@@ -402,7 +403,7 @@ public class AmbariContext {
       for (String component : entry.getValue()) {
         //todo: handle this in a generic manner.  These checks are all over the code
         try {
-          if (cluster.getService(service) != null && !component.equals("AMBARI_SERVER")) {
+          if (cluster.getService(service) != null && !component.equals(RootComponent.AMBARI_SERVER.name())) {
             requests.add(new ServiceComponentHostRequest(clusterName, service, component, hostName, null));
           }
         } catch(AmbariException se) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/786d4b63/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintFactory.java
index 404068d..24b4785 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/BlueprintFactory.java
@@ -30,6 +30,7 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.AmbariServer;
+import org.apache.ambari.server.controller.RootComponent;
 import org.apache.ambari.server.controller.internal.ProvisionAction;
 import org.apache.ambari.server.controller.internal.Stack;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
@@ -205,7 +206,7 @@ public class BlueprintFactory {
       allComponents.addAll(components);
     }
     // currently ambari server is no a recognized component
-    allComponents.add("AMBARI_SERVER");
+    allComponents.add(RootComponent.AMBARI_SERVER.name());
 
     return allComponents;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/786d4b63/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/RequiredPasswordValidator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/RequiredPasswordValidator.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/RequiredPasswordValidator.java
index 5b4ecc1..3ad1a19 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/RequiredPasswordValidator.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/RequiredPasswordValidator.java
@@ -19,6 +19,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 
+import org.apache.ambari.server.controller.RootComponent;
 import org.apache.ambari.server.controller.internal.Stack;
 import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.topology.Blueprint;
@@ -86,7 +87,7 @@ public class RequiredPasswordValidator implements TopologyValidator {
       HostGroup hostGroup = blueprint.getHostGroup(hostGroupName);
       for (String component : hostGroup.getComponentNames()) {
         //for now, AMBARI is not recognized as a service in Stacks
-        if (component.equals("AMBARI_SERVER")) {
+        if (component.equals(RootComponent.AMBARI_SERVER.name())) {
           continue;
         }
 


[45/49] ambari git commit: AMBARI-22519 Admin View: add ability to change roles. (atkach)

Posted by rl...@apache.org.
AMBARI-22519 Admin View: add ability to change roles. (atkach)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 32e25b80c43158bd7114f11825eaa590c9b7e8b0
Parents: 3dca560
Author: Andrii Tkach <at...@apache.org>
Authored: Mon Nov 27 14:18:59 2017 +0200
Committer: Andrii Tkach <at...@apache.org>
Committed: Mon Nov 27 15:41:01 2017 +0200

----------------------------------------------------------------------
 .../main/resources/ui/admin-web/app/index.html  |   1 -
 .../userManagement/GroupCreateCtrl.js           |  32 +-
 .../controllers/userManagement/GroupEditCtrl.js | 162 +++++++---
 .../userManagement/GroupsListCtrl.js            |  17 +-
 .../userManagement/UserCreateCtrl.js            |  25 +-
 .../controllers/userManagement/UserEditCtrl.js  | 304 ++++++++++++-------
 .../userManagement/UserManagementCtrl.js        |   4 +-
 .../controllers/userManagement/UsersListCtrl.js |  69 +++--
 .../ui/admin-web/app/scripts/i18n.config.js     |   6 +-
 .../admin-web/app/scripts/services/Cluster.js   |  90 +++---
 .../ui/admin-web/app/scripts/services/Group.js  | 144 ++++-----
 .../app/scripts/services/GroupConstants.js      |  38 ---
 .../app/scripts/services/RoleDetailsModal.js    |   5 +-
 .../ui/admin-web/app/scripts/services/User.js   |  17 +-
 .../resources/ui/admin-web/app/styles/main.css  |   5 -
 .../ui/admin-web/app/styles/user-management.css |  13 +
 .../app/views/remoteClusters/list.html          |   5 +-
 .../admin-web/app/views/stackVersions/list.html |   7 +-
 .../app/views/userManagement/groupEdit.html     | 149 +++++----
 .../app/views/userManagement/main.html          |   4 +-
 .../userManagement/modals/groupCreate.html      |   8 +-
 .../views/userManagement/modals/userCreate.html |  10 +-
 .../app/views/userManagement/userEdit.html      |  48 ++-
 .../app/views/userManagement/usersList.html     |   2 +-
 24 files changed, 647 insertions(+), 518 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/index.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/index.html b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
index e3b817e..bf033e6 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/index.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
@@ -153,7 +153,6 @@
 <script src="scripts/services/Utility.js"></script>
 <script src="scripts/services/UserConstants.js"></script>
 <script src="scripts/services/User.js"></script>
-<script src="scripts/services/GroupConstants.js"></script>
 <script src="scripts/services/Group.js"></script>
 <script src="scripts/services/RemoteCluster.js"></script>
 <script src="scripts/services/View.js"></script>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
index 94a2c9f..a34033b 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
@@ -19,8 +19,8 @@
 
 angular.module('ambariAdminConsole')
 .controller('GroupCreateCtrl',
-['$scope', '$rootScope', 'Group', '$location', 'Alert', 'UnsavedDialog', '$translate', '$modalInstance', 'Cluster',
-function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate, $modalInstance, Cluster) {
+['$scope', '$rootScope', 'Group', '$location', 'Alert', 'UnsavedDialog', '$translate', '$modalInstance', 'Cluster', 'RoleDetailsModal',
+function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate, $modalInstance, Cluster, RoleDetailsModal) {
   var $t = $translate.instant;
 
   $scope.form = {};
@@ -33,10 +33,8 @@ function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate,
 
 
   function loadRoles() {
-    Cluster.getPermissions().then(function(data) {
-      $scope.roleOptions = data.map(function(item) {
-        return item.PermissionInfo;
-      });
+    return Cluster.getRoleOptions().then(function (data) {
+      $scope.roleOptions = data;
     });
   }
 
@@ -60,6 +58,9 @@ function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate,
   }
 
   function saveMembers(group, members) {
+    if (!members.length) {
+      return;
+    }
     group.members = members.filter(function(item) {
       return item.trim();
     }).map(function(item) {
@@ -70,6 +71,12 @@ function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate,
     });
   }
 
+  $scope.showHelpPage = function() {
+    Cluster.getRolesWithAuthorizations().then(function(roles) {
+      RoleDetailsModal.show(roles);
+    });
+  };
+
   $scope.save = function () {
     $scope.form.groupCreateForm.submitted = true;
     if ($scope.form.groupCreateForm.$valid) {
@@ -87,21 +94,22 @@ function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate,
   };
 
   function saveRole() {
+    if (!$scope.formData.role || $scope.formData.role === 'NONE') {
+      return;
+    }
     Cluster.createPrivileges(
       {
         clusterId: $rootScope.cluster.Clusters.cluster_name
       },
       [{PrivilegeInfo: {
-        permission_name: $scope.roleOptions.filter(function(role) {
-          return role.permission_id == Number($scope.formData.role);
-        })[0].permission_name,
+        permission_name: $scope.formData.role,
         principal_name: $scope.formData.groupName,
         principal_type: 'GROUP'
       }}]
     )
-      .catch(function(data) {
-        Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
-      });
+    .catch(function(data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
   }
 
   $scope.cancel = function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
index ff705eb..8855317 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
@@ -19,9 +19,14 @@
 
 angular.module('ambariAdminConsole')
 .controller('GroupEditCtrl',
-['$scope', 'Group', '$routeParams', 'Cluster', 'View', 'Alert', 'ConfirmationModal', '$location', 'GroupConstants', '$translate',
-function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $location, GroupConstants, $translate) {
+['$scope', '$rootScope', 'Group', '$routeParams', 'Cluster', 'View', 'Alert', 'ConfirmationModal', '$location', '$translate', 'RoleDetailsModal',
+function($scope, $rootScope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $location,  $translate, RoleDetailsModal) {
   var $t = $translate.instant;
+  var nonRole = {
+    permission_name: 'NONE',
+    permission_label: $t('users.roles.none')
+  };
+
   $scope.constants = {
     group: $t('common.group'),
     view: $t('common.view').toLowerCase(),
@@ -32,7 +37,6 @@ function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $
   $scope.group.editingUsers = [];
   $scope.groupMembers = [];
   $scope.dataLoaded = false;
-  
   $scope.isMembersEditing = false;
 
   $scope.$watch(function() {
@@ -62,30 +66,11 @@ function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $
     $scope.group.saveMembers().catch(function(data) {
         Alert.error($t('groups.alerts.cannotUpdateGroupMembers'), "<div class='break-word'>" + data.message + "</div>");
       }).finally(function() {
-        loadMembers();
+        loadGroup();
       });
     $scope.isMembersEditing = false;
   };
 
-
-  function loadMembers(){
-    $scope.group.getMembers().then(function(members) {
-      $scope.group.groupTypeName = $t(GroupConstants.TYPES[$scope.group.group_type].LABEL_KEY);
-      $scope.groupMembers = members;
-      $scope.group.editingUsers = angular.copy($scope.groupMembers);
-    });
-  }    
-  
-  $scope.group.isLDAP().then(function(isLDAP) {
-    $scope.group.ldap_group = isLDAP;
-    $scope.group.getGroupType().then(function() {
-      $scope.group.groupTypeName = $t(GroupConstants.TYPES[$scope.group.group_type].LABEL_KEY);
-    });
-    loadMembers();
-  });
-
-  $scope.group.getGroupType();
-
   $scope.deleteGroup = function(group) {
     ConfirmationModal.show(
       $t('common.delete', {
@@ -119,12 +104,9 @@ function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $
           });
         }
         group.destroy().then(function() {
-          $location.path('/userManagement');
+          $location.path('/userManagement?tab=groups');
           if (clusterPrivilegesIds.length) {
-            Cluster.getAllClusters().then(function (clusters) {
-              var clusterName = clusters[0].Clusters.cluster_name;
-              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
-            });
+            Cluster.deleteMultiplePrivileges($rootScope.cluster.Clusters.cluster_name, clusterPrivilegesIds);
           }
           angular.forEach(viewsPrivileges, function(privilege) {
             View.deletePrivilege(privilege);
@@ -135,7 +117,7 @@ function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $
   };
 
 
-  $scope.removePrivilege = function(name, privilege) {
+  $scope.removeViewPrivilege = function(name, privilege) {
     var privilegeObject = {
         id: privilege.privilege_id,
         view_name: privilege.view_name,
@@ -143,40 +125,124 @@ function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $
         instance_name: name
     };
     View.deletePrivilege(privilegeObject).then(function() {
-      loadPrivileges();
+      loadGroup();
     });
   };
 
-function loadPrivileges() {
-  // Load privileges
-  Group.getPrivileges($routeParams.id).then(function(data) {
+  $scope.showHelpPage = function() {
+    Cluster.getRolesWithAuthorizations().then(function(roles) {
+      RoleDetailsModal.show(roles);
+    });
+  };
+
+  $scope.updateRole = function () {
+    var clusterName = $rootScope.cluster.Clusters.cluster_name;
+    if ($scope.originalRole.permission_name !== $scope.currentRole.permission_name) {
+      if ($scope.currentRole.permission_name === 'NONE') {
+        deleteGroupRoles(clusterName, $scope.group).finally(loadGroup);
+      } else {
+        if ($scope.group.roles.length) {
+          deleteGroupRoles(clusterName, $scope.group, true).finally(function() {
+            addGroupRoles(clusterName, $scope.currentRole, $scope.group).finally(loadGroup);
+          });
+        } else {
+          addGroupRoles(clusterName, $scope.currentRole, $scope.group).finally(loadGroup);
+        }
+      }
+    }
+  };
+
+  function deleteGroupRoles(clusterName, group, ignoreAlert) {
+    return Cluster.deleteMultiplePrivileges(
+      clusterName,
+      group.roles.map(function(item) {
+        return item.privilege_id;
+      })
+    ).then(function () {
+      if (!ignoreAlert) {
+        Alert.success($t('users.alerts.roleChangedToNone', {
+          user_name: group.group_name
+        }));
+      }
+    }).catch(function (data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
+  }
+
+  function addGroupRoles(clusterName, newRole, group) {
+    return Cluster.createPrivileges(
+      {
+        clusterId: clusterName
+      },
+      [{
+        PrivilegeInfo: {
+          permission_name: newRole.permission_name,
+          principal_name: group.group_name,
+          principal_type: 'GROUP'
+        }
+      }]
+    ).then(function () {
+      Alert.success($t('users.alerts.roleChanged', {
+        name: group.group_name,
+        role: newRole.permission_label
+      }));
+    }).catch(function (data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
+  }
+
+  function parsePrivileges(rawPrivileges) {
     var privileges = {
       clusters: {},
       views: {}
     };
-    angular.forEach(data.data.items, function(privilege) {
+    angular.forEach(rawPrivileges, function (privilege) {
       privilege = privilege.PrivilegeInfo;
-      if(privilege.type === 'CLUSTER'){
+      if (privilege.type === 'CLUSTER') {
         // This is cluster
         privileges.clusters[privilege.cluster_name] = privileges.clusters[privilege.cluster_name] || [];
         privileges.clusters[privilege.cluster_name].push(privilege.permission_label);
-      } else if ( privilege.type === 'VIEW'){
-        privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || { privileges:[]};
-        privileges.views[privilege.instance_name].version = privilege.version;
-        privileges.views[privilege.instance_name].view_name = privilege.view_name;
-        privileges.views[privilege.instance_name].privilege_id = privilege.privilege_id;
-        privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
+      } else if (privilege.type === 'VIEW') {
+        privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || {
+          privileges: [],
+          version: privilege.version,
+          view_name: privilege.view_name,
+          privilege_id: privilege.privilege_id
+        };
+        if (privileges.views[privilege.instance_name].privileges.indexOf(privilege.permission_label) === -1) {
+          privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
+        }
       }
     });
 
-    $scope.privileges = data.data.items.length ? privileges : null;
+    $scope.privileges = privileges;
     $scope.noClusterPriv = $.isEmptyObject(privileges.clusters);
     $scope.noViewPriv = $.isEmptyObject(privileges.views);
     $scope.hidePrivileges = $scope.noClusterPriv && $scope.noViewPriv;
-    $scope.dataLoaded = true;
-  }).catch(function(data) {
-    Alert.error($t('common.alerts.cannotLoadPrivileges'), data.data.message);
-  });
-}
-loadPrivileges();
+  }
+
+  function loadGroup() {
+    Group.get($routeParams.id).then(function(group) {
+      $scope.group = group;
+      parsePrivileges(group.privileges);
+      var clusterRole = $scope.group.roles[0];
+      $scope.currentRole = clusterRole || nonRole;
+      $scope.originalRole = clusterRole || nonRole;
+      $scope.groupMembers = group.members.map(function(item) {
+        return item.MemberInfo.user_name;
+      });
+      $scope.group.editingUsers = angular.copy($scope.groupMembers);
+    }).finally(function() {
+      $scope.dataLoaded = true;
+    });
+  }
+
+  function loadRoles() {
+    return Cluster.getRoleOptions().then(function(data) {
+      $scope.roleOptions = data;
+    });
+  }
+
+  loadRoles().finally(loadGroup);
+
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
index af77ba9..61b5282 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
@@ -19,8 +19,8 @@
 
 angular.module('ambariAdminConsole')
 .controller('GroupsListCtrl',
-['$scope', 'Group', '$modal', 'ConfirmationModal', '$rootScope', 'GroupConstants', '$translate', 'Settings', 'Cluster', 'View', '$location',
-function($scope, Group, $modal, ConfirmationModal, $rootScope, GroupConstants, $translate, Settings, Cluster, View, $location) {
+['$scope', 'Group', '$modal', 'ConfirmationModal', '$rootScope', '$translate', 'Settings', 'Cluster', 'View', 'Alert',
+function($scope, Group, $modal, ConfirmationModal, $rootScope, $translate, Settings, Cluster, View, Alert) {
   var $t = $translate.instant;
   $scope.constants = {
     groups: $t('common.groups').toLowerCase()
@@ -70,15 +70,15 @@ function($scope, Group, $modal, ConfirmationModal, $rootScope, GroupConstants, $
       $scope.tableInfo.showed = groups.length;
     })
     .catch(function(data) {
-      console.error($t('groups.alerts.getGroupsListError'));
+      Alert.error($t('groups.alerts.getGroupsListError'), data.data.message);
     });
   }
 
   $scope.typeFilterOptions = [{ label: $t('common.all'), value: '*'}]
-    .concat(Object.keys(GroupConstants.TYPES).map(function(key) {
+    .concat(Object.keys(Group.getTypes()).map(function(key) {
       return {
-        label: $t(GroupConstants.TYPES[key].LABEL_KEY),
-        value: GroupConstants.TYPES[key].VALUE
+        label: $t(Group.getTypes()[key].LABEL_KEY),
+        value: Group.getTypes()[key].VALUE
       };
   }));
   $scope.filter.type = $scope.typeFilterOptions[0];
@@ -153,10 +153,7 @@ function($scope, Group, $modal, ConfirmationModal, $rootScope, GroupConstants, $
         }
         group.destroy().then(function() {
           if (clusterPrivilegesIds.length) {
-            Cluster.getAllClusters().then(function (clusters) {
-              var clusterName = clusters[0].Clusters.cluster_name;
-              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
-            });
+            Cluster.deleteMultiplePrivileges($rootScope.cluster.Clusters.cluster_name, clusterPrivilegesIds);
           }
           angular.forEach(viewsPrivileges, function(privilege) {
             View.deletePrivilege(privilege);

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
index 34637ae..3b29b90 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
@@ -19,8 +19,8 @@
 
 angular.module('ambariAdminConsole')
 .controller('UserCreateCtrl',
-['$scope', '$rootScope', 'User', '$location', 'Alert', 'UnsavedDialog', '$translate', 'Cluster', '$modalInstance',
-function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate, Cluster, $modalInstance) {
+['$scope', '$rootScope', 'User', '$location', 'Alert', 'UnsavedDialog', '$translate', 'Cluster', '$modalInstance', 'RoleDetailsModal',
+function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate, Cluster, $modalInstance, RoleDetailsModal) {
   var $t = $translate.instant;
 
   $scope.form = {};
@@ -28,17 +28,15 @@ function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate,
     userName: '',
     password: '',
     confirmPassword: '',
-    role: null,
+    role: '',
     isAdmin: false,
     isActive: true
   };
   $scope.roleOptions = [];
 
   function loadRoles() {
-    Cluster.getPermissions().then(function(data) {
-      $scope.roleOptions = data.map(function(item) {
-        return item.PermissionInfo;
-      });
+    return Cluster.getRoleOptions().then(function (data) {
+      $scope.roleOptions = data;
     });
   }
 
@@ -61,6 +59,12 @@ function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate,
     }
   }
 
+  $scope.showHelpPage = function() {
+    Cluster.getRolesWithAuthorizations().then(function(roles) {
+      RoleDetailsModal.show(roles);
+    });
+  };
+
   $scope.save = function () {
     $scope.form.userCreateForm.submitted = true;
     if ($scope.form.userCreateForm.$valid) {
@@ -83,14 +87,15 @@ function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate,
   };
 
   function saveRole() {
+    if (!$scope.formData.role || $scope.formData.role === 'NONE') {
+      return;
+    }
     Cluster.createPrivileges(
       {
         clusterId: $rootScope.cluster.Clusters.cluster_name
       },
       [{PrivilegeInfo: {
-        permission_name: $scope.roleOptions.filter(function(role) {
-          return role.permission_id == Number($scope.formData.role);
-        })[0].permission_name,
+        permission_name: $scope.formData.role,
         principal_name: $scope.formData.userName,
         principal_type: 'USER'
       }}]

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
index 001bb1b..a3c96cd 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
@@ -18,9 +18,15 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('UserEditCtrl', ['$scope', '$routeParams', 'Cluster', 'User', 'View', '$modal', '$location', 'ConfirmationModal', 'Alert', 'Auth', 'getDifference', 'Group', '$q', 'UserConstants', '$translate', function($scope, $routeParams, Cluster, User, View, $modal, $location, ConfirmationModal, Alert, Auth, getDifference, Group, $q, UserConstants, $translate) {
+.controller('UserEditCtrl',
+['$scope', '$rootScope', '$routeParams', 'Cluster', 'User', 'View', '$modal', '$location', 'ConfirmationModal', 'Alert', 'Auth', 'getDifference', 'Group', '$q', 'UserConstants', '$translate', 'RoleDetailsModal',
+function($scope, $rootScope, $routeParams, Cluster, User, View, $modal, $location, ConfirmationModal, Alert, Auth, getDifference, Group, $q, UserConstants, $translate, RoleDetailsModal) {
 
   var $t = $translate.instant;
+  var nonRole = {
+    permission_name: 'NONE',
+    permission_label: $t('users.roles.none')
+  };
 
   $scope.constants = {
     user: $t('common.user'),
@@ -31,77 +37,95 @@ angular.module('ambariAdminConsole')
     cluster: $t('common.cluster').toLowerCase()
   };
 
-  function loadUserInfo(){
-    User.get($routeParams.id).then(function(data) {
-      $scope.user = User.makeUser(data).Users;
-      $scope.isCurrentUser = $scope.user.user_name === Auth.getCurrentUser();
-      $scope.editingGroupsList = angular.copy($scope.user.groups);
-    });
-  }
-
-  loadUserInfo();
-  $scope.user;
+  $scope.user = null;
   $scope.isCurrentUser = true;
   $scope.dataLoaded = false;
-
   $scope.isGroupEditing = false;
-  $scope.enableGroupEditing = function() {
+
+  $scope.enableGroupEditing = function () {
     $scope.isGroupEditing = true;
     $scope.editingGroupsList = angular.copy($scope.user.groups);
   };
 
-  $scope.$watch(function() {
+  $scope.$watch(function () {
     return $scope.editingGroupsList;
-  }, function(newValue) {
-    if(newValue){
-      if( !angular.equals(newValue, $scope.user.groups) ){
+  }, function (newValue) {
+    if (newValue) {
+      if (!angular.equals(newValue, $scope.user.groups)) {
         $scope.updateGroups();
       }
     }
   }, true);
 
-  $scope.updateGroups = function() {
-    var groups = $scope.editingGroupsList.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()});
+  $scope.showHelpPage = function() {
+    Cluster.getRolesWithAuthorizations().then(function(roles) {
+      RoleDetailsModal.show(roles);
+    });
+  };
+
+  $scope.updateRole = function () {
+    var clusterName = $rootScope.cluster.Clusters.cluster_name;
+    if ($scope.originalRole.permission_name !== $scope.currentRole.permission_name) {
+      if ($scope.currentRole.permission_name === 'NONE') {
+        deleteUserRoles(clusterName, $scope.user).finally(loadUserInfo);
+      } else {
+        if ($scope.user.roles.length) {
+          deleteUserRoles(clusterName, $scope.user, true).finally(function() {
+            addUserRoles(clusterName, $scope.currentRole, $scope.user).finally(loadUserInfo);
+          });
+        } else {
+          addUserRoles(clusterName, $scope.currentRole, $scope.user).finally(loadUserInfo);
+        }
+      }
+    }
+  };
+
+  $scope.updateGroups = function () {
+    var groups = $scope.editingGroupsList.filter(function (item) {
+      return item.trim();
+    }).map(function (item) {
+      return item.trim();
+    });
     var diff = getDifference($scope.user.groups, groups);
     var promises = [];
     // Remove user from groups
-    angular.forEach(diff.del, function(groupName) {
-      promises.push(Group.removeMemberFromGroup(groupName, $scope.user.user_name).catch(function(data) {
+    angular.forEach(diff.del, function (groupName) {
+      promises.push(Group.removeMemberFromGroup(groupName, $scope.user.user_name).catch(function (data) {
         Alert.error($t('users.alerts.removeUserError'), data.data.message);
       }));
     });
     // Add user to groups
-    angular.forEach(diff.add, function(groupName) {
-      promises.push(Group.addMemberToGroup(groupName, $scope.user.user_name).catch(function(data) {
+    angular.forEach(diff.add, function (groupName) {
+      promises.push(Group.addMemberToGroup(groupName, $scope.user.user_name).catch(function (data) {
         Alert.error($t('users.alerts.cannotAddUser'), data.data.message);
       }));
     });
-    $q.all(promises).then(function() {
+    $q.all(promises).then(function () {
       loadUserInfo();
     });
     $scope.isGroupEditing = false;
   };
 
-  $scope.getUserMembership = function(userType) {
-    if(userType) {
-	return $t(UserConstants.TYPES[userType].LABEL_KEY) + " " + $t('users.groupMembership');
+  $scope.getUserMembership = function (userType) {
+    if (userType) {
+      return $t(UserConstants.TYPES[userType].LABEL_KEY) + " " + $t('users.groupMembership');
     }
   };
 
-  $scope.cancelUpdate = function() {
+  $scope.cancelUpdate = function () {
     $scope.isGroupEditing = false;
     $scope.editingGroupsList = '';
   };
 
-  $scope.openChangePwdDialog = function() {
+  $scope.openChangePwdDialog = function () {
     var modalInstance = $modal.open({
       templateUrl: 'views/userManagement/modals/changePassword.html',
       resolve: {
-        userName: function() {
+        userName: function () {
           return $scope.user.user_name;
         }
       },
-      controller: ['$scope', 'userName', function($scope, userName) {
+      controller: ['$scope', 'userName', function ($scope, userName) {
         $scope.passwordData = {
           password: '',
           currentUserPassword: ''
@@ -110,55 +134,54 @@ angular.module('ambariAdminConsole')
         $scope.form = {};
         $scope.userName = userName;
 
-        $scope.ok = function() {
+        $scope.ok = function () {
           $scope.form.passwordChangeForm.submitted = true;
-          if($scope.form.passwordChangeForm.$valid){
-
+          if ($scope.form.passwordChangeForm.$valid) {
             modalInstance.close({
-              password: $scope.passwordData.password, 
+              password: $scope.passwordData.password,
               currentUserPassword: $scope.passwordData.currentUserPassword
             });
           }
         };
-        $scope.cancel = function() {
+        $scope.cancel = function () {
           modalInstance.dismiss('cancel');
         };
       }]
     });
 
-    modalInstance.result.then(function(data) {
-      User.setPassword($scope.user, data.password, data.currentUserPassword).then(function() {
+    modalInstance.result.then(function (data) {
+      User.setPassword($scope.user, data.password, data.currentUserPassword).then(function () {
         Alert.success($t('users.alerts.passwordChanged'));
-      }).catch(function(data) {
+      }).catch(function (data) {
         Alert.error($t('users.alerts.cannotChangePassword'), data.data.message);
       });
-    }); 
+    });
   };
 
-  $scope.toggleUserActive = function() {
-    if(!$scope.isCurrentUser){
-      var newStatusKey = $scope.user.active ? 'inactive' : 'active',
-        newStatus = $t('users.' + newStatusKey).toLowerCase();
+  $scope.toggleUserActive = function () {
+    if (!$scope.isCurrentUser) {
+      var newStatusKey = $scope.user.active ? 'inactive' : 'active';
       ConfirmationModal.show(
         $t('users.changeStatusConfirmation.title'),
         $t('users.changeStatusConfirmation.message', {
           userName: $scope.user.user_name,
-          status: newStatus
+          status: $t('users.' + newStatusKey).toLowerCase()
         })
-      ).then(function() {
+      ).then(function () {
         User.setActive($scope.user.user_name, $scope.user.active)
-          .catch(function(data) {
-            Alert.error($t('common.alerts.cannotUpdateStatus'), data.data.message);
-            $scope.user.active = !$scope.user.active;
-          });
+        .catch(function (data) {
+          Alert.error($t('common.alerts.cannotUpdateStatus'), data.data.message);
+          $scope.user.active = !$scope.user.active;
+        });
       })
-      .catch(function() {
+      .catch(function () {
         $scope.user.active = !$scope.user.active;
       });
     }
-  };    
-  $scope.toggleUserAdmin = function() {
-    if(!$scope.isCurrentUser){
+  };
+
+  $scope.toggleUserAdmin = function () {
+    if (!$scope.isCurrentUser) {
       var action = $scope.user.admin ?
         $t('users.changePrivilegeConfirmation.revoke') : $t('users.changePrivilegeConfirmation.grant');
       ConfirmationModal.show(
@@ -167,36 +190,35 @@ angular.module('ambariAdminConsole')
           action: action,
           userName: $scope.user.user_name
         })
-      ).then(function() {
+      ).then(function () {
         User.setAdmin($scope.user.user_name, $scope.user.admin)
-        .then(function() {
-          loadPrivileges();
+        .then(function () {
+          loadUserInfo();
         })
         .catch(function (data) {
           Alert.error($t('common.alerts.cannotUpdateAdminStatus'), data.data.message);
           $scope.user.admin = !$scope.user.admin;
         });
       })
-      .catch(function() {
+      .catch(function () {
         $scope.user.admin = !$scope.user.admin;
       });
-
     }
   };
 
-  $scope.removePrivilege = function(name, privilege) {
+  $scope.removeViewPrivilege = function (name, privilege) {
     var privilegeObject = {
-        id: privilege.privilege_id,
-        view_name: privilege.view_name,
-        version: privilege.version,
-        instance_name: name
+      id: privilege.privilege_id,
+      view_name: privilege.view_name,
+      version: privilege.version,
+      instance_name: name
     };
-    View.deletePrivilege(privilegeObject).then(function() {
-      loadPrivileges();
+    View.deletePrivilege(privilegeObject).then(function () {
+      loadUserInfo();
     });
   };
 
-  $scope.deleteUser = function() {
+  $scope.deleteUser = function () {
     ConfirmationModal.show(
       $t('common.delete', {
         term: $t('common.user')
@@ -205,15 +227,15 @@ angular.module('ambariAdminConsole')
         instanceType: $t('common.user').toLowerCase(),
         instanceName: '"' + $scope.user.user_name + '"'
       })
-    ).then(function() {
+    ).then(function () {
       Cluster.getPrivilegesForResource({
-        nameFilter : $scope.user.user_name,
-        typeFilter : {value: 'USER'}
-      }).then(function(data) {
+        nameFilter: $scope.user.user_name,
+        typeFilter: {value: 'USER'}
+      }).then(function (data) {
         var clusterPrivilegesIds = [];
         var viewsPrivileges = [];
         if (data.items && data.items.length) {
-          angular.forEach(data.items[0].privileges, function(privilege) {
+          angular.forEach(data.items[0].privileges, function (privilege) {
             if (privilege.PrivilegeInfo.principal_type === 'USER') {
               if (privilege.PrivilegeInfo.type === 'VIEW') {
                 viewsPrivileges.push({
@@ -228,15 +250,12 @@ angular.module('ambariAdminConsole')
             }
           });
         }
-        User.delete($scope.user.user_name).then(function() {
-          $location.path('/userManagement');
+        User.delete($scope.user.user_name).then(function () {
+          $location.path('/userManagement?tab=users');
           if (clusterPrivilegesIds.length) {
-            Cluster.getAllClusters().then(function (clusters) {
-              var clusterName = clusters[0].Clusters.cluster_name;
-              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
-            });
+            Cluster.deleteMultiplePrivileges($rootScope.cluster.Clusters.cluster_name, clusterPrivilegesIds);
           }
-          angular.forEach(viewsPrivileges, function(privilege) {
+          angular.forEach(viewsPrivileges, function (privilege) {
             View.deletePrivilege(privilege);
           });
         });
@@ -244,47 +263,102 @@ angular.module('ambariAdminConsole')
     });
   };
 
-  // Load privileges
-  function loadPrivileges(){
-    User.getPrivileges($routeParams.id).then(function(data) {
-      var privileges = {
-        clusters: {},
-        views: {}
-      };
-      angular.forEach(data.data.items, function(privilege) {
-        privilege = privilege.PrivilegeInfo;
-        if(privilege.type === 'CLUSTER'){
-          // This is cluster
-          if (privileges.clusters[privilege.cluster_name]) {
-            var preIndex = Cluster.orderedRoles.indexOf(privileges.clusters[privilege.cluster_name].permission_name);
-            var curIndex = Cluster.orderedRoles.indexOf(privilege.permission_name);
-            // replace when cur is a more powerful role
-            if (curIndex < preIndex) {
-              privileges.clusters[privilege.cluster_name] = privilege;
-            }
-          } else {
+  function deleteUserRoles(clusterName, user, ignoreAlert) {
+    return Cluster.deleteMultiplePrivileges(
+      clusterName,
+      user.roles.map(function(item) {
+        return item.privilege_id;
+      })
+    ).then(function () {
+      if (!ignoreAlert) {
+        Alert.success($t('users.alerts.roleChangedToNone', {
+          user_name: user.user_name
+        }));
+      }
+    }).catch(function (data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
+  }
+
+  function addUserRoles(clusterName, newRole, user) {
+    return Cluster.createPrivileges(
+      {
+        clusterId: clusterName
+      },
+      [{
+        PrivilegeInfo: {
+          permission_name: newRole.permission_name,
+          principal_name: user.user_name,
+          principal_type: 'USER'
+        }
+      }]
+    ).then(function () {
+      Alert.success($t('users.alerts.roleChanged', {
+        name: user.user_name,
+        role: newRole.permission_label
+      }));
+    }).catch(function (data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
+  }
+
+  function loadUserInfo() {
+    return User.getWithRoles($routeParams.id).then(function (data) {
+      $scope.user = User.makeUser(data.data).Users;
+      $scope.isCurrentUser = $scope.user.user_name === Auth.getCurrentUser();
+      $scope.editingGroupsList = angular.copy($scope.user.groups);
+      parsePrivileges(data.data.privileges);
+      var clusterRole = $scope.user.roles[0];
+      $scope.currentRole = clusterRole || nonRole;
+      $scope.originalRole = clusterRole || nonRole;
+      $scope.dataLoaded = true;
+    });
+  }
+
+  function parsePrivileges(rawPrivileges) {
+    var privileges = {
+      clusters: {},
+      views: {}
+    };
+    angular.forEach(rawPrivileges, function (privilege) {
+      privilege = privilege.PrivilegeInfo;
+      if (privilege.type === 'CLUSTER') {
+        // This is cluster
+        if (privileges.clusters[privilege.cluster_name]) {
+          var preIndex = Cluster.orderedRoles.indexOf(privileges.clusters[privilege.cluster_name].permission_name);
+          var curIndex = Cluster.orderedRoles.indexOf(privilege.permission_name);
+          // set more powerful role
+          if (curIndex < preIndex) {
             privileges.clusters[privilege.cluster_name] = privilege;
           }
-        } else if ( privilege.type === 'VIEW'){
-          privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || { privileges:[]};
-          privileges.views[privilege.instance_name].version = privilege.version;
-          privileges.views[privilege.instance_name].view_name = privilege.view_name;
-          privileges.views[privilege.instance_name].privilege_id = privilege.privilege_id;
-          if (privileges.views[privilege.instance_name].privileges.indexOf(privilege.permission_label) == -1) {
-            privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
-          }
+        } else {
+          privileges.clusters[privilege.cluster_name] = privilege;
         }
-      });
+      } else if (privilege.type === 'VIEW') {
+        privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || {
+          privileges: [],
+          version: privilege.version,
+          view_name: privilege.view_name,
+          privilege_id: privilege.privilege_id
+        };
+        if (privileges.views[privilege.instance_name].privileges.indexOf(privilege.permission_label) === -1) {
+          privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
+        }
+      }
+    });
 
-      $scope.privileges = data.data.items.length ? privileges : null;
-      $scope.noClusterPriv = $.isEmptyObject(privileges.clusters);
-      $scope.noViewPriv = $.isEmptyObject(privileges.views);
-      $scope.hidePrivileges = $scope.noClusterPriv && $scope.noViewPriv;
-      $scope.dataLoaded = true;
+    $scope.privilegesView = privileges;
+    $scope.noClusterPriv = $.isEmptyObject(privileges.clusters);
+    $scope.noViewPriv = $.isEmptyObject(privileges.views);
+    $scope.hidePrivileges = $scope.noClusterPriv && $scope.noViewPriv;
+  }
 
-    }).catch(function(data) {
-      Alert.error($t('common.alerts.cannotLoadPrivileges'), data.data.message);
+  function loadRoles() {
+    return Cluster.getRoleOptions().then(function (data) {
+      $scope.roleOptions = data;
     });
   }
-  loadPrivileges();
+
+  loadRoles().finally(loadUserInfo);
+
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
index e9ec6ab..cb25606 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
@@ -18,6 +18,6 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('UserManagementCtrl', ['$scope', function($scope) {
-  $scope.activeTab = 'USERS';
+.controller('UserManagementCtrl', ['$scope', '$routeParams', function($scope, $routeParams) {
+  $scope.activeTab = $routeParams.tab === 'groups' ? 'GROUPS' : 'USERS';
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
index abe1780..00bf9c3 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
@@ -44,14 +44,7 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
   };
   $scope.isNotEmptyFilter = true;
 
-  $scope.pageChanged = function() {
-    $scope.loadUsers();
-  };
-  $scope.usersPerPageChanges = function() {
-    $scope.resetPagination();
-  };
-
-  $scope.loadUsers = function(){
+  function loadUsers() {
     $scope.isLoading = true;
     User.list({
       currentPage: $scope.currentPage,
@@ -59,29 +52,37 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
       searchString: $scope.filters.name,
       user_type: $scope.filters.type.value,
       active: $scope.filters.status.value
-    }).then(function(data) {
-      $scope.isLoading = false;
+    }).then(function (data) {
       $scope.totalUsers = data.data.itemTotal;
       $scope.users = data.data.items.map(User.makeUser);
       $scope.tableInfo.showed = data.data.items.length;
       $scope.tableInfo.total = data.data.itemTotal;
+    }).finally(function () {
+      $scope.isLoading = false;
     });
+  }
+
+  $scope.pageChanged = function () {
+    loadUsers();
+  };
+  $scope.usersPerPageChanges = function () {
+    $scope.resetPagination();
   };
 
-  $scope.resetPagination = function() {
+  $scope.resetPagination = function () {
     $scope.currentPage = 1;
-    $scope.loadUsers();
+    loadUsers();
   };
 
   $scope.activeFilterOptions = [
     {label: $t('common.all'), value: '*'},
     {label: $t('users.active'), value: true},
-    {label: $t('users.inactive'), value:false}
+    {label: $t('users.inactive'), value: false}
   ];
   $scope.filters.status = $scope.activeFilterOptions[0];
 
-  $scope.typeFilterOptions = [{ label: $t('common.all'), value: '*'}]
-    .concat(Object.keys(UserConstants.TYPES).map(function(key) {
+  $scope.typeFilterOptions = [{label: $t('common.all'), value: '*'}]
+    .concat(Object.keys(UserConstants.TYPES).map(function (key) {
       return {
         label: $t(UserConstants.TYPES[key].LABEL_KEY),
         value: UserConstants.TYPES[key].VALUE
@@ -97,8 +98,6 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
     $scope.resetPagination();
   };
 
-  $scope.loadUsers();
-
   $scope.$watch(
     function (scope) {
       return Boolean(scope.filters.name || (scope.filters.status && scope.filters.status.value !== '*')
@@ -109,12 +108,12 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
     }
   );
 
-  $rootScope.$watch(function(scope) {
+  $rootScope.$watch(function (scope) {
     return scope.LDAPSynced;
-  }, function(LDAPSynced) {
-    if(LDAPSynced === true){
+  }, function (LDAPSynced) {
+    if (LDAPSynced === true) {
       $rootScope.LDAPSynced = false;
-      $scope.loadUsers();
+      loadUsers();
     }
   });
 
@@ -125,10 +124,10 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
       backdrop: 'static'
     });
 
-    modalInstance.result.finally($scope.loadUsers);
+    modalInstance.result.finally(loadUsers);
   };
 
-  $scope.deleteUser = function(user) {
+  $scope.deleteUser = function (user) {
     ConfirmationModal.show(
       $t('common.delete', {
         term: $t('common.user')
@@ -137,15 +136,15 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
         instanceType: $t('common.user').toLowerCase(),
         instanceName: '"' + user.user_name + '"'
       })
-    ).then(function() {
+    ).then(function () {
       Cluster.getPrivilegesForResource({
-        nameFilter : user.user_name,
-        typeFilter : {value: 'USER'}
-      }).then(function(data) {
+        nameFilter: user.user_name,
+        typeFilter: {value: 'USER'}
+      }).then(function (data) {
         var clusterPrivilegesIds = [];
         var viewsPrivileges = [];
         if (data.items && data.items.length) {
-          angular.forEach(data.items[0].privileges, function(privilege) {
+          angular.forEach(data.items[0].privileges, function (privilege) {
             if (privilege.PrivilegeInfo.principal_type === 'USER') {
               if (privilege.PrivilegeInfo.type === 'VIEW') {
                 viewsPrivileges.push({
@@ -160,19 +159,19 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
             }
           });
         }
-        User.delete(user.user_name).then(function() {
+        User.delete(user.user_name).then(function () {
           if (clusterPrivilegesIds.length) {
-            Cluster.getAllClusters().then(function (clusters) {
-              var clusterName = clusters[0].Clusters.cluster_name;
-              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
-            });
+            Cluster.deleteMultiplePrivileges($rootScope.cluster.Clusters.cluster_name, clusterPrivilegesIds);
           }
-          angular.forEach(viewsPrivileges, function(privilege) {
+          angular.forEach(viewsPrivileges, function (privilege) {
             View.deletePrivilege(privilege);
           });
-          $scope.loadUsers();
+          loadUsers();
         });
       });
     });
   };
+
+  loadUsers();
+
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
index de3968d..4a13e02 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
@@ -303,7 +303,7 @@ angular.module('ambariAdminConsole')
     'users.inactive': 'Inactive',
     'users.status': 'Status',
     'users.password': 'Password',
-    'users.role': 'Add roles for this user (Cluster Operator/Service Admin)',
+    'users.role': 'Add roles for this user',
     'users.confirmPassword': 'Confirm Password',
     'users.passwordConfirmation': 'Password сonfirmation',
     'users.isAmbariAdmin': 'Is this user an Ambari Admin?',
@@ -337,7 +337,7 @@ angular.module('ambariAdminConsole')
     'users.alerts.wrongPassword': 'Password must match!',
     'users.alerts.usernameRequired': 'Username Required',
     'users.alerts.cannotChange': 'Cannot Change {{term}}',
-    'users.alerts.userCreated': 'Created user <a href="#/users/{{encUserName}}">{{userName}}</a>',
+    'users.alerts.userCreated': 'Created user <a href="#/users/{{encUserName}}/edit">{{userName}}</a>',
     'users.alerts.userCreationError': 'User creation error',
     'users.alerts.removeUserError': 'Removing from group error',
     'users.alerts.cannotAddUser': 'Cannot add user to group',
@@ -373,8 +373,6 @@ angular.module('ambariAdminConsole')
     'versions.installOn': 'Install on...',
 
     'versions.register.title': 'Register Version',
-    'versions.add.title': 'Add Version',
-
     'versions.register.error.header': 'Unable to Register',
     'versions.register.error.body': 'You are attempting to register a version with a Base URL that is already in use with an existing registered version. You *must* review your Base URLs and confirm they are unique for the version you are trying to register.',
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
index 0f9b582..30ef91a 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
@@ -18,7 +18,11 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.factory('Cluster', ['$http', '$q', 'Settings', function($http, $q, Settings) {
+.factory('Cluster', ['$http', '$q', 'Settings', '$translate', function($http, $q, Settings, $translate) {
+  var $t = $translate.instant;
+  var permissions = null;
+  var rolesWithAuthorizations = null;
+
   return {
     repoStatusCache : {},
 
@@ -34,6 +38,13 @@ angular.module('ambariAdminConsole')
 
     ineditableRoles : ['VIEW.USER', 'AMBARI.ADMINISTRATOR'],
 
+    sortRoles: function(roles) {
+      var orderedRoles = ['AMBARI.ADMINISTRATOR'].concat(this.orderedRoles);
+      return roles.sort(function(a, b) {
+        return orderedRoles.indexOf(a.permission_name) - orderedRoles.indexOf(b.permission_name);
+      });
+    },
+
     getAllClusters: function() {
       var deferred = $q.defer();
       $http.get(Settings.baseUrl + '/clusters?fields=Clusters/cluster_id', {mock: 'cluster/clusters.json'})
@@ -120,22 +131,48 @@ angular.module('ambariAdminConsole')
 
       return deferred.promise;
     },
+    getRoleOptions: function () {
+      var roleOptions = [];
+      var deferred = $q.defer();
+      var localDeferred = $q.defer();
+      var promise = permissions ? localDeferred.promise : this.getPermissions();
+
+      localDeferred.resolve(permissions);
+      promise.then(function(data) {
+        permissions = data;
+        roleOptions = data.map(function(item) {
+          return item.PermissionInfo;
+        });
+        roleOptions.unshift({
+          permission_name: 'NONE',
+          permission_label: $t('users.roles.none')
+        });
+      }).finally(function() {
+        deferred.resolve(roleOptions);
+      });
+      return deferred.promise;
+    },
     getRolesWithAuthorizations: function() {
-      var self = this;
       var deferred = $q.defer();
-      $http({
-        method: 'GET',
-        url: Settings.baseUrl + '/permissions?PermissionInfo/resource_name.in(CLUSTER,AMBARI)',
-        mock: 'permission/permissions.json',
-        params: {
-          fields: 'PermissionInfo/*,authorizations/AuthorizationInfo/*'
-        }
-      })
-        .success(function(data) {
-          deferred.resolve(data.items);
+      if (rolesWithAuthorizations) {
+        deferred.resolve(rolesWithAuthorizations);
+      } else {
+        $http({
+          method: 'GET',
+          url: Settings.baseUrl + '/permissions?PermissionInfo/resource_name.in(CLUSTER,AMBARI)',
+          mock: 'permission/permissions.json',
+          params: {
+            fields: 'PermissionInfo/*,authorizations/AuthorizationInfo/*'
+          }
         })
-        .catch(function(data) {
-          deferred.reject(data); });
+          .success(function (data) {
+            rolesWithAuthorizations = data.items;
+            deferred.resolve(data.items);
+          })
+          .catch(function (data) {
+            deferred.reject(data);
+          });
+      }
 
       return deferred.promise;
     },
@@ -159,31 +196,6 @@ angular.module('ambariAdminConsole')
 
       return deferred.promise;
     },
-    getPrivilegesWithFilters: function(params) {
-      var deferred = $q.defer();
-      var isUser = params.typeFilter.value == 'USER';
-      var endpoint = isUser? '/users' : '/groups';
-      var nameURL = isUser? '&Users/user_name.matches(.*' : '&Groups/group_name.matches(.*';
-      var nameFilter = params.nameFilter? nameURL + params.nameFilter + '.*)' : '';
-      var roleFilter = params.roleFilter.value? '&privileges/PrivilegeInfo/permission_name.matches(.*' + params.roleFilter.value + '.*)' : '';
-      $http({
-        method: 'GET',
-        url: Settings.baseUrl + endpoint + '?'
-        + 'fields=privileges/PrivilegeInfo/*'
-        + nameFilter
-        + roleFilter
-        + '&from=' + (params.currentPage - 1) * params.usersPerPage
-        + '&page_size=' + params.usersPerPage
-      })
-      .success(function(data) {
-        deferred.resolve(data);
-      })
-      .catch(function(data) {
-        deferred.reject(data);
-      });
-
-      return deferred.promise;
-    },
     getPrivilegesForResource: function(params) {
       var deferred = $q.defer();
       var isUser = (params.typeFilter.value == 'USER');

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js
index f52a7e5..0509e11 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js
@@ -18,49 +18,29 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.factory('Group', ['$http', '$q', 'Settings', 'GroupConstants', '$translate', function($http, $q, Settings, GroupConstants, $translate) {
+.factory('Group', ['$http', '$q', 'Settings', '$translate', 'Cluster', function($http, $q, Settings, $translate, Cluster) {
   var $t = $translate.instant;
-  function Group(item){
-    if(typeof item === 'string'){
-      this.group_name = item;
-    } else if(typeof item === 'object'){
-      angular.extend(this, item.Groups);
-      this.getMembers();
+  var types = {
+    LOCAL: {
+      VALUE: 'LOCAL',
+      LABEL_KEY: 'common.local'
+    },
+    PAM: {
+      VALUE: 'PAM',
+      LABEL_KEY: 'common.pam'
+    },
+    LDAP: {
+      VALUE: 'LDAP',
+      LABEL_KEY: 'common.ldap'
     }
-  }
+  };
 
-  Group.prototype.isLDAP = function() {
-    var deferred = $q.defer();
-    var self = this;
-    if( typeof this.ldap_group === 'boolean' ){
-      deferred.resolve(this.ldap_group)
-    } else {
-      $http({
-        method: 'GET',
-        url: Settings.baseUrl + '/groups/'+this.group_name
-      }).
-      success(function(data) {
-        self.ldap_group = data.Groups.ldap_group;
-        deferred.resolve(self.ldap_group);
-      });
+  function Group(item) {
+    if (typeof item === 'string') {
+      this.group_name = item;
+    } else if (typeof item === 'object') {
+      angular.extend(this, item.Groups);
     }
-
-    return deferred.promise;
-  }
-
-  Group.prototype.getGroupType = function() {
-    var deferred = $q.defer();
-    var self = this;
-    $http({
-      method: 'GET',
-      url: Settings.baseUrl + '/groups/'+this.group_name
-    }).
-    success(function(data) {
-      self.group_type = data.Groups.group_type;
-      deferred.resolve(self.group_type);
-    });
-
-    return deferred.promise;
   }
 
   Group.prototype.save = function() {
@@ -86,28 +66,6 @@ angular.module('ambariAdminConsole')
     return deferred.promise;
   };
 
-  Group.prototype.getMembers = function() {
-    var deferred = $q.defer();
-    var self = this;
-
-    $http({
-      method: 'GET',
-      url: Settings.baseUrl + '/groups/' + this.group_name + '/members'
-    })
-    .success(function(data) {
-      self.members = [];
-      angular.forEach(data.items, function(member) {
-        self.members.push(member.MemberInfo.user_name);
-      });
-      deferred.resolve(self.members);
-    })
-    .error(function(data) {
-      deferred.reject(data);
-    });
-
-    return deferred.promise;
-  };
-
   Group.prototype.saveMembers = function() {
     var self = this;
     var deferred = $q.defer();
@@ -132,27 +90,6 @@ angular.module('ambariAdminConsole')
       deferred.reject(data);
     });
     return deferred.promise;
-  }
-
-  Group.prototype.addMember = function(memberName) {
-    var deferred = $q.defer();
-
-    $http({
-      method: 'POST',
-      url: Settings.baseUrl + '/groups/' + this.group_name + '/members' + '/'+ encodeURIComponent(member.user_name)
-    })
-    .success(function(data) {
-      deferred.resolve(data)
-    })
-    .error(function(data) {
-      deferred.reject(data);
-    });
-
-    return deferred.promise;
-  };
-
-  Group.prototype.removeMember = function(memberId) {
-    return $http.delete(Settings.baseUrl + '/groups/'+this.group_name+'/members/'+memberId);
   };
 
   Group.removeMemberFromGroup = function(groupName, memberName) {
@@ -174,14 +111,8 @@ angular.module('ambariAdminConsole')
       + (params.group_type === '*' ? '' : '&Groups/group_type=' + params.group_type)
     )
     .success(function(data) {
-      var groups = [];
-      if(Array.isArray(data.items)){
-        angular.forEach(data.items, function(item) {
-          groups.push(new Group(item));
-        });
-      }
-      groups.itemTotal = data.itemTotal;
-      deferred.resolve(groups);
+      data.items.itemTotal = data.itemTotal;
+      deferred.resolve(data.items);
     })
     .error(function(data) {
       deferred.reject(data);
@@ -204,6 +135,23 @@ angular.module('ambariAdminConsole')
     });
   };
 
+  Group.get = function (group_name) {
+    var deferred = $q.defer();
+    $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/groups/' + group_name +
+      '?fields=Groups,privileges/PrivilegeInfo/*,members/MemberInfo'
+    }).success(function (data) {
+      deferred.resolve(Group.makeGroup(data));
+    });
+
+    return deferred.promise;
+  };
+
+  Group.getTypes = function () {
+    return types;
+  };
+
   /**
      * Generate group info to display by response data from API.
      * Generally this is a single point to manage all required and useful data
@@ -212,9 +160,19 @@ angular.module('ambariAdminConsole')
      * @param {Object} group - object from API response
      * @returns {Object}
      */
-   Group.makeGroup = function(group) {
-      group.groupTypeName = $t(GroupConstants.TYPES[group.group_type].LABEL_KEY);
-      return group;
+  Group.makeGroup = function(data) {
+    var group = new Group(data.Groups.group_name);
+    group.groupTypeName = $t(types[data.Groups.group_type].LABEL_KEY);
+    group.group_type = data.Groups.group_type;
+    group.ldap_group = data.Groups.ldap_group;
+    group.privileges = data.privileges;
+    group.members = data.members;
+    group.roles = Cluster.sortRoles(data.privileges.filter(function(item) {
+      return item.PrivilegeInfo.type === 'CLUSTER' || item.PrivilegeInfo.type === 'AMBARI';
+    }).map(function(item) {
+      return item.PrivilegeInfo;
+    }));
+    return group;
   };
 
   return Group;

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GroupConstants.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GroupConstants.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GroupConstants.js
deleted file mode 100644
index 42e8d73..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GroupConstants.js
+++ /dev/null
@@ -1,38 +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.
- */
-'use strict';
-
-angular.module('ambariAdminConsole').constant('GroupConstants', {
-  /**
-   * Available group_types 'values' and 'labels' map.
-   */
-  TYPES: {
-    LOCAL: {
-      VALUE: 'LOCAL',
-      LABEL_KEY: 'common.local'
-    },
-    PAM: {
-      VALUE: 'PAM',
-      LABEL_KEY: 'common.pam'
-    },
-    LDAP: {
-      VALUE: 'LDAP',
-      LABEL_KEY: 'common.ldap'
-    }
-  }
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RoleDetailsModal.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RoleDetailsModal.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RoleDetailsModal.js
index 06019c2..7b01116 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RoleDetailsModal.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RoleDetailsModal.js
@@ -22,11 +22,10 @@ angular.module('ambariAdminConsole')
   return {
     show: function(roles) {
       roles = roles.map(function(role) {
-        role.authorizations = role.authorizations.map(function(authorization) {
+        var r = role.PermissionInfo;
+        r.authorizations = role.authorizations.map(function(authorization) {
           return authorization.AuthorizationInfo;
         });
-        var r = role.PermissionInfo;
-        r.authorizations = role.authorizations;
         return r;
       });
       var modalInstance = $modal.open({

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
index 47015d1..7932d9b 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
@@ -18,7 +18,7 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-  .factory('User', ['Restangular', '$http', 'Settings', 'UserConstants', '$translate', function(Restangular, $http, Settings, UserConstants, $translate) {
+.factory('User', ['Restangular', '$http', 'Settings', 'UserConstants', '$translate', 'Cluster', function(Restangular, $http, Settings, UserConstants, $translate, Cluster) {
   Restangular.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
     var extractedData;
     if(operation === 'getList'){
@@ -31,14 +31,13 @@ angular.module('ambariAdminConsole')
     return extractedData;
   });
   var $t = $translate.instant;
-  var Users = Restangular.all('users');
 
   return {
     list: function(params) {
       return $http.get(
         Settings.baseUrl + '/users/?'
         + 'Users/user_name.matches(.*'+params.searchString+'.*)'
-        + '&fields=*'
+        + '&fields=privileges/PrivilegeInfo/*,Users'
         + '&from=' + (params.currentPage-1)*params.usersPerPage
         + '&page_size=' + params.usersPerPage
         + (params.user_type === '*' ? '' : '&Users/user_type=' + params.user_type)
@@ -53,6 +52,12 @@ angular.module('ambariAdminConsole')
         + '&from=0&page_size=20'
       );
     },
+    getWithRoles: function(userId) {
+      return $http.get(
+        Settings.baseUrl + '/users/' + userId
+        + '?fields=privileges/PrivilegeInfo,Users'
+      );
+    },
     get: function(userId) {
       return Restangular.one('users', userId).get();
     },
@@ -97,7 +102,11 @@ angular.module('ambariAdminConsole')
       user.Users.encodedName = encodeURIComponent(user.Users.user_name);
       user.Users.userTypeName = $t(UserConstants.TYPES[user.Users.user_type].LABEL_KEY);
       user.Users.ldapUser = user.Users.user_type === UserConstants.TYPES.LDAP.VALUE;
-      user.Users.role = user.privileges.length ? user.privileges[0].PrivilegeInfo.privilege_id : null;
+      user.Users.roles = Cluster.sortRoles(user.privileges.filter(function(item) {
+        return item.PrivilegeInfo.type === 'CLUSTER' || item.PrivilegeInfo.type === 'AMBARI';
+      }).map(function(item) {
+        return item.PrivilegeInfo;
+      }));
 
       return user;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
index 91b2fb1..b4aa558 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
@@ -312,11 +312,6 @@ a.gotoinstance{
   font-size: 16px;
 }
 
-.user-edit-panel .ats-switch span.switch-right , .create-user-form .ats-switch span.switch-right, .enable-ldap .ats-switch span.switch-right {
-  background-color: #da4f49;
-  color: white;
-}
-
 .create-view-form, .register-version-form, .edit-version-form {
   padding-bottom: 50px;
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
index 77c94ac..3c9756e 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
@@ -28,3 +28,16 @@
 #user-management .groups-pane {
   margin-top: -35px;
 }
+
+#group-edit .roles-label,
+#user-edit .roles-label {
+  line-height: 30px;
+}
+
+#create-user-form .roles-label i,
+#create-group-form .roles-label i,
+#group-edit .roles-label i,
+#user-edit .roles-label i {
+  margin-right: -10px;
+  cursor: pointer;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
index 8bb6632..59d8acb 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
@@ -18,10 +18,7 @@
 
 <div class="users-pane">
   <div class="clearfix">
-    <ol class="breadcrumb pull-left">
-      <li class="active">{{'common.remoteClusters' | translate}}</li>
-    </ol>
-    <div class="pull-right top-margin-4">
+    <div class="pull-right">
       <a href="#/remoteClusters/create" class="btn btn-default">
         {{'views.registerRemoteCluster' | translate}}
       </a>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
index a411640..cf5c516 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
@@ -18,12 +18,9 @@
 
 <div id="stack-versions">
   <div class="clearfix">
-    <ol class="breadcrumb pull-left">
-      <li class="active">{{'common.versions' | translate}}</li>
-    </ol>
-    <div class="pull-right top-margin-4">
+    <div class="pull-right">
       <a href="#/stackVersions/create" class="btn btn-default">
-        {{'versions.add.title' | translate}}
+        {{'versions.register.title' | translate}}
       </a>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
index 90a1907..5656417 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
@@ -16,84 +16,107 @@
 * limitations under the License.
 -->
 
-<div class="clearfix">
-  <div class="pull-right">
-    <div ng-switch="group.group_type != 'LOCAL'">
-      <button
-        ng-switch-when="true"
-        class="btn disabled deletegroup-btn"
-        tooltip="{{'common.cannotDelete' | translate: '{term: constants.group}'}}">
-        {{'common.delete' | translate: '{term: constants.group}'}}
-      </button>
-      <button ng-switch-when="false" class="btn btn-danger deletegroup-btn" ng-click="deleteGroup(group)">
-        {{'common.delete' | translate: '{term: constants.group}'}}
-      </button>
+<div id="group-edit">
+  <div class="clearfix">
+    <ol class="breadcrumb pull-left">
+      <li><a href="#/userManagement?tab=groups">{{'common.groups' | translate}}</a></li>
+      <li class="active">{{group.group_name}}</li>
+    </ol>
+    <div class="pull-right">
+      <div ng-switch="group.group_type != 'LOCAL'">
+        <button
+          ng-switch-when="true"
+          class="btn disabled deletegroup-btn"
+          tooltip="{{'common.cannotDelete' | translate: '{term: constants.group}'}}">
+          {{'common.delete' | translate: '{term: constants.group}'}}
+        </button>
+        <button ng-switch-when="false" class="btn btn-danger deletegroup-btn" ng-click="deleteGroup(group)">
+          {{'common.delete' | translate: '{term: constants.group}'}}
+        </button>
+      </div>
     </div>
   </div>
-</div>
-<form class="form-horizontal group-edit" role="form" novalidate name="form" >
-  <div class="form-group">
-    <label class="col-sm-2 control-label">{{'common.type' | translate}}</label>
-    <div class="col-sm-10">
-      <label class="control-label">{{group.groupTypeName | translate}}</label>
+
+  <form class="form-horizontal" role="form" novalidate name="form" >
+    <div class="form-group">
+      <label class="col-sm-2 control-label">{{'common.type' | translate}}</label>
+      <div class="col-sm-10">
+        <label class="control-label">{{group.groupTypeName | translate}}</label>
+      </div>
     </div>
-  </div>
-  <div class="form-group">
-    <label class="col-sm-2 control-label">{{group.groupTypeName | translate}} {{'groups.members' | translate}}</label>
-    <div class="col-sm-10">
-      <editable-list items-source="group.editingUsers" resource-type="User" editable="group.group_type == 'LOCAL'"></editable-list>
+    <div class="form-group">
+      <label class="col-sm-2 control-label">{{group.groupTypeName | translate}} {{'groups.members' | translate}}</label>
+      <div class="col-sm-10">
+        <editable-list items-source="group.editingUsers" resource-type="User" editable="group.group_type == 'LOCAL'"></editable-list>
+      </div>
     </div>
-  </div>
-
-  <div class="form-group">
+    <div class="form-group">
+      <label for="role" class="col-sm-2 roles-label">
+        {{'groups.role' | translate}}
+        <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
+      </label>
+      <div class="col-sm-3">
+        <select class="form-control"
+                id="role"
+                name="role"
+                ng-change="updateRole()"
+                ng-options="item as item.permission_label for item in roleOptions track by item.permission_name"
+                ng-model="currentRole">
+        </select>
+      </div>
+    </div>
+    <div class="form-group">
       <label class="col-sm-2 control-label">{{'common.privileges' | translate}}</label>
       <div class="col-sm-10">
         <table class="table" ng-hide="hidePrivileges">
           <thead>
-            <tr>
-              <th>{{'common.cluster' | translate}}</th>
-              <th>{{'common.clusterRole' | translate}}</th>
-            </tr>
+          <tr>
+            <th>{{'common.cluster' | translate}}</th>
+            <th>{{'common.clusterRole' | translate}}</th>
+          </tr>
           </thead>
           <tbody>
-            <tr ng-repeat="(name, privilege) in privileges.clusters">
-              <td>
-                <span class="glyphicon glyphicon-cloud"></span> 
-                <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
-              </td>
-              <td>
-                <span tooltip="{{item}}" ng-repeat="item in privilege">{{item | translate}}{{$last ? '' : ', '}}</span>
-              </td>
-            </tr>
-            <tr>
-              <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
-            </tr>
+          <tr ng-repeat="(name, privilege) in privileges.clusters">
+            <td>
+              <span class="glyphicon glyphicon-cloud"></span>
+              <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
+            </td>
+            <td>
+              <span tooltip="{{item}}" ng-repeat="item in privilege">{{item | translate}}{{$last ? '' : ', '}}</span>
+            </td>
+          </tr>
+          <tr>
+            <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
+          </tr>
           </tbody>
           <thead class="view-permission-header">
-            <tr>
-              <th>{{'common.view' | translate}}</th>
-              <th>{{'common.viewPermissions' | translate}}</th>
-            </tr>
+          <tr>
+            <th>{{'common.view' | translate}}</th>
+            <th>{{'common.viewPermissions' | translate}}</th>
+          </tr>
           </thead>
           <tbody>
-            <tr ng-repeat="(name, privilege) in privileges.views">
-              <td>
-                <span class="glyphicon glyphicon-th"></span>
-                <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
-              </td>
-              <td>
-                <span tooltip="{{item}}" ng-repeat="item in privilege.privileges">{{item | translate}}{{$last ? '' : ', '}}</span>
-              </td>
-              <td>
-                <i class="fa fa-trash-o" aria-hidden="true" ng-click="removePrivilege(name, privilege);"></i>
-              </td>
-            </tr>
-            <tr>
-              <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
-            </tr>
+          <tr ng-repeat="(name, privilege) in privileges.views">
+            <td>
+              <span class="glyphicon glyphicon-th"></span>
+              <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
+            </td>
+            <td>
+              <span tooltip="{{item}}" ng-repeat="item in privilege.privileges">{{item | translate}}{{$last ? '' : ', '}}</span>
+            </td>
+            <td>
+              <i class="fa fa-trash-o" aria-hidden="true" ng-click="removeViewPrivilege(name, privilege);"></i>
+            </td>
+          </tr>
+          <tr>
+            <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
+          </tr>
           </tbody>
         </table>
-        <div class="alert alert-info hide-soft" ng-class="{'visible' : !privileges}">{{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.group.toLowerCase()}'}}</div>
+        <div class="alert alert-info" ng-show="hidePrivileges">
+          {{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.group.toLowerCase()}'}}
+        </div>
       </div>
     </div>
-</form>
+  </form>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
index 079eefb..8520fc2 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
@@ -19,10 +19,10 @@
 <div id="user-management">
   <ul class="nav nav-tabs">
     <li ng-class="{active: activeTab === 'USERS'}">
-      <a ng-click="activeTab = 'USERS'">{{'common.users' | translate}}</a>
+      <a href="#/userManagement?tab=users" >{{'common.users' | translate}}</a>
     </li>
     <li ng-class="{active: activeTab === 'GROUPS'}">
-      <a ng-click="activeTab = 'GROUPS'">{{'common.groups' | translate}}</a>
+      <a href="#/userManagement?tab=groups" >{{'common.groups' | translate}}</a>
     </li>
   </ul>
   <div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
index e0c1144..e11b478 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
@@ -60,17 +60,17 @@
     <div class="row">
       <div class="form-group col-sm-6"
            ng-class="{ 'has-error': form.groupCreateForm.role.$error.required && form.groupCreateForm.submitted }">
-        <label for="role" class="nowrap">
+        <label for="role" class="nowrap roles-label">
           {{'groups.role' | translate}}
-          <i class="fa fa-question-circle" aria-hidden="true"></i>
+          <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
         </label>
         <select
           class="form-control"
           id="role"
           name="role"
           ng-model="formData.role">
-          <option value="" disabled selected>{{'common.select' | translate}}</option>
-          <option ng-repeat="role in roleOptions" value="{{role.permission_id}}">{{role.permission_label}}</option>
+          <option value="" class="hide">{{'common.select' | translate}}</option>
+          <option ng-repeat="role in roleOptions" value="{{role.permission_name}}">{{role.permission_label}}</option>
         </select>
         <span class="help-block validation-block" ng-show='form.groupCreateForm.role.$error.required && form.groupCreateForm.submitted'>
           {{'common.alerts.fieldRequired' | translate}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
index 0af26eb..2a71102 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
@@ -100,9 +100,9 @@
     <div class="row">
       <div class="form-group col-sm-6"
            ng-class="{ 'has-error': form.userCreateForm.role.$error.required && form.userCreateForm.submitted }">
-        <label for="role" class="nowrap">
-          {{'users.role' | translate}}<span>&nbsp;*</span>&nbsp;
-          <i class="fa fa-question-circle" aria-hidden="true"></i>
+        <label for="role" class="nowrap roles-label">
+          {{'users.role' | translate}}<span>&nbsp;*</span>
+          <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
         </label>
         <select
           class="form-control"
@@ -110,8 +110,8 @@
           name="role"
           ng-model="formData.role"
           required>
-          <option value="" disabled selected>{{'common.select' | translate}}</option>
-          <option ng-repeat="role in roleOptions" value="{{role.permission_id}}">{{role.permission_label}}</option>
+          <option value="" class="hide">{{'common.select' | translate}}</option>
+          <option ng-repeat="role in roleOptions" value="{{role.permission_name}}">{{role.permission_label}}</option>
         </select>
         <span class="help-block validation-block" ng-show='form.userCreateForm.role.$error.required && form.userCreateForm.submitted'>
           {{'common.alerts.fieldRequired' | translate}}


[02/49] ambari git commit: AMBARI-22318 repositoryFile entity populating for wrong repository for RU (dgrinenko)

Posted by rl...@apache.org.
AMBARI-22318 repositoryFile entity populating for wrong repository for RU (dgrinenko)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 18c4af48c8f409fa083172df6b04e94d010d8410
Parents: 365c91e
Author: Dmytro Grinenko <ha...@apache.org>
Authored: Fri Nov 17 10:23:55 2017 +0200
Committer: Dmytro Grinenko <ha...@apache.org>
Committed: Fri Nov 17 10:23:55 2017 +0200

----------------------------------------------------------------------
 .../actionmanager/ExecutionCommandWrapper.java  |  35 +++
 .../ambari/server/agent/CommandRepository.java  |   2 +-
 .../controller/ActionExecutionContext.java      |   6 +-
 .../controller/AmbariActionExecutionHelper.java |  71 +----
 .../AmbariCustomCommandExecutionHelper.java     | 257 +--------------
 .../AmbariManagementControllerImpl.java         |  14 +-
 .../ClusterStackVersionResourceProvider.java    |  16 +-
 .../HostStackVersionResourceProvider.java       |   3 +-
 .../stack/upgrade/RepositoryVersionHelper.java  | 314 +++++++++++++++++--
 .../AmbariCustomCommandExecutionHelperTest.java |  13 +-
 .../AmbariManagementControllerTest.java         | 176 +++++------
 ...ClusterStackVersionResourceProviderTest.java |  51 ++-
 .../internal/UpgradeResourceProviderTest.java   |  12 +-
 .../apache/ambari/server/orm/OrmTestHelper.java |   4 +-
 14 files changed, 530 insertions(+), 444 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
index ff13d0b..a0c5f26 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
@@ -31,15 +31,19 @@ import org.apache.ambari.server.ClusterNotFoundException;
 import org.apache.ambari.server.RoleCommand;
 import org.apache.ambari.server.ServiceNotFoundException;
 import org.apache.ambari.server.agent.AgentCommand.AgentCommandType;
+import org.apache.ambari.server.agent.CommandRepository;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
+import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceInfo;
@@ -48,6 +52,7 @@ import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.UpgradeContext;
 import org.apache.ambari.server.state.UpgradeContext.UpgradeSummary;
 import org.apache.ambari.server.state.UpgradeContextFactory;
+import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -79,6 +84,9 @@ public class ExecutionCommandWrapper {
   @Inject
   private UpgradeContextFactory upgradeContextFactory;
 
+  @Inject
+  private RepositoryVersionHelper repoVersionHelper;
+
   /**
    * Used for injecting hooks and common-services into the command.
    */
@@ -215,9 +223,36 @@ public class ExecutionCommandWrapper {
       if (null != upgrade) {
         UpgradeContext upgradeContext = upgradeContextFactory.create(cluster, upgrade);
         UpgradeSummary upgradeSummary = upgradeContext.getUpgradeSummary();
+
         executionCommand.setUpgradeSummary(upgradeSummary);
       }
 
+      // setting repositoryFile
+      final Host host = cluster.getHost(executionCommand.getHostname());  // can be null on internal commands
+      final String serviceName = executionCommand.getServiceName(); // can be null on executing special RU tasks
+
+      if (null == executionCommand.getRepositoryFile() && null != host && null != serviceName) {
+        final CommandRepository commandRepository;
+        final Service service = cluster.getService(serviceName);
+        final String componentName = executionCommand.getComponentName();
+
+        try {
+
+          if (null != componentName) {
+            ServiceComponent serviceComponent = service.getServiceComponent(componentName);
+            commandRepository = repoVersionHelper.getCommandRepository(null, serviceComponent, host);
+          } else {
+            RepositoryVersionEntity repoVersion = service.getDesiredRepositoryVersion();
+            OperatingSystemEntity osEntity = repoVersionHelper.getOSEntityForHost(host, repoVersion);
+            commandRepository = repoVersionHelper.getCommandRepository(repoVersion, osEntity);
+          }
+          executionCommand.setRepositoryFile(commandRepository);
+
+        } catch (SystemException e) {
+          throw new RuntimeException(e);
+        }
+      }
+
     } catch (ClusterNotFoundException cnfe) {
       // it's possible that there are commands without clusters; in such cases,
       // just return the de-serialized command and don't try to read configs

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
index a70326e..449d2d5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
@@ -51,7 +51,7 @@ public class CommandRepository {
   private String m_repoFileName;
 
   @SerializedName("feature")
-  private CommandRepositoryFeature feature = new CommandRepositoryFeature();
+  private final CommandRepositoryFeature feature = new CommandRepositoryFeature();
 
   /**
    * Provides {@link CommandRepository} feature

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/main/java/org/apache/ambari/server/controller/ActionExecutionContext.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ActionExecutionContext.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ActionExecutionContext.java
index 5d71869..e94defc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ActionExecutionContext.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ActionExecutionContext.java
@@ -262,12 +262,12 @@ public class ActionExecutionContext {
   }
 
   /**
+   *
    * Interface that allows a final attempt to setting values on an {@link ExecutionCommand}
-   * @author ncole
    *
    */
-  public static interface ExecutionCommandVisitor {
-    public void visit(ExecutionCommand command);
+  public interface ExecutionCommandVisitor {
+    void visit(ExecutionCommand command);
   }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
index 0a43732..23c2297 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
@@ -22,11 +22,8 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AGENT_STA
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AGENT_STACK_RETRY_ON_UNAVAILABILITY;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMMAND_TIMEOUT;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMPONENT_CATEGORY;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.REPO_INFO;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT_TYPE;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
 
 import java.util.HashSet;
 import java.util.List;
@@ -46,9 +43,9 @@ import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.internal.RequestResourceFilter;
+import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.customactions.ActionDefinition;
 import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -58,6 +55,7 @@ import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpInProgressEvent;
 import org.apache.ambari.server.utils.SecretReference;
 import org.apache.ambari.server.utils.StageUtils;
@@ -65,8 +63,6 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -78,6 +74,7 @@ public class AmbariActionExecutionHelper {
   private final static Logger LOG =
       LoggerFactory.getLogger(AmbariActionExecutionHelper.class);
   private static final String TYPE_PYTHON = "PYTHON";
+  private static final String ACTION_FILE_EXTENSION = "py";
   private static final String ACTION_UPDATE_REPO = "update_repo";
   private static final String SUCCESS_FACTOR_PARAMETER = "success_factor";
 
@@ -85,15 +82,23 @@ public class AmbariActionExecutionHelper {
 
   @Inject
   private Clusters clusters;
+
   @Inject
   private AmbariManagementController managementController;
+
   @Inject
   private AmbariMetaInfo ambariMetaInfo;
+
   @Inject
   private MaintenanceStateHelper maintenanceStateHelper;
+
   @Inject
   private Configuration configs;
 
+  @Inject
+  private RepositoryVersionHelper repoVersionHelper;
+
+
   /**
    * Validates the request to execute an action.
    * @param actionRequest
@@ -417,7 +422,7 @@ public class AmbariActionExecutionHelper {
         commandParams.put(KeyNames.LOG_OUTPUT, requestParams.get(KeyNames.LOG_OUTPUT));
       }
 
-      commandParams.put(SCRIPT, actionName + ".py");
+      commandParams.put(SCRIPT, actionName + "." + ACTION_FILE_EXTENSION);
       commandParams.put(SCRIPT_TYPE, TYPE_PYTHON);
       StageUtils.useAmbariJdkInCommandParams(commandParams, configs);
 
@@ -465,10 +470,10 @@ public class AmbariActionExecutionHelper {
 
       if (StringUtils.isNotBlank(serviceName)) {
         Service service = cluster.getService(serviceName);
-        addRepoInfoToHostLevelParams(actionContext, service.getDesiredRepositoryVersion(),
+        repoVersionHelper.addRepoInfoToHostLevelParams(cluster, actionContext, service.getDesiredRepositoryVersion(),
             hostLevelParams, hostName);
       } else {
-        addRepoInfoToHostLevelParams(actionContext, null, hostLevelParams, hostName);
+        repoVersionHelper.addRepoInfoToHostLevelParams(cluster, actionContext, null, hostLevelParams, hostName);
       }
 
 
@@ -526,52 +531,4 @@ public class AmbariActionExecutionHelper {
     }
   }
 
-  /*
-  * This method builds and adds repo info
-  * to hostLevelParams of action
-  *
-  * */
-
-  private void addRepoInfoToHostLevelParams(ActionExecutionContext actionContext,
-      RepositoryVersionEntity repositoryVersion, Map<String, String> hostLevelParams,
-      String hostName) throws AmbariException {
-
-    // if the repo is null, see if any values from the context should go on the
-    // host params and then return
-    if (null == repositoryVersion) {
-      // see if the action context has a repository set to use for the command
-      if (null != actionContext.getRepositoryVersion()) {
-        StackId stackId = actionContext.getRepositoryVersion().getStackId();
-        hostLevelParams.put(STACK_NAME, stackId.getStackName());
-        hostLevelParams.put(STACK_VERSION, stackId.getStackVersion());
-      }
-
-      return;
-    } else {
-      StackId stackId = repositoryVersion.getStackId();
-      hostLevelParams.put(STACK_NAME, stackId.getStackName());
-      hostLevelParams.put(STACK_VERSION, stackId.getStackVersion());
-    }
-
-    JsonObject rootJsonObject = new JsonObject();
-    JsonArray repositories = new JsonArray();
-
-    String hostOsFamily = clusters.getHost(hostName).getOsFamily();
-    for (OperatingSystemEntity operatingSystemEntity : repositoryVersion.getOperatingSystems()) {
-      // ostype in OperatingSystemEntity it's os family. That should be fixed
-      // in OperatingSystemEntity.
-      if (operatingSystemEntity.getOsType().equals(hostOsFamily)) {
-        for (RepositoryEntity repositoryEntity : operatingSystemEntity.getRepositories()) {
-          JsonObject repositoryInfo = new JsonObject();
-          repositoryInfo.addProperty("base_url", repositoryEntity.getBaseUrl());
-          repositoryInfo.addProperty("repo_name", repositoryEntity.getName());
-          repositoryInfo.addProperty("repo_id", repositoryEntity.getRepositoryId());
-
-          repositories.add(repositoryInfo);
-        }
-        rootJsonObject.add("repositories", repositories);
-      }
-    }
-    hostLevelParams.put(REPO_INFO, rootJsonObject.toString());
-  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
index dc6bbb7..9f95f7a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
@@ -53,8 +53,6 @@ import java.util.Random;
 import java.util.Set;
 import java.util.TreeMap;
 
-import org.apache.ambari.annotations.Experimental;
-import org.apache.ambari.annotations.ExperimentalFeature;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.Role;
 import org.apache.ambari.server.RoleCommand;
@@ -62,7 +60,6 @@ import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.agent.AgentCommand.AgentCommandType;
-import org.apache.ambari.server.agent.CommandRepository;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
@@ -70,11 +67,9 @@ import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.internal.RequestOperationLevel;
 import org.apache.ambari.server.controller.internal.RequestResourceFilter;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.metadata.ActionMetadata;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.CommandScriptDefinition;
@@ -90,7 +85,6 @@ import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.PropertyInfo.PropertyType;
 import org.apache.ambari.server.state.RefreshCommandConfiguration;
-import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
@@ -99,6 +93,7 @@ import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpInProgressEvent;
 import org.apache.ambari.server.utils.StageUtils;
 import org.apache.commons.lang.StringUtils;
@@ -106,11 +101,7 @@ import org.apache.commons.lang.math.NumberUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Function;
 import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -175,6 +166,9 @@ public class AmbariCustomCommandExecutionHelper {
   @Inject
   private HostRoleCommandDAO hostRoleCommandDAO;
 
+  @Inject
+  private RepositoryVersionHelper repoVersionHelper;
+
   private Map<String, Map<String, Map<String, String>>> configCredentialsForService = new HashMap<>();
 
   protected static final String SERVICE_CHECK_COMMAND_NAME = "SERVICE_CHECK";
@@ -413,7 +407,11 @@ public class AmbariCustomCommandExecutionHelper {
       hostLevelParams.put(CUSTOM_COMMAND, commandName);
 
       // Set parameters required for re-installing clients on restart
-      hostLevelParams.put(REPO_INFO, getRepoInfo(cluster, component, host));
+      try {
+        hostLevelParams.put(REPO_INFO, repoVersionHelper.getRepoInfo(cluster, component, host));
+      } catch (SystemException e) {
+        throw new AmbariException("", e);
+      }
       hostLevelParams.put(STACK_NAME, stackId.getStackName());
       hostLevelParams.put(STACK_VERSION, stackId.getStackVersion());
 
@@ -521,8 +519,6 @@ public class AmbariCustomCommandExecutionHelper {
       execCmd.setCommandParams(commandParams);
       execCmd.setRoleParams(roleParams);
 
-      execCmd.setRepositoryFile(getCommandRepository(cluster, component, host));
-
       // perform any server side command related logic - eg - set desired states on restart
       applyCustomCommandBackendLogic(cluster, serviceName, componentName, commandName, hostName);
     }
@@ -848,7 +844,8 @@ public class AmbariCustomCommandExecutionHelper {
    * calls into the implementation of a custom command
    */
   private void addDecommissionAction(final ActionExecutionContext actionExecutionContext,
-      final RequestResourceFilter resourceFilter, Stage stage, ExecuteCommandJson executeCommandJson) throws AmbariException {
+      final RequestResourceFilter resourceFilter, Stage stage, ExecuteCommandJson executeCommandJson)
+    throws AmbariException {
 
     String clusterName = actionExecutionContext.getClusterName();
     final Cluster cluster = clusters.getCluster(clusterName);
@@ -1145,7 +1142,8 @@ public class AmbariCustomCommandExecutionHelper {
    * @throws AmbariException if the commands can not be added
    */
   public void addExecutionCommandsToStage(ActionExecutionContext actionExecutionContext,
-      Stage stage, Map<String, String> requestParams, ExecuteCommandJson executeCommandJson) throws AmbariException {
+      Stage stage, Map<String, String> requestParams, ExecuteCommandJson executeCommandJson)
+    throws AmbariException {
 
     List<RequestResourceFilter> resourceFilters = actionExecutionContext.getResourceFilters();
 
@@ -1209,216 +1207,6 @@ public class AmbariCustomCommandExecutionHelper {
     }
   }
 
-  /**
-   * Get repository info given a cluster and host.
-   *
-   * @param cluster  the cluster
-   * @param host     the host
-   *
-   * @return the repo info
-   *
-   * @deprecated use {@link #getCommandRepository(Cluster, ServiceComponent, Host)} instead.
-   * @throws AmbariException if the repository information can not be obtained
-   */
-  @Deprecated
-  public String getRepoInfo(Cluster cluster, ServiceComponent component, Host host) throws AmbariException {
-
-    Function<List<RepositoryInfo>, JsonArray> function = new Function<List<RepositoryInfo>, JsonArray>() {
-      @Override
-      public JsonArray apply(List<RepositoryInfo> input) {
-        return null == input ? null : (JsonArray) gson.toJsonTree(input);
-      }
-    };
-
-    final JsonArray gsonList = getBaseUrls(cluster, component, host, function);
-
-    if (null == gsonList) {
-      return "";
-    }
-
-    BaseUrlUpdater<JsonArray> updater = new BaseUrlUpdater<JsonArray>(gsonList) {
-      @Override
-      public JsonArray apply(final RepositoryVersionEntity rve) {
-
-        JsonArray result = new JsonArray();
-
-        for (JsonElement e : gsonList) {
-          JsonObject obj = e.getAsJsonObject();
-
-          String repoId = obj.has("repoId") ? obj.get("repoId").getAsString() : null;
-          String repoName = obj.has("repoName") ? obj.get("repoName").getAsString() : null;
-          String baseUrl = obj.has("baseUrl") ? obj.get("baseUrl").getAsString() : null;
-          String osType = obj.has("osType") ? obj.get("osType").getAsString() : null;
-
-          if (null == repoId || null == baseUrl || null == osType || null == repoName) {
-            continue;
-          }
-
-          for (OperatingSystemEntity ose : rve.getOperatingSystems()) {
-            if (ose.getOsType().equals(osType) && ose.isAmbariManagedRepos()) {
-              for (RepositoryEntity re : ose.getRepositories()) {
-                if (re.getName().equals(repoName) &&
-                    !re.getBaseUrl().equals(baseUrl)) {
-                  obj.addProperty("baseUrl", re.getBaseUrl());
-                }
-              }
-            result.add(e);
-            }
-          }
-        }
-
-        return result;
-      }
-    };
-
-    return updateBaseUrls(cluster, component, updater).toString();
-  }
-
-  /**
-   * Builds repository information for inclusion in a command.  This replaces escaping json on
-   * a command.
-   *
-   * @param cluster the cluster
-   * @param host    the host
-   * @return  the command repository
-   * @throws AmbariException
-   */
-  @Experimental(feature=ExperimentalFeature.PATCH_UPGRADES)
-  public CommandRepository getCommandRepository(final Cluster cluster, ServiceComponent component, final Host host) throws AmbariException {
-
-    final CommandRepository command = new CommandRepository();
-    boolean sysPreppedHost = configs.areHostsSysPrepped().equalsIgnoreCase("true");
-    StackId stackId = component.getDesiredStackId();
-    command.setRepositories(Collections.<RepositoryInfo>emptyList());
-    command.setStackName(stackId.getStackName());
-    command.getFeature().setPreInstalled(configs.areHostsSysPrepped());
-    command.getFeature().setIsScoped(!sysPreppedHost);
-
-    final BaseUrlUpdater<Void> updater = new BaseUrlUpdater<Void>(null) {
-      @Override
-      public Void apply(RepositoryVersionEntity rve) {
-        command.setRepositoryVersionId(rve.getId());
-        command.setRepositoryVersion(rve.getVersion());
-        command.setResolved(rve.isResolved());
-        command.setStackName(rve.getStackName());
-
-        // !!! a repository version entity has all the repos worked out.  We shouldn't use
-        // the stack at all.
-        for (OperatingSystemEntity osEntity : rve.getOperatingSystems()) {
-          String osEntityFamily = os_family.find(osEntity.getOsType());
-          if (osEntityFamily.equals(host.getOsFamily())) {
-            command.setRepositories(osEntity.getOsType(), osEntity.getRepositories());
-
-            if (!osEntity.isAmbariManagedRepos()) {
-              command.setNonManaged();
-            } else {
-              if (rve.isLegacy()){
-                command.setLegacyRepoId(rve.getVersion());
-                command.setLegacyRepoFileName(rve.getStackName(), rve.getVersion());
-                command.getFeature().setIsScoped(false);
-              } else {
-                command.setRepoFileName(rve.getStackName(), rve.getId());
-                command.setUniqueSuffix(String.format("-repo-%s", rve.getId()));
-              }
-            }
-          }
-        }
-
-        return null;
-      }
-    };
-
-    updateBaseUrls(cluster, component, updater);
-
-    if (configs.arePackagesLegacyOverridden()) {
-      LOG.warn("Legacy override option is turned on, disabling CommandRepositoryFeature.scoped feature");
-      command.getFeature().setIsScoped(false);
-    }
-
-    return command;
-  }
-
-  /**
-   * Executed by two different representations of repos.  When we are comfortable with the new
-   * implementation, this may be removed and called inline in {@link #getCommandRepository(Cluster, ServiceComponent, Host)}
-   *
-   * @param cluster   the cluster to isolate the stack
-   * @param component the component
-   * @param host      used to resolve the family for the repositories
-   * @param function  function that will transform the supplied repositories for specific use.
-   * @return <T> the type as defined by the supplied {@code function}.
-   * @throws AmbariException
-   */
-  @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES)
-  private <T> T getBaseUrls(Cluster cluster, ServiceComponent component, Host host,
-      Function<List<RepositoryInfo>, T> function) throws AmbariException {
-
-    String hostOsType = host.getOsType();
-    String hostOsFamily = host.getOsFamily();
-    String hostName = host.getHostName();
-
-    StackId stackId = component.getDesiredStackId();
-
-    Map<String, List<RepositoryInfo>> repos = ambariMetaInfo.getRepository(
-            stackId.getStackName(), stackId.getStackVersion());
-
-    String family = os_family.find(hostOsType);
-    if (null == family) {
-      family = hostOsFamily;
-    }
-
-    final List<RepositoryInfo> repoInfos;
-
-    // !!! check for the most specific first
-    if (repos.containsKey(hostOsType)) {
-      repoInfos = repos.get(hostOsType);
-    } else if (null != family && repos.containsKey(family)) {
-      repoInfos = repos.get(family);
-    } else {
-      repoInfos = null;
-      LOG.warn("Could not retrieve repo information for host"
-              + ", hostname=" + hostName
-              + ", clusterName=" + cluster.getClusterName()
-              + ", stackInfo=" + stackId.getStackId());
-    }
-
-    // leave it to function implementation to handle null.
-    return function.apply(repoInfos);
-  }
-
-  /**
-   * Checks repo URLs against the current version for the cluster and makes
-   * adjustments to the Base URL when the current is different.
-   *
-   * @param <T> the result after appling the repository version, if found.
-   */
-  @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES)
-  private <T> T updateBaseUrls(Cluster cluster, ServiceComponent component, BaseUrlUpdater<T> function) throws AmbariException {
-
-    RepositoryVersionEntity repositoryEntity = null;
-
-    // !!! try to find the component repo first
-    if (null != component) {
-      repositoryEntity = component.getDesiredRepositoryVersion();
-    } else {
-      LOG.info("Service component not passed in, attempt to resolve the repository for cluster {}",
-          cluster.getClusterName());
-    }
-
-    if (null == repositoryEntity && null != component) {
-      Service service = cluster.getService(component.getServiceName());
-
-      repositoryEntity = service.getDesiredRepositoryVersion();
-    }
-
-    if (null == repositoryEntity) {
-      LOG.info("Cluster {} has no specific Repository Versions.  Using stack-defined values", cluster.getClusterName());
-      return function.getDefault();
-    }
-
-    return function.apply(repositoryEntity);
-  }
-
 
   /**
    * Helper method to fill execution command information.
@@ -1652,21 +1440,4 @@ public class AmbariCustomCommandExecutionHelper {
     return removedHosts;
   }
 
-  /**
-   * Class that is used to update base urls.  There are two implementations of this - when we no
-   * longer are sure the deprecated repo info can be removed, so too can this class.
-   */
-  @Experimental(feature=ExperimentalFeature.PATCH_UPGRADES)
-  abstract static class BaseUrlUpdater<T> implements Function<RepositoryVersionEntity, T> {
-    private T m_default;
-
-    private BaseUrlUpdater(T defaultValue) {
-      m_default = defaultValue;
-    }
-
-    private T getDefault() {
-      return m_default;
-    }
-
-  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 4c00f1f..fd91e9d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -89,6 +89,7 @@ import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.RequestFactory;
 import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.actionmanager.StageFactory;
+import org.apache.ambari.server.agent.CommandRepository;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
@@ -107,6 +108,7 @@ import org.apache.ambari.server.controller.metrics.MetricPropertyProviderFactory
 import org.apache.ambari.server.controller.metrics.MetricsCollectorHAManager;
 import org.apache.ambari.server.controller.metrics.timeline.cache.TimelineMetricCacheProvider;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.customactions.ActionDefinition;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.metadata.ActionMetadata;
@@ -193,6 +195,7 @@ import org.apache.ambari.server.state.stack.OsFamily;
 import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.ambari.server.state.stack.WidgetLayout;
 import org.apache.ambari.server.state.stack.WidgetLayoutInfo;
+import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpInProgressEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpSucceededEvent;
@@ -321,6 +324,9 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   @Inject
   protected OsFamily osFamily;
 
+  @Inject
+  private RepositoryVersionHelper repoVersionHelper;
+
   /**
    * The KerberosHelper to help setup for enabling for disabling Kerberos
    */
@@ -2463,7 +2469,12 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     }
     StageUtils.useAmbariJdkInCommandParams(commandParams, configs);
 
-    String repoInfo = customCommandExecutionHelper.getRepoInfo(cluster, component, host);
+    String repoInfo;
+    try {
+      repoInfo = repoVersionHelper.getRepoInfo(cluster, component, host);
+    } catch (SystemException e) {
+      throw new AmbariException("", e);
+    }
     if (LOG.isDebugEnabled()) {
       LOG.debug("Sending repo information to agent, hostname={}, clusterName={}, stackInfo={}, repoInfo={}",
         scHost.getHostName(), clusterName, stackId.getStackId(), repoInfo);
@@ -2561,7 +2572,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     execCmd.setRoleParams(roleParams);
     execCmd.setCommandParams(commandParams);
 
-    execCmd.setRepositoryFile(customCommandExecutionHelper.getCommandRepository(cluster, component, host));
     execCmdWrapper.setVersions(cluster);
 
     if (execCmd.getConfigurationTags().containsKey("cluster-env")) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
index 24e4d70..1c36c96 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
@@ -705,18 +705,10 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
 
     // Determine repositories for host
     String osFamily = host.getOsFamily();
+    OperatingSystemEntity osEntity = repoVersionHelper.getOSEntityForHost(host, repoVersion);
 
-    OperatingSystemEntity osEntity = null;
-    for (OperatingSystemEntity os : repoVersion.getOperatingSystems()) {
-      if (os.getOsType().equals(osFamily)) {
-        osEntity = os;
-        break;
-      }
-    }
-
-    if (null == osEntity || CollectionUtils.isEmpty(osEntity.getRepositories())) {
-      throw new SystemException(String.format("Repositories for os type %s are " +
-          "not defined for version %s of Stack %s.",
+    if (CollectionUtils.isEmpty(osEntity.getRepositories())) {
+      throw new SystemException(String.format("Repositories for os type %s are not defined for version %s of Stack %s.",
             osFamily, repoVersion.getVersion(), stackId));
     }
 
@@ -747,7 +739,7 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
     actionContext.setRepositoryVersion(repoVersion);
     actionContext.setTimeout(Short.valueOf(configuration.getDefaultAgentTaskTimeout(true)));
 
-    repoVersionHelper.addCommandRepository(actionContext, cluster, repoVersion, osEntity);
+    repoVersionHelper.addCommandRepositoryToContext(actionContext, osEntity);
 
     return actionContext;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostStackVersionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostStackVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostStackVersionResourceProvider.java
index 62fb530..48e9f59 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostStackVersionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostStackVersionResourceProvider.java
@@ -446,8 +446,9 @@ public class HostStackVersionResourceProvider extends AbstractControllerResource
             Collections.singletonList(filter),
             roleParams);
     actionContext.setTimeout(Short.valueOf(configuration.getDefaultAgentTaskTimeout(true)));
+    actionContext.setRepositoryVersion(repoVersionEnt);
 
-    repoVersionHelper.addCommandRepository(actionContext, cluster, repoVersionEnt, osEntity);
+    repoVersionHelper.addCommandRepositoryToContext(actionContext, osEntity);
 
     String caption = String.format(INSTALL_PACKAGES_FULL_NAME + " on host %s", hostName);
     RequestStageContainer req = createRequest(caption);

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
index 87943d1..8276f4a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
@@ -25,14 +25,14 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import org.apache.ambari.annotations.Experimental;
+import org.apache.ambari.annotations.ExperimentalFeature;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.CommandRepository;
-import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.ActionExecutionContext;
-import org.apache.ambari.server.controller.ActionExecutionContext.ExecutionCommandVisitor;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.internal.OperatingSystemResourceProvider;
 import org.apache.ambari.server.controller.internal.RepositoryResourceProvider;
@@ -42,13 +42,18 @@ import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
 import org.apache.ambari.server.orm.entities.RepositoryEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.RepositoryType;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.ServiceOsSpecific;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.repository.ClusterVersionSummary;
 import org.apache.ambari.server.state.repository.VersionDefinitionXml;
+import org.apache.ambari.server.state.stack.OsFamily;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -65,6 +70,7 @@ import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
+
 /**
  * Provides helper methods to manage repository versions.
  */
@@ -82,6 +88,51 @@ public class RepositoryVersionHelper {
   @Inject
   private Provider<Configuration> configuration;
 
+  @Inject
+  private Provider<OsFamily> os_family;
+
+  @Inject Provider<Clusters> clusters;
+
+
+  /**
+   * Checks repo URLs against the current version for the cluster and make
+   * adjustments to the Base URL when the current is different.
+   *
+   * @param cluster {@link Cluster} object
+   * @param component resolve {@link RepositoryVersionEntity} for the component, could be {@code null}
+   *
+   * @return {@link RepositoryVersionEntity} retrieved for component if set or cluster if not
+   */
+  @Experimental(feature = ExperimentalFeature.PATCH_UPGRADES)
+  private RepositoryVersionEntity getRepositoryVersionEntity(Cluster cluster, ServiceComponent component) throws SystemException {
+
+    RepositoryVersionEntity repositoryEntity = null;
+
+    // !!! try to find the component repo first
+    if (null != component) {
+      repositoryEntity = component.getDesiredRepositoryVersion();
+    } else {
+      LOG.info("Service component not passed in, attempt to resolve the repository for cluster {}",
+        cluster.getClusterName());
+    }
+
+    if (null == repositoryEntity && null != component) {
+      try {
+        Service service = cluster.getService(component.getServiceName());
+        repositoryEntity = service.getDesiredRepositoryVersion();
+      } catch (AmbariException e) {
+        throw new SystemException("Unhandled exception", e);
+      }
+    }
+
+    if (null == repositoryEntity) {
+      LOG.info("Cluster {} has no specific Repository Versions.  Using stack-defined values", cluster.getClusterName());
+      return null;
+    }
+
+    return repositoryEntity;
+  }
+
   /**
    * Parses operating systems json to a list of entities. Expects json like:
    * <pre>
@@ -310,17 +361,46 @@ public class RepositoryVersionHelper {
     return roleParams;
   }
 
+
+  /**
+   * Return repositories available for target os version on host based on {@code repoVersion} repository definition
+   * @param host target {@link Host} for providing repositories list
+   * @param repoVersion {@link RepositoryVersionEntity} version definition with all available repositories
+   *
+   * @return {@link OperatingSystemEntity} with available repositories for host
+   * @throws SystemException if no repository available for target {@link Host}
+   */
+  public OperatingSystemEntity getOSEntityForHost(Host host, RepositoryVersionEntity repoVersion) throws SystemException {
+    String osFamily = host.getOsFamily();
+    OperatingSystemEntity osEntity = null;
+    for (OperatingSystemEntity operatingSystem : repoVersion.getOperatingSystems()) {
+      if (osFamily.equals(operatingSystem.getOsType())) {
+        osEntity = operatingSystem;
+        break;
+      }
+    }
+
+    if (null == osEntity) {
+      throw new SystemException(String.format("Operating System matching %s could not be found",
+        osFamily));
+    }
+
+    return osEntity;
+  }
+
   /**
    * Adds a command repository to the action context
-   * @param context       the context
    * @param osEntity      the OS family
-   * @param repoVersion   the repository version entity
    */
-  public void addCommandRepository(ActionExecutionContext context, Cluster cluster,
-      RepositoryVersionEntity repoVersion, OperatingSystemEntity osEntity) {
+  public CommandRepository getCommandRepository(final RepositoryVersionEntity repoVersion,
+                                                final OperatingSystemEntity osEntity) throws SystemException {
 
     final CommandRepository commandRepo = new CommandRepository();
-    boolean sysPreppedHost = configuration.get().areHostsSysPrepped().equalsIgnoreCase("true");
+    final boolean sysPreppedHost = configuration.get().areHostsSysPrepped().equalsIgnoreCase("true");
+
+    if (null == repoVersion) {
+      throw new SystemException("Repository version entity is not provided");
+    }
 
     commandRepo.setRepositories(osEntity.getOsType(), osEntity.getRepositories());
     commandRepo.setRepositoryVersion(repoVersion.getVersion());
@@ -347,10 +427,202 @@ public class RepositoryVersionHelper {
       LOG.warn("Legacy override option is turned on, disabling CommandRepositoryFeature.scoped feature");
       commandRepo.getFeature().setIsScoped(false);
     }
+    return commandRepo;
+  }
+
+
+  /**
+   * Builds repository information for inclusion in a command.  This replaces escaping json on
+   * a command.
+   *
+   * @param cluster the cluster
+   * @param host    the host
+   * @param component {@link ServiceComponent} object, could be null to return service-related repository
+   * @return  the command repository
+   * @throws SystemException
+   */
+  @Experimental(feature=ExperimentalFeature.PATCH_UPGRADES)
+  public CommandRepository getCommandRepository(final Cluster cluster, ServiceComponent component, final Host host)
+    throws SystemException {
+
+    RepositoryVersionEntity repoVersion = getRepositoryVersionEntity(cluster, component);
+    OperatingSystemEntity osEntity = getOSEntityForHost(host, repoVersion);
+
+    return getCommandRepository(repoVersion, osEntity);
+  }
+
+  /**
+   * This method builds and adds repo infoto hostLevelParams of action
+   *
+   * @param cluster cluster to which host level params belongs
+   * @param actionContext context of the action. Must be not {@code null}
+   * @param repositoryVersion repository version entity to use
+   * @param hostLevelParams hasgmap with host level params. Must be not {@code null}
+   * @param hostName host name to which add repo onfo
+   * @throws AmbariException
+   */
+  @Deprecated
+  public void addRepoInfoToHostLevelParams(final Cluster cluster, final ActionExecutionContext actionContext,
+                                           final RepositoryVersionEntity repositoryVersion, final Map<String, String> hostLevelParams,
+                                           final String hostName) throws AmbariException {
+
+    // if the repo is null, see if any values from the context should go on the
+    // host params and then return
+    if (null == repositoryVersion) {
+      // see if the action context has a repository set to use for the command
+      if (null != actionContext.getRepositoryVersion()) {
+        StackId stackId = actionContext.getRepositoryVersion().getStackId();
+        hostLevelParams.put(KeyNames.STACK_NAME, stackId.getStackName());
+        hostLevelParams.put(KeyNames.STACK_VERSION, stackId.getStackVersion());
+      }
+
+      return;
+    } else {
+      StackId stackId = repositoryVersion.getStackId();
+      hostLevelParams.put(KeyNames.STACK_NAME, stackId.getStackName());
+      hostLevelParams.put(KeyNames.STACK_VERSION, stackId.getStackVersion());
+    }
+
+    JsonObject rootJsonObject = new JsonObject();
+    JsonArray repositories = new JsonArray();
+
+    String hostOsFamily = cluster.getHost(hostName).getOsFamily();
+    for (OperatingSystemEntity operatingSystemEntity : repositoryVersion.getOperatingSystems()) {
+      // ostype in OperatingSystemEntity it's os family. That should be fixed
+      // in OperatingSystemEntity.
+      if (operatingSystemEntity.getOsType().equals(hostOsFamily)) {
+        for (RepositoryEntity repositoryEntity : operatingSystemEntity.getRepositories()) {
+          JsonObject repositoryInfo = new JsonObject();
+          repositoryInfo.addProperty("base_url", repositoryEntity.getBaseUrl());
+          repositoryInfo.addProperty("repo_name", repositoryEntity.getName());
+          repositoryInfo.addProperty("repo_id", repositoryEntity.getRepositoryId());
+
+          repositories.add(repositoryInfo);
+        }
+        rootJsonObject.add("repositories", repositories);
+      }
+    }
+    hostLevelParams.put(KeyNames.REPO_INFO, rootJsonObject.toString());
+  }
+
+
+  /**
+   * Get repository info given a cluster and host.
+   *
+   * @param cluster  the cluster
+   * @param host     the host
+   *
+   * @return the repo info
+   *
+   * @deprecated use {@link #getCommandRepository(Cluster, ServiceComponent, Host)} instead.
+   * @throws SystemException if the repository information can not be obtained
+   */
+  @Deprecated
+  public String getRepoInfo(Cluster cluster, ServiceComponent component, Host host) throws SystemException {
+    final JsonArray jsonList = getBaseUrls(cluster, component, host);
+    final RepositoryVersionEntity rve = getRepositoryVersionEntity(cluster, component);
+
+    if (null == rve || null == jsonList) {
+      return "";
+    }
+
+    final JsonArray result = new JsonArray();
+
+    for (JsonElement e : jsonList) {
+      JsonObject obj = e.getAsJsonObject();
+
+      String repoId = obj.has("repoId") ? obj.get("repoId").getAsString() : null;
+      String repoName = obj.has("repoName") ? obj.get("repoName").getAsString() : null;
+      String baseUrl = obj.has("baseUrl") ? obj.get("baseUrl").getAsString() : null;
+      String osType = obj.has("osType") ? obj.get("osType").getAsString() : null;
+
+      if (null == repoId || null == baseUrl || null == osType || null == repoName) {
+        continue;
+      }
+
+      for (OperatingSystemEntity ose : rve.getOperatingSystems()) {
+        if (ose.getOsType().equals(osType) && ose.isAmbariManagedRepos()) {
+          for (RepositoryEntity re : ose.getRepositories()) {
+            if (re.getName().equals(repoName) &&
+              !re.getBaseUrl().equals(baseUrl)) {
+              obj.addProperty("baseUrl", re.getBaseUrl());
+            }
+          }
+          result.add(e);
+        }
+      }
+    }
+    return result.toString();
+  }
+
+
+  /**
+   * Executed by two different representations of repos.  When we are comfortable with the new
+   * implementation, this may be removed and called inline in {@link #getCommandRepository(Cluster, ServiceComponent, Host)}
+   *
+   * @param cluster   the cluster to isolate the stack
+   * @param component the component
+   * @param host      used to resolve the family for the repositories
+   * @return JsonArray the type as defined by the supplied {@code function}.
+   * @throws SystemException
+   */
+  @Deprecated
+  private JsonArray getBaseUrls(Cluster cluster, ServiceComponent component, Host host) throws SystemException {
+
+    String hostOsType = host.getOsType();
+    String hostOsFamily = host.getOsFamily();
+    String hostName = host.getHostName();
+
+    StackId stackId = component.getDesiredStackId();
+    Map<String, List<RepositoryInfo>> repos;
+
+    try {
+      repos = ami.get().getRepository(stackId.getStackName(), stackId.getStackVersion());
+    }catch (AmbariException e) {
+      throw new SystemException("Unhandled exception", e);
+    }
+
+    String family = os_family.get().find(hostOsType);
+    if (null == family) {
+      family = hostOsFamily;
+    }
+
+    final List<RepositoryInfo> repoInfoList;
+
+    // !!! check for the most specific first
+    if (repos.containsKey(hostOsType)) {
+      repoInfoList = repos.get(hostOsType);
+    } else if (null != family && repos.containsKey(family)) {
+      repoInfoList = repos.get(family);
+    } else {
+      repoInfoList = null;
+      LOG.warn("Could not retrieve repo information for host"
+        + ", hostname=" + hostName
+        + ", clusterName=" + cluster.getClusterName()
+        + ", stackInfo=" + stackId.getStackId());
+    }
+
+    return (null == repoInfoList) ? null : (JsonArray) gson.toJsonTree(repoInfoList);
+  }
+
+
+  /**
+   * Adds a command repository to the action context
+   * @param context       the context
+   * @param osEntity      the OS family
+   */
+  public void addCommandRepositoryToContext(ActionExecutionContext context,
+                                            OperatingSystemEntity osEntity) throws SystemException {
+
+    final RepositoryVersionEntity repoVersion = context.getRepositoryVersion();
+    final CommandRepository commandRepo = getCommandRepository(repoVersion, osEntity);
 
     ClusterVersionSummary summary = null;
+
     if (RepositoryType.STANDARD != repoVersion.getType()) {
       try {
+        final Cluster cluster = clusters.get().getCluster(context.getClusterName());
+
         VersionDefinitionXml xml = repoVersion.getRepositoryXml();
         summary = xml.getClusterSummary(cluster);
       } catch (Exception e) {
@@ -360,25 +632,23 @@ public class RepositoryVersionHelper {
 
     final ClusterVersionSummary clusterSummary = summary;
 
-    context.addVisitor(new ExecutionCommandVisitor() {
-      @Override
-      public void visit(ExecutionCommand command) {
-        if (null == command.getRepositoryFile()) {
-          command.setRepositoryFile(commandRepo);
-        }
 
-        if (null != clusterSummary) {
-          Map<String, Object> params = command.getRoleParameters();
-          if (null == params) {
-            params = new HashMap<>();
-            command.setRoleParameters(params);
-          }
-          params.put(KeyNames.CLUSTER_VERSION_SUMMARY, clusterSummary);
-        }
+    context.addVisitor(command -> {
+      if (null == command.getRepositoryFile()) {
+        command.setRepositoryFile(commandRepo);
+      }
 
+      if (null != clusterSummary) {
+        Map<String, Object> params = command.getRoleParameters();
+        if (null == params) {
+          params = new HashMap<>();
+          command.setRoleParameters(params);
+        }
+        params.put(KeyNames.CLUSTER_VERSION_SUMMARY, clusterSummary);
       }
+
     });
   }
 
 
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/18c4af48/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
index 883e891..26c79e6 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
@@ -574,14 +574,15 @@ public class AmbariCustomCommandExecutionHelperTest {
     Host host = clusters.getHost("c1-c6401");
 
     AmbariCustomCommandExecutionHelper helper = injector.getInstance(AmbariCustomCommandExecutionHelper.class);
+    RepositoryVersionHelper repoHelper = injector.getInstance(RepositoryVersionHelper.class);
     StackDAO stackDAO = injector.getInstance(StackDAO.class);
     RepositoryVersionDAO repoVersionDAO = injector.getInstance(RepositoryVersionDAO.class);
     ServiceComponentDesiredStateDAO componentDAO = injector.getInstance(ServiceComponentDesiredStateDAO.class);
     RepositoryVersionHelper repoVersionHelper = injector.getInstance(RepositoryVersionHelper.class);
 
-    CommandRepository commandRepo = helper.getCommandRepository(cluster, componentRM, host);
+    CommandRepository commandRepo = repoHelper.getCommandRepository(cluster, componentRM, host);
+    Assert.assertEquals(2, commandRepo.getRepositories().size());
 
-    Assert.assertEquals(0, commandRepo.getRepositories().size());
 
     RepositoryInfo ri = new RepositoryInfo();
     ri.setBaseUrl("http://foo");
@@ -607,18 +608,18 @@ public class AmbariCustomCommandExecutionHelperTest {
 
     componentEntity.setDesiredRepositoryVersion(repositoryVersion);
     componentEntity.addVersion(componentVersionEntity);
-    componentEntity = componentDAO.merge(componentEntity);
+    componentDAO.merge(componentEntity);
 
     // !!! make sure the override is set
-    commandRepo = helper.getCommandRepository(cluster, componentRM, host);
+    commandRepo = repoHelper.getCommandRepository(cluster, componentRM, host);
 
     Assert.assertEquals(1, commandRepo.getRepositories().size());
     CommandRepository.Repository repo = commandRepo.getRepositories().iterator().next();
     Assert.assertEquals("http://foo", repo.getBaseUrl());
 
     // verify that ZK has no repositories, since we haven't defined a repo version for ZKC
-    commandRepo = helper.getCommandRepository(cluster, componentZKC, host);
-    Assert.assertEquals(0, commandRepo.getRepositories().size());
+    commandRepo = repoHelper.getCommandRepository(cluster, componentZKC, host);
+    Assert.assertEquals(2, commandRepo.getRepositories().size());
   }
 
   private void createClusterFixture(String clusterName, StackId stackId,


[32/49] ambari git commit: AMBARI-22495. Installer - Select Version page should show HDP-GPL repo if necessary (vsubramanian)

Posted by rl...@apache.org.
AMBARI-22495. Installer - Select Version page should show HDP-GPL repo if necessary (vsubramanian)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 6b17d0142266f714807bd06e3ce1afbe535a0a73
Parents: 9fc7223
Author: Vivek Ratnavel Subramanian <vi...@gmail.com>
Authored: Wed Nov 22 18:00:32 2017 -0800
Committer: Vivek Ratnavel Subramanian <vi...@gmail.com>
Committed: Wed Nov 22 18:00:32 2017 -0800

----------------------------------------------------------------------
 ambari-web/app/controllers/installer.js         | 53 +++++++++++---------
 .../app/controllers/wizard/step8_controller.js  | 12 +++--
 .../app/mappers/repository_version_mapper.js    |  3 +-
 ambari-web/app/mappers/stack_mapper.js          |  3 +-
 ambari-web/app/models/repository.js             | 17 +++++++
 .../app/models/stack_version/repository.js      |  3 +-
 ambari-web/app/templates/wizard/step1.hbs       | 36 +++++++++++++
 ambari-web/test/controllers/installer_test.js   | 14 ++++--
 8 files changed, 103 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6b17d014/ambari-web/app/controllers/installer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/installer.js b/ambari-web/app/controllers/installer.js
index 3c50b26..d6be78d 100644
--- a/ambari-web/app/controllers/installer.js
+++ b/ambari-web/app/controllers/installer.js
@@ -813,6 +813,7 @@ App.InstallerController = App.WizardController.extend(App.Persist, {
             "repo_id": repository.get('repoId'),
             "repo_name": repository.get('repoName'),
             "components": repository.get('components'),
+            "tags": repository.get('tags'),
             "distribution": repository.get('distribution')
           }
         });
@@ -833,7 +834,7 @@ App.InstallerController = App.WizardController.extend(App.Persist, {
     var dfd = $.Deferred();
     if (selectedStack && selectedStack.get('operatingSystems')) {
       this.set('validationCnt', selectedStack.get('operatingSystems').filterProperty('isSelected').filterProperty('isEmpty', false).map(function (os) {
-        return os.get('repositories.length');
+        return os.get('repositories').filterProperty('showRepo', true).length;
       }).reduce(Em.sum, 0));
       var verifyBaseUrl = !wizardStep1Controller.get('skipValidationChecked') && !wizardStep1Controller.get('selectedStack.useRedhatSatellite');
       if (!verifyBaseUrl) {
@@ -842,32 +843,34 @@ App.InstallerController = App.WizardController.extend(App.Persist, {
       selectedStack.get('operatingSystems').forEach(function (os) {
         if (os.get('isSelected') && !os.get('isEmpty')) {
           os.get('repositories').forEach(function (repo) {
-            repo.setProperties({
-              errorTitle: '',
-              errorContent: '',
-              validation: 'INPROGRESS'
-            });
-            this.set('content.isCheckInProgress', true);
-            App.ajax.send({
-              name: 'wizard.advanced_repositories.valid_url',
-              sender: this,
-              data: {
-                stackName: stackName,
-                stackVersion: stackVersion,
-                repoId: repo.get('repoId'),
-                osType: os.get('osType'),
-                osId: os.get('id'),
-                dfd: dfd,
+            if (repo.get('showRepo')) {
+              repo.setProperties({
+                errorTitle: '',
+                errorContent: '',
+                validation: 'INPROGRESS'
+              });
+              this.set('content.isCheckInProgress', true);
+              App.ajax.send({
+                name: 'wizard.advanced_repositories.valid_url',
+                sender: this,
                 data: {
-                  'Repositories': {
-                    'base_url': repo.get('baseUrl'),
-                    "verify_base_url": verifyBaseUrl
+                  stackName: stackName,
+                  stackVersion: stackVersion,
+                  repoId: repo.get('repoId'),
+                  osType: os.get('osType'),
+                  osId: os.get('id'),
+                  dfd: dfd,
+                  data: {
+                    'Repositories': {
+                      'base_url': repo.get('baseUrl'),
+                      "verify_base_url": verifyBaseUrl
+                    }
                   }
-                }
-              },
-              success: 'checkRepoURLSuccessCallback',
-              error: 'checkRepoURLErrorCallback'
-            });
+                },
+                success: 'checkRepoURLSuccessCallback',
+                error: 'checkRepoURLErrorCallback'
+              });
+            }
           }, this);
         } else if (os.get('isSelected') && os.get('isEmpty')) {
           os.set('isSelected', false);

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b17d014/ambari-web/app/controllers/wizard/step8_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step8_controller.js b/ambari-web/app/controllers/wizard/step8_controller.js
index 94139e0..e64a09a 100644
--- a/ambari-web/app/controllers/wizard/step8_controller.js
+++ b/ambari-web/app/controllers/wizard/step8_controller.js
@@ -307,11 +307,13 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz
         selectedStack.get('operatingSystems').forEach(function (os) {
           if (os.get('isSelected')) {
             os.get('repositories').forEach(function(repo) {
-              allRepos.push(Em.Object.create({
-                base_url: repo.get('baseUrl'),
-                os_type: repo.get('osType'),
-                repo_id: repo.get('repoId')
-              }));
+              if (repo.get('showRepo')) {
+                allRepos.push(Em.Object.create({
+                  base_url: repo.get('baseUrl'),
+                  os_type: repo.get('osType'),
+                  repo_id: repo.get('repoId')
+                }));
+              }
             }, this);
           }
         }, this);

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b17d014/ambari-web/app/mappers/repository_version_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/repository_version_mapper.js b/ambari-web/app/mappers/repository_version_mapper.js
index 3838d34..8843dcd 100644
--- a/ambari-web/app/mappers/repository_version_mapper.js
+++ b/ambari-web/app/mappers/repository_version_mapper.js
@@ -73,7 +73,8 @@ App.repoVersionMapper = App.QuickDataMapper.create({
     repo_id : 'Repositories.repo_id',
     repo_name : 'Repositories.repo_name',
     stack_name : 'Repositories.stack_name',
-    stack_version : 'Repositories.stack_version'
+    stack_version : 'Repositories.stack_version',
+    tags: 'Repositories.tags'
   },
 
   map: function (json, loadAll, isCurrentStackOnly) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b17d014/ambari-web/app/mappers/stack_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/stack_mapper.js b/ambari-web/app/mappers/stack_mapper.js
index 07fb137..323a033 100644
--- a/ambari-web/app/mappers/stack_mapper.js
+++ b/ambari-web/app/mappers/stack_mapper.js
@@ -87,7 +87,8 @@ App.stackMapper = App.QuickDataMapper.create({
     stack_version: 'stack_version',
     operating_system_id: 'os_id',
     components: 'components',
-    distribution: 'distribution'
+    distribution: 'distribution',
+    tags: 'tags'
   },
   
   map: function(json) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b17d014/ambari-web/app/models/repository.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/repository.js b/ambari-web/app/models/repository.js
index c50750f..d85c55d 100644
--- a/ambari-web/app/models/repository.js
+++ b/ambari-web/app/models/repository.js
@@ -34,6 +34,7 @@ App.Repository = DS.Model.extend({
   operatingSystem: DS.belongsTo('App.OperatingSystem'),
   components: DS.attr('string'),
   distribution: DS.attr('string'),
+  tags: DS.attr('array'),
 
   validation: DS.attr('string', {defaultValue: ''}),
   validationClassName: Em.computed.getByKey('validationClassNameMap', 'validation', ''),
@@ -66,6 +67,22 @@ App.Repository = DS.Model.extend({
     return this.get('repoName').contains('UTILS');
   }.property('repoName'),
 
+  /**
+   * @type {boolean}
+   */
+  isGPL: function () {
+    return this.get('tags').contains('GPL');    
+  }.property('tags'),
+
+  /**
+   * Determines whether a repo needs to be displayed in the UI or not
+   * @type {boolean}
+   */
+  showRepo: function () {
+    const isGPLAccepted = App.router.get('clusterController.ambariProperties')['gpl.license.accepted'] === 'true';
+    return isGPLAccepted || !this.get('isGPL');
+  }.property('isGPL'),
+
   undo: Em.computed.notEqualProperties('baseUrl', 'baseUrlInit'),
 
   notEmpty: Em.computed.notEqual('baseUrl', ''),

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b17d014/ambari-web/app/models/stack_version/repository.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/stack_version/repository.js b/ambari-web/app/models/stack_version/repository.js
index 8bd4323..6c93416 100644
--- a/ambari-web/app/models/stack_version/repository.js
+++ b/ambari-web/app/models/stack_version/repository.js
@@ -29,7 +29,8 @@ App.Repository = DS.Model.extend({
   repoName : DS.attr('string'),
   stackName : DS.attr('string'),
   stackVersion : DS.attr('string'),
-  operatingSystem: DS.belongsTo('App.OS')
+  operatingSystem: DS.belongsTo('App.OS'),
+  tags: DS.attr('array')
 });
 
 App.Repository.FIXTURES = [];

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b17d014/ambari-web/app/templates/wizard/step1.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/wizard/step1.hbs b/ambari-web/app/templates/wizard/step1.hbs
index 6b15e65..eb746c3 100644
--- a/ambari-web/app/templates/wizard/step1.hbs
+++ b/ambari-web/app/templates/wizard/step1.hbs
@@ -131,6 +131,42 @@
                       </div>
                       {{! Add OS END}}
                     </div>
+                    <div class="span9 repo-name-url">
+                      {{#each repository in operatingSystem.repositories}}
+                        {{#if repository.showRepo}}
+                        <div {{bindAttr class=":clearfix :repo-name-url-inner repository.repoName"}}>
+                          <div class="span3">
+                            <label class="repo-name-label control-label">{{repository.repoId}}</label>
+                          </div>
+                          <div class="validation-td span1">
+                            {{#if repository.validation}}
+                              {{view view.popoverView repositoryBinding="repository"}}
+                            {{/if}}
+                          </div>
+                          <div {{bindAttr class=":span8 :repo-url repository.invalidFormatError:textfield-error repository.invalidError:textfield-error"}}>
+                            {{view Ember.TextField placeholderBinding="repository.placeholder" valueBinding="repository.baseUrl" disabledBinding="controller.selectedStack.useRedhatSatellite"}}
+                            {{#if controller.selectedStack.usePublicRepo}}
+                              {{#if repository.undo}}
+                                <i class="icon-undo" data-toggle="tooltip"
+                                  {{action "doRestoreDefaultValue" repository target="controller"}}
+                                  {{translateAttr title="common.undo"}}>
+                                </i>
+                              {{/if}}
+                            {{else}}
+                              {{#if repository.notEmpty}}
+                                <i class="icon-undo" data-toggle="tooltip"
+                                  {{action "doRestoreToEmpty" repository target="controller"}}
+                                  {{translateAttr title="common.undo"}}>
+                                </i>
+                              {{/if}}
+                            {{/if}}
+                          </div>
+                        </div>
+                        {{/if}}
+                      {{/each}}
+                    </div>
+                    <div {{bindAttr class=":span1 :remove-icon controller.selectedStack.useRedhatSatellite:disabled"}} {{action "removeOS" operatingSystem target="controller"}}>
+                      <i class="icon-minus"></i>{{t common.remove}}</div>
                   </div>
                 </div>
                 <table class="table table-hover">

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b17d014/ambari-web/test/controllers/installer_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/installer_test.js b/ambari-web/test/controllers/installer_test.js
index 65a1e5c..3831c79 100644
--- a/ambari-web/test/controllers/installer_test.js
+++ b/ambari-web/test/controllers/installer_test.js
@@ -92,7 +92,8 @@ describe('App.InstallerController', function () {
                 isEmpty: false,
                 errorTitle: '1',
                 errorContent: '1',
-                validation: ''
+                validation: '',
+                showRepo: true
               })
             ])
           })
@@ -131,7 +132,8 @@ describe('App.InstallerController', function () {
                   "isEmpty": false,
                   "errorTitle": "",
                   "errorContent": "",
-                  "validation": "INPROGRESS"
+                  "validation": "INPROGRESS",
+                  "showRepo": true
                 }
               ]
             }
@@ -172,7 +174,8 @@ describe('App.InstallerController', function () {
                 isEmpty: false,
                 errorTitle: '1',
                 errorContent: '1',
-                validation: ''
+                validation: '',
+                showRepo: true
               })
             ])
           })
@@ -189,7 +192,7 @@ describe('App.InstallerController', function () {
         }
       }
     };
-    it ('Should check stacks for sucess', function() {
+    it ('Should check stacks for success', function() {
 
       installerController.set('content.stacks', stacks);
       installerController.checkRepoURLSuccessCallback(null,null,data);
@@ -220,7 +223,8 @@ describe('App.InstallerController', function () {
                   "isEmpty": false,
                   "errorTitle": "1",
                   "errorContent": "1",
-                  "validation": "OK"
+                  "validation": "OK",
+                  "showRepo": true
                 }
               ]
             }


[29/49] ambari git commit: AMBARI-22503 Log Search UI: refine time range picker. (ababiichuk)

Posted by rl...@apache.org.
AMBARI-22503 Log Search UI: refine time range picker. (ababiichuk)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: bce0bd8f9424828d0d43ad5e427dff7259496e64
Parents: 5d421b7
Author: ababiichuk <ab...@hortonworks.com>
Authored: Wed Nov 22 19:54:00 2017 +0200
Committer: ababiichuk <ab...@hortonworks.com>
Committed: Thu Nov 23 00:47:34 2017 +0200

----------------------------------------------------------------------
 .../date-picker/date-picker.component.spec.ts   |  2 ++
 .../date-picker/date-picker.component.ts        | 35 +++++++++++++++++---
 .../time-range-picker.component.html            |  6 ++--
 .../time-range-picker.component.ts              | 12 ++++---
 .../src/app/services/logs-container.service.ts  | 20 ++++++++---
 .../src/assets/i18n/en.json                     |  4 ++-
 6 files changed, 61 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/bce0bd8f/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.spec.ts
index e6c0bfe..dfd9711 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.spec.ts
@@ -18,6 +18,7 @@
 
 import {async, ComponentFixture, TestBed} from '@angular/core/testing';
 import {StoreModule} from '@ngrx/store';
+import * as moment from 'moment-timezone';
 import {AppSettingsService, appSettings} from '@app/services/storage/app-settings.service';
 
 import {DatePickerComponent} from './date-picker.component';
@@ -42,6 +43,7 @@ describe('DatePickerComponent', () => {
   beforeEach(() => {
     fixture = TestBed.createComponent(DatePickerComponent);
     component = fixture.componentInstance;
+    component.time = moment();
     fixture.detectChanges();
   });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/bce0bd8f/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts
index efb5e34..e33d71e 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/date-picker/date-picker.component.ts
@@ -16,8 +16,11 @@
  * limitations under the License.
  */
 
-import {Component, OnInit, OnDestroy, Output, EventEmitter, ViewChild, ElementRef} from '@angular/core';
+import {
+  Component, OnInit, OnChanges, OnDestroy, SimpleChanges, Input, Output, EventEmitter, ViewChild, ElementRef
+} from '@angular/core';
 import * as $ from 'jquery';
+import {Moment} from 'moment-timezone';
 import '@vendor/js/bootstrap-datetimepicker.min';
 import {AppSettingsService} from '@app/services/storage/app-settings.service';
 
@@ -25,10 +28,10 @@ import {AppSettingsService} from '@app/services/storage/app-settings.service';
   selector: 'date-picker',
   templateUrl: './date-picker.component.html'
 })
-export class DatePickerComponent implements OnInit, OnDestroy {
+export class DatePickerComponent implements OnInit, OnChanges, OnDestroy {
 
   constructor(private appSettings: AppSettingsService) {
-    appSettings.getParameter('timeZone').subscribe(value => {
+    appSettings.getParameter('timeZone').subscribe((value: string): void => {
       this.destroyDatePicker();
       this.timeZone = value;
       if (this.datePickerElement) {
@@ -37,14 +40,27 @@ export class DatePickerComponent implements OnInit, OnDestroy {
     });
   }
 
-  ngOnInit() {
+  ngOnInit(): void {
     this.createDatePicker();
   }
 
-  ngOnDestroy() {
+  ngOnChanges(changes: SimpleChanges): void {
+    if (changes.hasOwnProperty('time') && this.datePickerElement) {
+      this.setTime(changes.time.currentValue);
+    }
+  }
+
+  ngOnDestroy(): void {
     this.destroyDatePicker();
   }
 
+  /**
+   * Value of time input field passed from parent component
+   * @type {Moment}
+   */
+  @Input()
+  time: Moment;
+
   @Output()
   timeChange: EventEmitter<number> = new EventEmitter();
 
@@ -60,6 +76,7 @@ export class DatePickerComponent implements OnInit, OnDestroy {
     this.datePickerElement.datetimepicker({
       timeZone: this.timeZone
     });
+    this.setTime(this.time);
     this.datePickerElement.on('dp.change', event => this.timeChange.emit(event.date));
   }
 
@@ -70,4 +87,12 @@ export class DatePickerComponent implements OnInit, OnDestroy {
     }
   }
 
+  /**
+   * Set value to time input field
+   * @param {Moment} time
+   */
+  private setTime(time: Moment): void {
+    this.datePickerElement.data('DateTimePicker').date(time);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/bce0bd8f/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
index 621f995..c3f0b6a 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
@@ -22,8 +22,10 @@
 <div class="dropdown-menu row col-md-12">
   <div class="col-md-4" (click)="$event.stopPropagation()">
     <h4>{{'filter.timeRange' | translate}}</h4>
-    <date-picker (timeChange)="setStartTime($event)"></date-picker>
-    <date-picker (timeChange)="setEndTime($event)"></date-picker>
+    <div class="col-md-12 row text-uppercase">{{'filter.timeRange.from' | translate}}</div>
+    <date-picker class="col-md-12 row" [time]="startTime" (timeChange)="setStartTime($event)"></date-picker>
+    <div class="col-md-12 row text-uppercase">{{'filter.timeRange.to' | translate}}</div>
+    <date-picker class="col-md-12 row" [time]="endTime" (timeChange)="setEndTime($event)"></date-picker>
     <button class="btn btn-success pull-right" type="button" (click)="setCustomTimeRange()"
             [disabled]="!startTime || !endTime || startTime >= endTime">
       {{'modal.apply' | translate}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bce0bd8f/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
index cacabc3..74a2b2d 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.ts
@@ -18,7 +18,7 @@
 
 import {Component, forwardRef} from '@angular/core';
 import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
-import {Moment} from 'moment';
+import {Moment} from 'moment-timezone';
 import {LogsContainerService} from '@app/services/logs-container.service';
 import {ListItem} from '@app/classes/list-item';
 import {TimeUnitListItem} from '@app/classes/filtering';
@@ -61,6 +61,8 @@ export class TimeRangePickerComponent implements ControlValueAccessor {
     if (this.onChange) {
       this.onChange(newValue);
     }
+    this.setEndTime(this.logsContainer.getEndTimeMoment(newValue));
+    this.setStartTime(this.logsContainer.getStartTimeMoment(newValue, this.endTime));
   }
 
   setStartTime(timeObject: Moment): void {
@@ -71,11 +73,11 @@ export class TimeRangePickerComponent implements ControlValueAccessor {
     this.endTime = timeObject;
   }
 
-  setTimeRange(value: any, label: string) {
+  setTimeRange(value: any, label: string): void {
     this.selection = {label, value};
   }
 
-  setCustomTimeRange() {
+  setCustomTimeRange(): void {
     this.selection = {
       label: 'filter.timeRange.custom',
       value: {
@@ -86,7 +88,7 @@ export class TimeRangePickerComponent implements ControlValueAccessor {
     };
   }
 
-  writeValue(selection: TimeUnitListItem) {
+  writeValue(selection: TimeUnitListItem): void {
     this.selection = selection;
   }
 
@@ -94,7 +96,7 @@ export class TimeRangePickerComponent implements ControlValueAccessor {
     this.onChange = callback;
   }
 
-  registerOnTouched() {
+  registerOnTouched(): void {
   }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/bce0bd8f/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
index 90ab9b7..a715adc 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
@@ -728,11 +728,11 @@ export class LogsContainerService {
     return Object.keys(keysObject).map((key: string): {fieldClass} => new fieldClass(key));
   }
 
-  private getStartTime = (selection: TimeUnitListItem, current: string): string => {
+  getStartTimeMoment = (selection: TimeUnitListItem, end: moment.Moment): moment.Moment | undefined => {
     let time;
     const value = selection && selection.value;
     if (value) {
-      const endTime = moment(moment(current).valueOf());
+      const endTime = end.clone();
       switch (value.type) {
         case 'LAST':
           time = endTime.subtract(value.interval, value.unit);
@@ -750,10 +750,15 @@ export class LogsContainerService {
           break;
       }
     }
-    return time ? time.toISOString() : '';
+    return time;
   };
 
-  private getEndTime = (selection: TimeUnitListItem): string => {
+  private getStartTime = (selection: TimeUnitListItem, current: string): string => {
+    const startMoment = this.getStartTimeMoment(selection, moment(moment(current).valueOf()));
+    return startMoment ? startMoment.toISOString() : '';
+  };
+
+  getEndTimeMoment = (selection: TimeUnitListItem): moment.Moment | undefined => {
     let time;
     const value = selection && selection.value;
     if (value) {
@@ -774,7 +779,12 @@ export class LogsContainerService {
           break;
       }
     }
-    return time ? time.toISOString() : '';
+    return time;
+  };
+
+  private getEndTime = (selection: TimeUnitListItem): string => {
+    const endMoment = this.getEndTimeMoment(selection);
+    return endMoment ? endMoment.toISOString() : '';
   };
 
   private getQuery(isExclude: boolean): (value: any[]) => string {

http://git-wip-us.apache.org/repos/asf/ambari/blob/bce0bd8f/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json b/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
index b214a4f..98b9e29 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
+++ b/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
@@ -62,7 +62,9 @@
   "filter.timeRange.6hr": "Last 6 hours",
   "filter.timeRange.12hr": "Last 12 hours",
   "filter.timeRange.24hr": "Last 24 hours",
-  "filter.timeRange.custom": "Custom time range",
+  "filter.timeRange.custom": "Custom",
+  "filter.timeRange.from": "from",
+  "filter.timeRange.to": "to",
 
   "levels.fatal": "Fatal",
   "levels.error": "Error",


[40/49] ambari git commit: AMBARI-22513 Make yumrpm.py functions to use global defined commands (dgrinenko)

Posted by rl...@apache.org.
AMBARI-22513 Make yumrpm.py functions to use global defined commands (dgrinenko)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 0249073469de5cd11f032705d609f8cb19ff28c0
Parents: 99b19e5
Author: Dmytro Grinenko <ha...@apache.org>
Authored: Fri Nov 24 16:41:12 2017 +0200
Committer: Dmytro Grinenko <ha...@apache.org>
Committed: Fri Nov 24 16:41:12 2017 +0200

----------------------------------------------------------------------
 .../core/providers/package/yumrpm.py                    |  4 ++--
 .../HIVE/0.12.0.2.0/package/scripts/hive.py             | 12 ++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/02490734/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py b/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
index 8426479..367e2af 100644
--- a/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
+++ b/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
@@ -138,7 +138,7 @@ class YumProvider(RPMBasedPackageProvider):
     :rtype list[list,]
     """
 
-    cmd = [AMBARI_SUDO_BINARY, "yum", "list", "available"]
+    cmd = list(ALL_AVAILABLE_PACKAGES_CMD)
 
     if repo_filter:
       cmd.extend(["--disablerepo=*", "--enablerepo=" + repo_filter])
@@ -154,7 +154,7 @@ class YumProvider(RPMBasedPackageProvider):
     :rtype list[list,]
     """
 
-    packages = self._lookup_packages([AMBARI_SUDO_BINARY, "yum", "list", "installed"], "Installed Packages")
+    packages = self._lookup_packages(list(ALL_INSTALLED_PACKAGES_CMD), "Installed Packages")
     if repo_filter:
       packages = [item for item in packages if item[2].lower() == repo_filter.lower()]
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/02490734/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive.py b/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive.py
index 716a37c..d9cc55f 100644
--- a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive.py
+++ b/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive.py
@@ -24,7 +24,7 @@ from urlparse import urlparse
 
 from resource_management.libraries.script.script import Script
 from resource_management.libraries.resources.hdfs_resource import HdfsResource
-from resource_management.libraries.functions.copy_tarball import copy_to_hdfs
+from resource_management.libraries.functions import copy_tarball
 from resource_management.libraries.functions.get_config import get_config
 from resource_management.libraries.functions import StackFeature
 from resource_management.libraries.functions.stack_features import check_stack_feature
@@ -177,19 +177,19 @@ def setup_hiveserver2():
   # *********************************
   #  if copy tarball to HDFS feature  supported copy mapreduce.tar.gz and tez.tar.gz to HDFS
   if params.stack_version_formatted_major and check_stack_feature(StackFeature.COPY_TARBALL_TO_HDFS, params.stack_version_formatted_major):
-    copy_to_hdfs("mapreduce", params.user_group, params.hdfs_user, skip=params.sysprep_skip_copy_tarballs_hdfs)
-    copy_to_hdfs("tez", params.user_group, params.hdfs_user, skip=params.sysprep_skip_copy_tarballs_hdfs)
+    copy_tarball.copy_to_hdfs("mapreduce", params.user_group, params.hdfs_user, skip=params.sysprep_skip_copy_tarballs_hdfs)
+    copy_tarball.copy_to_hdfs("tez", params.user_group, params.hdfs_user, skip=params.sysprep_skip_copy_tarballs_hdfs)
 
   # Always copy pig.tar.gz and hive.tar.gz using the appropriate mode.
   # This can use a different source and dest location to account
-  copy_to_hdfs("pig",
+  copy_tarball.copy_to_hdfs("pig",
                params.user_group,
                params.hdfs_user,
                file_mode=params.tarballs_mode,
                custom_source_file=params.pig_tar_source,
                custom_dest_file=params.pig_tar_dest_file,
                skip=params.sysprep_skip_copy_tarballs_hdfs)
-  copy_to_hdfs("hive",
+  copy_tarball.copy_to_hdfs("hive",
                params.user_group,
                params.hdfs_user,
                file_mode=params.tarballs_mode,
@@ -210,7 +210,7 @@ def setup_hiveserver2():
       src_filename = os.path.basename(source_file)
       dest_file = os.path.join(dest_dir, src_filename)
 
-      copy_to_hdfs(tarball_name,
+      copy_tarball.copy_to_hdfs(tarball_name,
                    params.user_group,
                    params.hdfs_user,
                    file_mode=params.tarballs_mode,


[13/49] ambari git commit: BUG-91896. Moving Metrics Collector Forces ZooKeeper Server Install on Target Host (alexantonenko)

Posted by rl...@apache.org.
BUG-91896. Moving Metrics Collector Forces ZooKeeper Server Install on Target Host (alexantonenko)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 3f836c0a5dc97d47a4bdb6192a4cc3cdeea643ac
Parents: 9910c49
Author: Alex Antonenko <aa...@hortonworks.com>
Authored: Tue Nov 21 20:07:03 2017 +0300
Committer: Alex Antonenko <aa...@hortonworks.com>
Committed: Tue Nov 21 20:07:03 2017 +0300

----------------------------------------------------------------------
 .../main/service/reassign/step3_controller.js           |  3 +++
 .../main/service/reassign/step4_controller.js           | 12 ++++++++++--
 .../main/service/reassign/step4_controller_test.js      |  9 ++++++---
 3 files changed, 19 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3f836c0a/ambari-web/app/controllers/main/service/reassign/step3_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/reassign/step3_controller.js b/ambari-web/app/controllers/main/service/reassign/step3_controller.js
index 4898b75..d994aaf 100644
--- a/ambari-web/app/controllers/main/service/reassign/step3_controller.js
+++ b/ambari-web/app/controllers/main/service/reassign/step3_controller.js
@@ -286,6 +286,9 @@ App.ReassignMasterWizardStep3Controller = Em.Controller.extend({
         success: 'onLoadConfigsTags'
       });
     }
+    else{
+      this.set('isLoaded', true);
+    }
   },
 
   clearStep: function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/3f836c0a/ambari-web/app/controllers/main/service/reassign/step4_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/reassign/step4_controller.js b/ambari-web/app/controllers/main/service/reassign/step4_controller.js
index 108b3e9..8e854b0 100644
--- a/ambari-web/app/controllers/main/service/reassign/step4_controller.js
+++ b/ambari-web/app/controllers/main/service/reassign/step4_controller.js
@@ -108,13 +108,21 @@ App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageContro
    */
   setDependentHostComponents: function (componentName) {
     var installedServices = App.Service.find().mapProperty('serviceName');
-    var installedComponents = App.Host.find(this.get('content.reassignHosts.target'))
+    var hostInstalledComponents = App.Host.find(this.get('content.reassignHosts.target'))
         .get('hostComponents')
         .mapProperty('componentName');
+    var clusterInstalledComponents = App.MasterComponent.find().toArray()
+        .concat(App.ClientComponent.find().toArray())
+        .concat(App.SlaveComponent.find().toArray())
+        .filter(function(service){
+          return service.get("installedCount") > 0;
+        })
+        .mapProperty('componentName');
+
     var dependenciesToInstall = App.StackServiceComponent.find(componentName)
         .get('dependencies')
         .filter(function (component) {
-          return !installedComponents.contains(component.componentName) && installedServices.contains(component.serviceName);
+          return !(component.scope == 'host' ? hostInstalledComponents : clusterInstalledComponents).contains(component.componentName) && (installedServices.contains(component.serviceName));
         })
         .mapProperty('componentName');
     this.set('dependentHostComponents', dependenciesToInstall);

http://git-wip-us.apache.org/repos/asf/ambari/blob/3f836c0a/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js b/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
index 8eb9c9f..42f6f91 100644
--- a/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
+++ b/ambari-web/test/controllers/main/service/reassign/step4_controller_test.js
@@ -1104,15 +1104,18 @@ describe('App.ReassignMasterWizardStep4Controller', function () {
         dependencies: [
           Em.Object.create({
             componentName: 'C1',
-            serviceName: 'S1'
+            serviceName: 'S1',
+            scope: 'host'
           }),
           Em.Object.create({
             componentName: 'C2',
-            serviceName: 'S2'
+            serviceName: 'S2',
+            scope: 'host'
           }),
           Em.Object.create({
             componentName: 'C3',
-            serviceName: 'S3'
+            serviceName: 'S3',
+            scope: 'host'
           })
         ]
       }));


[22/49] ambari git commit: AMBARI-22469. Ambari upgrade failed (dlysnichenko)

Posted by rl...@apache.org.
AMBARI-22469. Ambari upgrade failed (dlysnichenko)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: b1acd1dfe214f1d381af6cdb54300daa78cbd37f
Parents: 5dd334c
Author: Lisnichenko Dmitro <dl...@hortonworks.com>
Authored: Wed Nov 22 17:04:42 2017 +0200
Committer: Lisnichenko Dmitro <dl...@hortonworks.com>
Committed: Wed Nov 22 17:06:30 2017 +0200

----------------------------------------------------------------------
 .../server/upgrade/UpgradeCatalog260.java       | 41 +++++++++++++++-----
 1 file changed, 31 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b1acd1df/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
index 11f79fe..25635b6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog260.java
@@ -17,8 +17,6 @@
  */
 package org.apache.ambari.server.upgrade;
 
-import static org.apache.ambari.server.view.ViewContextImpl.CORE_SITE;
-
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -134,9 +132,9 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog {
   public static final String HOST_COMPONENT_DESIRED_STATE = "hostcomponentdesiredstate";
   public static final String HOST_COMPONENT_STATE = "hostcomponentstate";
 
+  private static final String CORE_SITE = "core-site";
   public static final String AMS_SSL_CLIENT = "ams-ssl-client";
   public static final String METRIC_TRUSTSTORE_ALIAS = "ssl.client.truststore.alias";
-
   /**
    * Logger.
    */
@@ -193,7 +191,7 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog {
    */
   @Override
   protected void executeDDLUpdates() throws AmbariException, SQLException {
-    int currentVersionID = getCurrentVersionID();
+    Integer currentVersionID = getCurrentVersionID();
     dropBrokenFK();
     updateServiceComponentDesiredStateTable(currentVersionID);
     updateServiceDesiredStateTable(currentVersionID);
@@ -360,10 +358,13 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog {
    * Removes {@value #FK_SDS_DESIRED_STACK_ID} foreign key.
    * adds {@value #FK_REPO_VERSION_ID} foreign key.
    *
+   * @param currentRepoID id of current repo_version. Can be null if there are no cluster repo versions
+   *                      (in this case {@value #SERVICE_DESIRED_STATE_TABLE} table must be empty)
+   *
    * @throws java.sql.SQLException
    */
-  private void updateServiceDesiredStateTable(int currentRepoID) throws SQLException {
-
+  private void updateServiceDesiredStateTable(Integer currentRepoID) throws SQLException {
+    //in case if currentRepoID is null {@value #SERVICE_DESIRED_STATE_TABLE} table must be empty and null defaultValue is ok for non-nullable column
     dbAccessor.addColumn(SERVICE_DESIRED_STATE_TABLE,
         new DBAccessor.DBColumnInfo(DESIRED_REPO_VERSION_ID_COLUMN, Long.class, null, currentRepoID, false));
     dbAccessor.alterColumn(SERVICE_DESIRED_STATE_TABLE,
@@ -413,9 +414,13 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog {
    * Removes {@value #FK_SCDS_DESIRED_STACK_ID} foreign key.
    * adds {@value #FK_SCDS_DESIRED_REPO_ID} foreign key.
    *
+   * @param currentRepoID id of current repo_version. Can be null if there are no cluster repo versions
+   *                      (in this case {@value #SERVICE_DESIRED_STATE_TABLE} table must be empty)
+   *
    * @throws java.sql.SQLException
    */
-  private void updateServiceComponentDesiredStateTable(int currentRepoID) throws SQLException {
+  private void updateServiceComponentDesiredStateTable(Integer currentRepoID) throws SQLException {
+    //in case if currentRepoID is null {@value #SERVICE_DESIRED_STATE_TABLE} table must be empty and null defaultValue is ok for non-nullable column
     dbAccessor.addColumn(SERVICE_COMPONENT_DESIRED_STATE_TABLE,
         new DBAccessor.DBColumnInfo(DESIRED_REPO_VERSION_ID_COLUMN, Long.class, null, currentRepoID, false));
     dbAccessor.alterColumn(SERVICE_COMPONENT_DESIRED_STATE_TABLE,
@@ -496,11 +501,27 @@ public class UpgradeCatalog260 extends AbstractUpgradeCatalog {
     updateExistingRepositoriesToBeResolved();
   }
 
-  public int getCurrentVersionID() throws AmbariException, SQLException {
+  /**
+   * get {@value #REPO_VERSION_ID_COLUMN} value from {@value #CLUSTER_VERSION_TABLE}
+   * where {@value #STATE_COLUMN} = {@value #CURRENT}
+   * and validate it
+   *
+   * @return current version ID or null if no cluster versions do exist
+   * @throws AmbariException if cluster versions are present, but current is not selected
+   * @throws SQLException
+   */
+  public Integer getCurrentVersionID() throws AmbariException, SQLException {
     List<Integer> currentVersionList = dbAccessor.getIntColumnValues(CLUSTER_VERSION_TABLE, REPO_VERSION_ID_COLUMN,
         new String[]{STATE_COLUMN}, new String[]{CURRENT}, false);
-    if (currentVersionList.size() != 1) {
-      throw new AmbariException("Can't get current version id");
+    if (currentVersionList.isEmpty()) {
+      List<Integer> allVersionList = dbAccessor.getIntColumnValues(CLUSTER_VERSION_TABLE, REPO_VERSION_ID_COLUMN, null, null,false);
+      if (allVersionList.isEmpty()){
+        return null;
+      } else {
+        throw new AmbariException("Unable to find any CURRENT repositories.");
+      }
+    } else if (currentVersionList.size() != 1) {
+      throw new AmbariException("The following repositories were found to be CURRENT: ".concat(StringUtils.join(currentVersionList, ",")));
     }
     return currentVersionList.get(0);
   }


[17/49] ambari git commit: AMBARI-22467. YARN, MapReduce2, Hive, and Oozie Should Conditionally Install LZO (aonishuk)

Posted by rl...@apache.org.
AMBARI-22467. YARN, MapReduce2, Hive, and Oozie Should Conditionally Install LZO (aonishuk)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 7eb14a0a563eb478d3e47d910c4dbf66b05fdfdf
Parents: 135d88b
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Wed Nov 22 13:45:30 2017 +0200
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Wed Nov 22 13:45:30 2017 +0200

----------------------------------------------------------------------
 .../libraries/functions/__init__.py             |  2 +-
 .../libraries/functions/get_lzo_packages.py     | 50 -----------
 .../libraries/functions/lzo_utils.py            | 93 ++++++++++++++++++++
 .../libraries/functions/package_conditions.py   |  8 +-
 .../common-services/HDFS/2.1.0.2.0/metainfo.xml | 30 -------
 .../HDFS/2.1.0.2.0/package/scripts/hdfs.py      |  7 +-
 .../2.1.0.2.0/package/scripts/install_params.py |  4 -
 .../2.1.0.2.0/package/scripts/params_linux.py   |  5 --
 .../common-services/HDFS/3.0.0.3.0/metainfo.xml | 30 -------
 .../HDFS/3.0.0.3.0/package/scripts/hdfs.py      |  7 +-
 .../3.0.0.3.0/package/scripts/install_params.py |  4 -
 .../3.0.0.3.0/package/scripts/params_linux.py   |  4 -
 .../HIVE/0.12.0.2.0/package/scripts/hive.py     |  3 +
 .../HIVE/2.1.0.3.0/package/scripts/hive.py      |  3 +
 .../OOZIE/4.0.0.2.0/package/scripts/oozie.py    | 38 ++++----
 .../4.0.0.2.0/package/scripts/params_linux.py   |  5 +-
 .../OOZIE/4.2.0.3.0/package/scripts/oozie.py    | 16 ++--
 .../4.2.0.3.0/package/scripts/params_linux.py   |  5 +-
 .../YARN/2.1.0.2.0/package/scripts/yarn.py      |  3 +
 .../YARN/3.0.0.3.0/package/scripts/yarn.py      |  3 +
 .../stacks/HDP/2.2/services/HDFS/metainfo.xml   | 35 --------
 .../stacks/HDP/2.3/services/HDFS/metainfo.xml   | 30 -------
 .../stacks/HDP/3.0/services/HDFS/metainfo.xml   | 30 -------
 .../stacks/2.2/configs/oozie-upgrade.json       |  3 +-
 24 files changed, 142 insertions(+), 276 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-common/src/main/python/resource_management/libraries/functions/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/__init__.py b/ambari-common/src/main/python/resource_management/libraries/functions/__init__.py
index f144b2d..b907844 100644
--- a/ambari-common/src/main/python/resource_management/libraries/functions/__init__.py
+++ b/ambari-common/src/main/python/resource_management/libraries/functions/__init__.py
@@ -39,7 +39,7 @@ from resource_management.libraries.functions.version import *
 from resource_management.libraries.functions.format_jvm_option import *
 from resource_management.libraries.functions.constants import *
 from resource_management.libraries.functions.get_stack_version import *
-from resource_management.libraries.functions.get_lzo_packages import *
+from resource_management.libraries.functions.lzo_utils import *
 from resource_management.libraries.functions.setup_ranger_plugin import *
 from resource_management.libraries.functions.curl_krb_request import *
 from resource_management.libraries.functions.get_bare_principal import *

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-common/src/main/python/resource_management/libraries/functions/get_lzo_packages.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/get_lzo_packages.py b/ambari-common/src/main/python/resource_management/libraries/functions/get_lzo_packages.py
deleted file mode 100644
index cfbb7d8..0000000
--- a/ambari-common/src/main/python/resource_management/libraries/functions/get_lzo_packages.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python
-"""
-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.
-
-Ambari Agent
-
-"""
-__all__ = ["get_lzo_packages"]
-
-from ambari_commons.os_check import OSCheck
-from resource_management.libraries.functions.stack_features import check_stack_feature
-from resource_management.libraries.functions import StackFeature
-from resource_management.libraries.script.script import Script
-
-# TODO: Make list of lzo packages stack driven
-def get_lzo_packages(stack_version_unformatted):
-  lzo_packages = []
-  script_instance = Script.get_instance()
-  if OSCheck.is_suse_family() and int(OSCheck.get_os_major_version()) >= 12:
-    lzo_packages += ["liblzo2-2", "hadoop-lzo-native"]
-  elif OSCheck.is_redhat_family() or OSCheck.is_suse_family():
-    lzo_packages += ["lzo", "hadoop-lzo-native"]
-  elif OSCheck.is_ubuntu_family():
-    lzo_packages += ["liblzo2-2"]
-
-  if stack_version_unformatted and check_stack_feature(StackFeature.ROLLING_UPGRADE, stack_version_unformatted):
-    if OSCheck.is_ubuntu_family():
-      lzo_packages += [script_instance.format_package_name("hadooplzo-${stack_version}") ,
-                       script_instance.format_package_name("hadooplzo-${stack_version}-native")]
-    else:
-      lzo_packages += [script_instance.format_package_name("hadooplzo_${stack_version}"),
-                       script_instance.format_package_name("hadooplzo_${stack_version}-native")]
-  else:
-    lzo_packages += ["hadoop-lzo"]
-
-  return lzo_packages

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-common/src/main/python/resource_management/libraries/functions/lzo_utils.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/lzo_utils.py b/ambari-common/src/main/python/resource_management/libraries/functions/lzo_utils.py
new file mode 100644
index 0000000..d6d987f
--- /dev/null
+++ b/ambari-common/src/main/python/resource_management/libraries/functions/lzo_utils.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+__all__ = ["should_install_lzo", "get_lzo_packages", "install_lzo_if_needed"]
+
+from ambari_commons.os_check import OSCheck
+from resource_management.libraries.functions.stack_features import check_stack_feature
+from resource_management.libraries.functions.default import default
+from resource_management.libraries.functions import StackFeature, stack_features
+from resource_management.libraries.script.script import Script
+from resource_management.core.logger import Logger
+from resource_management.libraries.functions.expect import expect
+from resource_management.core.resources.packaging import Package
+
+INSTALLING_LZO_WITHOUT_GPL = "Cannot install LZO.  The GPL license must be explicitly enabled using 'ambari-server setup' on the Ambari host, then restart the server and try again."
+
+def get_lzo_packages():
+  lzo_packages = []
+  script_instance = Script.get_instance()
+  if OSCheck.is_suse_family() and int(OSCheck.get_os_major_version()) >= 12:
+    lzo_packages += ["liblzo2-2", "hadoop-lzo-native"]
+  elif OSCheck.is_redhat_family() or OSCheck.is_suse_family():
+    lzo_packages += ["lzo", "hadoop-lzo-native"]
+  elif OSCheck.is_ubuntu_family():
+    lzo_packages += ["liblzo2-2"]
+
+
+  stack_version_unformatted = stack_features.get_stack_feature_version(Script.get_config()) # only used to check stack_feature, NOT as package version!
+  if stack_version_unformatted and check_stack_feature(StackFeature.ROLLING_UPGRADE, stack_version_unformatted):
+    if OSCheck.is_ubuntu_family():
+      lzo_packages += [script_instance.format_package_name("hadooplzo-${stack_version}") ,
+                       script_instance.format_package_name("hadooplzo-${stack_version}-native")]
+    else:
+      lzo_packages += [script_instance.format_package_name("hadooplzo_${stack_version}"),
+                       script_instance.format_package_name("hadooplzo_${stack_version}-native")]
+  else:
+    lzo_packages += ["hadoop-lzo"]
+
+  return lzo_packages
+
+def should_install_lzo():
+  """
+  Return true if lzo is enabled via core-site.xml and GPL license (required for lzo) is accepted.
+  """
+  config = Script.get_config()
+  io_compression_codecs = default("/configurations/core-site/io.compression.codecs", None)
+  lzo_enabled = io_compression_codecs is not None and "com.hadoop.compression.lzo" in io_compression_codecs.lower()
+
+  if not lzo_enabled:
+    return False
+
+  is_gpl_license_accepted = default("/hostLevelParams/gpl_license_accepted", False)
+  if not is_gpl_license_accepted:
+    Logger.warning(INSTALLING_LZO_WITHOUT_GPL)
+    return False
+
+  return True
+
+def install_lzo_if_needed():
+  """
+  Install lzo package if {#should_install_lzo} is true
+  """
+  if not should_install_lzo():
+    return
+
+  lzo_packages = get_lzo_packages()
+
+  config = Script.get_config()
+  agent_stack_retry_on_unavailability = config['hostLevelParams']['agent_stack_retry_on_unavailability']
+  agent_stack_retry_count = expect("/hostLevelParams/agent_stack_retry_count", int)
+
+  Package(lzo_packages,
+          retry_on_repo_unavailability=agent_stack_retry_on_unavailability,
+          retry_count=agent_stack_retry_count
+  )

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-common/src/main/python/resource_management/libraries/functions/package_conditions.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/package_conditions.py b/ambari-common/src/main/python/resource_management/libraries/functions/package_conditions.py
index 31e78b9..ded63cf 100644
--- a/ambari-common/src/main/python/resource_management/libraries/functions/package_conditions.py
+++ b/ambari-common/src/main/python/resource_management/libraries/functions/package_conditions.py
@@ -19,7 +19,7 @@ limitations under the License.
 Ambari Agent
 
 """
-__all__ = ["is_lzo_enabled", "should_install_phoenix", "should_install_ams_collector", "should_install_ams_grafana",
+__all__ = ["should_install_phoenix", "should_install_ams_collector", "should_install_ams_grafana",
            "should_install_mysql", "should_install_ranger_tagsync"]
 
 import os
@@ -44,12 +44,6 @@ def _has_local_components(config, components, indicator_function = any):
 def _has_applicable_local_component(config, components):
   return _has_local_components(config, components, any)
 
-def should_install_lzo():
-  config = Script.get_config()
-  io_compression_codecs = default("/configurations/core-site/io.compression.codecs", None)
-  lzo_enabled = io_compression_codecs is not None and "com.hadoop.compression.lzo" in io_compression_codecs.lower()
-  return lzo_enabled
-
 def should_install_phoenix():
   phoenix_hosts = default('/clusterHostInfo/phoenix_query_server_hosts', [])
   phoenix_enabled = default('/configurations/hbase-env/phoenix_sql_enabled', False)

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml
index 9979de4..6bbb583 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml
+++ b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml
@@ -244,11 +244,6 @@
             <package>
               <name>hadoop</name>
             </package>
-            <package>
-              <name>hadoop-lzo</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
           </packages>
         </osSpecific>
         
@@ -265,16 +260,6 @@
               <name>snappy-devel</name>
             </package>
             <package>
-              <name>lzo</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadoop-lzo-native</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop-libhdfs</name>
             </package>
             <package>
@@ -296,16 +281,6 @@
               <name>snappy-devel</name>
             </package>
             <package>
-              <name>liblzo2-2</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadoop-lzo-native</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop-libhdfs</name>
             </package>
           </packages>
@@ -324,11 +299,6 @@
               <name>libsnappy-dev</name>
             </package>
             <package>
-              <name>liblzo2-2</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop-hdfs</name>
             </package>
             <package>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/hdfs.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/hdfs.py b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/hdfs.py
index 4022986..bc80ba6 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/hdfs.py
+++ b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/hdfs.py
@@ -33,6 +33,7 @@ from resource_management.libraries.functions.format import format
 import os
 from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl
 from ambari_commons import OSConst
+from resource_management.libraries.functions.lzo_utils import install_lzo_if_needed
 
 @OsFamilyFuncImpl(os_family=OsFamilyImpl.DEFAULT)
 def hdfs(name=None):
@@ -143,11 +144,7 @@ def hdfs(name=None):
        content=Template("slaves.j2")
   )
   
-  if params.lzo_enabled:
-    lzo_packages = get_lzo_packages(params.stack_version_unformatted)
-    Package(lzo_packages,
-            retry_on_repo_unavailability=params.agent_stack_retry_on_unavailability,
-            retry_count=params.agent_stack_retry_count)
+  install_lzo_if_needed()
       
 def install_snappy():
   import params

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/install_params.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/install_params.py b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/install_params.py
index 235f231..dc3279f 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/install_params.py
+++ b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/install_params.py
@@ -27,7 +27,3 @@ else:
 
   _config = Script.get_config()
   stack_version_unformatted = str(_config['hostLevelParams']['stack_version'])
-
-  # The logic for LZO also exists in OOZIE's params.py
-  io_compression_codecs = default("/configurations/core-site/io.compression.codecs", None)
-  lzo_enabled = io_compression_codecs is not None and "com.hadoop.compression.lzo" in io_compression_codecs.lower()

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/params_linux.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/params_linux.py b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/params_linux.py
index bb6349b..e2790e1 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/params_linux.py
+++ b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/package/scripts/params_linux.py
@@ -383,11 +383,6 @@ HdfsResource = functools.partial(
   immutable_paths = get_not_managed_resources(),
   dfs_type = dfs_type
 )
-
-
-# The logic for LZO also exists in OOZIE's params.py
-io_compression_codecs = default("/configurations/core-site/io.compression.codecs", None)
-lzo_enabled = io_compression_codecs is not None and "com.hadoop.compression.lzo" in io_compression_codecs.lower()
   
 name_node_params = default("/commandParams/namenode", None)
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/metainfo.xml b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/metainfo.xml
index e6d1166..0c629f3 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/metainfo.xml
+++ b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/metainfo.xml
@@ -270,11 +270,6 @@
             <package>
               <name>hadoop</name>
             </package>
-            <package>
-              <name>hadoop-lzo</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
           </packages>
         </osSpecific>
         
@@ -291,16 +286,6 @@
               <name>snappy-devel</name>
             </package>
             <package>
-              <name>lzo</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadoop-lzo-native</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop-libhdfs</name>
             </package>
           </packages>
@@ -319,16 +304,6 @@
               <name>snappy-devel</name>
             </package>
             <package>
-              <name>liblzo2-2</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadoop-lzo-native</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop-libhdfs</name>
             </package>
           </packages>
@@ -347,11 +322,6 @@
               <name>libsnappy-dev</name>
             </package>
             <package>
-              <name>liblzo2-2</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop-hdfs</name>
             </package>
             <package>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/hdfs.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/hdfs.py b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/hdfs.py
index 4022986..bc80ba6 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/hdfs.py
+++ b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/hdfs.py
@@ -33,6 +33,7 @@ from resource_management.libraries.functions.format import format
 import os
 from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl
 from ambari_commons import OSConst
+from resource_management.libraries.functions.lzo_utils import install_lzo_if_needed
 
 @OsFamilyFuncImpl(os_family=OsFamilyImpl.DEFAULT)
 def hdfs(name=None):
@@ -143,11 +144,7 @@ def hdfs(name=None):
        content=Template("slaves.j2")
   )
   
-  if params.lzo_enabled:
-    lzo_packages = get_lzo_packages(params.stack_version_unformatted)
-    Package(lzo_packages,
-            retry_on_repo_unavailability=params.agent_stack_retry_on_unavailability,
-            retry_count=params.agent_stack_retry_count)
+  install_lzo_if_needed()
       
 def install_snappy():
   import params

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/install_params.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/install_params.py b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/install_params.py
index 235f231..dc3279f 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/install_params.py
+++ b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/install_params.py
@@ -27,7 +27,3 @@ else:
 
   _config = Script.get_config()
   stack_version_unformatted = str(_config['hostLevelParams']['stack_version'])
-
-  # The logic for LZO also exists in OOZIE's params.py
-  io_compression_codecs = default("/configurations/core-site/io.compression.codecs", None)
-  lzo_enabled = io_compression_codecs is not None and "com.hadoop.compression.lzo" in io_compression_codecs.lower()

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/params_linux.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/params_linux.py b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/params_linux.py
index 2fa6208..cbe7943 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/params_linux.py
+++ b/ambari-server/src/main/resources/common-services/HDFS/3.0.0.3.0/package/scripts/params_linux.py
@@ -373,10 +373,6 @@ HdfsResource = functools.partial(
   dfs_type = dfs_type
 )
 
-
-# The logic for LZO also exists in OOZIE's params.py
-io_compression_codecs = default("/configurations/core-site/io.compression.codecs", None)
-lzo_enabled = io_compression_codecs is not None and "com.hadoop.compression.lzo" in io_compression_codecs.lower()
   
 name_node_params = default("/commandParams/namenode", None)
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive.py b/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive.py
index c4b34a5..716a37c 100644
--- a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive.py
+++ b/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/package/scripts/hive.py
@@ -42,6 +42,7 @@ from resource_management.core.logger import Logger
 from resource_management.core import utils
 from resource_management.libraries.functions.setup_atlas_hook import has_atlas_in_cluster, setup_atlas_hook
 from resource_management.libraries.functions.security_commons import update_credential_provider_path
+from resource_management.libraries.functions.lzo_utils import install_lzo_if_needed
 from ambari_commons.constants import SERVICE
 
 from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl
@@ -50,6 +51,8 @@ from ambari_commons import OSConst
 @OsFamilyFuncImpl(os_family=OsFamilyImpl.DEFAULT)
 def hive(name=None):
   import params
+  
+  install_lzo_if_needed()
 
   hive_client_conf_path = format("{stack_root}/current/{component_directory}/conf")
   # Permissions 644 for conf dir (client) files, and 600 for conf.server

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/HIVE/2.1.0.3.0/package/scripts/hive.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HIVE/2.1.0.3.0/package/scripts/hive.py b/ambari-server/src/main/resources/common-services/HIVE/2.1.0.3.0/package/scripts/hive.py
index 22ff9fd..1724bae 100644
--- a/ambari-server/src/main/resources/common-services/HIVE/2.1.0.3.0/package/scripts/hive.py
+++ b/ambari-server/src/main/resources/common-services/HIVE/2.1.0.3.0/package/scripts/hive.py
@@ -42,6 +42,7 @@ from resource_management.core.logger import Logger
 from resource_management.core import utils
 from resource_management.libraries.functions.setup_atlas_hook import has_atlas_in_cluster, setup_atlas_hook
 from resource_management.libraries.functions.security_commons import update_credential_provider_path
+from resource_management.libraries.functions.lzo_utils import install_lzo_if_needed
 from ambari_commons.constants import SERVICE
 
 from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl
@@ -50,6 +51,8 @@ from ambari_commons import OSConst
 @OsFamilyFuncImpl(os_family=OsFamilyImpl.DEFAULT)
 def hive(name=None):
   import params
+  
+  install_lzo_if_needed()
 
   hive_client_conf_path = format("{stack_root}/current/{component_directory}/conf")
   # Permissions 644 for conf dir (client) files, and 600 for conf.server

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py b/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
index f215a1e..2306108 100644
--- a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
+++ b/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/oozie.py
@@ -35,6 +35,7 @@ from resource_management.libraries.functions.stack_features import check_stack_f
 from resource_management.libraries.functions.oozie_prepare_war import prepare_war
 from resource_management.libraries.functions.copy_tarball import get_current_version
 from resource_management.libraries.resources.xml_config import XmlConfig
+from resource_management.libraries.functions.lzo_utils import install_lzo_if_needed
 from resource_management.libraries.script.script import Script
 from resource_management.libraries.functions.security_commons import update_credential_provider_path
 from resource_management.libraries.functions.get_lzo_packages import get_lzo_packages
@@ -190,6 +191,12 @@ def oozie(is_server=False, upgrade_type=None):
 
   oozie_ownership()
   
+  if params.lzo_enabled:
+    install_lzo_if_needed()
+    Execute(format('{sudo} cp {hadoop_lib_home}/hadoop-lzo*.jar {oozie_lib_dir}'),
+      not_if  = no_op_test,
+    )
+  
   if is_server:
     oozie_server_specific(upgrade_type)
   
@@ -238,14 +245,14 @@ def get_oozie_ext_zip_source_paths(upgrade_type, params):
 
 def oozie_server_specific(upgrade_type):
   import params
-  
+
   no_op_test = as_user(format("ls {pid_file} >/dev/null 2>&1 && ps -p `cat {pid_file}` >/dev/null 2>&1"), user=params.oozie_user)
-  
+
   File(params.pid_file,
     action="delete",
     not_if=no_op_test
   )
-  
+
   oozie_server_directories = [format("{oozie_home}/{oozie_tmp_dir}"), params.oozie_pid_dir, params.oozie_log_dir, params.oozie_tmp_dir, params.oozie_data_dir, params.oozie_lib_dir, params.oozie_webapps_dir, params.oozie_webapps_conf_dir, params.oozie_server_dir]
   Directory( oozie_server_directories,
     owner = params.oozie_user,
@@ -254,25 +261,25 @@ def oozie_server_specific(upgrade_type):
     create_parents = True,
     cd_access="a",
   )
-  
+
   Directory(params.oozie_libext_dir,
             create_parents = True,
   )
-  
+
   hashcode_file = format("{oozie_home}/.hashcode")
   skip_recreate_sharelib = format("test -f {hashcode_file} && test -d {oozie_home}/share")
 
   untar_sharelib = ('tar','-xvf',format('{oozie_home}/oozie-sharelib.tar.gz'),'-C',params.oozie_home)
 
   Execute( untar_sharelib,    # time-expensive
-    not_if  = format("{no_op_test} || {skip_recreate_sharelib}"), 
+    not_if  = format("{no_op_test} || {skip_recreate_sharelib}"),
     sudo = True,
   )
 
   configure_cmds = []
   # Default to /usr/share/$TARGETSTACK-oozie/ext-2.2.zip as the first path
   source_ext_zip_paths = get_oozie_ext_zip_source_paths(upgrade_type, params)
-  
+
   # Copy the first oozie ext-2.2.zip file that is found.
   # This uses a list to handle the cases when migrating from some versions of BigInsights to HDP.
   if source_ext_zip_paths is not None:
@@ -286,8 +293,8 @@ def oozie_server_specific(upgrade_type):
                 sudo=True,
                 )
         break
-  
-  
+
+
   Directory(params.oozie_webapps_conf_dir,
             owner = params.oozie_user,
             group = params.user_group,
@@ -306,15 +313,6 @@ def oozie_server_specific(upgrade_type):
     Execute(format('{sudo} chown {oozie_user}:{user_group} {oozie_libext_dir}/falcon-oozie-el-extension-*.jar'),
       not_if  = no_op_test)
 
-  if params.lzo_enabled:
-    all_lzo_packages = get_lzo_packages(params.stack_version_unformatted)
-    Package(all_lzo_packages,
-            retry_on_repo_unavailability=params.agent_stack_retry_on_unavailability,
-            retry_count=params.agent_stack_retry_count)
-    Execute(format('{sudo} cp {hadoop_lib_home}/hadoop-lzo*.jar {oozie_lib_dir}'),
-      not_if  = no_op_test,
-    )
-
   prepare_war(params)
 
   File(hashcode_file,
@@ -365,7 +363,7 @@ def oozie_server_specific(upgrade_type):
   Directory(params.oozie_server_dir,
     owner = params.oozie_user,
     group = params.user_group,
-    recursive_ownership = True,  
+    recursive_ownership = True,
   )
   if params.security_enabled:
     File(os.path.join(params.conf_dir, 'zkmigrator_jaas.conf'),
@@ -410,7 +408,7 @@ def copy_atlas_hive_hook_to_dfs_share_lib(upgrade_type=None, upgrade_direction=N
   effective_version = params.stack_version_formatted if upgrade_type is None else format_stack_version(params.version)
   if not check_stack_feature(StackFeature.ATLAS_HOOK_SUPPORT, effective_version):
     return
-    
+
   # Important that oozie_server_hostnames is sorted by name so that this only runs on a single Oozie server.
   if not (len(params.oozie_server_hostnames) > 0 and params.hostname == params.oozie_server_hostnames[0]):
     Logger.debug("Will not attempt to copy Atlas Hive hook to DFS since this is not the first Oozie Server "

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/params_linux.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/params_linux.py b/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/params_linux.py
index a0f0672..125ecfe 100644
--- a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/params_linux.py
+++ b/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/package/scripts/params_linux.py
@@ -30,6 +30,7 @@ from resource_management.libraries.functions import get_port_from_url
 from resource_management.libraries.functions.get_not_managed_resources import get_not_managed_resources
 from resource_management.libraries.functions.setup_atlas_hook import has_atlas_in_cluster
 from resource_management.libraries.script.script import Script
+from resource_management.libraries.functions.lzo_utils import should_install_lzo
 from resource_management.libraries.functions.expect import expect
 from resource_management.libraries.resources.hdfs_resource import HdfsResource
 from resource_management.libraries.functions.get_architecture import get_architecture
@@ -384,6 +385,4 @@ HdfsResource = functools.partial(
 
 is_webhdfs_enabled = config['configurations']['hdfs-site']['dfs.webhdfs.enabled']
 
-# The logic for LZO also exists in HDFS' params.py
-io_compression_codecs = default("/configurations/core-site/io.compression.codecs", None)
-lzo_enabled = io_compression_codecs is not None and "com.hadoop.compression.lzo" in io_compression_codecs.lower()
+lzo_enabled = should_install_lzo()

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py b/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py
index 0771e93..1db16a9 100644
--- a/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py
+++ b/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/oozie.py
@@ -35,6 +35,7 @@ from resource_management.libraries.functions.stack_features import check_stack_f
 from resource_management.libraries.functions.oozie_prepare_war import prepare_war
 from resource_management.libraries.functions.copy_tarball import get_current_version
 from resource_management.libraries.resources.xml_config import XmlConfig
+from resource_management.libraries.functions.lzo_utils import install_lzo_if_needed
 from resource_management.libraries.script.script import Script
 from resource_management.libraries.functions.security_commons import update_credential_provider_path
 from resource_management.core.resources.packaging import Package
@@ -189,6 +190,12 @@ def oozie(is_server=False):
 
   oozie_ownership()
   
+  if params.lzo_enabled:
+    install_lzo_if_needed()
+    Execute(format('{sudo} cp {hadoop_lib_home}/hadoop-lzo*.jar {oozie_lib_dir}'),
+      not_if  = no_op_test,
+    )
+  
   if is_server:      
     oozie_server_specific()
   
@@ -275,15 +282,6 @@ def oozie_server_specific():
     Execute(format('{sudo} chown {oozie_user}:{user_group} {oozie_libext_dir}/falcon-oozie-el-extension-*.jar'),
       not_if  = no_op_test)
 
-  if params.lzo_enabled:
-    all_lzo_packages = get_lzo_packages(params.stack_version_unformatted)
-    Package(all_lzo_packages,
-            retry_on_repo_unavailability=params.agent_stack_retry_on_unavailability,
-            retry_count=params.agent_stack_retry_count)
-    Execute(format('{sudo} cp {hadoop_lib_home}/hadoop-lzo*.jar {oozie_lib_dir}'),
-      not_if  = no_op_test,
-    )
-
   prepare_war(params)
 
   File(hashcode_file,

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/params_linux.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/params_linux.py b/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/params_linux.py
index 70b89b7..1ae86e8 100644
--- a/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/params_linux.py
+++ b/ambari-server/src/main/resources/common-services/OOZIE/4.2.0.3.0/package/scripts/params_linux.py
@@ -28,6 +28,7 @@ from resource_management.libraries.functions import get_port_from_url
 from resource_management.libraries.functions.get_not_managed_resources import get_not_managed_resources
 from resource_management.libraries.functions.setup_atlas_hook import has_atlas_in_cluster
 from resource_management.libraries.script.script import Script
+from resource_management.libraries.functions.lzo_utils import should_install_lzo
 from resource_management.libraries.functions.expect import expect
 from resource_management.libraries.resources.hdfs_resource import HdfsResource
 from resource_management.libraries.functions.get_architecture import get_architecture
@@ -366,6 +367,4 @@ HdfsResource = functools.partial(
 
 is_webhdfs_enabled = config['configurations']['hdfs-site']['dfs.webhdfs.enabled']
 
-# The logic for LZO also exists in HDFS' params.py
-io_compression_codecs = default("/configurations/core-site/io.compression.codecs", None)
-lzo_enabled = io_compression_codecs is not None and "com.hadoop.compression.lzo" in io_compression_codecs.lower()
+lzo_enabled = should_install_lzo()

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/yarn.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/yarn.py b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/yarn.py
index 363d464..d077c84 100644
--- a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/yarn.py
+++ b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/yarn.py
@@ -27,6 +27,7 @@ from resource_management.libraries.script.script import Script
 from resource_management.core.resources.service import ServiceConfig
 from resource_management.libraries.functions.format import format
 from resource_management.libraries.functions.is_empty import is_empty
+from resource_management.libraries.functions.lzo_utils import install_lzo_if_needed
 from resource_management.core.resources.system import Directory
 from resource_management.core.resources.system import File
 from resource_management.libraries.resources.xml_config import XmlConfig
@@ -45,6 +46,8 @@ def yarn(name=None, config_dir=None):
   """
   import params
 
+  install_lzo_if_needed()
+
   if config_dir is None:
     config_dir = params.hadoop_conf_dir
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/common-services/YARN/3.0.0.3.0/package/scripts/yarn.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/YARN/3.0.0.3.0/package/scripts/yarn.py b/ambari-server/src/main/resources/common-services/YARN/3.0.0.3.0/package/scripts/yarn.py
index ef314f3..7731aeb 100644
--- a/ambari-server/src/main/resources/common-services/YARN/3.0.0.3.0/package/scripts/yarn.py
+++ b/ambari-server/src/main/resources/common-services/YARN/3.0.0.3.0/package/scripts/yarn.py
@@ -27,6 +27,7 @@ from resource_management.libraries.script.script import Script
 from resource_management.core.resources.service import ServiceConfig
 from resource_management.libraries.functions.format import format
 from resource_management.libraries.functions.is_empty import is_empty
+from resource_management.libraries.functions.lzo_utils import install_lzo_if_needed
 from resource_management.core.resources.system import Directory
 from resource_management.core.resources.system import File
 from resource_management.libraries.resources.xml_config import XmlConfig
@@ -44,6 +45,8 @@ def yarn(name=None, config_dir=None):
   :param config_dir: Which config directory to write configs to, which could be different during rolling upgrade.
   """
   import params
+  
+  install_lzo_if_needed()
 
   if config_dir is None:
     config_dir = params.hadoop_conf_dir

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/stacks/HDP/2.2/services/HDFS/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/HDFS/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/HDFS/metainfo.xml
index 8c2ec8b..d7221b9 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/HDFS/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/HDFS/metainfo.xml
@@ -40,19 +40,6 @@
               <name>snappy-devel</name>
             </package>
             <package>
-              <name>lzo</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}-native</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop_${stack_version}-libhdfs</name>
             </package>
             <package>
@@ -77,19 +64,6 @@
               <name>snappy-devel</name>
             </package>
             <package>
-              <name>liblzo2-2</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}-native</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop_${stack_version}-libhdfs</name>
             </package>
           </packages>
@@ -123,15 +97,6 @@
               <name>libsnappy-dev</name>
             </package>
             <package>
-              <name>hadooplzo-${stack_version}</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>liblzo2-2</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>libhdfs0-${stack_version}</name>
             </package>
           </packages>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
index ccf9a4e..86531cc 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
@@ -72,19 +72,6 @@
               <name>snappy-devel</name>
             </package>
             <package>
-              <name>lzo</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}-native</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop_${stack_version}-libhdfs</name>
             </package>
             <package>
@@ -109,19 +96,6 @@
               <name>snappy-devel</name>
             </package>
             <package>
-              <name>liblzo2-2</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}-native</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop_${stack_version}-libhdfs</name>
             </package>
           </packages>
@@ -155,10 +129,6 @@
               <name>libsnappy-dev</name>
             </package>
             <package>
-              <name>hadooplzo-${stack_version}</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>libhdfs0-${stack_version}</name>
             </package>
           </packages>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/main/resources/stacks/HDP/3.0/services/HDFS/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/3.0/services/HDFS/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/3.0/services/HDFS/metainfo.xml
index 95a5f84..775508e 100644
--- a/ambari-server/src/main/resources/stacks/HDP/3.0/services/HDFS/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/3.0/services/HDFS/metainfo.xml
@@ -50,19 +50,6 @@
               <name>snappy-devel</name>
             </package>
             <package>
-              <name>lzo</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}-native</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop_${stack_version}-libhdfs</name>
             </package>
           </packages>
@@ -84,19 +71,6 @@
               <name>snappy-devel</name>
             </package>
             <package>
-              <name>liblzo2-2</name>
-              <skipUpgrade>true</skipUpgrade>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
-              <name>hadooplzo_${stack_version}-native</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>hadoop_${stack_version}-libhdfs</name>
             </package>
           </packages>
@@ -130,10 +104,6 @@
               <name>libsnappy-dev</name>
             </package>
             <package>
-              <name>hadooplzo-${stack_version}</name>
-              <condition>should_install_lzo</condition>
-            </package>
-            <package>
               <name>libhdfs0-${stack_version}</name>
             </package>
           </packages>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7eb14a0a/ambari-server/src/test/python/stacks/2.2/configs/oozie-upgrade.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/2.2/configs/oozie-upgrade.json b/ambari-server/src/test/python/stacks/2.2/configs/oozie-upgrade.json
index 86ca03a..29cbddc 100644
--- a/ambari-server/src/test/python/stacks/2.2/configs/oozie-upgrade.json
+++ b/ambari-server/src/test/python/stacks/2.2/configs/oozie-upgrade.json
@@ -55,7 +55,8 @@
         "mysql_jdbc_url": "http://c6401.ambari.apache.org:8080/resources//mysql-connector-java.jar",
         "custom_mysql_jdbc_name" : "mysql-connector-java.jar",
         "custom_oracle_jdbc_name" : "oracle-jdbc-driver.jar",
-        "custom_postgres_jdbc_name" : "test-postgres-jdbc.jar"
+        "custom_postgres_jdbc_name" : "test-postgres-jdbc.jar",
+        "gpl_license_accepted": "true"
     }, 
     "commandType": "EXECUTION_COMMAND", 
     "roleParams": {


[16/49] ambari git commit: AMBARI-22454. ambari-server upgrade to 2.6.1 should surface the GPL agreement (aonishuk)

Posted by rl...@apache.org.
AMBARI-22454. ambari-server upgrade to 2.6.1 should surface the GPL agreement (aonishuk)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 135d88bc1c9e650a6ff969bb1468cdd3a386a011
Parents: 930c7d5
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Wed Nov 22 13:31:36 2017 +0200
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Wed Nov 22 13:31:36 2017 +0200

----------------------------------------------------------------------
 .../python/ambari_server/serverConfiguration.py | 1532 ++++++++++++++++++
 .../main/python/ambari_server/serverSetup.py    |    5 +-
 2 files changed, 1535 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/135d88bc/ambari-server/src/main/python/ambari_server/serverConfiguration.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/serverConfiguration.py b/ambari-server/src/main/python/ambari_server/serverConfiguration.py
new file mode 100644
index 0000000..5eb12e1
--- /dev/null
+++ b/ambari-server/src/main/python/ambari_server/serverConfiguration.py
@@ -0,0 +1,1532 @@
+#!/usr/bin/env python
+
+'''
+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 datetime
+import glob
+import os
+import re
+import shutil
+import stat
+import string
+import sys
+import tempfile
+import getpass
+import ambari_server.serverClassPath
+
+from ambari_commons.exceptions import FatalException
+from ambari_commons.os_check import OSCheck, OSConst
+from ambari_commons.os_family_impl import OsFamilyImpl
+from ambari_commons.os_utils import run_os_command, search_file, set_file_permissions, parse_log4j_file
+from ambari_commons.logging_utils import get_debug_mode, print_info_msg, print_warning_msg, print_error_msg, \
+  set_debug_mode
+from ambari_server.properties import Properties
+from ambari_server.userInput import get_validated_string_input
+from ambari_server.utils import compare_versions, locate_file, on_powerpc
+from ambari_server.ambariPath import AmbariPath
+
+
+OS_VERSION = OSCheck().get_os_major_version()
+OS_TYPE = OSCheck.get_os_type()
+OS_FAMILY = OSCheck.get_os_family()
+
+PID_NAME = "ambari-server.pid"
+
+# Non-root user setup commands
+NR_USER_PROPERTY = "ambari-server.user"
+
+BLIND_PASSWORD = "*****"
+
+# Common messages
+PRESS_ENTER_MSG = "Press <enter> to continue."
+
+OS_FAMILY_PROPERTY = "server.os_family"
+OS_TYPE_PROPERTY = "server.os_type"
+
+BOOTSTRAP_DIR_PROPERTY = "bootstrap.dir"
+RECOMMENDATIONS_DIR_PROPERTY = 'recommendations.dir'
+
+AMBARI_CONF_VAR = "AMBARI_CONF_DIR"
+AMBARI_PROPERTIES_FILE = "ambari.properties"
+AMBARI_ENV_FILE = "ambari-env.sh"
+AMBARI_KRB_JAAS_LOGIN_FILE = "krb5JAASLogin.conf"
+GET_FQDN_SERVICE_URL = "server.fqdn.service.url"
+
+SERVER_OUT_FILE_KEY = "ambari.output.file.path"
+VERBOSE_OUTPUT_KEY = "ambari.output.verbose"
+
+DEBUG_MODE_KEY = "ambari.server.debug"
+SUSPEND_START_MODE_KEY = "ambari.server.debug.suspend.start"
+
+# Environment variables
+AMBARI_SERVER_LIB = "AMBARI_SERVER_LIB"
+JAVA_HOME = "JAVA_HOME"
+
+AMBARI_VERSION_VAR = "AMBARI_VERSION_VAR"
+
+# JDK
+JAVA_HOME_PROPERTY = "java.home"
+JDK_NAME_PROPERTY = "jdk.name"
+JCE_NAME_PROPERTY = "jce.name"
+JDK_DOWNLOAD_SUPPORTED_PROPERTY = "jdk.download.supported"
+JCE_DOWNLOAD_SUPPORTED_PROPERTY = "jce.download.supported"
+
+# Stack JDK
+STACK_JAVA_HOME_PROPERTY = "stack.java.home"
+STACK_JDK_NAME_PROPERTY = "stack.jdk.name"
+STACK_JCE_NAME_PROPERTY = "stack.jce.name"
+STACK_JAVA_VERSION = "stack.java.version"
+
+
+#TODO property used incorrectly in local case, it was meant to be dbms name, not postgres database name,
+# has workaround for now, as we don't need dbms name if persistence_type=local
+JDBC_DATABASE_PROPERTY = "server.jdbc.database"                 # E.g., embedded|oracle|mysql|mssql|postgres
+JDBC_DATABASE_NAME_PROPERTY = "server.jdbc.database_name"       # E.g., ambari. Not used on Windows.
+JDBC_HOSTNAME_PROPERTY = "server.jdbc.hostname"
+JDBC_PORT_PROPERTY = "server.jdbc.port"
+JDBC_POSTGRES_SCHEMA_PROPERTY = "server.jdbc.postgres.schema"   # Only for postgres, defaults to same value as DB name
+JDBC_SQLA_SERVER_NAME = "server.jdbc.sqla.server_name"
+
+JDBC_USER_NAME_PROPERTY = "server.jdbc.user.name"
+JDBC_PASSWORD_PROPERTY = "server.jdbc.user.passwd"
+JDBC_PASSWORD_FILENAME = "password.dat"
+JDBC_RCA_PASSWORD_FILENAME = "rca_password.dat"
+
+CLIENT_API_PORT_PROPERTY = "client.api.port"
+CLIENT_API_PORT = "8080"
+
+SERVER_VERSION_FILE_PATH = "server.version.file"
+
+PERSISTENCE_TYPE_PROPERTY = "server.persistence.type"
+JDBC_DRIVER_PROPERTY = "server.jdbc.driver"
+JDBC_URL_PROPERTY = "server.jdbc.url"
+
+# connection pool (age and time are in seconds)
+JDBC_CONNECTION_POOL_TYPE = "server.jdbc.connection-pool"
+JDBC_CONNECTION_POOL_ACQUISITION_SIZE = "server.jdbc.connection-pool.acquisition-size"
+JDBC_CONNECTION_POOL_MAX_AGE = "server.jdbc.connection-pool.max-age"
+JDBC_CONNECTION_POOL_MAX_IDLE_TIME = "server.jdbc.connection-pool.max-idle-time"
+JDBC_CONNECTION_POOL_MAX_IDLE_TIME_EXCESS = "server.jdbc.connection-pool.max-idle-time-excess"
+JDBC_CONNECTION_POOL_IDLE_TEST_INTERVAL = "server.jdbc.connection-pool.idle-test-interval"
+
+JDBC_RCA_DATABASE_PROPERTY = "server.jdbc.database"
+JDBC_RCA_HOSTNAME_PROPERTY = "server.jdbc.hostname"
+JDBC_RCA_PORT_PROPERTY = "server.jdbc.port"
+JDBC_RCA_SCHEMA_PROPERTY = "server.jdbc.schema"
+
+JDBC_RCA_DRIVER_PROPERTY = "server.jdbc.rca.driver"
+JDBC_RCA_URL_PROPERTY = "server.jdbc.rca.url"
+JDBC_RCA_USER_NAME_PROPERTY = "server.jdbc.rca.user.name"
+JDBC_RCA_PASSWORD_FILE_PROPERTY = "server.jdbc.rca.user.passwd"
+
+DEFAULT_DBMS_PROPERTY = "server.setup.default.dbms"
+
+JDBC_RCA_PASSWORD_ALIAS = "ambari.db.password"
+
+### # Windows-specific # ###
+
+JDBC_USE_INTEGRATED_AUTH_PROPERTY = "server.jdbc.use.integrated.auth"
+
+JDBC_RCA_USE_INTEGRATED_AUTH_PROPERTY = "server.jdbc.rca.use.integrated.auth"
+
+### # End Windows-specific # ###
+# The user which will bootstrap embedded postgres database setup by creating the default schema and ambari user.
+LOCAL_DATABASE_ADMIN_PROPERTY = "local.database.user"
+
+# resources repo configuration
+RESOURCES_DIR_PROPERTY = "resources.dir"
+
+# stack repo upgrade
+STACK_LOCATION_KEY = 'metadata.path'
+
+# LDAP security
+IS_LDAP_CONFIGURED = "ambari.ldap.isConfigured"
+LDAP_MGR_PASSWORD_ALIAS = "ambari.ldap.manager.password"
+LDAP_MGR_PASSWORD_PROPERTY = "authentication.ldap.managerPassword"
+LDAP_MGR_PASSWORD_FILENAME = "ldap-password.dat"
+LDAP_MGR_USERNAME_PROPERTY = "authentication.ldap.managerDn"
+LDAP_PRIMARY_URL_PROPERTY = "authentication.ldap.primaryUrl"
+
+# SSL truststore
+SSL_TRUSTSTORE_PASSWORD_ALIAS = "ambari.ssl.trustStore.password"
+SSL_TRUSTSTORE_PATH_PROPERTY = "ssl.trustStore.path"
+SSL_TRUSTSTORE_PASSWORD_PROPERTY = "ssl.trustStore.password"
+SSL_TRUSTSTORE_TYPE_PROPERTY = "ssl.trustStore.type"
+
+# SSL common
+SSL_API = 'api.ssl'
+SSL_API_PORT = 'client.api.ssl.port'
+DEFAULT_SSL_API_PORT = 8443
+
+# Kerberos
+CHECK_AMBARI_KRB_JAAS_CONFIGURATION_PROPERTY = "kerberos.check.jaas.configuration"
+
+# JDK
+JDK_RELEASES="java.releases"
+
+if on_powerpc():
+  JDK_RELEASES += ".ppc64le"
+
+VIEWS_DIR_PROPERTY = "views.dir"
+
+ACTIVE_INSTANCE_PROPERTY = "active.instance"
+
+# web server startup timeout
+WEB_SERVER_STARTUP_TIMEOUT = "server.startup.web.timeout"
+
+#Common setup or upgrade message
+SETUP_OR_UPGRADE_MSG = "- If this is a new setup, then run the \"ambari-server setup\" command to create the user\n" \
+                       "- If this is an upgrade of an existing setup, run the \"ambari-server upgrade\" command.\n" \
+                       "Refer to the Ambari documentation for more information on setup and upgrade."
+
+DEFAULT_DB_NAME = "ambari"
+
+SECURITY_KEYS_DIR = "security.server.keys_dir"
+EXTENSION_PATH_PROPERTY = 'extensions.path'
+COMMON_SERVICES_PATH_PROPERTY = 'common.services.path'
+MPACKS_STAGING_PATH_PROPERTY = 'mpacks.staging.path'
+WEBAPP_DIR_PROPERTY = 'webapp.dir'
+SHARED_RESOURCES_DIR = 'shared.resources.dir'
+BOOTSTRAP_SCRIPT = 'bootstrap.script'
+CUSTOM_ACTION_DEFINITIONS = 'custom.action.definitions'
+BOOTSTRAP_SETUP_AGENT_SCRIPT = 'bootstrap.setup_agent.script'
+STACKADVISOR_SCRIPT = 'stackadvisor.script'
+PID_DIR_PROPERTY = 'pid.dir'
+SERVER_TMP_DIR_PROPERTY = "server.tmp.dir"
+REQUIRED_PROPERTIES = [OS_FAMILY_PROPERTY, OS_TYPE_PROPERTY, COMMON_SERVICES_PATH_PROPERTY, SERVER_VERSION_FILE_PATH,
+                       WEBAPP_DIR_PROPERTY, STACK_LOCATION_KEY, SECURITY_KEYS_DIR, JDBC_DATABASE_NAME_PROPERTY,
+                       NR_USER_PROPERTY, JAVA_HOME_PROPERTY, JDBC_PASSWORD_PROPERTY, SHARED_RESOURCES_DIR,
+                       JDBC_USER_NAME_PROPERTY, BOOTSTRAP_SCRIPT, RESOURCES_DIR_PROPERTY, CUSTOM_ACTION_DEFINITIONS,
+                       BOOTSTRAP_SETUP_AGENT_SCRIPT, STACKADVISOR_SCRIPT, BOOTSTRAP_DIR_PROPERTY, PID_DIR_PROPERTY,
+                       MPACKS_STAGING_PATH_PROPERTY]
+
+# if these properties are available 'ambari-server setup -s' is not triggered again.
+SETUP_DONE_PROPERTIES = [OS_FAMILY_PROPERTY, OS_TYPE_PROPERTY, JDK_NAME_PROPERTY, JDBC_DATABASE_PROPERTY,
+                         NR_USER_PROPERTY, PERSISTENCE_TYPE_PROPERTY
+]
+
+def get_default_views_dir():
+  return AmbariPath.get("/var/lib/ambari-server/resources/views")
+
+def get_conf_dir():
+  try:
+    conf_dir = os.environ[AMBARI_CONF_VAR]
+    return conf_dir
+  except KeyError:
+    default_conf_dir = AmbariPath.get("/etc/ambari-server/conf")
+    print_info_msg("{0} is not set, using default {1}".format(AMBARI_CONF_VAR, default_conf_dir))
+    return default_conf_dir
+
+def find_properties_file():
+  conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
+  if conf_file is None:
+    err = 'File %s not found in search path $%s: %s' % (AMBARI_PROPERTIES_FILE,
+          AMBARI_CONF_VAR, get_conf_dir())
+    print_error_msg (err)
+    raise FatalException(1, err)
+  else:
+    print_info_msg('Loading properties from {0}'.format(conf_file))
+  return conf_file
+
+# Load ambari properties and return dict with values
+def get_ambari_properties():
+  conf_file = find_properties_file()
+
+  # Try to read ambari properties file. It is OK to fail.
+  # Return -1 on failure.
+  properties = None
+  try:
+    properties = Properties()
+    with open(conf_file) as hfR:
+      properties.load(hfR)
+  except (Exception), e:
+    print_error_msg ('Could not read "%s": %s' % (conf_file, str(e)))
+    return -1
+
+  # Try to replace $ROOT with the value from the OS environment.
+  # OK to fail. Just print the exception and return the properties
+  # dictionary read above
+  try:
+    root_env = 'ROOT'
+    if root_env in os.environ:
+      root = os.environ["ROOT"].rstrip("/")
+    else:
+      root = ''
+
+    for k,v in properties.iteritems():
+      properties.__dict__[k] = v.replace("$ROOT", root)
+      properties._props[k] = v.replace("$ROOT", root)
+  except (Exception), e:
+    print_error_msg ('Could not replace %s in "%s": %s' %(conf_file, root_env, str(e)))
+  return properties
+
+class ServerDatabaseType(object):
+  internal = 0
+  remote = 1
+
+
+class ServerDatabaseEntry(object):
+  def __init__(self, name, title, db_type, aliases=None):
+    """
+    :type name str
+    :type title str
+    :type db_type int
+    :type aliases list
+    """
+    self.__name = name
+    self.__title = title
+    self.__type = db_type
+    if aliases is None:
+      aliases = []
+
+    self.__aliases = aliases
+
+  @property
+  def name(self):
+    return self.__name
+
+  @property
+  def title(self):
+    return self.__title
+
+  @property
+  def dbtype(self):
+    return self.__type
+
+  def __str__(self):
+    return self.name
+
+  def __eq__(self, other):
+    if other is None:
+      return False
+
+    if isinstance(other, ServerDatabaseEntry):
+      return self.name == other.name and self.dbtype == other.dbtype
+    elif isinstance(other, str):
+      return self.name == other or other in self.__aliases
+
+    raise RuntimeError("Not compatible type")
+
+
+class ServerDatabases(object):
+  postgres = ServerDatabaseEntry("postgres", "Postgres", ServerDatabaseType.remote)
+  oracle = ServerDatabaseEntry("oracle", "Oracle", ServerDatabaseType.remote)
+  mysql = ServerDatabaseEntry("mysql", "MySQL", ServerDatabaseType.remote)
+  mssql = ServerDatabaseEntry("mssql", "MSSQL", ServerDatabaseType.remote)
+  derby = ServerDatabaseEntry("derby", "Derby", ServerDatabaseType.remote)
+  sqlanywhere = ServerDatabaseEntry("sqlanywhere", "SQL Anywhere", ServerDatabaseType.remote)
+  postgres_internal = ServerDatabaseEntry("postgres", "Embedded Postgres", ServerDatabaseType.internal, aliases=['embedded'])
+
+  @staticmethod
+  def databases():
+    props = ServerDatabases.__dict__
+    r_props = []
+    for p in props:
+      if isinstance(props[p], ServerDatabaseEntry):
+        r_props.append(props[p].name)
+
+    return set(r_props)
+
+  @staticmethod
+  def match(name):
+    """
+    :type name str
+    :rtype ServerDatabaseEntry
+    """
+    props = ServerDatabases.__dict__
+
+    for p in props:
+      if isinstance(props[p], ServerDatabaseEntry):
+        if name == props[p]:
+          return props[p]
+
+    return None
+
+class ServerConfigDefaults(object):
+  def __init__(self):
+    properties = get_ambari_properties()
+    if properties == -1:
+      print_error_msg("Error getting ambari properties")
+  
+    self.JAVA_SHARE_PATH = "/usr/share/java"
+    self.SHARE_PATH = "/usr/share"
+    self.OUT_DIR = parse_log4j_file(get_conf_dir() + "/log4j.properties")['ambari.log.dir'].replace("//", "/")
+    self.SERVER_OUT_FILE = os.path.join(self.OUT_DIR, "ambari-server.out")
+    self.SERVER_LOG_FILE = os.path.join(self.OUT_DIR, "ambari-server.log")
+    self.DB_CHECK_LOG = os.path.join(self.OUT_DIR, "ambari-server-check-database.log")
+    self.ROOT_FS_PATH = os.sep
+
+    self.JDK_INSTALL_DIR = ""
+    self.JDK_SEARCH_PATTERN = ""
+    self.JAVA_EXE_SUBPATH = ""
+    self.JDK_SECURITY_DIR = os.path.join("jre", "lib", "security")
+    self.SERVER_RESOURCES_DIR = ""
+
+    # Configuration defaults
+    self.DEFAULT_CONF_DIR = ""
+    if properties == -1:
+      self.PID_DIR = AmbariPath.get(os.sep + os.path.join("var", "run", "ambari-server"))
+      self.BOOTSTRAP_DIR = AmbariPath.get(os.sep + os.path.join("var", "run", "ambari-server", "bootstrap"))
+      self.RECOMMENDATIONS_DIR = AmbariPath.get(os.sep + os.path.join("var", "run", "ambari-server", "stack-recommendations"))
+    else:
+      self.PID_DIR = properties.get_property(PID_DIR_PROPERTY)
+      self.BOOTSTRAP_DIR = properties.get_property(BOOTSTRAP_DIR_PROPERTY)
+      self.RECOMMENDATIONS_DIR = properties.get_property(RECOMMENDATIONS_DIR_PROPERTY)
+    
+    # this directories should be pre-created by user and be writable.
+    self.check_if_directories_writable([self.OUT_DIR, self.PID_DIR])
+    
+    self.DEFAULT_LIBS_DIR = ""
+    self.DEFAULT_VLIBS_DIR = ""
+
+    self.AMBARI_PROPERTIES_BACKUP_FILE = ""
+    self.AMBARI_ENV_BACKUP_FILE = ""
+    self.AMBARI_KRB_JAAS_LOGIN_BACKUP_FILE = ""
+
+    # ownership/permissions mapping
+    # path - permissions - user - group - recursive
+    # Rules are executed in the same order as they are listed
+    # {0} in user/group will be replaced by customized ambari-server username
+    self.NR_ADJUST_OWNERSHIP_LIST = []
+    self.NR_CHANGE_OWNERSHIP_LIST = []
+    self.NR_USERADD_CMD = ""
+
+    self.MASTER_KEY_FILE_PERMISSIONS = "640"
+    self.CREDENTIALS_STORE_FILE_PERMISSIONS = "640"
+    self.TRUST_STORE_LOCATION_PERMISSIONS = "640"
+
+    self.DEFAULT_DB_NAME = "ambari"
+
+    self.STACK_LOCATION_DEFAULT = ""
+    self.EXTENSION_LOCATION_DEFAULT = ""
+    self.COMMON_SERVICES_LOCATION_DEFAULT = ""
+    self.MPACKS_STAGING_LOCATION_DEFAULT = ""
+    self.SERVER_TMP_DIR_DEFAULT = ""
+    self.DASHBOARD_DIRNAME = "dashboards"
+
+    self.DEFAULT_VIEWS_DIR = ""
+
+    #keytool commands
+    self.keytool_bin_subpath = ""
+
+    #Standard messages
+    self.MESSAGE_SERVER_RUNNING_AS_ROOT = ""
+    self.MESSAGE_WARN_SETUP_NOT_ROOT = ""
+    self.MESSAGE_ERROR_RESET_NOT_ROOT = ""
+    self.MESSAGE_ERROR_UPGRADE_NOT_ROOT = ""
+    self.MESSAGE_CHECK_FIREWALL = ""
+    
+  def check_if_directories_writable(self, directories):
+    for directory in directories:
+      if not os.path.isdir(directory):
+        try:
+          os.makedirs(directory, 0755)
+        except Exception as ex:
+          # permission denied here is expected when ambari runs as non-root
+          print_error_msg("Could not create {0}. Reason: {1}".format(directory, str(ex)))
+      
+      if not os.path.isdir(directory) or not os.access(directory, os.W_OK):
+        raise FatalException(-1, "Unable to access {0} directory. Confirm the directory is created and is writable by Ambari Server user account '{1}'".format(directory, getpass.getuser()))
+
+@OsFamilyImpl(os_family=OSConst.WINSRV_FAMILY)
+class ServerConfigDefaultsWindows(ServerConfigDefaults):
+  def __init__(self):
+    super(ServerConfigDefaultsWindows, self).__init__()
+    self.JDK_INSTALL_DIR = "C:\\"
+    self.JDK_SEARCH_PATTERN = "j[2se|dk|re]*"
+    self.JAVA_EXE_SUBPATH = "bin\\java.exe"
+
+    # Configuration defaults
+    self.DEFAULT_CONF_DIR = "conf"
+    self.DEFAULT_LIBS_DIR = "lib"
+
+    self.AMBARI_PROPERTIES_BACKUP_FILE = "ambari.properties.backup"
+    self.AMBARI_KRB_JAAS_LOGIN_BACKUP_FILE = ""  # ToDo: should be adjusted later
+    # ownership/permissions mapping
+    # path - permissions - user - group - recursive
+    # Rules are executed in the same order as they are listed
+    # {0} in user/group will be replaced by customized ambari-server username
+    # The permissions are icacls
+    self.NR_ADJUST_OWNERSHIP_LIST = [
+      (self.OUT_DIR, "M", "{0}", True),  #0110-0100-0100 rw-r-r
+      (self.OUT_DIR, "F", "{0}", False), #0111-0101-0101 rwx-rx-rx
+      (self.PID_DIR, "M", "{0}", True),
+      (self.PID_DIR, "F", "{0}", False),
+      ("bootstrap", "F", "{0}", False),
+      ("ambari-env.cmd", "F", "{0}", False),
+      ("keystore", "M", "{0}", True),
+      ("keystore", "F", "{0}", False),
+      ("keystore\\db", "700", "{0}", False),
+      ("keystore\\db\\newcerts", "700", "{0}", False),
+      ("resources\\stacks", "755", "{0}", True),
+      ("resources\\custom_actions", "755", "{0}", True),
+      ("conf", "644", "{0}", True),
+      ("conf", "755", "{0}", False),
+      ("conf\\password.dat", "640", "{0}", False),
+      # Also, /etc/ambari-server/conf/password.dat
+      # is generated later at store_password_file
+    ]
+    self.NR_USERADD_CMD = "cmd /C net user {0} {1} /ADD"
+
+    self.SERVER_RESOURCES_DIR = "resources"
+    self.STACK_LOCATION_DEFAULT = "resources\\stacks"
+    self.EXTENSION_LOCATION_DEFAULT = "resources\\extensions"
+    self.COMMON_SERVICES_LOCATION_DEFAULT = "resources\\common-services"
+    self.MPACKS_STAGING_LOCATION_DEFAULT = "resources\\mpacks"
+    self.SERVER_TMP_DIR_DEFAULT = "data\\tmp"
+
+    self.DEFAULT_VIEWS_DIR = "resources\\views"
+
+    #keytool commands
+    self.keytool_bin_subpath = "bin\\keytool.exe"
+
+    #Standard messages
+    self.MESSAGE_SERVER_RUNNING_AS_ROOT = "Ambari Server running with 'root' privileges."
+    self.MESSAGE_WARN_SETUP_NOT_ROOT = "Ambari-server setup is run with root-level privileges, passwordless sudo access for some commands commands may be required"
+    self.MESSAGE_ERROR_RESET_NOT_ROOT = "Ambari-server reset must be run with administrator-level privileges"
+    self.MESSAGE_ERROR_UPGRADE_NOT_ROOT = "Ambari-server upgrade must be run with administrator-level privileges"
+    self.MESSAGE_CHECK_FIREWALL = "Checking firewall status..."
+
+@OsFamilyImpl(os_family=OsFamilyImpl.DEFAULT)
+class ServerConfigDefaultsLinux(ServerConfigDefaults):
+  def __init__(self):
+    super(ServerConfigDefaultsLinux, self).__init__()
+    # JDK
+    self.JDK_INSTALL_DIR = AmbariPath.get("/usr/jdk64")
+    self.JDK_SEARCH_PATTERN = "jdk*"
+    self.JAVA_EXE_SUBPATH = "bin/java"
+
+    # Configuration defaults
+    self.DEFAULT_CONF_DIR = AmbariPath.get("/etc/ambari-server/conf")
+    self.DEFAULT_LIBS_DIR = AmbariPath.get("/usr/lib/ambari-server")
+    self.DEFAULT_VLIBS_DIR = AmbariPath.get("/var/lib/ambari-server")
+
+    self.AMBARI_PROPERTIES_BACKUP_FILE = "ambari.properties.rpmsave"
+    self.AMBARI_ENV_BACKUP_FILE = "ambari-env.sh.rpmsave"
+    self.AMBARI_KRB_JAAS_LOGIN_BACKUP_FILE = "krb5JAASLogin.conf.rpmsave"
+    # ownership/permissions mapping
+    # path - permissions - user - group - recursive
+    # Rules are executed in the same order as they are listed
+    # {0} in user/group will be replaced by customized ambari-server username
+    self.NR_ADJUST_OWNERSHIP_LIST = [
+      (self.OUT_DIR + "/*", "644", "{0}", True),
+      (self.OUT_DIR, "755", "{0}", False),
+      (self.PID_DIR + "/*", "644", "{0}", True),
+      (self.PID_DIR, "755", "{0}", False),
+      (self.BOOTSTRAP_DIR, "755", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/ambari-env.sh"), "700", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/ambari-sudo.sh"), "700", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/keys/*"), "600", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/keys/"), "700", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/keys/db/"), "700", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/keys/db/newcerts/"), "700", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/keys/.ssh"), "700", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/resources/common-services/"), "755", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/resources/stacks/"), "755", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/resources/extensions/"), "755", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/resources/dashboards/"), "755", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/resources/mpacks/"), "755", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/resources/custom_actions/"), "755", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/resources/host_scripts/"), "755", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/resources/views/*"), "644", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/resources/views/"), "755", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/resources/views/work/"), "755", "{0}", True),
+      (AmbariPath.get("/etc/ambari-server/conf/*"), "644", "{0}", True),
+      (AmbariPath.get("/etc/ambari-server/conf/"), "755", "{0}", False),
+      (AmbariPath.get("/etc/ambari-server/conf/password.dat"), "640", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/keys/pass.txt"), "600", "{0}", False),
+      (AmbariPath.get("/etc/ambari-server/conf/ldap-password.dat"), "640", "{0}", False),
+      (self.RECOMMENDATIONS_DIR, "744", "{0}", True),
+      (self.RECOMMENDATIONS_DIR, "755", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/resources/data/"), "644", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/resources/data/"), "755", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/data/tmp/*"), "644", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/data/tmp/"), "755", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/data/cache/"), "600", "{0}", True),
+      (AmbariPath.get("/var/lib/ambari-server/data/cache/"), "700", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/resources/common-services/STORM/0.9.1/package/files/wordCount.jar"), "644", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/resources/stacks/HDP/2.1.GlusterFS/services/STORM/package/files/wordCount.jar"), "644", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/resources/stack-hooks/before-START/files/fast-hdfs-resource.jar"), "644", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/resources/stacks/HDP/2.1/services/SMARTSENSE/package/files/view/smartsense-ambari-view-1.4.0.0.60.jar"), "644", "{0}", False),
+      (AmbariPath.get("/var/lib/ambari-server/resources/stacks/HDP/3.0/hooks/before-START/files/fast-hdfs-resource.jar"), "644", "{0}", False),
+      # Also, /etc/ambari-server/conf/password.dat
+      # is generated later at store_password_file
+    ]
+    self.NR_CHANGE_OWNERSHIP_LIST = [
+      (AmbariPath.get("/var/lib/ambari-server"), "{0}", True),
+      (AmbariPath.get("/usr/lib/ambari-server"), "{0}", True),
+      (self.OUT_DIR, "{0}", True),
+      (self.PID_DIR, "{0}", True),
+      (AmbariPath.get("/etc/ambari-server"), "{0}", True),
+    ]
+    self.NR_USERADD_CMD = 'useradd -M --comment "{1}" ' \
+                 '--shell %s ' % locate_file('nologin', '/sbin') + ' -d ' + AmbariPath.get('/var/lib/ambari-server/keys/') + ' {0}'
+
+    self.SERVER_RESOURCES_DIR = AmbariPath.get("/var/lib/ambari-server/resources")
+    self.STACK_LOCATION_DEFAULT = AmbariPath.get("/var/lib/ambari-server/resources/stacks")
+    self.EXTENSION_LOCATION_DEFAULT = AmbariPath.get("/var/lib/ambari-server/resources/extensions")
+    self.COMMON_SERVICES_LOCATION_DEFAULT = AmbariPath.get("/var/lib/ambari-server/resources/common-services")
+    self.MPACKS_STAGING_LOCATION_DEFAULT = AmbariPath.get("/var/lib/ambari-server/resources/mpacks")
+    self.SERVER_TMP_DIR_DEFAULT = AmbariPath.get("/var/lib/ambari-server/data/tmp")
+
+    self.DEFAULT_VIEWS_DIR = AmbariPath.get("/var/lib/ambari-server/resources/views")
+
+    #keytool commands
+    self.keytool_bin_subpath = "bin/keytool"
+
+    #Standard messages
+    self.MESSAGE_SERVER_RUNNING_AS_ROOT = "Ambari Server running with administrator privileges."
+    self.MESSAGE_WARN_SETUP_NOT_ROOT = "Ambari-server setup is run with root-level privileges, passwordless sudo access for some commands commands may be required"
+    self.MESSAGE_ERROR_RESET_NOT_ROOT = "Ambari-server reset should be run with root-level privileges"
+    self.MESSAGE_ERROR_UPGRADE_NOT_ROOT = "Ambari-server upgrade must be run with root-level privileges"
+    self.MESSAGE_CHECK_FIREWALL = "Checking firewall status..."
+
+configDefaults = ServerConfigDefaults()
+
+# Security
+SECURITY_MASTER_KEY_LOCATION = "security.master.key.location"
+SECURITY_KEY_IS_PERSISTED = "security.master.key.ispersisted"
+SECURITY_KEY_ENV_VAR_NAME = "AMBARI_SECURITY_MASTER_KEY"
+SECURITY_MASTER_KEY_FILENAME = "master"
+SECURITY_IS_ENCRYPTION_ENABLED = "security.passwords.encryption.enabled"
+SECURITY_KERBEROS_JASS_FILENAME = "krb5JAASLogin.conf"
+
+SECURITY_PROVIDER_GET_CMD = "{0} -cp {1} " + \
+                            "org.apache.ambari.server.security.encryption" + \
+                            ".CredentialProvider GET {2} {3} {4} " + \
+                            "> " + configDefaults.SERVER_OUT_FILE + " 2>&1"
+
+SECURITY_PROVIDER_PUT_CMD = "{0} -cp {1} " + \
+                            "org.apache.ambari.server.security.encryption" + \
+                            ".CredentialProvider PUT {2} {3} {4} " + \
+                            "> " + configDefaults.SERVER_OUT_FILE + " 2>&1"
+
+SECURITY_PROVIDER_KEY_CMD = "{0} -cp {1} " + \
+                            "org.apache.ambari.server.security.encryption" + \
+                            ".MasterKeyServiceImpl {2} {3} {4} " + \
+                            "> " + configDefaults.SERVER_OUT_FILE + " 2>&1"
+
+
+
+def read_ambari_user():
+  '''
+  Reads ambari user from properties file
+  '''
+  properties = get_ambari_properties()
+  if properties != -1:
+    user = properties[NR_USER_PROPERTY]
+    if user:
+      return user
+  return None
+
+def get_is_active_instance():
+  # active.instance, if missing, will be considered to be true;
+  # if present, it should be explicitly set to "true" to set this as the active instance;
+  # any other value will be taken as a "false"
+  properties = get_ambari_properties()
+  # Get the value of active.instance.
+  active_instance_value = None
+  if properties != -1:
+    if ACTIVE_INSTANCE_PROPERTY in properties.propertyNames():
+      active_instance_value = properties[ACTIVE_INSTANCE_PROPERTY]
+
+  if active_instance_value is None:  # property is missing
+    is_active_instance = True
+  elif (active_instance_value == 'true'): # property is explicitly set to true
+    is_active_instance = True
+  else:  # any other value
+    is_active_instance = False
+
+  return is_active_instance
+
+def get_value_from_properties(properties, key, default=""):
+  try:
+    value = properties.get_property(key)
+    if not value:
+      value = default
+  except:
+    return default
+  return value
+
+def get_views_dir(properties):
+  views_dir = properties.get_property(VIEWS_DIR_PROPERTY)
+  if views_dir is None or views_dir == "":
+    views_dirs = glob.glob(AmbariPath.get("/var/lib/ambari-server/resources/views/work"))
+  else:
+    views_dirs = glob.glob(views_dir + "/work")
+  return views_dirs
+
+def get_admin_views_dir(properties):
+  views_dir = properties.get_property(VIEWS_DIR_PROPERTY)
+  if views_dir is None or views_dir == "":
+    views_dirs = glob.glob(AmbariPath.get("/var/lib/ambari-server/resources/views/work/ADMIN_VIEW*"))
+  else:
+    views_dirs = glob.glob(views_dir + "/work/ADMIN_VIEW*")
+  return views_dirs
+
+def get_views_jars(properties):
+  views_dir = properties.get_property(VIEWS_DIR_PROPERTY)
+  if views_dir is None or views_dir == "":
+    views_jars = glob.glob(AmbariPath.get("/var/lib/ambari-server/resources/views/*.jar"))
+  else:
+    views_jars = glob.glob(views_dir + "/*.jar")
+  return views_jars
+
+def get_is_secure(properties):
+  isSecure = properties.get_property(SECURITY_IS_ENCRYPTION_ENABLED)
+  isSecure = True if isSecure and isSecure.lower() == 'true' else False
+  return isSecure
+
+def get_is_persisted(properties):
+  keyLocation = get_master_key_location(properties)
+  masterKeyFile = search_file(SECURITY_MASTER_KEY_FILENAME, keyLocation)
+  isPersisted = True if masterKeyFile else False
+
+  return (isPersisted, masterKeyFile)
+
+def get_credential_store_location(properties):
+  store_loc = properties[SECURITY_KEYS_DIR]
+  if store_loc is None or store_loc == "":
+    store_loc = AmbariPath.get("/var/lib/ambari-server/keys/credentials.jceks")
+  else:
+    store_loc += os.sep + "credentials.jceks"
+  return store_loc
+
+def get_master_key_location(properties):
+  keyLocation = properties[SECURITY_MASTER_KEY_LOCATION]
+  if keyLocation is None or keyLocation == "":
+    keyLocation = properties[SECURITY_KEYS_DIR]
+  return keyLocation
+
+def get_ambari_server_ui_port(properties):
+  ambari_server_ui_port = CLIENT_API_PORT
+  client_api_port = properties.get_property(CLIENT_API_PORT_PROPERTY)
+  if client_api_port:
+    ambari_server_ui_port = client_api_port
+  api_ssl = properties.get_property(SSL_API)
+  if api_ssl and str(api_ssl).lower() == "true":
+    ambari_server_ui_port = DEFAULT_SSL_API_PORT
+    ssl_api_port = properties.get_property(SSL_API_PORT)
+    if ssl_api_port:
+      ambari_server_ui_port = ssl_api_port
+  return ambari_server_ui_port
+
+# Copy file to /tmp and save with file.# (largest # is latest file)
+def backup_file_in_temp(filePath):
+  if filePath is not None:
+    tmpDir = tempfile.gettempdir()
+    back_up_file_count = len(glob.glob1(tmpDir, AMBARI_PROPERTIES_FILE + "*"))
+    try:
+      shutil.copyfile(filePath, tmpDir + os.sep +
+                      AMBARI_PROPERTIES_FILE + "." + str(back_up_file_count + 1))
+    except (Exception), e:
+      print_error_msg('Could not backup file in temp "%s": %s' % (
+        back_up_file_count, str(e)))
+  return 0
+
+def get_ambari_version(properties):
+  """
+  :param properties: Ambari properties
+  :return: Return a string of the ambari version. When comparing versions, please use "compare_versions" function.
+  """
+  version = None
+  try:
+    server_version_file_path = properties[SERVER_VERSION_FILE_PATH]
+    if server_version_file_path and os.path.exists(server_version_file_path):
+      with open(server_version_file_path, 'r') as file:
+        version = file.read().strip()
+  except:
+    print_error_msg("Error getting ambari version")
+  return version
+
+def get_db_type(properties):
+  """
+  :rtype ServerDatabaseEntry
+  """
+  db_type = None
+  persistence_type = properties[PERSISTENCE_TYPE_PROPERTY]
+
+  if properties[JDBC_DATABASE_PROPERTY]:
+    db_type = ServerDatabases.match(properties[JDBC_DATABASE_PROPERTY])
+    if db_type == ServerDatabases.postgres and persistence_type == "local":
+      db_type = ServerDatabases.postgres_internal
+
+  if properties[JDBC_URL_PROPERTY] and db_type is None:
+    jdbc_url = properties[JDBC_URL_PROPERTY].lower()
+    if str(ServerDatabases.postgres) in jdbc_url:
+      db_type = ServerDatabases.postgres
+    elif str(ServerDatabases.oracle) in jdbc_url:
+      db_type = ServerDatabases.oracle
+    elif str(ServerDatabases.mysql) in jdbc_url:
+      db_type = ServerDatabases.mysql
+    elif str(ServerDatabases.mssql) in jdbc_url:
+      db_type = ServerDatabases.mssql
+    elif str(ServerDatabases.derby) in jdbc_url:
+      db_type = ServerDatabases.derby
+    elif str(ServerDatabases.sqlanywhere) in jdbc_url:
+      db_type = ServerDatabases.sqlanywhere
+
+  if persistence_type == "local" and db_type is None:
+    db_type = ServerDatabases.postgres_internal
+
+  return db_type
+
+def check_database_name_property(upgrade=False):
+  """
+  :param upgrade: If Ambari is being upgraded.
+  :return:
+  """
+  properties = get_ambari_properties()
+  if properties == -1:
+    print_error_msg("Error getting ambari properties")
+    return -1
+
+  version = get_ambari_version(properties)
+  if upgrade and (properties[JDBC_DATABASE_PROPERTY] not in ServerDatabases.databases()
+                    or properties.has_key(JDBC_RCA_SCHEMA_PROPERTY)):
+    # This code exists for historic reasons in which property names changed from Ambari 1.6.1 to 1.7.0
+    persistence_type = properties[PERSISTENCE_TYPE_PROPERTY]
+    if persistence_type == "remote":
+      db_name = properties[JDBC_RCA_SCHEMA_PROPERTY]  # this was a property in Ambari 1.6.1, but not after 1.7.0
+      if db_name:
+        write_property(JDBC_DATABASE_NAME_PROPERTY, db_name)
+
+      # If DB type is missing, attempt to reconstruct it from the JDBC URL
+      db_type = properties[JDBC_DATABASE_PROPERTY]
+      if db_type is None or db_type.strip().lower() not in ServerDatabases.databases():
+        db_type = get_db_type(properties).name
+        if db_type:
+          write_property(JDBC_DATABASE_PROPERTY, db_type)
+
+      properties = get_ambari_properties()
+    elif persistence_type == "local":
+      # Ambari 1.6.1, had "server.jdbc.database" as the DB name, and the
+      # DB type was assumed to be "postgres" if was embedded ("local")
+      db_name = properties[JDBC_DATABASE_PROPERTY]
+      if db_name:
+        write_property(JDBC_DATABASE_NAME_PROPERTY, db_name)
+        write_property(JDBC_DATABASE_PROPERTY, "postgres")
+        properties = get_ambari_properties()
+
+  dbname = properties[JDBC_DATABASE_NAME_PROPERTY]
+  if dbname is None or dbname == "":
+    err = "DB Name property not set in config file.\n" + SETUP_OR_UPGRADE_MSG
+    raise FatalException(-1, err)
+
+def update_database_name_property(upgrade=False):
+  try:
+    check_database_name_property(upgrade)
+  except FatalException:
+    properties = get_ambari_properties()
+    if properties == -1:
+      err = "Error getting ambari properties"
+      raise FatalException(-1, err)
+    print_warning_msg("{0} property isn't set in {1} . Setting it to default value - {3}".format(JDBC_DATABASE_NAME_PROPERTY, AMBARI_PROPERTIES_FILE, configDefaults.DEFAULT_DB_NAME))
+    properties.process_pair(JDBC_DATABASE_NAME_PROPERTY, configDefaults.DEFAULT_DB_NAME)
+    conf_file = find_properties_file()
+    try:
+      with open(conf_file, "w") as hfW:
+        properties.store(hfW)
+    except Exception, e:
+      err = 'Could not write ambari config file "%s": %s' % (conf_file, e)
+      raise FatalException(-1, err)
+
+
+def encrypt_password(alias, password, options):
+  properties = get_ambari_properties()
+  if properties == -1:
+    raise FatalException(1, None)
+  return get_encrypted_password(alias, password, properties, options)
+
+def get_encrypted_password(alias, password, properties, options):
+  isSecure = get_is_secure(properties)
+  (isPersisted, masterKeyFile) = get_is_persisted(properties)
+  if isSecure:
+    masterKey = None
+    if not masterKeyFile:
+      # Encryption enabled but no master key file found
+      masterKey = get_original_master_key(properties, options)
+
+    retCode = save_passwd_for_alias(alias, password, masterKey)
+    if retCode != 0:
+      print_error_msg ('Failed to save secure password!')
+      return password
+    else:
+      return get_alias_string(alias)
+
+  return password
+
+
+def is_alias_string(passwdStr):
+  regex = re.compile("\$\{alias=[\w\.]+\}")
+  # Match implies string at beginning of word
+  r = regex.match(passwdStr)
+  if r is not None:
+    return True
+  else:
+    return False
+
+def get_alias_string(alias):
+  return "${alias=" + alias + "}"
+
+def get_alias_from_alias_string(aliasStr):
+  return aliasStr[8:-1]
+
+def read_passwd_for_alias(alias, masterKey="", options=None):
+  if alias:
+    jdk_path = find_jdk()
+    if jdk_path is None:
+      print_error_msg("No JDK found, please run the \"setup\" "
+                      "command to install a JDK automatically or install any "
+                      "JDK manually to {0}".format(configDefaults.JDK_INSTALL_DIR))
+      return 1
+
+    tempFileName = "ambari.passwd"
+    passwd = ""
+    tempDir = tempfile.gettempdir()
+    #create temporary file for writing
+    tempFilePath = tempDir + os.sep + tempFileName
+    with open(tempFilePath, 'w+'):
+      os.chmod(tempFilePath, stat.S_IREAD | stat.S_IWRITE)
+
+    if options is not None and options.master_key is not None and options.master_key:
+      masterKey = options.master_key
+    if masterKey is None or masterKey == "":
+      masterKey = "None"
+
+    serverClassPath = ambari_server.serverClassPath.ServerClassPath(get_ambari_properties(), None)
+    command = SECURITY_PROVIDER_GET_CMD.format(get_java_exe_path(),
+                                               serverClassPath.get_full_ambari_classpath_escaped_for_shell(), alias, tempFilePath, masterKey)
+    (retcode, stdout, stderr) = run_os_command(command)
+    print_info_msg("Return code from credential provider get passwd: {0}".format(str(retcode)))
+    if retcode != 0:
+      print_error_msg ('ERROR: Unable to read password from store. alias = {0}'.format(alias))
+    else:
+      with open(tempFilePath, 'r') as hfRTemp:
+        passwd = hfRTemp.read()
+      # Remove temporary file
+    os.remove(tempFilePath)
+    return passwd
+  else:
+    print_error_msg("Alias is unreadable.")
+
+def decrypt_password_for_alias(properties, alias, options=None):
+  isSecure = get_is_secure(properties)
+  if isSecure:
+    masterKey = None
+    (isPersisted, masterKeyFile) = get_is_persisted(properties)
+    if not masterKeyFile:
+      # Encryption enabled but no master key file found
+      masterKey = get_original_master_key(properties, options)
+    return read_passwd_for_alias(alias, masterKey, options)
+  else:
+    return alias
+
+def save_passwd_for_alias(alias, passwd, masterKey=""):
+  if alias and passwd:
+    jdk_path = find_jdk()
+    if jdk_path is None:
+      print_error_msg("No JDK found, please run the \"setup\" "
+                      "command to install a JDK automatically or install any "
+                      "JDK manually to {0}".format(configDefaults.JDK_INSTALL_DIR))
+      return 1
+
+    if masterKey is None or masterKey == "":
+      masterKey = "None"
+
+    serverClassPath = ambari_server.serverClassPath.ServerClassPath(get_ambari_properties(), None)
+    command = SECURITY_PROVIDER_PUT_CMD.format(get_java_exe_path(),
+                                               serverClassPath.get_full_ambari_classpath_escaped_for_shell(), alias, passwd, masterKey)
+    (retcode, stdout, stderr) = run_os_command(command)
+    print_info_msg("Return code from credential provider save passwd: {0}".format(str(retcode)))
+    return retcode
+  else:
+    print_error_msg("Alias or password is unreadable.")
+
+
+def get_pass_file_path(conf_file, filename):
+  return os.path.join(os.path.dirname(conf_file), filename)
+
+def store_password_file(password, filename):
+  conf_file = find_properties_file()
+  passFilePath = get_pass_file_path(conf_file, filename)
+
+  with open(passFilePath, 'w+') as passFile:
+    passFile.write(password)
+  print_info_msg("Adjusting filesystem permissions")
+  ambari_user = read_ambari_user()
+  if ambari_user: # at the first install ambari_user can be None. Which is fine since later on password.dat is chowned with the correct ownership.
+    set_file_permissions(passFilePath, "660", ambari_user, False)
+
+  #Windows paths need double backslashes, otherwise the Ambari server deserializer will think the single \ are escape markers
+  return passFilePath.replace('\\', '\\\\')
+
+def remove_password_file(filename):
+  conf_file = find_properties_file()
+  passFilePath = os.path.join(os.path.dirname(conf_file),
+                              filename)
+
+  if os.path.exists(passFilePath):
+    try:
+      os.remove(passFilePath)
+    except Exception, e:
+      print_warning_msg('Unable to remove password file: {0}'.format(str(e)))
+      return 1
+  pass
+  return 0
+
+
+def get_web_server_startup_timeout(properties):
+  """
+  Gets the time, in seconds, that the startup script should wait for the web server to bind to
+  the configured port. If this value is too low, then the startup script will return an
+  error code even though Ambari is actually starting up.
+  :param properties:
+  :return: The timeout value, in seconds. The default is 50.
+  """
+  # get the timeout property and strip it if it exists
+  timeout = properties[WEB_SERVER_STARTUP_TIMEOUT]
+  timeout = None if timeout is None else timeout.strip()
+
+  if timeout is None or timeout == "":
+    timeout = 50
+  else:
+    timeout = int(timeout)
+  return timeout
+
+
+def get_original_master_key(properties, options = None):
+  input = True
+  masterKey = None
+  while(input):
+    try:
+      if options is not None and options.master_key is not None and options.master_key:
+        masterKey = options.master_key
+      if masterKey is None:
+        masterKey = get_validated_string_input('Enter current Master Key: ',
+                                               "", ".*", "", True, False)
+    except KeyboardInterrupt:
+      print_warning_msg('Exiting...')
+      sys.exit(1)
+
+    # Find an alias that exists
+    alias = None
+    property = properties.get_property(JDBC_PASSWORD_PROPERTY)
+    if property and is_alias_string(property):
+      alias = JDBC_RCA_PASSWORD_ALIAS
+
+    if not alias:
+      property = properties.get_property(LDAP_MGR_PASSWORD_PROPERTY)
+      if property and is_alias_string(property):
+        alias = LDAP_MGR_PASSWORD_ALIAS
+
+    if not alias:
+      property = properties.get_property(SSL_TRUSTSTORE_PASSWORD_PROPERTY)
+      if property and is_alias_string(property):
+        alias = SSL_TRUSTSTORE_PASSWORD_ALIAS
+
+    # Decrypt alias with master to validate it, if no master return
+    if alias and masterKey:
+      password = read_passwd_for_alias(alias, masterKey, options)
+      if not password:
+        print_error_msg ("ERROR: Master key does not match.")
+        continue
+
+    input = False
+
+  return masterKey
+
+
+# Load database connection properties from conf file
+def parse_properties_file(args):
+  properties = get_ambari_properties()
+  if properties == -1:
+    print_error_msg("Error getting ambari properties")
+    return -1
+
+  args.server_version_file_path = properties[SERVER_VERSION_FILE_PATH]
+  args.persistence_type = properties[PERSISTENCE_TYPE_PROPERTY]
+  args.jdbc_url = properties[JDBC_URL_PROPERTY]
+
+  args.dbms = properties[JDBC_DATABASE_PROPERTY]
+  if not args.persistence_type:
+    args.persistence_type = "local"
+
+  if args.persistence_type == 'remote':
+    args.database_host = properties[JDBC_HOSTNAME_PROPERTY]
+    args.database_port = properties[JDBC_PORT_PROPERTY]
+
+  args.database_name = properties[JDBC_DATABASE_NAME_PROPERTY]
+  args.database_username = properties[JDBC_USER_NAME_PROPERTY]
+  args.postgres_schema = properties[JDBC_POSTGRES_SCHEMA_PROPERTY] \
+    if JDBC_POSTGRES_SCHEMA_PROPERTY in properties.propertyNames() else None
+  args.database_password_file = properties[JDBC_PASSWORD_PROPERTY]
+  if args.database_password_file:
+    if not is_alias_string(args.database_password_file):
+      with open(properties[JDBC_PASSWORD_PROPERTY]) as hfDbPwd:
+        args.database_password = hfDbPwd.read()
+    else:
+      args.database_password = args.database_password_file
+  return 0
+
+def is_jaas_keytab_exists(conf_file):
+  with open(conf_file, "r") as f:
+    lines = f.read()
+
+  match = re.search("keyTab=(.*)$", lines, re.MULTILINE)
+  return os.path.exists(match.group(1).strip("\"").strip())
+
+def update_krb_jaas_login_properties():
+  """
+  Update configuration files
+  :return: int -2 - skipped, -1 - error, 0 - successful
+  """
+  prev_conf_file = search_file(configDefaults.AMBARI_KRB_JAAS_LOGIN_BACKUP_FILE, get_conf_dir())
+  conf_file = search_file(AMBARI_KRB_JAAS_LOGIN_FILE, get_conf_dir())
+
+  # check if source and target files exists, if not - skip copy action
+  if prev_conf_file is None or conf_file is None:
+    return -2
+
+  # if rpmsave file contains invalid keytab, we can skip restoring
+  if not is_jaas_keytab_exists(prev_conf_file):
+    return -2
+
+  try:
+    # restore original file, destination arg for rename func shouldn't exists
+    os.remove(conf_file)
+    os.rename(prev_conf_file, conf_file)
+    print_warning_msg("Original file %s kept" % AMBARI_KRB_JAAS_LOGIN_FILE)
+  except OSError as e:
+    print_error_msg ("Couldn't move %s file: %s" % (prev_conf_file, str(e)))
+    return -1
+
+  return 0
+
+def update_ambari_env():
+  prev_env_file = search_file(configDefaults.AMBARI_ENV_BACKUP_FILE, configDefaults.DEFAULT_VLIBS_DIR)
+  env_file = search_file(AMBARI_ENV_FILE, configDefaults.DEFAULT_VLIBS_DIR)
+
+  # Previous env file does not exist
+  if (not prev_env_file) or (prev_env_file is None):
+    print ("INFO: Can not find %s file from previous version, skipping restore of environment settings. "
+           "%s may not include any user customization.") % (configDefaults.AMBARI_ENV_BACKUP_FILE, AMBARI_ENV_FILE)
+    return 0
+
+  try:
+    if env_file is not None:
+      os.remove(env_file)
+      os.rename(prev_env_file, env_file)
+      print ("INFO: Original file %s kept") % (AMBARI_ENV_FILE)
+  except OSError as e:
+    print_error_msg ( "Couldn't move %s file: %s" % (prev_env_file, str(e)))
+    return -1
+
+  return 0
+  
+def write_gpl_license_accepted():
+  properties = get_ambari_properties()
+  if properties == -1:
+    err = "Error getting ambari properties"
+    raise FatalException(-1, err)
+
+
+  if GPL_LICENSE_ACCEPTED_PROPERTY in properties.keys() and properties.get_property(GPL_LICENSE_ACCEPTED_PROPERTY).lower() == "true":
+    return True
+
+  result = get_YN_input(GPL_LICENSE_PROMPT_TEXT, True)
+
+  properties.process_pair(GPL_LICENSE_ACCEPTED_PROPERTY, str(result).lower())
+  update_properties(properties)
+
+  return result
+
+def update_ambari_properties():
+  prev_conf_file = search_file(configDefaults.AMBARI_PROPERTIES_BACKUP_FILE, get_conf_dir())
+  conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
+
+  # Previous config file does not exist
+  if (not prev_conf_file) or (prev_conf_file is None):
+    print_warning_msg("Can not find %s file from previous version, skipping import of settings" % configDefaults.AMBARI_PROPERTIES_BACKUP_FILE)
+    return 0
+
+  # ambari.properties file does not exists
+  if conf_file is None:
+    print_error_msg("Can't find %s file" % AMBARI_PROPERTIES_FILE)
+    return -1
+
+  with open(prev_conf_file) as hfOld:
+    try:
+      old_properties = Properties()
+      old_properties.load(hfOld)
+    except Exception, e:
+      print_error_msg ('Could not read "%s": %s' % (prev_conf_file, str(e)))
+      return -1
+
+  try:
+    new_properties = Properties()
+    with open(conf_file) as hfNew:
+      new_properties.load(hfNew)
+
+    for prop_key, prop_value in old_properties.getPropertyDict().items():
+      if "agent.fqdn.service.url" == prop_key:
+        # what is agent.fqdn property in ambari.props?
+        new_properties.process_pair(GET_FQDN_SERVICE_URL, prop_value)
+      elif "server.os_type" == prop_key:
+        new_properties.process_pair(OS_TYPE_PROPERTY, OS_FAMILY + OS_VERSION)
+      elif JDK_RELEASES == prop_key:
+        # don't replace new jdk releases with old releases, because they can be updated
+        pass
+      else:
+        new_properties.process_pair(prop_key, prop_value)
+
+    # Adding custom user name property if it is absent
+    # In previous versions without custom user support server was started as
+    # "root" anyway so it's a reasonable default
+    if NR_USER_PROPERTY not in new_properties.keys():
+      new_properties.process_pair(NR_USER_PROPERTY, "root")
+
+    # update the os. In case os detection routine changed
+    new_properties.process_pair(OS_FAMILY_PROPERTY, OS_FAMILY + OS_VERSION)
+
+    with open(conf_file, 'w') as hfW:
+      new_properties.store(hfW)
+
+  except Exception, e:
+    print_error_msg ('Could not write "%s": %s' % (conf_file, str(e)))
+    return -1
+
+  timestamp = datetime.datetime.now()
+  fmt = '%Y%m%d%H%M%S'
+  new_conf_file = prev_conf_file + '.' + timestamp.strftime(fmt)
+  try:
+    os.rename(prev_conf_file, new_conf_file)
+  except Exception, e:
+    print_error_msg ('Could not rename "%s" to "%s": %s' % (prev_conf_file, new_conf_file, str(e)))
+    #Not critical, move on
+
+  return 0
+
+# update properties in a section-less properties file
+# Cannot use ConfigParser due to bugs in version 2.6
+def update_properties(propertyMap):
+  conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
+  backup_file_in_temp(conf_file)
+  if propertyMap is not None and conf_file is not None:
+    properties = Properties()
+    try:
+      with open(conf_file, 'r') as file:
+        properties.load(file)
+    except (Exception), e:
+      print_error_msg('Could not read "%s": %s' % (conf_file, e))
+      return -1
+
+    for key in propertyMap.keys():
+      properties.removeOldProp(key)
+      properties.process_pair(key, str(propertyMap[key]))
+
+    for key in properties.keys():
+      if not propertyMap.has_key(key):
+        properties.removeOldProp(key)
+
+    with open(conf_file, 'w') as file:
+      properties.store_ordered(file)
+
+  return 0
+
+def update_properties_2(properties, propertyMap):
+  conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
+  backup_file_in_temp(conf_file)
+  if conf_file is not None:
+    if propertyMap is not None:
+      for key in propertyMap.keys():
+        properties.removeOldProp(key)
+        properties.process_pair(key, str(propertyMap[key]))
+      pass
+
+    with open(conf_file, 'w') as file:
+      properties.store_ordered(file)
+    pass
+  pass
+
+def write_property(key, value):
+  conf_file = find_properties_file()
+  properties = Properties()
+  try:
+    with open(conf_file, "r") as hfR:
+      properties.load(hfR)
+  except Exception, e:
+    print_error_msg('Could not read ambari config file "%s": %s' % (conf_file, e))
+    return -1
+  properties.process_pair(key, value)
+  try:
+    with open(conf_file, 'w') as hfW:
+      properties.store(hfW)
+  except Exception, e:
+    print_error_msg('Could not write ambari config file "%s": %s' % (conf_file, e))
+    return -1
+  return 0
+
+#
+# Checks if options determine local DB configuration
+#
+def is_local_database(args):
+  try:
+    return args.persistence_type == 'local'
+  except AttributeError:
+    return False
+
+
+def update_debug_mode():
+  debug_mode = get_debug_mode()
+  # The command-line settings supersede the ones in ambari.properties
+  if not debug_mode & 1:
+    properties = get_ambari_properties()
+    if properties == -1:
+      print_error_msg("Error getting ambari properties")
+      return -1
+
+    if get_value_from_properties(properties, DEBUG_MODE_KEY, False):
+      debug_mode = debug_mode | 1
+    if get_value_from_properties(properties, SUSPEND_START_MODE_KEY, False):
+      debug_mode = debug_mode | 2
+
+    set_debug_mode(debug_mode)
+
+#
+### JDK ###
+#
+
+#
+# Describes the JDK configuration data, necessary for download and installation
+#
+class JDKRelease:
+  name = ""
+  desc = ""
+  url = ""
+  dest_file = ""
+  jcpol_url = "http://public-repo-1.hortonworks.com/ARTIFACTS/UnlimitedJCEPolicyJDK7.zip"
+  dest_jcpol_file = ""
+  inst_dir = ""
+
+  def __init__(self, i_name, i_desc, i_url, i_dest_file, i_jcpol_url, i_dest_jcpol_file, i_inst_dir, i_reg_exp):
+    if i_name is None or i_name is "":
+      raise FatalException(-1, "Invalid JDK name: " + (i_desc or ""))
+    self.name = i_name
+    if i_desc is None or i_desc is "":
+      self.desc = self.name
+    else:
+      self.desc = i_desc
+    if i_url is None or i_url is "":
+      raise FatalException(-1, "Invalid URL for JDK " + i_name)
+    self.url = i_url
+    if i_dest_file is None or i_dest_file is "":
+      self.dest_file = i_name + ".exe"
+    else:
+      self.dest_file = i_dest_file
+    if not (i_jcpol_url is None or i_jcpol_url is ""):
+      self.jcpol_url = i_jcpol_url
+    if i_dest_jcpol_file is None or i_dest_jcpol_file is "":
+      self.dest_jcpol_file = "jcpol-" + i_name + ".zip"
+    else:
+      self.dest_jcpol_file = i_dest_jcpol_file
+    if i_inst_dir is None or i_inst_dir is "":
+      self.inst_dir = os.path.join(configDefaults.JDK_INSTALL_DIR, i_desc)
+    else:
+      self.inst_dir = i_inst_dir
+    if i_reg_exp is None or i_reg_exp is "":
+      raise FatalException(-1, "Invalid output parsing regular expression for JDK " + i_name)
+    self.reg_exp = i_reg_exp
+
+  @classmethod
+  def from_properties(cls, properties, section_name):
+    (desc, url, dest_file, jcpol_url, jcpol_file, inst_dir, reg_exp) = JDKRelease.__load_properties(properties, section_name)
+    cls = JDKRelease(section_name, desc, url, dest_file, jcpol_url, jcpol_file, inst_dir, reg_exp)
+    return cls
+
+  @staticmethod
+  def __load_properties(properties, section_name):
+    if section_name is None or section_name is "":
+      raise FatalException(-1, "Invalid properties section: " + ("(empty)" if section_name is None else ""))
+    if(properties.has_key(section_name + ".desc")):   #Not critical
+      desc = properties[section_name + ".desc"]
+    else:
+      desc = section_name
+    if not properties.has_key(section_name + ".url"):
+      raise FatalException(-1, "Invalid JDK URL in the properties section: " + section_name)
+    url = properties[section_name + ".url"]      #Required
+    if not properties.has_key(section_name + ".re"):
+      raise FatalException(-1, "Invalid JDK output parsing regular expression in the properties section: " + section_name)
+    reg_exp = properties[section_name + ".re"]      #Required
+    if(properties.has_key(section_name + ".dest-file")):   #Not critical
+      dest_file = properties[section_name + ".dest-file"]
+    else:
+      dest_file = section_name + ".exe"
+    if(properties.has_key(section_name + ".jcpol-url")):   #Not critical
+      jcpol_url = properties[section_name + ".jcpol-url"]
+    else:
+      jcpol_url = None
+    if(properties.has_key(section_name + ".jcpol-file")):   #Not critical
+      jcpol_file = properties[section_name + ".jcpol-file"]
+    else:
+      jcpol_file = None
+    if(properties.has_key(section_name + ".home")):   #Not critical
+      inst_dir = properties[section_name + ".home"]
+    else:
+      inst_dir = "C:\\" + section_name
+    return (desc, url, dest_file, jcpol_url, jcpol_file, inst_dir, reg_exp)
+  pass
+
+def get_JAVA_HOME():
+  properties = get_ambari_properties()
+  if properties == -1:
+    print_error_msg("Error getting ambari properties")
+    return None
+
+  java_home = properties[JAVA_HOME_PROPERTY]
+
+  if (not 0 == len(java_home)) and (os.path.exists(java_home)):
+    return java_home
+
+  return None
+
+#
+# Checks jdk path for correctness
+#
+def validate_jdk(jdk_path):
+  if jdk_path:
+    if os.path.exists(jdk_path):
+      java_exe_path = os.path.join(jdk_path, configDefaults.JAVA_EXE_SUBPATH)
+      if os.path.exists(java_exe_path) and os.path.isfile(java_exe_path):
+        return True
+  return False
+
+#
+# Finds the available JDKs.
+#
+def find_jdk():
+  jdkPath = get_JAVA_HOME()
+  if jdkPath:
+    if validate_jdk(jdkPath):
+      return jdkPath
+  print("INFO: Looking for available JDKs at {0}".format(configDefaults.JDK_INSTALL_DIR))
+  jdks = glob.glob(os.path.join(configDefaults.JDK_INSTALL_DIR, configDefaults.JDK_SEARCH_PATTERN))
+  #[fbarca] Use the newest JDK
+  jdks.sort(None, None, True)
+  print_info_msg("Found: {0}".format(str(jdks)))
+  if len(jdks) == 0:
+    return
+  for jdkPath in jdks:
+    print "INFO: Trying to use JDK {0}".format(jdkPath)
+    if validate_jdk(jdkPath):
+      print "INFO: Selected JDK {0}".format(jdkPath)
+      return jdkPath
+    else:
+      print_error_msg ("JDK {0} is invalid".format(jdkPath))
+  return
+
+def get_java_exe_path():
+  jdkPath = find_jdk()
+  if jdkPath:
+    java_exe = os.path.join(jdkPath, configDefaults.JAVA_EXE_SUBPATH)
+    return java_exe
+  return
+
+
+#
+# Server resource files location
+#
+def get_resources_location(properties):
+  err = 'Invalid directory'
+  try:
+    resources_dir = properties[RESOURCES_DIR_PROPERTY]
+    if not resources_dir:
+      resources_dir = configDefaults.SERVER_RESOURCES_DIR
+  except (KeyError), e:
+    err = 'Property ' + str(e) + ' is not defined at ' + properties.fileName
+    resources_dir = configDefaults.SERVER_RESOURCES_DIR
+
+  if not os.path.exists(os.path.abspath(resources_dir)):
+    msg = 'Resources dir ' + resources_dir + ' is incorrectly configured: ' + err
+    raise FatalException(1, msg)
+
+  return resources_dir
+
+#
+# Stack location
+#
+def get_stack_location(properties):
+  stack_location = properties[STACK_LOCATION_KEY]
+  if not stack_location:
+    stack_location = configDefaults.STACK_LOCATION_DEFAULT
+  return stack_location
+
+#
+# Extension location
+#
+def get_extension_location(properties):
+  extension_location = properties[EXTENSION_PATH_PROPERTY]
+  if not extension_location:
+    extension_location = configDefaults.EXTENSION_LOCATION_DEFAULT
+  return extension_location
+
+#
+# Common services location
+#
+def get_common_services_location(properties):
+  common_services_location = properties[COMMON_SERVICES_PATH_PROPERTY]
+  if not common_services_location:
+    common_services_location = configDefaults.COMMON_SERVICES_LOCATION_DEFAULT
+  return common_services_location
+
+#
+# Management packs staging location
+#
+def get_mpacks_staging_location(properties):
+  mpacks_staging_location = properties[MPACKS_STAGING_PATH_PROPERTY]
+  if not mpacks_staging_location:
+    mpacks_staging_location = configDefaults.MPACKS_STAGING_LOCATION_DEFAULT
+  return mpacks_staging_location
+
+
+#
+# Dashboard location
+#
+def get_dashboard_location(properties):
+  resources_dir = get_resources_location(properties)
+  dashboard_location = os.path.join(resources_dir, configDefaults.DASHBOARD_DIRNAME)
+  return dashboard_location
+
+#
+# Server temp location
+#
+def get_server_temp_location(properties):
+  server_tmp_dir = properties[SERVER_TMP_DIR_PROPERTY]
+  if not server_tmp_dir:
+    server_tmp_dir = configDefaults.SERVER_TMP_DIR_DEFAULT
+  return server_tmp_dir
+
+def get_missing_properties(properties, property_set=REQUIRED_PROPERTIES):
+  missing_propertiers = []
+  for property in property_set:
+    value = properties[property]
+    if not value:
+      missing_propertiers.append(property)
+
+  return missing_propertiers

http://git-wip-us.apache.org/repos/asf/ambari/blob/135d88bc/ambari-server/src/main/python/ambari_server/serverSetup.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/serverSetup.py b/ambari-server/src/main/python/ambari_server/serverSetup.py
index ad6dc4f..af45584 100644
--- a/ambari-server/src/main/python/ambari_server/serverSetup.py
+++ b/ambari-server/src/main/python/ambari_server/serverSetup.py
@@ -1182,8 +1182,9 @@ def setup(options):
     err = 'Downloading or installing JDK failed: {0}. Exiting.'.format(e)
     raise FatalException(e.code, err)
 
-  print 'Checking GPL software agreement...'
-  write_gpl_license_accepted(is_silent=get_silent())
+  if not get_silent() or options.accept_gpl:
+    print 'Checking GPL software agreement...'
+    write_gpl_license_accepted()
 
   print 'Completing setup...'
   retcode = configure_os_settings()