Search in sources :

Example 1 with SubmitDryRunResponse

use of org.apache.heron.scheduler.dryrun.SubmitDryRunResponse in project heron by twitter.

the class TopologyResource method submit.

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
@SuppressWarnings({ "IllegalCatch", "JavadocMethod" })
public Response submit(FormDataMultiPart form) throws IOException {
    // verify that all we have all the required params
    final List<String> missingDataKeys = verifyKeys(form.getFields().keySet(), REQUIRED_SUBMIT_TOPOLOGY_PARAMS);
    if (!missingDataKeys.isEmpty()) {
        // return error since we are missing required parameters
        final String message = String.format("Validation failed missing required params: %s", missingDataKeys.toString());
        return Response.status(HTTP_UNPROCESSABLE_ENTITY_CODE).type(MediaType.APPLICATION_JSON).entity(Utils.createValidationError(message, missingDataKeys)).build();
    }
    final String cluster = Forms.getString(form, FORM_KEY_CLUSTER);
    if (!doesClusterMatch(cluster)) {
        return Response.status(HTTP_UNPROCESSABLE_ENTITY_CODE).type(MediaType.APPLICATION_JSON).entity(Utils.createMessage(String.format("Unknown cluster %s expecting '%s'", cluster, getCluster()))).build();
    }
    final String topologyName = Forms.getString(form, FORM_KEY_NAME);
    final String role = Forms.getString(form, FORM_KEY_ROLE);
    final String environment = Forms.getString(form, FORM_KEY_ENVIRONMENT, Constants.DEFAULT_HERON_ENVIRONMENT);
    final String user = Forms.getString(form, FORM_KEY_USER, role);
    // submit overrides are passed key=value
    final Map<String, String> submitOverrides = getSubmitOverrides(form);
    final String topologyDirectory = Files.createTempDirectory(topologyName).toFile().getAbsolutePath();
    try {
        // upload the topology definition file to the topology directory
        final FormDataBodyPart definitionFilePart = form.getField(FORM_KEY_DEFINITION);
        final File topologyDefinitionFile = Forms.uploadFile(definitionFilePart, topologyDirectory);
        // upload the topology binary file to the topology directory
        final FormDataBodyPart topologyFilePart = form.getField(FORM_KEY_TOPOLOGY);
        final File topologyBinaryFile = Forms.uploadFile(topologyFilePart, topologyDirectory);
        final boolean isDryRun = form.getFields().containsKey(PARAM_DRY_RUN);
        final boolean isVerbose = form.getFields().containsKey("verbose");
        final boolean isVerboseGC = form.getFields().containsKey("verbose_gc");
        // copy configuration files to the sandbox config location
        // topology-dir/<default-heron-sandbox-config>
        FileHelper.copyDirectory(Paths.get(getConfigurationDirectory()), Paths.get(topologyDirectory, Constants.DEFAULT_HERON_SANDBOX_CONFIG));
        final java.nio.file.Path overridesPath = Paths.get(topologyDirectory, Constants.DEFAULT_HERON_SANDBOX_CONFIG, Constants.OVERRIDE_FILE);
        // copy override file into topology configuration directory
        FileHelper.copy(Paths.get(getConfigurationOverridePath()), overridesPath);
        // apply submit overrides
        ConfigUtils.applyOverrides(overridesPath, submitOverrides);
        // apply overrides to state manager config
        ConfigUtils.applyOverridesToStateManagerConfig(overridesPath, Paths.get(topologyDirectory, Constants.DEFAULT_HERON_SANDBOX_CONFIG, Constants.STATE_MANAGER_FILE));
        // create tar file from the contents of the topology directory
        final File topologyPackageFile = Paths.get(topologyDirectory, TOPOLOGY_TAR_GZ_FILENAME).toFile();
        FileHelper.createTarGz(topologyPackageFile, FileHelper.getChildren(topologyDirectory));
        // create configs
        Config topologyConfig = ConfigUtils.getTopologyConfig(topologyPackageFile.getAbsolutePath(), topologyBinaryFile.getName(), topologyDefinitionFile.getAbsolutePath());
        List<Pair<String, Object>> val = new LinkedList<>();
        for (Map.Entry<String, Object> entry : topologyConfig.getEntrySet()) {
            val.add(Pair.create(entry.getKey(), entry.getValue()));
        }
        val.addAll(Arrays.asList(Pair.create(Key.CLUSTER.value(), cluster), Pair.create(Key.TOPOLOGY_NAME.value(), topologyName), Pair.create(Key.ROLE.value(), role), Pair.create(Key.ENVIRON.value(), environment), Pair.create(Key.SUBMIT_USER.value(), user), Pair.create(Key.DRY_RUN.value(), isDryRun), Pair.create(Key.VERBOSE.value(), isVerbose), Pair.create(Key.VERBOSE_GC.value(), isVerboseGC)));
        final Config config = createConfig(val, submitOverrides);
        // submit the topology
        getActionFactory().createSubmitAction(config, topologyPackageFile.getAbsolutePath(), topologyBinaryFile.getName(), topologyDefinitionFile.getAbsolutePath()).execute();
        return Response.created(URI.create(String.format(TOPOLOGY_PATH_FORMAT, cluster, role, environment, topologyName))).type(MediaType.APPLICATION_JSON).entity(createdResponse(cluster, role, environment, topologyName)).build();
    } catch (SubmitDryRunResponse response) {
        return createDryRunResponse(response, Forms.getString(form, PARAM_DRY_RUN_FORMAT, DEFAULT_DRY_RUN_FORMAT));
    } catch (Exception ex) {
        LOG.error("error submitting topology {}", topologyName, ex);
        return Response.serverError().type(MediaType.APPLICATION_JSON).entity(Utils.createMessage(ex.getMessage())).build();
    } finally {
        FileUtils.deleteDir(topologyDirectory);
    }
}
Also used : Config(org.apache.heron.spi.common.Config) LinkedList(java.util.LinkedList) IOException(java.io.IOException) SubmitDryRunResponse(org.apache.heron.scheduler.dryrun.SubmitDryRunResponse) FormDataBodyPart(org.glassfish.jersey.media.multipart.FormDataBodyPart) File(java.io.File) HashMap(java.util.HashMap) Map(java.util.Map) MultivaluedMap(javax.ws.rs.core.MultivaluedMap) Pair(org.apache.heron.common.basics.Pair) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces)

