You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2016/06/14 10:14:36 UTC

ambari git commit: AMBARI-17162. View config- Allows remote cluster creation using a user having no permissions on the cluster. (Gaurav Nagar via dipayanb)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.4 92dbf64ca -> 4cb2ba5d1


AMBARI-17162. View config- Allows remote cluster creation using a user having no permissions on the cluster. (Gaurav Nagar via dipayanb)


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

Branch: refs/heads/branch-2.4
Commit: 4cb2ba5d1567f8b83843481394f122ae44d62358
Parents: 92dbf64
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Tue Jun 14 15:44:14 2016 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Tue Jun 14 15:44:14 2016 +0530

----------------------------------------------------------------------
 .../ambari/server/view/RemoteAmbariCluster.java | 115 ++++++++++++++-----
 .../view/RemoteAmbariClusterRegistry.java       |  14 ++-
 .../apache/ambari/server/view/ViewRegistry.java |   7 +-
 .../server/view/RemoteAmbariClusterTest.java    |  16 +--
 4 files changed, 110 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/4cb2ba5d/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariCluster.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariCluster.java b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariCluster.java
index 1135424..6a4f04a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariCluster.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariCluster.java
@@ -32,6 +32,8 @@ import org.apache.commons.io.IOUtils;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -44,10 +46,31 @@ import java.util.concurrent.TimeUnit;
  */
 public class RemoteAmbariCluster implements Cluster {
 
+  public static final String AMBARI_OR_CLUSTER_ADMIN = "/api/v1/users/%s?privileges/PrivilegeInfo/permission_name=AMBARI.ADMINISTRATOR|" +
+    "(privileges/PrivilegeInfo/permission_name=CLUSTER.ADMINISTRATOR&privileges/PrivilegeInfo/cluster_name=%s)";
+
+  /**
+   * Name of the remote Ambari Cluster
+   */
   private String name;
 
+  /**
+   * StreamProvider for the remote cluster
+   * Base path will be http://host:port
+   */
   private AmbariStreamProvider streamProvider;
 
+  /**
+   * Path for the cluster.
+   * Value will be like : /api/v1/clusters/clusterName
+   */
+  private String clusterPath;
+
+  /**
+   * User for the cluster
+   */
+  private String username;
+
   private final LoadingCache<String, JsonElement> configurationCache = CacheBuilder.newBuilder()
     .expireAfterWrite(10, TimeUnit.SECONDS)
     .build(new CacheLoader<String, JsonElement>() {
@@ -63,16 +86,29 @@ public class RemoteAmbariCluster implements Cluster {
    *
    * @param remoteAmbariClusterEntity
    */
-  public RemoteAmbariCluster(RemoteAmbariClusterEntity remoteAmbariClusterEntity, Configuration config) {
-    String [] urlSplit = remoteAmbariClusterEntity.getUrl().split("/");
+  public RemoteAmbariCluster(RemoteAmbariClusterEntity remoteAmbariClusterEntity, Configuration config) throws MalformedURLException {
+
+    this.name = getClusterName(remoteAmbariClusterEntity);
+    this.username = remoteAmbariClusterEntity.getUsername();
+
+    URL url = new URL(remoteAmbariClusterEntity.getUrl());
+
+    String portString = url.getPort() == -1 ? "" : ":" + url.getPort();
+    String baseUrl = url.getProtocol() + "://" + url.getHost() + portString;
+
+    this.clusterPath = url.getPath();
+
+    this.streamProvider = new RemoteAmbariStreamProvider(
+      baseUrl, remoteAmbariClusterEntity.getUsername(),
+      remoteAmbariClusterEntity.getPassword(), config.getRequestConnectTimeout(), config.getRequestReadTimeout());
+  }
+
+  private String getClusterName(RemoteAmbariClusterEntity remoteAmbariClusterEntity) {
+    String[] urlSplit = remoteAmbariClusterEntity.getUrl().split("/");
 
     // remoteAmbariClusterEntity.getName() is not the actual name of Remote Cluster
     // We need to extract the name from cluster url which is like. http://host:port/api/vi/clusters/${clusterName}
-    this.name = urlSplit[urlSplit.length -1];
-    
-    this.streamProvider = new RemoteAmbariStreamProvider(
-      remoteAmbariClusterEntity.getUrl(), remoteAmbariClusterEntity.getUsername(),
-      remoteAmbariClusterEntity.getPassword(),config.getRequestConnectTimeout(),config.getRequestReadTimeout());
+    return urlSplit[urlSplit.length - 1];
   }
 
   /**
@@ -81,8 +117,9 @@ public class RemoteAmbariCluster implements Cluster {
    * @param name
    * @param streamProvider
    */
-  public RemoteAmbariCluster(String name, AmbariStreamProvider streamProvider) {
+  public RemoteAmbariCluster(String name, String clusterPath, AmbariStreamProvider streamProvider) {
     this.name = name;
+    this.clusterPath = clusterPath;
     this.streamProvider = streamProvider;
   }
 
@@ -96,45 +133,45 @@ public class RemoteAmbariCluster implements Cluster {
     JsonElement config = null;
     try {
       String desiredTag = getDesiredConfig(type);
-      if(desiredTag != null){
-        config = configurationCache.get(String.format("/configurations?(type=%s&tag=%s)", type, desiredTag));
+      if (desiredTag != null) {
+        config = configurationCache.get(String.format("%s/configurations?(type=%s&tag=%s)",this.clusterPath, type, desiredTag));
       }
     } catch (ExecutionException e) {
       throw new RemoteAmbariConfigurationReadException("Can't retrieve configuration from Remote Ambari", e);
     }
 
-    if(config == null || !config.isJsonObject()) return null;
+    if (config == null || !config.isJsonObject()) return null;
     JsonElement items = config.getAsJsonObject().get("items");
 
-    if(items == null || !items.isJsonArray()) return null;
+    if (items == null || !items.isJsonArray()) return null;
     JsonElement item = items.getAsJsonArray().get(0);
 
-    if(item == null || !item.isJsonObject()) return null;
+    if (item == null || !item.isJsonObject()) return null;
     JsonElement properties = item.getAsJsonObject().get("properties");
 
-    if(properties == null || !properties.isJsonObject()) return null;
+    if (properties == null || !properties.isJsonObject()) return null;
     JsonElement property = properties.getAsJsonObject().get(key);
 
-    if(property == null || !property.isJsonPrimitive()) return null;
+    if (property == null || !property.isJsonPrimitive()) return null;
 
     return property.getAsJsonPrimitive().getAsString();
   }
 
   @Override
   public List<String> getHostsForServiceComponent(String serviceName, String componentName) {
-    String url = String.format("services/%s/components/%s?" +
-      "fields=host_components/HostRoles/host_name",serviceName,componentName);
+    String url = String.format("%s/services/%s/components/%s?" +
+      "fields=host_components/HostRoles/host_name", this.clusterPath, serviceName, componentName);
 
     List<String> hosts = new ArrayList<String>();
 
     try {
       JsonElement response = configurationCache.get(url);
 
-      if(response == null || !response.isJsonObject()) return hosts;
+      if (response == null || !response.isJsonObject()) return hosts;
 
       JsonElement hostComponents = response.getAsJsonObject().get("host_components");
 
-      if(hostComponents == null || !hostComponents.isJsonArray()) return hosts;
+      if (hostComponents == null || !hostComponents.isJsonArray()) return hosts;
 
       for (JsonElement element : hostComponents.getAsJsonArray()) {
         JsonElement hostRoles = element.getAsJsonObject().get("HostRoles");
@@ -156,15 +193,15 @@ public class RemoteAmbariCluster implements Cluster {
    */
   public Set<String> getServices() throws IOException, AmbariHttpException {
     Set<String> services = new HashSet<String>();
-    String path = "?fields=services/ServiceInfo/service_name";
+    String path = this.clusterPath + "?fields=services/ServiceInfo/service_name";
     JsonElement config = configurationCache.getUnchecked(path);
 
-    if(config != null && config.isJsonObject()){
+    if (config != null && config.isJsonObject()) {
       JsonElement items = config.getAsJsonObject().get("services");
-      if(items != null && items.isJsonArray()){
+      if (items != null && items.isJsonArray()) {
         for (JsonElement item : items.getAsJsonArray()) {
-          JsonElement serviceInfo =  item.getAsJsonObject().get("ServiceInfo");
-          if(serviceInfo != null && serviceInfo.isJsonObject()){
+          JsonElement serviceInfo = item.getAsJsonObject().get("ServiceInfo");
+          if (serviceInfo != null && serviceInfo.isJsonObject()) {
             String serviceName = serviceInfo.getAsJsonObject().get("service_name").getAsString();
             services.add(serviceName);
           }
@@ -175,6 +212,22 @@ public class RemoteAmbariCluster implements Cluster {
     return services;
   }
 
+  public boolean isAmbariOrClusterAdmin() throws AmbariHttpException {
+
+    if (username == null) return false;
+
+    String url = String.format(AMBARI_OR_CLUSTER_ADMIN, username, name);
+    JsonElement response = configurationCache.getUnchecked(url);
+
+    if (response != null && response.isJsonObject()) {
+      JsonElement privileges = response.getAsJsonObject().get("privileges");
+      if (privileges != null && privileges.isJsonArray()) {
+        if (privileges.getAsJsonArray().size() > 0) return true;
+      }
+    }
+    return false;
+  }
+
   /**
    * Get the current tag for the config type
    *
@@ -183,21 +236,21 @@ public class RemoteAmbariCluster implements Cluster {
    * @throws ExecutionException
    */
   private String getDesiredConfig(String type) throws ExecutionException {
-    JsonElement desiredConfigResponse = configurationCache.get("?fields=services/ServiceInfo,hosts,Clusters");
+    JsonElement desiredConfigResponse = configurationCache.get(this.clusterPath +"?fields=services/ServiceInfo,hosts,Clusters");
 
-    if(desiredConfigResponse == null || !desiredConfigResponse.isJsonObject()) return null;
+    if (desiredConfigResponse == null || !desiredConfigResponse.isJsonObject()) return null;
     JsonElement clusters = desiredConfigResponse.getAsJsonObject().get("Clusters");
 
-    if(clusters == null || !clusters.isJsonObject()) return null;
+    if (clusters == null || !clusters.isJsonObject()) return null;
     JsonElement desiredConfig = clusters.getAsJsonObject().get("desired_configs");
 
-    if(desiredConfig == null || !desiredConfig.isJsonObject()) return null;
+    if (desiredConfig == null || !desiredConfig.isJsonObject()) return null;
     JsonElement desiredConfigForType = desiredConfig.getAsJsonObject().get(type);
 
-    if(desiredConfigForType == null || !desiredConfigForType.isJsonObject()) return null;
+    if (desiredConfigForType == null || !desiredConfigForType.isJsonObject()) return null;
     JsonElement typeJson = desiredConfigForType.getAsJsonObject().get("tag");
 
-    if( typeJson == null || !(typeJson.isJsonPrimitive())) return null;
+    if (typeJson == null || !(typeJson.isJsonPrimitive())) return null;
 
     return typeJson.getAsJsonPrimitive().getAsString();
   }
@@ -211,7 +264,7 @@ public class RemoteAmbariCluster implements Cluster {
    * @throws AmbariHttpException
    */
   private JsonElement readFromUrlJSON(String url) throws IOException, AmbariHttpException {
-    InputStream inputStream = streamProvider.readFrom(url, "GET", (String)null, null);
+    InputStream inputStream = streamProvider.readFrom(url, "GET", (String) null, null);
     String response = IOUtils.toString(inputStream);
     return new JsonParser().parse(response);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4cb2ba5d/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
index fb59485..5e168ee 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.view;
 
+import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.dao.RemoteAmbariClusterDAO;
 import org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity;
@@ -27,6 +28,7 @@ import org.apache.ambari.view.AmbariHttpException;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import java.io.IOException;
+import java.net.MalformedURLException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Set;
@@ -46,7 +48,7 @@ public class RemoteAmbariClusterRegistry {
   @Inject
   private Configuration configuration;
 
-  public RemoteAmbariCluster get(Long clusterId) {
+  public RemoteAmbariCluster get(Long clusterId) throws MalformedURLException {
     RemoteAmbariCluster remoteAmbariCluster = clusterMap.get(clusterId);
     if (remoteAmbariCluster == null) {
       RemoteAmbariCluster cluster = getCluster(clusterId);
@@ -58,7 +60,7 @@ public class RemoteAmbariClusterRegistry {
   }
 
 
-  private RemoteAmbariCluster getCluster(Long clusterId) {
+  private RemoteAmbariCluster getCluster(Long clusterId) throws MalformedURLException {
     RemoteAmbariClusterEntity remoteAmbariClusterEntity = remoteAmbariClusterDAO.findById(clusterId);
     RemoteAmbariCluster remoteAmbariCluster = new RemoteAmbariCluster(remoteAmbariClusterEntity, configuration);
     return remoteAmbariCluster;
@@ -93,8 +95,14 @@ public class RemoteAmbariClusterRegistry {
    * @throws AmbariHttpException
    */
   public void saveOrUpdate(RemoteAmbariClusterEntity entity, boolean update) throws IOException, AmbariHttpException {
-    RemoteAmbariCluster cluster = new RemoteAmbariCluster(entity,configuration);
+
+    RemoteAmbariCluster cluster = new RemoteAmbariCluster(entity, configuration);
     Set<String> services = cluster.getServices();
+
+    if (!cluster.isAmbariOrClusterAdmin()) {
+      throw new AmbariException("User must be Ambari or Cluster Adminstrator.");
+    }
+
     Collection<RemoteAmbariClusterServiceEntity> serviceEntities = new ArrayList<RemoteAmbariClusterServiceEntity>();
 
     for (String service : services) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/4cb2ba5d/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
index 90144e2..9760c28 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
@@ -113,6 +113,7 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.nio.file.Path;
 import java.util.Collection;
@@ -936,7 +937,11 @@ public class ViewRegistry {
           LOG.warn("Could not find the cluster identified by " + clusterId + ".");
         }
       } else if(clusterId != null && viewInstance.getClusterType() == ClusterType.REMOTE_AMBARI){
-        return remoteAmbariClusterRegistry.get(clusterId);
+        try {
+          return remoteAmbariClusterRegistry.get(clusterId);
+        } catch (MalformedURLException e) {
+          LOG.warn("Cannot get Remote Cluster ." + e.getMessage() ,e);
+        }
       }
     }
     return null;

http://git-wip-us.apache.org/repos/asf/ambari/blob/4cb2ba5d/ambari-server/src/test/java/org/apache/ambari/server/view/RemoteAmbariClusterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/RemoteAmbariClusterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/RemoteAmbariClusterTest.java
index 2b6e014..0e76cc8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/RemoteAmbariClusterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/RemoteAmbariClusterTest.java
@@ -57,8 +57,9 @@ public class RemoteAmbariClusterTest {
     final String configurationString = "{\"items\": [{\"properties\": {\"test.property.name\": \"test property value\"}}]}";
     final int[] desiredConfigPolls = {0};
     final int[] testConfigPolls = {0};
+    final String clusterPath = "/api/v1/clusters/Test";
 
-    expect(clusterStreamProvider.readFrom(eq(  "?fields=services/ServiceInfo,hosts,Clusters"),
+    expect(clusterStreamProvider.readFrom(eq( clusterPath + "?fields=services/ServiceInfo,hosts,Clusters"),
       eq("GET"), (String) isNull(), (Map<String, String>) anyObject())).andAnswer(new IAnswer<InputStream>() {
       @Override
       public InputStream answer() throws Throwable {
@@ -67,7 +68,7 @@ public class RemoteAmbariClusterTest {
       }
     }).anyTimes();
 
-    expect(clusterStreamProvider.readFrom(eq( "/configurations?(type=test-site&tag=TAG)"),
+    expect(clusterStreamProvider.readFrom(eq(clusterPath + "/configurations?(type=test-site&tag=TAG)"),
       eq("GET"), (String)isNull(), (Map<String, String>) anyObject())).andAnswer(new IAnswer<InputStream>() {
       @Override
       public InputStream answer() throws Throwable {
@@ -80,7 +81,7 @@ public class RemoteAmbariClusterTest {
 
     replay(clusterStreamProvider,entity);
 
-    RemoteAmbariCluster cluster = new RemoteAmbariCluster("Test", clusterStreamProvider);
+    RemoteAmbariCluster cluster = new RemoteAmbariCluster("Test", clusterPath, clusterStreamProvider);
 
     String value = cluster.getConfigurationValue("test-site", "test.property.name");
     assertEquals(value, "test property value");
@@ -108,9 +109,10 @@ public class RemoteAmbariClusterTest {
 
     String service = "SERVICE";
     String component = "COMPONENT";
+    final String clusterPath = "/api/v1/clusters/Test";
 
-    expect(clusterStreamProvider.readFrom(eq(String.format("services/%s/components/%s?" +
-        "fields=host_components/HostRoles/host_name",service,component)),
+    expect(clusterStreamProvider.readFrom(eq(String.format("%s/services/%s/components/%s?" +
+        "fields=host_components/HostRoles/host_name", clusterPath, service, component)),
       eq("GET"), (String) isNull(), (Map<String, String>) anyObject()))
       .andReturn(new ByteArrayInputStream(componentHostsString.getBytes()));
 
@@ -118,7 +120,7 @@ public class RemoteAmbariClusterTest {
 
     replay(clusterStreamProvider,entity);
 
-    RemoteAmbariCluster cluster = new RemoteAmbariCluster("Test", clusterStreamProvider);
+    RemoteAmbariCluster cluster = new RemoteAmbariCluster("Test", clusterPath, clusterStreamProvider);
 
     List<String> hosts = cluster.getHostsForServiceComponent(service,component);
     Assert.assertEquals(2, hosts.size());
@@ -128,4 +130,4 @@ public class RemoteAmbariClusterTest {
     verify(clusterStreamProvider, entity);
 
   }
-}
\ No newline at end of file
+}