001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.oozie.cli; 020 021import com.google.common.annotations.VisibleForTesting; 022import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 023import org.apache.commons.cli.CommandLine; 024import org.apache.commons.cli.Option; 025import org.apache.commons.cli.OptionBuilder; 026import org.apache.commons.cli.OptionGroup; 027import org.apache.commons.cli.Options; 028import org.apache.commons.cli.ParseException; 029import org.apache.commons.io.FilenameUtils; 030import org.apache.oozie.BuildInfo; 031import org.apache.oozie.client.ApiJarLoader; 032import org.apache.oozie.client.AuthOozieClient; 033import org.apache.oozie.client.BulkResponse; 034import org.apache.oozie.client.BundleJob; 035import org.apache.oozie.client.CoordinatorAction; 036import org.apache.oozie.client.CoordinatorJob; 037import org.apache.oozie.client.OozieClient; 038import org.apache.oozie.client.OozieClient.SYSTEM_MODE; 039import org.apache.oozie.client.OozieClientException; 040import org.apache.oozie.client.WorkflowAction; 041import org.apache.oozie.client.WorkflowJob; 042import org.apache.oozie.client.XOozieClient; 043import org.apache.oozie.client.rest.JsonTags; 044import org.apache.oozie.client.rest.JsonToBean; 045import org.apache.oozie.client.rest.RestConstants; 046import org.apache.oozie.fluentjob.api.serialization.WorkflowMarshaller; 047import org.apache.oozie.fluentjob.api.workflow.Workflow; 048import org.json.simple.JSONArray; 049import org.json.simple.JSONObject; 050import org.w3c.dom.DOMException; 051import org.w3c.dom.Document; 052import org.w3c.dom.Element; 053import org.w3c.dom.Node; 054import org.w3c.dom.NodeList; 055import org.w3c.dom.Text; 056import org.xml.sax.SAXException; 057 058import javax.xml.bind.JAXBException; 059import javax.xml.parsers.DocumentBuilder; 060import javax.xml.parsers.DocumentBuilderFactory; 061import javax.xml.parsers.ParserConfigurationException; 062import java.io.File; 063import java.io.FileInputStream; 064import java.io.IOException; 065import java.io.InputStream; 066import java.io.InputStreamReader; 067import java.io.PrintStream; 068import java.lang.reflect.InvocationTargetException; 069import java.nio.charset.StandardCharsets; 070import java.nio.file.Files; 071import java.nio.file.Path; 072import java.text.SimpleDateFormat; 073import java.util.ArrayList; 074import java.util.Date; 075import java.util.List; 076import java.util.Locale; 077import java.util.Map; 078import java.util.Properties; 079import java.util.TimeZone; 080import java.util.TreeMap; 081import java.util.concurrent.Callable; 082import java.util.regex.Matcher; 083import java.util.regex.Pattern; 084 085/** 086 * Oozie command line utility. 087 */ 088public class OozieCLI { 089 public static final String ENV_OOZIE_URL = "OOZIE_URL"; 090 public static final String ENV_OOZIE_DEBUG = "OOZIE_DEBUG"; 091 public static final String ENV_OOZIE_TIME_ZONE = "OOZIE_TIMEZONE"; 092 public static final String ENV_OOZIE_AUTH = "OOZIE_AUTH"; 093 public static final String OOZIE_RETRY_COUNT = "oozie.connection.retry.count"; 094 public static final String WS_HEADER_PREFIX = "header:"; 095 096 public static final String HELP_CMD = "help"; 097 public static final String VERSION_CMD = "version"; 098 public static final String JOB_CMD = "job"; 099 public static final String JOBS_CMD = "jobs"; 100 public static final String ADMIN_CMD = "admin"; 101 public static final String VALIDATE_CMD = "validate"; 102 public static final String SLA_CMD = "sla"; 103 public static final String PIG_CMD = "pig"; 104 public static final String HIVE_CMD = "hive"; 105 public static final String SQOOP_CMD = "sqoop"; 106 public static final String MR_CMD = "mapreduce"; 107 public static final String INFO_CMD = "info"; 108 109 public static final String OOZIE_OPTION = "oozie"; 110 public static final String CONFIG_OPTION = "config"; 111 public static final String SUBMIT_OPTION = "submit"; 112 public static final String OFFSET_OPTION = "offset"; 113 public static final String START_OPTION = "start"; 114 public static final String RUN_OPTION = "run"; 115 public static final String DRYRUN_OPTION = "dryrun"; 116 public static final String SUSPEND_OPTION = "suspend"; 117 public static final String RESUME_OPTION = "resume"; 118 public static final String KILL_OPTION = "kill"; 119 public static final String CHANGE_OPTION = "change"; 120 public static final String CHANGE_VALUE_OPTION = "value"; 121 public static final String RERUN_OPTION = "rerun"; 122 public static final String INFO_OPTION = "info"; 123 public static final String LOG_OPTION = "log"; 124 public static final String ERROR_LOG_OPTION = "errorlog"; 125 public static final String AUDIT_LOG_OPTION = "auditlog"; 126 public static final String VALIDATE_JAR_OPTION = "validatejar"; 127 public static final String SUBMIT_JAR_OPTION = "submitjar"; 128 public static final String RUN_JAR_OPTION = "runjar"; 129 130 public static final String ACTION_OPTION = "action"; 131 public static final String DEFINITION_OPTION = "definition"; 132 public static final String CONFIG_CONTENT_OPTION = "configcontent"; 133 public static final String SQOOP_COMMAND_OPTION = "command"; 134 public static final String SHOWDIFF_OPTION = "diff"; 135 public static final String UPDATE_OPTION = "update"; 136 public static final String IGNORE_OPTION = "ignore"; 137 public static final String POLL_OPTION = "poll"; 138 public static final String TIMEOUT_OPTION = "timeout"; 139 public static final String INTERVAL_OPTION = "interval"; 140 141 public static final String DO_AS_OPTION = "doas"; 142 143 public static final String LEN_OPTION = "len"; 144 public static final String FILTER_OPTION = "filter"; 145 public static final String JOBTYPE_OPTION = "jobtype"; 146 public static final String SYSTEM_MODE_OPTION = "systemmode"; 147 public static final String VERSION_OPTION = "version"; 148 public static final String STATUS_OPTION = "status"; 149 public static final String LOCAL_TIME_OPTION = "localtime"; 150 public static final String TIME_ZONE_OPTION = "timezone"; 151 public static final String QUEUE_DUMP_OPTION = "queuedump"; 152 public static final String DATE_OPTION = "date"; 153 public static final String RERUN_REFRESH_OPTION = "refresh"; 154 public static final String RERUN_NOCLEANUP_OPTION = "nocleanup"; 155 public static final String RERUN_FAILED_OPTION = "failed"; 156 public static final String ORDER_OPTION = "order"; 157 public static final String COORD_OPTION = "coordinator"; 158 159 public static final String UPDATE_SHARELIB_OPTION = "sharelibupdate"; 160 161 public static final String LIST_SHARELIB_LIB_OPTION = "shareliblist"; 162 public static final String PURGE_OPTION = "purge"; 163 164 public static final String SLA_DISABLE_ALERT = "sladisable"; 165 public static final String SLA_ENABLE_ALERT = "slaenable"; 166 public static final String SLA_CHANGE = "slachange"; 167 168 public static final String SERVER_CONFIGURATION_OPTION = "configuration"; 169 public static final String SERVER_OS_ENV_OPTION = "osenv"; 170 public static final String SERVER_JAVA_SYSTEM_PROPERTIES_OPTION = "javasysprops"; 171 172 public static final String METRICS_OPTION = "metrics"; 173 public static final String INSTRUMENTATION_OPTION = "instrumentation"; 174 175 public static final String AUTH_OPTION = "auth"; 176 177 public static final String VERBOSE_OPTION = "verbose"; 178 public static final String VERBOSE_DELIMITER = "\t"; 179 public static final String DEBUG_OPTION = "debug"; 180 181 public static final String SCRIPTFILE_OPTION = "file"; 182 183 public static final String INFO_TIME_ZONES_OPTION = "timezones"; 184 185 public static final String BULK_OPTION = "bulk"; 186 187 public static final String AVAILABLE_SERVERS_OPTION = "servers"; 188 189 public static final String ALL_WORKFLOWS_FOR_COORD_ACTION = "allruns"; 190 191 public static final String WORKFLOW_ACTIONS_RETRIES = "retries"; 192 193 public static final String COORD_ACTION_MISSING_DEPENDENCIES = "missingdeps"; 194 195 private static final String[] OOZIE_HELP = { 196 "the env variable '" + ENV_OOZIE_URL + "' is used as default value for the '-" + OOZIE_OPTION + "' option", 197 "the env variable '" + ENV_OOZIE_TIME_ZONE + "' is used as default value for the '-" + TIME_ZONE_OPTION + "' option", 198 "the env variable '" + ENV_OOZIE_AUTH + "' is used as default value for the '-" + AUTH_OPTION + "' option", 199 "custom headers for Oozie web services can be specified using '-D" + WS_HEADER_PREFIX + "NAME=VALUE'" }; 200 201 private static final String RULER; 202 private static final int LINE_WIDTH = 132; 203 204 private static final int RETRY_COUNT = 4; 205 206 private boolean used; 207 208 private static final String INSTANCE_SEPARATOR = "#"; 209 210 private static final String MAPRED_MAPPER = "mapred.mapper.class"; 211 private static final String MAPRED_MAPPER_2 = "mapreduce.map.class"; 212 private static final String MAPRED_REDUCER = "mapred.reducer.class"; 213 private static final String MAPRED_REDUCER_2 = "mapreduce.reduce.class"; 214 private static final String MAPRED_INPUT = "mapred.input.dir"; 215 private static final String MAPRED_OUTPUT = "mapred.output.dir"; 216 217 private static final Pattern GMT_OFFSET_SHORTEN_PATTERN = Pattern.compile("(.* )GMT((?:-|\\+)\\d{2}:\\d{2})"); 218 219 static { 220 StringBuilder sb = new StringBuilder(); 221 for (int i = 0; i < LINE_WIDTH; i++) { 222 sb.append("-"); 223 } 224 RULER = sb.toString(); 225 } 226 227 /** 228 * Entry point for the Oozie CLI when invoked from the command line. 229 * <p> 230 * Upon completion this method exits the JVM with '0' (success) or '-1' (failure). 231 * 232 * @param args options and arguments for the Oozie CLI. 233 */ 234 public static void main(String[] args) { 235 if (!System.getProperties().containsKey(AuthOozieClient.USE_AUTH_TOKEN_CACHE_SYS_PROP)) { 236 System.setProperty(AuthOozieClient.USE_AUTH_TOKEN_CACHE_SYS_PROP, "true"); 237 } 238 System.exit(new OozieCLI().run(args)); 239 } 240 241 /** 242 * Create an Oozie CLI instance. 243 */ 244 public OozieCLI() { 245 used = false; 246 } 247 248 /** 249 * Return Oozie CLI top help lines. 250 * 251 * @return help lines. 252 */ 253 protected String[] getCLIHelp() { 254 return OOZIE_HELP; 255 } 256 257 /** 258 * Add authentication specific options to oozie cli 259 * 260 * @param options the collection of options to add auth options 261 */ 262 protected void addAuthOptions(Options options) { 263 Option auth = new Option(AUTH_OPTION, true, "select authentication type [SIMPLE|KERBEROS]"); 264 options.addOption(auth); 265 } 266 267 /** 268 * Create option for command line option 'admin' 269 * @return admin options 270 */ 271 protected Options createAdminOptions() { 272 Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL"); 273 Option system_mode = new Option(SYSTEM_MODE_OPTION, true, 274 "Supported in Oozie-2.0 or later versions ONLY. Change oozie system mode [NORMAL|NOWEBSERVICE|SAFEMODE]"); 275 Option status = new Option(STATUS_OPTION, false, "show the current system status"); 276 Option version = new Option(VERSION_OPTION, false, "show Oozie server build version"); 277 Option queuedump = new Option(QUEUE_DUMP_OPTION, false, "show Oozie server queue elements"); 278 Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user"); 279 Option availServers = new Option(AVAILABLE_SERVERS_OPTION, false, "list available Oozie servers" 280 + " (more than one only if HA is enabled)"); 281 Option sharelibUpdate = new Option(UPDATE_SHARELIB_OPTION, false, "Update server to use a newer version of sharelib"); 282 Option serverConfiguration = new Option(SERVER_CONFIGURATION_OPTION, false, "show Oozie system configuration"); 283 Option osEnv = new Option(SERVER_OS_ENV_OPTION, false, "show Oozie system OS environment"); 284 Option javaSysProps = new Option(SERVER_JAVA_SYSTEM_PROPERTIES_OPTION, false, "show Oozie Java system properties"); 285 Option metrics = new Option(METRICS_OPTION, false, "show Oozie system metrics"); 286 Option instrumentation = new Option(INSTRUMENTATION_OPTION, false, "show Oozie system instrumentation"); 287 288 Option sharelib = new Option(LIST_SHARELIB_LIB_OPTION, false, 289 "List available sharelib that can be specified in a workflow action"); 290 sharelib.setOptionalArg(true); 291 Option purge = new Option(PURGE_OPTION, true, "purge old oozie workflow, coordinator and bundle records from DB " + 292 "(parameter unit: day)"); 293 294 Options adminOptions = new Options(); 295 adminOptions.addOption(oozie); 296 adminOptions.addOption(doAs); 297 OptionGroup group = new OptionGroup(); 298 group.addOption(system_mode); 299 group.addOption(status); 300 group.addOption(version); 301 group.addOption(queuedump); 302 group.addOption(availServers); 303 group.addOption(sharelibUpdate); 304 group.addOption(sharelib); 305 group.addOption(serverConfiguration); 306 group.addOption(osEnv); 307 group.addOption(javaSysProps); 308 group.addOption(metrics); 309 group.addOption(instrumentation); 310 group.addOption(purge); 311 adminOptions.addOptionGroup(group); 312 addAuthOptions(adminOptions); 313 return adminOptions; 314 } 315 316 /** 317 * Create option for command line option 'job' 318 * @return job options 319 */ 320 protected Options createJobOptions() { 321 Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL"); 322 Option config = new Option(CONFIG_OPTION, true, "job configuration file '.xml' or '.properties'"); 323 Option submit = new Option(SUBMIT_OPTION, false, "submit a job"); 324 Option run = new Option(RUN_OPTION, false, "run a job"); 325 Option debug = new Option(DEBUG_OPTION, false, "Use debug mode to see debugging statements on stdout"); 326 Option rerun = new Option(RERUN_OPTION, true, 327 "rerun a job (coordinator requires -action or -date, bundle requires -coordinator or -date)"); 328 Option dryrun = new Option(DRYRUN_OPTION, false, "Dryrun a workflow (since 3.3.2), a coordinator (since 2.0) " 329 + " or a bundle (since 5.1) job without actually executing it"); 330 Option update = new Option(UPDATE_OPTION, true, "Update coord definition and properties"); 331 Option showdiff = new Option(SHOWDIFF_OPTION, true, 332 "Show diff of the new coord definition and properties with the existing one (default true)"); 333 Option start = new Option(START_OPTION, true, "start a job"); 334 Option suspend = new Option(SUSPEND_OPTION, true, "suspend a job"); 335 Option resume = new Option(RESUME_OPTION, true, "resume a job"); 336 Option kill = new Option(KILL_OPTION, true, "kill a job (coordinator can mention -action or -date)"); 337 Option change = new Option(CHANGE_OPTION, true, "change a coordinator or bundle job"); 338 Option changeValue = new Option(CHANGE_VALUE_OPTION, true, 339 "new endtime/concurrency/pausetime value for changing a coordinator job"); 340 Option info = new Option(INFO_OPTION, true, "info of a job"); 341 Option poll = new Option(POLL_OPTION, true, "poll Oozie until a job reaches a terminal state or a timeout occurs"); 342 Option offset = new Option(OFFSET_OPTION, true, "job info offset of actions (default '1', requires -info)"); 343 Option len = new Option(LEN_OPTION, true, "number of actions (default TOTAL ACTIONS, requires -info)"); 344 Option filter = new Option(FILTER_OPTION, true, 345 "<key><comparator><value>[;<key><comparator><value>]*\n" 346 + "(All Coordinator actions satisfying the filters will be retrieved).\n" 347 + "key: status or nominaltime\n" 348 + "comparator: =, !=, <, <=, >, >=. = is used as OR and others as AND\n" 349 + "status: values are valid status like SUCCEEDED, KILLED etc. Only = and != apply for status\n" 350 + "nominaltime: time of format yyyy-MM-dd'T'HH:mm'Z'"); 351 Option order = new Option(ORDER_OPTION, true, 352 "order to show coord actions (default ascending order, 'desc' for descending order, requires -info)"); 353 Option localtime = new Option(LOCAL_TIME_OPTION, false, "use local time (same as passing your time zone to -" + 354 TIME_ZONE_OPTION + "). Overrides -" + TIME_ZONE_OPTION + " option"); 355 Option timezone = new Option(TIME_ZONE_OPTION, true, 356 "use time zone with the specified ID (default GMT).\nSee 'oozie info -timezones' for a list"); 357 Option log = new Option(LOG_OPTION, true, "job log"); 358 Option errorlog = new Option(ERROR_LOG_OPTION, true, "job error log"); 359 Option auditlog = new Option(AUDIT_LOG_OPTION, true, "job audit log"); 360 final Option generateAndCheck = new Option(VALIDATE_JAR_OPTION, true, "generate and check job definition"); 361 final Option generateAndSubmit = new Option(SUBMIT_JAR_OPTION, true, "generate and submit job definition"); 362 final Option generateAndRun = new Option(RUN_JAR_OPTION, true, "generate and run job definition"); 363 Option logFilter = new Option( 364 RestConstants.LOG_FILTER_OPTION, true, 365 "job log search parameter. Can be specified as -logfilter opt1=val1;opt2=val1;opt3=val1. " 366 + "Supported options are recent, start, end, loglevel, text, limit and debug"); 367 Option definition = new Option(DEFINITION_OPTION, true, "job definition"); 368 Option config_content = new Option(CONFIG_CONTENT_OPTION, true, "job configuration"); 369 Option verbose = new Option(VERBOSE_OPTION, false, "verbose mode"); 370 Option action = new Option(ACTION_OPTION, true, 371 "coordinator rerun/kill on action ids (requires -rerun/-kill); coordinator log retrieval on action ids" 372 + "(requires -log)"); 373 Option date = new Option(DATE_OPTION, true, 374 "coordinator/bundle rerun on action dates (requires -rerun); " 375 + "coordinator log retrieval on action dates (requires -log)"); 376 Option rerun_coord = new Option(COORD_OPTION, true, "bundle rerun on coordinator names (requires -rerun)"); 377 Option rerun_refresh = new Option(RERUN_REFRESH_OPTION, false, 378 "re-materialize the coordinator rerun actions (requires -rerun)"); 379 Option rerun_nocleanup = new Option(RERUN_NOCLEANUP_OPTION, false, 380 "do not clean up output-events of the coordinator rerun actions (requires -rerun)"); 381 Option rerun_failed = new Option(RERUN_FAILED_OPTION, false, 382 "runs the failed workflow actions of the coordinator actions (requires -rerun)"); 383 Option property = OptionBuilder.withArgName("property=value").hasArgs(2).withValueSeparator().withDescription( 384 "set/override value for given property").create("D"); 385 Option getAllWorkflows = new Option(ALL_WORKFLOWS_FOR_COORD_ACTION, false, 386 "Get workflow jobs corresponding to a coordinator action including all the reruns"); 387 Option ignore = new Option(IGNORE_OPTION, true, 388 "change status of a coordinator job or action to IGNORED" 389 + " (-action required to ignore coord actions)"); 390 Option timeout = new Option(TIMEOUT_OPTION, true, "timeout in minutes (default is 30, negative values indicate no " 391 + "timeout, requires -poll)"); 392 timeout.setType(Integer.class); 393 Option interval = new Option(INTERVAL_OPTION, true, "polling interval in minutes (default is 5, requires -poll)"); 394 interval.setType(Integer.class); 395 396 Option slaDisableAlert = new Option(SLA_DISABLE_ALERT, true, 397 "disables sla alerts for the job and its children"); 398 Option slaEnableAlert = new Option(SLA_ENABLE_ALERT, true, 399 "enables sla alerts for the job and its children"); 400 Option slaChange = new Option(SLA_CHANGE, true, 401 "Update sla param for jobs, supported param are should-start, should-end, nominal-time and max-duration"); 402 Option coordActionMissingDependencies = new Option(COORD_ACTION_MISSING_DEPENDENCIES, true, 403 "List missing dependencies of a coord action. To specify multiple actions, use with -action or -date option."); 404 405 406 Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user"); 407 408 Option workflowActionRetries = new Option(WORKFLOW_ACTIONS_RETRIES, true, 409 "Get information of the retry attempts for a given workflow action"); 410 411 OptionGroup actions = new OptionGroup(); 412 actions.addOption(submit); 413 actions.addOption(start); 414 actions.addOption(run); 415 actions.addOption(dryrun); 416 actions.addOption(suspend); 417 actions.addOption(resume); 418 actions.addOption(kill); 419 actions.addOption(change); 420 actions.addOption(update); 421 actions.addOption(info); 422 actions.addOption(rerun); 423 actions.addOption(log); 424 actions.addOption(errorlog); 425 actions.addOption(auditlog); 426 actions.addOption(generateAndCheck); 427 actions.addOption(generateAndSubmit); 428 actions.addOption(generateAndRun); 429 actions.addOption(definition); 430 actions.addOption(config_content); 431 actions.addOption(ignore); 432 actions.addOption(poll); 433 actions.addOption(slaDisableAlert); 434 actions.addOption(slaEnableAlert); 435 actions.addOption(slaChange); 436 actions.addOption(workflowActionRetries); 437 actions.addOption(coordActionMissingDependencies); 438 actions.setRequired(true); 439 Options jobOptions = new Options(); 440 jobOptions.addOption(oozie); 441 jobOptions.addOption(doAs); 442 jobOptions.addOption(config); 443 jobOptions.addOption(property); 444 jobOptions.addOption(changeValue); 445 jobOptions.addOption(localtime); 446 jobOptions.addOption(timezone); 447 jobOptions.addOption(verbose); 448 jobOptions.addOption(debug); 449 jobOptions.addOption(offset); 450 jobOptions.addOption(len); 451 jobOptions.addOption(filter); 452 jobOptions.addOption(order); 453 jobOptions.addOption(action); 454 jobOptions.addOption(date); 455 jobOptions.addOption(rerun_coord); 456 jobOptions.addOption(rerun_refresh); 457 jobOptions.addOption(rerun_nocleanup); 458 jobOptions.addOption(rerun_failed); 459 jobOptions.addOption(getAllWorkflows); 460 jobOptions.addOptionGroup(actions); 461 jobOptions.addOption(logFilter); 462 jobOptions.addOption(timeout); 463 jobOptions.addOption(interval); 464 addAuthOptions(jobOptions); 465 jobOptions.addOption(showdiff); 466 467 //Needed to make dryrun and update mutually exclusive options 468 OptionGroup updateOption = new OptionGroup(); 469 updateOption.addOption(dryrun); 470 jobOptions.addOptionGroup(updateOption); 471 472 return jobOptions; 473 } 474 475 /** 476 * Create option for command line option 'jobs' 477 * @return jobs options 478 */ 479 protected Options createJobsOptions() { 480 Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL"); 481 Option start = new Option(OFFSET_OPTION, true, "jobs offset (default '1')"); 482 Option jobtype = new Option(JOBTYPE_OPTION, true, 483 "job type ('Supported in Oozie-2.0 or later versions ONLY - 'coordinator' or 'bundle' or 'wf'(default))"); 484 Option len = new Option(LEN_OPTION, true, "number of jobs (default '100')"); 485 Option filter = new Option(FILTER_OPTION, true, 486 "text=<*>\\;user=<U>\\;name=<N>\\;group=<G>\\;status=<S>\\;frequency=<F>\\;unit=<M>" + 487 "\\;startcreatedtime=<SC>\\;endcreatedtime=<EC> \\;sortBy=<SB>\n" + 488 "(text filter: matches partially with name and user or complete match with job ID. " + 489 "Valid unit values are 'months', 'days', 'hours' or 'minutes'. " + 490 "startcreatedtime, endcreatedtime: time of format yyyy-MM-dd'T'HH:mm'Z'. " + 491 "Valid values for sortBy are 'createdTime' or 'lastModifiedTime'.)"); 492 Option localtime = new Option(LOCAL_TIME_OPTION, false, "use local time (same as passing your time zone to -" + 493 TIME_ZONE_OPTION + "). Overrides -" + TIME_ZONE_OPTION + " option"); 494 Option kill = new Option(KILL_OPTION, false, "bulk kill operation"); 495 Option suspend = new Option(SUSPEND_OPTION, false, "bulk suspend operation"); 496 Option resume = new Option(RESUME_OPTION, false, "bulk resume operation"); 497 Option timezone = new Option(TIME_ZONE_OPTION, true, 498 "use time zone with the specified ID (default GMT).\nSee 'oozie info -timezones' for a list"); 499 Option verbose = new Option(VERBOSE_OPTION, false, "verbose mode"); 500 Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user"); 501 Option bulkMonitor = new Option(BULK_OPTION, true, "key-value pairs to filter bulk jobs response. e.g. bundle=<B>\\;" + 502 "coordinators=<C>\\;actionstatus=<S>\\;startcreatedtime=<SC>\\;endcreatedtime=<EC>\\;" + 503 "startscheduledtime=<SS>\\;endscheduledtime=<ES>\\; bundle, " + 504 "coordinators and actionstatus can be multiple comma separated values. " + 505 "Bundle and coordinators can be id(s) or appName(s) of those jobs. " + 506 "Specifying bundle is mandatory, other params are optional"); 507 start.setType(Integer.class); 508 len.setType(Integer.class); 509 Options jobsOptions = new Options(); 510 jobsOptions.addOption(oozie); 511 jobsOptions.addOption(doAs); 512 jobsOptions.addOption(localtime); 513 jobsOptions.addOption(kill); 514 jobsOptions.addOption(suspend); 515 jobsOptions.addOption(resume); 516 jobsOptions.addOption(timezone); 517 jobsOptions.addOption(start); 518 jobsOptions.addOption(len); 519 jobsOptions.addOption(oozie); 520 jobsOptions.addOption(filter); 521 jobsOptions.addOption(jobtype); 522 jobsOptions.addOption(verbose); 523 jobsOptions.addOption(bulkMonitor); 524 addAuthOptions(jobsOptions); 525 return jobsOptions; 526 } 527 528 /** 529 * Create option for command line option 'sla' 530 * 531 * @return sla options 532 */ 533 protected Options createSlaOptions() { 534 Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL"); 535 Option start = new Option(OFFSET_OPTION, true, "start offset (default '0')"); 536 Option len = new Option(LEN_OPTION, true, "number of results (default '100', max '1000')"); 537 Option filter = new Option(FILTER_OPTION, true, "filter of SLA events. e.g., jobid=<J>\\;appname=<A>"); 538 start.setType(Integer.class); 539 len.setType(Integer.class); 540 Options slaOptions = new Options(); 541 slaOptions.addOption(start); 542 slaOptions.addOption(len); 543 slaOptions.addOption(filter); 544 slaOptions.addOption(oozie); 545 addAuthOptions(slaOptions); 546 return slaOptions; 547 } 548 549 /** 550 * Create option for command line option 'validate' 551 * 552 * @return validate options 553 */ 554 protected Options createValidateOptions() { 555 Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL"); 556 Options validateOption = new Options(); 557 validateOption.addOption(oozie); 558 addAuthOptions(validateOption); 559 return validateOption; 560 } 561 562 /** 563 * Create option for command line option 'pig' or 'hive' 564 * @param jobType type of job - pig or hive 565 * @return pig or hive options 566 */ 567 @SuppressWarnings("static-access") 568 protected Options createScriptLanguageOptions(String jobType) { 569 Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL"); 570 Option config = new Option(CONFIG_OPTION, true, "job configuration file '.properties'"); 571 Option file = new Option(SCRIPTFILE_OPTION, true, jobType + " script"); 572 Option property = OptionBuilder.withArgName("property=value").hasArgs(2).withValueSeparator().withDescription( 573 "set/override value for given property").create("D"); 574 Option params = OptionBuilder.withArgName("property=value").hasArgs(2).withValueSeparator().withDescription( 575 "set parameters for script").create("P"); 576 Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user"); 577 Options Options = new Options(); 578 Options.addOption(oozie); 579 Options.addOption(doAs); 580 Options.addOption(config); 581 Options.addOption(property); 582 Options.addOption(params); 583 Options.addOption(file); 584 addAuthOptions(Options); 585 return Options; 586 } 587 588 /** 589 * Create option for command line option 'sqoop' 590 * @return sqoop options 591 */ 592 @SuppressWarnings("static-access") 593 protected Options createSqoopCLIOptions() { 594 Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL"); 595 Option config = new Option(CONFIG_OPTION, true, "job configuration file '.properties'"); 596 Option command = OptionBuilder.withArgName(SQOOP_COMMAND_OPTION).hasArgs().withValueSeparator().withDescription( 597 "sqoop command").create(SQOOP_COMMAND_OPTION); 598 Option property = OptionBuilder.withArgName("property=value").hasArgs(2).withValueSeparator().withDescription( 599 "set/override value for given property").create("D"); 600 Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user"); 601 Options Options = new Options(); 602 Options.addOption(oozie); 603 Options.addOption(doAs); 604 Options.addOption(config); 605 Options.addOption(property); 606 Options.addOption(command); 607 addAuthOptions(Options); 608 return Options; 609 } 610 611 /** 612 * Create option for command line option 'info' 613 * @return info options 614 */ 615 protected Options createInfoOptions() { 616 Option timezones = new Option(INFO_TIME_ZONES_OPTION, false, "display a list of available time zones"); 617 Options infoOptions = new Options(); 618 infoOptions.addOption(timezones); 619 return infoOptions; 620 } 621 622 /** 623 * Create option for command line option 'mapreduce' 624 * @return mapreduce options 625 */ 626 @SuppressWarnings("static-access") 627 protected Options createMROptions() { 628 Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL"); 629 Option config = new Option(CONFIG_OPTION, true, "job configuration file '.properties'"); 630 Option property = OptionBuilder.withArgName("property=value").hasArgs(2).withValueSeparator().withDescription( 631 "set/override value for given property").create("D"); 632 Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user"); 633 Options mrOptions = new Options(); 634 mrOptions.addOption(oozie); 635 mrOptions.addOption(doAs); 636 mrOptions.addOption(config); 637 mrOptions.addOption(property); 638 addAuthOptions(mrOptions); 639 return mrOptions; 640 } 641 642 /** 643 * Run a CLI programmatically. 644 * <p> 645 * It does not exit the JVM. 646 * <p> 647 * A CLI instance can be used only once. 648 * 649 * @param args options and arguments for the Oozie CLI. 650 * @return '0' (success), '-1' (failure). 651 */ 652 public synchronized int run(String[] args) { 653 if (used) { 654 throw new IllegalStateException("CLI instance already used"); 655 } 656 used = true; 657 final CLIParser parser = getCLIParser(); 658 try { 659 final CLIParser.Command command = parser.parse(args); 660 661 String doAsUser = command.getCommandLine().getOptionValue(DO_AS_OPTION); 662 663 if (doAsUser != null) { 664 OozieClient.doAs(doAsUser, new Callable<Void>() { 665 @Override 666 public Void call() throws Exception { 667 processCommand(parser, command); 668 return null; 669 } 670 }); 671 } 672 else { 673 processCommand(parser, command); 674 } 675 return 0; 676 } 677 catch (OozieCLIException ex) { 678 System.err.println("Error: " + ex.getMessage()); 679 return -1; 680 } 681 catch (ParseException ex) { 682 System.err.println("Invalid sub-command: " + ex.getMessage()); 683 System.err.println(); 684 System.err.println(parser.shortHelp()); 685 return -1; 686 } 687 catch (Exception ex) { 688 ex.printStackTrace(); 689 System.err.println(ex.getMessage()); 690 return -1; 691 } 692 } 693 694 @VisibleForTesting 695 public CLIParser getCLIParser(){ 696 CLIParser parser = new CLIParser(OOZIE_OPTION, getCLIHelp()); 697 parser.addCommand(HELP_CMD, "", "display usage for all commands or specified command", new Options(), false); 698 parser.addCommand(VERSION_CMD, "", "show client version", new Options(), false); 699 parser.addCommand(JOB_CMD, "", "job operations", createJobOptions(), false); 700 parser.addCommand(JOBS_CMD, "", "jobs status", createJobsOptions(), false); 701 parser.addCommand(ADMIN_CMD, "", "admin operations", createAdminOptions(), false); 702 parser.addCommand(VALIDATE_CMD, "", "validate a workflow, coordinator, bundle XML file", createValidateOptions(), true); 703 parser.addCommand(SLA_CMD, "", "sla operations (Deprecated with Oozie 4.0)", createSlaOptions(), false); 704 parser.addCommand(PIG_CMD, "-X ", "submit a pig job, everything after '-X' are pass-through parameters to pig, any '-D' " 705 + "arguments after '-X' are put in <configuration>", createScriptLanguageOptions(PIG_CMD), true); 706 parser.addCommand(HIVE_CMD, "-X ", "submit a hive job, everything after '-X' are pass-through parameters to hive, any '-D' " 707 + "arguments after '-X' are put in <configuration>", createScriptLanguageOptions(HIVE_CMD), true); 708 parser.addCommand(SQOOP_CMD, "-X ", "submit a sqoop job, everything after '-X' are pass-through parameters " + 709 "to sqoop, any '-D' arguments after '-X' are put in <configuration>", createSqoopCLIOptions(), true); 710 parser.addCommand(INFO_CMD, "", "get more detailed info about specific topics", createInfoOptions(), false); 711 parser.addCommand(MR_CMD, "", "submit a mapreduce job", createMROptions(), false); 712 return parser; 713 } 714 715 public void processCommand(CLIParser parser, CLIParser.Command command) throws Exception { 716 switch (command.getName()) { 717 case JOB_CMD: 718 jobCommand(command.getCommandLine()); 719 break; 720 case JOBS_CMD: 721 jobsCommand(command.getCommandLine()); 722 break; 723 case ADMIN_CMD: 724 adminCommand(command.getCommandLine()); 725 break; 726 case VERSION_CMD: 727 versionCommand(); 728 break; 729 case VALIDATE_CMD: 730 validateCommand(command.getCommandLine()); 731 break; 732 case SLA_CMD: 733 slaCommand(command.getCommandLine()); 734 break; 735 case PIG_CMD: 736 scriptLanguageCommand(command.getCommandLine(), PIG_CMD); 737 break; 738 case HIVE_CMD: 739 scriptLanguageCommand(command.getCommandLine(), HIVE_CMD); 740 break; 741 case SQOOP_CMD: 742 sqoopCommand(command.getCommandLine()); 743 break; 744 case INFO_CMD: 745 infoCommand(command.getCommandLine()); 746 break; 747 case MR_CMD: 748 mrCommand(command.getCommandLine()); 749 break; 750 default: 751 parser.showHelp(command.getCommandLine()); 752 } 753 } 754 protected String getOozieUrl(CommandLine commandLine) { 755 String url = commandLine.getOptionValue(OOZIE_OPTION); 756 if (url == null) { 757 url = System.getenv(ENV_OOZIE_URL); 758 if (url == null) { 759 throw new IllegalArgumentException( 760 "Oozie URL is not available neither in command option or in the environment"); 761 } 762 } 763 return url; 764 } 765 766 private String getTimeZoneId(CommandLine commandLine) 767 { 768 if (commandLine.hasOption(LOCAL_TIME_OPTION)) { 769 return null; 770 } 771 if (commandLine.hasOption(TIME_ZONE_OPTION)) { 772 return commandLine.getOptionValue(TIME_ZONE_OPTION); 773 } 774 String timeZoneId = System.getenv(ENV_OOZIE_TIME_ZONE); 775 if (timeZoneId != null) { 776 return timeZoneId; 777 } 778 return "GMT"; 779 } 780 781 // Canibalized from Hadoop <code>Configuration.loadResource()</code>. 782 private Properties parse(InputStream is, Properties conf) throws IOException { 783 try { 784 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); 785 docBuilderFactory.setNamespaceAware(true); 786 // support for includes in the xml file 787 docBuilderFactory.setXIncludeAware(true); 788 // ignore all comments inside the xml file 789 docBuilderFactory.setIgnoringComments(true); 790 docBuilderFactory.setExpandEntityReferences(false); 791 docBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); 792 DocumentBuilder builder = docBuilderFactory.newDocumentBuilder(); 793 Document doc = builder.parse(is); 794 return parseDocument(doc, conf); 795 } 796 catch (SAXException | ParserConfigurationException e) { 797 throw new IOException(e); 798 } 799 } 800 801 // Canibalized from Hadoop <code>Configuration.loadResource()</code>. 802 private Properties parseDocument(Document doc, Properties conf) throws IOException { 803 try { 804 Element root = doc.getDocumentElement(); 805 if (!"configuration".equals(root.getLocalName())) { 806 throw new RuntimeException("bad conf file: top-level element not <configuration>"); 807 } 808 NodeList props = root.getChildNodes(); 809 for (int i = 0; i < props.getLength(); i++) { 810 Node propNode = props.item(i); 811 if (!(propNode instanceof Element)) { 812 continue; 813 } 814 Element prop = (Element) propNode; 815 if (!"property".equals(prop.getLocalName())) { 816 throw new RuntimeException("bad conf file: element not <property>"); 817 } 818 NodeList fields = prop.getChildNodes(); 819 String attr = null; 820 String value = null; 821 for (int j = 0; j < fields.getLength(); j++) { 822 Node fieldNode = fields.item(j); 823 if (!(fieldNode instanceof Element)) { 824 continue; 825 } 826 Element field = (Element) fieldNode; 827 if ("name".equals(field.getLocalName()) && field.hasChildNodes()) { 828 attr = ((Text) field.getFirstChild()).getData(); 829 } 830 if ("value".equals(field.getLocalName()) && field.hasChildNodes()) { 831 value = ((Text) field.getFirstChild()).getData(); 832 } 833 } 834 835 if (attr != null && value != null) { 836 conf.setProperty(attr, value); 837 } 838 } 839 return conf; 840 } 841 catch (DOMException e) { 842 throw new IOException(e); 843 } 844 } 845 846 private Properties getConfiguration(OozieClient wc, CommandLine commandLine) throws IOException { 847 if (!isConfigurationSpecified(wc, commandLine)) { 848 throw new IOException("configuration is not specified"); 849 } 850 Properties conf = wc.createConfiguration(); 851 String configFile = commandLine.getOptionValue(CONFIG_OPTION); 852 if (configFile != null) { 853 File file = new File(configFile); 854 if (!file.exists()) { 855 throw new IOException("configuration file [" + configFile + "] not found"); 856 } 857 if (configFile.endsWith(".properties")) { 858 conf.load(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)); 859 } 860 else if (configFile.endsWith(".xml")) { 861 parse(new FileInputStream(configFile), conf); 862 } 863 else { 864 throw new IllegalArgumentException("configuration must be a '.properties' or a '.xml' file"); 865 } 866 } 867 if (commandLine.hasOption("D")) { 868 Properties commandLineProperties = commandLine.getOptionProperties("D"); 869 conf.putAll(commandLineProperties); 870 } 871 return conf; 872 } 873 874 /** 875 * Check if configuration has specified 876 * @param wc 877 * @param commandLine 878 * @return isConf 879 * @throws IOException 880 */ 881 private boolean isConfigurationSpecified(OozieClient wc, CommandLine commandLine) throws IOException { 882 boolean isConf; 883 String configFile = commandLine.getOptionValue(CONFIG_OPTION); 884 if (configFile == null) { 885 isConf = false; 886 } 887 else { 888 isConf = new File(configFile).exists(); 889 } 890 if (commandLine.hasOption("D")) { 891 isConf = true; 892 } 893 return isConf; 894 } 895 896 /** 897 * @param commandLine command line string. 898 * @return change value specified by -value. 899 * @throws OozieCLIException 900 */ 901 private String getChangeValue(CommandLine commandLine) throws OozieCLIException { 902 String changeValue = commandLine.getOptionValue(CHANGE_VALUE_OPTION); 903 904 if (changeValue == null) { 905 throw new OozieCLIException("-value option needs to be specified for -change option"); 906 } 907 908 return changeValue; 909 } 910 911 protected void addHeader(OozieClient wc) { 912 for (Map.Entry entry : System.getProperties().entrySet()) { 913 String key = (String) entry.getKey(); 914 if (key.startsWith(WS_HEADER_PREFIX)) { 915 String header = key.substring(WS_HEADER_PREFIX.length()); 916 wc.setHeader(header, (String) entry.getValue()); 917 } 918 } 919 } 920 921 /** 922 * Get auth option from command line 923 * 924 * @param commandLine the command line object 925 * @return auth option 926 */ 927 protected String getAuthOption(CommandLine commandLine) { 928 String authOpt = commandLine.getOptionValue(AUTH_OPTION); 929 if (authOpt == null) { 930 authOpt = System.getenv(ENV_OOZIE_AUTH); 931 } 932 if (commandLine.hasOption(DEBUG_OPTION)) { 933 System.out.println(" Auth type : " + authOpt); 934 } 935 return authOpt; 936 } 937 938 /** 939 * Create a OozieClient. 940 * <p> 941 * It injects any '-Dheader:' as header to the the {@link org.apache.oozie.client.OozieClient}. 942 * 943 * @param commandLine the parsed command line options. 944 * @return a pre configured eXtended workflow client. 945 * @throws OozieCLIException thrown if the OozieClient could not be configured. 946 */ 947 protected OozieClient createOozieClient(CommandLine commandLine) throws OozieCLIException { 948 return createXOozieClient(commandLine); 949 } 950 951 /** 952 * Create a XOozieClient. 953 * <p> 954 * It injects any '-Dheader:' as header to the the {@link org.apache.oozie.client.OozieClient}. 955 * 956 * @param commandLine the parsed command line options. 957 * @return a pre configured eXtended workflow client. 958 * @throws OozieCLIException thrown if the XOozieClient could not be configured. 959 */ 960 protected XOozieClient createXOozieClient(CommandLine commandLine) throws OozieCLIException { 961 XOozieClient wc = new AuthOozieClient(getOozieUrl(commandLine), getAuthOption(commandLine)); 962 addHeader(wc); 963 setDebugMode(wc,commandLine.hasOption(DEBUG_OPTION)); 964 setRetryCount(wc); 965 return wc; 966 } 967 968 protected void setDebugMode(OozieClient wc, boolean debugOpt) { 969 970 String debug = System.getenv(ENV_OOZIE_DEBUG); 971 if (debug != null && !debug.isEmpty()) { 972 int debugVal = 0; 973 try { 974 debugVal = Integer.parseInt(debug.trim()); 975 } 976 catch (Exception ex) { 977 System.out.println("Unable to parse the debug settings. May be not an integer [" + debug + "]"); 978 ex.printStackTrace(); 979 } 980 wc.setDebugMode(debugVal); 981 } 982 else if(debugOpt){ // CLI argument "-debug" used 983 wc.setDebugMode(1); 984 } 985 } 986 987 protected void setRetryCount(OozieClient wc) { 988 String retryCount = System.getProperty(OOZIE_RETRY_COUNT); 989 if (retryCount != null && !retryCount.isEmpty()) { 990 try { 991 int retry = Integer.parseInt(retryCount.trim()); 992 wc.setRetryCount(retry); 993 } 994 catch (Exception ex) { 995 System.err.println("Unable to parse the retry settings. May be not an integer [" + retryCount + "]"); 996 ex.printStackTrace(); 997 } 998 } 999 } 1000 1001 private static String JOB_ID_PREFIX = "job: "; 1002 1003 private void jobCommand(CommandLine commandLine) throws IOException, OozieCLIException { 1004 XOozieClient wc = createXOozieClient(commandLine); 1005 1006 List<String> options = new ArrayList<>(); 1007 for (Option option : commandLine.getOptions()) { 1008 options.add(option.getOpt()); 1009 } 1010 1011 try { 1012 if (options.contains(SUBMIT_OPTION)) { 1013 System.out.println(JOB_ID_PREFIX + wc.submit(getConfiguration(wc, commandLine))); 1014 } 1015 else if (options.contains(START_OPTION)) { 1016 wc.start(commandLine.getOptionValue(START_OPTION)); 1017 } 1018 else if (options.contains(DRYRUN_OPTION) && !options.contains(UPDATE_OPTION)) { 1019 String dryrunStr = wc.dryrun(getConfiguration(wc, commandLine)); 1020 if (dryrunStr.equals("OK")) { // workflow 1021 System.out.println("OK"); 1022 } 1023 else if (dryrunStr.contains("<bundle-app")) { 1024 // bundle 1025 System.out.println("***Bundle job after parsing: ***"); 1026 System.out.println(dryrunStr); 1027 } 1028 else { 1029 // coordinator 1030 String[] dryrunStrs = dryrunStr.split("action for new instance"); 1031 int arraysize = dryrunStrs.length; 1032 System.out.println("***coordJob after parsing: ***"); 1033 System.out.println(dryrunStrs[0]); 1034 int aLen = dryrunStrs.length - 1; 1035 if (aLen < 0) { 1036 aLen = 0; 1037 } 1038 System.out.println("***total coord actions is " + aLen + " ***"); 1039 for (int i = 1; i <= arraysize - 1; i++) { 1040 System.out.println(RULER); 1041 System.out.println("coordAction instance: " + i + ":"); 1042 System.out.println(dryrunStrs[i]); 1043 } 1044 } 1045 } 1046 else if (options.contains(SUSPEND_OPTION)) { 1047 wc.suspend(commandLine.getOptionValue(SUSPEND_OPTION)); 1048 } 1049 else if (options.contains(RESUME_OPTION)) { 1050 wc.resume(commandLine.getOptionValue(RESUME_OPTION)); 1051 } 1052 else if (options.contains(IGNORE_OPTION)) { 1053 String ignoreScope = null; 1054 if (options.contains(ACTION_OPTION)) { 1055 ignoreScope = commandLine.getOptionValue(ACTION_OPTION); 1056 if (ignoreScope == null || ignoreScope.isEmpty()) { 1057 throw new OozieCLIException("-" + ACTION_OPTION + " is empty"); 1058 } 1059 } 1060 printCoordActionsStatus(wc.ignore(commandLine.getOptionValue(IGNORE_OPTION), ignoreScope)); 1061 } 1062 else if (options.contains(KILL_OPTION)) { 1063 if (commandLine.getOptionValue(KILL_OPTION).contains("-C") 1064 && (options.contains(DATE_OPTION) || options.contains(ACTION_OPTION))) { 1065 String coordJobId = commandLine.getOptionValue(KILL_OPTION); 1066 String scope; 1067 String rangeType; 1068 if (options.contains(DATE_OPTION) && options.contains(ACTION_OPTION)) { 1069 throw new OozieCLIException("Invalid options provided for rerun: either" + DATE_OPTION + " or " 1070 + ACTION_OPTION + " expected. Don't use both at the same time."); 1071 } 1072 if (options.contains(DATE_OPTION)) { 1073 rangeType = RestConstants.JOB_COORD_SCOPE_DATE; 1074 scope = commandLine.getOptionValue(DATE_OPTION); 1075 } 1076 else if (options.contains(ACTION_OPTION)) { 1077 rangeType = RestConstants.JOB_COORD_SCOPE_ACTION; 1078 scope = commandLine.getOptionValue(ACTION_OPTION); 1079 } 1080 else { 1081 throw new OozieCLIException("Invalid options provided for rerun: " + DATE_OPTION + " or " 1082 + ACTION_OPTION + " expected."); 1083 } 1084 printCoordActions(wc.kill(coordJobId, rangeType, scope)); 1085 } 1086 else { 1087 wc.kill(commandLine.getOptionValue(KILL_OPTION)); 1088 } 1089 } 1090 else if (options.contains(CHANGE_OPTION)) { 1091 wc.change(commandLine.getOptionValue(CHANGE_OPTION), getChangeValue(commandLine)); 1092 } 1093 else if (options.contains(RUN_OPTION)) { 1094 System.out.println(JOB_ID_PREFIX + wc.run(getConfiguration(wc, commandLine))); 1095 } 1096 else if (options.contains(RERUN_OPTION)) { 1097 if (commandLine.getOptionValue(RERUN_OPTION).contains("-W")) { 1098 if (isConfigurationSpecified(wc, commandLine)) { 1099 wc.reRun(commandLine.getOptionValue(RERUN_OPTION), getConfiguration(wc, commandLine)); 1100 } 1101 else { 1102 wc.reRun(commandLine.getOptionValue(RERUN_OPTION), new Properties()); 1103 } 1104 } 1105 else if (commandLine.getOptionValue(RERUN_OPTION).contains("-B")) { 1106 String bundleJobId = commandLine.getOptionValue(RERUN_OPTION); 1107 String coordScope = null; 1108 String dateScope = null; 1109 boolean refresh = false; 1110 boolean noCleanup = false; 1111 if (options.contains(ACTION_OPTION)) { 1112 throw new OozieCLIException("Invalid options provided for bundle rerun. " + ACTION_OPTION 1113 + " is not valid for bundle rerun"); 1114 } 1115 if (options.contains(DATE_OPTION)) { 1116 dateScope = commandLine.getOptionValue(DATE_OPTION); 1117 } 1118 1119 if (options.contains(COORD_OPTION)) { 1120 coordScope = commandLine.getOptionValue(COORD_OPTION); 1121 } 1122 1123 if (options.contains(RERUN_REFRESH_OPTION)) { 1124 refresh = true; 1125 } 1126 if (options.contains(RERUN_NOCLEANUP_OPTION)) { 1127 noCleanup = true; 1128 } 1129 wc.reRunBundle(bundleJobId, coordScope, dateScope, refresh, noCleanup); 1130 if (coordScope != null && !coordScope.isEmpty()) { 1131 System.out.println("Coordinators [" + coordScope + "] of bundle " + bundleJobId 1132 + " are scheduled to rerun on date ranges [" + dateScope + "]."); 1133 } 1134 else { 1135 System.out.println("All coordinators of bundle " + bundleJobId 1136 + " are scheduled to rerun on the date ranges [" + dateScope + "]."); 1137 } 1138 } 1139 else { 1140 String coordJobId = commandLine.getOptionValue(RERUN_OPTION); 1141 String scope; 1142 String rerunType; 1143 boolean refresh = false; 1144 boolean noCleanup = false; 1145 boolean failed = false; 1146 if (options.contains(DATE_OPTION) && options.contains(ACTION_OPTION)) { 1147 throw new OozieCLIException("Invalid options provided for rerun: either" + DATE_OPTION + " or " 1148 + ACTION_OPTION + " expected. Don't use both at the same time."); 1149 } 1150 if (options.contains(DATE_OPTION)) { 1151 rerunType = RestConstants.JOB_COORD_SCOPE_DATE; 1152 scope = commandLine.getOptionValue(DATE_OPTION); 1153 } 1154 else if (options.contains(ACTION_OPTION)) { 1155 rerunType = RestConstants.JOB_COORD_SCOPE_ACTION; 1156 scope = commandLine.getOptionValue(ACTION_OPTION); 1157 } 1158 else { 1159 throw new OozieCLIException("Invalid options provided for rerun: " + DATE_OPTION + " or " 1160 + ACTION_OPTION + " expected."); 1161 } 1162 if (options.contains(RERUN_REFRESH_OPTION)) { 1163 refresh = true; 1164 } 1165 if (options.contains(RERUN_NOCLEANUP_OPTION)) { 1166 noCleanup = true; 1167 } 1168 1169 Properties props = null; 1170 if(isConfigurationSpecified(wc, commandLine)) { 1171 props = getConfiguration(wc, commandLine); 1172 } 1173 1174 if (options.contains(RERUN_FAILED_OPTION)) { 1175 failed = true; 1176 } 1177 1178 printCoordActions(wc.reRunCoord(coordJobId, rerunType, scope, refresh, noCleanup, failed, props)); 1179 } 1180 } 1181 else if (options.contains(INFO_OPTION)) { 1182 String timeZoneId = getTimeZoneId(commandLine); 1183 final String optionValue = commandLine.getOptionValue(INFO_OPTION); 1184 if (optionValue.endsWith("-B")) { 1185 String filter = commandLine.getOptionValue(FILTER_OPTION); 1186 if (filter != null) { 1187 throw new OozieCLIException("Filter option is currently not supported for a Bundle job"); 1188 } 1189 printBundleJob(wc.getBundleJobInfo(optionValue), timeZoneId, 1190 options.contains(VERBOSE_OPTION)); 1191 } 1192 else if (optionValue.endsWith("-C")) { 1193 String s = commandLine.getOptionValue(OFFSET_OPTION); 1194 int start = Integer.parseInt((s != null) ? s : "-1"); 1195 s = commandLine.getOptionValue(LEN_OPTION); 1196 int len = Integer.parseInt((s != null) ? s : "-1"); 1197 String filter = commandLine.getOptionValue(FILTER_OPTION); 1198 String order = commandLine.getOptionValue(ORDER_OPTION); 1199 printCoordJob(wc.getCoordJobInfo(optionValue, filter, start, len, order), timeZoneId, 1200 options.contains(VERBOSE_OPTION)); 1201 } 1202 else if (optionValue.contains("-C@")) { 1203 if (options.contains(ALL_WORKFLOWS_FOR_COORD_ACTION)) { 1204 printWfsForCoordAction(wc.getWfsForCoordAction(optionValue), timeZoneId); 1205 } 1206 else { 1207 String filter = commandLine.getOptionValue(FILTER_OPTION); 1208 if (filter != null) { 1209 throw new OozieCLIException("Filter option is not supported for a Coordinator action"); 1210 } 1211 printCoordAction(wc.getCoordActionInfo(optionValue), timeZoneId); 1212 } 1213 } 1214 else if (optionValue.contains("-W@")) { 1215 String filter = commandLine.getOptionValue(FILTER_OPTION); 1216 if (filter != null) { 1217 throw new OozieCLIException("Filter option is not supported for a Workflow action"); 1218 } 1219 printWorkflowAction(wc.getWorkflowActionInfo(optionValue), timeZoneId, 1220 options.contains(VERBOSE_OPTION)); 1221 1222 } 1223 else { 1224 String filter = commandLine.getOptionValue(FILTER_OPTION); 1225 if (filter != null) { 1226 throw new OozieCLIException("Filter option is currently not supported for a Workflow job"); 1227 } 1228 String s = commandLine.getOptionValue(OFFSET_OPTION); 1229 int start = Integer.parseInt((s != null) ? s : "0"); 1230 s = commandLine.getOptionValue(LEN_OPTION); 1231 String jobtype = commandLine.getOptionValue(JOBTYPE_OPTION); 1232 jobtype = (jobtype != null) ? jobtype : "wf"; 1233 int len = Integer.parseInt((s != null) ? s : "0"); 1234 printJob(wc.getJobInfo(optionValue, start, len), timeZoneId, 1235 options.contains(VERBOSE_OPTION)); 1236 } 1237 } 1238 else if (options.contains(LOG_OPTION)) { 1239 PrintStream ps = System.out; 1240 String logFilter = null; 1241 if (options.contains(RestConstants.LOG_FILTER_OPTION)) { 1242 logFilter = commandLine.getOptionValue(RestConstants.LOG_FILTER_OPTION); 1243 } 1244 if (commandLine.getOptionValue(LOG_OPTION).contains("-C")) { 1245 String logRetrievalScope = null; 1246 String logRetrievalType = null; 1247 if (options.contains(ACTION_OPTION)) { 1248 logRetrievalType = RestConstants.JOB_LOG_ACTION; 1249 logRetrievalScope = commandLine.getOptionValue(ACTION_OPTION); 1250 } 1251 if (options.contains(DATE_OPTION)) { 1252 logRetrievalType = RestConstants.JOB_LOG_DATE; 1253 logRetrievalScope = commandLine.getOptionValue(DATE_OPTION); 1254 } 1255 try { 1256 wc.getJobLog(commandLine.getOptionValue(LOG_OPTION), logRetrievalType, logRetrievalScope, 1257 logFilter, ps); 1258 } 1259 finally { 1260 ps.close(); 1261 } 1262 } 1263 else { 1264 if (!options.contains(ACTION_OPTION) && !options.contains(DATE_OPTION)) { 1265 wc.getJobLog(commandLine.getOptionValue(LOG_OPTION), null, null, logFilter, ps); 1266 } 1267 else { 1268 throw new OozieCLIException("Invalid options provided for log retrieval. " + ACTION_OPTION 1269 + " and " + DATE_OPTION + " are valid only for coordinator job log retrieval"); 1270 } 1271 } 1272 } 1273 else if (options.contains(ERROR_LOG_OPTION)) { 1274 try (PrintStream ps = System.out) { 1275 wc.getJobErrorLog(commandLine.getOptionValue(ERROR_LOG_OPTION), ps); 1276 } 1277 } 1278 else if (options.contains(AUDIT_LOG_OPTION)) { 1279 try (PrintStream ps = System.out) { 1280 wc.getJobAuditLog(commandLine.getOptionValue(AUDIT_LOG_OPTION), ps); 1281 } 1282 } 1283 else if (options.contains(DEFINITION_OPTION)) { 1284 System.out.println(wc.getJobDefinition(commandLine.getOptionValue(DEFINITION_OPTION))); 1285 } 1286 else if (options.contains(CONFIG_CONTENT_OPTION)) { 1287 if (commandLine.getOptionValue(CONFIG_CONTENT_OPTION).endsWith("-C")) { 1288 System.out.println(wc.getCoordJobInfo(commandLine.getOptionValue(CONFIG_CONTENT_OPTION)).getConf()); 1289 } 1290 else if (commandLine.getOptionValue(CONFIG_CONTENT_OPTION).endsWith("-W")) { 1291 System.out.println(wc.getJobInfo(commandLine.getOptionValue(CONFIG_CONTENT_OPTION)).getConf()); 1292 } 1293 else if (commandLine.getOptionValue(CONFIG_CONTENT_OPTION).endsWith("-B")) { 1294 System.out 1295 .println(wc.getBundleJobInfo(commandLine.getOptionValue(CONFIG_CONTENT_OPTION)).getConf()); 1296 } 1297 else { 1298 System.out.println("ERROR: job id [" + commandLine.getOptionValue(CONFIG_CONTENT_OPTION) 1299 + "] doesn't end with either C or W or B"); 1300 } 1301 } 1302 else if (options.contains(UPDATE_OPTION)) { 1303 String coordJobId = commandLine.getOptionValue(UPDATE_OPTION); 1304 Properties conf = null; 1305 1306 String dryrun = ""; 1307 String showdiff = ""; 1308 1309 if (commandLine.getOptionValue(CONFIG_OPTION) != null) { 1310 conf = getConfiguration(wc, commandLine); 1311 } 1312 if (options.contains(DRYRUN_OPTION)) { 1313 dryrun = "true"; 1314 } 1315 if (commandLine.getOptionValue(SHOWDIFF_OPTION) != null) { 1316 showdiff = commandLine.getOptionValue(SHOWDIFF_OPTION); 1317 } 1318 if (conf == null) { 1319 System.out.println(wc.updateCoord(coordJobId, dryrun, showdiff)); 1320 } 1321 else { 1322 System.out.println(wc.updateCoord(coordJobId, conf, dryrun, showdiff)); 1323 } 1324 } 1325 else if (options.contains(POLL_OPTION)) { 1326 String jobId = commandLine.getOptionValue(POLL_OPTION); 1327 int timeout = 30; 1328 int interval = 5; 1329 String timeoutS = commandLine.getOptionValue(TIMEOUT_OPTION); 1330 if (timeoutS != null) { 1331 timeout = Integer.parseInt(timeoutS); 1332 } 1333 String intervalS = commandLine.getOptionValue(INTERVAL_OPTION); 1334 if (intervalS != null) { 1335 interval = Integer.parseInt(intervalS); 1336 } 1337 boolean verbose = commandLine.hasOption(VERBOSE_OPTION); 1338 wc.pollJob(jobId, timeout, interval, verbose); 1339 } 1340 else if (options.contains(SLA_ENABLE_ALERT)) { 1341 slaAlertCommand(commandLine.getOptionValue(SLA_ENABLE_ALERT), wc, commandLine, options); 1342 } 1343 else if (options.contains(SLA_DISABLE_ALERT)) { 1344 slaAlertCommand(commandLine.getOptionValue(SLA_DISABLE_ALERT), wc, commandLine, options); 1345 } 1346 else if (options.contains(SLA_CHANGE)) { 1347 slaAlertCommand(commandLine.getOptionValue(SLA_CHANGE), wc, commandLine, options); 1348 } 1349 else if (options.contains(WORKFLOW_ACTIONS_RETRIES)) { 1350 printWorkflowActionRetries( 1351 wc.getWorkflowActionRetriesInfo(commandLine.getOptionValue(WORKFLOW_ACTIONS_RETRIES)), 1352 commandLine.getOptionValue(WORKFLOW_ACTIONS_RETRIES)); 1353 } 1354 else if (options.contains(COORD_ACTION_MISSING_DEPENDENCIES)) { 1355 String actions = null, dates = null; 1356 1357 if (options.contains(ACTION_OPTION)) { 1358 actions = commandLine.getOptionValue(ACTION_OPTION); 1359 } 1360 1361 if (options.contains(DATE_OPTION)) { 1362 dates = commandLine.getOptionValue(DATE_OPTION); 1363 } 1364 wc.getCoordActionMissingDependencies(commandLine.getOptionValue(COORD_ACTION_MISSING_DEPENDENCIES), 1365 actions, dates, System.out); 1366 } 1367 else if (options.contains(VALIDATE_JAR_OPTION)) { 1368 checkApiJar(wc, commandLine, options.contains(VERBOSE_OPTION)); 1369 } 1370 else if (options.contains(SUBMIT_JAR_OPTION)) { 1371 submitApiJar(wc, commandLine, options.contains(VERBOSE_OPTION)); 1372 } 1373 else if (options.contains(RUN_JAR_OPTION)) { 1374 runApiJar(wc, commandLine, options.contains(VERBOSE_OPTION)); 1375 } 1376 } 1377 catch (final OozieClientException ex) { 1378 throw new OozieCLIException(ex.toString(), ex); 1379 } 1380 } 1381 1382 private void checkApiJar(final XOozieClient wc, final CommandLine commandLine, final boolean verbose) 1383 throws OozieClientException { 1384 final String apiJarPath = commandLine.getOptionValue(VALIDATE_JAR_OPTION); 1385 logIfVerbose(verbose, "Checking API jar: " + apiJarPath); 1386 1387 final String generatedXml = loadApiJarAndGenerateXml(apiJarPath, verbose); 1388 1389 final Path workflowXml; 1390 try { 1391 workflowXml = Files.createTempFile("workflow", ".xml"); 1392 Files.write(workflowXml, generatedXml.getBytes(StandardCharsets.UTF_8)); 1393 1394 logIfVerbose(verbose, "API jar was written to " + workflowXml.toString()); 1395 } 1396 catch (final IOException e) { 1397 throw new OozieClientException(e.getMessage(), e); 1398 } 1399 1400 logIfVerbose(verbose, "Servlet response is: "); 1401 System.out.println(wc.validateXML(workflowXml.toString())); 1402 1403 logIfVerbose(verbose, "API jar is valid."); 1404 } 1405 1406 private void logIfVerbose(final boolean verbose, final String message) { 1407 if (verbose) { 1408 System.out.println(message); 1409 } 1410 } 1411 1412 @SuppressFBWarnings(value = {"PATH_TRAVERSAL_IN", "WEAK_FILENAMEUTILS"}, 1413 justification = "FilenameUtils is used to filter user input. JDK8+ is used.") 1414 private String loadApiJarAndGenerateXml(final String apiJarPath, final boolean verbose) throws OozieClientException { 1415 final String generatedXml; 1416 try { 1417 logIfVerbose(verbose, "Loading API jar " + apiJarPath); 1418 1419 final Workflow generatedWorkflow = new ApiJarLoader(new File( 1420 FilenameUtils.getFullPath(apiJarPath) + FilenameUtils.getName(apiJarPath))) 1421 .loadAndGenerate(); 1422 generatedXml = WorkflowMarshaller.marshal(generatedWorkflow); 1423 1424 logIfVerbose(verbose, "Workflow job definition generated from API jar: \n" + generatedXml); 1425 } 1426 catch (final IOException | ClassNotFoundException | IllegalAccessException | NoSuchMethodException | 1427 InvocationTargetException | InstantiationException | JAXBException e) { 1428 throw new OozieClientException(e.getMessage(), e); 1429 } 1430 1431 return generatedXml; 1432 } 1433 1434 private void submitApiJar(final XOozieClient wc, final CommandLine commandLine, final boolean verbose) 1435 throws OozieClientException { 1436 final String apiJarPath = commandLine.getOptionValue(SUBMIT_JAR_OPTION); 1437 logIfVerbose(verbose, "Submitting a job based on API jar: " + apiJarPath); 1438 1439 try { 1440 System.out.println(JOB_ID_PREFIX + wc.submit(getConfiguration(wc, commandLine), 1441 loadApiJarAndGenerateXml(apiJarPath, verbose))); 1442 } 1443 catch (final IOException e) { 1444 throw new OozieClientException(e.getMessage(), e); 1445 } 1446 1447 logIfVerbose(verbose, "Job based on API jar submitted successfully."); 1448 } 1449 1450 private void runApiJar(final XOozieClient wc, final CommandLine commandLine, final boolean verbose) 1451 throws OozieClientException { 1452 final String apiJarPath = commandLine.getOptionValue(RUN_JAR_OPTION); 1453 logIfVerbose(verbose, "Running a job based on API jar: " + apiJarPath); 1454 1455 try { 1456 System.out.println(JOB_ID_PREFIX + wc.run(getConfiguration(wc, commandLine), 1457 loadApiJarAndGenerateXml(apiJarPath, verbose))); 1458 } 1459 catch (final IOException e) { 1460 throw new OozieClientException(e.getMessage(), e); 1461 } 1462 1463 logIfVerbose(verbose, "Job based on API jar run successfully."); 1464 } 1465 1466 @VisibleForTesting 1467 void printCoordJob(CoordinatorJob coordJob, String timeZoneId, boolean verbose) { 1468 System.out.println("Job ID : " + coordJob.getId()); 1469 1470 System.out.println(RULER); 1471 1472 List<CoordinatorAction> actions = coordJob.getActions(); 1473 System.out.println("Job Name : " + maskIfNull(coordJob.getAppName())); 1474 System.out.println("App Path : " + maskIfNull(coordJob.getAppPath())); 1475 System.out.println("Status : " + coordJob.getStatus()); 1476 System.out.println("Start Time : " + maskDate(coordJob.getStartTime(), timeZoneId, false)); 1477 System.out.println("End Time : " + maskDate(coordJob.getEndTime(), timeZoneId, false)); 1478 System.out.println("Pause Time : " + maskDate(coordJob.getPauseTime(), timeZoneId, false)); 1479 System.out.println("Concurrency : " + coordJob.getConcurrency()); 1480 System.out.println(RULER); 1481 1482 if (verbose) { 1483 System.out.println("ID" + VERBOSE_DELIMITER + "Action Number" + VERBOSE_DELIMITER + "Console URL" 1484 + VERBOSE_DELIMITER + "Error Code" + VERBOSE_DELIMITER + "Error Message" + VERBOSE_DELIMITER 1485 + "External ID" + VERBOSE_DELIMITER + "External Status" + VERBOSE_DELIMITER + "Job ID" 1486 + VERBOSE_DELIMITER + "Tracker URI" + VERBOSE_DELIMITER + "Created" + VERBOSE_DELIMITER 1487 + "Nominal Time" + VERBOSE_DELIMITER + "Status" + VERBOSE_DELIMITER + "Last Modified" 1488 + VERBOSE_DELIMITER + "Missing Dependencies"); 1489 System.out.println(RULER); 1490 1491 for (CoordinatorAction action : actions) { 1492 System.out.println(maskIfNull(action.getId()) + VERBOSE_DELIMITER + action.getActionNumber() 1493 + VERBOSE_DELIMITER + maskIfNull(action.getConsoleUrl()) + VERBOSE_DELIMITER 1494 + maskIfNull(action.getErrorCode()) + VERBOSE_DELIMITER + maskIfNull(action.getErrorMessage()) 1495 + VERBOSE_DELIMITER + maskIfNull(action.getExternalId()) + VERBOSE_DELIMITER 1496 + maskIfNull(action.getExternalStatus()) + VERBOSE_DELIMITER + maskIfNull(action.getJobId()) 1497 + VERBOSE_DELIMITER + maskIfNull(action.getTrackerUri()) + VERBOSE_DELIMITER 1498 + maskDate(action.getCreatedTime(), timeZoneId, verbose) + VERBOSE_DELIMITER 1499 + maskDate(action.getNominalTime(), timeZoneId, verbose) + action.getStatus() + VERBOSE_DELIMITER 1500 + maskDate(action.getLastModifiedTime(), timeZoneId, verbose) + VERBOSE_DELIMITER 1501 + maskIfNull(getFirstMissingDependencies(action))); 1502 1503 System.out.println(RULER); 1504 } 1505 } 1506 else { 1507 System.out.println(String.format(COORD_ACTION_FORMATTER, "ID", "Status", "Ext ID", "Err Code", "Created", 1508 "Nominal Time", "Last Mod")); 1509 1510 for (CoordinatorAction action : actions) { 1511 System.out.println(String.format(COORD_ACTION_FORMATTER, maskIfNull(action.getId()), 1512 action.getStatus(), maskIfNull(action.getExternalId()), maskIfNull(action.getErrorCode()), 1513 maskDate(action.getCreatedTime(), timeZoneId, verbose), 1514 maskDate(action.getNominalTime(), timeZoneId, verbose), 1515 maskDate(action.getLastModifiedTime(), timeZoneId, verbose))); 1516 1517 System.out.println(RULER); 1518 } 1519 } 1520 } 1521 1522 @VisibleForTesting 1523 void printBundleJob(BundleJob bundleJob, String timeZoneId, boolean verbose) { 1524 System.out.println("Job ID : " + bundleJob.getId()); 1525 1526 System.out.println(RULER); 1527 1528 List<CoordinatorJob> coordinators = bundleJob.getCoordinators(); 1529 System.out.println("Job Name : " + maskIfNull(bundleJob.getAppName())); 1530 System.out.println("App Path : " + maskIfNull(bundleJob.getAppPath())); 1531 System.out.println("Status : " + bundleJob.getStatus()); 1532 System.out.println("Kickoff time : " + bundleJob.getKickoffTime()); 1533 System.out.println(RULER); 1534 1535 System.out.println(String.format(BUNDLE_COORD_JOBS_FORMATTER, "Job ID", "Status", "Freq", "Unit", "Started", 1536 "Next Materialized")); 1537 System.out.println(RULER); 1538 1539 for (CoordinatorJob job : coordinators) { 1540 System.out.println(String.format(BUNDLE_COORD_JOBS_FORMATTER, maskIfNull(job.getId()), job.getStatus(), 1541 job.getFrequency(), job.getTimeUnit(), maskDate(job.getStartTime(), timeZoneId, verbose), 1542 maskDate(job.getNextMaterializedTime(), timeZoneId, verbose))); 1543 1544 System.out.println(RULER); 1545 } 1546 } 1547 1548 @VisibleForTesting 1549 void printCoordAction(CoordinatorAction coordAction, String timeZoneId) { 1550 System.out.println("ID : " + maskIfNull(coordAction.getId())); 1551 1552 System.out.println(RULER); 1553 1554 System.out.println("Action Number : " + coordAction.getActionNumber()); 1555 System.out.println("Console URL : " + maskIfNull(coordAction.getConsoleUrl())); 1556 System.out.println("Error Code : " + maskIfNull(coordAction.getErrorCode())); 1557 System.out.println("Error Message : " + maskIfNull(coordAction.getErrorMessage())); 1558 System.out.println("External ID : " + maskIfNull(coordAction.getExternalId())); 1559 System.out.println("External Status : " + maskIfNull(coordAction.getExternalStatus())); 1560 System.out.println("Job ID : " + maskIfNull(coordAction.getJobId())); 1561 System.out.println("Tracker URI : " + maskIfNull(coordAction.getTrackerUri())); 1562 System.out.println("Created : " + maskDate(coordAction.getCreatedTime(), timeZoneId, false)); 1563 System.out.println("Nominal Time : " + maskDate(coordAction.getNominalTime(), timeZoneId, false)); 1564 System.out.println("Status : " + coordAction.getStatus()); 1565 System.out.println("Last Modified : " + maskDate(coordAction.getLastModifiedTime(), timeZoneId, false)); 1566 System.out.println("First Missing Dependency : " + maskIfNull(getFirstMissingDependencies(coordAction))); 1567 1568 System.out.println(RULER); 1569 } 1570 1571 private void printCoordActions(List<CoordinatorAction> actions) { 1572 if (actions != null && actions.size() > 0) { 1573 System.out.println("Action ID" + VERBOSE_DELIMITER + "Nominal Time"); 1574 System.out.println(RULER); 1575 for (CoordinatorAction action : actions) { 1576 System.out.println(maskIfNull(action.getId()) + VERBOSE_DELIMITER 1577 + maskDate(action.getNominalTime(), null,false)); 1578 } 1579 } 1580 else { 1581 System.out.println("No Actions match your criteria!"); 1582 } 1583 } 1584 1585 private void printCoordActionsStatus(List<CoordinatorAction> actions) { 1586 if (actions != null && actions.size() > 0) { 1587 System.out.println("Action ID" + VERBOSE_DELIMITER + "Nominal Time" + VERBOSE_DELIMITER + "Status"); 1588 System.out.println(RULER); 1589 for (CoordinatorAction action : actions) { 1590 System.out.println(maskIfNull(action.getId()) + VERBOSE_DELIMITER 1591 + maskDate(action.getNominalTime(), null, false) + VERBOSE_DELIMITER 1592 + maskIfNull(action.getStatus().name())); 1593 } 1594 } 1595 } 1596 1597 @VisibleForTesting 1598 void printWorkflowAction(WorkflowAction action, String timeZoneId, boolean verbose) { 1599 1600 System.out.println("ID : " + maskIfNull(action.getId())); 1601 1602 System.out.println(RULER); 1603 1604 System.out.println("Console URL : " + maskIfNull(action.getConsoleUrl())); 1605 System.out.println("Error Code : " + maskIfNull(action.getErrorCode())); 1606 System.out.println("Error Message : " + maskIfNull(action.getErrorMessage())); 1607 System.out.println("External ID : " + maskIfNull(action.getExternalId())); 1608 System.out.println("External Status : " + maskIfNull(action.getExternalStatus())); 1609 System.out.println("Name : " + maskIfNull(action.getName())); 1610 System.out.println("Retries : " + action.getUserRetryCount()); 1611 System.out.println("Tracker URI : " + maskIfNull(action.getTrackerUri())); 1612 System.out.println("Type : " + maskIfNull(action.getType())); 1613 System.out.println("Started : " + maskDate(action.getStartTime(), timeZoneId, verbose)); 1614 System.out.println("Status : " + action.getStatus()); 1615 System.out.println("Ended : " + maskDate(action.getEndTime(), timeZoneId, verbose)); 1616 1617 if (verbose) { 1618 System.out.println("External Stats : " + action.getStats()); 1619 System.out.println("External ChildIDs : " + action.getExternalChildIDs()); 1620 } 1621 1622 System.out.println(RULER); 1623 } 1624 1625 void printWorkflowActionRetries(List<Map<String, String>> retries, String actionId) { 1626 System.out.println("ID : " + maskIfNull(actionId)); 1627 if (retries.isEmpty()) { 1628 System.out.println("No Retries"); 1629 } 1630 for (Map<String, String> retry: retries) { 1631 System.out.println(RULER); 1632 System.out.println("Attempt : " + retry.get(JsonTags.ACTION_ATTEMPT)); 1633 System.out.println("Start Time : " + retry.get(JsonTags.WORKFLOW_ACTION_START_TIME)); 1634 System.out.println("End Time : " + retry.get(JsonTags.WORKFLOW_ACTION_END_TIME)); 1635 if (null != retry.get(JsonTags.WORKFLOW_ACTION_CONSOLE_URL)) { 1636 System.out.println("Console URL : " + retry.get(JsonTags.WORKFLOW_ACTION_CONSOLE_URL)); 1637 } 1638 if (null != retry.get(JsonTags.WORKFLOW_ACTION_EXTERNAL_CHILD_IDS)) { 1639 System.out.println("Child URL : " + retry.get(JsonTags.WORKFLOW_ACTION_EXTERNAL_CHILD_IDS)); 1640 } 1641 } 1642 System.out.println(RULER); 1643 } 1644 1645 private static final String WORKFLOW_JOBS_FORMATTER = "%-41s%-13s%-10s%-10s%-10s%-24s%-24s"; 1646 private static final String COORD_JOBS_FORMATTER = "%-41s%-15s%-10s%-5s%-13s%-24s%-24s"; 1647 private static final String BUNDLE_JOBS_FORMATTER = "%-41s%-15s%-10s%-20s%-20s%-13s%-13s"; 1648 private static final String BUNDLE_COORD_JOBS_FORMATTER = "%-41s%-15s%-5s%-13s%-24s%-24s"; 1649 1650 private static final String WORKFLOW_ACTION_FORMATTER = "%-78s%-10s%-23s%-11s%-10s"; 1651 private static final String COORD_ACTION_FORMATTER = "%-43s%-10s%-37s%-10s%-21s%-21s"; 1652 private static final String BULK_RESPONSE_FORMATTER = "%-13s%-38s%-13s%-41s%-10s%-38s%-21s%-38s"; 1653 1654 @VisibleForTesting 1655 void printJob(WorkflowJob job, String timeZoneId, boolean verbose) throws IOException { 1656 System.out.println("Job ID : " + maskIfNull(job.getId())); 1657 1658 System.out.println(RULER); 1659 1660 System.out.println("Workflow Name : " + maskIfNull(job.getAppName())); 1661 System.out.println("App Path : " + maskIfNull(job.getAppPath())); 1662 System.out.println("Status : " + job.getStatus()); 1663 System.out.println("Run : " + job.getRun()); 1664 System.out.println("User : " + maskIfNull(job.getUser())); 1665 System.out.println("Group : " + maskIfNull(job.getGroup())); 1666 System.out.println("Created : " + maskDate(job.getCreatedTime(), timeZoneId, verbose)); 1667 System.out.println("Started : " + maskDate(job.getStartTime(), timeZoneId, verbose)); 1668 System.out.println("Last Modified : " + maskDate(job.getLastModifiedTime(), timeZoneId, verbose)); 1669 System.out.println("Ended : " + maskDate(job.getEndTime(), timeZoneId, verbose)); 1670 System.out.println("CoordAction ID: " + maskIfNull(job.getParentId())); 1671 1672 List<WorkflowAction> actions = job.getActions(); 1673 1674 if (actions != null && actions.size() > 0) { 1675 System.out.println(); 1676 System.out.println("Actions"); 1677 System.out.println(RULER); 1678 1679 if (verbose) { 1680 System.out.println("ID" + VERBOSE_DELIMITER + "Console URL" + VERBOSE_DELIMITER + "Error Code" 1681 + VERBOSE_DELIMITER + "Error Message" + VERBOSE_DELIMITER + "External ID" + VERBOSE_DELIMITER 1682 + "External Status" + VERBOSE_DELIMITER + "Name" + VERBOSE_DELIMITER + "Retries" 1683 + VERBOSE_DELIMITER + "Tracker URI" + VERBOSE_DELIMITER + "Type" + VERBOSE_DELIMITER 1684 + "Started" + VERBOSE_DELIMITER + "Status" + VERBOSE_DELIMITER + "Ended"); 1685 System.out.println(RULER); 1686 1687 for (WorkflowAction action : job.getActions()) { 1688 System.out.println(maskIfNull(action.getId()) + VERBOSE_DELIMITER 1689 + maskIfNull(action.getConsoleUrl()) + VERBOSE_DELIMITER 1690 + maskIfNull(action.getErrorCode()) + VERBOSE_DELIMITER 1691 + maskIfNull(action.getErrorMessage()) + VERBOSE_DELIMITER 1692 + maskIfNull(action.getExternalId()) + VERBOSE_DELIMITER 1693 + maskIfNull(action.getExternalStatus()) + VERBOSE_DELIMITER + maskIfNull(action.getName()) 1694 + VERBOSE_DELIMITER + action.getRetries() + VERBOSE_DELIMITER 1695 + maskIfNull(action.getTrackerUri()) + VERBOSE_DELIMITER + maskIfNull(action.getType()) 1696 + VERBOSE_DELIMITER + maskDate(action.getStartTime(), timeZoneId, verbose) 1697 + VERBOSE_DELIMITER + action.getStatus() + VERBOSE_DELIMITER 1698 + maskDate(action.getEndTime(), timeZoneId, verbose)); 1699 1700 System.out.println(RULER); 1701 } 1702 } 1703 else { 1704 System.out.println(String.format(WORKFLOW_ACTION_FORMATTER, "ID", "Status", "Ext ID", "Ext Status", 1705 "Err Code")); 1706 1707 System.out.println(RULER); 1708 1709 for (WorkflowAction action : job.getActions()) { 1710 System.out.println(String.format(WORKFLOW_ACTION_FORMATTER, maskIfNull(action.getId()), action 1711 .getStatus(), maskIfNull(action.getExternalId()), maskIfNull(action.getExternalStatus()), 1712 maskIfNull(action.getErrorCode()))); 1713 1714 System.out.println(RULER); 1715 } 1716 } 1717 } 1718 else { 1719 System.out.println(RULER); 1720 } 1721 1722 System.out.println(); 1723 } 1724 1725 private void jobsCommand(CommandLine commandLine) throws IOException, OozieCLIException { 1726 XOozieClient wc = createXOozieClient(commandLine); 1727 1728 List<String> options = new ArrayList<>(); 1729 for (Option option : commandLine.getOptions()) { 1730 options.add(option.getOpt()); 1731 } 1732 1733 String filter = commandLine.getOptionValue(FILTER_OPTION); 1734 String s = commandLine.getOptionValue(OFFSET_OPTION); 1735 int start = Integer.parseInt((s != null) ? s : "0"); 1736 s = commandLine.getOptionValue(LEN_OPTION); 1737 String jobtype = commandLine.getOptionValue(JOBTYPE_OPTION); 1738 String timeZoneId = getTimeZoneId(commandLine); 1739 jobtype = (jobtype != null) ? jobtype : "wf"; 1740 int len = Integer.parseInt((s != null) ? s : "0"); 1741 String bulkFilterString = commandLine.getOptionValue(BULK_OPTION); 1742 1743 try { 1744 if (options.contains(KILL_OPTION)) { 1745 printBulkModifiedJobs(wc.killJobs(filter, jobtype, start, len), timeZoneId, "killed"); 1746 } 1747 else if (options.contains(SUSPEND_OPTION)) { 1748 printBulkModifiedJobs(wc.suspendJobs(filter, jobtype, start, len), timeZoneId, "suspended"); 1749 } 1750 else if (options.contains(RESUME_OPTION)) { 1751 printBulkModifiedJobs(wc.resumeJobs(filter, jobtype, start, len), timeZoneId, "resumed"); 1752 } 1753 else if (bulkFilterString != null) { 1754 printBulkJobs(wc.getBulkInfo(bulkFilterString, start, len), timeZoneId, commandLine.hasOption(VERBOSE_OPTION)); 1755 } 1756 else if (jobtype.toLowerCase().contains("wf")) { 1757 printJobs(wc.getJobsInfo(filter, start, len), timeZoneId, commandLine.hasOption(VERBOSE_OPTION)); 1758 } 1759 else if (jobtype.toLowerCase().startsWith("coord")) { 1760 printCoordJobs(wc.getCoordJobsInfo(filter, start, len), timeZoneId, commandLine.hasOption(VERBOSE_OPTION)); 1761 } 1762 else if (jobtype.toLowerCase().startsWith("bundle")) { 1763 printBundleJobs(wc.getBundleJobsInfo(filter, start, len), timeZoneId, commandLine.hasOption(VERBOSE_OPTION)); 1764 } 1765 1766 } 1767 catch (OozieClientException ex) { 1768 throw new OozieCLIException(ex.toString(), ex); 1769 } 1770 } 1771 1772 @VisibleForTesting 1773 void printBulkModifiedJobs(JSONObject json, String timeZoneId, String action) throws IOException { 1774 if (json.containsKey(JsonTags.WORKFLOWS_JOBS)) { 1775 JSONArray workflows = (JSONArray) json.get(JsonTags.WORKFLOWS_JOBS); 1776 if (workflows == null) { 1777 workflows = new JSONArray(); 1778 } 1779 List<WorkflowJob> wfs = JsonToBean.createWorkflowJobList(workflows); 1780 if (wfs.isEmpty()) { 1781 System.out.println("bulk modify command did not modify any jobs"); 1782 } 1783 else { 1784 System.out.println("the following jobs have been " + action); 1785 printJobs(wfs, timeZoneId, false); 1786 } 1787 } 1788 else if (json.containsKey(JsonTags.COORDINATOR_JOBS)) { 1789 JSONArray coordinators = (JSONArray) json.get(JsonTags.COORDINATOR_JOBS); 1790 if (coordinators == null) { 1791 coordinators = new JSONArray(); 1792 } 1793 List<CoordinatorJob> coords = JsonToBean.createCoordinatorJobList(coordinators); 1794 if (coords.isEmpty()) { 1795 System.out.println("bulk modify command did not modify any jobs"); 1796 } 1797 else { 1798 System.out.println("the following jobs have been " + action); 1799 printCoordJobs(coords, timeZoneId, false); 1800 } 1801 } 1802 else { 1803 JSONArray bundles = (JSONArray) json.get(JsonTags.BUNDLE_JOBS); 1804 if (bundles == null) { 1805 bundles = new JSONArray(); 1806 } 1807 List<BundleJob> bundleJobs = JsonToBean.createBundleJobList(bundles); 1808 if (bundleJobs.isEmpty()) { 1809 System.out.println("bulk modify command did not modify any jobs"); 1810 } 1811 else { 1812 System.out.println("the following jobs have been " + action); 1813 printBundleJobs(bundleJobs, timeZoneId, false); 1814 } 1815 } 1816 } 1817 1818 @VisibleForTesting 1819 void printCoordJobs(List<CoordinatorJob> jobs, String timeZoneId, boolean verbose) throws IOException { 1820 if (jobs != null && jobs.size() > 0) { 1821 if (verbose) { 1822 System.out.println("Job ID" + VERBOSE_DELIMITER + "App Name" + VERBOSE_DELIMITER + "App Path" 1823 + VERBOSE_DELIMITER + "Console URL" + VERBOSE_DELIMITER + "User" + VERBOSE_DELIMITER + "Group" 1824 + VERBOSE_DELIMITER + "Concurrency" + VERBOSE_DELIMITER + "Frequency" + VERBOSE_DELIMITER 1825 + "Time Unit" + VERBOSE_DELIMITER + "Time Zone" + VERBOSE_DELIMITER + "Time Out" 1826 + VERBOSE_DELIMITER + "Started" + VERBOSE_DELIMITER + "Next Materialize" + VERBOSE_DELIMITER 1827 + "Status" + VERBOSE_DELIMITER + "Last Action" + VERBOSE_DELIMITER + "Ended"); 1828 System.out.println(RULER); 1829 1830 for (CoordinatorJob job : jobs) { 1831 System.out.println(maskIfNull(job.getId()) + VERBOSE_DELIMITER + maskIfNull(job.getAppName()) 1832 + VERBOSE_DELIMITER + maskIfNull(job.getAppPath()) + VERBOSE_DELIMITER 1833 + maskIfNull(job.getConsoleUrl()) + VERBOSE_DELIMITER + maskIfNull(job.getUser()) 1834 + VERBOSE_DELIMITER + maskIfNull(job.getGroup()) + VERBOSE_DELIMITER + job.getConcurrency() 1835 + VERBOSE_DELIMITER + job.getFrequency() + VERBOSE_DELIMITER + job.getTimeUnit() 1836 + VERBOSE_DELIMITER + maskIfNull(job.getTimeZone()) + VERBOSE_DELIMITER + job.getTimeout() 1837 + VERBOSE_DELIMITER + maskDate(job.getStartTime(), timeZoneId, verbose) + VERBOSE_DELIMITER 1838 + maskDate(job.getNextMaterializedTime(), timeZoneId, verbose) + VERBOSE_DELIMITER 1839 + job.getStatus() + VERBOSE_DELIMITER 1840 + maskDate(job.getLastActionTime(), timeZoneId, verbose) + VERBOSE_DELIMITER 1841 + maskDate(job.getEndTime(), timeZoneId, verbose)); 1842 1843 System.out.println(RULER); 1844 } 1845 } 1846 else { 1847 System.out.println(String.format(COORD_JOBS_FORMATTER, "Job ID", "App Name", "Status", "Freq", "Unit", 1848 "Started", "Next Materialized")); 1849 System.out.println(RULER); 1850 1851 for (CoordinatorJob job : jobs) { 1852 System.out.println(String.format(COORD_JOBS_FORMATTER, maskIfNull(job.getId()), maskIfNull(job 1853 .getAppName()), job.getStatus(), job.getFrequency(), job.getTimeUnit(), maskDate(job 1854 .getStartTime(), timeZoneId, verbose), maskDate(job.getNextMaterializedTime(), timeZoneId, verbose))); 1855 1856 System.out.println(RULER); 1857 } 1858 } 1859 } 1860 else { 1861 System.out.println("No Jobs match your criteria!"); 1862 } 1863 } 1864 1865 @VisibleForTesting 1866 void printBulkJobs(List<BulkResponse> jobs, String timeZoneId, boolean verbose) throws IOException { 1867 if (jobs != null && jobs.size() > 0) { 1868 for (BulkResponse response : jobs) { 1869 BundleJob bundle = response.getBundle(); 1870 CoordinatorJob coord = response.getCoordinator(); 1871 CoordinatorAction action = response.getAction(); 1872 if (verbose) { 1873 System.out.println(); 1874 System.out.println("Bundle Name : " + maskIfNull(bundle.getAppName())); 1875 1876 System.out.println(RULER); 1877 1878 System.out.println("Bundle ID : " + maskIfNull(bundle.getId())); 1879 System.out.println("Coordinator Name : " + maskIfNull(coord.getAppName())); 1880 System.out.println("Coord Action ID : " + maskIfNull(action.getId())); 1881 System.out.println("Action Status : " + action.getStatus()); 1882 System.out.println("External ID : " + maskIfNull(action.getExternalId())); 1883 System.out.println("Created Time : " + maskDate(action.getCreatedTime(), timeZoneId, false)); 1884 System.out.println("User : " + maskIfNull(bundle.getUser())); 1885 System.out.println("Error Message : " + maskIfNull(action.getErrorMessage())); 1886 System.out.println(RULER); 1887 } 1888 else { 1889 System.out.println(String.format(BULK_RESPONSE_FORMATTER, "Bundle Name", "Bundle ID", "Coord Name", 1890 "Coord Action ID", "Status", "External ID", "Created Time", "Error Message")); 1891 System.out.println(RULER); 1892 System.out 1893 .println(String.format(BULK_RESPONSE_FORMATTER, maskIfNull(bundle.getAppName()), 1894 maskIfNull(bundle.getId()), maskIfNull(coord.getAppName()), 1895 maskIfNull(action.getId()), action.getStatus(), maskIfNull(action.getExternalId()), 1896 maskDate(action.getCreatedTime(), timeZoneId, false), 1897 maskIfNull(action.getErrorMessage()))); 1898 System.out.println(RULER); 1899 } 1900 } 1901 } 1902 else { 1903 System.out.println("Bulk request criteria did not match any coordinator actions"); 1904 } 1905 } 1906 1907 @VisibleForTesting 1908 void printBundleJobs(List<BundleJob> jobs, String timeZoneId, boolean verbose) throws IOException { 1909 if (jobs != null && jobs.size() > 0) { 1910 if (verbose) { 1911 System.out.println("Job ID" + VERBOSE_DELIMITER + "Bundle Name" + VERBOSE_DELIMITER + "Bundle Path" 1912 + VERBOSE_DELIMITER + "User" + VERBOSE_DELIMITER + "Group" + VERBOSE_DELIMITER + "Status" 1913 + VERBOSE_DELIMITER + "Kickoff" + VERBOSE_DELIMITER + "Pause" + VERBOSE_DELIMITER + "Created" 1914 + VERBOSE_DELIMITER + "Console URL"); 1915 System.out.println(RULER); 1916 1917 for (BundleJob job : jobs) { 1918 System.out.println(maskIfNull(job.getId()) + VERBOSE_DELIMITER + maskIfNull(job.getAppName()) 1919 + VERBOSE_DELIMITER + maskIfNull(job.getAppPath()) + VERBOSE_DELIMITER 1920 + maskIfNull(job.getUser()) + VERBOSE_DELIMITER + maskIfNull(job.getGroup()) 1921 + VERBOSE_DELIMITER + job.getStatus() + VERBOSE_DELIMITER 1922 + maskDate(job.getKickoffTime(), timeZoneId, verbose) + VERBOSE_DELIMITER 1923 + maskDate(job.getPauseTime(), timeZoneId, verbose) + VERBOSE_DELIMITER 1924 + maskDate(job.getCreatedTime(), timeZoneId, verbose) + VERBOSE_DELIMITER 1925 + maskIfNull(job.getConsoleUrl())); 1926 1927 System.out.println(RULER); 1928 } 1929 } 1930 else { 1931 System.out.println(String.format(BUNDLE_JOBS_FORMATTER, "Job ID", "Bundle Name", "Status", "Kickoff", 1932 "Created", "User", "Group")); 1933 System.out.println(RULER); 1934 1935 for (BundleJob job : jobs) { 1936 System.out.println(String.format(BUNDLE_JOBS_FORMATTER, maskIfNull(job.getId()), 1937 maskIfNull(job.getAppName()), job.getStatus(), 1938 maskDate(job.getKickoffTime(), timeZoneId, verbose), 1939 maskDate(job.getCreatedTime(), timeZoneId, verbose), maskIfNull(job.getUser()), 1940 maskIfNull(job.getGroup()))); 1941 System.out.println(RULER); 1942 } 1943 } 1944 } 1945 else { 1946 System.out.println("No Jobs match your criteria!"); 1947 } 1948 } 1949 1950 private void slaCommand(CommandLine commandLine) throws IOException, OozieCLIException { 1951 XOozieClient wc = createXOozieClient(commandLine); 1952 1953 String s = commandLine.getOptionValue(OFFSET_OPTION); 1954 int start = Integer.parseInt((s != null) ? s : "0"); 1955 s = commandLine.getOptionValue(LEN_OPTION); 1956 int len = Integer.parseInt((s != null) ? s : "100"); 1957 String filter = commandLine.getOptionValue(FILTER_OPTION); 1958 1959 try { 1960 wc.getSlaInfo(start, len, filter); 1961 } 1962 catch (OozieClientException ex) { 1963 throw new OozieCLIException(ex.toString(), ex); 1964 } 1965 } 1966 1967 private void adminCommand(CommandLine commandLine) throws OozieCLIException { 1968 XOozieClient wc = createXOozieClient(commandLine); 1969 1970 List<String> options = new ArrayList<>(); 1971 for (Option option : commandLine.getOptions()) { 1972 options.add(option.getOpt()); 1973 } 1974 1975 try { 1976 SYSTEM_MODE status; 1977 if (options.contains(VERSION_OPTION)) { 1978 System.out.println("Oozie server build version: " + wc.getServerBuildVersion()); 1979 } 1980 else if (options.contains(SYSTEM_MODE_OPTION)) { 1981 String systemModeOption = commandLine.getOptionValue(SYSTEM_MODE_OPTION).toUpperCase(); 1982 try { 1983 status = SYSTEM_MODE.valueOf(systemModeOption); 1984 } 1985 catch (Exception e) { 1986 throw new OozieCLIException("Invalid input provided for option: " + SYSTEM_MODE_OPTION 1987 + " value given :" + systemModeOption 1988 + " Expected values are: NORMAL/NOWEBSERVICE/SAFEMODE "); 1989 } 1990 wc.setSystemMode(status); 1991 System.out.println("System mode: " + status); 1992 } 1993 else if (options.contains(STATUS_OPTION)) { 1994 status = wc.getSystemMode(); 1995 System.out.println("System mode: " + status); 1996 } 1997 1998 else if (options.contains(UPDATE_SHARELIB_OPTION)) { 1999 System.out.println(wc.updateShareLib()); 2000 } 2001 2002 else if (options.contains(LIST_SHARELIB_LIB_OPTION)) { 2003 String sharelibKey = null; 2004 if (commandLine.getArgList().size() > 0) { 2005 sharelibKey = (String) commandLine.getArgList().get(0); 2006 } 2007 System.out.println(wc.listShareLib(sharelibKey)); 2008 } 2009 2010 else if (options.contains(QUEUE_DUMP_OPTION)) { 2011 2012 List<String> list = wc.getQueueDump(); 2013 if (list != null && list.size() != 0) { 2014 for (String str : list) { 2015 System.out.println(str); 2016 } 2017 } 2018 else { 2019 System.out.println("QueueDump is null!"); 2020 } 2021 } 2022 else if (options.contains(AVAILABLE_SERVERS_OPTION)) { 2023 Map<String, String> availableOozieServers = new TreeMap<>(wc.getAvailableOozieServers()); 2024 for (Map.Entry<String, String> ent : availableOozieServers.entrySet()) { 2025 System.out.println(ent.getKey() + " : " + ent.getValue()); 2026 } 2027 } else if (options.contains(SERVER_CONFIGURATION_OPTION)) { 2028 Map<String, String> serverConfig = new TreeMap<>(wc.getServerConfiguration()); 2029 for (Map.Entry<String, String> ent : serverConfig.entrySet()) { 2030 System.out.println(ent.getKey() + " : " + ent.getValue()); 2031 } 2032 } else if (options.contains(SERVER_OS_ENV_OPTION)) { 2033 Map<String, String> osEnv = new TreeMap<>(wc.getOSEnv()); 2034 for (Map.Entry<String, String> ent : osEnv.entrySet()) { 2035 System.out.println(ent.getKey() + " : " + ent.getValue()); 2036 } 2037 } else if (options.contains(SERVER_JAVA_SYSTEM_PROPERTIES_OPTION)) { 2038 Map<String, String> javaSysProps = new TreeMap<>(wc.getJavaSystemProperties()); 2039 for (Map.Entry<String, String> ent : javaSysProps.entrySet()) { 2040 System.out.println(ent.getKey() + " : " + ent.getValue()); 2041 } 2042 } else if (options.contains(METRICS_OPTION)) { 2043 OozieClient.Metrics metrics = wc.getMetrics(); 2044 if (metrics == null) { 2045 System.out.println("Metrics are unavailable. Try Instrumentation (-" + INSTRUMENTATION_OPTION + ") instead"); 2046 } else { 2047 printMetrics(metrics); 2048 } 2049 } else if (options.contains(INSTRUMENTATION_OPTION)) { 2050 OozieClient.Instrumentation instrumentation = wc.getInstrumentation(); 2051 if (instrumentation == null) { 2052 System.out.println("Instrumentation is unavailable. Try Metrics (-" + METRICS_OPTION + ") instead"); 2053 } else { 2054 printInstrumentation(instrumentation); 2055 } 2056 } else if (options.contains(PURGE_OPTION)) { 2057 String purgeOptions = commandLine.getOptionValue(PURGE_OPTION); 2058 System.out.println(wc.purgeCommand(purgeOptions)); 2059 } 2060 } 2061 catch (OozieClientException ex) { 2062 throw new OozieCLIException(ex.toString(), ex); 2063 } 2064 } 2065 2066 private void versionCommand() throws OozieCLIException { 2067 StringBuilder sb = new StringBuilder(); 2068 sb.append("Oozie client build version: ") 2069 .append(BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VERSION)) 2070 .append("\nSource code repository: ") 2071 .append(BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VC_URL)) 2072 .append("\nCompiled by ") 2073 .append(BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_USER_NAME)) 2074 .append(" on ") 2075 .append(BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_TIME)) 2076 .append("\nFrom source with checksum: ") 2077 .append(BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VC_REVISION)); 2078 System.out.println(sb.toString()); 2079 } 2080 2081 @VisibleForTesting 2082 void printJobs(List<WorkflowJob> jobs, String timeZoneId, boolean verbose) throws IOException { 2083 if (jobs != null && jobs.size() > 0) { 2084 if (verbose) { 2085 System.out.println("Job ID" + VERBOSE_DELIMITER + "App Name" + VERBOSE_DELIMITER + "App Path" 2086 + VERBOSE_DELIMITER + "Console URL" + VERBOSE_DELIMITER + "User" + VERBOSE_DELIMITER + "Group" 2087 + VERBOSE_DELIMITER + "Run" + VERBOSE_DELIMITER + "Created" + VERBOSE_DELIMITER + "Started" 2088 + VERBOSE_DELIMITER + "Status" + VERBOSE_DELIMITER + "Last Modified" + VERBOSE_DELIMITER 2089 + "Ended"); 2090 System.out.println(RULER); 2091 2092 for (WorkflowJob job : jobs) { 2093 System.out.println(maskIfNull(job.getId()) + VERBOSE_DELIMITER + maskIfNull(job.getAppName()) 2094 + VERBOSE_DELIMITER + maskIfNull(job.getAppPath()) + VERBOSE_DELIMITER 2095 + maskIfNull(job.getConsoleUrl()) + VERBOSE_DELIMITER + maskIfNull(job.getUser()) 2096 + VERBOSE_DELIMITER + maskIfNull(job.getGroup()) + VERBOSE_DELIMITER + job.getRun() 2097 + VERBOSE_DELIMITER + maskDate(job.getCreatedTime(), timeZoneId, verbose) 2098 + VERBOSE_DELIMITER + maskDate(job.getStartTime(), timeZoneId, verbose) + VERBOSE_DELIMITER 2099 + job.getStatus() + VERBOSE_DELIMITER 2100 + maskDate(job.getLastModifiedTime(), timeZoneId, verbose) + VERBOSE_DELIMITER 2101 + maskDate(job.getEndTime(), timeZoneId, verbose)); 2102 2103 System.out.println(RULER); 2104 } 2105 } 2106 else { 2107 System.out.println(String.format(WORKFLOW_JOBS_FORMATTER, "Job ID", "App Name", "Status", "User", 2108 "Group", "Started", "Ended")); 2109 System.out.println(RULER); 2110 2111 for (WorkflowJob job : jobs) { 2112 System.out.println(String.format(WORKFLOW_JOBS_FORMATTER, maskIfNull(job.getId()), 2113 maskIfNull(job.getAppName()), job.getStatus(), maskIfNull(job.getUser()), 2114 maskIfNull(job.getGroup()), maskDate(job.getStartTime(), timeZoneId, verbose), 2115 maskDate(job.getEndTime(), timeZoneId, verbose))); 2116 2117 System.out.println(RULER); 2118 } 2119 } 2120 } 2121 else { 2122 System.out.println("No Jobs match your criteria!"); 2123 } 2124 } 2125 2126 void printWfsForCoordAction(List<WorkflowJob> jobs, String timeZoneId) throws IOException { 2127 if (jobs != null && jobs.size() > 0) { 2128 System.out.println(String.format("%-41s%-10s%-24s%-24s", "Job ID", "Status", "Started", "Ended")); 2129 System.out.println(RULER); 2130 2131 for (WorkflowJob job : jobs) { 2132 System.out 2133 .println(String.format("%-41s%-10s%-24s%-24s", maskIfNull(job.getId()), job.getStatus(), 2134 maskDate(job.getStartTime(), timeZoneId, false), 2135 maskDate(job.getEndTime(), timeZoneId, false))); 2136 System.out.println(RULER); 2137 } 2138 } 2139 } 2140 2141 private String maskIfNull(String value) { 2142 if (value != null && value.length() > 0) { 2143 return value; 2144 } 2145 return "-"; 2146 } 2147 2148 private String maskDate(Date date, String timeZoneId, boolean verbose) { 2149 if (date == null) { 2150 return "-"; 2151 } 2152 2153 SimpleDateFormat dateFormater; 2154 if (verbose) { 2155 dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz", Locale.US); 2156 } 2157 else { 2158 dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm zzz", Locale.US); 2159 } 2160 2161 if (timeZoneId != null) { 2162 dateFormater.setTimeZone(TimeZone.getTimeZone(timeZoneId)); 2163 } 2164 String dateString = dateFormater.format(date); 2165 // Most TimeZones are 3 or 4 characters; GMT offsets (e.g. GMT-07:00) are 9, so lets remove the "GMT" part to make it 6 2166 // to fit better 2167 Matcher m = GMT_OFFSET_SHORTEN_PATTERN.matcher(dateString); 2168 if (m.matches() && m.groupCount() == 2) { 2169 dateString = m.group(1) + m.group(2); 2170 } 2171 return dateString; 2172 } 2173 2174 private void validateCommand(CommandLine commandLine) throws OozieCLIException { 2175 String[] args = commandLine.getArgs(); 2176 if (args.length != 1) { 2177 throw new OozieCLIException("One file must be specified"); 2178 } 2179 try { 2180 XOozieClient wc = createXOozieClient(commandLine); 2181 String result = wc.validateXML(args[0]); 2182 if (result == null) { 2183 return; 2184 } 2185 System.out.println(result); 2186 } catch (OozieClientException e) { 2187 throw new OozieCLIException(e.getMessage(), e); 2188 } 2189 } 2190 2191 private void scriptLanguageCommand(CommandLine commandLine, String jobType) throws IOException, OozieCLIException { 2192 List<String> args = commandLine.getArgList(); 2193 if (args.size() > 0) { 2194 // checking if args starts with -X (because CLIParser cannot check this) 2195 if (!args.get(0).equals("-X")) { 2196 throw new OozieCLIException("Unrecognized option: " + args.get(0) + " Expecting -X"); 2197 } 2198 args.remove(0); 2199 } 2200 2201 if (!commandLine.hasOption(SCRIPTFILE_OPTION)) { 2202 throw new OozieCLIException("Need to specify -file <scriptfile>"); 2203 } 2204 2205 if (!commandLine.hasOption(CONFIG_OPTION)) { 2206 throw new OozieCLIException("Need to specify -config <configfile>"); 2207 } 2208 2209 try { 2210 XOozieClient wc = createXOozieClient(commandLine); 2211 Properties conf = getConfiguration(wc, commandLine); 2212 String script = commandLine.getOptionValue(SCRIPTFILE_OPTION); 2213 List<String> paramsList = new ArrayList<>(); 2214 if (commandLine.hasOption("P")) { 2215 Properties params = commandLine.getOptionProperties("P"); 2216 for (String key : params.stringPropertyNames()) { 2217 paramsList.add(key + "=" + params.getProperty(key)); 2218 } 2219 } 2220 System.out.println(JOB_ID_PREFIX + wc.submitScriptLanguage(conf, script, args.toArray(new String[args.size()]), 2221 paramsList.toArray(new String[paramsList.size()]), jobType)); 2222 } 2223 catch (OozieClientException ex) { 2224 throw new OozieCLIException(ex.toString(), ex); 2225 } 2226 } 2227 2228 private void sqoopCommand(CommandLine commandLine) throws IOException, OozieCLIException { 2229 List<String> args = commandLine.getArgList(); 2230 if (args.size() > 0) { 2231 // checking if args starts with -X (because CLIParser cannot check this) 2232 if (!args.get(0).equals("-X")) { 2233 throw new OozieCLIException("Unrecognized option: " + args.get(0) + " Expecting -X"); 2234 } 2235 args.remove(0); 2236 } 2237 2238 if (!commandLine.hasOption(SQOOP_COMMAND_OPTION)) { 2239 throw new OozieCLIException("Need to specify -command"); 2240 } 2241 2242 if (!commandLine.hasOption(CONFIG_OPTION)) { 2243 throw new OozieCLIException("Need to specify -config <configfile>"); 2244 } 2245 2246 try { 2247 XOozieClient wc = createXOozieClient(commandLine); 2248 Properties conf = getConfiguration(wc, commandLine); 2249 String[] command = commandLine.getOptionValues(SQOOP_COMMAND_OPTION); 2250 System.out.println(JOB_ID_PREFIX + wc.submitSqoop(conf, command, args.toArray(new String[args.size()]))); 2251 } 2252 catch (OozieClientException ex) { 2253 throw new OozieCLIException(ex.toString(), ex); 2254 } 2255 } 2256 2257 private void infoCommand(CommandLine commandLine) throws OozieCLIException { 2258 for (Option option : commandLine.getOptions()) { 2259 String opt = option.getOpt(); 2260 if (opt.equals(INFO_TIME_ZONES_OPTION)) { 2261 printAvailableTimeZones(); 2262 } 2263 } 2264 } 2265 2266 private void printAvailableTimeZones() { 2267 System.out.println("The format is \"SHORT_NAME (ID)\"\nGive the ID (GMT, UTC or Region/City)" + 2268 "to the -timezone argument"); 2269 System.out.println("GMT offsets can also be used (e.g. GMT-07:00, GMT-0700, GMT+05:30, GMT+0530)"); 2270 System.out.println("Available Time Zones:"); 2271 for (String tzId : TimeZone.getAvailableIDs()) { 2272 // skip id's that are like "Etc/GMT+01:00" because their display names are like "GMT-01:00", which is confusing 2273 if (!tzId.startsWith("Etc/GMT")) { 2274 TimeZone tZone = TimeZone.getTimeZone(tzId); 2275 System.out.println(" " + tZone.getDisplayName(false, TimeZone.SHORT) + " (" + tzId + ")"); 2276 } 2277 } 2278 } 2279 2280 2281 private void mrCommand(CommandLine commandLine) throws IOException, OozieCLIException { 2282 try { 2283 XOozieClient wc = createXOozieClient(commandLine); 2284 Properties conf = getConfiguration(wc, commandLine); 2285 2286 String mapper = conf.getProperty(MAPRED_MAPPER, conf.getProperty(MAPRED_MAPPER_2)); 2287 if (mapper == null) { 2288 throw new OozieCLIException("mapper (" + MAPRED_MAPPER + " or " + MAPRED_MAPPER_2 + ") must be specified in conf"); 2289 } 2290 2291 String reducer = conf.getProperty(MAPRED_REDUCER, conf.getProperty(MAPRED_REDUCER_2)); 2292 if (reducer == null) { 2293 throw new OozieCLIException("reducer (" + MAPRED_REDUCER + " or " + MAPRED_REDUCER_2 2294 + ") must be specified in conf"); 2295 } 2296 2297 String inputDir = conf.getProperty(MAPRED_INPUT); 2298 if (inputDir == null) { 2299 throw new OozieCLIException("input dir (" + MAPRED_INPUT +") must be specified in conf"); 2300 } 2301 2302 String outputDir = conf.getProperty(MAPRED_OUTPUT); 2303 if (outputDir == null) { 2304 throw new OozieCLIException("output dir (" + MAPRED_OUTPUT +") must be specified in conf"); 2305 } 2306 2307 System.out.println(JOB_ID_PREFIX + wc.submitMapReduce(conf)); 2308 } 2309 catch (OozieClientException ex) { 2310 throw new OozieCLIException(ex.toString(), ex); 2311 } 2312 } 2313 2314 private String getFirstMissingDependencies(CoordinatorAction action) { 2315 StringBuilder allDeps = new StringBuilder(); 2316 String missingDep = action.getMissingDependencies(); 2317 boolean depExists = false; 2318 if (missingDep != null && !missingDep.isEmpty()) { 2319 allDeps.append(missingDep.split(INSTANCE_SEPARATOR)[0]); 2320 depExists = true; 2321 } 2322 String pushDeps = action.getPushMissingDependencies(); 2323 if (pushDeps != null && !pushDeps.isEmpty()) { 2324 if(depExists) { 2325 allDeps.append(INSTANCE_SEPARATOR); 2326 } 2327 allDeps.append(pushDeps.split(INSTANCE_SEPARATOR)[0]); 2328 } 2329 return allDeps.toString(); 2330 } 2331 2332 private void slaAlertCommand(String jobIds, OozieClient wc, CommandLine commandLine, List<String> options) 2333 throws OozieCLIException, OozieClientException { 2334 String actions = null, coordinators = null, dates = null; 2335 2336 if (options.contains(ACTION_OPTION)) { 2337 actions = commandLine.getOptionValue(ACTION_OPTION); 2338 } 2339 2340 if (options.contains(DATE_OPTION)) { 2341 dates = commandLine.getOptionValue(DATE_OPTION); 2342 } 2343 2344 if (options.contains(COORD_OPTION)) { 2345 coordinators = commandLine.getOptionValue(COORD_OPTION); 2346 if (coordinators == null) { 2347 throw new OozieCLIException("No value specified for -coordinator option"); 2348 } 2349 } 2350 2351 if (options.contains(SLA_ENABLE_ALERT)) { 2352 wc.slaEnableAlert(jobIds, actions, dates, coordinators); 2353 } 2354 else if (options.contains(SLA_DISABLE_ALERT)) { 2355 wc.slaDisableAlert(jobIds, actions, dates, coordinators); 2356 } 2357 else if (options.contains(SLA_CHANGE)) { 2358 String newSlaParams = commandLine.getOptionValue(CHANGE_VALUE_OPTION); 2359 wc.slaChange(jobIds, actions, dates, coordinators, newSlaParams); 2360 } 2361 } 2362 2363 private void printMetrics(OozieClient.Metrics metrics) { 2364 System.out.println("COUNTERS"); 2365 System.out.println("--------"); 2366 Map<String, Long> counters = new TreeMap<>(metrics.getCounters()); 2367 for (Map.Entry<String, Long> ent : counters.entrySet()) { 2368 System.out.println(ent.getKey() + " : " + ent.getValue()); 2369 } 2370 System.out.println("\nGAUGES"); 2371 System.out.println("------"); 2372 Map<String, Object> gauges = new TreeMap<>(metrics.getGauges()); 2373 for (Map.Entry<String, Object> ent : gauges.entrySet()) { 2374 System.out.println(ent.getKey() + " : " + ent.getValue()); 2375 } 2376 System.out.println("\nTIMERS"); 2377 System.out.println("------"); 2378 Map<String, OozieClient.Metrics.Timer> timers = new TreeMap<>(metrics.getTimers()); 2379 for (Map.Entry<String, OozieClient.Metrics.Timer> ent : timers.entrySet()) { 2380 System.out.println(ent.getKey()); 2381 System.out.println(ent.getValue()); 2382 } 2383 System.out.println("\nHISTOGRAMS"); 2384 System.out.println("----------"); 2385 Map<String, OozieClient.Metrics.Histogram> histograms = new TreeMap<>(metrics.getHistograms()); 2386 for (Map.Entry<String, OozieClient.Metrics.Histogram> ent : histograms.entrySet()) { 2387 System.out.println(ent.getKey()); 2388 System.out.println(ent.getValue()); 2389 } 2390 } 2391 2392 private void printInstrumentation(OozieClient.Instrumentation instrumentation) { 2393 System.out.println("COUNTERS"); 2394 System.out.println("--------"); 2395 Map<String, Long> counters = new TreeMap<>(instrumentation.getCounters()); 2396 for (Map.Entry<String, Long> ent : counters.entrySet()) { 2397 System.out.println(ent.getKey() + " : " + ent.getValue()); 2398 } 2399 System.out.println("\nVARIABLES"); 2400 System.out.println("---------"); 2401 Map<String, Object> variables = new TreeMap<>(instrumentation.getVariables()); 2402 for (Map.Entry<String, Object> ent : variables.entrySet()) { 2403 System.out.println(ent.getKey() + " : " + ent.getValue()); 2404 } 2405 System.out.println("\nSAMPLERS"); 2406 System.out.println("---------"); 2407 Map<String, Double> samplers = new TreeMap<>(instrumentation.getSamplers()); 2408 for (Map.Entry<String, Double> ent : samplers.entrySet()) { 2409 System.out.println(ent.getKey() + " : " + ent.getValue()); 2410 } 2411 System.out.println("\nTIMERS"); 2412 System.out.println("---------"); 2413 Map<String, OozieClient.Instrumentation.Timer> timers = new TreeMap<>(instrumentation.getTimers()); 2414 for (Map.Entry<String, OozieClient.Instrumentation.Timer> ent : timers.entrySet()) { 2415 System.out.println(ent.getKey()); 2416 System.out.println(ent.getValue()); 2417 } 2418 } 2419}