diff --git a/helios-tools/src/main/java/com/spotify/helios/cli/command/JobInspectCommand.java b/helios-tools/src/main/java/com/spotify/helios/cli/command/JobInspectCommand.java index 12c68f45a..31fd45154 100644 --- a/helios-tools/src/main/java/com/spotify/helios/cli/command/JobInspectCommand.java +++ b/helios-tools/src/main/java/com/spotify/helios/cli/command/JobInspectCommand.java @@ -125,7 +125,7 @@ private static String formatRolloutOptions(final RolloutOptions options) { } public JobInspectCommand(final Subparser parser) { - super(parser); + super(parser, false); parser.help("print the configuration of a job"); } diff --git a/helios-tools/src/main/java/com/spotify/helios/cli/command/JobRemoveCommand.java b/helios-tools/src/main/java/com/spotify/helios/cli/command/JobRemoveCommand.java index 96554fcc5..7f2e99c05 100644 --- a/helios-tools/src/main/java/com/spotify/helios/cli/command/JobRemoveCommand.java +++ b/helios-tools/src/main/java/com/spotify/helios/cli/command/JobRemoveCommand.java @@ -40,7 +40,7 @@ public class JobRemoveCommand extends WildcardJobCommand { private final Argument yesArg; public JobRemoveCommand(Subparser parser) { - super(parser); + super(parser, false); parser.help("remove a job"); diff --git a/helios-tools/src/main/java/com/spotify/helios/cli/command/JobStartCommand.java b/helios-tools/src/main/java/com/spotify/helios/cli/command/JobStartCommand.java index 623aa4350..1c680edb7 100644 --- a/helios-tools/src/main/java/com/spotify/helios/cli/command/JobStartCommand.java +++ b/helios-tools/src/main/java/com/spotify/helios/cli/command/JobStartCommand.java @@ -41,7 +41,7 @@ public class JobStartCommand extends WildcardJobCommand { private final Argument tokenArg; public JobStartCommand(Subparser parser) { - super(parser); + super(parser, false); parser.help("start a stopped job"); diff --git a/helios-tools/src/main/java/com/spotify/helios/cli/command/JobStopCommand.java b/helios-tools/src/main/java/com/spotify/helios/cli/command/JobStopCommand.java index de33a4a7e..918887709 100644 --- a/helios-tools/src/main/java/com/spotify/helios/cli/command/JobStopCommand.java +++ b/helios-tools/src/main/java/com/spotify/helios/cli/command/JobStopCommand.java @@ -41,7 +41,7 @@ public class JobStopCommand extends WildcardJobCommand { private final Argument tokenArg; public JobStopCommand(Subparser parser) { - super(parser); + super(parser, false); parser.help("stop a running job without undeploying it"); diff --git a/helios-tools/src/main/java/com/spotify/helios/cli/command/JobUndeployCommand.java b/helios-tools/src/main/java/com/spotify/helios/cli/command/JobUndeployCommand.java index f9d36ade5..e8805af68 100644 --- a/helios-tools/src/main/java/com/spotify/helios/cli/command/JobUndeployCommand.java +++ b/helios-tools/src/main/java/com/spotify/helios/cli/command/JobUndeployCommand.java @@ -46,7 +46,7 @@ public class JobUndeployCommand extends WildcardJobCommand { private final Argument yesArg; public JobUndeployCommand(final Subparser parser) { - super(parser); + super(parser, false); parser.help("undeploy a job from hosts"); diff --git a/helios-tools/src/main/java/com/spotify/helios/cli/command/WildcardJobCommand.java b/helios-tools/src/main/java/com/spotify/helios/cli/command/WildcardJobCommand.java index 60d0c97eb..faaf722dd 100644 --- a/helios-tools/src/main/java/com/spotify/helios/cli/command/WildcardJobCommand.java +++ b/helios-tools/src/main/java/com/spotify/helios/cli/command/WildcardJobCommand.java @@ -41,6 +41,7 @@ abstract class WildcardJobCommand extends ControlCommand { private final Argument jobArg; + private final Argument strictStartArg; public WildcardJobCommand(final Subparser parser) { this(parser, false); @@ -51,16 +52,31 @@ public WildcardJobCommand(final Subparser parser, final boolean shortCircuit) { jobArg = parser.addArgument("job") .help("Job id."); + strictStartArg = parser.addArgument("--strict-start") + .type(Boolean.class) + .setDefault(false) + .help("Forces job names to be matched from the string start. " + + "By default, some commands will match on any jobs that contain the input name as a" + + " substring, this option forces the match to only happen if the string starts with" + + " the input name. Affects the subcommands: remove, inspect, rolling-update," + + " undeploy, deploy and stop."); } @Override int run(final Namespace options, final HeliosClient client, final PrintStream out, final boolean json, final BufferedReader stdin) throws ExecutionException, InterruptedException, IOException { - final String jobIdString = options.getString(jobArg.getDest()); final Map jobs = client.jobs(jobIdString).get(); + if (options.getBoolean(strictStartArg.getDest())) { + for (final Map.Entry entry : jobs.entrySet()) { + if (!entry.getKey().toShortString().startsWith(jobIdString)) { + jobs.remove(entry.getKey()); + } + } + } + if (jobs.size() == 0) { if (!json) { out.printf("Unknown job: %s%n", jobIdString); diff --git a/helios-tools/src/test/java/com/spotify/helios/cli/command/RollingUpdateCommandTest.java b/helios-tools/src/test/java/com/spotify/helios/cli/command/RollingUpdateCommandTest.java index 3f08fb91f..4e06b2a70 100644 --- a/helios-tools/src/test/java/com/spotify/helios/cli/command/RollingUpdateCommandTest.java +++ b/helios-tools/src/test/java/com/spotify/helios/cli/command/RollingUpdateCommandTest.java @@ -24,6 +24,7 @@ import static com.spotify.helios.common.descriptors.DeploymentGroup.RollingUpdateReason.MANUAL; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; @@ -648,6 +649,37 @@ public void testTimeoutDuringRolloutOutput() throws Exception { assertThat(baos.toString(), containsString(expectedSubstring)); } + @Test + public void testStrictStartJobName() throws Exception { + final JobId jobId1 = JobId.parse("foo-bar:cafe"); + Job job1 = Job.newBuilder() + .setName(jobId1.getName()) + .setHash(jobId1.getHash()) + .setRolloutOptions(jobOptions) + .build(); + final JobId jobId2 = JobId.parse("bar:beef"); + Job job2 = Job.newBuilder() + .setName(jobId2.getName()) + .setHash(jobId2.getHash()) + .setRolloutOptions(jobOptions) + .build(); + final Map jobs = ImmutableMap.of( + jobId1, job1, + jobId2, job2 + ); + when(client.jobs(anyString())).thenReturn(immediateFuture(jobs)); + + when(options.getBoolean("strict-start")).thenReturn(true); + + when(options.getString("job")).thenReturn("bar"); + + final int ret = command.run(options, client, out, false, null); + + assertEquals(ret, 0); + + assertThat(out.toString(), not(containsString("Ambiguous job reference"))); + } + private static class TimeUtil implements RollingUpdateCommand.SleepFunction, Supplier { private long curentTimeMillis = 0;