рдкреНрд░рд╛рдпреЛрдЧрд┐рдХ API рд╡рд╛рдкрд░реВрди рдПрдЕрд░рдлреНрд▓реЛрдордзреНрдпреЗ DAG рдЯреНрд░рд┐рдЧрд░ рдХрд╕рд╛ рдмрдирд╡рд╛рдпрдЪрд╛

рдЖрдордЪреЗ рд╢реИрдХреНрд╖рдгрд┐рдХ рдХрд╛рд░реНрдпрдХреНрд░рдо рддрдпрд╛рд░ рдХрд░рддрд╛рдирд╛, рдЖрдореНрд╣рд╛рд▓рд╛ рдард░рд╛рд╡рд┐рдХ рд╕рд╛рдзрдирд╛рдВрд╕рд╣ рдХрд╛рдо рдХрд░рддрд╛рдирд╛ рд╡реЗрд│реЛрд╡реЗрд│реА рдЕрдбрдЪрдгреА рдпреЗрддрд╛рдд. рдЖрдгрд┐ рдпрд╛ рдХреНрд╖рдгреА рдЬреЗрд╡реНрд╣рд╛ рдЖрдореНрд╣реА рддреНрдпрд╛рдВрдЪрд╛ рд╕рд╛рдордирд╛ рдХрд░рддреЛ рддреЗрд╡реНрд╣рд╛ рдиреЗрд╣рдореАрдЪ рдкреБрд░реЗрд╕реЗ рджрд╕реНрддрдРрд╡рдЬ рдЖрдгрд┐ рд▓реЗрдЦ рдирд╕рддрд╛рдд рдЬреЗ рдЖрдореНрд╣рд╛рд▓рд╛ рдпрд╛ рд╕рдорд╕реНрдпреЗрдЪрд╛ рд╕рд╛рдордирд╛ рдХрд░рдгреНрдпрд╛рд╕ рдорджрдд рдХрд░рддреАрд▓.

рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, 2015 рдордзреНрдпреЗ рд╣реА рдкрд░рд┐рд╕реНрдерд┐рддреА рд╣реЛрддреА рдЖрдгрд┐ тАЬрдмрд┐рдЧ рдбреЗрдЯрд╛ рд╕реНрдкреЗрд╢рд▓рд┐рд╕реНрдЯтАЭ рдкреНрд░реЛрдЧреНрд░рд╛рдо рджрд░рдореНрдпрд╛рди рдЖрдореНрд╣реА рдПрдХрд╛рдЪ рд╡реЗрд│реА 35 рд╡рд╛рдкрд░рдХрд░реНрддреНрдпрд╛рдВрд╕рд╛рдареА рд╕реНрдкрд╛рд░реНрдХрд╕рд╣ рд╣реЕрдбреВрдк рдХреНрд▓рд╕реНрдЯрд░ рд╡рд╛рдкрд░рд▓рд╛. рдпрд╛рд░реНрди рд╡рд╛рдкрд░реВрди рдЕрд╢рд╛ рд╡рд╛рдкрд░рд╛рдЪреНрдпрд╛ рдХреЗрд╕рд╕рд╛рдареА рддреЗ рдХрд╕реЗ рддрдпрд╛рд░ рдХрд░рд╛рдпрдЪреЗ рддреЗ рд╕реНрдкрд╖реНрдЯ рдирд╡реНрд╣рддреЗ. рд╢реЗрд╡рдЯреА, рддреЗ рд╢реЛрдзреВрди рдХрд╛рдврд▓реЗ рдЖрдгрд┐ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ рдорд╛рд░реНрдЧрд╛рд╡рд░ рдЪрд╛рд▓рдд рдЧреЗрд▓реЛ Habr├й рд╡рд░ рдкреЛрд╕реНрдЯ рдЖрдгрд┐ рдпреЗрдереЗ рджреЗрдЦреАрд▓ рд╕рд╛рджрд░ рдХреЗрд▓реЗ рдореЙрд╕реНрдХреЛ рд╕реНрдкрд╛рд░реНрдХ рдореАрдЯрдЕрдк.

prehistory

