/*
# Licensed Materials - Property of IBM
# Copyright IBM Corp. 2015, 2016
*/
package com.ibm.streamsx.topology.internal.streams;
import static com.ibm.streamsx.topology.internal.context.remote.DeployKeys.copyJobConfigOverlays;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Logger;
import com.google.gson.JsonObject;
import com.ibm.streams.operator.version.Product;
import com.ibm.streams.operator.version.Version;
import com.ibm.streamsx.topology.Topology;
import com.ibm.streamsx.topology.internal.gson.GsonUtilities;
import com.ibm.streamsx.topology.internal.process.ProcessOutputToLogger;
import com.ibm.streamsx.topology.jobconfig.JobConfig;
import com.ibm.streamsx.topology.jobconfig.SubmissionParameter;
public class InvokeSubmit {
static final Logger trace = Topology.STREAMS_LOGGER;
private final File bundle;
public InvokeSubmit(File bundle) {
super();
this.bundle = bundle;
}
public static void checkPreconditions() throws IllegalStateException {
Util.checkInvokeStreamtoolPreconditions();
}
public BigInteger invoke(JsonObject deploy) throws Exception, InterruptedException {
String si = Util.getStreamsInstall();
File sj = new File(si, "bin/streamtool");
checkPreconditions();
File jobidFile = Files.createTempFile("streamsjobid", "txt").toFile();
List<String> commands = new ArrayList<>();
commands.add(sj.getAbsolutePath());
commands.add("submitjob");
commands.add("--outfile");
commands.add(jobidFile.getAbsolutePath());
final JobConfig jobConfig = JobConfigOverlay.fromFullOverlay(deploy);
// For IBM Streams 4.2 or later use the job config overlay
// V.R.M.F
File jcoFile = null;
Version ver = Product.getVersion();
if (ver.getVersion() > 4 ||
(ver.getVersion() ==4 && ver.getRelease() >= 2)) {
jcoFile = fileJobConfig(commands, deploy);
} else {
explicitJobConfig(commands, jobConfig);
}
if (jobConfig.getOverrideResourceLoadProtection() != null) {
if (jobConfig.getOverrideResourceLoadProtection()) {
commands.add("--override");
commands.add("HostLoadProtection");
}
}
commands.add(bundle.getAbsolutePath());
trace.info("Invoking streamtool submitjob " + bundle.getAbsolutePath());
trace.info(Util.concatenate(commands));
ProcessBuilder pb = new ProcessBuilder(commands);
try {
Process sjProcess = pb.start();
ProcessOutputToLogger.log(trace, sjProcess);
sjProcess.getOutputStream().close();
int rc = sjProcess.waitFor();
trace.info("streamtool submitjob complete: return code=" + rc);
if (rc != 0)
throw new Exception("streamtool submitjob failed!");
try (Scanner jobIdScanner = new Scanner(jobidFile)) {
if (!jobIdScanner.hasNextBigInteger())
throw new Exception("streamtool failed to supply a job identifier!");
BigInteger jobId = jobIdScanner.nextBigInteger();
trace.info("Bundle: " + bundle.getName() + " submitted with jobid: " + jobId);
return jobId;
}
} finally {
jobidFile.delete();
if (jcoFile != null)
jcoFile.delete();
}
}
/**
* Set the job configuration as explicit streamtool submitjob arguments.
* Used for 4.1 and older.
*/
private void explicitJobConfig(List<String> commands, final JobConfig jobConfig) {
if (jobConfig.getTracing() != null) {
commands.add("--config");
commands.add("tracing="+jobConfig.getStreamsTracing());
}
if (jobConfig.getJobName() != null) {
commands.add("--jobname");
commands.add(jobConfig.getJobName());
}
if (jobConfig.getJobGroup() != null) {
commands.add("--jobgroup");
commands.add(jobConfig.getJobGroup());
}
if (jobConfig.getPreloadApplicationBundles() != null) {
commands.add("--config");
commands.add("preloadApplicationBundles="+jobConfig.getPreloadApplicationBundles());
}
if (jobConfig.getDataDirectory() != null) {
commands.add("--config");
commands.add("data-directory="+jobConfig.getDataDirectory());
}
if (jobConfig.hasSubmissionParameters()) {
for (SubmissionParameter param : jobConfig.getSubmissionParameters()) {
// note: this "streamtool" execution path does NOT correctly
// handle / preserve the semantics of escaped \t and \n.
// e.g., "\\n" is treated as a newline
// rather than the two char '\','n'
// This seems to be happening internal to streamtool.
// Adjust accordingly.
commands.add("-P");
commands.add(param.getName()+"="+param.getValue()
.replace("\\", "\\\\\\"));
}
}
}
/**
* Set the job configuration as a job config overlay
* Used for 4.2 and later.
*/
private File fileJobConfig(List<String> commands, final JsonObject deploy) throws IOException {
JsonObject jobConfigInfo = copyJobConfigOverlays(deploy);
String jcoJson = GsonUtilities.toJson(jobConfigInfo);
File jcoFile = File.createTempFile("streamsjco", ".json");
Files.write(jcoFile.toPath(), jcoJson.getBytes(StandardCharsets.UTF_8));
trace.info("Job Config Overlays: " + jcoJson);
commands.add("--jobConfig");
commands.add(jcoFile.getAbsolutePath());
return jcoFile;
}
}