Repository: ambari
Updated Branches:
  refs/heads/trunk 975c0bc44 -> d49cc72e9


AMBARI-13752. Add a functional test to create a local ambari server and test 
it's status using an API call. (Nahappan Somasundaram via swagle)


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

Branch: refs/heads/trunk
Commit: d49cc72e92a72596571061622aacb3c5b5721200
Parents: 975c0bc
Author: Siddharth Wagle <swa...@hortonworks.com>
Authored: Tue Nov 10 21:13:38 2015 -0800
Committer: Siddharth Wagle <swa...@hortonworks.com>
Committed: Tue Nov 10 21:13:38 2015 -0800

----------------------------------------------------------------------
 .../server/configuration/Configuration.java     |   9 ++
 .../ambari/server/controller/AmbariServer.java  |  96 ++++++-----
 .../server/LocalAmbariServer.java               | 120 ++++++++++++++
 .../server/StartStopServerTest.java             | 159 +++++++++++++++++++
 4 files changed, 343 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d49cc72e/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 e5e2c90..12f6bca 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
@@ -100,6 +100,7 @@ public class Configuration {
   public static final String API_GZIP_COMPRESSION_ENABLED_KEY = 
"api.gzip.compression.enabled";
   public static final String API_GZIP_MIN_COMPRESSION_SIZE_KEY = 
"api.gzip.compression.min.size";
   public static final String AGENT_API_GZIP_COMPRESSION_ENABLED_KEY = 
"agent.api.gzip.compression.enabled";
+  public static final String AGENT_USE_SSL = "agent.ssl";
   public static final String SRVR_TWO_WAY_SSL_KEY = 
"security.server.two_way_ssl";
   public static final String SRVR_TWO_WAY_SSL_PORT_KEY = 
"security.server.two_way_ssl.port";
   public static final String SRVR_ONE_WAY_SSL_PORT_KEY = 
"security.server.one_way_ssl.port";
@@ -1137,6 +1138,14 @@ public class Configuration {
   }
 
   /**
+   * Check to see if the Agent should be authenticated via ssl or not
+   * @return false if not, true if ssl needs to be used.
+   */
+  public boolean getAgentSSLAuthentication() {
+    return ("true".equals(properties.getProperty(AGENT_USE_SSL, "true")));
+  }
+
+  /**
    * Get the value that should be set for the 
<code>Strict-Transport-Security</code> HTTP response header for Ambari Server 
UI.
    * <p/>
    * By default this will be <code>max-age=31536000; includeSubDomains</code>. 
For example:

http://git-wip-us.apache.org/repos/asf/ambari/blob/d49cc72e/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index b59ae5d..71e8082 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -335,47 +335,54 @@ public class AmbariServer {
         // root.addFilter(new FilterHolder(springSecurityFilter), "/proxy/*", 
DISPATCHER_TYPES);
       }
 
-
-      //Secured connector for 2-way auth
-      SslContextFactory contextFactoryTwoWay = new SslContextFactory();
-      disableInsecureProtocols(contextFactoryTwoWay);
-      SslSelectChannelConnector sslConnectorTwoWay = new
-          SslSelectChannelConnector(contextFactoryTwoWay);
-      sslConnectorTwoWay.setPort(configs.getTwoWayAuthPort());
-
       Map<String, String> configsMap = configs.getConfigsMap();
-      String keystore = configsMap.get(Configuration.SRVR_KSTR_DIR_KEY) +
-          File.separator + configsMap.get(Configuration.KSTR_NAME_KEY);
-      String truststore = configsMap.get(Configuration.SRVR_KSTR_DIR_KEY) +
-          File.separator + configsMap.get(Configuration.TSTR_NAME_KEY);
-      String srvrCrtPass = configsMap.get(Configuration.SRVR_CRT_PASS_KEY);
-      sslConnectorTwoWay.setKeystore(keystore);
-      sslConnectorTwoWay.setTruststore(truststore);
-      sslConnectorTwoWay.setPassword(srvrCrtPass);
-      sslConnectorTwoWay.setKeyPassword(srvrCrtPass);
-      sslConnectorTwoWay.setTrustPassword(srvrCrtPass);
-      
sslConnectorTwoWay.setKeystoreType(configsMap.get(Configuration.KSTR_TYPE_KEY));
-      
sslConnectorTwoWay.setTruststoreType(configsMap.get(Configuration.TSTR_TYPE_KEY));
-      sslConnectorTwoWay.setNeedClientAuth(configs.getTwoWaySsl());
-
-      //SSL Context Factory
-      SslContextFactory contextFactoryOneWay = new SslContextFactory(true);
-      contextFactoryOneWay.setKeyStorePath(keystore);
-      contextFactoryOneWay.setTrustStore(truststore);
-      contextFactoryOneWay.setKeyStorePassword(srvrCrtPass);
-      contextFactoryOneWay.setKeyManagerPassword(srvrCrtPass);
-      contextFactoryOneWay.setTrustStorePassword(srvrCrtPass);
-      
contextFactoryOneWay.setKeyStoreType(configsMap.get(Configuration.KSTR_TYPE_KEY));
-      
contextFactoryOneWay.setTrustStoreType(configsMap.get(Configuration.TSTR_TYPE_KEY));
-      contextFactoryOneWay.setNeedClientAuth(false);
-      disableInsecureProtocols(contextFactoryOneWay);
-
-      //Secured connector for 1-way auth
-      SslSelectChannelConnector sslConnectorOneWay = new 
SslSelectChannelConnector(contextFactoryOneWay);
-      sslConnectorOneWay.setPort(configs.getOneWayAuthPort());
-      sslConnectorOneWay.setAcceptors(2);
-      sslConnectorTwoWay.setAcceptors(2);
-      serverForAgent.setConnectors(new Connector[]{sslConnectorOneWay, 
sslConnectorTwoWay});
+
+      if (configs.getAgentSSLAuthentication()) {
+        //Secured connector for 2-way auth
+        SslContextFactory contextFactoryTwoWay = new SslContextFactory();
+        disableInsecureProtocols(contextFactoryTwoWay);
+        SslSelectChannelConnector sslConnectorTwoWay = new
+                SslSelectChannelConnector(contextFactoryTwoWay);
+        sslConnectorTwoWay.setPort(configs.getTwoWayAuthPort());
+
+        String keystore = configsMap.get(Configuration.SRVR_KSTR_DIR_KEY) +
+                File.separator + configsMap.get(Configuration.KSTR_NAME_KEY);
+        String truststore = configsMap.get(Configuration.SRVR_KSTR_DIR_KEY) +
+                File.separator + configsMap.get(Configuration.TSTR_NAME_KEY);
+        String srvrCrtPass = configsMap.get(Configuration.SRVR_CRT_PASS_KEY);
+        sslConnectorTwoWay.setKeystore(keystore);
+        sslConnectorTwoWay.setTruststore(truststore);
+        sslConnectorTwoWay.setPassword(srvrCrtPass);
+        sslConnectorTwoWay.setKeyPassword(srvrCrtPass);
+        sslConnectorTwoWay.setTrustPassword(srvrCrtPass);
+        
sslConnectorTwoWay.setKeystoreType(configsMap.get(Configuration.KSTR_TYPE_KEY));
+        
sslConnectorTwoWay.setTruststoreType(configsMap.get(Configuration.TSTR_TYPE_KEY));
+        sslConnectorTwoWay.setNeedClientAuth(configs.getTwoWaySsl());
+
+        //SSL Context Factory
+        SslContextFactory contextFactoryOneWay = new SslContextFactory(true);
+        contextFactoryOneWay.setKeyStorePath(keystore);
+        contextFactoryOneWay.setTrustStore(truststore);
+        contextFactoryOneWay.setKeyStorePassword(srvrCrtPass);
+        contextFactoryOneWay.setKeyManagerPassword(srvrCrtPass);
+        contextFactoryOneWay.setTrustStorePassword(srvrCrtPass);
+        
contextFactoryOneWay.setKeyStoreType(configsMap.get(Configuration.KSTR_TYPE_KEY));
+        
contextFactoryOneWay.setTrustStoreType(configsMap.get(Configuration.TSTR_TYPE_KEY));
+        contextFactoryOneWay.setNeedClientAuth(false);
+        disableInsecureProtocols(contextFactoryOneWay);
+
+        //Secured connector for 1-way auth
+        SslSelectChannelConnector sslConnectorOneWay = new 
SslSelectChannelConnector(contextFactoryOneWay);
+        sslConnectorOneWay.setPort(configs.getOneWayAuthPort());
+        sslConnectorOneWay.setAcceptors(2);
+        sslConnectorTwoWay.setAcceptors(2);
+        serverForAgent.setConnectors(new Connector[]{sslConnectorOneWay, 
sslConnectorTwoWay});
+      } else {
+        SelectChannelConnector agentConnector = new SelectChannelConnector();
+        agentConnector.setPort(configs.getOneWayAuthPort());
+        agentConnector.setMaxIdleTime(configs.getConnectionMaxIdleTime());
+        serverForAgent.addConnector(agentConnector);
+      }
 
       ServletHolder sh = new ServletHolder(ServletContainer.class);
       sh.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
@@ -713,11 +720,18 @@ public class AmbariServer {
   }
 
   /**
+   * Initialize the view registry singleton instance.
+   */
+  public void initViewRegistry() {
+    ViewRegistry.initInstance(this.viewRegistry);
+  }
+
+  /**
    * Sets up proxy authentication.  This must be done before the server is
    * initialized since <code>AmbariMetaInfo</code> requires potential URL
    * lookups that may need the proxy.
    */
-  static void setupProxyAuth() {
+  public static void setupProxyAuth() {
     final String proxyUser = System.getProperty("http.proxyUser");
     final String proxyPass = System.getProperty("http.proxyPassword");
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d49cc72e/ambari-server/src/test/java/org/apache/ambari/server/functionaltests/server/LocalAmbariServer.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/functionaltests/server/LocalAmbariServer.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/functionaltests/server/LocalAmbariServer.java
new file mode 100644
index 0000000..ceadbc2
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/functionaltests/server/LocalAmbariServer.java
@@ -0,0 +1,120 @@
+/*
+ * 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.functionaltests.server;
+
+import com.google.inject.persist.PersistService;
+import org.apache.ambari.server.controller.AmbariServer;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.configuration.Configuration;
+
+/**
+* Wrap AmbariServer as a testable unit.
+*/
+public class LocalAmbariServer implements Runnable {
+
+  private static Log LOG = LogFactory.getLog(AmbariServer.class);
+
+  /**
+   * Actual ambari server instance.
+   */
+  private AmbariServer ambariServer = null;
+
+  private Injector injector = null;
+
+  private InMemoryDefaultTestModule module = null;
+
+  /**
+   * Default constructor using the default implementation of 
InMemoryDefaultTestModule.
+   */
+  public LocalAmbariServer() { this.module = new InMemoryDefaultTestModule(); }
+
+  /**
+   * Overloaded constructor for sub-classed InMemoryDefaultTestModule 
implementations.
+   * @param module
+   */
+  public LocalAmbariServer(InMemoryDefaultTestModule module) { this.module = 
module; }
+
+  /**
+   * Thread entry point.
+   */
+  @Override
+  public void run(){
+    try {
+      startServer();
+    }
+    catch (Exception ex) {
+      LOG.info("Exception received ", ex);
+      throw new RuntimeException(ex);
+    }
+  }
+
+  /**
+   * Configures the Guice injector to use the in-memory test DB
+   * and attempts to start an instance of AmbariServer.
+   *
+   * @throws Exception
+   */
+  private void startServer() throws Exception {
+    /**
+     * Specify the temp folder as the source for certificate keys.
+     * Without this, the CertificateManager will generate the keys
+     * in the current folder (ambari-server) causing issues with
+     * rat check.
+     */
+    String tmpDir = System.getProperty("java.io.tmpdir");
+    this.module.getProperties().setProperty(Configuration.SRVR_KSTR_DIR_KEY, 
tmpDir);
+    injector = Guice.createInjector(this.module);
+
+    try {
+      LOG.info("Attempting to start ambari server...");
+
+      AmbariServer.setupProxyAuth();
+      injector.getInstance(GuiceJpaInitializer.class);
+      ambariServer = injector.getInstance(AmbariServer.class);
+      ambariServer.initViewRegistry();
+      ambariServer.run();
+    } catch (InterruptedException ex) {
+      LOG.info(ex);
+    } catch (Throwable t) {
+      LOG.error("Failed to run the Ambari Server", t);
+      stopServer();
+    }
+  }
+
+  /**
+   * Attempts to stop the test AmbariServer instance.
+   * @throws Exception
+   */
+  public void stopServer() throws Exception {
+    LOG.info("Stopping ambari server...");
+
+    if (ambariServer != null) {
+      ambariServer.stop();
+    }
+
+    if (injector != null) {
+        injector.getInstance(PersistService.class).stop();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d49cc72e/ambari-server/src/test/java/org/apache/ambari/server/functionaltests/server/StartStopServerTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/functionaltests/server/StartStopServerTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/functionaltests/server/StartStopServerTest.java
new file mode 100644
index 0000000..604ef9e
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/functionaltests/server/StartStopServerTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.functionaltests.server;
+
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertTrue;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.GetMethod;
+
+import java.io.StringReader;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonArray;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import org.apache.http.HttpStatus;
+
+/**
+ * Simple test that starts the local ambari server,
+ * tests it's status and shuts down the server.
+ */
+public class StartStopServerTest {
+  /**
+   * Run the ambari server on a thread.
+   */
+  private Thread serverThread = null;
+
+  /**
+   * Instance of the local ambari server, which wraps the actual
+   * ambari server with test configuration.
+   */
+  private LocalAmbariServer server = null;
+
+  /**
+   * Server port
+   */
+  private static int serverPort = 9995;
+
+  /**
+   * Server URL
+   */
+  private static String SERVER_URL_FORMAT = "http://localhost:%d";;
+
+  /**
+   * Test URL for GETting the status of the ambari server
+   */
+  private static String stacksPath = "/api/v1/stacks";
+
+  /**
+   * Start our local server on a thread so that it does not block.
+   * @throws Exception
+   */
+  @Before
+  public void setup() throws Exception {
+    InMemoryDefaultTestModule testModule = new InMemoryDefaultTestModule();
+    Properties properties = testModule.getProperties();
+    properties.setProperty(Configuration.AGENT_USE_SSL, "false");
+    properties.setProperty(Configuration.CLIENT_API_PORT_KEY, 
Integer.toString(serverPort));
+    server = new LocalAmbariServer(testModule);
+    serverThread = new Thread(server);
+    serverThread.start();
+    serverThread.join(20000);     // Give a few seconds for the ambari server 
to start up
+  }
+
+  /**
+   * Shut down our local server.
+   * @throws Exception
+   */
+  @After
+  public void teardown() throws Exception {
+    if (serverThread != null) {
+      serverThread.interrupt();
+    }
+    if (server != null) {
+      server.stopServer();
+    }
+  }
+
+  /**
+   * Waits for the ambari server to startup and then checks it's
+   * status by querying /api/v1/stacks (does not touch the DB)
+   */
+  @Test
+  public void testServerStatus() throws IOException {
+    /**
+     * Query the ambari server for the list of stacks.
+     * A successful GET returns the list of stacks.
+     * We should get a json like:
+     * {
+     *   "href" : "http://localhost:9995/api/v1/stacks";,
+     *   "items" : [
+     *   {
+     *     "href" : "http://localhost:9995/api/v1/stacks/HDP";,
+     *     "Stacks" : {
+     *     "stack_name" : "HDP"
+     *     }
+     *   }
+     *  ]
+     * }
+     */
+
+    String stacksUrl = String.format(SERVER_URL_FORMAT, serverPort) + 
stacksPath;
+    HttpClient httpClient = new HttpClient();
+    GetMethod getMethod = new GetMethod(stacksUrl);
+
+    try {
+      int statusCode = httpClient.executeMethod(getMethod);
+
+      assertTrue (statusCode == HttpStatus.SC_OK); // HTTP status code 200
+
+      String responseBody = getMethod.getResponseBodyAsString();
+
+      assertTrue(responseBody != null); // Make sure response body is valid
+
+      JsonElement jsonElement = new JsonParser().parse(new JsonReader(new 
StringReader(responseBody)));
+
+      assertTrue (jsonElement != null); // Response was a JSON string
+
+      JsonObject jsonObject = jsonElement.getAsJsonObject();
+
+      assertTrue (jsonObject.has("items"));  // Should have "items" entry
+
+      JsonArray stacksArray = jsonObject.get("items").getAsJsonArray();
+
+      assertTrue (stacksArray.size() > 0); // Should have at least one stack
+
+    } finally {
+      getMethod.releaseConnection();
+    }
+  }
+}

Reply via email to