рдпрд╛рд╡реЗрд│реА рдЖрдкрдг рдПрдХрд╛ рд╡реЗрдЧрд│реНрдпрд╛ рдХрд╛рд░реНрдпрдХреНрд░рдорд╛рдмрджреНрджрд▓ рдмреЛрд▓реВ - рдбреЗрдЯрд╛ рдЗрдВрдЬрд┐рдирд┐рдпрд░. рдЖрдордЪреЗ рд╕рд╣рднрд╛рдЧреА рддреНрдпрд╛рд╡рд░ рджреЛрди рдкреНрд░рдХрд╛рд░рдЪреЗ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рддрдпрд╛рд░ рдХрд░рддрд╛рдд: рд▓реЕрдореНрдмрдбрд╛ рдЖрдгрд┐ рдХрдкреНрдкрд╛. рдЖрдгрд┐ lamdba рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░рдордзреНрдпреЗ, рдмреЕрдЪ рдкреНрд░рдХреНрд░рд┐рдпреЗрдЪрд╛ рдПрдХ рднрд╛рдЧ рдореНрд╣рдгреВрди, HDFS рд╡рд░реВрди рдХреНрд▓рд┐рдХрд╣рд╛рдКрд╕рдордзреНрдпреЗ рд▓реЙрдЧ рд╣рд╕реНрддрд╛рдВрддрд░рд┐рдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдПрдЕрд░рдлреНрд▓реЛрдЪрд╛ рд╡рд╛рдкрд░ рдХреЗрд▓рд╛ рдЬрд╛рддреЛ.

рд╕рд░реНрд╡ рдХрд╛рд╣реА рд╕рд╛рдзрд╛рд░рдгрдкрдгреЗ рдЪрд╛рдВрдЧрд▓реЗ рдЖрд╣реЗ. рддреНрдпрд╛рдВрдирд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдмрд╛рдВрдзреВ рджреНрдпрд╛. рддрдерд╛рдкрд┐, рддреЗрдереЗ рдПрдХ "рдкрдг" рдЖрд╣реЗ: рдЖрдордЪреЗ рд╕рд░реНрд╡ рдХрд╛рд░реНрдпрдХреНрд░рдо рд╣реЗ рд╢рд┐рдХрдгреНрдпрд╛рдЪреНрдпрд╛ рдкреНрд░рдХреНрд░рд┐рдпреЗрдЪреНрдпрд╛ рджреГрд╖реНрдЯрд┐рдХреЛрдирд╛рддреВрди рддрд╛рдВрддреНрд░рд┐рдХрджреГрд╖реНрдЯреНрдпрд╛ рдкреНрд░рдЧрдд рдЖрд╣реЗрдд. рд▓реЕрдм рддрдкрд╛рд╕рдгреНрдпрд╛рд╕рд╛рдареА, рдЖрдореНрд╣реА рд╕реНрд╡рдпрдВрдЪрд▓рд┐рдд рдЪреЗрдХрд░реНрд╕ рд╡рд╛рдкрд░рддреЛ: рд╕рд╣рднрд╛рдЧреАрд▓рд╛ рддреНрдпрд╛рдЪреНрдпрд╛ рд╡реИрдпрдХреНрддрд┐рдХ рдЦрд╛рддреНрдпрд╛рд╡рд░ рдЬрд╛рдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ, "рдЪреЗрдХ" рдмрдЯрдгрд╛рд╡рд░ рдХреНрд▓рд┐рдХ рдХрд░рд╛ рдЖрдгрд┐ рдХрд╛рд╣реА рдХрд╛рд│рд╛рдирдВрддрд░ рддреНрдпрд╛рд▓рд╛ рддреНрдпрд╛рдиреЗ рдХрд╛рдп рдХреЗрд▓реЗ рдпрд╛рд╡рд░ рдХрд╛рд╣реА рдкреНрд░рдХрд╛рд░рдЪреЗ рд╡рд┐рд╕реНрддрд╛рд░рд┐рдд рдЕрднрд┐рдкреНрд░рд╛рдп рджрд┐рд╕рддреЛ. рдЖрдгрд┐ рдпрд╛ рдХреНрд╖рдгреАрдЪ рдЖрдкрдг рдЖрдкрд▓реНрдпрд╛ рд╕рдорд╕реНрдпреЗрдХрдбреЗ рдЬрд╛рдгреНрдпрд╛рд╕ рд╕реБрд░рд╡рд╛рдд рдХрд░рддреЛ.

