В этой статье поговорим о том, как избавиться от ошибок с таблицами Active Objects при восстановлении Jira из бэкапа и напишем плагин для удаления ненужных таблиц Active Objects из архивного файла бэкапа.

Что такое таблицы Active Objects?


База данных Jira содержит два типа таблиц: системные таблицы, такие как jiraissue, cwd_user, changegroup, и таблицы, добавленные установленными в Jira плагинами. Эти таблицы и есть таблицы Active Objects. Их легко отличить от системных таблиц по префиксу AO_XXXXXX.
AO означает Active Objects, а XXXXXX это хэшкод, который генерирует Jira для каждого плагина. Хэшкод нужен для того, чтобы была возможность создавать в разных плагинах таблицы с одинаковыми именами. Так как после добавления префикса AO_XXXXXX к таблицам с одинаковым наименованием, имена таблиц начинают различаться, и поэтому они могу быть созданы в базе данных.

Active Objects это ORM слой в продуктах Atlassian. Подробнее про него можно почитать здесь.

В Jira можно посмотреть информацию о всех созданных таблицах каждым плагином, если перейти по Шестеренка -> System -> Plugin Data Storage. Например, на моем инстансе Jira информация по плагинам выглядит вот так:



На скриншоте видно, что плагин Atlassian Notifications создал три таблицы, у которых хэшкод 21F425

AO errors


Теперь посмотрим, как эти ошибки выглядят в реальном времени. Вот пример ошибки «unsupported field encountered: binary»:



Исправляем ошибку «unsupported field encountered: binary»


Давайте попробуем исправить эту ошибку. Для этого распакуем файл бэкапа. Внутри мы увидим два файла: entities.xml и activeobjects.xml.

Файл entities.xml содержит данные системных таблиц. Файл activeobjects.xml содержит данные таблиц Active Objects. Нам как раз и нужен файл activeobjects.xml.

Открываем файл activeobjects.xml file и ищем слово «binary» в файле. В моем случае найдено 10 совпадений. Эти совпадения выглядят вот так:

<row> 
<string>Alexey Matveev</string> 
<string>alexey.matveev@aaa.com</string> 
<integer>1</integer>
<timestamp xsi:nil="true"/> 
<string xsi:nil="true"/> 
<integer xsi:nil="true"/> 
<binary xsi:nil="true"/> 
<string xsi:nil="true"/> 
<string xsi:nil="true"/> 
<integer xsi:nil="true"/> 
<string>Europe/Moscow</string> 
<string>alexey</string> 
<string>alexey</string>
</row>

Удаляем все строки <binary xsi:nil=«true»/> в файле activeobjects.xml file и пробуем снова восстановить Jira.

На этот раз ошибка «unsupported field encountered: binary» исправлена, но мы видим новую ошибку:



Давайте посмотрим содержимое файла atlassian-jira.log:

[INFO] [talledLocalContainer] com.atlassian.activeobjects.spi.ActiveObjectsImportExportException: There was an error during import/export with <unknown plugin> (table AO_6B9F04_AIO_USER):Could not import data in table 'AO_6B9F04_AIO_USER' column #10, value is too big for column which size limit is 10, value is:
[INFO] [talledLocalContainer] Europe/Moscow

Если поискать информацию об этой ошибке в интернете, то мы найдем вот такую KB.

В этой KB предлагается изменить размерность поля №10 на -1. Давайте попробуем.

<table name="AO_6B9F04_AIO_USER"> 
<column name="DISPLAY_NAME" primaryKey="false" autoIncrement="false" sqlType="-9" precision="255"/> 
<column name="EMAIL_ADDRESS" primaryKey="false" autoIncrement="false" sqlType="-9" precision="255"/> 
<column name="ID" primaryKey="true" autoIncrement="true" sqlType="4" precision="10"/> 
<column name="LAST_LOGIN_DATE" primaryKey="false" autoIncrement="false" sqlType="93" precision="23" scale="3"/> 
<column name="LOCALE" primaryKey="false" autoIncrement="false" sqlType="-9" precision="255"/> 
<column name="LOGIN_DAYS_COUNT" primaryKey="false" autoIncrement="false" sqlType="4" precision="10"/> 
<column name="O_AUTH_TOKEN" primaryKey="false" autoIncrement="false" sqlType="-4" precision="2147483647"/> 
<column name="O_AUTH_TOKEN_SECRET" primaryKey="false" autoIncrement="false" sqlType="-9" precision="255"/> 
<column name="TABLEAU_KEY" primaryKey="false" autoIncrement="false" sqlType="-9" precision="255"/>
<column name="TENANT_ID" primaryKey="false" autoIncrement="false" sqlType="4" precision="10"/> 
<column name="TIME_ZONE" primaryKey="false" autoIncrement="false" sqlType="-9" precision="255"/> 
<column name="USERKEY" primaryKey="false" autoIncrement="false" sqlType="-9" precision="255"/> 
<column name="USERNAME" primaryKey="false" autoIncrement="false" sqlType="-9" precision="255"/> 
<foreignKey fromTable="AO_6B9F04_AIO_USER" fromColumn="TENANT_ID" toTable="AO_6B9F04_AIO_TENANT" toColumn="ID"/> 
</table>

