You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/10/25 19:20:42 UTC

[06/17] knox git commit: KNOX-1062 - Service-Level Parameter Support in Service Discovery and Topology Generation (Phil Zampino via lmccay)

KNOX-1062 - Service-Level Parameter Support in Service Discovery and Topology Generation (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/0e13dc72
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/0e13dc72
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/0e13dc72

Branch: refs/heads/KNOX-998-Package_Restructuring
Commit: 0e13dc72e7719163ffca638a7f809dce3f9cf54c
Parents: 8ecac92
Author: Larry McCay <lm...@hortonworks.com>
Authored: Thu Oct 19 15:45:37 2017 -0400
Committer: Larry McCay <lm...@hortonworks.com>
Committed: Thu Oct 19 15:45:37 2017 -0400

----------------------------------------------------------------------
 .../discovery/ambari/AmbariCluster.java         |   2 +-
 .../topology/simple/SimpleDescriptor.java       |   4 +-
 .../simple/SimpleDescriptorHandler.java         |  43 +++-
 .../topology/simple/SimpleDescriptorImpl.java   |  12 +
 .../simple/SimpleDescriptorFactoryTest.java     | 230 +++++++++++++++++--
 .../simple/SimpleDescriptorHandlerTest.java     |  79 ++++++-
 6 files changed, 338 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/0e13dc72/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariCluster.java
----------------------------------------------------------------------
diff --git a/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariCluster.java b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariCluster.java
index eb84433..c841d9c 100644
--- a/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariCluster.java
+++ b/gateway-discovery-ambari/src/main/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariCluster.java
@@ -42,7 +42,7 @@ class AmbariCluster implements ServiceDiscovery.Cluster {
 
     void addServiceConfiguration(String serviceName, String configurationType, ServiceConfiguration serviceConfig) {
         if (!serviceConfigurations.keySet().contains(serviceName)) {
-            serviceConfigurations.put(serviceName, new HashMap<String, ServiceConfiguration>());
+            serviceConfigurations.put(serviceName, new HashMap<>());
         }
         serviceConfigurations.get(serviceName).put(configurationType, serviceConfig);
     }

http://git-wip-us.apache.org/repos/asf/knox/blob/0e13dc72/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptor.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptor.java
index aa28469..7072965 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptor.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptor.java
@@ -17,6 +17,7 @@
 package org.apache.hadoop.gateway.topology.simple;
 
 import java.util.List;
+import java.util.Map;
 
 public interface SimpleDescriptor {
 
@@ -40,7 +41,8 @@ public interface SimpleDescriptor {
     interface Service {
         String getName();
 
+        Map<String, String> getParams();
+
         List<String> getURLs();
     }
-
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/0e13dc72/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java
index 521b5b4..70c9539 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java
@@ -80,7 +80,10 @@ public class SimpleDescriptorHandler {
         ServiceDiscovery sd = ServiceDiscoveryFactory.get(desc.getDiscoveryType(), gatewayServices);
         ServiceDiscovery.Cluster cluster = sd.discover(sdc, desc.getClusterName());
 
-        Map<String, List<String>> serviceURLs = new HashMap<>();
+        List<String> validServiceNames = new ArrayList<>();
+
+        Map<String, Map<String, String>> serviceParams = new HashMap<>();
+        Map<String, List<String>>        serviceURLs   = new HashMap<>();
 
         if (cluster != null) {
             for (SimpleDescriptor.Service descService : desc.getServices()) {
@@ -100,6 +103,10 @@ public class SimpleDescriptorHandler {
                             validURLs.add(descServiceURL);
                         }
                     }
+
+                    if (!validURLs.isEmpty()) {
+                        validServiceNames.add(serviceName);
+                    }
                 }
 
                 // If there is at least one valid URL associated with the service, then add it to the map
@@ -108,6 +115,14 @@ public class SimpleDescriptorHandler {
                 } else {
                     log.failedToDiscoverClusterServiceURLs(serviceName, cluster.getName());
                 }
+
+                // Service params
+                if (descService.getParams() != null) {
+                    serviceParams.put(serviceName, descService.getParams());
+                    if (!validServiceNames.contains(serviceName)) {
+                        validServiceNames.add(serviceName);
+                    }
+                }
             }
         } else {
             log.failedToDiscoverClusterServices(desc.getClusterName());
@@ -115,7 +130,7 @@ public class SimpleDescriptorHandler {
 
         BufferedWriter fw = null;
         topologyDescriptor = null;
-        File providerConfig = null;
+        File providerConfig;
         try {
             // Verify that the referenced provider configuration exists before attempting to reading it
             providerConfig = resolveProviderConfigurationReference(desc.getProviderConfig(), srcDirectory);
@@ -147,16 +162,33 @@ public class SimpleDescriptorHandler {
             policyReader.close();
 
             // Sort the service names to write the services alphabetically
-            List<String> serviceNames = new ArrayList<>(serviceURLs.keySet());
+            List<String> serviceNames = new ArrayList<>(validServiceNames);
             Collections.sort(serviceNames);
 
             // Write the service declarations
             for (String serviceName : serviceNames) {
                 fw.write("    <service>\n");
                 fw.write("        <role>" + serviceName + "</role>\n");
-                for (String url : serviceURLs.get(serviceName)) {
-                    fw.write("        <url>" + url + "</url>\n");
+
+                // URLs
+                List<String> urls = serviceURLs.get(serviceName);
+                if (urls != null) {
+                    for (String url : urls) {
+                        fw.write("        <url>" + url + "</url>\n");
+                    }
                 }
+
+                // Params
+                Map<String, String> svcParams = serviceParams.get(serviceName);
+                if (svcParams != null) {
+                    for (String paramName : svcParams.keySet()) {
+                        fw.write("        <param>\n");
+                        fw.write("            <name>" + paramName + "</name>\n");
+                        fw.write("            <value>" + svcParams.get(paramName) + "</value>\n");
+                        fw.write("        </param>\n");
+                    }
+                }
+
                 fw.write("    </service>\n");
             }
 
@@ -195,6 +227,7 @@ public class SimpleDescriptorHandler {
         return result;
     }
 
+
     private static File resolveProviderConfigurationReference(String reference, File srcDirectory) {
         File providerConfig;
 

http://git-wip-us.apache.org/repos/asf/knox/blob/0e13dc72/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorImpl.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorImpl.java
index 32ceba9..bb430a1 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorImpl.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorImpl.java
@@ -21,6 +21,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 class SimpleDescriptorImpl implements SimpleDescriptor {
 
@@ -94,7 +95,13 @@ class SimpleDescriptorImpl implements SimpleDescriptor {
     }
 
     public static class ServiceImpl implements Service {
+        @JsonProperty("name")
         private String name;
+
+        @JsonProperty("params")
+        private Map<String, String> params;
+
+        @JsonProperty("urls")
         private List<String> urls;
 
         @Override
@@ -103,6 +110,11 @@ class SimpleDescriptorImpl implements SimpleDescriptor {
         }
 
         @Override
+        public Map<String, String> getParams() {
+            return params;
+        }
+
+        @Override
         public List<String> getURLs() {
             return urls;
         }

http://git-wip-us.apache.org/repos/asf/knox/blob/0e13dc72/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorFactoryTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorFactoryTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorFactoryTest.java
index 3dac66a..2ba8758 100644
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorFactoryTest.java
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorFactoryTest.java
@@ -64,6 +64,68 @@ public class SimpleDescriptorFactoryTest {
     }
 
     @Test
+    public void testParseJSONSimpleDescriptorWithServiceParams() throws Exception {
+
+        final String   discoveryType    = "AMBARI";
+        final String   discoveryAddress = "http://c6401.ambari.apache.org:8080";
+        final String   discoveryUser    = "admin";
+        final String   providerConfig   = "ambari-cluster-policy.xml";
+        final String   clusterName      = "myCluster";
+
+        final Map<String, List<String>> services = new HashMap<>();
+        services.put("NODEMANAGER", null);
+        services.put("JOBTRACKER", null);
+        services.put("RESOURCEMANAGER", null);
+        services.put("HIVE", Arrays.asList("http://c6401.ambari.apache.org", "http://c6402.ambari.apache.org", "http://c6403.ambari.apache.org"));
+        services.put("AMBARIUI", Collections.singletonList("http://c6401.ambari.apache.org:8080"));
+        services.put("KNOXSSO", null);
+        services.put("KNOXTOKEN", null);
+        services.put("CustomRole", Collections.singletonList("http://c6402.ambari.apache.org:1234"));
+
+        final Map<String, Map<String, String>> serviceParams = new HashMap<>();
+        Map<String, String> knoxSSOParams = new HashMap<>();
+        knoxSSOParams.put("knoxsso.cookie.secure.only", "true");
+        knoxSSOParams.put("knoxsso.token.ttl", "100000");
+        serviceParams.put("KNOXSSO", knoxSSOParams);
+
+        Map<String, String> knoxTokenParams = new HashMap<>();
+        knoxTokenParams.put("knox.token.ttl", "36000000");
+        knoxTokenParams.put("knox.token.audiences", "tokenbased");
+        knoxTokenParams.put("knox.token.target.url", "https://localhost:8443/gateway/tokenbased");
+        serviceParams.put("KNOXTOKEN", knoxTokenParams);
+
+        Map<String, String> customRoleParams = new HashMap<>();
+        customRoleParams.put("custom.param.1", "value1");
+        customRoleParams.put("custom.param.2", "value2");
+        serviceParams.put("CustomRole", customRoleParams);
+
+        String fileName = "test-topology.json";
+        File testJSON = null;
+        try {
+            testJSON = writeJSON(fileName,
+                                 discoveryType,
+                                 discoveryAddress,
+                                 discoveryUser,
+                                 providerConfig,
+                                 clusterName,
+                                 services,
+                                 serviceParams);
+            SimpleDescriptor sd = SimpleDescriptorFactory.parse(testJSON.getAbsolutePath());
+            validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, services, serviceParams);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (testJSON != null) {
+                try {
+                    testJSON.delete();
+                } catch (Exception e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+    @Test
     public void testParseYAMLSimpleDescriptor() throws Exception {
 
         final String   discoveryType    = "AMBARI";
@@ -99,12 +161,79 @@ public class SimpleDescriptorFactoryTest {
     }
 
 
-    private void validateSimpleDescriptor(SimpleDescriptor    sd,
-                                          String              discoveryType,
-                                          String              discoveryAddress,
-                                          String              providerConfig,
-                                          String              clusterName,
+    @Test
+    public void testParseYAMLSimpleDescriptorWithServiceParams() throws Exception {
+
+        final String   discoveryType    = "AMBARI";
+        final String   discoveryAddress = "http://c6401.ambari.apache.org:8080";
+        final String   discoveryUser    = "joeblow";
+        final String   providerConfig   = "ambari-cluster-policy.xml";
+        final String   clusterName      = "myCluster";
+
+        final Map<String, List<String>> services = new HashMap<>();
+        services.put("NODEMANAGER", null);
+        services.put("JOBTRACKER", null);
+        services.put("RESOURCEMANAGER", null);
+        services.put("HIVE", Arrays.asList("http://c6401.ambari.apache.org", "http://c6402.ambari.apache.org", "http://c6403.ambari.apache.org"));
+        services.put("AMBARIUI", Arrays.asList("http://c6401.ambari.apache.org:8080"));
+        services.put("KNOXSSO", null);
+        services.put("KNOXTOKEN", null);
+        services.put("CustomRole", Collections.singletonList("http://c6402.ambari.apache.org:1234"));
+
+        final Map<String, Map<String, String>> serviceParams = new HashMap<>();
+        Map<String, String> knoxSSOParams = new HashMap<>();
+        knoxSSOParams.put("knoxsso.cookie.secure.only", "true");
+        knoxSSOParams.put("knoxsso.token.ttl", "100000");
+        serviceParams.put("KNOXSSO", knoxSSOParams);
+
+        Map<String, String> knoxTokenParams = new HashMap<>();
+        knoxTokenParams.put("knox.token.ttl", "36000000");
+        knoxTokenParams.put("knox.token.audiences", "tokenbased");
+        knoxTokenParams.put("knox.token.target.url", "https://localhost:8443/gateway/tokenbased");
+        serviceParams.put("KNOXTOKEN", knoxTokenParams);
+
+        Map<String, String> customRoleParams = new HashMap<>();
+        customRoleParams.put("custom.param.1", "value1");
+        customRoleParams.put("custom.param.2", "value2");
+        serviceParams.put("CustomRole", customRoleParams);
+
+        String fileName = "test-topology.yml";
+        File testYAML = null;
+        try {
+            testYAML = writeYAML(fileName, discoveryType, discoveryAddress, discoveryUser, providerConfig, clusterName, services, serviceParams);
+            SimpleDescriptor sd = SimpleDescriptorFactory.parse(testYAML.getAbsolutePath());
+            validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, services, serviceParams);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (testYAML != null) {
+                try {
+                    testYAML.delete();
+                } catch (Exception e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+
+    private void validateSimpleDescriptor(SimpleDescriptor          sd,
+                                          String                    discoveryType,
+                                          String                    discoveryAddress,
+                                          String                    providerConfig,
+                                          String                    clusterName,
                                           Map<String, List<String>> expectedServices) {
+        validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, expectedServices, null);
+    }
+
+
+    private void validateSimpleDescriptor(SimpleDescriptor                 sd,
+                                          String                           discoveryType,
+                                          String                           discoveryAddress,
+                                          String                           providerConfig,
+                                          String                           clusterName,
+                                          Map<String, List<String>>        expectedServices,
+                                          Map<String, Map<String, String>> expectedServiceParameters) {
         assertNotNull(sd);
         assertEquals(discoveryType, sd.getDiscoveryType());
         assertEquals(discoveryAddress, sd.getDiscoveryAddress());
@@ -118,6 +247,25 @@ public class SimpleDescriptorFactoryTest {
         for (SimpleDescriptor.Service actualService : actualServices) {
             assertTrue(expectedServices.containsKey(actualService.getName()));
             assertEquals(expectedServices.get(actualService.getName()), actualService.getURLs());
+
+            // Validate service parameters
+            if (expectedServiceParameters != null) {
+                if (expectedServiceParameters.containsKey(actualService.getName())) {
+                    Map<String, String> expectedParams = expectedServiceParameters.get(actualService.getName());
+
+                    Map<String, String> actualServiceParams = actualService.getParams();
+                    assertNotNull(actualServiceParams);
+
+                    // Validate the size of the service parameter set
+                    assertEquals(expectedParams.size(), actualServiceParams.size());
+
+                    // Validate the parameter contents
+                    for (String paramName : actualServiceParams.keySet()) {
+                        assertTrue(expectedParams.containsKey(paramName));
+                        assertEquals(expectedParams.get(paramName), actualServiceParams.get(paramName));
+                    }
+                }
+            }
         }
     }
 
@@ -141,6 +289,17 @@ public class SimpleDescriptorFactoryTest {
                            String providerConfig,
                            String clusterName,
                            Map<String, List<String>> services) throws Exception {
+        return writeJSON(path, discoveryType, discoveryAddress, discoveryUser, providerConfig, clusterName, services, null);
+    }
+
+    private File writeJSON(String path,
+                           String discoveryType,
+                           String discoveryAddress,
+                           String discoveryUser,
+                           String providerConfig,
+                           String clusterName,
+                           Map<String, List<String>> services,
+                           Map<String, Map<String, String>> serviceParams) throws Exception {
         File f = new File(path);
 
         Writer fw = new FileWriter(f);
@@ -155,9 +314,27 @@ public class SimpleDescriptorFactoryTest {
         int i = 0;
         for (String name : services.keySet()) {
             fw.write("{\"name\":\"" + name + "\"");
+
+            // Service params
+            if (serviceParams != null && !serviceParams.isEmpty()) {
+                Map<String, String> params = serviceParams.get(name);
+                if (params != null && !params.isEmpty()) {
+                    fw.write(",\n\"params\":{\n");
+                    Iterator<String> paramNames = params.keySet().iterator();
+                    while (paramNames.hasNext()) {
+                        String paramName = paramNames.next();
+                        String paramValue = params.get(paramName);
+                        fw.write("\"" + paramName + "\":\"" + paramValue + "\"");
+                        fw.write(paramNames.hasNext() ? ",\n" : "");
+                    }
+                    fw.write("\n}");
+                }
+            }
+
+            // Service URLs
             List<String> urls = services.get(name);
             if (urls != null) {
-                fw.write(", \"urls\":[");
+                fw.write(",\n\"urls\":[");
                 Iterator<String> urlIter = urls.iterator();
                 while (urlIter.hasNext()) {
                     fw.write("\"" + urlIter.next() + "\"");
@@ -165,8 +342,9 @@ public class SimpleDescriptorFactoryTest {
                         fw.write(", ");
                     }
                 }
-                fw.write("]");
+                fw.write("]\n");
             }
+
             fw.write("}");
             if (i++ < services.size() - 1) {
                 fw.write(",");
@@ -181,13 +359,26 @@ public class SimpleDescriptorFactoryTest {
         return f;
     }
 
-    private File writeYAML(String path,
-                           String discoveryType,
-                           String discoveryAddress,
-                           String discoveryUser,
-                           String providerConfig,
-                           String clusterName,
+
+    private File writeYAML(String                    path,
+                           String                    discoveryType,
+                           String                    discoveryAddress,
+                           String                    discoveryUser,
+                           String                    providerConfig,
+                           String                    clusterName,
                            Map<String, List<String>> services) throws Exception {
+        return writeYAML(path, discoveryType, discoveryAddress, discoveryUser, providerConfig, clusterName, services, null);
+    }
+
+
+    private File writeYAML(String                           path,
+                           String                           discoveryType,
+                           String                           discoveryAddress,
+                           String                           discoveryUser,
+                           String                           providerConfig,
+                           String                           clusterName,
+                           Map<String, List<String>>        services,
+                           Map<String, Map<String, String>> serviceParams) throws Exception {
         File f = new File(path);
 
         Writer fw = new FileWriter(f);
@@ -200,6 +391,19 @@ public class SimpleDescriptorFactoryTest {
         fw.write("services:\n");
         for (String name : services.keySet()) {
             fw.write("    - name: " + name + "\n");
+
+            // Service params
+            if (serviceParams != null && !serviceParams.isEmpty()) {
+                if (serviceParams.containsKey(name)) {
+                    Map<String, String> params = serviceParams.get(name);
+                    fw.write("      params:\n");
+                    for (String paramName : params.keySet()) {
+                        fw.write("            " + paramName + ": " + params.get(paramName) + "\n");
+                    }
+                }
+            }
+
+            // Service URLs
             List<String> urls = services.get(name);
             if (urls != null) {
                 fw.write("      urls:\n");

http://git-wip-us.apache.org/repos/asf/knox/blob/0e13dc72/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandlerTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandlerTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandlerTest.java
index f79ef23..a1fda1c 100644
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandlerTest.java
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandlerTest.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.gateway.topology.simple;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 
@@ -131,15 +132,37 @@ public class SimpleDescriptorHandlerTest {
     /**
      * KNOX-1006
      *
-     * N.B. This test depends on the DummyServiceDiscovery extension being configured:
-     *             org.apache.hadoop.gateway.topology.discovery.test.extension.DummyServiceDiscovery
+     * N.B. This test depends on the PropertiesFileServiceDiscovery extension being configured:
+     *             org.apache.hadoop.gateway.topology.discovery.test.extension.PropertiesFileServiceDiscovery
      */
     @Test
     public void testSimpleDescriptorHandler() throws Exception {
 
-        final String type = "DUMMY";
-        final String address = "http://c6401.ambari.apache.org:8080";
+        final String type = "PROPERTIES_FILE";
         final String clusterName = "dummy";
+
+        // Create a properties file to be the source of service discovery details for this test
+        final File discoveryConfig = File.createTempFile(getClass().getName() + "_discovery-config", ".properties");
+
+        final String address = discoveryConfig.getAbsolutePath();
+
+        final Properties DISCOVERY_PROPERTIES = new Properties();
+        DISCOVERY_PROPERTIES.setProperty(clusterName + ".name", clusterName);
+        DISCOVERY_PROPERTIES.setProperty(clusterName + ".NAMENODE", "hdfs://namenodehost:8020");
+        DISCOVERY_PROPERTIES.setProperty(clusterName + ".JOBTRACKER", "rpc://jobtrackerhostname:8050");
+        DISCOVERY_PROPERTIES.setProperty(clusterName + ".WEBHDFS", "http://webhdfshost:1234");
+        DISCOVERY_PROPERTIES.setProperty(clusterName + ".WEBHCAT", "http://webhcathost:50111/templeton");
+        DISCOVERY_PROPERTIES.setProperty(clusterName + ".OOZIE", "http://ooziehost:11000/oozie");
+        DISCOVERY_PROPERTIES.setProperty(clusterName + ".WEBHBASE", "http://webhbasehost:1234");
+        DISCOVERY_PROPERTIES.setProperty(clusterName + ".HIVE", "http://hivehostname:10001/clipath");
+        DISCOVERY_PROPERTIES.setProperty(clusterName + ".RESOURCEMANAGER", "http://remanhost:8088/ws");
+
+        try {
+            DISCOVERY_PROPERTIES.store(new FileOutputStream(discoveryConfig), null);
+        } catch (FileNotFoundException e) {
+            fail(e.getMessage());
+        }
+
         final Map<String, List<String>> serviceURLs = new HashMap<>();
         serviceURLs.put("NAMENODE", null);
         serviceURLs.put("JOBTRACKER", null);
@@ -150,13 +173,21 @@ public class SimpleDescriptorHandlerTest {
         serviceURLs.put("HIVE", null);
         serviceURLs.put("RESOURCEMANAGER", null);
         serviceURLs.put("AMBARIUI", Collections.singletonList("http://c6401.ambari.apache.org:8080"));
+        serviceURLs.put("KNOXSSO", null);
 
         // Write the externalized provider config to a temp file
-        File providerConfig = writeProviderConfig("ambari-cluster-policy.xml", TEST_PROVIDER_CONFIG);
+        File providerConfig = new File(System.getProperty("java.io.tmpdir"), "ambari-cluster-policy.xml");
+        FileUtils.write(providerConfig, TEST_PROVIDER_CONFIG);
 
         File topologyFile = null;
         try {
-            File destDir = (new File(".")).getCanonicalFile();
+            File destDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile();
+
+            Map<String, Map<String, String>> serviceParameters = new HashMap<>();
+            Map<String, String> knoxssoParams = new HashMap<>();
+            knoxssoParams.put("knoxsso.cookie.secure.only", "true");
+            knoxssoParams.put("knoxsso.token.ttl", "100000");
+            serviceParameters.put("KNOXSSO", knoxssoParams);
 
             // Mock out the simple descriptor
             SimpleDescriptor testDescriptor = EasyMock.createNiceMock(SimpleDescriptor.class);
@@ -171,6 +202,7 @@ public class SimpleDescriptorHandlerTest {
                 SimpleDescriptor.Service svc = EasyMock.createNiceMock(SimpleDescriptor.Service.class);
                 EasyMock.expect(svc.getName()).andReturn(serviceName).anyTimes();
                 EasyMock.expect(svc.getURLs()).andReturn(serviceURLs.get(serviceName)).anyTimes();
+                EasyMock.expect(svc.getParams()).andReturn(serviceParameters.get(serviceName)).anyTimes();
                 EasyMock.replay(svc);
                 serviceMocks.add(svc);
             }
@@ -211,28 +243,51 @@ public class SimpleDescriptorHandlerTest {
                         (NodeList) xpath.compile("/topology/service").evaluate(topologyXml, XPathConstants.NODESET);
             for (int serviceNodeIndex=0; serviceNodeIndex < serviceNodes.getLength(); serviceNodeIndex++) {
                 Node serviceNode = serviceNodes.item(serviceNodeIndex);
+
+                // Validate the role
                 Node roleNode = (Node) xpath.compile("role/text()").evaluate(serviceNode, XPathConstants.NODE);
                 assertNotNull(roleNode);
                 String role = roleNode.getNodeValue();
+
+                // Validate the URLs
                 NodeList urlNodes = (NodeList) xpath.compile("url/text()").evaluate(serviceNode, XPathConstants.NODESET);
                 for(int urlNodeIndex = 0 ; urlNodeIndex < urlNodes.getLength(); urlNodeIndex++) {
                     Node urlNode = urlNodes.item(urlNodeIndex);
                     assertNotNull(urlNode);
                     String url = urlNode.getNodeValue();
-                    assertNotNull("Every declared service should have a URL.", url);
-                    if (!topologyServiceURLs.containsKey(role)) {
-                        topologyServiceURLs.put(role, new ArrayList<String>());
+
+                    // If the service should have a URL (some don't require it)
+                    if (serviceURLs.containsKey(role)) {
+                        assertNotNull("Declared service should have a URL.", url);
+                        if (!topologyServiceURLs.containsKey(role)) {
+                            topologyServiceURLs.put(role, new ArrayList<>());
+                        }
+                        topologyServiceURLs.get(role).add(url); // Add it for validation later
+                    }
+                }
+
+                // If params were declared in the descriptor, then validate them in the resulting topology file
+                Map<String, String> params = serviceParameters.get(role);
+                if (params != null) {
+                    NodeList paramNodes = (NodeList) xpath.compile("param").evaluate(serviceNode, XPathConstants.NODESET);
+                    for (int paramNodeIndex = 0; paramNodeIndex < paramNodes.getLength(); paramNodeIndex++) {
+                        Node paramNode = paramNodes.item(paramNodeIndex);
+                        String paramName = (String) xpath.compile("name/text()").evaluate(paramNode, XPathConstants.STRING);
+                        String paramValue = (String) xpath.compile("value/text()").evaluate(paramNode, XPathConstants.STRING);
+                        assertTrue(params.keySet().contains(paramName));
+                        assertEquals(params.get(paramName), paramValue);
                     }
-                    topologyServiceURLs.get(role).add(url);
                 }
+
             }
-            assertEquals("Unexpected number of service declarations.", serviceURLs.size(), topologyServiceURLs.size());
+            assertEquals("Unexpected number of service declarations.", (serviceURLs.size() - 1), topologyServiceURLs.size());
 
         } catch (Exception e) {
             e.printStackTrace();
             fail(e.getMessage());
         } finally {
             providerConfig.delete();
+            discoveryConfig.delete();
             if (topologyFile != null) {
                 topologyFile.delete();
             }
@@ -358,7 +413,7 @@ public class SimpleDescriptorHandlerTest {
                     String url = urlNode.getNodeValue();
                     assertNotNull("Every declared service should have a URL.", url);
                     if (!topologyServiceURLs.containsKey(role)) {
-                        topologyServiceURLs.put(role, new ArrayList<String>());
+                        topologyServiceURLs.put(role, new ArrayList<>());
                     }
                     topologyServiceURLs.get(role).add(url);
                 }