Использование¶
Программа запускается из командной строки.
Структура репозитория¶
Пример структуры репозитория:
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.
Пример содержимого скрипта миграции:
"""
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, но в виде плана. Например:
$ 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.
$ ipmt version 1.0.0
Это означает, что текущая версия IPMT 1.0.0.
- init
Отображает установленную версию инструмента миграций IPMT.
$ ipmt init $ # или с созданием baseline версии $ IPMT_DSN=username@hostname/dbname ipmt init
При инициализации создается директория versions. Если в качестве аргумента передать строку подключения к БД, то будет создана baseline миграция с текущей структурой БД, и для указанной БД будет установлена версия в таблице public.ipmt_version
- create
Создает в директории path новый файл миграции.
$ ipmt create alter some table Created versions/000007#alter_some_table.py
Инструмент поддерживает работу в разных ветках. Именами веток могут быть любые символы из a-zA-Z0-9_. Для создания новой версии в отдельной ветке необходимо передать аргументом –branch полный путь к ветке, например:
$ 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. В этом случае будет отображена последняя версия в указанной ветке.
$ ipmt head 000001 $ ipmt head --branch 000001.mybranch 000001.mybranch.2
- show
Отображает все миграции репозитория в директории path
$ IPMT_DSN=username@hostname/dbname ipmt show Repository: ver. 000001 ver. 000001.mybranch.1 ver. 000002 ver. 000003
Жирным будут отмечены те миграции, которые применены к указанной БД
- current
Отображает текущую версию БД
$ IPMT_DSN=username@hostname/dbname ipmt current 000006
- up
Обновление БД к указанной версии. Если целевая версия не указана, то будет выполнено обновление до последней версии.
$ # обновление до версии 000003 $ IPMT_DSN=username@hostname/dbname ipmt up 000003 000003 $ # обновление до последней версии $ IPMT_DSN=username@hostname/dbname ipmt up 000007
- down
Откат БД к укзанной версии. Если целевая версия не указана, то будет произведен откат на одну версию назад. Если передать целевую версию 0, то будет произведен откат к начальному состаянию БД, т.е. будут отменены все миграции.
$ # откат к версии 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, то произойдет откат всех миграций.
$ # обновление/откат до версии 000007 $ IPMT_DSN=username@hostname/dbname ipmt switch 000007 000007 $ # откат всех миграций $ IPMT_DSN=username@hostname/dbname ipmt switch 0 0
- rebase
Перенос миграций из указанной ветки в родительскую.
$ ipmt rebase 000001.mybranch Moving 000001.mybranch.1 to 000007
- actualize
Исправляет неверную последовательность миграций в БД путем отката и обновления миграций.
$ 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 с родительской веткой:
$ 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 файла или выгружает в файл привелегии привелегии из указанной БД
$ # выгружает привелегии всех пользователей БД в файл 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 не поддерживаются. Если не указан путь к файлу для сохранения дампа, то дамп будет выведен в стандартный вывод.
# 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, установленный в требуемый уровень.
- Например:
from ipmt.db import transactional, SERIALIZABLE @transactional(isolation_level=SERIALIZABLE) def up(db): """ :type db: ipmt.db.Database """ db.execute( """\ CREATE SCHEMA myschema; """ ) @transactional(isolation_level=SERIALIZABLE) def down(db): """ :type db: ipmt.db.Database """ db.execute( """\ DROP SCHEMA myschema; """ )
Транзакционные миграции с одинаковым уровнем изояции, идущие в плане выполнения последовательно друг за другом, будут выполняться в одной транзакции. В противном случае после транзации будет выполнен COMMIT, т.о. зафиксировав версию БД.
Работа с ветками¶
Ветки предназначены для разработки нескольких новых функций, которые незвестно в каком порядке будут обновляться в prod-среде. В одной базе данных может быть применена только одна конкретная версия из конкретной ветки. Создание новой ветки производится командой create с аргументом –branch. Перенос изменений из ветки происходи при помощи команды rebase. Исправление последствий некорректного слияния веток производится командой actualize.