Repository: incubator-eagle Updated Branches: refs/heads/master a39ca45cb -> 7499be694
[EAGLE-786] Add unit test for eagle-jpm-mr-running's MRRunningJobFetc⦠- Add unit test for eagle-jpm-mr-running's MRRunningJobFetchSpout https://issues.apache.org/jira/browse/EAGLE-786 Author: r7raul1984 <tangji...@yhd.com> Closes #668 from r7raul1984/EAGLE-786. Project: http://git-wip-us.apache.org/repos/asf/incubator-eagle/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-eagle/commit/7499be69 Tree: http://git-wip-us.apache.org/repos/asf/incubator-eagle/tree/7499be69 Diff: http://git-wip-us.apache.org/repos/asf/incubator-eagle/diff/7499be69 Branch: refs/heads/master Commit: 7499be694a6ae2c334751d49927cc5eaac6f5f2b Parents: a39ca45 Author: r7raul1984 <tangji...@yhd.com> Authored: Wed Nov 23 11:40:19 2016 +0800 Committer: wujinhu <wujinhu...@126.com> Committed: Wed Nov 23 11:40:19 2016 +0800 ---------------------------------------------------------------------- eagle-jpm/eagle-jpm-mr-running/pom.xml | 12 ++ .../running/storm/MRRunningJobFetchSpout.java | 64 ++++---- .../mr/running/MRRunningJobApplicationTest.java | 147 ++++++++++++++++++- .../application_1479206441898_35341.json | 35 +++++ .../test/resources/previousmrrunningapp.json | 64 ++++++++ .../test/resources/thistimemrrunningapp.json | 35 +++++ 6 files changed, 326 insertions(+), 31 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/7499be69/eagle-jpm/eagle-jpm-mr-running/pom.xml ---------------------------------------------------------------------- diff --git a/eagle-jpm/eagle-jpm-mr-running/pom.xml b/eagle-jpm/eagle-jpm-mr-running/pom.xml index bb0ac5a..b4db22b 100644 --- a/eagle-jpm/eagle-jpm-mr-running/pom.xml +++ b/eagle-jpm/eagle-jpm-mr-running/pom.xml @@ -69,6 +69,18 @@ <artifactId>eagle-app-base</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <version>${powermock.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + <version>${powermock.version}</version> + <scope>test</scope> + </dependency> </dependencies> <build> <resources> http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/7499be69/eagle-jpm/eagle-jpm-mr-running/src/main/java/org/apache/eagle/jpm/mr/running/storm/MRRunningJobFetchSpout.java ---------------------------------------------------------------------- diff --git a/eagle-jpm/eagle-jpm-mr-running/src/main/java/org/apache/eagle/jpm/mr/running/storm/MRRunningJobFetchSpout.java b/eagle-jpm/eagle-jpm-mr-running/src/main/java/org/apache/eagle/jpm/mr/running/storm/MRRunningJobFetchSpout.java index 7c910e7..cc5df84 100644 --- a/eagle-jpm/eagle-jpm-mr-running/src/main/java/org/apache/eagle/jpm/mr/running/storm/MRRunningJobFetchSpout.java +++ b/eagle-jpm/eagle-jpm-mr-running/src/main/java/org/apache/eagle/jpm/mr/running/storm/MRRunningJobFetchSpout.java @@ -18,6 +18,7 @@ package org.apache.eagle.jpm.mr.running.storm; +import org.apache.commons.collections.CollectionUtils; import org.apache.eagle.jpm.mr.running.MRRunningJobConfig; import org.apache.eagle.jpm.mr.running.recover.MRRunningJobManager; import org.apache.eagle.jpm.mr.runningentity.JobExecutionAPIEntity; @@ -87,40 +88,31 @@ public class MRRunningJobFetchSpout extends BaseRichSpout { } else { apps = resourceFetcher.getResource(Constants.ResourceType.RUNNING_MR_JOB); LOG.info("get {} apps from resource manager", apps.size()); - Set<String> running = new HashSet<>(); - for (AppInfo appInfo : apps) { - running.add(appInfo.getId()); - } - Iterator<String> appIdIterator = this.runningYarnApps.iterator(); - while (appIdIterator.hasNext()) { - String appId = appIdIterator.next(); - boolean hasFinished = true; - for (AppInfo appInfo : apps) { - if (appId.equals(appInfo.getId())) { - hasFinished = false; - } - } - if (hasFinished) { - try { - Map<String, JobExecutionAPIEntity> result = this.runningJobManager.recoverYarnApp(appId); - if (result.size() > 0) { - if (mrApps == null) { - mrApps = new HashMap<>(); - } - mrApps.put(appId, result); - AppInfo appInfo = result.get(result.keySet().iterator().next()).getAppInfo(); - appInfo.setState(Constants.AppState.FINISHED.toString()); - apps.add(appInfo); + Set<String> runningAppIdsAtThisTime = runningAppIdsAtThisTime(apps); + Set<String> runningAppIdsAtPreviousTime = this.runningYarnApps; + Set<String> finishedAppIds = getFinishedAppIds(runningAppIdsAtThisTime, runningAppIdsAtPreviousTime); + + Iterator<String> finishedAppIdIterator = finishedAppIds.iterator(); + while (finishedAppIdIterator.hasNext()) { + String appId = finishedAppIdIterator.next(); + try { + Map<String, JobExecutionAPIEntity> result = this.runningJobManager.recoverYarnApp(appId); + if (result.size() > 0) { + if (mrApps == null) { + mrApps = new HashMap<>(); } - } catch (KeeperException.NoNodeException e) { - LOG.warn("{}", e); - LOG.warn("yarn app {} has finished", appId); + mrApps.put(appId, result); + AppInfo appInfo = result.get(result.keySet().iterator().next()).getAppInfo(); + appInfo.setState(Constants.AppState.FINISHED.toString()); + apps.add(appInfo); } + } catch (KeeperException.NoNodeException e) { + LOG.warn("{}", e); + LOG.warn("yarn app {} has finished", appId); } } - - this.runningYarnApps = running; + this.runningYarnApps = runningAppIdsAtThisTime; LOG.info("get {} total apps(contains finished)", apps.size()); } @@ -141,6 +133,20 @@ public class MRRunningJobFetchSpout extends BaseRichSpout { } } + + private Set<String> getFinishedAppIds(Set<String> runningAppIdsAtThisTime, Set<String> runningAppIdsAtPreviousTime) { + Set<String> finishedAppIds = new HashSet<>(CollectionUtils.subtract(runningAppIdsAtPreviousTime, runningAppIdsAtThisTime)); + return finishedAppIds; + } + + private Set<String> runningAppIdsAtThisTime(List<AppInfo> apps) { + Set<String> running = new HashSet<>(); + for (AppInfo appInfo : apps) { + running.add(appInfo.getId()); + } + return running; + } + private Map<String, Map<String, JobExecutionAPIEntity>> recoverRunningApps() { //we need read from zookeeper, path looks like /apps/mr/running/yarnAppId/jobId/ //content of path /apps/mr/running/yarnAppId/jobId is JobExecutionAPIEntity http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/7499be69/eagle-jpm/eagle-jpm-mr-running/src/test/java/org/apache/eagle/jpm/mr/running/MRRunningJobApplicationTest.java ---------------------------------------------------------------------- diff --git a/eagle-jpm/eagle-jpm-mr-running/src/test/java/org/apache/eagle/jpm/mr/running/MRRunningJobApplicationTest.java b/eagle-jpm/eagle-jpm-mr-running/src/test/java/org/apache/eagle/jpm/mr/running/MRRunningJobApplicationTest.java index 3ec9089..8707182 100644 --- a/eagle-jpm/eagle-jpm-mr-running/src/test/java/org/apache/eagle/jpm/mr/running/MRRunningJobApplicationTest.java +++ b/eagle-jpm/eagle-jpm-mr-running/src/test/java/org/apache/eagle/jpm/mr/running/MRRunningJobApplicationTest.java @@ -16,12 +16,155 @@ */ package org.apache.eagle.jpm.mr.running; +import backtype.storm.spout.ISpoutOutputCollector; +import backtype.storm.spout.SpoutOutputCollector; import com.typesafe.config.ConfigFactory; +import org.apache.eagle.jpm.mr.running.recover.MRRunningJobManager; +import org.apache.eagle.jpm.mr.running.storm.MRRunningJobFetchSpout; +import org.apache.eagle.jpm.mr.runningentity.JobExecutionAPIEntity; +import org.apache.eagle.jpm.util.Constants; +import org.apache.eagle.jpm.util.resourcefetch.connection.InputStreamUtils; +import org.apache.eagle.jpm.util.resourcefetch.model.AppInfo; +import org.apache.eagle.jpm.util.resourcefetch.model.AppsWrapper; +import org.codehaus.jackson.JsonParser; +import org.codehaus.jackson.map.ObjectMapper; +import org.junit.Assert; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.*; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({InputStreamUtils.class, MRRunningJobFetchSpout.class}) +@PowerMockIgnore({"javax.*"}) public class MRRunningJobApplicationTest { + + public static final String RM_URL = "http://sandbox.hortonworks.com:50030/ws/v1/cluster/apps?applicationTypes=MAPREDUCE&state=RUNNING&anonymous=true"; + public static final String RUNNING_YARNAPPS = "[application_1479206441898_35341, application_1479206441898_30784]"; + public static final String TUPLE_1 = "[application_1479206441898_30784, AppInfo{id='application_1479206441898_30784', user='xxx', name='oozie:launcher:T=shell:W=wf_co_xxx_xxx_v3:A=extract_org_data:ID=0002383-161115184801730-oozie-oozi-W', queue='xxx', state='RUNNING', finalStatus='UNDEFINED', progress=95.0, trackingUI='ApplicationMaster', trackingUrl='http://host.domain.com:8088/proxy/application_1479206441898_30784/', diagnostics='', clusterId='1479206441898', applicationType='MAPREDUCE', startedTime=1479328221694, finishedTime=0, elapsedTime=13367402, amContainerLogs='http://host.domain.com:8088/node/containerlogs/container_e11_1479206441898_30784_01_000001/xxx', amHostHttpAddress='host.domain.com:8088', allocatedMB=3072, allocatedVCores=2, runningContainers=2}, null]"; + public static final String TUPLE_2 = "[application_1479206441898_35341, AppInfo{id='application_1479206441898_35341', user='yyy', name='insert overwrite table inter...a.xxx(Stage-3)', queue='yyy', state='RUNNING', finalStatus='UNDEFINED', progress=59.545456, trackingUI='ApplicationMaster', trackingUrl='http://host.domain.com:8088/proxy/application_1479206441898_35341/', diagnostics='', clusterId='1479206441898', applicationType='MAPREDUCE', startedTime=1479341511477, finishedTime=0, elapsedTime=77619, amContainerLogs='http://host.domain.com:8042/node/containerlogs/container_e11_1479206441898_35341_01_000005/yyy', amHostHttpAddress='host.domain.com:8042', allocatedMB=27648, allocatedVCores=6, runningContainers=6}, null]"; + + private static final ObjectMapper OBJ_MAPPER = new ObjectMapper(); + + static { + OBJ_MAPPER.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true); + } + @Test - public void testRunApplicationWithCLI(){ - new MRRunningJobApplication().run(ConfigFactory.load()); + public void testMRRunningJobFetchSpout() throws Exception { + + List<Object> tuples = new ArrayList<>(); + SpoutOutputCollector collector = new SpoutOutputCollector(new ISpoutOutputCollector() { + @Override + public List<Integer> emit(String streamId, List<Object> tuple, Object messageId) { + tuples.add(tuple); + return null; + } + + @Override + public void emitDirect(int taskId, String streamId, List<Object> tuple, Object messageId) { + + } + + @Override + public void reportError(Throwable error) { + + } + }); + + //1st run + Field initField = MRRunningJobFetchSpout.class.getDeclaredField("init"); + initField.setAccessible(true); + MRRunningJobFetchSpout mrRunningJobFetchSpout = makeMrRunningJobFetchSpout(); + boolean init = (boolean) initField.get(mrRunningJobFetchSpout); + mrRunningJobFetchSpout.open(new HashMap<>(), null, collector); + Assert.assertFalse(init); + mrRunningJobFetchSpout.nextTuple(); + + init = (boolean) initField.get(mrRunningJobFetchSpout); + Field runningYarnAppsField = MRRunningJobFetchSpout.class.getDeclaredField("runningYarnApps"); + runningYarnAppsField.setAccessible(true); + Set<String> runningYarnApps = (Set<String>) runningYarnAppsField.get(mrRunningJobFetchSpout); + Assert.assertTrue(tuples.isEmpty()); + Assert.assertTrue(init); + Assert.assertTrue(runningYarnApps.isEmpty()); + + //2nd run + mrRunningJobFetchSpout.nextTuple(); + + init = (boolean) initField.get(mrRunningJobFetchSpout); + Assert.assertTrue(init); + Assert.assertEquals(2, tuples.size()); + Assert.assertEquals(TUPLE_1, tuples.get(0).toString()); + Assert.assertEquals(TUPLE_2, tuples.get(1).toString()); + runningYarnApps = (Set<String>) runningYarnAppsField.get(mrRunningJobFetchSpout); + Assert.assertEquals(2, runningYarnApps.size()); + Assert.assertEquals(RUNNING_YARNAPPS, runningYarnApps.toString()); + + //3rd run + mockInputSteam("/previousmrrunningapp.json"); + tuples.clear(); + + mrRunningJobFetchSpout.nextTuple(); + + Assert.assertTrue(init); + Assert.assertEquals(2, tuples.size()); + Assert.assertEquals(TUPLE_1, tuples.get(0).toString()); + Assert.assertEquals(TUPLE_2, tuples.get(1).toString()); + runningYarnApps = (Set<String>) runningYarnAppsField.get(mrRunningJobFetchSpout); + Assert.assertEquals(2, runningYarnApps.size()); + Assert.assertEquals(RUNNING_YARNAPPS, runningYarnApps.toString()); + + //4th run + mockInputSteam("/thistimemrrunningapp.json"); + tuples.clear(); + + mrRunningJobFetchSpout.nextTuple(); + + Assert.assertTrue(init); + Assert.assertEquals(2, tuples.size()); + Assert.assertEquals(TUPLE_1, tuples.get(0).toString()); + Assert.assertEquals("[application_1479206441898_35341, AppInfo{id='application_1479206441898_35341', user='yyy', name='insert overwrite table inter...a.xxx(Stage-3)', queue='yyy', state='FINISHED', finalStatus='UNDEFINED', progress=59.545456, trackingUI='ApplicationMaster', trackingUrl='http://host.domain.com:8088/proxy/application_1479206441898_35341/', diagnostics='', clusterId='1479206441898', applicationType='MAPREDUCE', startedTime=1479341511477, finishedTime=0, elapsedTime=77619, amContainerLogs='http://host.domain.com:8042/node/containerlogs/container_e11_1479206441898_35341_01_000005/yyy', amHostHttpAddress='host.domain.com:8042', allocatedMB=27648, allocatedVCores=6, runningContainers=6}, {jobId=prefix:null, timestamp:0, humanReadableDate:1970-01-01 00:00:00,000, tags: , encodedRowkey:null}]", tuples.get(1).toString()); + + runningYarnApps = (Set<String>) runningYarnAppsField.get(mrRunningJobFetchSpout); + Assert.assertEquals(1, runningYarnApps.size()); + Assert.assertEquals("[application_1479206441898_30784]", runningYarnApps.toString()); + + } + + private MRRunningJobFetchSpout makeMrRunningJobFetchSpout() throws Exception { + + mockInputSteam("/previousmrrunningapp.json"); + + MRRunningJobConfig mrRunningJobConfig = MRRunningJobConfig.newInstance(ConfigFactory.load()); + mrRunningJobConfig.getEndpointConfig().fetchRunningJobInterval = 1; + MRRunningJobManager mrRunningJobManager = mock(MRRunningJobManager.class); + PowerMockito.whenNew(MRRunningJobManager.class).withArguments(mrRunningJobConfig.getZkStateConfig()).thenReturn(mrRunningJobManager); + + InputStream app35341 = this.getClass().getResourceAsStream("/application_1479206441898_35341.json"); + AppsWrapper appWrapper = OBJ_MAPPER.readValue(app35341, AppsWrapper.class); + List<AppInfo> appInfos = appWrapper.getApps().getApp(); + Map<String, JobExecutionAPIEntity> jobs = new HashMap<>(); + JobExecutionAPIEntity jobExecutionAPIEntity = new JobExecutionAPIEntity(); + jobExecutionAPIEntity.setAppInfo(appInfos.get(0)); + jobs.put("jobId", jobExecutionAPIEntity); + when(mrRunningJobManager.recoverYarnApp("application_1479206441898_35341")).thenReturn(jobs); + + return new MRRunningJobFetchSpout(mrRunningJobConfig.getEndpointConfig(), mrRunningJobConfig.getZkStateConfig()); + } + private void mockInputSteam(String mockDataFilePath) throws Exception { + InputStream jsonstream = this.getClass().getResourceAsStream(mockDataFilePath); + mockStatic(InputStreamUtils.class); + when(InputStreamUtils.getInputStream(RM_URL, null, Constants.CompressionType.GZIP)).thenReturn(jsonstream); } } http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/7499be69/eagle-jpm/eagle-jpm-mr-running/src/test/resources/application_1479206441898_35341.json ---------------------------------------------------------------------- diff --git a/eagle-jpm/eagle-jpm-mr-running/src/test/resources/application_1479206441898_35341.json b/eagle-jpm/eagle-jpm-mr-running/src/test/resources/application_1479206441898_35341.json new file mode 100644 index 0000000..7c5906d --- /dev/null +++ b/eagle-jpm/eagle-jpm-mr-running/src/test/resources/application_1479206441898_35341.json @@ -0,0 +1,35 @@ +{ + "apps": { + "app": [ + { + "id": "application_1479206441898_35341", + "user": "yyy", + "name": "insert overwrite table inter...a.xxx(Stage-3)", + "queue": "yyy", + "state": "RUNNING", + "finalStatus": "UNDEFINED", + "progress": 59.545456, + "trackingUI": "ApplicationMaster", + "trackingUrl": "http://host.domain.com:8088/proxy/application_1479206441898_35341/", + "diagnostics": "", + "clusterId": 1479206441898, + "applicationType": "MAPREDUCE", + "applicationTags": "", + "startedTime": 1479341511477, + "finishedTime": 0, + "elapsedTime": 77619, + "amContainerLogs": "http://host.domain.com:8042/node/containerlogs/container_e11_1479206441898_35341_01_000005/yyy", + "amHostHttpAddress": "host.domain.com:8042", + "allocatedMB": 27648, + "allocatedVCores": 6, + "runningContainers": 6, + "memorySeconds": 4940802, + "vcoreSeconds": 1483, + "preemptedResourceMB": 0, + "preemptedResourceVCores": 0, + "numNonAMContainerPreempted": 0, + "numAMContainerPreempted": 0 + } + ] + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/7499be69/eagle-jpm/eagle-jpm-mr-running/src/test/resources/previousmrrunningapp.json ---------------------------------------------------------------------- diff --git a/eagle-jpm/eagle-jpm-mr-running/src/test/resources/previousmrrunningapp.json b/eagle-jpm/eagle-jpm-mr-running/src/test/resources/previousmrrunningapp.json new file mode 100644 index 0000000..64a20f8 --- /dev/null +++ b/eagle-jpm/eagle-jpm-mr-running/src/test/resources/previousmrrunningapp.json @@ -0,0 +1,64 @@ +{ + "apps": { + "app": [ + { + "id": "application_1479206441898_30784", + "user": "xxx", + "name": "oozie:launcher:T=shell:W=wf_co_xxx_xxx_v3:A=extract_org_data:ID=0002383-161115184801730-oozie-oozi-W", + "queue": "xxx", + "state": "RUNNING", + "finalStatus": "UNDEFINED", + "progress": 95.0, + "trackingUI": "ApplicationMaster", + "trackingUrl": "http://host.domain.com:8088/proxy/application_1479206441898_30784/", + "diagnostics": "", + "clusterId": 1479206441898, + "applicationType": "MAPREDUCE", + "applicationTags": "", + "startedTime": 1479328221694, + "finishedTime": 0, + "elapsedTime": 13367402, + "amContainerLogs": "http://host.domain.com:8088/node/containerlogs/container_e11_1479206441898_30784_01_000001/xxx", + "amHostHttpAddress": "host.domain.com:8088", + "allocatedMB": 3072, + "allocatedVCores": 2, + "runningContainers": 2, + "memorySeconds": 41051800, + "vcoreSeconds": 26728, + "preemptedResourceMB": 0, + "preemptedResourceVCores": 0, + "numNonAMContainerPreempted": 0, + "numAMContainerPreempted": 0 + }, + { + "id": "application_1479206441898_35341", + "user": "yyy", + "name": "insert overwrite table inter...a.xxx(Stage-3)", + "queue": "yyy", + "state": "RUNNING", + "finalStatus": "UNDEFINED", + "progress": 59.545456, + "trackingUI": "ApplicationMaster", + "trackingUrl": "http://host.domain.com:8088/proxy/application_1479206441898_35341/", + "diagnostics": "", + "clusterId": 1479206441898, + "applicationType": "MAPREDUCE", + "applicationTags": "", + "startedTime": 1479341511477, + "finishedTime": 0, + "elapsedTime": 77619, + "amContainerLogs": "http://host.domain.com:8042/node/containerlogs/container_e11_1479206441898_35341_01_000005/yyy", + "amHostHttpAddress": "host.domain.com:8042", + "allocatedMB": 27648, + "allocatedVCores": 6, + "runningContainers": 6, + "memorySeconds": 4940802, + "vcoreSeconds": 1483, + "preemptedResourceMB": 0, + "preemptedResourceVCores": 0, + "numNonAMContainerPreempted": 0, + "numAMContainerPreempted": 0 + } + ] + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/7499be69/eagle-jpm/eagle-jpm-mr-running/src/test/resources/thistimemrrunningapp.json ---------------------------------------------------------------------- diff --git a/eagle-jpm/eagle-jpm-mr-running/src/test/resources/thistimemrrunningapp.json b/eagle-jpm/eagle-jpm-mr-running/src/test/resources/thistimemrrunningapp.json new file mode 100644 index 0000000..dbcbba5 --- /dev/null +++ b/eagle-jpm/eagle-jpm-mr-running/src/test/resources/thistimemrrunningapp.json @@ -0,0 +1,35 @@ +{ + "apps": { + "app": [ + { + "id": "application_1479206441898_30784", + "user": "xxx", + "name": "oozie:launcher:T=shell:W=wf_co_xxx_xxx_v3:A=extract_org_data:ID=0002383-161115184801730-oozie-oozi-W", + "queue": "xxx", + "state": "RUNNING", + "finalStatus": "UNDEFINED", + "progress": 95.0, + "trackingUI": "ApplicationMaster", + "trackingUrl": "http://host.domain.com:8088/proxy/application_1479206441898_30784/", + "diagnostics": "", + "clusterId": 1479206441898, + "applicationType": "MAPREDUCE", + "applicationTags": "", + "startedTime": 1479328221694, + "finishedTime": 0, + "elapsedTime": 13367402, + "amContainerLogs": "http://host.domain.com:8088/node/containerlogs/container_e11_1479206441898_30784_01_000001/xxx", + "amHostHttpAddress": "host.domain.com:8088", + "allocatedMB": 3072, + "allocatedVCores": 2, + "runningContainers": 2, + "memorySeconds": 41051800, + "vcoreSeconds": 26728, + "preemptedResourceMB": 0, + "preemptedResourceVCores": 0, + "numNonAMContainerPreempted": 0, + "numAMContainerPreempted": 0 + } + ] + } +} \ No newline at end of file