рдпрд╛ рд▓реЕрдмрдЪреА рдкрдбрддрд╛рд│рдгреА рдЕрд╢реА рд░рдЪрдирд╛ рдХреЗрд▓реА рдЖрд╣реЗ: рдЖрдореНрд╣реА рд╕рд╣рднрд╛рдЧреАрдЪреНрдпрд╛ рдХрд╛рдлреНрдХрд╛рд▓рд╛ рдПрдХ рдирд┐рдпрдВрддреНрд░рдг рдбреЗрдЯрд╛ рдкреЕрдХреЗрдЯ рдкрд╛рдард╡рддреЛ, рддреНрдпрд╛рдирдВрддрд░ Gobblin рд╣реЗ рдбреЗрдЯрд╛ рдкреЕрдХреЗрдЯ HDFS рдордзреНрдпреЗ рд╣рд╕реНрддрд╛рдВрддрд░рд┐рдд рдХрд░рддреЛ, рддреНрдпрд╛рдирдВрддрд░ Airflow рд╣реЗ рдбреЗрдЯрд╛ рдкреЕрдХреЗрдЯ рдШреЗрддреЛ рдЖрдгрд┐ рдХреНрд▓рд┐рдХрд╣рд╛рдКрд╕рдордзреНрдпреЗ рдареЗрд╡рддреЛ. рдпреБрдХреНрддреА рдЕрд╢реА рдЖрд╣реЗ рдХреА рдПрдЕрд░рдлреНрд▓реЛрд▓рд╛ рд╣реЗ рд░рд┐рдЕрд▓ рдЯрд╛рдЗрдордордзреНрдпреЗ рдХрд░рдгреНрдпрд╛рдЪреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╛рд╣реА, рддреЗ рдПрдХрд╛ рд╢реЗрдбреНрдпреВрд▓рдиреБрд╕рд╛рд░ рдХрд░рддреЗ: рдкреНрд░рддреНрдпреЗрдХ 15 рдорд┐рдирд┐рдЯрд╛рдВрдиреА рдлрд╛рдпрд▓реАрдВрдЪрд╛ рдПрдХ рд╕рдореВрд╣ рдШреЗрддреЗ рдЖрдгрд┐ рддреНрдпрд╛ рдЕрдкрд▓реЛрдб рдХрд░рддреЗ.

рд╣реЗ рдирд┐рд╖реНрдкрдиреНрди рдЭрд╛рд▓реЗ рдХреА рдпреЗрдереЗ рдЖрдгрд┐ рдЖрддрд╛ рддрдкрд╛рд╕рдХ рдЪрд╛рд▓реВ рдЕрд╕рддрд╛рдирд╛ рдЖрдореНрд╣рд╛рд▓рд╛ рдЖрдордЪреНрдпрд╛ рд╡рд┐рдирдВрддреАрдиреБрд╕рд╛рд░ рддреНрдпрд╛рдВрдЪреЗ DAG рд╕реНрд╡рддрдГрдЪ рдЯреНрд░рд┐рдЧрд░ рдХрд░рд╛рд╡реЗ рд▓рд╛рдЧреЗрд▓. рдЧреБрдЧрд▓рд┐рдВрдЧ рдХреЗрд▓реНрдпрд╛рдирдВрддрд░, рдЖрдореНрд╣рд╛рд▓рд╛ рдЖрдврд│рд▓реЗ рдХреА рдПрдЕрд░рдлреНрд▓реЛрдЪреНрдпрд╛ рдирдВрддрд░рдЪреНрдпрд╛ рдЖрд╡реГрддреНрддреНрдпрд╛рдВрд╕рд╛рдареА рдПрдХ рддрдерд╛рдХрдерд┐рдд рдЖрд╣реЗ рдкреНрд░рд╛рдпреЛрдЧрд┐рдХ API. рд╢рдмреНрдж experimental, рдирдХреНрдХреАрдЪ, рднреАрддреАрджрд╛рдпрдХ рд╡рд╛рдЯрддреЗ, рдкрдг рдХрд╛рдп рдХрд░рд╛рд╡реЗ... рдЕрдЪрд╛рдирдХ рддреЗ рдмрдВрдж рд╣реЛрддреЗ.

рдкреБрдвреЗ, рдЖрдореНрд╣реА рд╕рдВрдкреВрд░реНрдг рдорд╛рд░реНрдЧрд╛рдЪреЗ рд╡рд░реНрдгрди рдХрд░реВ: рдПрдЕрд░рдлреНрд▓реЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдгреНрдпрд╛рдкрд╛рд╕реВрди рддреЗ рдкреНрд░рд╛рдпреЛрдЧрд┐рдХ API рд╡рд╛рдкрд░реВрди DAG рд▓рд╛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдгрд╛рд░реА POST рд╡рд┐рдирдВрддреА рддрдпрд╛рд░ рдХрд░рдгреНрдпрд╛рдкрд░реНрдпрдВрдд. рдЖрдореНрд╣реА рдЙрдмрдВрдЯреВ 16.04 рд╕рд╣ рдХрд╛рд░реНрдп рдХрд░реВ.

1. рдПрдЕрд░рдлреНрд▓реЛ рд╕реНрдерд╛рдкрдирд╛

рдЖрдордЪреНрдпрд╛рдХрдбреЗ Python 3 рдЖрдгрд┐ virtualenv рдЖрд╣реЗрдд рд╣реЗ рддрдкрд╛рд╕реВ.

$ python3 --version
Python 3.6.6
$ virtualenv --version
15.2.0

рдпрд╛рдкреИрдХреА рдХрд╛рд╣реА рдЧрд╣рд╛рд│ рдЕрд╕рд▓реНрдпрд╛рд╕, рддреЗ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рд╛.

рдЖрддрд╛ рдПрдХ рдбрд┐рд░реЗрдХреНрдЯрд░реА рддрдпрд╛рд░ рдХрд░реВ рдЬреНрдпрд╛рдордзреНрдпреЗ рдЖрдкрдг Airflow рд╕рд╣ рдХрд╛рдо рдХрд░рдд рд░рд╛рд╣реВ.

$ mkdir <your name of directory>
$ cd /path/to/your/new/directory
$ virtualenv -p which python3 venv
$ source venv/bin/activate
(venv) $

рдПрдЕрд░рдлреНрд▓реЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рд╛:

(venv) $ pip install airflow

рдЖрдореНрд╣реА рдЬреНрдпрд╛ рдЖрд╡реГрддреНрддреАрд╡рд░ рдХрд╛рдо рдХреЗрд▓реЗ: 1.10.

рдЖрддрд╛ рдЖрдкрд▓реНрдпрд╛рд▓рд╛ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рддрдпрд╛рд░ рдХрд░рд╛рдпрдЪреА рдЖрд╣реЗ airflow_home, рдЬреЗрдереЗ DAG рдлрд╛рдЗрд▓реНрд╕ рдЖрдгрд┐ рдПрдЕрд░рдлреНрд▓реЛ рдкреНрд▓рдЧрдЗрдиреНрд╕ рдЕрд╕рддреАрд▓. рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рддрдпрд╛рд░ рдХреЗрд▓реНрдпрд╛рдирдВрддрд░, рдкрд░реНрдпрд╛рд╡рд░рдг рд╡реНрд╣реЗрд░рд┐рдПрдмрд▓ рд╕реЗрдЯ рдХрд░рд╛ AIRFLOW_HOME.

(venv) $ cd /path/to/my/airflow/workspace
(venv) $ mkdir airflow_home
(venv) $ export AIRFLOW_HOME=<path to airflow_home>

