SLIDER-324. Exports should be attributed to individual master components rather than only one master component
Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/2a25ab91 Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/2a25ab91 Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/2a25ab91 Branch: refs/heads/feature/SLIDER-149_Support_a_YARN_service_registry Commit: 2a25ab9192bc96a2f6f4409f9eea916e94c9484c Parents: bc9561d Author: Sumit Mohanty <smoha...@hortonworks.com> Authored: Fri Aug 15 17:18:52 2014 -0700 Committer: Sumit Mohanty <smoha...@hortonworks.com> Committed: Fri Aug 15 17:18:52 2014 -0700 ---------------------------------------------------------------------- app-packages/storm/metainfo.xml | 4 +- .../providers/agent/AgentProviderService.java | 216 +++++++++++-------- .../application/metadata/MetainfoParser.java | 8 +- .../agent/TestAgentProviderService.java | 34 ++- .../metadata/MetainfoParserTest.java | 59 ----- .../metadata/TestMetainfoParser.java | 63 ++++++ 6 files changed, 221 insertions(+), 163 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/app-packages/storm/metainfo.xml ---------------------------------------------------------------------- diff --git a/app-packages/storm/metainfo.xml b/app-packages/storm/metainfo.xml index d9004ad..dbe8549 100644 --- a/app-packages/storm/metainfo.xml +++ b/app-packages/storm/metainfo.xml @@ -45,7 +45,7 @@ <value>http://${site.global.ganglia_server_host}/ganglia?c=${site.global.ganglia_server_id}</value> </export> <export> - <name>nimbus.url</name> + <name>nimbus.host_port</name> <value>http://${NIMBUS_HOST}:${site.storm-site.nimbus.thrift.port}</value> </export> </exports> @@ -82,7 +82,7 @@ <name>NIMBUS</name> <category>MASTER</category> <autoStartOnFailure>true</autoStartOnFailure> - <appExports>QuickLinks-nimbus.url,QuickLinks-ganglia.ui,QuickLinks-app.metrics</appExports> + <appExports>QuickLinks-nimbus.host_port,QuickLinks-ganglia.ui,QuickLinks-app.metrics</appExports> <commandScript> <script>scripts/nimbus.py</script> <scriptType>PYTHON</scriptType> http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java index 91bc0a6..842f4f6 100644 --- a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java +++ b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java @@ -56,6 +56,7 @@ import org.apache.slider.providers.ProviderRole; import org.apache.slider.providers.ProviderUtils; import org.apache.slider.providers.agent.application.metadata.Application; import org.apache.slider.providers.agent.application.metadata.Component; +import org.apache.slider.providers.agent.application.metadata.ComponentExport; import org.apache.slider.providers.agent.application.metadata.Export; import org.apache.slider.providers.agent.application.metadata.ExportGroup; import org.apache.slider.providers.agent.application.metadata.Metainfo; @@ -137,6 +138,8 @@ public class AgentProviderService extends AbstractProviderService implements new ConcurrentHashMap<String, ComponentInstanceState>(); private final Map<String, Map<String, String>> componentInstanceData = new ConcurrentHashMap<String, Map<String, String>>(); + private final Map<String, Map<String, String>> exportGroups = + new ConcurrentHashMap<String, Map<String, String>>(); private final Map<String, Map<String, String>> allocatedPorts = new ConcurrentHashMap<String, Map<String, String>>(); private final Map<String, String> workFolders = @@ -451,22 +454,8 @@ public class AgentProviderService extends AbstractProviderService implements Boolean isMaster = isMaster(roleName); ComponentInstanceState componentStatus = getComponentStatuses().get(label); componentStatus.heartbeat(System.currentTimeMillis()); - // If no Master can explicitly publish then publish if its a master - // Otherwise, wait till the master that can publish is ready - if (isMaster && - (canAnyMasterPublishConfig() == false || canPublishConfig(roleName))) { - publishConfigAndExportGroups(heartBeat, componentStatus); - } else { - // Ack that config has been reported - List<ComponentStatus> statuses = heartBeat.getComponentStatus(); - if (statuses != null && !statuses.isEmpty()) { - ComponentStatus status = statuses.get(0); - if(status.getConfigs().size() > 0) { - log.info("Config got reported by {} but discarded as component {} cannot publish.", label, roleName); - componentStatus.setConfigReported(true); - } - } - } + + publishConfigAndExportGroups(heartBeat, componentStatus, roleName); List<CommandReport> reports = heartBeat.getReports(); if (reports != null && !reports.isEmpty()) { @@ -513,6 +502,7 @@ public class AgentProviderService extends AbstractProviderService implements } } } + // if there is no outstanding command then retrieve config if (isMaster && componentStatus.getState() == State.STARTED && command == Command.NOP) { @@ -758,39 +748,60 @@ public class AgentProviderService extends AbstractProviderService implements /** * Process return status for component instances + * * @param heartBeat * @param componentStatus */ - protected void publishConfigAndExportGroups(HeartBeat heartBeat, ComponentInstanceState componentStatus) { + protected void publishConfigAndExportGroups( + HeartBeat heartBeat, ComponentInstanceState componentStatus, String roleName) { List<ComponentStatus> statuses = heartBeat.getComponentStatus(); if (statuses != null && !statuses.isEmpty()) { log.info("Processing {} status reports.", statuses.size()); - Application application = getMetainfo().getApplication(); - List<ExportGroup> exportGroups = application.getExportGroups(); - boolean hasExportGroups = exportGroups != null && !exportGroups.isEmpty(); - Set<String> exportedConfigs = new HashSet(); - String exportedConfigsStr = application.getExportedConfigs(); - boolean exportedAllConfigs = exportedConfigsStr == null || exportedConfigsStr.isEmpty(); - if (application.getExportedConfigs() != null && application.getExportedConfigs().length() > 0) { - for (String exportedConfig : application.getExportedConfigs().split(",")) { - if (exportedConfig.trim().length() > 0) { - exportedConfigs.add(exportedConfig.trim()); - } - } - } - for (ComponentStatus status : statuses) { log.info("Status report: " + status.toString()); + if (status.getConfigs() != null) { - for (String key : status.getConfigs().keySet()) { - if ((!exportedAllConfigs && exportedConfigs.contains(key)) || - exportedAllConfigs) { - Map<String, String> configs = status.getConfigs().get(key); - publishApplicationInstanceData(key, key, configs.entrySet()); + Application application = getMetainfo().getApplication(); + + if (canAnyMasterPublishConfig() == false || canPublishConfig(roleName)) { + // If no Master can explicitly publish then publish if its a master + // Otherwise, wait till the master that can publish is ready + + Set<String> exportedConfigs = new HashSet(); + String exportedConfigsStr = application.getExportedConfigs(); + boolean exportedAllConfigs = exportedConfigsStr == null || exportedConfigsStr.isEmpty(); + if (!exportedAllConfigs) { + for (String exportedConfig : exportedConfigsStr.split(",")) { + if (exportedConfig.trim().length() > 0) { + exportedConfigs.add(exportedConfig.trim()); + } + } + } + + for (String key : status.getConfigs().keySet()) { + if ((!exportedAllConfigs && exportedConfigs.contains(key)) || + exportedAllConfigs) { + Map<String, String> configs = status.getConfigs().get(key); + publishApplicationInstanceData(key, key, configs.entrySet()); + } } } - if (hasExportGroups) { + List<ExportGroup> exportGroups = application.getExportGroups(); + boolean hasExportGroups = exportGroups != null && !exportGroups.isEmpty(); + + Set<String> appExports = new HashSet(); + String appExportsStr = getApplicationComponent(roleName).getAppExports(); + boolean hasNoAppExports = appExportsStr == null || appExportsStr.isEmpty(); + if (!hasNoAppExports) { + for (String appExport : appExportsStr.split(",")) { + if (appExport.trim().length() > 0) { + appExports.add(appExport.trim()); + } + } + } + + if (hasExportGroups && appExports.size() > 0) { String configKeyFormat = "${site.%s.%s}"; String hostKeyFormat = "${%s_HOST}"; @@ -809,33 +820,63 @@ public class AgentProviderService extends AbstractProviderService implements } } + Set<String> modifiedGroups = new HashSet<String>(); for (ExportGroup exportGroup : exportGroups) { List<Export> exports = exportGroup.getExports(); if (exports != null && !exports.isEmpty()) { String exportGroupName = exportGroup.getName(); - Map<String, String> map = new HashMap<String, String>(); + Map<String, String> map = getCurrentExports(exportGroupName); for (Export export : exports) { - String value = export.getValue(); - // replace host names - for (String token : replaceTokens.keySet()) { - if (value.contains(token)) { - value = value.replace(token, replaceTokens.get(token)); + if (canBeExported(exportGroupName, export.getName(), appExports)) { + String value = export.getValue(); + // replace host names + for (String token : replaceTokens.keySet()) { + if (value.contains(token)) { + value = value.replace(token, replaceTokens.get(token)); + } } + map.put(export.getName(), value); + log.info("Preparing to publish. Key {} and Value {}", export.getName(), value); } - map.put(export.getName(), value); - log.info("Preparing to publish. Key {} and Value {}", export.getName(), value); } - publishApplicationInstanceData(exportGroupName, exportGroupName, map.entrySet()); + modifiedGroups.add(exportGroupName); } } + publishModifiedExportGroups(modifiedGroups); } - log.info("Received and stored config for {}", heartBeat.getHostname()); + + log.info("Received and processed config for {}", heartBeat.getHostname()); componentStatus.setConfigReported(true); + } } } } + private boolean canBeExported(String exportGroupName, String name, Set<String> appExports) { + return appExports.contains(String.format("%s-%s", exportGroupName, name)); + } + + protected Map<String, String> getCurrentExports(String groupName) { + if(!this.exportGroups.containsKey(groupName)) { + synchronized (this.exportGroups) { + if(!this.exportGroups.containsKey(groupName)) { + this.exportGroups.put(groupName, new ConcurrentHashMap<String, String>()); + } + } + } + + return this.exportGroups.get(groupName); + } + + private void publishModifiedExportGroups(Set<String> modifiedGroups) { + synchronized (this.exportGroups) { + for(String groupName : modifiedGroups) { + publishApplicationInstanceData(groupName, groupName, this.exportGroups.get(groupName).entrySet()); + } + } + } + /** Publish component instance specific data if the component demands it */ protected void processAndPublishComponentSpecificData(Map<String, String> ports, String containerId, @@ -848,9 +889,9 @@ public class AgentProviderService extends AbstractProviderService implements Application application = getMetainfo().getApplication(); for (Component component : application.getComponents()) { if (component.getName().equals(roleName)) { - if (component.getExports().size() > 0) { + if (component.getComponentExports().size() > 0) { - for (Export export : component.getExports()) { + for (ComponentExport export : component.getComponentExports()) { String templateToExport = export.getValue(); for (String portName : ports.keySet()) { boolean publishData = false; @@ -901,26 +942,37 @@ public class AgentProviderService extends AbstractProviderService implements } /** - * Extract script path from the application metainfo - * + * Return Component based on name * @param roleName - * * @return */ - protected String getScriptPathFromMetainfo(String roleName) { - String scriptPath = null; + protected Component getApplicationComponent(String roleName) { Application application = getMetainfo().getApplication(); if (application == null) { log.error("Malformed app definition: Expect application as the top level element for metainfo.xml"); - return scriptPath; - } - for (Component component : application.getComponents()) { - if (component.getName().equals(roleName)) { - scriptPath = component.getCommandScript().getScript(); - break; + } else { + for (Component component : application.getComponents()) { + if (component.getName().equals(roleName)) { + return component; + } } } - return scriptPath; + return null; + } + + /** + * Extract script path from the application metainfo + * + * @param roleName + * + * @return + */ + protected String getScriptPathFromMetainfo(String roleName) { + Component component = getApplicationComponent(roleName); + if (component != null) { + return component.getCommandScript().getScript(); + } + return null; } /** @@ -931,18 +983,10 @@ public class AgentProviderService extends AbstractProviderService implements * @return */ protected boolean isMaster(String roleName) { - Application application = getMetainfo().getApplication(); - if (application == null) { - log.error("Malformed app definition: Expect application as the top level element for metainfo.xml"); - } else { - for (Component component : application.getComponents()) { - if (component.getName().equals(roleName)) { - if (component.getCategory().equals("MASTER")) { - return true; - } else { - return false; - } - } + Component component = getApplicationComponent(roleName); + if (component != null) { + if (component.getCategory().equals("MASTER")) { + return true; } } return false; @@ -956,34 +1000,24 @@ public class AgentProviderService extends AbstractProviderService implements * @return */ protected boolean canPublishConfig(String roleName) { - Application application = getMetainfo().getApplication(); - if (application == null) { - log.error("Malformed app definition: Expect application as the top level element for metainfo.xml"); - } else { - for (Component component : application.getComponents()) { - if (component.getName().equals(roleName)) { - return Boolean.TRUE.toString().equals(component.getPublishConfig()); - } - } + Component component = getApplicationComponent(roleName); + if (component != null) { + return Boolean.TRUE.toString().equals(component.getPublishConfig()); } return false; } /** * Checks if the role is marked auto-restart + * * @param roleName + * * @return */ protected boolean isMarkedAutoRestart(String roleName) { - Application application = getMetainfo().getApplication(); - if (application == null) { - log.error("Malformed app definition: Expect application as the top level element for metainfo.xml"); - } else { - for (Component component : application.getComponents()) { - if (component.getName().equals(roleName)) { - return component.getRequiresAutoRestart(); - } - } + Component component = getApplicationComponent(roleName); + if (component != null) { + return component.getRequiresAutoRestart(); } return false; } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java index 4b91ff7..bc93d6f 100644 --- a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java +++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java @@ -61,10 +61,10 @@ public class MetainfoParser { digester.addBeanPropertySetter("*/component/maxInstanceCount"); digester.addBeanPropertySetter("*/component/autoStartOnFailure"); digester.addBeanPropertySetter("*/component/appExports"); - digester.addObjectCreate("*/component/componentExport", ComponentExport.class); - digester.addBeanPropertySetter("*/component/componentExport/name"); - digester.addBeanPropertySetter("*/component/componentExport/value"); - digester.addSetNext("*/component/componentExport", "addComponentExport"); + digester.addObjectCreate("*/componentExport", ComponentExport.class); + digester.addBeanPropertySetter("*/componentExport/name"); + digester.addBeanPropertySetter("*/componentExport/value"); + digester.addSetNext("*/componentExport", "addComponentExport"); digester.addSetNext("*/component", "addComponent"); digester.addObjectCreate("*/commandScript", CommandScript.class); http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java ---------------------------------------------------------------------- diff --git a/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java b/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java index 1ea11a6..6ed950f 100644 --- a/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java +++ b/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java @@ -136,8 +136,18 @@ public class TestAgentProviderService { + " </commandOrders>\n" + " <components>\n" + " <component>\n" + + " <name>HBASE_REST</name>\n" + + " <category>MASTER</category>\n" + + " <commandScript>\n" + + " <script>scripts/hbase_rest.py</script>\n" + + " <scriptType>PYTHON</scriptType>\n" + + " <timeout>600</timeout>\n" + + " </commandScript>\n" + + " </component>\n" + + " <component>\n" + " <name>HBASE_MASTER</name>\n" + " <category>MASTER</category>\n" + + " <publishConfig>true</publishConfig>\n" + " <autoStartOnFailure>true</autoStartOnFailure>\n" + " <appExports>QuickLinks-JMX_Endpoint,QuickLinks-Master_Status</appExports>\n" + " <minInstanceCount>1</minInstanceCount>\n" @@ -166,7 +176,7 @@ public class TestAgentProviderService { + " <name>PropertyB</name>\n" + " <value>AConstant</value>\n" + " </componentExport>\n" - + " </componentExport>\n" + + " </componentExports>\n" + " </component>\n" + " </components>\n" + " <osSpecifics>\n" @@ -458,15 +468,15 @@ public class TestAgentProviderService { doReturn(metainfo).when(mockAps).getMetainfo(); doReturn(roleClusterNodeMap).when(mockAps).getRoleClusterNodeMapping(); - mockAps.publishConfigAndExportGroups(hb, componentStatus); - assert componentStatus.getConfigReported() == true; + mockAps.publishConfigAndExportGroups(hb, componentStatus, "HBASE_MASTER"); + Assert.assertTrue(componentStatus.getConfigReported()); ArgumentCaptor<Collection> entriesCaptor = ArgumentCaptor. forClass(Collection.class); Mockito.verify(mockAps, Mockito.times(3)).publishApplicationInstanceData( anyString(), anyString(), entriesCaptor.capture()); - assert entriesCaptor.getAllValues().size() == 3; + Assert.assertEquals(3, entriesCaptor.getAllValues().size()); for (Collection coll : entriesCaptor.getAllValues()) { Set<Map.Entry<String, String>> entrySet = (Set<Map.Entry<String, String>>) coll; for (Map.Entry entry : entrySet) { @@ -476,6 +486,16 @@ public class TestAgentProviderService { } } } + + Map<String, String> exports = mockAps.getCurrentExports("QuickLinks"); + Assert.assertEquals(2, exports.size()); + Assert.assertEquals(exports.get("JMX_Endpoint"), "http://HOST1:60012/jmx"); + + mockAps.publishConfigAndExportGroups(hb, componentStatus, "HBASE_REST"); + Mockito.verify(mockAps, Mockito.times(3)).publishApplicationInstanceData( + anyString(), + anyString(), + entriesCaptor.capture()); } @Test @@ -487,7 +507,7 @@ public class TestAgentProviderService { log.info("Service: " + application.toString()); Assert.assertEquals(application.getName(), "HBASE"); Assert.assertEquals(application.getExportedConfigs(), "hbase-site,global"); - Assert.assertEquals(application.getComponents().size(), 2); + Assert.assertEquals(application.getComponents().size(), 3); List<Component> components = application.getComponents(); int found = 0; for (Component component : components) { @@ -596,9 +616,9 @@ public class TestAgentProviderService { Assert.assertTrue(mockAps.isMaster(role_hm)); Assert.assertFalse(mockAps.isMaster(role_hrs)); - Assert.assertFalse(mockAps.canPublishConfig(role_hm)); + Assert.assertTrue(mockAps.canPublishConfig(role_hm)); Assert.assertFalse(mockAps.canPublishConfig(role_hrs)); - Assert.assertFalse(mockAps.canAnyMasterPublishConfig()); + Assert.assertTrue(mockAps.canAnyMasterPublishConfig()); Assert.assertTrue(mockAps2.isMaster(role_hm)); Assert.assertFalse(mockAps2.isMaster(role_hrs)); http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/MetainfoParserTest.java ---------------------------------------------------------------------- diff --git a/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/MetainfoParserTest.java b/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/MetainfoParserTest.java deleted file mode 100644 index 61c53df..0000000 --- a/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/MetainfoParserTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.slider.providers.agent.application.metadata; - -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; - -/** - * - */ -public class MetainfoParserTest { - protected static final Logger log = - LoggerFactory.getLogger(MetainfoParserTest.class); - public static final String METAINFO_XML = - "/org/apache/slider/providers/agent/application/metadata/metainfo.xml"; - - @Test - public void testParse() throws IOException { - - InputStream resStream = this.getClass().getResourceAsStream( - METAINFO_XML); - MetainfoParser parser = new MetainfoParser(); - Metainfo metainfo = parser.parse(resStream); - Assert.assertNotNull(metainfo); - Assert.assertNotNull(metainfo.getApplication()); - Application application = metainfo.getApplication(); - assert "STORM".equals(application.getName()); - assert 5 == application.getComponents().size(); - OSPackage pkg = application.getOSSpecifics().get(0).getPackages().get(0); - assert "tarball".equals(pkg.getType()); - assert "files/apache-storm-0.9.1.2.1.1.0-237.tar.gz".equals(pkg.getName()); - boolean found = false; - for (Component comp : application.getComponents()) { - if (comp != null && comp.getName().equals("NIMBUS")) { - found = true; - } - } - assert found; - } -} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/TestMetainfoParser.java ---------------------------------------------------------------------- diff --git a/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/TestMetainfoParser.java b/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/TestMetainfoParser.java new file mode 100644 index 0000000..98f0afb --- /dev/null +++ b/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/TestMetainfoParser.java @@ -0,0 +1,63 @@ +/* + * 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.slider.providers.agent.application.metadata; + +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; + +/** + * + */ +public class TestMetainfoParser { + protected static final Logger log = + LoggerFactory.getLogger(TestMetainfoParser.class); + public static final String METAINFO_XML = + "/org/apache/slider/providers/agent/application/metadata/metainfo.xml"; + + @Test + public void testParse() throws IOException { + + InputStream resStream = this.getClass().getResourceAsStream( + METAINFO_XML); + MetainfoParser parser = new MetainfoParser(); + Metainfo metainfo = parser.parse(resStream); + Assert.assertNotNull(metainfo); + Assert.assertNotNull(metainfo.getApplication()); + Application application = metainfo.getApplication(); + assert "STORM".equals(application.getName()); + assert 5 == application.getComponents().size(); + OSPackage pkg = application.getOSSpecifics().get(0).getPackages().get(0); + assert "tarball".equals(pkg.getType()); + assert "files/apache-storm-0.9.1.2.1.1.0-237.tar.gz".equals(pkg.getName()); + boolean found = false; + for (Component comp : application.getComponents()) { + if (comp != null && comp.getName().equals("NIMBUS")) { + found = true; + Assert.assertEquals(0, comp.getComponentExports().size()); + } + if (comp != null && comp.getName().equals("SUPERVISOR")) { + Assert.assertEquals(1, comp.getComponentExports().size()); + } + } + assert found; + } +}