Repository: incubator-airflow
Updated Branches:
  refs/heads/master 82a65eeca -> 0e748ad86


[AIRFLOW-2040] Escape special chars in task instance logs URL

Closes #2982 from cinhil/AIRFLOW-2040


Project: http://git-wip-us.apache.org/repos/asf/incubator-airflow/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-airflow/commit/0e748ad8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-airflow/tree/0e748ad8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-airflow/diff/0e748ad8

Branch: refs/heads/master
Commit: 0e748ad86af7ed76ecaedeb1ca3eab3955ad5a7c
Parents: 82a65ee
Author: Fabrice <[email protected]>
Authored: Mon Feb 5 16:31:02 2018 +0100
Committer: Fokko Driesprong <[email protected]>
Committed: Mon Feb 5 16:31:02 2018 +0100

----------------------------------------------------------------------
 airflow/models.py |  6 +++---
 tests/models.py   | 25 +++++++++++++++++++++++++
 2 files changed, 28 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-airflow/blob/0e748ad8/airflow/models.py
----------------------------------------------------------------------
diff --git a/airflow/models.py b/airflow/models.py
index 4b95068..9854213 100755
--- a/airflow/models.py
+++ b/airflow/models.py
@@ -47,7 +47,7 @@ import warnings
 import hashlib
 
 from datetime import datetime
-from urllib.parse import urlparse
+from urllib.parse import urlparse, quote
 
 from sqlalchemy import (
     Column, Integer, String, DateTime, Text, Boolean, ForeignKey, PickleType,
@@ -994,7 +994,7 @@ class TaskInstance(Base, LoggingMixin):
 
     @property
     def log_url(self):
-        iso = self.execution_date.isoformat()
+        iso = quote(self.execution_date.isoformat())
         BASE_URL = configuration.get('webserver', 'BASE_URL')
         return BASE_URL + (
             "/admin/airflow/log"
@@ -1005,7 +1005,7 @@ class TaskInstance(Base, LoggingMixin):
 
     @property
     def mark_success_url(self):
-        iso = self.execution_date.isoformat()
+        iso = quote(self.execution_date.isoformat())
         BASE_URL = configuration.get('webserver', 'BASE_URL')
         return BASE_URL + (
             "/admin/airflow/action"

http://git-wip-us.apache.org/repos/asf/incubator-airflow/blob/0e748ad8/tests/models.py
----------------------------------------------------------------------
diff --git a/tests/models.py b/tests/models.py
index 6586177..17a9043 100644
--- a/tests/models.py
+++ b/tests/models.py
@@ -25,6 +25,7 @@ import unittest
 import time
 import six
 import re
+import urllib
 
 from airflow import configuration, models, settings, AirflowException
 from airflow.exceptions import AirflowSkipException
@@ -1479,6 +1480,30 @@ class TaskInstanceTest(unittest.TestCase):
         self.assertEquals(1, 
ti2.get_num_running_task_instances(session=session))
         self.assertEquals(1, 
ti3.get_num_running_task_instances(session=session))
 
+    def test_log_url(self):
+        now = pendulum.now('Europe/Brussels')
+        dag = DAG('dag', start_date=DEFAULT_DATE)
+        task = DummyOperator(task_id='op', dag=dag)
+        ti = TI(task=task, execution_date=now)
+        d = urllib.parse.parse_qs(
+            urllib.parse.urlparse(ti.log_url).query,
+            keep_blank_values=True, strict_parsing=True)
+        self.assertEqual(d['dag_id'][0], 'dag')
+        self.assertEqual(d['task_id'][0], 'op')
+        self.assertEqual(pendulum.parse(d['execution_date'][0]), now)
+
+    def test_mark_success_url(self):
+        now = pendulum.now('Europe/Brussels')
+        dag = DAG('dag', start_date=DEFAULT_DATE)
+        task = DummyOperator(task_id='op', dag=dag)
+        ti = TI(task=task, execution_date=now)
+        d = urllib.parse.parse_qs(
+            urllib.parse.urlparse(ti.mark_success_url).query,
+            keep_blank_values=True, strict_parsing=True)
+        self.assertEqual(d['dag_id'][0], 'dag')
+        self.assertEqual(d['task_id'][0], 'op')
+        self.assertEqual(pendulum.parse(d['execution_date'][0]), now)
+
 
 class ClearTasksTest(unittest.TestCase):
     def test_clear_task_instances(self):

Reply via email to