Example 2 with SubmitDryRunResponse

use of org.apache.heron.scheduler.dryrun.SubmitDryRunResponse in project heron by twitter.

the class LaunchRunner method call.

/**
 * Call launcher to launch topology
 *
 * @throws LauncherException
 * @throws PackingException
 * @throws SubmitDryRunResponse
 */
public void call() throws LauncherException, PackingException, SubmitDryRunResponse {
    SchedulerStateManagerAdaptor statemgr = Runtime.schedulerStateManagerAdaptor(runtime);
    TopologyAPI.Topology topology = Runtime.topology(runtime);
    String topologyName = Context.topologyName(config);
    PackingPlan packedPlan = LauncherUtils.getInstance().createPackingPlan(config, runtime);
    if (Context.dryRun(config)) {
        throw new SubmitDryRunResponse(topology, config, packedPlan);
    }
    // initialize the launcher
    launcher.initialize(config, runtime);
    // Set topology def first since we determine whether a topology is running
    // by checking the existence of topology def
    // store the trimmed topology definition into the state manager
    // TODO(rli): log-and-false anti-pattern is too nested on this path. will not refactor
    Boolean result = statemgr.setTopology(trimTopology(topology), topologyName);
    if (result == null || !result) {
        throw new LauncherException(String.format("Failed to set topology definition for topology '%s'", topologyName));
    }
    result = statemgr.setPackingPlan(createPackingPlan(packedPlan), topologyName);
    if (result == null || !result) {
        statemgr.deleteTopology(topologyName);
        throw new LauncherException(String.format("Failed to set packing plan for topology '%s'", topologyName));
    }
    // store the execution state into the state manager
    ExecutionEnvironment.ExecutionState executionState = createExecutionState();
    result = statemgr.setExecutionState(executionState, topologyName);
    if (result == null || !result) {
        statemgr.deletePackingPlan(topologyName);
        statemgr.deleteTopology(topologyName);
        throw new LauncherException(String.format("Failed to set execution state for topology '%s'", topologyName));
    }
    // returning false. In some cases the scheduler needs to have the topology deleted.
    try {
        if (!launcher.launch(packedPlan)) {
            throw new TopologySubmissionException(null);
        }
    } catch (TopologySubmissionException e) {
        // Compile error message to throw.
        final StringBuilder errorMessage = new StringBuilder(String.format("Failed to launch topology '%s'", topologyName));
        if (e.getMessage() != null) {
            errorMessage.append("\n").append(e.getMessage());
        }
        try {
            // Clear state from the Scheduler via RPC.
            Scheduler.KillTopologyRequest killTopologyRequest = Scheduler.KillTopologyRequest.newBuilder().setTopologyName(topologyName).build();
            ISchedulerClient schedulerClient = new SchedulerClientFactory(config, runtime).getSchedulerClient();
            if (!schedulerClient.killTopology(killTopologyRequest)) {
                final String logMessage = String.format("Failed to remove topology '%s' from scheduler after failed submit. " + "Please re-try the kill command.", topologyName);
                errorMessage.append("\n").append(logMessage);
                LOG.log(Level.SEVERE, logMessage);
            }
        // SUPPRESS CHECKSTYLE IllegalCatch
        } catch (Exception ignored) {
            // The above call to clear the Scheduler may fail. This situation can be ignored.
            LOG.log(Level.FINE, String.format("Failure clearing failed topology `%s` from Scheduler during `submit`", topologyName));
        }
        // Clear state from the State Manager.
        statemgr.deleteExecutionState(topologyName);
        statemgr.deletePackingPlan(topologyName);
        statemgr.deleteTopology(topologyName);
        throw new LauncherException(errorMessage.toString());
    }
}
Also used : LauncherException(org.apache.heron.spi.scheduler.LauncherException) ExecutionEnvironment(org.apache.heron.proto.system.ExecutionEnvironment) PackingPlan(org.apache.heron.spi.packing.PackingPlan) SchedulerClientFactory(org.apache.heron.scheduler.client.SchedulerClientFactory) PackingException(org.apache.heron.spi.packing.PackingException) LauncherException(org.apache.heron.spi.scheduler.LauncherException) SchedulerStateManagerAdaptor(org.apache.heron.spi.statemgr.SchedulerStateManagerAdaptor) TopologyAPI(org.apache.heron.api.generated.TopologyAPI) SubmitDryRunResponse(org.apache.heron.scheduler.dryrun.SubmitDryRunResponse) ISchedulerClient(org.apache.heron.scheduler.client.ISchedulerClient)

