Repository: ambari Updated Branches: refs/heads/trunk af0253506 -> 2bebb6e1e
AMBARI-7964 - Views: on deploy, validate view.xml Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/2bebb6e1 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/2bebb6e1 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/2bebb6e1 Branch: refs/heads/trunk Commit: 2bebb6e1e3e7a0570996f2c4b458289f6763feda Parents: af02535 Author: tbeerbower <[email protected]> Authored: Mon Oct 27 10:08:35 2014 -0400 Committer: tbeerbower <[email protected]> Committed: Mon Oct 27 10:09:05 2014 -0400 ---------------------------------------------------------------------- .../server/configuration/Configuration.java | 19 +++- .../ambari/server/view/ViewArchiveUtility.java | 46 ++++++++-- .../apache/ambari/server/view/ViewRegistry.java | 3 +- .../server/configuration/ConfigurationTest.java | 15 ++++ .../server/view/ViewArchiveUtilityTest.java | 38 ++++++++ .../ambari/server/view/ViewExtractorTest.java | 3 +- .../ambari/server/view/ViewRegistryTest.java | 3 +- ambari-server/src/test/resources/test_view.xml | 94 ++++++++++++++++++++ 8 files changed, 209 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java index feb4318..ed59e8a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java @@ -61,6 +61,8 @@ public class Configuration { public static final String BOOTSTRAP_DIR_DEFAULT = "/var/run/ambari-server/bootstrap"; public static final String VIEWS_DIR = "views.dir"; public static final String VIEWS_DIR_DEFAULT = "/var/lib/ambari-server/resources/views"; + public static final String VIEWS_VALIDATE = "views.validate"; + public static final String VIEWS_VALIDATE_DEFAULT = "false"; public static final String WEBAPP_DIR = "webapp.dir"; public static final String BOOTSTRAP_SCRIPT = "bootstrap.script"; public static final String BOOTSTRAP_SCRIPT_DEFAULT = "/usr/bin/ambari_bootstrap"; @@ -529,6 +531,15 @@ public class Configuration { return new File(fileName); } + /** + * Determine whether or not view validation is enabled. + * + * @return true if view validation is enabled + */ + public boolean isViewValidationEnabled() { + return "true".equalsIgnoreCase(properties.getProperty(VIEWS_VALIDATE, VIEWS_VALIDATE_DEFAULT)); + } + public File getBootStrapDir() { String fileName = properties.getProperty(BOOTSTRAP_DIR, BOOTSTRAP_DIR_DEFAULT); return new File(fileName); @@ -616,7 +627,7 @@ public class Configuration { * @return null if such a file is not present, value if present. */ public String getHostsMapFile() { - LOG.info("Hosts Mapping File " + properties.getProperty(SRVR_HOSTS_MAPPING)); + LOG.info("Hosts Mapping File " + properties.getProperty(SRVR_HOSTS_MAPPING)); return properties.getProperty(SRVR_HOSTS_MAPPING); } @@ -1015,12 +1026,12 @@ public class Configuration { public String getExecutionSchedulerThreads() { return properties.getProperty(EXECUTION_SCHEDULER_THREADS, - DEFAULT_SCHEDULER_THREAD_COUNT); + DEFAULT_SCHEDULER_THREAD_COUNT); } public String getExecutionSchedulerConnections() { return properties.getProperty(EXECUTION_SCHEDULER_CONNECTIONS, - DEFAULT_SCHEDULER_MAX_CONNECTIONS); + DEFAULT_SCHEDULER_MAX_CONNECTIONS); } public Long getExecutionSchedulerMisfireToleration() { @@ -1032,7 +1043,7 @@ public class Configuration { public Integer getExecutionSchedulerStartDelay() { String delay = properties.getProperty(EXECUTION_SCHEDULER_START_DELAY, - DEFAULT_SCHEDULER_START_DELAY_SECONDS); + DEFAULT_SCHEDULER_START_DELAY_SECONDS); return Integer.parseInt(delay); } http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/main/java/org/apache/ambari/server/view/ViewArchiveUtility.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewArchiveUtility.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewArchiveUtility.java index f5f2732..950f552 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewArchiveUtility.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewArchiveUtility.java @@ -19,10 +19,15 @@ package org.apache.ambari.server.view; import org.apache.ambari.server.view.configuration.ViewConfig; +import org.xml.sax.SAXException; +import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -43,6 +48,7 @@ public class ViewArchiveUtility { * Constants */ private static final String VIEW_XML = "view.xml"; + private static final String VIEW_XSD = "view.xsd"; // ----- ViewArchiveUtility ------------------------------------------------ @@ -53,6 +59,8 @@ public class ViewArchiveUtility { * @param archiveFile the archive file * * @return the associated view configuration + * + * @throws JAXBException if xml is malformed */ public ViewConfig getViewConfigFromArchive(File archiveFile) throws MalformedURLException, JAXBException { @@ -68,17 +76,25 @@ public class ViewArchiveUtility { /** * Get the view configuration from the extracted archive file. * - * @param archivePath path to extracted archive + * @param archivePath path to extracted archive + * @param validate indicates whether or not the view configuration should be validated * * @return the associated view configuration * * @throws JAXBException if xml is malformed - * @throws java.io.FileNotFoundException if xml was not found + * @throws IOException if xml can not be read + * @throws SAXException if the validation fails */ - public ViewConfig getViewConfigFromExtractedArchive(String archivePath) - throws JAXBException, FileNotFoundException { + public ViewConfig getViewConfigFromExtractedArchive(String archivePath, boolean validate) + throws JAXBException, IOException, SAXException { + + File configFile = new File(archivePath + File.separator + VIEW_XML); + + if (validate) { + validateConfig(new FileInputStream(configFile)); + } - InputStream configStream = new FileInputStream(new File(archivePath + File.separator + VIEW_XML)); + InputStream configStream = new FileInputStream(configFile); JAXBContext jaxbContext = JAXBContext.newInstance(ViewConfig.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); @@ -117,4 +133,24 @@ public class ViewArchiveUtility { public JarFile getJarFile(File file) throws IOException { return new JarFile(file); } + + + // ----- helper methods ---------------------------------------------------- + + /** + * Validate the given view descriptor file against the view schema. + * + * @param configStream input stream of view descriptor file to be validated + * + * @throws SAXException if the validation fails + * @throws IOException if the descriptor file can not be read + */ + protected void validateConfig(InputStream configStream) throws SAXException, IOException { + SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + + URL schemaUrl = getClass().getClassLoader().getResource(VIEW_XSD); + Schema schema = schemaFactory.newSchema(schemaUrl); + + schema.newValidator().validate(new StreamSource(configStream)); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java index c4da8b4..a5d11bd 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java @@ -1290,7 +1290,8 @@ public class ViewRegistry { // extract the archive and get the class loader ClassLoader cl = extractor.extractViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile); - ViewConfig viewConfig = archiveUtility.getViewConfigFromExtractedArchive(extractedArchiveDirPath); + ViewConfig viewConfig = archiveUtility.getViewConfigFromExtractedArchive(extractedArchiveDirPath, + configuration.isViewValidationEnabled()); setupViewDefinition(viewDefinition, viewConfig, cl); http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java b/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java index 12b5333..0f7de36 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java @@ -305,6 +305,21 @@ public class ConfigurationTest { } @Test + public void testIsViewValidationEnabled() throws Exception { + final Properties ambariProperties = new Properties(); + Configuration configuration = new Configuration(ambariProperties); + Assert.assertFalse(configuration.isViewValidationEnabled()); + + ambariProperties.setProperty(Configuration.VIEWS_VALIDATE, "false"); + configuration = new Configuration(ambariProperties); + Assert.assertFalse(configuration.isViewValidationEnabled()); + + ambariProperties.setProperty(Configuration.VIEWS_VALIDATE, "true"); + configuration = new Configuration(ambariProperties); + Assert.assertTrue(configuration.isViewValidationEnabled()); + } + + @Test public void testGetLdapServerProperties() throws Exception { final Properties ambariProperties = new Properties(); final Configuration configuration = new Configuration(ambariProperties); http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/test/java/org/apache/ambari/server/view/ViewArchiveUtilityTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewArchiveUtilityTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewArchiveUtilityTest.java new file mode 100644 index 0000000..aff29f4 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewArchiveUtilityTest.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.view; + +import org.junit.Test; + +import java.io.InputStream; + +/** + * ViewArchiveUtility tests. + */ +public class ViewArchiveUtilityTest { + + @Test + public void testValidateConfig() throws Exception { + ViewArchiveUtility utility = new ViewArchiveUtility(); + + InputStream configStream = getClass().getClassLoader().getResourceAsStream("test_view.xml"); + + utility.validateConfig(configStream); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/test/java/org/apache/ambari/server/view/ViewExtractorTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewExtractorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewExtractorTest.java index 1b71c37..b66714e 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewExtractorTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewExtractorTest.java @@ -234,7 +234,8 @@ public class ViewExtractorTest { return viewConfigs.get(archiveFile); } - public ViewConfig getViewConfigFromExtractedArchive(String archivePath) + @Override + public ViewConfig getViewConfigFromExtractedArchive(String archivePath, boolean validate) throws JAXBException, FileNotFoundException { for (File viewConfigKey: viewConfigs.keySet()) { if (viewConfigKey.getAbsolutePath().equals(archivePath)) { http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java index 7c0cade..1d98b6c 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java @@ -1111,7 +1111,8 @@ public class ViewRegistryTest { return viewConfigs.get(archiveFile); } - public ViewConfig getViewConfigFromExtractedArchive(String archivePath) + @Override + public ViewConfig getViewConfigFromExtractedArchive(String archivePath, boolean validate) throws JAXBException, FileNotFoundException { for (File viewConfigKey: viewConfigs.keySet()) { if (viewConfigKey.getAbsolutePath().equals(archivePath)) { http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/test/resources/test_view.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/resources/test_view.xml b/ambari-server/src/test/resources/test_view.xml new file mode 100644 index 0000000..5742bfe --- /dev/null +++ b/ambari-server/src/test/resources/test_view.xml @@ -0,0 +1,94 @@ +<!-- + 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. +--> +<view> + <name>view1</name> + <label>str1234</label> + <version>str1234</version> + <description>str1234</description> + <icon64>str1234</icon64> + <icon>str1234</icon> + <system>true</system> + <view-class>str1234</view-class> + <masker-class>str1234</masker-class> + <parameter> + <name>parameter1</name> + <description>str1234</description> + <required>true</required> + <masked>true</masked> + </parameter> + <parameter> + <name>parameter2</name> + <description>str1234</description> + <required>false</required> + <masked>false</masked> + </parameter> + <resource> + <name>resource1</name> + <plural-name>str1234</plural-name> + <id-property>str1234</id-property> + <resource-class>str1234</resource-class> + <provider-class>str1234</provider-class> + <service-class>str1234</service-class> + <sub-resource-name>resource2</sub-resource-name> + </resource> + <resource> + <name>resource2</name> + <plural-name>str1234</plural-name> + <id-property>str1234</id-property> + <resource-class>str1234</resource-class> + <provider-class>str1234</provider-class> + <service-class>str1234</service-class> + </resource> + <resource> + <name>resource3</name> + <service-class>str1234</service-class> + </resource> + <permission> + <name>permission1</name> + <description>str1234</description> + </permission> + <permission> + <name>permission2</name> + <description>str1234</description> + </permission> + <persistence> + <entity> + <class>entity1</class> + <id-property>str1234</id-property> + </entity> + <entity> + <class>entity2</class> + <id-property>str1234</id-property> + </entity> + </persistence> + <instance> + <name>instance1</name> + <label>str1234</label> + <description>str1234</description> + <icon64>str1234</icon64> + <icon>str1234</icon> + <visible>true</visible> + <property> + <key>parameter1</key> + <value>str1234</value> + </property> + <property> + <key>parameter2</key> + <value>str1234</value> + </property> + </instance> +</view>
