KNOX-1014 - Service Discovery and Topology Generation Framework (Phil Zampino 
via lmccay)

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

Branch: refs/heads/master
Commit: c2ca443262a848ae0d56e03e92ecba32fbf149f2
Parents: 3a0119b
Author: Larry McCay <lmc...@hortonworks.com>
Authored: Sat Sep 23 11:04:39 2017 -0400
Committer: Larry McCay <lmc...@hortonworks.com>
Committed: Sat Sep 23 11:04:39 2017 -0400

----------------------------------------------------------------------
 b/gateway-discovery-ambari/pom.xml              |  66 ++
 .../discovery/ambari/AmbariCluster.java         | 114 +++
 .../discovery/ambari/AmbariComponent.java       |  76 ++
 .../ambari/AmbariServiceDiscovery.java          | 291 +++++++
 .../ambari/AmbariServiceDiscoveryMessages.java  |  81 ++
 .../ambari/AmbariServiceDiscoveryType.java      |  35 +
 .../ambari/AmbariServiceURLCreator.java         | 184 ++++
 ...eway.topology.discovery.ServiceDiscoveryType |  19 +
 .../ambari/AmbariServiceDiscoveryTest.java      | 856 +++++++++++++++++++
 b/gateway-release/home/conf/descriptors/README  |   1 +
 .../home/conf/shared-providers/README           |   1 +
 gateway-discovery-ambari/pom.xml                |  66 ++
 .../discovery/ambari/AmbariCluster.java         | 114 +++
 .../discovery/ambari/AmbariComponent.java       |  76 ++
 .../ambari/AmbariServiceDiscovery.java          | 291 +++++++
 .../ambari/AmbariServiceDiscoveryMessages.java  |  81 ++
 .../ambari/AmbariServiceDiscoveryType.java      |  35 +
 .../ambari/AmbariServiceURLCreator.java         | 184 ++++
 ...eway.topology.discovery.ServiceDiscoveryType |  19 +
 .../ambari/AmbariServiceDiscoveryTest.java      | 856 +++++++++++++++++++
 gateway-release/home/conf/descriptors/README    |   1 +
 .../home/conf/shared-providers/README           |   1 +
 gateway-release/pom.xml                         |   4 +
 gateway-server/pom.xml                          |   5 +
 .../apache/hadoop/gateway/GatewayMessages.java  |   9 +-
 .../services/DefaultGatewayServices.java        |   3 +-
 .../topology/impl/DefaultTopologyService.java   | 278 +++++-
 .../builder/BeanPropertyTopologyBuilder.java    |   2 +-
 .../DefaultServiceDiscoveryConfig.java          |  48 ++
 .../discovery/ServiceDiscoveryFactory.java      |  81 ++
 .../topology/simple/SimpleDescriptor.java       |  46 +
 .../simple/SimpleDescriptorFactory.java         |  71 ++
 .../simple/SimpleDescriptorHandler.java         | 186 ++++
 .../topology/simple/SimpleDescriptorImpl.java   | 111 +++
 .../simple/SimpleDescriptorMessages.java        |  44 +
 .../topology/DefaultTopologyServiceTest.java    |  70 +-
 .../PropertiesFileServiceDiscoveryTest.java     |  90 ++
 .../discovery/ServiceDiscoveryFactoryTest.java  |  81 ++
 .../test/extension/DummyServiceDiscovery.java   |  66 ++
 .../extension/DummyServiceDiscoveryType.java    |  32 +
 .../PropertiesFileServiceDiscovery.java         | 108 +++
 .../PropertiesFileServiceDiscoveryType.java     |  35 +
 .../extension/SneakyServiceDiscoveryImpl.java   |  40 +
 .../extension/SneakyServiceDiscoveryType.java   |  33 +
 .../simple/SimpleDescriptorFactoryTest.java     | 218 +++++
 .../simple/SimpleDescriptorHandlerTest.java     | 239 ++++++
 ...eway.topology.discovery.ServiceDiscoveryType |  21 +
 .../topology/file/ambari-cluster-policy.xml     |  74 ++
 .../topology/file/simple-topology-four.json     |  18 +
 .../topology/discovery/GatewayService.java      |  29 +
 .../topology/discovery/ServiceDiscovery.java    |  76 ++
 .../discovery/ServiceDiscoveryConfig.java       |  42 +
 .../discovery/ServiceDiscoveryType.java         |  40 +
 pom.xml                                         |  27 +-
 54 files changed, 5626 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/b/gateway-discovery-ambari/pom.xml
