Mercurial > hg > release > thermostat-1.4
changeset 1535:f380c0ac5d57
VM-Stat command 'since' option addition
Addresses the cli/shell side for PR2006
Reviewed-by: jerboaa
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2014-November/011423.html
line wrap: on
line diff
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/LocaleResources.java Tue Nov 04 17:03:43 2014 -0500 +++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/LocaleResources.java Wed Nov 05 10:40:33 2014 -0500 @@ -105,6 +105,8 @@ PURGE_EXPENSIVE_OPERATION_PROMPT, PURGE_CANCELLED_MESSAGE, AFFIRMATIVE_RESPONSES, + + VM_STAT_INVALID_SINCE_ARGUMENT, ; static final String RESOURCE_BUNDLE = "com.redhat.thermostat.client.cli.strings";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/SinceTimestampParser.java Wed Nov 05 10:40:33 2014 -0500 @@ -0,0 +1,113 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.cli.internal; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class SinceTimestampParser { + + private final List<String> acceptedTimeUnits = Arrays.asList(new String[]{"DAYS", "HOURS", "MINUTES", "SECONDS"}); + + private final String parseString; + private final long defaultSinceTimestamp; + private final long startTimestamp; + + + public SinceTimestampParser(String parseString, long startTimestamp, long defaultSinceTimestamp) { + this.parseString = parseString; + this.startTimestamp = startTimestamp; + this.defaultSinceTimestamp = defaultSinceTimestamp; + } + + public long parse() throws InvalidSinceTimestampFormatException { + long since; + if (parseString != null) { + since = parseString(); + } else { + since = defaultSinceTimestamp; + } + return since; + } + + private long parseString() throws InvalidSinceTimestampFormatException { + if (parseString.equals("all")) { + return Long.MIN_VALUE; + } else { + return parseValueFromString(); + } + } + + private long parseValueFromString() throws InvalidSinceTimestampFormatException { + try { + String[] split = parseString.split(":"); + if (split.length != 2) { + throw new InvalidSinceTimestampFormatException("Invalid input"); + } + + long timeValue = Long.valueOf(split[0]); + + String timeString = split[1]; + TimeUnit timeUnit = getTimeUnitFromString(timeString); + + long value = timeUnit.toMillis(timeValue); + + if (!(value > 0)) { + throw new InvalidSinceTimestampFormatException("Time input must be greater than 0"); + } + + return startTimestamp - value; + } catch (Exception e) { + throw new InvalidSinceTimestampFormatException(e.getMessage()); + } + } + + private TimeUnit getTimeUnitFromString(String timeUnit) throws InvalidSinceTimestampFormatException { + timeUnit = timeUnit.toUpperCase(); + if (!acceptedTimeUnits.contains(timeUnit)) { + throw new InvalidSinceTimestampFormatException("Invalid time unit. Accepted time units are: days, hours, minutes or seconds"); + } + return TimeUnit.valueOf(timeUnit); + } + + public static class InvalidSinceTimestampFormatException extends Exception { + InvalidSinceTimestampFormatException(String message) { + super(message); + } + } +} \ No newline at end of file
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java Tue Nov 04 17:03:43 2014 -0500 +++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java Wed Nov 05 10:40:33 2014 -0500 @@ -57,16 +57,19 @@ import com.redhat.thermostat.common.cli.AbstractCommand; import com.redhat.thermostat.common.cli.CommandContext; import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.cli.CommandLineArgumentParseException; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.shared.locale.Translate; import com.redhat.thermostat.storage.core.VmRef; public class VMStatCommand extends AbstractCommand { + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); private static final Logger log = LoggingUtils.getLogger(VMStatCommand.class); - + private List<VMStatPrintDelegate> delegates; private BundleContext context; - + public VMStatCommand() { this(FrameworkUtil.getBundle(VMStatCommand.class).getBundleContext()); } @@ -93,11 +96,25 @@ @Override public void run(final CommandContext ctx) throws CommandException { + long currentTime = System.currentTimeMillis(); + long defaultSinceTime = currentTime - TimeUnit.MINUTES.toMillis(10); + HostVMArguments hostVMArgs = new HostVMArguments(ctx.getArguments()); VmRef vm = hostVMArgs.getVM(); + + long sinceTimestamp; + + String sinceArg = ctx.getArguments().getArgument("since"); + try { + sinceTimestamp = new SinceTimestampParser(sinceArg, currentTime, defaultSinceTime).parse(); + } catch (SinceTimestampParser.InvalidSinceTimestampFormatException e) { + throw new CommandLineArgumentParseException(translator.localize(LocaleResources.VM_STAT_INVALID_SINCE_ARGUMENT)); + } + // Pass a copy of the delegates list to the printer - final VMStatPrinter statPrinter = new VMStatPrinter(vm, new ArrayList<>(delegates), ctx.getConsole().getOutput()); + final VMStatPrinter statPrinter = new VMStatPrinter(vm, new ArrayList<>(delegates), ctx.getConsole().getOutput(), sinceTimestamp); statPrinter.printStats(); + boolean continuous = ctx.getArguments().hasArgument("continuous"); if (continuous) { startContinuousStats(ctx, statPrinter); @@ -115,7 +132,6 @@ timer.setSchedulingType(Timer.SchedulingType.FIXED_RATE); timer.setTimeUnit(TimeUnit.SECONDS); timer.setAction(new Runnable() { - @Override public void run() { statPrinter.printUpdatedStats(); @@ -140,7 +156,7 @@ } catch (InterruptedException e) { // Return immediately. } - + context.ungetService(ref); }
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatPrinter.java Tue Nov 04 17:03:43 2014 -0500 +++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatPrinter.java Wed Nov 05 10:40:33 2014 -0500 @@ -71,20 +71,20 @@ private int numCols; private Map<VMStatPrintDelegate, DelegateInfo> delegateInfo; - VMStatPrinter(VmRef vm, List<VMStatPrintDelegate> delegates, PrintStream out) { + VMStatPrinter(VmRef vm, List<VMStatPrintDelegate> delegates, PrintStream out, long sinceTimestamp) { this.vm = vm; this.delegates = delegates; this.out = out; int numDelegates = delegates.size(); this.delegateInfo = new HashMap<>(); this.correlator = new TimeStampedPojoCorrelator(numDelegates); - + // Sort the delegates list Collections.sort(delegates, new OrderedComparator<>()); - + for (VMStatPrintDelegate delegate : delegates) { DelegateInfo info = new DelegateInfo(); - info.lastTimeStamp = Long.MIN_VALUE; + info.lastTimeStamp = sinceTimestamp; delegateInfo.put(delegate, info); } }
--- a/client/cli/src/main/resources/com/redhat/thermostat/client/cli/strings.properties Tue Nov 04 17:03:43 2014 -0500 +++ b/client/cli/src/main/resources/com/redhat/thermostat/client/cli/strings.properties Wed Nov 05 10:40:33 2014 -0500 @@ -64,3 +64,5 @@ PURGE_EXPENSIVE_OPERATION_PROMPT = Are you sure you want to continue (Y/y/N/n)? PURGE_CANCELLED_MESSAGE = Not cleaning Thermostat data at this time. AFFIRMATIVE_RESPONSES = y|yes +VM_STAT_INVALID_SINCE_ARGUMENT = Invalid arguments for -since : Expected format time:timeunit : e.g. 5:seconds. Time must be positive. \ + Timeunit must be days, hours, minutes or seconds. \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/SinceTimestampParserTest.java Wed Nov 05 10:40:33 2014 -0500 @@ -0,0 +1,131 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.cli.internal; + +import static org.junit.Assert.assertEquals; + +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Test; + +public class SinceTimestampParserTest { + + private SinceTimestampParser parser; + private long startTimestamp; + + @Before + public void setup() { + startTimestamp = System.currentTimeMillis(); + } + + @Test + public void testAllInput() throws SinceTimestampParser.InvalidSinceTimestampFormatException { + parser = setupDefaultParser("all"); + long result = parser.parse(); + + assertEquals(Long.MIN_VALUE, result); + } + + @Test + public void testDefaultStamp() throws SinceTimestampParser.InvalidSinceTimestampFormatException { + long defaultTimestamp = 0l; + + parser = new SinceTimestampParser(null, startTimestamp, defaultTimestamp); + long result = parser.parse(); + + assertEquals(defaultTimestamp, result); + } + + @Test + public void testSecondsTimestamp() throws SinceTimestampParser.InvalidSinceTimestampFormatException { + parser = setupDefaultParser("1:seconds"); + long result = parser.parse(); + + assertEquals(startTimestamp - TimeUnit.SECONDS.toMillis(1), result); + } + + @Test + public void testMinutesTimestamp() throws SinceTimestampParser.InvalidSinceTimestampFormatException { + parser = setupDefaultParser("2:minutes"); + long result = parser.parse(); + assertEquals(startTimestamp - TimeUnit.MINUTES.toMillis(2), result); + } + + @Test + public void testHoursTimestamp() throws SinceTimestampParser.InvalidSinceTimestampFormatException { + parser = setupDefaultParser("3:hours"); + long result = parser.parse(); + assertEquals(startTimestamp - TimeUnit.HOURS.toMillis(3), result); + } + + @Test + public void testDaysTimestamp() throws SinceTimestampParser.InvalidSinceTimestampFormatException { + parser = setupDefaultParser("4:days"); + long result = parser.parse(); + assertEquals(startTimestamp - TimeUnit.DAYS.toMillis(4), result); + } + + @Test (expected = SinceTimestampParser.InvalidSinceTimestampFormatException.class) + public void testIncorrectTime() throws SinceTimestampParser.InvalidSinceTimestampFormatException { + parser = setupDefaultParser("0:minutes"); + parser.parse(); + } + + @Test (expected = SinceTimestampParser.InvalidSinceTimestampFormatException.class) + public void testNotAcceptedUnit() throws SinceTimestampParser.InvalidSinceTimestampFormatException { + parser = setupDefaultParser("5:milliseconds"); + parser.parse(); + } + + @Test (expected = SinceTimestampParser.InvalidSinceTimestampFormatException.class) + public void testIncorrectArgument() throws SinceTimestampParser.InvalidSinceTimestampFormatException { + parser = setupDefaultParser("aString"); + parser.parse(); + } + + @Test (expected = SinceTimestampParser.InvalidSinceTimestampFormatException.class) + public void testIncorrectArgumentTwo() throws SinceTimestampParser.InvalidSinceTimestampFormatException { + parser = setupDefaultParser("5:seconds:hello"); + parser.parse(); + } + + public SinceTimestampParser setupDefaultParser(String sinceTimestamp) { + return new SinceTimestampParser(sinceTimestamp, startTimestamp, 0l); + } + +} \ No newline at end of file
--- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VmStatCommandTest.java Tue Nov 04 17:03:43 2014 -0500 +++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VmStatCommandTest.java Wed Nov 05 10:40:33 2014 -0500 @@ -38,7 +38,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; @@ -54,13 +53,10 @@ import java.util.TimeZone; import java.util.concurrent.TimeUnit; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import com.redhat.thermostat.client.cli.VMStatPrintDelegate; @@ -68,7 +64,6 @@ import com.redhat.thermostat.common.Timer; import com.redhat.thermostat.common.cli.CommandException; import com.redhat.thermostat.common.cli.SimpleArguments; -import com.redhat.thermostat.storage.core.HostRef; import com.redhat.thermostat.storage.core.VmRef; import com.redhat.thermostat.storage.model.TimeStampedPojo; import com.redhat.thermostat.test.TestCommandContextFactory; @@ -165,26 +160,20 @@ VMStatCommand cmd = new VMStatCommand(context); - SimpleArguments args = new SimpleArguments(); - args.addArgument("vmId", "234"); - args.addArgument("hostId", "123"); - cmd.run(cmdCtxFactory.createContext(args)); + cmd.run(cmdCtxFactory.createContext(setupArguments())); String expected = "TIME FIRST SECOND THIRD FOURTH FIFTH\n" + "12:00:00 AM 1 2 3 4 5\n" + "12:00:01 AM 6 7 8 9 10\n" + "12:00:02 AM 11 12 13 14 15\n"; assertEquals(expected, cmdCtxFactory.getOutput()); } - + @Test public void testNoDelegates() throws CommandException { StubBundleContext context = new StubBundleContext(); VMStatCommand cmd = new VMStatCommand(context); - SimpleArguments args = new SimpleArguments(); - args.addArgument("vmId", "234"); - args.addArgument("hostId", "123"); - cmd.run(cmdCtxFactory.createContext(args)); + cmd.run(cmdCtxFactory.createContext(setupArguments())); String expected = "TIME\n"; assertEquals(expected, cmdCtxFactory.getOutput()); } @@ -216,9 +205,7 @@ Thread t = new Thread() { public void run() { - SimpleArguments args = new SimpleArguments(); - args.addArgument("vmId", "234"); - args.addArgument("hostId", "123"); + SimpleArguments args = setupArguments(); args.addArgument("continuous", "true"); try { cmd.run(cmdCtxFactory.createContext(args)); @@ -275,10 +262,7 @@ VMStatCommand cmd = new VMStatCommand(context); - SimpleArguments args = new SimpleArguments(); - args.addArgument("vmId", "234"); - args.addArgument("hostId", "123"); - cmd.run(cmdCtxFactory.createContext(args)); + cmd.run(cmdCtxFactory.createContext(setupArguments())); String expected = "TIME FIRST SECOND THIRD FOURTH FIFTH\n" + "12:00:00 AM 1 2 3 4 5\n" + "12:00:01 AM 6 7 8 9 10\n" @@ -301,10 +285,7 @@ VMStatCommand cmd = new VMStatCommand(context); - SimpleArguments args = new SimpleArguments(); - args.addArgument("vmId", "234"); - args.addArgument("hostId", "123"); - cmd.run(cmdCtxFactory.createContext(args)); + cmd.run(cmdCtxFactory.createContext(setupArguments())); String expected = "TIME FIRST SECOND THIRD FOURTH FIFTH\n" + "12:00:00 AM 1 2 3 4 5\n" + "12:00:01 AM 6 7 8 9 10\n" @@ -331,10 +312,7 @@ VMStatCommand cmd = new VMStatCommand(context); - SimpleArguments args = new SimpleArguments(); - args.addArgument("vmId", "234"); - args.addArgument("hostId", "123"); - cmd.run(cmdCtxFactory.createContext(args)); + cmd.run(cmdCtxFactory.createContext(setupArguments())); String expected = "TIME FIRST SECOND THIRD BAD FOURTH FIFTH\n" + "12:00:00 AM 1 2 3 4 5\n" + "12:00:01 AM 6 7 8 0 9 10\n" @@ -348,5 +326,13 @@ VMStatCommand cmd = new VMStatCommand(context); assertTrue(cmd.isStorageRequired()); } + + private SimpleArguments setupArguments() { + SimpleArguments args = new SimpleArguments(); + args.addArgument("vmId", "234"); + args.addArgument("hostId", "123"); + args.addArgument("since", "all"); + return args; + } }
--- a/distribution/config/commands/vm-stat.properties Tue Nov 04 17:03:43 2014 -0500 +++ b/distribution/config/commands/vm-stat.properties Wed Nov 05 10:40:33 2014 -0500 @@ -12,28 +12,35 @@ org.apache.commons.collections=${commons-collections.version}, \ org.apache.commons.logging=${commons-logging.version} -description = show various statistics about a VM +description = Show various statistics about a VM. -usage = vm-stat -hostId <host> --vmId <vm> [-d <url>] [-l <level>] +usage = vm-stat -hostId <host> --vmId <vm> [-c] [-s <time:timeunit>] [-d <url>] [-l <level>] -options = hostId, vmId, continuous, AUTO_DB_OPTIONS, AUTO_LOG_OPTION +options = hostId, vmId, continuous, since, AUTO_DB_OPTIONS, AUTO_LOG_OPTION hostId.short = a hostId.long = hostId hostId.hasarg = true hostId.required = true -hostId.description = the ID of the host to monitor +hostId.description = The ID of the host to monitor vmId.short = v vmId.long = vmId vmId.hasarg = true vmId.required = true -vmId.description = the ID of the VM to monitor +vmId.description = The ID of the VM to monitor continuous.short = c continuous.long = continuous continuous.hasarg = false continuous.required = false -continuous.description = print data continuously +continuous.description = Print data continuously + +since.short = s +since.long = since +since.hasarg = true +since.required = false +since.description = Print data since [-s time:timeunits] ago or print all data [-s all]. Defaults to since 10 minutes ago [-s 10:minutes]. Accepts positive times \ + and days, hours, minutes, or seconds. environments = cli, shell