jason810496 commented on code in PR #61833:
URL: https://github.com/apache/airflow/pull/61833#discussion_r2828451399
##########
airflow-core/src/airflow/api_fastapi/core_api/routes/public/backfills.py:
##########
@@ -252,6 +252,11 @@ def create_backfill(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Could not find dag {backfill_request.dag_id}",
)
+ except DagRunTypeNotAllowed as e:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
Review Comment:
We need to update the `create_openapi_http_exception_doc` for the route
definition.
##########
task-sdk/src/airflow/sdk/definitions/dag.py:
##########
@@ -590,6 +610,29 @@ def _validate_tags(self, _, tags: Collection[str]):
if tags and any(len(tag) > TAG_MAX_LEN for tag in tags):
raise ValueError(f"tag cannot be longer than {TAG_MAX_LEN}
characters")
+ @allowed_run_types.validator
+ def _validate_allowed_run_types(self, _, allowed_run_types):
+ if not allowed_run_types:
+ return
+ from airflow.sdk.api.datamodels._generated import DagRunType
+
+ if isinstance(self.timetable, AssetTriggeredTimetable):
+ if DagRunType.ASSET_TRIGGERED not in allowed_run_types:
+ raise ValueError(
+ "allowed_run_types must include ASSET_TRIGGERED when the
DAG is scheduled by assets"
+ )
+ elif self.timetable.can_be_scheduled:
+ if DagRunType.SCHEDULED not in allowed_run_types:
+ raise ValueError(
+ "allowed_run_types must include SCHEDULED when the DAG has
a schedule defined"
+ )
+ else:
+ if DagRunType.MANUAL not in allowed_run_types:
+ raise ValueError(
+ "allowed_run_types must include MANUAL when the DAG "
Review Comment:
```suggestion
"allowed_run_types must include ASSET_TRIGGERED when the
Dag is scheduled by assets"
)
elif self.timetable.can_be_scheduled:
if DagRunType.SCHEDULED not in allowed_run_types:
raise ValueError(
"allowed_run_types must include SCHEDULED when the Dag
has a schedule defined"
)
else:
if DagRunType.MANUAL not in allowed_run_types:
raise ValueError(
"allowed_run_types must include MANUAL when the Dag "
```
##########
airflow-core/src/airflow/ui/public/i18n/locales/en/components.json:
##########
@@ -130,6 +130,7 @@
"intervalStart": "Start",
"loading": "Loading Dag information...",
"loadingFailed": "Failed to load Dag information. Please try again.",
+ "manualRunDenied": "Manual runs are not allowed for this DAG",
Review Comment:
```suggestion
"manualRunDenied": "Manual runs are not allowed for this Dag",
```
##########
airflow-core/src/airflow/api_fastapi/execution_api/routes/dag_runs.py:
##########
@@ -112,6 +112,17 @@ def trigger_dag_run(
},
)
+ # TODO: TriggerDagRunOperator also calls this route but creates MANUAL
runs.
+ # Consider a dedicated run type for operator-triggered runs.
+ if dm.allowed_run_types is not None and DagRunType.MANUAL not in
dm.allowed_run_types:
+ raise HTTPException(
+ status.HTTP_400_BAD_REQUEST,
Review Comment:
We need to update the description of `HTTP_400_BAD_REQUEST` about
`denied_run_type`.
##########
airflow-core/src/airflow/api_fastapi/core_api/routes/public/assets.py:
##########
@@ -403,6 +403,13 @@ def materialize_asset(
)
dag = get_latest_version_of_dag(dag_bag, dag_id, session)
+
+ if dag.allowed_run_types is not None and DagRunType.MANUAL not in
dag.allowed_run_types:
+ raise HTTPException(
+ status.HTTP_400_BAD_REQUEST,
Review Comment:
Same here.
##########
airflow-core/src/airflow/migrations/versions/0104_3_2_0_add_allowed_run_types_to_dag.py:
##########
@@ -0,0 +1,50 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Add allowed_run_types to dag.
+
+Revision ID: e42d9fcd10d9
+Revises: f8c9d7e6b5a4
+Create Date: 2026-02-12 11:49:40.753440
+
+"""
+
+from __future__ import annotations
+
+import sqlalchemy as sa
+from alembic import op
+
+# revision identifiers, used by Alembic.
+revision = "e42d9fcd10d9"
+down_revision = "f8c9d7e6b5a4"
+branch_labels = None
+depends_on = None
+airflow_version = "3.2.0"
+
+
+def upgrade():
+ """Add allowed_run_types column to dag table."""
+ with op.batch_alter_table("dag", schema=None) as batch_op:
+ batch_op.add_column(sa.Column("allowed_run_types", sa.JSON(),
nullable=True))
Review Comment:
I had the same thought as Ash during last review, maybe we could track this
in a new issue about the ARRAY <-> JSON trade-off for list-type columns.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]