http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorImpl.java ---------------------------------------------------------------------- diff --cc gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorImpl.java index 4eb1954,0000000..f3288fd mode 100644,000000..100644 --- a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorImpl.java +++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorImpl.java @@@ -1,123 -1,0 +1,163 @@@ +/** + * 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.knox.gateway.topology.simple; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +class SimpleDescriptorImpl implements SimpleDescriptor { + + @JsonProperty("discovery-type") + private String discoveryType; + + @JsonProperty("discovery-address") + private String discoveryAddress; + + @JsonProperty("discovery-user") + private String discoveryUser; + + @JsonProperty("discovery-pwd-alias") + private String discoveryPasswordAlias; + + @JsonProperty("provider-config-ref") + private String providerConfig; + + @JsonProperty("cluster") + private String cluster; + + @JsonProperty("services") + private List<ServiceImpl> services; + ++ @JsonProperty("applications") ++ private List<ApplicationImpl> applications; ++ + private String name = null; + + void setName(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDiscoveryType() { + return discoveryType; + } + + @Override + public String getDiscoveryAddress() { + return discoveryAddress; + } + + @Override + public String getDiscoveryUser() { + return discoveryUser; + } + + @Override + public String getDiscoveryPasswordAlias() { + return discoveryPasswordAlias; + } + + @Override + public String getClusterName() { + return cluster; + } + + @Override + public String getProviderConfig() { + return providerConfig; + } + + @Override + public List<Service> getServices() { + List<Service> result = new ArrayList<>(); - result.addAll(services); ++ if (services != null) { ++ result.addAll(services); ++ } ++ return result; ++ } ++ ++ @Override ++ public List<Application> getApplications() { ++ List<Application> result = new ArrayList<>(); ++ if (applications != null) { ++ result.addAll(applications); ++ } + return result; + } + + 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 + public String getName() { + return name; + } + + @Override + public Map<String, String> getParams() { + return params; + } + + @Override + public List<String> getURLs() { + return urls; + } + } + ++ public static class ApplicationImpl implements Application { ++ @JsonProperty("name") ++ private String name; ++ ++ @JsonProperty("params") ++ private Map<String, String> params; ++ ++ @JsonProperty("urls") ++ private List<String> urls; ++ ++ @Override ++ public String getName() { ++ return name; ++ } ++ ++ @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/2c69152f/gateway-server/src/main/java/org/apache/knox/gateway/topology/xml/KnoxFormatXmlTopologyRules.java ---------------------------------------------------------------------- diff --cc gateway-server/src/main/java/org/apache/knox/gateway/topology/xml/KnoxFormatXmlTopologyRules.java index 81aedec,0000000..a1fcb6d mode 100644,000000..100644 --- a/gateway-server/src/main/java/org/apache/knox/gateway/topology/xml/KnoxFormatXmlTopologyRules.java +++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/xml/KnoxFormatXmlTopologyRules.java @@@ -1,95 -1,0 +1,97 @@@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.knox.gateway.topology.xml; + +import org.apache.commons.digester3.Rule; +import org.apache.commons.digester3.binder.AbstractRulesModule; +import org.apache.knox.gateway.topology.Application; +import org.apache.knox.gateway.topology.Param; +import org.apache.knox.gateway.topology.Provider; +import org.apache.knox.gateway.topology.Service; +import org.apache.knox.gateway.topology.Version; +import org.apache.knox.gateway.topology.builder.BeanPropertyTopologyBuilder; +import org.xml.sax.Attributes; + +public class KnoxFormatXmlTopologyRules extends AbstractRulesModule { + + private static final String ROOT_TAG = "topology"; + private static final String NAME_TAG = "name"; + private static final String VERSION_TAG = "version"; + private static final String DEFAULT_SERVICE_TAG = "path"; ++ private static final String GENERATED_TAG = "generated"; + private static final String APPLICATION_TAG = "application"; + private static final String SERVICE_TAG = "service"; + private static final String ROLE_TAG = "role"; + private static final String URL_TAG = "url"; + private static final String PROVIDER_TAG = "gateway/provider"; + private static final String ENABLED_TAG = "enabled"; + private static final String PARAM_TAG = "param"; + private static final String VALUE_TAG = "value"; + + private static final Rule paramRule = new ParamRule(); + + @Override + protected void configure() { + forPattern( ROOT_TAG ).createObject().ofType( BeanPropertyTopologyBuilder.class ); + forPattern( ROOT_TAG + "/" + NAME_TAG ).callMethod("name").usingElementBodyAsArgument(); + forPattern( ROOT_TAG + "/" + VERSION_TAG ).callMethod("version").usingElementBodyAsArgument(); + forPattern( ROOT_TAG + "/" + DEFAULT_SERVICE_TAG ).callMethod("defaultService").usingElementBodyAsArgument(); ++ forPattern( ROOT_TAG + "/" + GENERATED_TAG ).callMethod("generated").usingElementBodyAsArgument(); + + forPattern( ROOT_TAG + "/" + APPLICATION_TAG ).createObject().ofType( Application.class ).then().setNext( "addApplication" ); + forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + ROLE_TAG ).setBeanProperty(); + forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + NAME_TAG ).setBeanProperty(); + forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + VERSION_TAG ).createObject().ofType(Version.class).then().setBeanProperty().then().setNext("setVersion"); + forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + URL_TAG ).callMethod( "addUrl" ).usingElementBodyAsArgument(); + forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + PARAM_TAG ).createObject().ofType( Param.class ).then().addRule( paramRule ).then().setNext( "addParam" ); + forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + PARAM_TAG + "/" + NAME_TAG ).setBeanProperty(); + forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + PARAM_TAG + "/" + VALUE_TAG ).setBeanProperty(); + + forPattern( ROOT_TAG + "/" + SERVICE_TAG ).createObject().ofType( Service.class ).then().setNext( "addService" ); + forPattern( ROOT_TAG + "/" + SERVICE_TAG + "/" + ROLE_TAG ).setBeanProperty(); + forPattern( ROOT_TAG + "/" + SERVICE_TAG + "/" + NAME_TAG ).setBeanProperty(); + forPattern( ROOT_TAG + "/" + SERVICE_TAG + "/" + VERSION_TAG ).createObject().ofType(Version.class).then().setBeanProperty().then().setNext("setVersion"); + forPattern( ROOT_TAG + "/" + SERVICE_TAG + "/" + URL_TAG ).callMethod( "addUrl" ).usingElementBodyAsArgument(); + forPattern( ROOT_TAG + "/" + SERVICE_TAG + "/" + PARAM_TAG ).createObject().ofType( Param.class ).then().addRule( paramRule ).then().setNext( "addParam" ); + forPattern( ROOT_TAG + "/" + SERVICE_TAG + "/" + PARAM_TAG + "/" + NAME_TAG ).setBeanProperty(); + forPattern( ROOT_TAG + "/" + SERVICE_TAG + "/" + PARAM_TAG + "/" + VALUE_TAG ).setBeanProperty(); + + forPattern( ROOT_TAG + "/" + PROVIDER_TAG ).createObject().ofType( Provider.class ).then().setNext( "addProvider" ); + forPattern( ROOT_TAG + "/" + PROVIDER_TAG + "/" + ROLE_TAG ).setBeanProperty(); + forPattern( ROOT_TAG + "/" + PROVIDER_TAG + "/" + ENABLED_TAG ).setBeanProperty(); + forPattern( ROOT_TAG + "/" + PROVIDER_TAG + "/" + NAME_TAG ).setBeanProperty(); + forPattern( ROOT_TAG + "/" + PROVIDER_TAG + "/" + PARAM_TAG ).createObject().ofType( Param.class ).then().addRule( paramRule ).then().setNext( "addParam" ); + forPattern( ROOT_TAG + "/" + PROVIDER_TAG + "/" + PARAM_TAG + "/" + NAME_TAG ).setBeanProperty(); + forPattern( ROOT_TAG + "/" + PROVIDER_TAG + "/" + PARAM_TAG + "/" + VALUE_TAG ).setBeanProperty(); + } + + private static class ParamRule extends Rule { + + @Override + public void begin( String namespace, String name, Attributes attributes ) { + Param param = getDigester().peek(); + String paramName = attributes.getValue( "name" ); + if( paramName != null ) { + param.setName( paramName ); + param.setValue( attributes.getValue( "value" ) ); + } + } + + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java ---------------------------------------------------------------------- diff --cc gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java index 41a7c10,0000000..df31f3d mode 100644,000000..100644 --- a/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java +++ b/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java @@@ -1,422 -1,0 +1,681 @@@ +/** + * 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.knox.gateway.topology.simple; + +import java.io.File; +import java.io.FileWriter; +import java.io.Writer; +import java.util.*; + +import org.junit.Test; +import static org.junit.Assert.*; + + +public class SimpleDescriptorFactoryTest { + ++ private enum FileType { ++ JSON, ++ YAML ++ } + + @Test + public void testParseJSONSimpleDescriptor() throws Exception { ++ testParseSimpleDescriptor(FileType.JSON); ++ } ++ ++ @Test ++ public void testParseYAMLSimpleDescriptor() throws Exception { ++ testParseSimpleDescriptor(FileType.YAML); ++ } ++ ++ @Test ++ public void testParseJSONSimpleDescriptorWithServiceParams() throws Exception { ++ testParseSimpleDescriptorWithServiceParams(FileType.JSON); ++ } ++ ++ @Test ++ public void testParseYAMLSimpleDescriptorWithServiceParams() throws Exception { ++ testParseSimpleDescriptorWithServiceParams(FileType.YAML); ++ } ++ ++ @Test ++ public void testParseJSONSimpleDescriptorWithApplications() throws Exception { ++ testParseSimpleDescriptorWithApplications(FileType.JSON); ++ } ++ ++ @Test ++ public void testParseYAMLSimpleDescriptorApplications() throws Exception { ++ testParseSimpleDescriptorWithApplications(FileType.YAML); ++ } ++ ++ ++ @Test ++ public void testParseJSONSimpleDescriptorWithServicesAndApplications() throws Exception { ++ testParseSimpleDescriptorWithServicesAndApplications(FileType.JSON); ++ } ++ ++ @Test ++ public void testParseYAMLSimpleDescriptorWithServicesAndApplications() throws Exception { ++ testParseSimpleDescriptorWithServicesAndApplications(FileType.YAML); ++ } ++ + ++ private void testParseSimpleDescriptor(FileType type) throws Exception { + final String discoveryType = "AMBARI"; + final String discoveryAddress = "http://c6401.ambari.apache.org:8080"; - final String discoveryUser = "admin"; ++ 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("AMBARIUI", Collections.singletonList("http://c6401.ambari.apache.org:8080")); + - String fileName = "test-topology.json"; - File testJSON = null; ++ String fileName = "test-topology." + getFileExtensionForType(type); ++ File testFile = null; + try { - testJSON = writeJSON(fileName, discoveryType, discoveryAddress, discoveryUser, providerConfig, clusterName, services); - SimpleDescriptor sd = SimpleDescriptorFactory.parse(testJSON.getAbsolutePath()); ++ testFile = writeDescriptorFile(type, ++ fileName, ++ discoveryType, ++ discoveryAddress, ++ discoveryUser, ++ providerConfig, ++ clusterName, ++ services); ++ SimpleDescriptor sd = SimpleDescriptorFactory.parse(testFile.getAbsolutePath()); + validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, services); + } catch (Exception e) { + e.printStackTrace(); + } finally { - if (testJSON != null) { ++ if (testFile != null) { + try { - testJSON.delete(); ++ testFile.delete(); + } catch (Exception e) { + // Ignore + } + } + } + } + - @Test - public void testParseJSONSimpleDescriptorWithServiceParams() throws Exception { ++ private void testParseSimpleDescriptorWithServiceParams(FileType type) 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; ++ String fileName = "test-topology." + getFileExtensionForType(type); ++ File testFile = null; + try { - testJSON = writeJSON(fileName, - discoveryType, - discoveryAddress, - discoveryUser, - providerConfig, - clusterName, - services, - serviceParams); - SimpleDescriptor sd = SimpleDescriptorFactory.parse(testJSON.getAbsolutePath()); ++ testFile = writeDescriptorFile(type, ++ fileName, ++ discoveryType, ++ discoveryAddress, ++ discoveryUser, ++ providerConfig, ++ clusterName, ++ services, ++ serviceParams); ++ SimpleDescriptor sd = SimpleDescriptorFactory.parse(testFile.getAbsolutePath()); + validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, services, serviceParams); - } catch (Exception e) { - e.printStackTrace(); + } finally { - if (testJSON != null) { ++ if (testFile != null) { + try { - testJSON.delete(); ++ testFile.delete(); + } catch (Exception e) { + // Ignore + } + } + } + } + - @Test - public void testParseYAMLSimpleDescriptor() throws Exception { ++ private void testParseSimpleDescriptorWithApplications(FileType type) throws Exception { + + final String discoveryType = "AMBARI"; + final String discoveryAddress = "http://c6401.ambari.apache.org:8080"; - final String discoveryUser = "joeblow"; ++ 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", Arrays.asList("http://c6401.ambari.apache.org:8080")); - - String fileName = "test-topology.yml"; - File testYAML = null; ++ final Map<String, List<String>> apps = new HashMap<>(); ++ apps.put("app-one", null); ++ apps.put("appTwo", null); ++ apps.put("thirdApps", null); ++ apps.put("appfour", Arrays.asList("http://host1:1234", "http://host2:5678", "http://host1:1357")); ++ apps.put("AppFive", Collections.singletonList("http://host5:8080")); ++ ++ final Map<String, Map<String, String>> appParams = new HashMap<>(); ++ Map<String, String> oneParams = new HashMap<>(); ++ oneParams.put("appone.cookie.secure.only", "true"); ++ oneParams.put("appone.token.ttl", "100000"); ++ appParams.put("app-one", oneParams); ++ Map<String, String> fiveParams = new HashMap<>(); ++ fiveParams.put("myproperty", "true"); ++ fiveParams.put("anotherparam", "100000"); ++ appParams.put("AppFive", fiveParams); ++ ++ String fileName = "test-topology." + getFileExtensionForType(type); ++ File testFile = null; + try { - testYAML = writeYAML(fileName, discoveryType, discoveryAddress, discoveryUser, providerConfig, clusterName, services); - SimpleDescriptor sd = SimpleDescriptorFactory.parse(testYAML.getAbsolutePath()); - validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, services); - } catch (Exception e) { - e.printStackTrace(); ++ testFile = writeDescriptorFile(type, ++ fileName, ++ discoveryType, ++ discoveryAddress, ++ discoveryUser, ++ providerConfig, ++ clusterName, ++ null, ++ null, ++ apps, ++ appParams); ++ SimpleDescriptor sd = SimpleDescriptorFactory.parse(testFile.getAbsolutePath()); ++ validateSimpleDescriptor(sd, ++ discoveryType, ++ discoveryAddress, ++ providerConfig, ++ clusterName, ++ null, ++ null, ++ apps, ++ appParams); + } finally { - if (testYAML != null) { ++ if (testFile != null) { + try { - testYAML.delete(); ++ testFile.delete(); + } catch (Exception e) { + // Ignore + } + } + } + } + - - @Test - public void testParseYAMLSimpleDescriptorWithServiceParams() throws Exception { ++ private void testParseSimpleDescriptorWithServicesAndApplications(FileType type) throws Exception { + + final String discoveryType = "AMBARI"; + final String discoveryAddress = "http://c6401.ambari.apache.org:8080"; - final String discoveryUser = "joeblow"; ++ 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", Arrays.asList("http://c6401.ambari.apache.org:8080")); ++ 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.yml"; - File testYAML = null; ++ final Map<String, List<String>> apps = new HashMap<>(); ++ apps.put("app-one", null); ++ apps.put("appTwo", null); ++ apps.put("thirdApps", null); ++ apps.put("appfour", Arrays.asList("http://host1:1234", "http://host2:5678", "http://host1:1357")); ++ apps.put("AppFive", Collections.singletonList("http://host5:8080")); ++ ++ final Map<String, Map<String, String>> appParams = new HashMap<>(); ++ Map<String, String> oneParams = new HashMap<>(); ++ oneParams.put("appone.cookie.secure.only", "true"); ++ oneParams.put("appone.token.ttl", "100000"); ++ appParams.put("app-one", oneParams); ++ Map<String, String> fiveParams = new HashMap<>(); ++ fiveParams.put("myproperty", "true"); ++ fiveParams.put("anotherparam", "100000"); ++ appParams.put("AppFive", fiveParams); ++ ++ String fileName = "test-topology." + getFileExtensionForType(type); ++ File testFile = 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(); ++ testFile = writeDescriptorFile(type, ++ fileName, ++ discoveryType, ++ discoveryAddress, ++ discoveryUser, ++ providerConfig, ++ clusterName, ++ services, ++ serviceParams, ++ apps, ++ appParams); ++ SimpleDescriptor sd = SimpleDescriptorFactory.parse(testFile.getAbsolutePath()); ++ validateSimpleDescriptor(sd, ++ discoveryType, ++ discoveryAddress, ++ providerConfig, ++ clusterName, ++ services, ++ serviceParams, ++ apps, ++ appParams); + } finally { - if (testYAML != null) { ++ if (testFile != null) { + try { - testYAML.delete(); ++ testFile.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()); - assertEquals(providerConfig, sd.getProviderConfig()); - assertEquals(clusterName, sd.getClusterName()); - - List<SimpleDescriptor.Service> actualServices = sd.getServices(); - - assertEquals(expectedServices.size(), actualServices.size()); - - 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)); - } - } - } ++ private String getFileExtensionForType(FileType type) { ++ String extension = null; ++ switch (type) { ++ case JSON: ++ extension = "json"; ++ break; ++ case YAML: ++ extension = "yml"; ++ break; + } ++ return extension; + } + ++ private File writeDescriptorFile(FileType type, ++ String path, ++ String discoveryType, ++ String discoveryAddress, ++ String discoveryUser, ++ String providerConfig, ++ String clusterName, ++ Map<String, List<String>> services) throws Exception { ++ return writeDescriptorFile(type, ++ path, ++ discoveryType, ++ discoveryAddress, ++ discoveryUser, ++ providerConfig, ++ clusterName, ++ services, ++ null); ++ } + - private File writeJSON(String path, String content) throws Exception { - File f = new File(path); - - Writer fw = new FileWriter(f); - fw.write(content); - fw.flush(); - fw.close(); - - return f; ++ private File writeDescriptorFile(FileType type, ++ 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 { ++ return writeDescriptorFile(type, ++ path, ++ discoveryType, ++ discoveryAddress, ++ discoveryUser, ++ providerConfig, ++ clusterName, ++ services, ++ serviceParams, ++ null, ++ null); + } + + - private File writeJSON(String path, - String discoveryType, - String discoveryAddress, - String discoveryUser, - String providerConfig, - String clusterName, - Map<String, List<String>> services) throws Exception { - return writeJSON(path, discoveryType, discoveryAddress, discoveryUser, providerConfig, clusterName, services, null); ++ private File writeDescriptorFile(FileType type, ++ String path, ++ String discoveryType, ++ String discoveryAddress, ++ String discoveryUser, ++ String providerConfig, ++ String clusterName, ++ Map<String, List<String>> services, ++ Map<String, Map<String, String>> serviceParams, ++ Map<String, List<String>> apps, ++ Map<String, Map<String, String>> appParams) throws Exception { ++ File result = null; ++ switch (type) { ++ case JSON: ++ result = writeJSON(path, ++ discoveryType, ++ discoveryAddress, ++ discoveryUser, ++ providerConfig, ++ clusterName, ++ services, ++ serviceParams, ++ apps, ++ appParams); ++ break; ++ case YAML: ++ result = writeYAML(path, ++ discoveryType, ++ discoveryAddress, ++ discoveryUser, ++ providerConfig, ++ clusterName, ++ services, ++ serviceParams, ++ apps, ++ appParams); ++ break; ++ } ++ return result; + } + ++ + 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 { ++ Map<String, Map<String, String>> serviceParams, ++ Map<String, List<String>> apps, ++ Map<String, Map<String, String>> appParams) throws Exception { + File f = new File(path); + + Writer fw = new FileWriter(f); + fw.write("{" + "\n"); + fw.write("\"discovery-type\":\"" + discoveryType + "\",\n"); + fw.write("\"discovery-address\":\"" + discoveryAddress + "\",\n"); + fw.write("\"discovery-user\":\"" + discoveryUser + "\",\n"); + fw.write("\"provider-config-ref\":\"" + providerConfig + "\",\n"); - fw.write("\"cluster\":\"" + clusterName + "\",\n"); - fw.write("\"services\":[\n"); - - 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}"); - } - } ++ fw.write("\"cluster\":\"" + clusterName + "\""); + - // Service URLs - List<String> urls = services.get(name); - if (urls != null) { - fw.write(",\n\"urls\":["); - Iterator<String> urlIter = urls.iterator(); - while (urlIter.hasNext()) { - fw.write("\"" + urlIter.next() + "\""); - if (urlIter.hasNext()) { - fw.write(", "); - } - } - fw.write("]\n"); - } ++ if (services != null && !services.isEmpty()) { ++ fw.write(",\n\"services\":[\n"); ++ writeServiceOrApplicationJSON(fw, services, serviceParams); ++ fw.write("]\n"); ++ } + - fw.write("}"); - if (i++ < services.size() - 1) { - fw.write(","); - } - fw.write("\n"); ++ if (apps != null && !apps.isEmpty()) { ++ fw.write(",\n\"applications\":[\n"); ++ writeServiceOrApplicationJSON(fw, apps, appParams); ++ fw.write("]\n"); + } - fw.write("]\n"); ++ + fw.write("}\n"); + fw.flush(); + fw.close(); + + return f; + } + ++ private void writeServiceOrApplicationJSON(Writer fw, ++ Map<String, List<String>> elementURLs, ++ Map<String, Map<String, String>> elementParams) throws Exception { ++ if (elementURLs != null) { ++ int i = 0; ++ for (String name : elementURLs.keySet()) { ++ fw.write("{\"name\":\"" + name + "\""); ++ ++ // Service params ++ if (elementParams != null && !elementParams.isEmpty()) { ++ Map<String, String> params = elementParams.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}"); ++ } ++ } + - 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); - } ++ // Service URLs ++ List<String> urls = elementURLs.get(name); ++ if (urls != null) { ++ fw.write(",\n\"urls\":["); ++ Iterator<String> urlIter = urls.iterator(); ++ while (urlIter.hasNext()) { ++ fw.write("\"" + urlIter.next() + "\""); ++ if (urlIter.hasNext()) { ++ fw.write(", "); ++ } ++ } ++ fw.write("]\n"); ++ } + ++ fw.write("}"); ++ if (i++ < elementURLs.size() - 1) { ++ fw.write(","); ++ } ++ fw.write("\n"); ++ } ++ } ++ } + + 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 { ++ Map<String, Map<String, String>> serviceParams, ++ Map<String, List<String>> apps, ++ Map<String, Map<String, String>> appParams) throws Exception { ++ + File f = new File(path); + + Writer fw = new FileWriter(f); + fw.write("---" + "\n"); + fw.write("discovery-type: " + discoveryType + "\n"); + fw.write("discovery-address: " + discoveryAddress + "\n"); + fw.write("discovery-user: " + discoveryUser + "\n"); + fw.write("provider-config-ref: " + providerConfig + "\n"); + fw.write("cluster: " + clusterName+ "\n"); - fw.write("services:\n"); - for (String name : services.keySet()) { ++ ++ if (services != null && !services.isEmpty()) { ++ fw.write("services:\n"); ++ writeServiceOrApplicationYAML(fw, services, serviceParams); ++ } ++ ++ if (apps != null && !apps.isEmpty()) { ++ fw.write("applications:\n"); ++ writeServiceOrApplicationYAML(fw, apps, appParams); ++ } ++ ++ fw.flush(); ++ fw.close(); ++ ++ return f; ++ } ++ ++ private void writeServiceOrApplicationYAML(Writer fw, ++ Map<String, List<String>> elementURLs, ++ Map<String, Map<String, String>> elementParams) throws Exception { ++ for (String name : elementURLs.keySet()) { + fw.write(" - name: " + name + "\n"); + + // Service params - if (serviceParams != null && !serviceParams.isEmpty()) { - if (serviceParams.containsKey(name)) { - Map<String, String> params = serviceParams.get(name); ++ if (elementParams != null && !elementParams.isEmpty()) { ++ if (elementParams.containsKey(name)) { ++ Map<String, String> params = elementParams.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); ++ List<String> urls = elementURLs.get(name); + if (urls != null) { + fw.write(" urls:\n"); + for (String url : urls) { + fw.write(" - " + url + "\n"); + } + } + } - fw.flush(); - fw.close(); ++ } + - return f; ++ ++ 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) { ++ validateSimpleDescriptor(sd, ++ discoveryType, ++ discoveryAddress, ++ providerConfig, ++ clusterName, ++ expectedServices, ++ expectedServiceParameters, ++ null, ++ 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, ++ Map<String, List<String>> expectedApps, ++ Map<String, Map<String, String>> expectedAppParameters) { ++ assertNotNull(sd); ++ assertEquals(discoveryType, sd.getDiscoveryType()); ++ assertEquals(discoveryAddress, sd.getDiscoveryAddress()); ++ assertEquals(providerConfig, sd.getProviderConfig()); ++ assertEquals(clusterName, sd.getClusterName()); ++ ++ List<SimpleDescriptor.Service> actualServices = sd.getServices(); ++ ++ if (expectedServices == null) { ++ assertTrue(actualServices.isEmpty()); ++ } else { ++ assertEquals(expectedServices.size(), actualServices.size()); ++ ++ 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)); ++ } ++ } ++ } ++ } ++ } ++ ++ List<SimpleDescriptor.Application> actualApps = sd.getApplications(); ++ ++ if (expectedApps == null) { ++ assertTrue(actualApps.isEmpty()); ++ } else { ++ assertEquals(expectedApps.size(), actualApps.size()); ++ ++ for (SimpleDescriptor.Application actualApp : actualApps) { ++ assertTrue(expectedApps.containsKey(actualApp.getName())); ++ assertEquals(expectedApps.get(actualApp.getName()), actualApp.getURLs()); ++ ++ // Validate service parameters ++ if (expectedServiceParameters != null) { ++ if (expectedAppParameters.containsKey(actualApp.getName())) { ++ Map<String, String> expectedParams = expectedAppParameters.get(actualApp.getName()); ++ ++ Map<String, String> actualAppParams = actualApp.getParams(); ++ assertNotNull(actualAppParams); ++ ++ // Validate the size of the service parameter set ++ assertEquals(expectedParams.size(), actualAppParams.size()); ++ ++ // Validate the parameter contents ++ for (String paramName : actualAppParams.keySet()) { ++ assertTrue(expectedParams.containsKey(paramName)); ++ assertEquals(expectedParams.get(paramName), actualAppParams.get(paramName)); ++ } ++ } ++ } ++ } ++ } ++ } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandlerTest.java ---------------------------------------------------------------------- diff --cc gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandlerTest.java index f40fad7,0000000..575b68a mode 100644,000000..100644 --- a/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandlerTest.java +++ b/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandlerTest.java @@@ -1,447 -1,0 +1,455 @@@ +/** + * 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.knox.gateway.topology.simple; + +import org.apache.knox.gateway.topology.validation.TopologyValidator; +import org.apache.knox.gateway.util.XmlUtils; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; + +import org.apache.commons.io.FileUtils; +import org.easymock.EasyMock; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + ++import static org.hamcrest.Matchers.hasXPath; ++import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; ++import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + + +public class SimpleDescriptorHandlerTest { + + private static final String TEST_PROVIDER_CONFIG = + " <gateway>\n" + + " <provider>\n" + + " <role>authentication</role>\n" + + " <name>ShiroProvider</name>\n" + + " <enabled>true</enabled>\n" + + " <param>\n" + + " <!-- \n" + + " session timeout in minutes, this is really idle timeout,\n" + + " defaults to 30mins, if the property value is not defined,, \n" + + " current client authentication would expire if client idles contiuosly for more than this value\n" + + " -->\n" + + " <name>sessionTimeout</name>\n" + + " <value>30</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapRealm</name>\n" + + " <value>org.apache.knox.gateway.shirorealm.KnoxLdapRealm</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapContextFactory</name>\n" + + " <value>org.apache.knox.gateway.shirorealm.KnoxLdapContextFactory</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapRealm.contextFactory</name>\n" + + " <value>$ldapContextFactory</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapRealm.userDnTemplate</name>\n" + + " <value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapRealm.contextFactory.url</name>\n" + + " <value>ldap://localhost:33389</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapRealm.contextFactory.authenticationMechanism</name>\n" + + " <value>simple</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>urls./**</name>\n" + + " <value>authcBasic</value>\n" + + " </param>\n" + + " </provider>\n" + + "\n" + + " <provider>\n" + + " <role>identity-assertion</role>\n" + + " <name>Default</name>\n" + + " <enabled>true</enabled>\n" + + " </provider>\n" + + "\n" + + " <!--\n" + + " Defines rules for mapping host names internal to a Hadoop cluster to externally accessible host names.\n" + + " For example, a hadoop service running in AWS may return a response that includes URLs containing the\n" + + " some AWS internal host name. If the client needs to make a subsequent request to the host identified\n" + + " in those URLs they need to be mapped to external host names that the client Knox can use to connect.\n" + + "\n" + + " If the external hostname and internal host names are same turn of this provider by setting the value of\n" + + " enabled parameter as false.\n" + + "\n" + + " The name parameter specifies the external host names in a comma separated list.\n" + + " The value parameter specifies corresponding internal host names in a comma separated list.\n" + + "\n" + + " Note that when you are using Sandbox, the external hostname needs to be localhost, as seen in out\n" + + " of box sandbox.xml. This is because Sandbox uses port mapping to allow clients to connect to the\n" + + " Hadoop services using localhost. In real clusters, external host names would almost never be localhost.\n" + + " -->\n" + + " <provider>\n" + + " <role>hostmap</role>\n" + + " <name>static</name>\n" + + " <enabled>true</enabled>\n" + + " <param><name>localhost</name><value>sandbox,sandbox.hortonworks.com</value></param>\n" + + " </provider>\n" + + " </gateway>\n"; + + + /** + * KNOX-1006 + * + * N.B. This test depends on the PropertiesFileServiceDiscovery extension being configured: + * org.apache.knox.gateway.topology.discovery.test.extension.PropertiesFileServiceDiscovery + */ + @Test + public void testSimpleDescriptorHandler() throws Exception { + + 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); + serviceURLs.put("WEBHDFS", null); + serviceURLs.put("WEBHCAT", null); + serviceURLs.put("OOZIE", null); + serviceURLs.put("WEBHBASE", null); + 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 = 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(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); + EasyMock.expect(testDescriptor.getName()).andReturn("mysimpledescriptor").anyTimes(); + EasyMock.expect(testDescriptor.getDiscoveryAddress()).andReturn(address).anyTimes(); + EasyMock.expect(testDescriptor.getDiscoveryType()).andReturn(type).anyTimes(); + EasyMock.expect(testDescriptor.getDiscoveryUser()).andReturn(null).anyTimes(); + EasyMock.expect(testDescriptor.getProviderConfig()).andReturn(providerConfig.getAbsolutePath()).anyTimes(); + EasyMock.expect(testDescriptor.getClusterName()).andReturn(clusterName).anyTimes(); + List<SimpleDescriptor.Service> serviceMocks = new ArrayList<>(); + for (String serviceName : serviceURLs.keySet()) { + 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); + } + EasyMock.expect(testDescriptor.getServices()).andReturn(serviceMocks).anyTimes(); + EasyMock.replay(testDescriptor); + + // Invoke the simple descriptor handler + Map<String, File> files = + SimpleDescriptorHandler.handle(testDescriptor, + providerConfig.getParentFile(), // simple desc co-located with provider config + destDir); + topologyFile = files.get("topology"); + + // Validate the resulting topology descriptor + assertTrue(topologyFile.exists()); + + // Validate the topology descriptor's correctness + TopologyValidator validator = new TopologyValidator( topologyFile.getAbsolutePath() ); + if( !validator.validateTopology() ){ + throw new SAXException( validator.getErrorString() ); + } + + XPathFactory xPathfactory = XPathFactory.newInstance(); + XPath xpath = xPathfactory.newXPath(); + + // Parse the topology descriptor + Document topologyXml = XmlUtils.readXml(topologyFile); + ++ // KNOX-1105 Mark generated topology files ++ assertThat("Expected the \"generated\" marker element in the topology XML, with value of \"true\".", ++ topologyXml, ++ hasXPath("/topology/generated", is("true"))); ++ + // Validate the provider configuration + Document extProviderConf = XmlUtils.readXml(new ByteArrayInputStream(TEST_PROVIDER_CONFIG.getBytes())); + Node gatewayNode = (Node) xpath.compile("/topology/gateway").evaluate(topologyXml, XPathConstants.NODE); + assertTrue("Resulting provider config should be identical to the referenced content.", + extProviderConf.getDocumentElement().isEqualNode(gatewayNode)); + + // Validate the service declarations + Map<String, List<String>> topologyServiceURLs = new HashMap<>(); + NodeList serviceNodes = + (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(); + + // 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); + } + } + + } + 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(); + } + } + } + + + /** + * KNOX-1006 + * + * Verify the behavior of the SimpleDescriptorHandler when service discovery fails to produce a valid URL for + * a service. + * + * N.B. This test depends on the PropertiesFileServiceDiscovery extension being configured: + * org.apache.knox.gateway.topology.discovery.test.extension.PropertiesFileServiceDiscovery + */ + @Test + public void testInvalidServiceURLFromDiscovery() throws Exception { + final String CLUSTER_NAME = "myproperties"; + + // Configure the PropertiesFile Service Discovery implementation for this test + final String DEFAULT_VALID_SERVICE_URL = "http://localhost:9999/thiswillwork"; + Properties serviceDiscoverySourceProps = new Properties(); + serviceDiscoverySourceProps.setProperty(CLUSTER_NAME + ".NAMENODE", + DEFAULT_VALID_SERVICE_URL.replace("http", "hdfs")); + serviceDiscoverySourceProps.setProperty(CLUSTER_NAME + ".JOBTRACKER", + DEFAULT_VALID_SERVICE_URL.replace("http", "rpc")); + serviceDiscoverySourceProps.setProperty(CLUSTER_NAME + ".WEBHDFS", DEFAULT_VALID_SERVICE_URL); + serviceDiscoverySourceProps.setProperty(CLUSTER_NAME + ".WEBHCAT", DEFAULT_VALID_SERVICE_URL); + serviceDiscoverySourceProps.setProperty(CLUSTER_NAME + ".OOZIE", DEFAULT_VALID_SERVICE_URL); + serviceDiscoverySourceProps.setProperty(CLUSTER_NAME + ".WEBHBASE", DEFAULT_VALID_SERVICE_URL); + serviceDiscoverySourceProps.setProperty(CLUSTER_NAME + ".HIVE", "{SCHEME}://localhost:10000/"); + serviceDiscoverySourceProps.setProperty(CLUSTER_NAME + ".RESOURCEMANAGER", DEFAULT_VALID_SERVICE_URL); + serviceDiscoverySourceProps.setProperty(CLUSTER_NAME + ".AMBARIUI", DEFAULT_VALID_SERVICE_URL); + File serviceDiscoverySource = File.createTempFile("service-discovery", ".properties"); + serviceDiscoverySourceProps.store(new FileOutputStream(serviceDiscoverySource), + "Test Service Discovery Source"); + + // Prepare a mock SimpleDescriptor + final String type = "PROPERTIES_FILE"; + final String address = serviceDiscoverySource.getAbsolutePath(); + final Map<String, List<String>> serviceURLs = new HashMap<>(); + serviceURLs.put("NAMENODE", null); + serviceURLs.put("JOBTRACKER", null); + serviceURLs.put("WEBHDFS", null); + serviceURLs.put("WEBHCAT", null); + serviceURLs.put("OOZIE", null); + serviceURLs.put("WEBHBASE", null); + serviceURLs.put("HIVE", null); + serviceURLs.put("RESOURCEMANAGER", null); + serviceURLs.put("AMBARIUI", Collections.singletonList("http://c6401.ambari.apache.org:8080")); + + // Write the externalized provider config to a temp file + File providerConfig = writeProviderConfig("ambari-cluster-policy.xml", TEST_PROVIDER_CONFIG); + + File topologyFile = null; + try { + File destDir = (new File(".")).getCanonicalFile(); + + // Mock out the simple descriptor + SimpleDescriptor testDescriptor = EasyMock.createNiceMock(SimpleDescriptor.class); + EasyMock.expect(testDescriptor.getName()).andReturn("mysimpledescriptor").anyTimes(); + EasyMock.expect(testDescriptor.getDiscoveryAddress()).andReturn(address).anyTimes(); + EasyMock.expect(testDescriptor.getDiscoveryType()).andReturn(type).anyTimes(); + EasyMock.expect(testDescriptor.getDiscoveryUser()).andReturn(null).anyTimes(); + EasyMock.expect(testDescriptor.getProviderConfig()).andReturn(providerConfig.getAbsolutePath()).anyTimes(); + EasyMock.expect(testDescriptor.getClusterName()).andReturn(CLUSTER_NAME).anyTimes(); + List<SimpleDescriptor.Service> serviceMocks = new ArrayList<>(); + for (String serviceName : serviceURLs.keySet()) { + 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.replay(svc); + serviceMocks.add(svc); + } + EasyMock.expect(testDescriptor.getServices()).andReturn(serviceMocks).anyTimes(); + EasyMock.replay(testDescriptor); + + // Invoke the simple descriptor handler + Map<String, File> files = + SimpleDescriptorHandler.handle(testDescriptor, + providerConfig.getParentFile(), // simple desc co-located with provider config + destDir); + + topologyFile = files.get("topology"); + + // Validate the resulting topology descriptor + assertTrue(topologyFile.exists()); + + // Validate the topology descriptor's correctness + TopologyValidator validator = new TopologyValidator( topologyFile.getAbsolutePath() ); + if( !validator.validateTopology() ){ + throw new SAXException( validator.getErrorString() ); + } + + XPathFactory xPathfactory = XPathFactory.newInstance(); + XPath xpath = xPathfactory.newXPath(); + + // Parse the topology descriptor + Document topologyXml = XmlUtils.readXml(topologyFile); + + // Validate the provider configuration + Document extProviderConf = XmlUtils.readXml(new ByteArrayInputStream(TEST_PROVIDER_CONFIG.getBytes())); + Node gatewayNode = (Node) xpath.compile("/topology/gateway").evaluate(topologyXml, XPathConstants.NODE); + assertTrue("Resulting provider config should be identical to the referenced content.", + extProviderConf.getDocumentElement().isEqualNode(gatewayNode)); + + // Validate the service declarations + List<String> topologyServices = new ArrayList<>(); + Map<String, List<String>> topologyServiceURLs = new HashMap<>(); + NodeList serviceNodes = + (NodeList) xpath.compile("/topology/service").evaluate(topologyXml, XPathConstants.NODESET); + for (int serviceNodeIndex=0; serviceNodeIndex < serviceNodes.getLength(); serviceNodeIndex++) { + Node serviceNode = serviceNodes.item(serviceNodeIndex); + Node roleNode = (Node) xpath.compile("role/text()").evaluate(serviceNode, XPathConstants.NODE); + assertNotNull(roleNode); + String role = roleNode.getNodeValue(); + topologyServices.add(role); + 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<>()); + } + topologyServiceURLs.get(role).add(url); + } + } + + // There should not be a service element for HIVE, since it had no valid URLs + assertEquals("Unexpected number of service declarations.", serviceURLs.size() - 1, topologyServices.size()); + assertFalse("The HIVE service should have been omitted from the generated topology.", topologyServices.contains("HIVE")); + + assertEquals("Unexpected number of service URLs.", serviceURLs.size() - 1, topologyServiceURLs.size()); + + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } finally { + serviceDiscoverySource.delete(); + providerConfig.delete(); + if (topologyFile != null) { + topologyFile.delete(); + } + } + } + + + private File writeProviderConfig(String path, String content) throws IOException { + File f = new File(path); + FileUtils.write(f, content); + return f; + } + +}