рдкреБрдвреАрд▓ рдкрд╛рдпрд░реА рдореНрд╣рдгрдЬреЗ рдПрдХ рдХрдорд╛рдВрдб рдЪрд╛рд▓рд╡рдгреЗ рдЬреА SQLite рдордзреНрдпреЗ рдбреЗрдЯрд╛рдлреНрд▓реЛ рдбреЗрдЯрд╛рдмреЗрд╕ рддрдпрд╛рд░ рдХрд░реЗрд▓ рдЖрдгрд┐ рдЖрд░рдВрдн рдХрд░реЗрд▓:

(venv) $ airflow initdb

рдордзреНрдпреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рддрдпрд╛рд░ рдХреЗрд▓рд╛ рдЬрд╛рдИрд▓ airflow.db рдбреАрдлреЙрд▓реНрдЯ

рдПрдЕрд░рдлреНрд▓реЛ рд╕реНрдерд╛рдкрд┐рдд рдЖрд╣реЗ рдХрд╛ рддреЗ рддрдкрд╛рд╕реВрдпрд╛:

$ airflow version
[2018-11-26 19:38:19,607] {__init__.py:57} INFO - Using executor SequentialExecutor
[2018-11-26 19:38:19,745] {driver.py:123} INFO - Generating grammar tables from /usr/lib/python3.6/lib2to3/Grammar.txt
[2018-11-26 19:38:19,771] {driver.py:123} INFO - Generating grammar tables from /usr/lib/python3.6/lib2to3/PatternGrammar.txt
  ____________       _____________
 ____    |__( )_________  __/__  /________      __
____  /| |_  /__  ___/_  /_ __  /_  __ _ | /| / /
___  ___ |  / _  /   _  __/ _  / / /_/ /_ |/ |/ /
 _/_/  |_/_/  /_/    /_/    /_/  ____/____/|__/
   v1.10.0

рдЬрд░ рдХрдорд╛рдВрдб рдХрд╛рд░реНрдп рдХрд░рдд рдЕрд╕реЗрд▓, рддрд░ рдПрдЕрд░рдлреНрд▓реЛрдиреЗ рд╕реНрд╡рддрдГрдЪреА рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди рдлрд╛рдЗрд▓ рддрдпрд╛рд░ рдХреЗрд▓реА airflow.cfg ╨▓ AIRFLOW_HOME:

$ tree
.
тФЬтФАтФА airflow.cfg
тФФтФАтФА unittests.cfg

рдПрдЕрд░рдлреНрд▓реЛрдордзреНрдпреЗ рд╡реЗрдм рдЗрдВрдЯрд░рдлреЗрд╕ рдЖрд╣реЗ. рд╣реЗ рдХрдорд╛рдВрдб рдЪрд╛рд▓рд╡реВрди рд▓реЙрдиреНрдЪ рдХреЗрд▓реЗ рдЬрд╛рдК рд╢рдХрддреЗ:

(venv) $ airflow webserver --port 8081

рддреБрдореНрд╣реА рдЖрддрд╛ рд╣реЛрд╕реНрдЯрд╡рд░ рдкреЛрд░реНрдЯ 8081 рд╡рд░ рдмреНрд░рд╛рдЙрдЭрд░рдордзреНрдпреЗ рд╡реЗрдм рдЗрдВрдЯрд░рдлреЗрд╕ рджрд╛рдмреВ рд╢рдХрддрд╛ рдЬреЗрдереЗ Airflow рдЪрд╛рд▓реВ рд╣реЛрддреЗ, рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде: <hostname:8081>.

2. рдкреНрд░рд╛рдпреЛрдЧрд┐рдХ API рд╕рд╣ рдХрд╛рд░реНрдп рдХрд░рдгреЗ

