diff --git a/pom.xml b/pom.xml index 84ef907..ad6bd94 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.cloudera.utils.hadoop hadoop-cli - 2.4.1.0 + 2.4.3.0 Hadoop CLI Hadoop Command Line Interface @@ -50,8 +50,8 @@ 3.12.0 3.1.1 - 1.1.0 - 7.1.7.1000-141 + 1.2.0 + 7.1.8.8-3 1.0.0 2.5 @@ -92,8 +92,8 @@ ${hadoop.version}.${cdp.version} - org.apache.hadoop - hadoop-ozone-filesystem-hadoop3 + org.apache.ozone + ozone-filesystem-hadoop3 ${ozone.version}.${cdp.version} diff --git a/src/main/java/com/cloudera/utils/hadoop/HadoopSession.java b/src/main/java/com/cloudera/utils/hadoop/HadoopSession.java index b235dad..9b1bbf0 100644 --- a/src/main/java/com/cloudera/utils/hadoop/HadoopSession.java +++ b/src/main/java/com/cloudera/utils/hadoop/HadoopSession.java @@ -28,8 +28,8 @@ import com.cloudera.utils.hadoop.shell.commands.Exit; import com.cloudera.utils.hadoop.shell.commands.Help; import com.cloudera.utils.hadoop.shell.commands.HistoryCmd; -import com.cloudera.utils.hadoop.yarn.ContainerStats; -import com.cloudera.utils.hadoop.yarn.SchedulerStats; +import com.cloudera.utils.hadoop.yarn.ContainerStatsCommand; +import com.cloudera.utils.hadoop.yarn.SchedulerStatsCommand; import org.apache.commons.cli.*; import java.io.*; @@ -581,8 +581,8 @@ public void initialize() throws Exception { // getEnv().addCommand(new JhsStats("jhsstat", getEnv(), Direction.NONE)); // Yarn Tools - getEnv().addCommand(new ContainerStats("cstat", getEnv(), Direction.NONE)); - getEnv().addCommand(new SchedulerStats("sstat", getEnv(), Direction.NONE)); + getEnv().addCommand(new ContainerStatsCommand("cstat", getEnv(), Direction.NONE)); + getEnv().addCommand(new SchedulerStatsCommand("sstat", getEnv(), Direction.NONE)); getEnv().addCommand(new Exit("exit")); getEnv().addCommand(new LocalLs("lls", getEnv())); diff --git a/src/main/java/com/cloudera/utils/hadoop/shell/AbstractShell.java b/src/main/java/com/cloudera/utils/hadoop/shell/AbstractShell.java index 9759fb5..5b89b00 100644 --- a/src/main/java/com/cloudera/utils/hadoop/shell/AbstractShell.java +++ b/src/main/java/com/cloudera/utils/hadoop/shell/AbstractShell.java @@ -53,7 +53,7 @@ public abstract class AbstractShell implements Shell { private String bannerResource = "/banner.txt"; private boolean apiMode = false; - protected Environment getEnv() { + public Environment getEnv() { return env; } diff --git a/src/main/java/com/cloudera/utils/hadoop/yarn/ContainerStats.java b/src/main/java/com/cloudera/utils/hadoop/yarn/ContainerStats.java index b3512f1..8d0593f 100644 --- a/src/main/java/com/cloudera/utils/hadoop/yarn/ContainerStats.java +++ b/src/main/java/com/cloudera/utils/hadoop/yarn/ContainerStats.java @@ -16,11 +16,12 @@ package com.cloudera.utils.hadoop.yarn; -import com.cloudera.utils.hadoop.AbstractQueryTimeFrameStats; -import com.cloudera.utils.hadoop.hdfs.shell.command.Direction; -import com.cloudera.utils.hadoop.shell.Environment; import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionGroup; +import org.apache.commons.cli.Options; import org.apache.commons.io.IOUtils; +import org.apache.hadoop.conf.Configuration; import java.io.IOException; import java.net.MalformedURLException; @@ -38,7 +39,8 @@ * Using the Resource Manager JMX, collect the stats on applications since the last time this was run or up to * 'n' (limit). */ -public class ContainerStats extends AbstractQueryTimeFrameStats { +public class ContainerStats extends ResourceManagerStats { + public static final String URL_PATH = "/ws/v1/cluster/apps"; public static final String APP = "app"; // Not helpful for workload analysis. Leaving out for now. public static final String ATTEMPT = "attempt"; @@ -67,34 +69,23 @@ public class ContainerStats extends AbstractQueryTimeFrameStats { recordFieldMap.put(ATTEMPT, APP_ATTEMPT_FIELDS); } - public ContainerStats(String name) { - super(name); + public Map getRecordFieldMap() { + return recordFieldMap; } - @Override - public String getDescription() { - return "Collect Container Stats from the YARN REST API"; - } - - public ContainerStats(String name, Environment env, Direction directionContext) { - super(name, env, directionContext); - } - - public ContainerStats(String name, Environment env, Direction directionContext, int directives) { - super(name, env, directionContext, directives); + public ContainerStats(Configuration configuration) { + super(configuration); } - public ContainerStats(String name, Environment env, Direction directionContext, int directives, boolean directivesBefore, boolean directivesOptional) { - super(name, env, directionContext, directives, directivesBefore, directivesOptional); + public ContainerStats() { } - public ContainerStats(String name, Environment env) { - super(name, env); + // @Override + public String getDescription() { + return "Collect Application Container Stats from the YARN REST API"; } - @Override - public void process(CommandLine cmdln) { - + public void execute() { String baseRMUrlStr = getResourceManagerWebAddress(); // Test with Call. // if (ResourceManagerResolvable(baseRMUrlStr)) { @@ -104,9 +95,9 @@ public void process(CommandLine cmdln) { System.out.println("Resource Manager Server URL: " + baseRMUrlStr); - String rootPath = baseRMUrlStr + "/ws/v1/cluster/apps"; + String rootPath = baseRMUrlStr + URL_PATH; - Map queries = getQueries(cmdln); + Map queries = getQueries(); Iterator> iQ = queries.entrySet().iterator(); @@ -123,7 +114,7 @@ public void process(CommandLine cmdln) { String appsJson = IOUtils.toString(appsConnection.getInputStream(), StandardCharsets.UTF_8); if (raw) { - print(APP + "_raw", appsJson); +// print(APP + "_raw", appsJson); } else { YarnAppRecordConverter yarnRc = new YarnAppRecordConverter(); @@ -157,25 +148,59 @@ public void process(CommandLine cmdln) { ioe.printStackTrace(); } - if (!raw) { - Iterator>>> rIter = getRecords().entrySet().iterator(); - while (rIter.hasNext()) { - Map.Entry>> recordSet = rIter.next(); - print(recordSet.getKey(), recordFieldMap.get(recordSet.getKey()), recordSet.getValue()); - } - } - clearCache(); +// if (!raw) { +// Iterator>>> rIter = getRecords().entrySet().iterator(); +// while (rIter.hasNext()) { +// Map.Entry>> recordSet = rIter.next(); +// } +// } } } +// @Override + public void process(CommandLine cmdln) { + init(cmdln); + execute(); + } protected void getHelp() { StringBuilder sb = new StringBuilder(); - sb.append("Collect Container Stats for the YARN REST API.").append("\n"); - + sb.append("Collect Application Container Stats for the YARN REST API.").append("\n"); System.out.println(sb.toString()); } + @Override + public Options getOptions() { + Options options = super.getOptions(); + + OptionGroup beginOptionGroup = new OptionGroup(); + Option startOption = new Option("s", "start", true, + "Start time for retrieval in 'yyyy-MM-dd HH:mm:ss'"); + startOption.setRequired(false); + beginOptionGroup.addOption(startOption); + + Option lastOption = new Option("l", "last", true, + "last x-DAY(S)|x-HOUR(S)|x-MIN(S). 1-HOUR=1 hour, 2-DAYS=2 days, 3-HOURS=3 hours, etc."); + lastOption.setRequired(false); + beginOptionGroup.addOption(lastOption); + options.addOptionGroup(beginOptionGroup); + + // TODO: WIP for current stats. +// Option currentOption = new Option("c", "current", false, "Get Current / Active Records"); +// currentOption.setRequired(false); +// beginOptionGroup.addOption(currentOption); + + Option endOption = new Option("e", "end", true, + "End time for retrieval in 'yyyy-MM-dd HH:mm:ss'"); + endOption.setRequired(false); + options.addOption(endOption); + + Option incOption = new Option("inc", "increment", true, "Query Increment in minutes"); + incOption.setRequired(false); + options.addOption(incOption); + + return options; + } } diff --git a/src/main/java/com/cloudera/utils/hadoop/yarn/ContainerStatsCommand.java b/src/main/java/com/cloudera/utils/hadoop/yarn/ContainerStatsCommand.java new file mode 100644 index 0000000..5e8808a --- /dev/null +++ b/src/main/java/com/cloudera/utils/hadoop/yarn/ContainerStatsCommand.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022. David W. Streever All Rights Reserved + * + * Licensed 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 com.cloudera.utils.hadoop.yarn; + +import com.cloudera.utils.hadoop.AbstractStats; +import com.cloudera.utils.hadoop.hdfs.shell.command.Direction; +import com.cloudera.utils.hadoop.shell.Environment; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionGroup; +import org.apache.commons.cli.Options; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Created by streever on 2016-04-25. + *

+ * Using the Resource Manager JMX, collect the stats on applications since the last time this was run or up to + * 'n' (limit). + */ +public class ContainerStatsCommand extends AbstractStats { + + private ContainerStats containerStats = null; + @Override + public String getDescription() { + return "Collect Container Stats from the YARN REST API"; + } + + public ContainerStatsCommand(String name, Environment env, Direction directionContext) { + super(name, env, directionContext); +// appStats = new ContainerStatsImpl(env.getConfig()); + } + + public ContainerStatsCommand(String name, Environment env, Direction directionContext, int directives) { + super(name, env, directionContext, directives); + } + + public ContainerStatsCommand(String name, Environment env, Direction directionContext, int directives, boolean directivesBefore, boolean directivesOptional) { + super(name, env, directionContext, directives, directivesBefore, directivesOptional); + } + + public ContainerStatsCommand(String name, Environment env) { + super(name, env); + } + + protected ContainerStats getContainerStats() { + if (containerStats == null) + containerStats = new ContainerStats(env.getConfig()); + return containerStats; + } + @Override + public void process(CommandLine cmdln) { + getContainerStats().process(cmdln); + Iterator>>> rIter = getContainerStats().getRecords().entrySet().iterator(); + while (rIter.hasNext()) { + Map.Entry>> recordSet = rIter.next(); + print(recordSet.getKey(), getContainerStats().getRecordFieldMap().get(recordSet.getKey()), recordSet.getValue()); + } + getContainerStats().clearCache(); + } + + @Override + public Options getOptions() { + Options options = super.getOptions(); + Options csOptions = getContainerStats().getOptions(); + for (Object option: csOptions.getOptions()) { + if (option instanceof Option) { + options.addOption((Option)option); + } else if (option instanceof OptionGroup) { + options.addOptionGroup((OptionGroup)option); + } + } + return options; + } + + protected void getHelp() { + StringBuilder sb = new StringBuilder(); + sb.append("Collect Container Stats for the YARN REST API.").append("\n"); + + System.out.println(sb.toString()); + } + + +} diff --git a/src/main/java/com/cloudera/utils/hadoop/yarn/ResourceManagerStats.java b/src/main/java/com/cloudera/utils/hadoop/yarn/ResourceManagerStats.java new file mode 100644 index 0000000..3a436be --- /dev/null +++ b/src/main/java/com/cloudera/utils/hadoop/yarn/ResourceManagerStats.java @@ -0,0 +1,357 @@ +package com.cloudera.utils.hadoop.yarn; + +import com.cloudera.utils.hadoop.shell.Environment; +import com.cloudera.utils.hadoop.shell.command.CommandReturn; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionGroup; +import org.apache.commons.cli.Options; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.hadoop.conf.Configuration; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.map.ObjectMapper; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +public abstract class ResourceManagerStats implements Stats { + + protected ObjectMapper mapper = new ObjectMapper(); + + protected Configuration configuration = null; + + protected Boolean ssl = Boolean.FALSE; + protected Boolean raw = Boolean.FALSE; + + protected Long increment = 60l * 60l * 1000l; // 1 hour + + /** + * The earliest start time to get available jobs. Time since Epoch... + */ + protected Long startTime = 0l; + protected Long endTime = 0l; + + protected Map>> records = new LinkedHashMap>>(); + + private Options options; + + public Boolean getSsl() { + return ssl; + } + + public void setSsl(Boolean ssl) { + this.ssl = ssl; + } + + public Boolean getRaw() { + return raw; + } + + public void setRaw(Boolean raw) { + this.raw = raw; + } + + public Long getIncrement() { + return increment; + } + + public void setIncrement(Long increment) { + this.increment = increment; + } + + public Long getStartTime() { + return startTime; + } + + public void setStartTime(Long startTime) { + this.startTime = startTime; + } + + public Long getEndTime() { + return endTime; + } + + public void setEndTime(Long endTime) { + this.endTime = endTime; + } + + public ResourceManagerStats(Configuration configuration) { + setConfiguration(configuration); + } + + public ResourceManagerStats() { + } + + public Configuration getConfiguration() { + return configuration; + } + + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; + } + + public List> getRecordList(String recordType) { + List> rtn = records.get(recordType); + return rtn; + } + + public void clearCache() { + records.clear(); + } + + public Map>> getRecords() { + return records; + } + + public void addRecord(String recordType, Map record) { + List> list = null; + if (records.containsKey(recordType)) { + list = records.get(recordType); + } else { + list = new ArrayList>(); + records.put(recordType, list); + } + list.add(record); + } + + public void addRecords(String recordType, List> inRecords) { + List> list = null; + if (records.containsKey(recordType)) { + list = records.get(recordType); + } else { + list = new ArrayList>(); + records.put(recordType, list); + } + list.addAll(inRecords); + } + + public void init(CommandLine cmd) { +// cr = super.processOptions(environment, cmd, cr); + + try { + + Option[] cmdOpts = cmd.getOptions(); + String[] cmdArgs = cmd.getArgs(); + + if (cmd.hasOption("ssl")) { + ssl = Boolean.TRUE; + } else { + ssl = Boolean.FALSE; + } + + if (cmd.hasOption("raw")) { + this.raw = Boolean.TRUE; + } else { + this.raw = Boolean.FALSE; + } + + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + // Default Behaviour + // Set Start Time to previous day IF no config is specified. + Calendar startCal = Calendar.getInstance(); + Date startDate = new Date(); // default today. + if (cmd.hasOption("last")) { + String lastOption = cmd.getOptionValue("last"); + String[] lastParts = lastOption.split("-"); + if (lastParts.length == 2 && NumberUtils.isCreatable(lastParts[0])) { + Integer window = Integer.parseInt(lastParts[0]); + if (lastParts[1].toUpperCase().startsWith("MIN")) { + startCal.add(Calendar.MINUTE, (-1 * window)); + increment = 60l * 1000l; + } else if (lastParts[1].toUpperCase().startsWith("HOUR")) { + startCal.add(Calendar.HOUR, (-1 * window)); + increment = 10l * 60l * 1000l; // ten minutes + } else if (lastParts[1].toUpperCase().startsWith("DAY")) { + startCal.add(Calendar.DAY_OF_MONTH, (-1 * window)); + increment = 60l * 60l * 1000l; // 1 hour + } else { + // bad. + System.err.println("last option can't be parsed"); + throw new RuntimeException("stat option 'l|last' can't be parsed"); + } + } else { + System.err.println("last option can't be parsed"); + throw new RuntimeException("stat option 'l|last' can't be parsed"); + } + startDate = startCal.getTime(); + } else if (cmd.hasOption("start")) { + if (cmd.hasOption("start")) { + try { + startDate = df.parse(cmd.getOptionValue("start")); + } catch (ParseException e) { + e.printStackTrace(); +// cr.setCode(CODE_BAD_DATE); +// cr.getErr().print(e.getMessage()); +// return cr; + } + } + } else { + // default is 1 day. + startCal.add(Calendar.DAY_OF_MONTH, -1); + startDate = startCal.getTime(); + } + + // TODO: Need to work in 'current' + // Set the startTime + startTime = startDate.getTime(); + + if (cmd.hasOption("end")) { + Date endDate = null; + try { + endDate = df.parse(cmd.getOptionValue("end")); + } catch (ParseException e) { +// cr.setCode(CODE_BAD_DATE); +// cr.getErr().print(e.getMessage()); +// return cr; +// e.printStackTrace(); +// return new CommandReturn(CODE_BAD_DATE, e.getMessage()); // Bad Date + } + endTime = endDate.getTime(); + } else { + // If no Config. + // Set to now. + endTime = new Date().getTime(); + } + + if (cmd.hasOption("increment")) { + String incStr = cmd.getOptionValue("increment"); + increment = Long.parseLong(incStr) * 60l * 1000l; + } + } catch (Throwable t) { +// cr.setCode(CODE_STATS_ISSUE); +// cr.getErr().print(t.getMessage()); +// return cr; + } +// return cr; + } + + public String getProtocol() { + if (ssl) { + return "https://"; + } else { + return "http://"; + } + } + + protected Map getQueries() { + Map rtn = new LinkedHashMap(); + Long begin = startTime; + Long end = endTime; + + if (begin + increment < end) { + while (begin < end) { + StringBuilder sb = new StringBuilder(); + StringBuilder sb2 = new StringBuilder(); + sb.append("finishedTimeBegin=").append(begin); + sb2.append("finishedTimeBegin=").append(new Date(begin)); + begin = begin + increment - 1; + sb.append("&finishedTimeEnd=").append(begin); + sb2.append("&finishedTimeEnd=").append(new Date(begin)); + begin += 1; + rtn.put(sb.toString(), sb2.toString()); + } + } + return rtn; + } + + protected String getInternalRMAddress(String rmId) { + String rmAddress = null; + if (ssl) { + rmAddress = configuration.get("yarn.resourcemanager.webapp.https.address." + rmId); + } else { + rmAddress = configuration.get("yarn.resourcemanager.webapp.http.address." + rmId); + if (rmAddress == null) { + // Legacy + rmAddress = configuration.get("yarn.resourcemanager.webapp.address." + rmId); + } + } + if (rmAddress == null) { + throw new RuntimeException("Could locate RM Web Address, check protocol"); + } else { + rmAddress = getProtocol() + rmAddress; + } +// System.out.println("Checking Resource Manager Endpoint: " + rmAddress); + return rmAddress; + } + + protected String getRMState(String urlStr) { + String rtn = null; + try { + URL infoUrl = new URL(urlStr + "/ws/v1/cluster/info"); + URLConnection infoConnection = infoUrl.openConnection(); + String infoJson = IOUtils.toString(infoConnection.getInputStream()); + JsonNode info = mapper.readValue(infoJson, JsonNode.class); + JsonNode infoNode = info.get("clusterInfo"); + JsonNode haStateNode = infoNode.get("haState"); + rtn = haStateNode.asText(); + System.out.println("RM: " + urlStr + " state: " + rtn); + } catch (IOException ioe) { + ioe.printStackTrace(); + throw new RuntimeException("Failed to connect to RM at " + urlStr + ". Check Protocol.", ioe); + } + return rtn; + } + + protected String getActiveRMAddress() { + String[] rmIds = configuration.get("yarn.resourcemanager.ha.rm-ids").split(","); + // Get the Host and Port Address using the first id. + // Is SSL? +// System.out.println("RM Ids: " + rmIds[0]); + // Look at the first RM's Info and check for Active. + String rmAddress = getInternalRMAddress(rmIds[0]); + if (!getRMState(rmAddress).equals("ACTIVE")) { + rmAddress = getInternalRMAddress(rmIds[1]); + if (!getRMState(rmAddress).equals("ACTIVE")) { + throw new RuntimeException("Could locate ACTIVE Resource Manager"); + } + } + return rmAddress; + } + + public String getResourceManagerWebAddress() { + // Check for HA. + // yarn.resourcemanager.ha.enabled=true + String rmAddress = null; + String ha = configuration.get("yarn.resourcemanager.ha.enabled"); + if (ha != null && Boolean.parseBoolean(ha)) { + // Get the RM id's + rmAddress = getActiveRMAddress(); + } else { + // Non HA + // Is SSL? + if (ssl) { + rmAddress = getProtocol() + configuration.get("yarn.resourcemanager.webapp.https.address"); + } else { + rmAddress = getProtocol() + configuration.get("yarn.resourcemanager.webapp.http.address"); + if (rmAddress == null) { + // Legacy + rmAddress = getProtocol() + configuration.get("yarn.resourcemanager.webapp.address"); + } + } + } + return rmAddress; + } + + public Options getOptions() { + Options opts = new Options(); + + Option sslOption = new Option("ssl", "ssl", false, + "https connection"); + sslOption.setRequired(false); + opts.addOption(sslOption); + + Option rawOption = new Option("raw", "raw", false, + "Raw Record Output"); + rawOption.setRequired(false); + opts.addOption(rawOption); + + return opts; + } +} diff --git a/src/main/java/com/cloudera/utils/hadoop/yarn/SchedulerStats.java b/src/main/java/com/cloudera/utils/hadoop/yarn/SchedulerStats.java index bc57241..15cfff0 100644 --- a/src/main/java/com/cloudera/utils/hadoop/yarn/SchedulerStats.java +++ b/src/main/java/com/cloudera/utils/hadoop/yarn/SchedulerStats.java @@ -16,12 +16,10 @@ package com.cloudera.utils.hadoop.yarn; -import com.cloudera.utils.hadoop.AbstractStats; -import com.cloudera.utils.hadoop.hdfs.shell.command.Direction; import com.cloudera.utils.hadoop.yarn.parsers.QueueParser; -import com.cloudera.utils.hadoop.shell.Environment; import org.apache.commons.cli.CommandLine; import org.apache.commons.io.IOUtils; +import org.apache.hadoop.conf.Configuration; import java.io.IOException; import java.net.URL; @@ -36,7 +34,9 @@ *

* Using the Resource Manager JMX, collect the queue stats . */ -public class SchedulerStats extends AbstractStats { +public class SchedulerStats extends ResourceManagerStats { + + public static final String URL_PATH = "/ws/v1/cluster/scheduler"; public static final String QUEUE = "queue"; public static final String QUEUE_USAGE = "queue_usage"; @@ -99,36 +99,26 @@ public class SchedulerStats extends AbstractStats { recordFieldMap.put(QUEUE_USAGE, QUEUE_USAGE_FIELDS); } - private String timestamp = null; - - public SchedulerStats(String name) { - super(name); + public Map getRecordFieldMap() { + return recordFieldMap; } - @Override - public String getDescription() { - return "Collect Queue Stats from the YARN REST API"; - } - - public SchedulerStats(String name, Environment env, Direction directionContext) { - super(name, env, directionContext); - } + private String timestamp = null; - public SchedulerStats(String name, Environment env, Direction directionContext, int directives) { - super(name, env, directionContext, directives); + public SchedulerStats(Configuration configuration) { + super(configuration); } - public SchedulerStats(String name, Environment env, Direction directionContext, int directives, boolean directivesBefore, boolean directivesOptional) { - super(name, env, directionContext, directives, directivesBefore, directivesOptional); + public SchedulerStats() { } - public SchedulerStats(String name, Environment env) { - super(name, env); + // @Override + public String getDescription() { + return "Collect Queue Stats from the YARN REST API"; } @Override - public void process(CommandLine cmdln) { - + public void execute() { DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ"); this.timestamp = df.format(new Date()); @@ -141,7 +131,7 @@ public void process(CommandLine cmdln) { System.out.println("Resource Manager Server URL: " + baseRMUrlStr); - String rootPath = baseRMUrlStr + "/ws/v1/cluster/scheduler"; + String rootPath = baseRMUrlStr + URL_PATH; try { @@ -151,7 +141,7 @@ public void process(CommandLine cmdln) { String schJson = IOUtils.toString(schConnection.getInputStream(), StandardCharsets.UTF_8); if (raw) { - print(QUEUE + "_raw", schJson); +// print(QUEUE + "_raw", schJson); } else { QueueParser queueParser = new QueueParser(schJson); @@ -170,18 +160,24 @@ public void process(CommandLine cmdln) { */ - Iterator>>> rIter = getRecords().entrySet().iterator(); - while (rIter.hasNext()) { - Map.Entry>> recordSet = rIter.next(); +// Iterator>>> rIter = getRecords().entrySet().iterator(); +// while (rIter.hasNext()) { +// Map.Entry>> recordSet = rIter.next(); // System.out.println("Key: " + recordSet.getKey()); - print(recordSet.getKey(), recordFieldMap.get(recordSet.getKey()), recordSet.getValue()); - } +// print(recordSet.getKey(), recordFieldMap.get(recordSet.getKey()), recordSet.getValue()); +// } } } catch (IOException ioe) { ioe.printStackTrace(); } } + // @Override + public void process(CommandLine cmdln) { + init(cmdln); + execute(); + } + protected void getHelp() { StringBuilder sb = new StringBuilder(); sb.append("Collect Queue Stats from the YARN REST API.").append("\n"); diff --git a/src/main/java/com/cloudera/utils/hadoop/yarn/SchedulerStatsCommand.java b/src/main/java/com/cloudera/utils/hadoop/yarn/SchedulerStatsCommand.java new file mode 100644 index 0000000..3067ef4 --- /dev/null +++ b/src/main/java/com/cloudera/utils/hadoop/yarn/SchedulerStatsCommand.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022. David W. Streever All Rights Reserved + * + * Licensed 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 com.cloudera.utils.hadoop.yarn; + +import com.cloudera.utils.hadoop.AbstractStats; +import com.cloudera.utils.hadoop.hdfs.shell.command.Direction; +import com.cloudera.utils.hadoop.shell.Environment; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionGroup; +import org.apache.commons.cli.Options; + +import java.util.*; + +/** + * Created by streever on 2016-04-25. + *

+ * Using the Resource Manager JMX, collect the queue stats . + */ +public class SchedulerStatsCommand extends AbstractStats { + + private SchedulerStats schedulerStats = null; + public static final String QUEUE = "queue"; + + private String timestamp = null; + + public SchedulerStatsCommand(String name) { + super(name); + } + + @Override + public String getDescription() { + return "Collect Queue Stats from the YARN REST API"; + } + + public SchedulerStatsCommand(String name, Environment env, Direction directionContext) { + super(name, env, directionContext); +// schedulerStats = new SchedulerStatsImpl(env.getConfig()); + } + + public SchedulerStatsCommand(String name, Environment env, Direction directionContext, int directives) { + super(name, env, directionContext, directives); + } + + public SchedulerStatsCommand(String name, Environment env, Direction directionContext, int directives, boolean directivesBefore, boolean directivesOptional) { + super(name, env, directionContext, directives, directivesBefore, directivesOptional); + } + + public SchedulerStatsCommand(String name, Environment env) { + super(name, env); + } + + protected SchedulerStats getSchedulerStats() { + if (schedulerStats == null) + schedulerStats = new SchedulerStats(env.getConfig()); + return schedulerStats; + } + + @Override + public void process(CommandLine cmdln) { + getSchedulerStats().process(cmdln); + Iterator>>> rIter = getSchedulerStats().getRecords().entrySet().iterator(); + while (rIter.hasNext()) { + Map.Entry>> recordSet = rIter.next(); + print(recordSet.getKey(), getSchedulerStats().getRecordFieldMap().get(recordSet.getKey()), recordSet.getValue()); + } + getSchedulerStats().clearCache(); + } + + @Override + public Options getOptions() { + Options options = super.getOptions(); + Options csOptions = getSchedulerStats().getOptions(); + for (Object option: csOptions.getOptions()) { + if (option instanceof Option) { + options.addOption((Option)option); + } else if (option instanceof OptionGroup) { + options.addOptionGroup((OptionGroup)option); + } + } + return options; + } + + protected void getHelp() { + StringBuilder sb = new StringBuilder(); + sb.append("Collect Queue Stats from the YARN REST API.").append("\n"); + + System.out.println(sb.toString()); + } + + +} diff --git a/src/main/java/com/cloudera/utils/hadoop/yarn/Stats.java b/src/main/java/com/cloudera/utils/hadoop/yarn/Stats.java new file mode 100644 index 0000000..0e30317 --- /dev/null +++ b/src/main/java/com/cloudera/utils/hadoop/yarn/Stats.java @@ -0,0 +1,24 @@ +package com.cloudera.utils.hadoop.yarn; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Options; + +import java.util.List; +import java.util.Map; + +public interface Stats { + void execute(); + + void process(CommandLine commandLine); + + void init(CommandLine commandLine); + void clearCache(); + + Options getOptions(); + + Map getRecordFieldMap(); + + Map>> getRecords(); + + List> getRecordList(String recordType); +} diff --git a/src/main/java/com/cloudera/utils/hadoop/yarn/parsers/QueueParser.java b/src/main/java/com/cloudera/utils/hadoop/yarn/parsers/QueueParser.java index 4ac4087..53aed72 100644 --- a/src/main/java/com/cloudera/utils/hadoop/yarn/parsers/QueueParser.java +++ b/src/main/java/com/cloudera/utils/hadoop/yarn/parsers/QueueParser.java @@ -16,8 +16,8 @@ package com.cloudera.utils.hadoop.yarn.parsers; -import com.cloudera.utils.hadoop.yarn.SchedulerStats; import com.cloudera.utils.hadoop.util.RecordConverter; +import com.cloudera.utils.hadoop.yarn.SchedulerStats; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper;