Package: o2a-potiuk
Oozie to AirflowA tool to easily convert betweenApache Oozieworkflows
andApache Airflowworkflows.The program targets Apache Airflow >= 1.10 and Apache Oozie 1.0 XML schema.If you want to contribute to the project, please take a look atCONTRIBUTING.mdTable of ContentsOozie to AirflowTable of ContentsBackgroundRunning the ProgramRequired Python DependenciesRunning the conversionStructure of the application folderSupported Oozie featuresControl nodesForkJoinDecisionStartEndKillKnown LimitationsEL FunctionsExamplesDemo ExampleCurrent limitationsOutputChildwf ExampleOutputCurrent limitationsSSH ExampleOutputCurrent limitationsMapReduce ExampleOutputCurrent limitationsFS ExampleOutputCurrent limitationsPig ExampleOutputCurrent limitationsShell ExampleOutputCurrent limitationsSpark ExampleOutputCurrent limitationsSub-workflow ExampleOutputCurrent limitationsDecision ExampleOutputCurrent limitationsEL ExampleOutputCurrent limitationsCreated bygh-md-tocBackgroundApache Airflow is a workflow management system developed by AirBnB in 2014.
It is a platform to programmatically author, schedule, and monitor workflows.
Airflow workflows are designed asDirected Acyclic Graphs(DAGs) of tasks in Python. The Airflow scheduler executes your tasks on an array of
workers while following the specified dependencies.Apache Oozie is a workflow scheduler system to manage Apache Hadoop jobs.
Oozie workflows are also designed asDirected Acyclic Graphs(DAGs) in XML.There are a few differences noted below:Spec.TaskDependencies"Subworkflows"ParameterizationNotificationOozieXMLAction NodeControl NodeSubworkflowEL functions/Properties fileURL based callbacksAirflowPythonOperatorsTrigger Rules, set_downstream()SubDagjinja2 and macrosCallbacks/EmailsRunning the ProgramRequired Python DependenciesPython >= 3.6Seerequirements.txtAdditionally the shell script included in the directory,init.sh, can
be executed to set up the dependencies and have your local machine ready to convert the examples.# Allow init.sh to execute$chmod+xinit.sh# Execute init.sh$./init.shAdding bin directory to your PATHYou can add thebinsubdirectory to your PATH, then all the scripts below can be run without adding
bin path.You can do it for example by adding similar line to your.bash_profileorbin/postactivatefrom your virtual environment:exportPATH=${PATH}:<INSERT_PATH_TO_YOUR_OOZIE_PROJECT>/binOtherwise you need to run them from the bin subdirectory - prepending it with the path, for example:./bin/o2a--helpIn all the examples below it is assumed that thebindirectory is in your PATH.Running the conversionYou can run the program (minimally) by calling:o2a -i <INPUT_APPLICATION_FOLDER> -o <OUTPUT_FOLDER_PATH>Example:o2a -i examples/demo -o output/demoThis is the full usage guide, available by runningo2a -husage: o2a [-h] -i INPUT_DIRECTORY_PATH -o OUTPUT_DIRECTORY_PATH [-d DAG_NAME]
           [-u USER] [-s START_DAYS_AGO] [-v SCHEDULE_INTERVAL]

Convert Apache Oozie workflows to Apache Airflow workflows.

optional arguments:
  -h, --help            show this help message and exit
  -i INPUT_DIRECTORY_PATH, --input-directory-path INPUT_DIRECTORY_PATH
                        Path to input directory
  -o OUTPUT_DIRECTORY_PATH, --output-directory-path OUTPUT_DIRECTORY_PATH
                        Desired output directory
  -d DAG_NAME, --dag-name DAG_NAME
                        Desired DAG name [defaults to input directory name]
  -u USER, --user USER  The user to be used in place of all ${user.name}
                        [defaults to user who ran the conversion]
  -s START_DAYS_AGO, --start-days-ago START_DAYS_AGO
                        Desired DAG start as number of days ago
  -v SCHEDULE_INTERVAL, --schedule-interval SCHEDULE_INTERVAL
                        Desired DAG schedule interval as number of daysStructure of the application folderThe application folder has to follow the structure defined as follows:<APPLICATION>/
             |- job.properties        - job properties that are used to run the job
             |- hdfs                  - folder with application - should be copied to HDFS
             |     |- workflow.xml    - Oozie workflow xml (1.0 schema)
             |     |- ...             - additional folders required to be copied to HDFS
             |- configuration.template.properties - template of configuration values used during conversion
             |- configuration.properties          - generated properties for configuration valuesSupported Oozie featuresControl nodesForkAfork nodesplits the path of execution into multiple concurrent paths of execution.JoinAjoin nodewaits until every concurrent execution of the previous fork node arrives to it. The fork and join nodes must be used in pairs. The join node
assumes concurrent execution paths are children of the same fork node.<workflow-app name="[WF-DEF-NAME]" xmlns="uri:oozie:workflow:0.1">
    ...
    <fork name="[FORK-NODE-NAME]">
        <path start="[NODE-NAME]" />
        ...
        <path start="[NODE-NAME]" />
    </fork>
    ...
    <join name="[JOIN-NODE-NAME]" to="[NODE-NAME]" />
    ...
</workflow-app>DecisionAdecision nodeenables a workflow to make a selection on the execution path to follow.The behavior of a decision node can be seen as a switch-case statement.A decision node consists of a list of predicates-transition pairs plus a default transition. Predicates are evaluated in order or appearance until one of them evaluates to true and the corresponding transition is taken. If none of the predicates evaluates to true the default transition is taken.Predicates are JSP Expression Language (EL) expressions (refer to section 4.2 of this document) that resolve into a boolean value, true or false . For example:${fs:fileSize('/usr/foo/myinputdir') gt 10 * GB}<workflow-app name="[WF-DEF-NAME]" xmlns="uri:oozie:workflow:0.1">
    ...
    <decision name="[NODE-NAME]">
        <switch>
            <case to="[NODE_NAME]">[PREDICATE]</case>
            ...
            <case to="[NODE_NAME]">[PREDICATE]</case>
            <default to="[NODE_NAME]"/>
        </switch>
    </decision>
    ...
</workflow-app>StartThestart nodeis the entry point for a workflow job, it indicates the first workflow node the workflow job must transition to.When a workflow is started, it automatically transitions to the node specified in the start .A workflow definition must have one start node.<workflow-app name="[WF-DEF-NAME]" xmlns="uri:oozie:workflow:0.1">
  ...
  <start to="[NODE-NAME]"/>
  ...
</workflow-app>EndTheend nodeis the end for a workflow job, it indicates that the workflow job has completed successfully.When a workflow job reaches the end it finishes successfully (SUCCEEDED).If one or more actions started by the workflow job are executing when the end node is reached, the actions will be killed. In this scenario the workflow job is still considered as successfully run.A workflow definition must have one end node.<workflow-app name="[WF-DEF-NAME]" xmlns="uri:oozie:workflow:0.1">
    ...
    <end name="[NODE-NAME]"/>
    ...
</workflow-app>KillThekill nodeallows a workflow job to exit with an error.When a workflow job reaches the kill it finishes in error (KILLED).If one or more actions started by the workflow job are executing when the kill node is reached, the actions will be killed.A workflow definition may have zero or more kill nodes.<workflow-app name="[WF-DEF-NAME]" xmlns="uri:oozie:workflow:0.1">
    ...
    <kill name="[NODE-NAME]">
        <message>[MESSAGE-TO-LOG]</message>
    </kill>
    ...
</workflow-app>Known LimitationsThe goal of this program is to mimic both the actions and control flow
that is outlined by the Oozie workflow file. Unfortunately there are some
limitations as of now that have not been worked around regarding the execution
flow. The situation where the execution path might not execute correctly is when
there are 4 nodes, A, B, C, D, with the following Oozie specified execution paths:A executes ok to C
B executes error to C

A executes error to D
B executes ok to DIn this situation Airflow does not have enough fine grained node execution control.
The converter should be able to handle this situation in the future, but it is not
currently guaranteed to work.This is because if goes from A to C on ok, and B goes to C on error, C's trigger rule
will have to be set toDUMMY, but this means that if A goes to error, and B goes to ok
C will then execute incorrectly.This limitation is temporary and will be removed in a future version of Oozie-2-Airflow converter.EL FunctionsAs of now, a very minimal set ofOozie ELfunctions are supported. The way they work is that there exists a
dictionary mapping from each Oozie EL function string to the
corresponding Python function. This is inutils/el_utils.py.
This design allows for custom EL function mapping if one so chooses. By
default everything gets mapped to the moduleo2a_libs. This means in
order to use EL function mapping, the foldero2a_libsshould
be copied over to the Airflow DAG folder. This should then be picked up and
parsed by the Airflow workers and then available to all DAGs.ExamplesAll examples can be found in theexamplesdirectory.DemoSSHMapReducePigShellSub-workflowDecisionELDemo ExampleThe demo example contains several action and control nodes. The control
nodes arefork,join,decision,start,end, andkill. As far as action
nodes go, there arefs,map-reduce, andpig.Most of these are already supported, but when the program encounters a node it does
not know how to parse, it will perform a sort of "skeleton transformation" -
it will convert all the unknown nodes to dummy nodes. This will
allow users to manually parse the nodes if they so wish as the control flow
is there.The demo can be run as:o2a -i examples/demo -o output/demoThis will parse and write to an output file in theoutput/demodirectory.Current limitationsThe decision node is not fully functional as there is not currently
support for all EL functions. So in order for it to run in Airflow you must
edit the Python output file and change the decision node expression.OutputIn this example the output will appear in/output/ssh/test_demo_dag.py.
Additionally subworkflow is generated in/output/ssh/subdag_test.py.Childwf ExampleThe childwf example is sub-workflow for thedemoexample. It can be run as:o2a -i examples/childwf -o output/childwfMake sure to first copyexamples/subwf/configuration.template.properties, rename it asconfiguration.propertiesand fill in with configuration data.OutputIn this example the output will appear inoutput/childwf/test_childwf_dag.py.Current limitationsNo known limitations.SSH ExampleThe ssh example can be run as:o2a -i examples/ssh -o output/sshThis will convert the specified Oozie XML and write the output into the
specified output directory, in this caseoutput/ssh/test_ssh_dag.py.There are some differences between Apache Oozie and Apache Airflow as far as the SSH specification goes.
In Airflow you will have to add/edit an SSH-specific connection that contains
the credentials required for the specified SSH action. For example, if
the SSH node looks like:<actionname="ssh"><sshxmlns="uri:oozie:ssh-action:0.1"><host>user@apache.org</host><command>echo</command><args>"HelloOozie!"</args></ssh><okto="end"/><errorto="fail"/></action>Then the default Airflow SSH connection,ssh_defaultshould have at
the very least a password set. This can be found in the Airflow Web UI
underAdmin > Connections. From the command line it is impossible to
edit connections so you must add one like:airflow connections --add --conn_id <SSH_CONN_ID> --conn_type SSH --conn_password <PASSWORD>More information can be found inAirflow's documentation.OutputIn this example the output will appear in/output/ssh/test_ssh_dag.py.The converted DAG uses theSSHOperatorin Airflow.Current limitationsNo known limitations.MapReduce ExampleThe MapReduce example can be run as:o2a -i examples/mapreduce -o output/mapreduceMake sure to first copyexamples/mapreduce/configuration.template.properties, rename it asconfiguration.propertiesand fill in with configuration data.OutputIn this example the output will appear in/output/mapreduce/test_mapreduce_dag.py.The converted DAG uses theDataProcHadoopOperatorin Airflow.Current limitations1. Exit status not availableFrom theOozie documentation:The counters of the Hadoop job and job exit status (FAILED, KILLED or SUCCEEDED) must be available to the
workflow job after the Hadoop jobs ends. This information can be used from within decision nodes and other
actions configurations.Currently we use theDataProcHadoopOperatorwhich does not store the job exit status in an XCOM for other tasks to use.2. Configuration optionsFrom theOozie documentation(the strikethrough is from us):Hadoop JobConf properties can be specified as part ofthe config-default.xml orJobConf XML file bundled with the workflow application or<global> tag in workflow definition orInline map-reduce action configuration orAn implementation of OozieActionConfigurator specified by the  tag in workflow definition.Currently the only supported way of configuring the map-reduce action is with the
inline action configuration, i.e. using the<configuration>tag in the workflow's XML file definition.3. Streaming and pipesStreaming and pipes are currently not supported.FS ExampleThe FS example can be run as:o2a -i examples/fs -o output/fsMake sure to first copyexamples/fs/configuration.template.properties, rename it asconfiguration.propertiesand fill in with configuration data.OutputIn this example the output will appear in/output/fs/test_fs_dag.py.The converted DAG uses theBashOperatorin Airflow.Current limitationsNot all FS operations are currently idempotent. This will be fixed.Pig ExampleThe Pig example can be run as:o2a -i examples/pig -o output/pigMake sure to first copyexamples/pig/configuration.template.properties, rename it asconfiguration.propertiesand fill in with configuration data.OutputIn this example the output will appear inoutput/pig/test_pig_dag.py.The converted DAG uses theDataProcPigOperatorin Airflow.Current limitations1. Configuration optionsFrom theOozie documentation(the strikethrough is from us):Hadoop JobConf properties can be specified as part ofthe config-default.xml orJobConf XML file bundled with the workflow application or<global> tag in workflow definition orInline pig action configuration.Currently the only supported way of configuring the pig action is with the
inline action configuration, i.e. using the<configuration>tag in the workflow's XML file definition.Shell ExampleThe Shell example can be run as:o2a -i examples/shell -o output/shellMake sure to first copyexamples/shell/configuration.template.properties, rename it asconfiguration.propertiesand fill in with configuration data.OutputIn this example the output will appear inoutput/shell/test_shell_dag.py.The converted DAG uses theBashOperatorin Airflow, which executes the desired shell
action with Pig by invokinggcloud dataproc jobs submit pig --cluster=<cluster> --region=<region> --execute 'sh <action> <args>'.Current limitations1. Exit status not availableFrom theOozie documentation:The output (STDOUT) of the Shell job can be made available to the workflow job after the Shell job ends.
This information could be used from within decision nodes.Currently we use theBashOperatorwhich can store only the last line of the job output in an XCOM.
In this case the line is not helpful as it relates to the Dataproc job submission status and
not the Shell action's result.2. No Shell launcher configurationFrom theOozie documentation:Shell launcher configuration can be specified with a file, using the job-xml element, and inline,
using the configuration elements.Currently there is no way specify the shell launcher configuration (it is ignored).Spark ExampleThe Shell example can be run as:o2a -i examples/spark -o output/sparkMake sure to first copy/examples/spark/configuration.template.properties, rename it asconfiguration.propertiesand fill in with configuration data.OutputIn this example the output will appear in/output/spark/spark.py.The converted DAG uses theDataProcSparkOperatorin Airflow.Current limitations1. Ony tasks written in Java are supportedFrom theOozie documentation:The jar element indicates a comma separated list of jars or python files.The solution was tested with only a single Jar file.2. No Spark launcher configurationFrom theOozie documentation:Shell launcher configuration can be specified with a file, using the job-xml element, and inline,
using the configuration elements.Currently there is no way to specify the Spark launcher configuration (it is ignored).3. Not all elements are supportedThe following elements are not supported:job-tracker,name-node,master,mode.Sub-workflow ExampleThe Sub-workflow example can be run as:o2a -i examples/subwf -o output/subwfMake sure to first copyexamples/subwf/configuration.template.properties, rename it asconfiguration.propertiesand fill in with configuration data.OutputIn this example the output will appear inoutput/subwf/test_subwf_dag.py.
Additionally, asubdag_test.py(name to be changed soon) file is generated in the same directory,
which contains the factory methodsub_dag()returning the actual Airflow subdag.The converted DAG uses theSubDagOperatorin Airflow.Current limitationsCurrently generated name of the sub-workflow is fixed which means that only one subworkflow is supported
per DAG folder. This will be fixed soon.Decision ExampleThe decision example can be run as:o2a -i examples/decision -o output/decisionMake sure to first copyexamples/decision/configuration.template.properties, rename it asconfiguration.propertiesand fill in with configuration data.OutputIn this example the output will appear inoutput/decision/test_decision_dag.py.The converted DAG uses theBranchPythonOperatorin Airflow.Current limitationsDecision example is not yet fully functional as EL functions are not yet fully implemented so condition is
hard-coded for now. Once EL functions are implemented, the condition in the example will be updated.EL ExampleThe Oozie Expression Language (EL) example can be run as:o2a -i examples/el -o output/elThis will showcase the ability to use theo2a_libsdirectory to map EL functions
to Python methods. This example assumes that the user has a valid Apache Airflow
SSH connection set up and theo2a_libsdirectory has been copied to the dags
folder.Please keep in mind that as of the current version only a single EL variable
or single EL function. Variable/function chaining is not currently supported.OutputIn this example the output will appear inoutput/el/test_el_dag.py.Current limitationsDecision example is not yet fully functional as EL functions are not yet fully implemented so condition is
hard-coded for now. Once EL functions are implemented, the condition in the example will be updated.