----------------------------------------------------------------------
diff --git a/b/gateway-discovery-ambari/pom.xml 
b/b/gateway-discovery-ambari/pom.xml
new file mode 100644
index 0000000..924e89c
--- /dev/null
+++ b/b/gateway-discovery-ambari/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.knox</groupId>
+        <artifactId>gateway</artifactId>
+        <version>0.14.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>gateway-discovery-ambari</artifactId>
+
+    <name>gateway-discovery-ambari</name>
+    <description>The extension to the gateway for service discovery using 
Apache Ambari.</description>
+
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <dependencies>
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-spi</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-test-utils</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariCluster.java
----------------------------------------------------------------------
diff --git 
a/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariCluster.java
 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariCluster.java
new file mode 100644
index 0000000..6eaabd3
--- /dev/null
+++ 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariCluster.java
@@ -0,0 +1,114 @@
+/**
+ * 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.hadoop.gateway.topology.discovery.ambari;
+
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+class AmbariCluster implements ServiceDiscovery.Cluster {
+
+    private String name = null;
+
+    private AmbariServiceURLCreator urlCreator = new AmbariServiceURLCreator();
+
+    private Map<String, Map<String, ServiceConfiguration>> 
serviceConfigurations = new HashMap<>();
+
+    private Map<String, AmbariComponent> components = null;
+
+
+    AmbariCluster(String name) {
+        this.name = name;
+        components = new HashMap<String, AmbariComponent>();
+    }
+
+    void addServiceConfiguration(String serviceName, String configurationType, 
ServiceConfiguration serviceConfig) {
+        if (!serviceConfigurations.keySet().contains(serviceName)) {
+            serviceConfigurations.put(serviceName, new HashMap<String, 
ServiceConfiguration>());
+        }
+        serviceConfigurations.get(serviceName).put(configurationType, 
serviceConfig);
+    }
+
+
+    void addComponent(AmbariComponent component) {
+        components.put(component.getName(), component);
+    }
+
+
+    ServiceConfiguration getServiceConfiguration(String serviceName, String 
configurationType) {
+        ServiceConfiguration sc = null;
+        Map<String, ServiceConfiguration> configs = 
serviceConfigurations.get(serviceName);
+        if (configs != null) {
+            sc = configs.get(configurationType);
+        }
+        return sc;
+    }
+
+
+    Map<String, AmbariComponent> getComponents() {
+        return components;
+    }
+
+
+    AmbariComponent getComponent(String name) {
+        return components.get(name);
+    }
+
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+
+    @Override
+    public List<String> getServiceURLs(String serviceName) {
+        List<String> urls = new ArrayList<>();
+        urls.addAll(urlCreator.create(this, serviceName));
+        return urls;
+    }
+
+
+    static class ServiceConfiguration {
+
+        private String type;
+        private String version;
+        private Map<String, String> props;
+
+        ServiceConfiguration(String type, String version, Map<String, String> 
properties) {
+            this.type = type;
+            this.version = version;
+            this.props = properties;
+        }
+
+        public String getVersion() {
+            return version;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public Map<String, String> getProperties() {
+            return props;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariComponent.java
----------------------------------------------------------------------
diff --git 
a/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariComponent.java
 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariComponent.java
new file mode 100644
index 0000000..55257fb
--- /dev/null
+++ 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariComponent.java
@@ -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.
+ */
+package org.apache.hadoop.gateway.topology.discovery.ambari;
+
+import java.util.List;
+import java.util.Map;
+
+class AmbariComponent {
+
+    private String clusterName = null;
+    private String serviceName = null;
+    private String name        = null;
+    private String version     = null;
+
+    private List<String> hostNames = null;
+
+    private Map<String, String> properties = null;
+
+    AmbariComponent(String              name,
+                    String              version,
+                    String              cluster,
+                    String              service,
+                    List<String>        hostNames,
+                    Map<String, String> properties) {
+        this.name = name;
+        this.serviceName = service;
+        this.clusterName = cluster;
+        this.version = version;
+        this.hostNames = hostNames;
+        this.properties = properties;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getServiceName() {
+        return serviceName;
+    }
+
+    public String getClusterName() {
+        return clusterName;
+    }
+
+    public List<String> getHostNames() {
+        return hostNames;
+    }
+
+    public Map<String, String> getConfigProperties() {
+        return properties;
+    }
+
+    public String getConfigProperty(String propertyName) {
+        return properties.get(propertyName);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscovery.java
----------------------------------------------------------------------
diff --git 
a/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscovery.java
 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscovery.java
new file mode 100644
index 0000000..34f20a7
--- /dev/null
+++ 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscovery.java
@@ -0,0 +1,291 @@
+/**
+ * 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.hadoop.gateway.topology.discovery.ambari;
+
+import net.minidev.json.JSONArray;
+import net.minidev.json.JSONObject;
+import net.minidev.json.JSONValue;
+import org.apache.hadoop.gateway.config.ConfigurationException;
+import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+import org.apache.hadoop.gateway.services.security.AliasService;
+import org.apache.hadoop.gateway.services.security.AliasServiceException;
+import org.apache.hadoop.gateway.topology.discovery.GatewayService;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryConfig;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.util.*;
+
+
+class AmbariServiceDiscovery implements ServiceDiscovery {
+
+    static final String TYPE = "AMBARI";
+
+    static final String AMBARI_CLUSTERS_URI = "/api/v1/clusters";
+
+    static final String AMBARI_HOSTROLES_URI =
+                                       AMBARI_CLUSTERS_URI + 
"/%s/services?fields=components/host_components/HostRoles";
+
+    static final String AMBARI_SERVICECONFIGS_URI =
+            AMBARI_CLUSTERS_URI + 
"/%s/configurations/service_config_versions?is_current=true";
+
+    // Map of component names to service configuration types
+    private static Map<String, String> componentServiceConfigs = new 
HashMap<>();
+    static {
+        componentServiceConfigs.put("NAMENODE", "hdfs-site");
+        componentServiceConfigs.put("RESOURCEMANAGER", "yarn-site");
+        componentServiceConfigs.put("OOZIE_SERVER", "oozie-site");
+        componentServiceConfigs.put("HIVE_SERVER", "hive-site");
+        componentServiceConfigs.put("WEBHCAT_SERVER", "webhcat-site");
+        componentServiceConfigs.put("HBASE_MASTER", "hbase-site");
+    } // TODO: Are there other service components, for which the endpoints can 
be discovered via Ambari?
+
+    private static final String DEFAULT_USER_ALIAS = "ambari.discovery.user";
+    private static final String DEFAULT_PWD_ALIAS  = 
"ambari.discovery.password";
+
+    private static AmbariServiceURLCreator urlCreator = new 
AmbariServiceURLCreator();
+
+    private AmbariServiceDiscoveryMessages log = 
MessagesFactory.get(AmbariServiceDiscoveryMessages.class);
+
+    @GatewayService
+    private AliasService aliasService;
+
+    private CloseableHttpClient httpClient = null;
+
+    private Map<String, Map<String, String>> serviceConfiguration = new 
HashMap<>();
+
+
+    AmbariServiceDiscovery() {
+        httpClient = org.apache.http.impl.client.HttpClients.createDefault();
+    }
+
+
+    @Override
+    public String getType() {
+        return TYPE;
+    }
+
+
+    @Override
+    public Map<String, Cluster> discover(ServiceDiscoveryConfig config) {
+        Map<String, Cluster> clusters = new HashMap<String, Cluster>();
+
+        String discoveryAddress = config.getAddress();
+
+        // Invoke Ambari REST API to discover the available clusters
+        String clustersDiscoveryURL = String.format("%s" + 
AMBARI_CLUSTERS_URI, discoveryAddress);
+
+        JSONObject json = invokeREST(clustersDiscoveryURL, config.getUser(), 
config.getPasswordAlias());
+
+        // Parse the cluster names from the response, and perform the cluster 
discovery
+        JSONArray clusterItems = (JSONArray) json.get("items");
+        for (Object clusterItem : clusterItems) {
+            String clusterName = (String) ((JSONObject)((JSONObject) 
clusterItem).get("Clusters")).get("cluster_name");
+            try {
+                Cluster c = discover(config, clusterName);
+                clusters.put(clusterName, c);
+            } catch (Exception e) {
+                log.clusterDiscoveryError(clusterName, e);
+            }
+        }
+
+        return clusters;
+    }
+
+
+    @Override
+    public Cluster discover(ServiceDiscoveryConfig config, String clusterName) 
{
+        AmbariCluster cluster = new AmbariCluster(clusterName);
+
+        Map<String, String> serviceComponents = new HashMap<>();
+
+        String discoveryAddress = config.getAddress();
+        String discoveryUser = config.getUser();
+        String discoveryPwdAlias = config.getPasswordAlias();
+
+        Map<String, List<String>> componentHostNames = new HashMap<>();
+        String hostRolesURL = String.format("%s" + AMBARI_HOSTROLES_URI, 
discoveryAddress, clusterName);
+        JSONObject hostRolesJSON = invokeREST(hostRolesURL, discoveryUser, 
discoveryPwdAlias);
+        if (hostRolesJSON != null) {
+            // Process the host roles JSON
+            JSONArray items = (JSONArray) hostRolesJSON.get("items");
+            for (Object obj : items) {
+                JSONArray components = (JSONArray) ((JSONObject) 
obj).get("components");
+                for (Object component : components) {
+                    JSONArray hostComponents = (JSONArray) ((JSONObject) 
component).get("host_components");
+                    for (Object hostComponent : hostComponents) {
+                        JSONObject hostRoles = (JSONObject) ((JSONObject) 
hostComponent).get("HostRoles");
+                        String serviceName = (String) 
hostRoles.get("service_name");
+                        String componentName = (String) 
hostRoles.get("component_name");
+
+                        serviceComponents.put(componentName, serviceName);
+
+//                    String hostName = (String) hostRoles.get("host_name");
+                        String hostName = (String) 
hostRoles.get("public_host_name"); // Assuming public host name is most 
applicable
+                        log.discoveredServiceHost(serviceName, hostName);
+                        if (!componentHostNames.containsKey(componentName)) {
+                            componentHostNames.put(componentName, new 
ArrayList<String>());
+                        }
+                        componentHostNames.get(componentName).add(hostName);
+                    }
+                }
+            }
+        }
+
+        Map<String, Map<String, AmbariCluster.ServiceConfiguration>> 
serviceConfigurations =
+                                                 new HashMap<String, 
Map<String, AmbariCluster.ServiceConfiguration>>();
+        String serviceConfigsURL = String.format("%s" + 
AMBARI_SERVICECONFIGS_URI, discoveryAddress, clusterName);
+        JSONObject serviceConfigsJSON = invokeREST(serviceConfigsURL, 
discoveryUser, discoveryPwdAlias);
+        if (serviceConfigsJSON != null) {
+            // Process the service configurations
+            JSONArray serviceConfigs = (JSONArray) 
serviceConfigsJSON.get("items");
+            for (Object serviceConfig : serviceConfigs) {
+                String serviceName = (String) ((JSONObject) 
serviceConfig).get("service_name");
+                JSONArray configurations = (JSONArray) ((JSONObject) 
serviceConfig).get("configurations");
+                for (Object configuration : configurations) {
+                    String configType = (String) ((JSONObject) 
configuration).get("type");
+                    String configVersion = String.valueOf(((JSONObject) 
configuration).get("version"));
+
+                    Map<String, String> configProps = new HashMap<String, 
String>();
+                    JSONObject configProperties = (JSONObject) ((JSONObject) 
configuration).get("properties");
+                    for (String propertyName : configProperties.keySet()) {
+                        configProps.put(propertyName, 
String.valueOf(((JSONObject) configProperties).get(propertyName)));
+                    }
+                    if (!serviceConfigurations.containsKey(serviceName)) {
+                        serviceConfigurations.put(serviceName, new 
HashMap<String, AmbariCluster.ServiceConfiguration>());
+                    }
+                    serviceConfigurations.get(serviceName).put(configType, new 
AmbariCluster.ServiceConfiguration(configType, configVersion, configProps));
+                    cluster.addServiceConfiguration(serviceName, configType, 
new AmbariCluster.ServiceConfiguration(configType, configVersion, configProps));
+                }
+            }
+        }
+
+        // Construct the AmbariCluster model
+        for (String componentName : serviceComponents.keySet()) {
+            String serviceName = serviceComponents.get(componentName);
+            List<String> hostNames = componentHostNames.get(componentName);
+
+            Map<String, AmbariCluster.ServiceConfiguration> configs = 
serviceConfigurations.get(serviceName);
+            String configType = componentServiceConfigs.get(componentName);
+            if (configType != null) {
+                AmbariCluster.ServiceConfiguration svcConfig = 
configs.get(configType);
+                AmbariComponent c = new AmbariComponent(componentName,
+                                                        svcConfig.getVersion(),
+                                                        clusterName,
+                                                        serviceName,
+                                                        hostNames,
+                                                        
svcConfig.getProperties());
+                cluster.addComponent(c);
+            }
+        }
+
+        return cluster;
+    }
+
+
+    protected JSONObject invokeREST(String url, String username, String 
passwordAlias) {
+        JSONObject result = null;
+
+        CloseableHttpResponse response = null;
+        try {
+            HttpGet request = new HttpGet(url);
+
+            // If no configured username, then use default username alias
+            String password = null;
+            if (username == null) {
+                if (aliasService != null) {
+                    try {
+                        char[] defaultUser = 
aliasService.getPasswordFromAliasForGateway(DEFAULT_USER_ALIAS);
+                        if (defaultUser != null) {
+                            username = new String(defaultUser);
+                        }
+                    } catch (AliasServiceException e) {
+                        log.aliasServiceUserError(DEFAULT_USER_ALIAS, 
e.getLocalizedMessage());
+                    }
+                }
+
+                // If username is still null
+                if (username == null) {
+                    log.aliasServiceUserNotFound();
+                    throw new ConfigurationException("No username is 
configured for Ambari service discovery.");
+                }
+            }
+
+            if (aliasService != null) {
+                // If not password alias is configured, then try the default 
alias
+                if (passwordAlias == null) {
+                    passwordAlias = DEFAULT_PWD_ALIAS;
+                }
+                try {
+                    char[] pwd = 
aliasService.getPasswordFromAliasForGateway(passwordAlias);
+                    if (pwd != null) {
+                        password = new String(pwd);
+                    }
+
+                } catch (AliasServiceException e) {
+                    log.aliasServicePasswordError(passwordAlias, 
e.getLocalizedMessage());
+                }
+            }
+
+            // If the password could not be determined
+            if (password == null) {
+                log.aliasServicePasswordNotFound();
+                throw new ConfigurationException("No password is configured 
for Ambari service discovery.");
+            }
+
+            // Add an auth header if credentials are available
+            String encodedCreds =
+                    
org.apache.commons.codec.binary.Base64.encodeBase64String((username + ":" + 
password).getBytes());
+            request.addHeader(new BasicHeader("Authorization", "Basic " + 
encodedCreds));
+
+            response = httpClient.execute(request);
+
+            if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
+                HttpEntity entity = response.getEntity();
+                if (entity != null) {
+                    result = (JSONObject) 
JSONValue.parse((EntityUtils.toString(entity)));
+                    log.debugJSON(result.toJSONString());
+                } else {
+                    log.noJSON(url);
+                }
+            } else {
+                log.unexpectedRestResponseStatusCode(url, 
response.getStatusLine().getStatusCode());
+            }
+
+        } catch (IOException e) {
+            log.restInvocationError(url, e);
+        } finally {
+            if(response != null) {
+                try {
+                    response.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+        }
+        return result;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscoveryMessages.java
----------------------------------------------------------------------
diff --git 
a/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscoveryMessages.java
 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscoveryMessages.java
new file mode 100644
index 0000000..caa16ed
--- /dev/null
+++ 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscoveryMessages.java
@@ -0,0 +1,81 @@
+/**
+ * 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.hadoop.gateway.topology.discovery.ambari;
+
+import org.apache.hadoop.gateway.i18n.messages.Message;
+import org.apache.hadoop.gateway.i18n.messages.MessageLevel;
+import org.apache.hadoop.gateway.i18n.messages.Messages;
+import org.apache.hadoop.gateway.i18n.messages.StackTrace;
+
+@Messages(logger="org.apache.gateway.topology.discovery.ambari")
+public interface AmbariServiceDiscoveryMessages {
+
+    @Message(level = MessageLevel.ERROR,
+            text = "Encountered an error during cluster {0} discovery: {1}")
+    void clusterDiscoveryError(final String clusterName,
+                               @StackTrace(level = MessageLevel.ERROR) 
Exception e);
+
+
+    @Message(level = MessageLevel.DEBUG,
+            text = "REST invocation {0} failed: {1}")
+    void restInvocationError(final String url,
+                             @StackTrace(level = MessageLevel.ERROR) Exception 
e);
+
+
+    @Message(level = MessageLevel.ERROR,
+            text = "Encountered an error attempting to determine the user for 
alias {0} : {1}")
+    void aliasServiceUserError(final String alias, final String error);
+
+
+    @Message(level = MessageLevel.ERROR,
+            text = "Encountered an error attempting to determine the password 
for alias {0} : {1}")
+    void aliasServicePasswordError(final String alias, final String error);
+
+
+    @Message(level = MessageLevel.ERROR,
+            text = "No user configured for Ambari service discovery.")
+    void aliasServiceUserNotFound();
+
+
+    @Message(level = MessageLevel.ERROR,
+            text = "No password configured for Ambari service discovery.")
+    void aliasServicePasswordNotFound();
+
+
+    @Message(level = MessageLevel.ERROR,
+            text = "Unexpected REST invocation response code for {0} : {1}")
+    void unexpectedRestResponseStatusCode(final String url, int 
responseStatusCode);
+
+
+    @Message(level = MessageLevel.ERROR,
+            text = "REST invocation {0} yielded a response without any JSON.")
+    void noJSON(final String url);
+
+
+    @Message(level = MessageLevel.DEBUG,
+            text = "REST invocation result: {0}")
+    void debugJSON(final String json);
+
+
+    @Message(level = MessageLevel.INFO,
+            text = "Discovered: Service: {0}, Host: {1}")
+    void discoveredServiceHost(final String serviceName, final String 
hostName);
+
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscoveryType.java
----------------------------------------------------------------------
diff --git 
a/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscoveryType.java
 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscoveryType.java
new file mode 100644
index 0000000..723a786
--- /dev/null
+++ 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceDiscoveryType.java
@@ -0,0 +1,35 @@
+/**
+ * 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.hadoop.gateway.topology.discovery.ambari;
+
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType;
+
+public class AmbariServiceDiscoveryType implements ServiceDiscoveryType {
+
+    private static final String IMPL = 
AmbariServiceDiscovery.class.getCanonicalName();
+
+    @Override
+    public String getType() {
+        return AmbariServiceDiscovery.TYPE;
+    }
+
+    @Override
+    public ServiceDiscovery newInstance() {
+        return new AmbariServiceDiscovery();
+    }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceURLCreator.java
----------------------------------------------------------------------
diff --git 
a/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceURLCreator.java
 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceURLCreator.java
new file mode 100644
index 0000000..0674642
--- /dev/null
+++ 
b/b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariServiceURLCreator.java
@@ -0,0 +1,184 @@
+/**
+ * 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.hadoop.gateway.topology.discovery.ambari;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+class AmbariServiceURLCreator {
+
+    private static final String NAMENODE_SERVICE        = "NAMENODE";
+    private static final String JOBTRACKER_SERVICE      = "JOBTRACKER";
+    private static final String WEBHDFS_SERVICE         = "WEBHDFS";
+    private static final String WEBHCAT_SERVICE         = "WEBHCAT";
+    private static final String OOZIE_SERVICE           = "OOZIE";
+    private static final String WEBHBASE_SERVICE        = "WEBHBASE";
+    private static final String HIVE_SERVICE            = "HIVE";
+    private static final String RESOURCEMANAGER_SERVICE = "RESOURCEMANAGER";
+
+
+    /**
+     * Derive the endpoint URL(s) for the specified service, based on the info 
from the specified Cluster.
+     *
+     * @param cluster The cluster discovery results
+     * @param serviceName The name of a Hadoop service
+     *
+     * @return One or more endpoint URLs for the specified service.
+     */
+    public List<String> create(AmbariCluster cluster, String serviceName) {
+        List<String> result = null;
+
+        if (NAMENODE_SERVICE.equals(serviceName)) {
+            result = createNameNodeURL(cluster);
+        } else if (JOBTRACKER_SERVICE.equals(serviceName)) {
+            result = createJobTrackerURL(cluster);
+        } else if (WEBHDFS_SERVICE.equals(serviceName)) {
+            result = createWebHDFSURL(cluster);
+        } else if (WEBHCAT_SERVICE.equals(serviceName)) {
+            result = createWebHCatURL(cluster);
+        } else if (OOZIE_SERVICE.equals(serviceName)) {
+            result = createOozieURL(cluster);
+        } else if (WEBHBASE_SERVICE.equals(serviceName)) {
+            result = createWebHBaseURL(cluster);
+        } else if (HIVE_SERVICE.equals(serviceName)) {
+            result = createHiveURL(cluster);
+        } else if (RESOURCEMANAGER_SERVICE.equals(serviceName)) {
+            result = createResourceManagerURL(cluster);
+        }
+
+        return result;
+    }
+
+
+    private List<String> createNameNodeURL(AmbariCluster cluster) {
+        List<String> result = new ArrayList<>();
+
+        AmbariComponent comp = cluster.getComponent("NAMENODE");
+        if (comp != null) {
+            result.add("hdfs://" + 
comp.getConfigProperty("dfs.namenode.rpc-address"));
+        }
+
+        return result;
+    }
+
+
+    private List<String> createJobTrackerURL(AmbariCluster cluster) {
+        List<String> result = new ArrayList<>();
+
+        AmbariComponent comp = cluster.getComponent("RESOURCEMANAGER");
+        if (comp != null) {
+            result.add("rpc://" + 
comp.getConfigProperty("yarn.resourcemanager.address"));
+        }
+
+        return result;
+    }
+
+
+    private List<String> createWebHDFSURL(AmbariCluster cluster) {
+        List<String> result = new ArrayList<>();
+
+        AmbariCluster.ServiceConfiguration sc = 
cluster.getServiceConfiguration("HDFS", "hdfs-site");
+        if (sc != null) {
+            String address = 
sc.getProperties().get("dfs.namenode.http-address");
+            result.add("http://"; + address + "/webhdfs");
+        }
+
+        return result;
+    }
+
+
+    private List<String> createWebHCatURL(AmbariCluster cluster) {
+        List<String> result = new ArrayList<>();
+
+        AmbariComponent webhcat = cluster.getComponent("WEBHCAT_SERVER");
+        if (webhcat != null) {
+            String port = webhcat.getConfigProperty("templeton.port");
+            String host = webhcat.getHostNames().get(0);
+
+            result.add("http://"; + host + ":" + port + "/templeton");
+        }
+        return result;
+    }
+
+
+    private List<String> createOozieURL(AmbariCluster cluster) {
+        List<String> result = new ArrayList<>();
+
+        AmbariComponent comp = cluster.getComponent("OOZIE_SERVER");
+        if (comp != null) {
+            result.add(comp.getConfigProperty("oozie.base.url"));
+        }
+
+        return result;
+    }
+
+
+    private List<String> createWebHBaseURL(AmbariCluster cluster) {
+        List<String> result = new ArrayList<>();
+
+        AmbariComponent comp = cluster.getComponent("HBASE_MASTER");
+        if (comp != null) {
+            for (String host : comp.getHostNames()) {
+                result.add("http://"; + host + ":60080");
+            }
+        }
+
+        return result;
+    }
+
+
+    private List<String> createHiveURL(AmbariCluster cluster) {
+        List<String> result = new ArrayList<>();
+
+        AmbariComponent hive = cluster.getComponent("HIVE_SERVER");
+        if (hive != null) {
+            String path = 
hive.getConfigProperty("hive.server2.thrift.http.path");
+            String port = 
hive.getConfigProperty("hive.server2.thrift.http.port");
+            String transport = 
hive.getConfigProperty("hive.server2.transport.mode");
+            String useSSL = hive.getConfigProperty("hive.server2.use.SSL");
+            String host = hive.getHostNames().get(0);
+
+            String scheme = null; // What is the scheme for the binary 
transport mode?
+            if ("http".equals(transport)) {
+                scheme = Boolean.valueOf(useSSL) ? "https" : "http";
+            }
+
+            result.add(scheme + "://" + host + ":" + port + "/" + path);
+        }
+        return result;
+    }
+
+
+    private List<String> createResourceManagerURL(AmbariCluster cluster) {
+        List<String> result = new ArrayList<>();
+
+        AmbariComponent resMan = cluster.getComponent("RESOURCEMANAGER");
+        if (resMan != null) {
+            String webappAddress = 
resMan.getConfigProperty("yarn.resourcemanager.webapp.address");
+            String httpPolicy = resMan.getConfigProperty("yarn.http.policy");
+            String scheme = ("HTTPS_ONLY".equalsIgnoreCase(httpPolicy)) ? 
"https" : "http";
+
+            result.add(scheme + "://" + webappAddress + "/ws");
+        }
+
+        return result;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/b/gateway-discovery-ambari/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType
----------------------------------------------------------------------
diff --git 
a/b/gateway-discovery-ambari/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType
 
b/b/gateway-discovery-ambari/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType
new file mode 100644
index 0000000..1da4fc9
--- /dev/null
+++ 
b/b/gateway-discovery-ambari/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType
@@ -0,0 +1,19 @@
+##########################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##########################################################################
+
+org.apache.hadoop.gateway.topology.discovery.ambari.AmbariServiceDiscoveryType
\ No newline at end of file

Reply via email to