рдпрд╛ рдЯрдкреНрдкреНрдпрд╛рд╡рд░, рдПрдЕрд░рдлреНрд▓реЛ рдХреЙрдиреНрдлрд┐рдЧрд░ рдХреЗрд▓реЗ рдЖрд╣реЗ рдЖрдгрд┐ рдЬрд╛рдгреНрдпрд╛рд╕рд╛рдареА рддрдпрд╛рд░ рдЖрд╣реЗ. рддрдерд╛рдкрд┐, рдЖрдореНрд╣рд╛рд▓рд╛ рдкреНрд░рд╛рдпреЛрдЧрд┐рдХ API рджреЗрдЦреАрд▓ рдЪрд╛рд▓рд╡рд╛рд╡реЗ рд▓рд╛рдЧреЗрд▓. рдЖрдордЪреЗ рдЪреЗрдХрд░реНрд╕ рдкрд╛рдпрдердирдордзреНрдпреЗ рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рдЖрд╣реЗрдд, рддреНрдпрд╛рдореБрд│реЗ рдкреБрдвреАрд▓ рд╕рд░реНрд╡ рд╡рд┐рдирдВрддреНрдпрд╛ рд▓рд╛рдпрдмреНрд░рд░реА рд╡рд╛рдкрд░реВрди рддреНрдпрд╛рдордзреНрдпреЗ рдЕрд╕рддреАрд▓ requests.

рдЦрд░рдВ рддрд░, API рдЖрдзреАрдЪ рд╕рд╛рдзреНрдпрд╛ рд╡рд┐рдирдВрддреНрдпрд╛рдВрд╕рд╛рдареА рдХрд╛рд░реНрдп рдХрд░рддреЗ. рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, рд╣реА рд╡рд┐рдирдВрддреА рддреБрдореНрд╣рд╛рд▓рд╛ рддреНрдпрд╛рдЪреЗ рдСрдкрд░реЗрд╢рди рддрдкрд╛рд╕рдгреНрдпрд╛рдЪреА рдкрд░рд╡рд╛рдирдЧреА рджреЗрддреЗ:

>>> import requests
>>> host = <your hostname>
>>> airflow_port = 8081 #╨▓ ╨╜╨░╤И╨╡╨╝ ╤Б╨╗╤Г╤З╨░╨╡ ╤В╨░╨║╨╛╨╣, ╨░ ╨┐╨╛ ╨┤╨╡╤Д╨╛╨╗╤В╤Г 8080
>>> requests.get('http://{}:{}/{}'.format(host, airflow_port, 'api/experimental/test').text
'OK'

рдЬрд░ рддреБрдореНрд╣рд╛рд▓рд╛ рдкреНрд░рддрд┐рд╕рд╛рджрд╛рдд рдЕрд╕рд╛ рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдЭрд╛рд▓рд╛ рддрд░ рдпрд╛рдЪрд╛ рдЕрд░реНрде рд╕рд░реНрд╡ рдХрд╛рд╣реА рдХрд╛рд░реНрдп рдХрд░рдд рдЖрд╣реЗ.

рддрдерд╛рдкрд┐, рдЬреЗрд╡реНрд╣рд╛ рдЖрдореНрд╣реА DAG рдЯреНрд░рд┐рдЧрд░ рдХрд░реВ рдЗрдЪреНрдЫрд┐рддреЛ, рддреЗрд╡реНрд╣рд╛ рдЖрдореНрд╣рд╛рд▓рд╛ рдпрд╛ рд╡рд╕реНрддреБрд╕реНрдерд┐рддреАрдЪрд╛ рд╕рд╛рдордирд╛ рдХрд░рд╛рд╡рд╛ рд▓рд╛рдЧрддреЛ рдХреА рдпрд╛ рдкреНрд░рдХрд╛рд░рдЪреА рд╡рд┐рдирдВрддреА рдкреНрд░рдорд╛рдгреАрдХрд░рдгрд╛рд╢рд┐рд╡рд╛рдп рдХреЗрд▓реА рдЬрд╛рдК рд╢рдХрдд рдирд╛рд╣реА.

рд╣реЗ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА, рддреБрдореНрд╣рд╛рд▓рд╛ рдЖрдгрдЦреА рдЕрдиреЗрдХ рдкрд╛рдпрд▒реНрдпрд╛ рдХрд░рд╛рд╡реНрдпрд╛ рд▓рд╛рдЧрддреАрд▓.

рдкреНрд░рдердо, рдЖрдкрд▓реНрдпрд╛рд▓рд╛ рд╣реЗ рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рдирдордзреНрдпреЗ рдЬреЛрдбрдгреНрдпрд╛рдЪреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдЖрд╣реЗ:

[api]
auth_backend = airflow.contrib.auth.backends.password_auth

рддреНрдпрд╛рдирдВрддрд░, рдЖрдкрд▓реНрдпрд╛рд▓рд╛ рдкреНрд░рд╢рд╛рд╕рдХ рдЕрдзрд┐рдХрд╛рд░рд╛рдВрд╕рд╣ рдЖрдкрд▓рд╛ рд╡рд╛рдкрд░рдХрд░реНрддрд╛ рддрдпрд╛рд░ рдХрд░рдгреНрдпрд╛рдЪреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдЖрд╣реЗ:

>>> import airflow
>>> from airflow import models, settings
>>> from airflow.contrib.auth.backends.password_auth import PasswordUser
>>> user = PasswordUser(models.Admin())
>>> user.username = 'new_user_name'
>>> user.password = 'set_the_password'
>>> session = settings.Session()
>>> session.add(user)
>>> session.commit()
>>> session.close()
>>> exit()

рдкреБрдвреЗ, рддреБрдореНрд╣рд╛рд▓рд╛ рд╕рд╛рдорд╛рдиреНрдп рдЕрдзрд┐рдХрд╛рд░рд╛рдВрд╕рд╣ рдПрдХ рд╡рд╛рдкрд░рдХрд░реНрддрд╛ рддрдпрд╛рд░ рдХрд░рдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ рдЬреНрдпрд╛рд▓рд╛ DAG рдЯреНрд░рд┐рдЧрд░ рдХрд░рдгреНрдпрд╛рдЪреА рдкрд░рд╡рд╛рдирдЧреА рдЕрд╕реЗрд▓.

>>> import airflow
>>> from airflow import models, settings
>>> from airflow.contrib.auth.backends.password_auth import PasswordUser
>>> user = PasswordUser(models.User())
>>> user.username = 'newprolab'
>>> user.password = 'Newprolab2019!'
>>> session = settings.Session()
>>> session.add(user)
>>> session.commit()
>>> session.close()
>>> exit()

рдЖрддрд╛ рд╕рд░реНрд╡рдХрд╛рд╣реА рддрдпрд╛рд░ рдЖрд╣реЗ.

3. POST рд╡рд┐рдирдВрддреА рд▓рд╛рдБрдЪ рдХрд░рд╛

POST рд╡рд┐рдирдВрддреА рд╕реНрд╡рддрдГ рдЕрд╕реЗ рджрд┐рд╕реЗрд▓:

>>> dag_id = newprolab
>>> url = 'http://{}:{}/{}/{}/{}'.format(host, airflow_port, 'api/experimental/dags', dag_id, 'dag_runs')
>>> data = {"conf":"{"key":"value"}"}
>>> headers = {'Content-type': 'application/json'}
>>> auth = ('newprolab', 'Newprolab2019!')
>>> uri = requests.post(url, data=json.dumps(data), headers=headers, auth=auth)
>>> uri.text
'{n  "message": "Created <DagRun newprolab @ 2019-03-27 10:24:25+00:00: manual__2019-03-27T10:24:25+00:00, externally triggered: True>"n}n'

рд╡рд┐рдирдВрддреАрд╡рд░ рдпрд╢рд╕реНрд╡реАрдкрдгреЗ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░рдгреНрдпрд╛рдд рдЖрд▓реА.

рддреНрдпрд╛рдиреБрд╕рд╛рд░, рдЖрдореНрд╣реА DAG рд▓рд╛ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдереЛрдбрд╛ рд╡реЗрд│ рджреЗрддреЛ рдЖрдгрд┐ рдХреНрд▓рд┐рдХрд╣рд╛рдКрд╕ рдЯреЗрдмрд▓рд▓рд╛ рд╡рд┐рдирдВрддреА рдХрд░рддреЛ, рдирд┐рдпрдВрддреНрд░рдг рдбреЗрдЯрд╛ рдкреЕрдХреЗрдЯ рдкрдХрдбрдгреНрдпрд╛рдЪрд╛ рдкреНрд░рдпрддреНрди рдХрд░рддреЛ.

рдЪреЗрдХ рдкреВрд░реНрдг рдЭрд╛рд▓рд╛.

рд╕реНрддреНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╛