============= Использование ============= Программа запускается из командной строки. Структура репозитория --------------------- Пример структуры репозитория:: versions/ 000001#baseline.py 000001.mybranch.1#alter_some_table.py 000001.mybranch2.1#alter_some_table.py 000001.mybranch2.2#alter_another_table.py 000001.mybranch.2#alter_another_table.py 000002#create_some_table.py meta.yml В этом примере репозиторий имеет структуру:: ver. 000001 ver. 000001.mybranch.1 ver. 000001.mybranch.2 ver. 000001.mybranch2.1 ver. 000001.mybranch2.2 ver. 000002 Миграции представляют собой исполняемые файлы на языке python, в которых должно быть объявлено 2 функции `up` и `down`. Файл `meta.yml` содержит в себе служебную информацию такую, как история слияния веток в репозитории, старые имена миграций и во что они были переименованы. Имя файла состоит из номера версии и краткого описания изменений, разделенных символом #(для того чтоб сохранить корректную сортировку внутри директории). Имя файла может быть вида: 000001.b1.1.b2.2#myname.py, где 001 - корневая версия БД от которой создана ветка b1, 1 - номер версии внутри ветки b1 и от которой создана ветка b2, в которой есть как минимут 2 миграции, и текущий файл описывает изменения для второй версии в ветке b2. Пример содержимого скрипта миграции: .. code-block:: python """ Name: alter_some_table Version: 001.mybranch.1 Create Date: 2017-05-29 10:52:46 """ from ipmt.db import transactional @transactional() def up(db): """ :type db: ipmt.db.Database """ db.execute("""\ ALTER TABLE schema1.table1 ADD COLUMN name text; """) @transactional() def down(db): """ :type db: ipmt.db.Database """ db.execute("""\ ALTER TABLE schema1.table1 DROP COLUMN name; """) Команды ------- Для команд `up`, `down`, `switch`, `init`, `actualize`, `grant` необходимо передавать строку подключения к БД в качестве аргумента командной строки в формате `--database username:password@hostname/dbname`. Ее можно также передать как переменную окружения IPMT_DSN, тогда аргумент `database` будет необязательным. Если передать переменную окружения и аргумент командной строки, то будет использоваться аргумент командной строки. Мирациии по-умолчанию сохраняются в директории versions текущего каталога. Эту директорию можно переопределить передав аргумент `--path` и указав нужную директорию. Либо директорию можно переопределить передав переменную окружения `IPMT_PATH`. Если передать переменную окружения и аргумент командной строки, то будет использоваться аргумент командной строки. По сути, переменная окружения переопределяет значение по-умолчанию для аргумента командной строки. Команды `up`, `down`, `switch`, `actualize`, `grant` в качестве агрумента могут принимать аргумент `--dry-run`, который вместо применения изменений в БД выведет список sql запросов в stdout. Команды `up`, `down`, `switch`, `actualize` в качестве аргумента могут принимать аргумент `--show-plan` или `-s`, который вместо применения миграций отобразит последовательность миграций, которые необходимо выполнить для выполнения команды. Т.е. поведение такое же как у --dry-run, но в виде плана. Например: .. code-block:: console $ IPMT_DSN=svc_ars@localhost/ars6 ipmt up -s 000003 0 -> 000001(xUp) -> 000002(xUp) -> 000003(Up) Означает, что текущая версия БД `0` и для обновления до версии 000002 необходимо выполнить обновление до версии 000001, затем до версии 000002 и затем до версии 000003. `xUp` - означает, что обновление будет происходить в транзакции. `Up` - означает, что миграция будет выполняться не в транзакции. Перечень команд инструмента миграций: **version** Отображает установленную версию инструмента миграций IPMT. .. code-block:: console $ ipmt version 1.0.0 Это означает, что текущая версия IPMT 1.0.0. **init** Отображает установленную версию инструмента миграций IPMT. .. code-block:: console $ ipmt init $ # или с созданием baseline версии $ IPMT_DSN=username@hostname/dbname ipmt init При инициализации создается директория versions. Если в качестве аргумента передать строку подключения к БД, то будет создана baseline миграция с текущей структурой БД, и для указанной БД будет установлена версия в таблице public.ipmt_version **create** Создает в директории `path` новый файл миграции. .. code-block:: console $ ipmt create alter some table Created versions/000007#alter_some_table.py Инструмент поддерживает работу в разных ветках. Именами веток могут быть любые символы из `a-zA-Z0-9_`. Для создания новой версии в отдельной ветке необходимо передать аргументом `--branch` полный путь к ветке, например: .. code-block:: console $ ipmt create --branch 000001.mybranch alter another table Created versions/000001.mybranch.1#alter_another_table.py В этом примере создается новая версия БД 000001.mybranch.1, которая идет следом за 000001. При применении такой миграции будет произведено обновление до версии 000001, а затем до версии 000001.mybranch.1. Поэтому, при создании верки необходимо, чтоб родительская версия, обязательно присутствовала в репозитории. В противном слючае инструмент не будет работать. **head** Отображает последнюю версию в репозитории. Команда может принимать аргумент --branch. В этом случае будет отображена последняя версия в указанной ветке. .. code-block:: console $ ipmt head 000001 $ ipmt head --branch 000001.mybranch 000001.mybranch.2 **show** Отображает все миграции репозитория в директории `path` .. code-block:: console $ IPMT_DSN=username@hostname/dbname ipmt show Repository: ver. 000001 ver. 000001.mybranch.1 ver. 000002 ver. 000003 Жирным будут отмечены те миграции, которые применены к указанной БД **current** Отображает текущую версию БД .. code-block:: console $ IPMT_DSN=username@hostname/dbname ipmt current 000006 **up** Обновление БД к указанной версии. Если целевая версия не указана, то будет выполнено обновление до последней версии. .. code-block:: console $ # обновление до версии 000003 $ IPMT_DSN=username@hostname/dbname ipmt up 000003 000003 $ # обновление до последней версии $ IPMT_DSN=username@hostname/dbname ipmt up 000007 **down** Откат БД к укзанной версии. Если целевая версия не указана, то будет произведен откат на одну версию назад. Если передать целевую версию `0`, то будет произведен откат к начальному состаянию БД, т.е. будут отменены все миграции. .. code-block:: console $ # откат к версии 000003 $ IPMT_DSN=username@hostname/dbname ipmt down 000003 000003 $ # откат на одну версию назад $ IPMT_DSN=username@hostname/dbname ipmt down 000002 $ # откат к начальному состоянию $ IPMT_DSN=username@hostname/dbname ipmt down 0 0 **switch** Откат или обновление БД к указанной версии. Если в качестве целевой версии передать 0, то произойдет откат всех миграций. .. code-block:: console $ # обновление/откат до версии 000007 $ IPMT_DSN=username@hostname/dbname ipmt switch 000007 000007 $ # откат всех миграций $ IPMT_DSN=username@hostname/dbname ipmt switch 0 0 **rebase** Перенос миграций из указанной ветки в родительскую. .. code-block:: console $ ipmt rebase 000001.mybranch Moving 000001.mybranch.1 to 000007 **actualize** Исправляет неверную последовательность миграций в БД путем отката и обновления миграций. .. code-block:: console $ IPMT_DSN=username@hostname/dbname ipmt actualize 000007 Неверная последовательность миграций может получиться после выполнения команды rebase. Например, в репозитории имеются миграции:: versions/ 000001#baseline.py 000001.mybranch.1#alter_some_table.py 000002#create_some_table.py Текущая версия БД: 000001.mybranch.1. Т.е. в БД применены миграции 000001 и 000001.mybranch.1. Выполняется слияние ветки mybranch с родительской веткой: .. code-block:: console $ ipmt rebase 000001.mybranch В результате получается новая структура репозитория:: versions/ 000001#baseline.py 000002#create_some_table.py 000003#alter_some_table.py Т.е. версия 000001.mybranch.1 превращается в 000003. При этом текущая версия БД 000001.mybranch.1. В новой схеме репозитория эта версия называется 000003(IPMT понимает это по файлу meta.yml). Т.о. получается, что у БД неконсистентное состояние(пропущена миграция 000002). В этом состоянии команды: `up`, `down` и `switch` будут недоступны и IPMT, при их вызове, будет выдавать ошибку. Для того, чтоб исправить это, необходимо выполнить команду `actualize`. Эта команда произведет откат миграции 000003(ранее известной как 000001.mybranch.1) и затем произведет обновление до версии 000002 и 000003 последовательно. **grant** Применяет привелегии из указанного yaml файла или выгружает в файл привелегии привелегии из указанной БД .. code-block:: console $ # выгружает привелегии всех пользователей БД в файл permissions.yml $ IPMT_DSN=svc_ars@localhost/ars6 ipmt grant -o permissions.yml $ # выгружает привелегии пользователей user1 и user2 в файл, за $ # исключением привелегий на объекты в схеме myschema $ IPMT_DSN=svc_ars@localhost/ars6 ipmt grant --roles user1 user2 \ > --exclude '~myschema\..*' -o permissions.yml $ # применение привелегий из файла permissions.yml к указанной БД $ IPMT_DSN=svc_ars@localhost/ars6 ipmt grant -i permissions.yml $ # применение привелегий из файла, за исключением привелегий $ # пользователей user3, user4 и за исключением объектов test.mytable и $ # test.mytable_seq $ IPMT_DSN=svc_ars@localhost/ars6 ipmt grant --roles user3 user4 \ > --exclude test.mytable test.mytable_seq -i permissions.yml Пример yaml файла:: roles: - user1 - user2 objects: public: user1: usage user2: usage public.some_table: user1: select ~public\..*: user2: all exclude: ~private_schema\..* **dump** Формирует дамп схемы БД указанной версии с помощью pg_dump. В качестве аргумента можно передать `--docker-image` и `--docker-version` с указанием требуемой версии postgresql или greenplum. Список доступных доступен на `docker hub`_. Версии alpine не поддерживаются. Если не указан путь к файлу для сохранения дампа, то дамп будет выведен в стандартный вывод. .. _docker hub: https://hub.docker.com/_/postgres/ .. code-block:: console # postgres $ ipmt dump -o dump.sql --docker-image postgres --docker-version 9.5 # greenplum $ ipmt dump -o dump.sql --docker-image pivotaldata/gpdb-dev --docker-version ubuntu-16.04 Транзакционность ---------------- По-умолчанию команда `ipmt create` создает транзакционные миграции. Если требуется создать миграцию, которая не должна выполняться в транзакции, то необходимо у функции up или down удалить декоратор `@transactional`. По-умочанию IPMT использует уровень изоляции `READ COMMITTED`. Если необходимо изменить его, то нужно прередать в декоратор параметр isolation_level, установленный в требуемый уровень. Например: .. literalinclude:: examples/000001#baseline.py Транзакционные миграции с одинаковым уровнем изояции, идущие в плане выполнения последовательно друг за другом, будут выполняться в одной транзакции. В противном случае после транзации будет выполнен `COMMIT`, т.о. зафиксировав версию БД. Работа с ветками ---------------- Ветки предназначены для разработки нескольких новых функций, которые незвестно в каком порядке будут обновляться в prod-среде. В одной базе данных может быть применена только одна конкретная версия из конкретной ветки. Создание новой ветки производится командой create с аргументом --branch. Перенос изменений из ветки происходи при помощи команды rebase. Исправление последствий некорректного слияния веток производится командой actualize.