diff --git a/airflow/www/templates/airflow/dag.html b/airflow/www/templates/airflow/dag.html index adb2d387da443..9ef4cce5c1c46 100644 --- a/airflow/www/templates/airflow/dag.html +++ b/airflow/www/templates/airflow/dag.html @@ -100,6 +100,13 @@

Refresh +
  • + + + Delete + +

  • @@ -302,6 +309,12 @@

    DAGs

    + + + + + {% endfor %} @@ -244,6 +250,12 @@

    DAGs

    function confirmTriggerDag(dag_id){ return confirm("Are you sure you want to run '"+dag_id+"' now?"); } + + function confirmDeleteDag(dag_id){ + return confirm("Are you sure you want to delete '"+dag_id+"' now?\n\ + This option will delete ALL metadata, DAG runs, etc.\n\ + This cannot be undone."); + } all_dags = $("[id^=toggle]"); $.each(all_dags, function(i,v) { $(v).change (function() { diff --git a/airflow/www/views.py b/airflow/www/views.py index c8baa5c06251f..5c0c9730c7387 100644 --- a/airflow/www/views.py +++ b/airflow/www/views.py @@ -1044,6 +1044,32 @@ def run(self): "it should start any moment now.".format(ti)) return redirect(origin) + @expose('/delete') + @login_required + @wwwutils.action_logging + @wwwutils.notify_owner + def delete(self): + from airflow.api.common.experimental import delete_dag + from airflow.exceptions import DagNotFound, DagFileExists + + dag_id = request.args.get('dag_id') + origin = request.args.get('origin') or "/admin/" + + try: + delete_dag.delete_dag(dag_id) + except DagNotFound: + flash("DAG with id {} not found. Cannot delete".format(dag_id)) + return redirect(request.referrer) + except DagFileExists: + flash("Dag id {} is still in DagBag. " + "Remove the DAG file first.".format(dag_id)) + return redirect(request.referrer) + + flash("Deleting DAG with id {}. May take a couple minutes to fully" + " disappear.".format(dag_id)) + # Upon successful delete return to origin + return redirect(origin) + @expose('/trigger') @login_required @wwwutils.action_logging @@ -1283,6 +1309,10 @@ def tree(self, session=None): dag_id = request.args.get('dag_id') blur = conf.getboolean('webserver', 'demo_mode') dag = dagbag.get_dag(dag_id) + if dag_id not in dagbag.dags: + flash('DAG "{0}" seems to be missing.'.format(dag_id), "error") + return redirect('/admin/') + root = request.args.get('root') if root: dag = dag.sub_dag( diff --git a/airflow/www_rbac/templates/airflow/dag.html b/airflow/www_rbac/templates/airflow/dag.html index eb449085023b9..e6495fe4be9da 100644 --- a/airflow/www_rbac/templates/airflow/dag.html +++ b/airflow/www_rbac/templates/airflow/dag.html @@ -99,6 +99,13 @@

    Refresh +
  • + + + Delete + +

  • @@ -300,6 +307,12 @@

    DAGs

    + + + + {% endfor %} @@ -242,6 +247,12 @@

    DAGs

    window.location = DAGS_INDEX + "?page_size=" + p_size; }); + function confirmDeleteDag(dag_id){ + return confirm("Are you sure you want to delete '"+dag_id+"' now?\n\ + This option will delete ALL metadata, DAG runs, etc.\n\ + This cannot be undone."); + } + function confirmTriggerDag(dag_id){ return confirm("Are you sure you want to run '"+dag_id+"' now?"); } diff --git a/airflow/www_rbac/views.py b/airflow/www_rbac/views.py index 91bd1770a828f..78f9799f16b04 100644 --- a/airflow/www_rbac/views.py +++ b/airflow/www_rbac/views.py @@ -728,6 +728,32 @@ def run(self): "it should start any moment now.".format(ti)) return redirect(origin) + @expose('/delete') + @action_logging + @has_access + def delete(self): + from airflow.api.common.experimental import delete_dag + from airflow.exceptions import DagNotFound, DagFileExists + + dag_id = request.args.get('dag_id') + origin = request.args.get('origin') or "/" + + try: + delete_dag.delete_dag(dag_id) + except DagNotFound: + flash("DAG with id {} not found. Cannot delete".format(dag_id)) + return redirect(request.referrer) + except DagFileExists: + flash("Dag id {} is still in DagBag. " + "Remove the DAG file first.".format(dag_id)) + return redirect(request.referrer) + + flash("Deleting DAG with id {}. May take a couple minutes to fully" + " disappear.".format(dag_id)) + + # Upon success return to origin. + return redirect(origin) + @expose('/trigger') @has_access @action_logging @@ -961,6 +987,10 @@ def tree(self, session=None): dag_id = request.args.get('dag_id') blur = conf.getboolean('webserver', 'demo_mode') dag = dagbag.get_dag(dag_id) + if dag_id not in dagbag.dags: + flash('DAG "{0}" seems to be missing.'.format(dag_id), "error") + return redirect('/') + root = request.args.get('root') if root: dag = dag.sub_dag(