Поменяем:

<column name="TENANT_ID" primaryKey="false" autoIncrement="false" sqlType="4" precision="10"/> 

на

<column name="TENANT_ID" primaryKey="false" autoIncrement="false" sqlType="4" precision="-1"/> 

и попробуем восстановить Jira из нашего бэкапа.

В логе мы видим опять те же самые ошибки. KB не помогло.

uknown plugin


Давайте еще раз внимательно почитаем ошибку. Мы увидим, что данные из UKNOWN PLUGIN плагина не могут быть импортированы. Почему из неизвестного плагина (UKNOWN PLUIGN)?
Если посмотреть на скриншот ниже, то можно заметить, что у некоторых объектов Active Objects нет имен плагинов, к которым они относятся:



Можно увидеть, что в красном прямоугольнике есть имя плагина, а в синем прямоугольнике плагина нет. Такое может случиться, если мы установили плагин, затем его удалили и перезапустили Jira с удалением папки .osgi_plugins. Такой вид перезапуска Jira рекомендуется, если есть какие-то проблемы с работой плагинов.

У нашей таблицы AIO_USER нет имени плагина, поэтому мы можем просто удалить таблицу.
Давайте найдем определение этой таблицы в файле activeobjects.xml, удалим найденное определение и попробуем восстановить Jira из бэкапа.

Мы увидим уже другую ошибку:

[INFO] [talledLocalContainer] com.atlassian.activeobjects.spi.ActiveObjectsImportExportException: There was an error during import/export with <unknown plugin> (table AO_6B9F04_AIO_USER):Could not create prepared statement for SQL query, [INSERT INTO PUBLIC."AO_6B9F04_AIO_USER" ("DISPLAY_NAME", "EMAIL_ADDRESS", "ID", "LAST_LOGIN_DATE", "LOCALE", "LOGIN_DAYS_COUNT", "O_AUTH_TOKEN", "O_AUTH_TOKEN_SECRET", "TABLEAU_KEY", "TENANT_ID", "TIME_ZONE", "USERKEY", "USERNAME") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]

Проблема в том, что мы удалили определение таблицы, но не удалили данные этой таблицы. Давайте найдем данные этой таблицы в файле activeobjects.xml и удалим их.

Данные по таблице начинаются вот таким тэгом:

<data tableName="AO_6B9F04_AIO_USER">

И заканчиваются вот таким тэгом:

</data>

Давайте удалим эти тэги и все, что между этими тэгами, и попробуем еще раз восстановить Jira из бэкапа.

Мы получим другую ошибку:

There was a problem restoring ActiveObjects data for the <unknown plugin> plugin. Caught exception with following message: Table "AO_6B9F04_AIO_USER" not found; SQL statement: ALTER TABLE PUBLIC.AO_6B9F04_AIO_REPORT ADD CONSTRAINT fk_ao_6b9f04_aio_report_owner_id FOREIGN KEY (OWNER_ID) REFERENCES PUBLIC.AO_6B9F04_AIO_USER(ID) [42102-185]. Please check the log for details.

Это означает, что есть еще таблицы в плагине, которые ссылаются на эту таблицы, поэтому нам еще нужно удалить все таблицы, которые ссылаются на удаленную таблицу. Дальше все может пойти по цепочке: может потребоваться еще удалить таблицы этого плагина, которые ссылаются на удаленные таблицы.

Поэтому гораздо быстрее будет удалить все таблицы с префиксом AO_6B9F04 из файла бэкапа программно.

Давайте напишем плагин, которые будет удалять таблицы из файла бэкапа по заданному префиксу. Плагин будет состоять из webwork, который будет получать имя файла бэкапа (файл бэкапа должен находиться в JIRA_HOME/import) и префикс.

Исходный код плагина можно взять здесь.

Создаем плагин


Открываем терминал и выполняем следующую команду:

atlas-create-jira-plugin

Необходимо ответить на вопросы вот так:

Define value for groupId: : ru.matveev.alexey.plugins.jira.cleanbackup
Define value for artifactId: : clean-backup
Define value for version:  1.0.0-SNAPSHOT: : 
Define value for package:  ru.matveev.alexey.plugins.jira.cleanbackup: : 

Confirm properties configuration:
groupId: ru.matveev.alexey.plugins.jira.cleanbackup
artifactId: clean-backup
version: 1.0.0-SNAPSHOT
package: ru.matveev.alexey.plugins.jira.cleanbackup
 Y: : Y

Редактируем POM.XML


Файл pom.xml должен выглядеть вот так:
bitbucket.org/alex1mmm/clean-backup/src/master/pom.xml

Создаем WEBWORK, WEB SECTION и WEB ITEM


Открываем терминал и выполняем:

atlas-create-jira-plugin-module

Ответить на вопросы нужно вот так:

Choose a number (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34): 31
Enter Plugin Module Name My Webwork Module: : cleanbackup
Show Advanced Setup? (Y/y/N/n) N: : y
Module Key cleanbackup: : 
Module Description The cleanbackup Plugin: : 
i18n Name Key cleanbackup.name: : 
i18n Description Key cleanbackup.description: : 
Enter Action Classname MyActionClass: : CleanBackup
Enter Package Name ru.matveev.alexey.plugins.jira.cleanbackup.jira.webwork: : 
Enter Alias CleanBackup: : CleanBackup
Enter View Name success: : success
Enter Template Path /templates/cleanbackup/cleanbackup/success.vm: : 
Add Another View? (Y/y/N/n) N: : N
Add Another Action? (Y/y/N/n) N: : N
Add Another Plugin Module? (Y/y/N/n) N: : Y
Choose a number (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34): 30
Enter Plugin Module Name My Web Section: : CleanBackup
Enter Location (e.g. system.admin/mynewsection): admin_plugins_menu
Show Advanced Setup? (Y/y/N/n) N: : n
Add Another Plugin Module? (Y/y/N/n) N: : Y
Choose a number (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34): 25
Enter Plugin Module Name My Web Item: : CleanAO
Enter Section (e.g. system.admin/globalsettings): admin_plugins_menu/clean-backup
Enter Link URL (e.g. /secure/CreateIssue!default.jspa): /secure/CleanBackup.jspa?
Show Advanced Setup? (Y/y/N/n) N: : Y
Module Key clean-ao: : 
Module Description The CleanAO Plugin: : 
i18n Name Key clean-ao.name: : 
i18n Description Key clean-ao.description: : 
Weight 1000: : 
Link Id clean-ao-link: : 
Enter Label Key clean-ao.label: : CleanBackup
Enter Label Value CleanAO: : CleanAO
Add Label Param? (Y/y/N/n) N: : n
Add Icon? (Y/y/N/n) N: : n
Add Tooltip? (Y/y/N/n) N: : n
Add Resource (Y/y/N/n) N: : n
Add Velocity Context Provider (Y/y/N/n) N: : n
Add Plugin Module Param? (Y/y/N/n) N: : n
Add Conditions? (Y/y/N/n) N: : n
Add Another Plugin Module? (Y/y/N/n) N: : n

Редактируем WEBWORK и SUCCESS.VM


Изменим наш success.vm так, чтобы наш webwork мог бы принимать два параметра: имя бэкапа и префикс:

clean-backup/src/main/resources/templates/cleanbackup/cleanbackup/success.vm.

Мы будем использовать SAX для работы с xml файлами, поэтому напишем фильтр для удаления таблиц:

clean-backup/src/main/java/ru/matveev/alexey/plugins/jira/cleanbackup/jira/webwork/TableFilter.java.
Теперь внесем изменения в webwork.

clean-backup/src/main/java/ru/matveev/alexey/plugins/jira/cleanbackup/jira/webwork/CleanBackup.java

Собираем и запускаем наш плагин


Идем в папку плагина и выполняем:

atlas-run

После того, как Jira запустилась, положим наш файл бэкапа в JIRA_HOME/import и перейдем в браузере по следующему адресу:

localhost:2990/jira/secure/CleanBackup.jspa

Вводим имя бэкапа, префикса и нажимаем на кнопку Clean:



Таблицы, с префиксом, который мы ввели, будут удалены из бэкапа и после этого можно восстанавливать Jira.

Комментарии (0)