Example 3 with SubmitDryRunResponse

use of org.apache.heron.scheduler.dryrun.SubmitDryRunResponse in project heron by twitter.

the class SubmitterMain method main.

public static void main(String[] args) throws Exception {
    Options options = constructOptions();
    Options helpOptions = constructHelpOptions();
    CommandLineParser parser = new DefaultParser();
    // parse the help options first.
    CommandLine cmd = parser.parse(helpOptions, args, true);
    if (cmd.hasOption("h")) {
        usage(options);
        return;
    }
    try {
        // Now parse the required options
        cmd = parser.parse(options, args);
    } catch (ParseException e) {
        usage(options);
        throw new RuntimeException("Error parsing command line options: ", e);
    }
    Level logLevel = Level.INFO;
    if (isVerbose(cmd)) {
        logLevel = Level.ALL;
    }
    // init log
    LoggingHelper.loggerInit(logLevel, false);
    // load the topology definition into topology proto
    TopologyAPI.Topology topology = TopologyUtils.getTopology(cmd.getOptionValue("topology_defn"));
    Config config = loadConfig(cmd, topology);
    LOG.fine("Static config loaded successfully");
    LOG.fine(config.toString());
    SubmitterMain submitterMain = new SubmitterMain(config, topology);
    /* Meaning of exit status code:
       - status code = 0:
         program exits without error
       - 0 < status code < 100:
         program fails to execute before program execution. For example,
         JVM cannot find or load main class
       - 100 <= status code < 200:
         program fails to launch after program execution. For example,
         topology definition file fails to be loaded
       - status code >= 200
         program sends out dry-run response */
    try {
        submitterMain.submitTopology();
    } catch (SubmitDryRunResponse response) {
        LOG.log(Level.FINE, "Sending out dry-run response");
        // Output may contain UTF-8 characters, so we should print using UTF-8 encoding
        PrintStream out = new PrintStream(System.out, true, StandardCharsets.UTF_8.name());
        out.print(DryRunRenders.render(response, Context.dryRunFormatType(config)));
        // Exit with status code 200 to indicate dry-run response is sent out
        // SUPPRESS CHECKSTYLE RegexpSinglelineJava
        System.exit(200);
    // SUPPRESS CHECKSTYLE IllegalCatch
    } catch (Exception e) {
        /* Since only stderr is used (by logging), we use stdout here to
         propagate error message back to Python's executor.py (invoke site). */
        LOG.log(Level.SEVERE, "Exception when submitting topology", e);
        System.out.println(e.getMessage());
        // Exit with status code 100 to indicate that error has happened on user-land
        // SUPPRESS CHECKSTYLE RegexpSinglelineJava
        System.exit(100);
    }
    LOG.log(Level.FINE, "Topology {0} submitted successfully", topology.getName());
}
Also used : Options(org.apache.commons.cli.Options) PrintStream(java.io.PrintStream) Config(org.apache.heron.spi.common.Config) PackingException(org.apache.heron.spi.packing.PackingException) UploaderException(org.apache.heron.spi.uploader.UploaderException) ParseException(org.apache.commons.cli.ParseException) LauncherException(org.apache.heron.spi.scheduler.LauncherException) TopologyAPI(org.apache.heron.api.generated.TopologyAPI) SubmitDryRunResponse(org.apache.heron.scheduler.dryrun.SubmitDryRunResponse) CommandLine(org.apache.commons.cli.CommandLine) Level(java.util.logging.Level) CommandLineParser(org.apache.commons.cli.CommandLineParser) ParseException(org.apache.commons.cli.ParseException) DefaultParser(org.apache.commons.cli.DefaultParser)

Aggregations

SubmitDryRunResponse (org.apache.heron.scheduler.dryrun.SubmitDryRunResponse)3 TopologyAPI (org.apache.heron.api.generated.TopologyAPI)2 Config (org.apache.heron.spi.common.Config)2 PackingException (org.apache.heron.spi.packing.PackingException)2 LauncherException (org.apache.heron.spi.scheduler.LauncherException)2 File (java.io.File)1 IOException (java.io.IOException)1 PrintStream (java.io.PrintStream)1 HashMap (java.util.HashMap)1 LinkedList (java.util.LinkedList)1 Map (java.util.Map)1 Level (java.util.logging.Level)1 Consumes (javax.ws.rs.Consumes)1 POST (javax.ws.rs.POST)1 Produces (javax.ws.rs.Produces)1 MultivaluedMap (javax.ws.rs.core.MultivaluedMap)1 CommandLine (org.apache.commons.cli.CommandLine)1 CommandLineParser (org.apache.commons.cli.CommandLineParser)1 DefaultParser (org.apache.commons.cli.DefaultParser)1 Options (org.apache.commons.cli.Options)1