Migrating Legacy Workflows
Migrating from KaapanaBaseOperator
This section explains how to migrate a processing-container that was previously used with an Airflow operator inheriting from KaapanaBaseOperator to one that works with the new KaapanaTaskOperator.
The KaapanaBaseOperator imposed several implicit conventions that affected how processing-containers interacted with the workflow environment.
In contrast, the KaapanaTaskOperator makes all expectations explicit through the Task API and the processing-container.json file.
The following table summarizes the main differences:
|
|
|---|---|
All workflow directories are mounted into the container. |
Only declared input and output channels are mounted. |
File paths must be constructed from environment variables. |
File paths are always relative to the |
Environment variables for file path construction are set automatically. |
No environment variables are set automatically. |
Variables in |
Variables in |
The most significant difference is how data is mounted into containers.
Legacy Data Mounting (KaapanaBaseOperator)
When using the KaapanaBaseOperator, each container received a generic directory structure that included workflow-level paths and environment variables such as WORKFLOW_DIR, BATCH_NAME, OPERATOR_IN_DIR, and OPERATOR_OUT_DIR.
For example, given the following DAG:
dag = DAG(dag_id="my_dag")
get_input = GetInputOperator(dag=dag)
my_algorithm = MyAlgorithmOperator(dag=dag, input_operator=get_input)
get_input >> my_algorithm
Kaapana automatically mounted the following directory structure in the container of my_algorithm:
└── ${WORKFLOW_DIR}
├── ${BATCH_NAME}
│ ├── item-1
│ │ └── ${OPERATOR_IN_DIR}/input
│ └── item-2
│ └── ${OPERATOR_IN_DIR}/input
└── conf/conf.json
After processing, the resulting structure typically looked like this:
└── ${WORKFLOW_DIR}
├── ${BATCH_NAME}
│ ├── item-1
│ │ ├── ${OPERATOR_IN_DIR}/input
│ │ └── ${OPERATOR_OUT_DIR}/result
│ └── item-2
│ ├── ${OPERATOR_IN_DIR}/input
│ └── ${OPERATOR_OUT_DIR}/result
└── conf/conf.json
Migrated Data Mounting (KaapanaTaskOperator)
When migrating to the KaapanaTaskOperator, data mounts are defined explicitly in the processing-container.json file and linked between tasks using IOMapping objects.
For example, the previous DAG can be migrated as follows:
with DAG("my_dag", default_args=args) as dag:
get_input = KaapanaTaskOperator(
task_id="get_input",
image=f"{DEFAULT_REGISTRY}/get-input:{KAAPANA_BUILD_VERSION}",
taskTemplate="dicom",
)
my_algorithm = KaapanaTaskOperator(
task_id="my_algorithm",
image=f"{DEFAULT_REGISTRY}/my-algorithm:{KAAPANA_BUILD_VERSION}",
taskTemplate="my_algorithm",
iochannel_maps=[
IOMapping(
upstream_operator=get_input,
upstream_output_channel="downloads",
input_channel="inputs",
)
],
)
get_input >> my_algorithm
Note
The upstream_output_channel of the get_input task is downloads.
This is explicitly declared in the corresponding task template in the processing-container.json file of the get-input image.
Following the data structure convention, the directory structure inside the container for my_algorithm now looks similar to this:
└── input-mount-path
│ ├── item-1/input
│ └── item-2/input
└── output-mount-path
├── item-1/result
└── item-2/result
This makes data flow between tasks more explicit and modular, removing hidden assumptions about directory layouts or shared environment variables.