Bitbucket POST HOOK для Yii2

Различные вопросы по установке и настройке фреймворка, конфигурции веб-сервера и IDE.
Ответить
Аватара пользователя
demisang
Сообщения: 159
Зарегистрирован: 2012.10.27, 15:03
Контактная информация:

Bitbucket POST HOOK для Yii2

Сообщение demisang »

Я написал свой первый хук и столкнулся с проблемой, я не могу через него применить миграции и ре-инициализировать приложение, вот код:

Код: Выделить всё

<?php

// Security key
$key = 'go6qyKw2tvDxbpG7Ss';
if (!isset($_GET['key']) || $_GET['key'] !== $key) {
    die;
}

// "/var/www/site/frontend/web/../../" => "/var/www/site"
$root_dir = rtrim(realpath(__DIR__ . '/../../'), '\\/');

// run git pull
$commands = array(
    'cd "' . $root_dir . '"',
    'git fetch --all',
    'git reset --hard origin/master',
    'git pull origin master'
);
$git_result = shell_exec(implode(' && ', $commands));

$php_command_tpl = '/usr/bin/php -q {file} &> /dev/null &';
// apply migrations & re-initialize application enviroment
$migrate_command = str_replace('{file}', '"' . $root_dir . '/yii" migrate/up --interactive=0', $php_command_tpl);
$init_command = str_replace('{file}', '"' . $root_dir . '/init" --env=Production --overwrite=All', $php_command_tpl);

$migrate_result = false;
$init_result = false;

// if changes exists
if (stripos($git_result, 'Already up-to-date') === false) {
    $migrate_result = shell_exec($migrate_command);
    $init_result = shell_exec($init_command);
} 
Когда срабатывает хук, то сервер примерно на минуту зависает, выбрасывает 500 ошибку и ssh становится недоступен, потом просерается и видно, что git pull сработал на ура, но вот миграции и ре-инициализация не прошли...
Если вручную в консоли ввести эти две команды(копировал из var_dump ручного запуска этого хука), то они работают.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Bitbucket POST HOOK для Yii2

Сообщение samdark »

Хук работает от веб-серверского юзера www-data. У него прав достаточно?
Аватара пользователя
demisang
Сообщения: 159
Зарегистрирован: 2012.10.27, 15:03
Контактная информация:

Re: Bitbucket POST HOOK для Yii2

Сообщение demisang »

Sam Dark писал(а):Хук работает от веб-серверского юзера www-data. У него прав достаточно?
В скрипте хука я вызвал:

Код: Выделить всё

var_dump(get_current_user());die;
И получил имя пользователя "xxxusername".
Владельцем файла в FileZilla отображается "2778 2778", я фиг знает кто это :o

Когда я подключаюсь к SSH, то использую то же самое имя пользователя, но в SSH я без проблем выполняю команду:

Код: Выделить всё

/usr/bin/php -q "/home/xxxusername/project_data/init" --env=Production --overwrite=All
и проект ре-инициализируется нормально.

На сам файл-хук поставлены права 0755, выше не получается, сервер ругается.
И ещё когда хук вызывается, то в течении минуты SSH недоступен, когда пытаешься вызвать любую команду, то выдаётся

Код: Выделить всё

-jailshell: fork: retry: Resource temporarily unavailable
и сам сайт выдаёт примерно такую же ошибку.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Bitbucket POST HOOK для Yii2

Сообщение samdark »

М... как там в jail я уже не помню. Скорее всего придётся хостера спрашивать.
Аватара пользователя
demisang
Сообщения: 159
Зарегистрирован: 2012.10.27, 15:03
Контактная информация:

Re: Bitbucket POST HOOK для Yii2

Сообщение demisang »

Sam Dark писал(а):М... как там в jail я уже не помню. Скорее всего придётся хостера спрашивать.
спасибо за помощь) Ну я думаю будет лучше и универсальнее выполнять консольные команды не чрез shell_exec, а напрямую инклудить файл "init.php", а так же вручную вызывать консольную команду для миграции :ugeek:
LAV45
Сообщения: 47
Зарегистрирован: 2014.01.16, 22:37

Re: Bitbucket POST HOOK для Yii2

Сообщение LAV45 »

Я обычно все это выполняю в отдельном потоке т.к. Nginx (или Apache) имеют свой лимит времени на выполнении скрипта, после истечении которого он просто рвет соединение и завершает скрипт.
fix для Apache в папку со свои скриптом можешь положить .htaccess приметно с таким кодом

Код: Выделить всё

# Не завершать скрипт даже если клиен разорвет соединение
php_flag allow_call_time_pass_reference on
# Снимаем ограничение по времени работы скрипта
php_flag max_input_time 0
php_flag max_execution_time 0
ЗЫ Это просто для общего понимания проблемы.

Но на этом не стоит заострять внимание. Вот рабочая версия моего решения.
Настраиваем на вашем git хостинге Web hooks на чтобы при каждом commit он вызывал ваш php скрипт

Код: Выделить всё

# Смотрим что пришло
$data = json_decode($HTTP_RAW_POST_DATA, true);
# Ищем имя ветки
preg_match('~([^/]+)$~', $data['ref'], $BR);
$BR = $BR[0];

if ( ! $BR ) exit('Incorrect data');

# Если ветка была удалена 
if ($data['after'] == '0000000000000000000000000000000000000000') {
    system('nohup rm -rf ../site.'.$BR.' ../deployment_'.$BR.'.log < /dev/null > /dev/null 2>&1 &');
    system('nohup mysql -u root -e "DROP DATABASE IF EXISTS w'.$BR.';" < /dev/null > /dev/null 2>&1 &');

# или добавлена новая ветка
} else {
    system('cd .. && nohup ./upgrade.sh '.$BR.' < /dev/null > deployment_'.$BR.'.log 2>&1 &');
}
В upgrade.sh можешь спокойно выполнять свой скрипт по выкатыванию проекта на обычном bash ;) .

ЗЫ nohup решает все проблемы :D одним & тут не отделаешься.
Аватара пользователя
demisang
Сообщения: 159
Зарегистрирован: 2012.10.27, 15:03
Контактная информация:

Re: Bitbucket POST HOOK для Yii2

Сообщение demisang »

Я последовал совету LAV45 и написал следующий код:

Файл /environments/prod/backend/web/bitbucket-hook.php:

Код: Выделить всё

<?php
// "/var/www/site/frontend/web/../../" => "/var/www/site"
$root_dir = rtrim(realpath(__DIR__ . '/../../'), '\\/');

shell_exec("cd $root_dir && nohup bash $root_dir/hook.sh >> hook.log 2> hook_err.log &> /dev/null &"); 
После ручной ре-инициализации проекта (/yii init) этот файл будет доступен извне по адресу: admin.site.com/bitbucket-hook.php

В этих строках кода мы вызываем bash-файл /hook.sh, который будет подтягивать изменения из репозитория, применять миграции и ре-инициализировать проект, кот скрипта:

Файл /hook.sh:

Код: Выделить всё

#!/bin/bash
now=`date`
printf "\n\nHook started at $now"
echo '---------------------------------------'
echo `
git fetch --all && 
git reset --hard origin/master && 
git pull origin master &&
php yii migrate/up --interactive=0 &&
php init --env=Production --overwrite=All
`

printf "Hook completed after ${SECONDS} seconds\n"
Здесь мы первыми тремя командами 100% подтянем все изменения из репозитория, 4-я команда применит все новые миграции, пятая команда ре-инициализирует проект с окружением "prod".
Символы && которые разделяют команды указывают на то, что команды должны выполняться последовательно, одна за другой.

Во время тестирования у меня возникла проблема с тем, что пользователь www-data не имел своей папки ~/.ssh, поэтому apache стандартно пытался найти ssh-ключи в папке /var/www/.ssh, я решил эту проблему простым копированием ключей root-пользователя в указанную директорию:

Код: Выделить всё

cp /root/.ssh/* /var/www/.ssh
После каждого запуска файла bitbucket-hook.php в корне проекта будут записываться два файла лога:
/hook.log - содержит весь текст, который отобразится при выполнении 5 вышеуказанных команд, файл каждый раз дополняется.
/hook_err.log - содержит ошибки, которые произошли при последнем запуске хука. У меня в него попадают всякие фигни от git`а, типа '\r': command not found или 6394d20..4733b26 master -> origin/master - это скорее всего не страшно ;)
LAV45
Сообщения: 47
Зарегистрирован: 2014.01.16, 22:37

Re: Bitbucket POST HOOK для Yii2

Сообщение LAV45 »

demisang писал(а):этот файл будет доступен извне по адресу: admin.site.com/bitbucket-hook.php
Это как бы не совсем по фэншую, но как тестовый(временный вариант) сойдет.

У меня для обновлений создан отдельный субдомен абракадабка.site.com у которого разрешен доступ только с одного IP адреса (например github)

Код: Выделить всё

server {
    listen 80;
    
    server_name абракадабка.site.com;

    root /var/www/upgrade;

    location / {
        allow 8.8.8.8; # IP которому разрешаем доступ
        deny all; # все остальные идут лесом 
    }
}
 
таким образом инициализировать обновление может сервер который нам присылает web-hook и из консоли (php bitbucket-hook.php)
Аватара пользователя
demisang
Сообщения: 159
Зарегистрирован: 2012.10.27, 15:03
Контактная информация:

Re: Bitbucket POST HOOK для Yii2

Сообщение demisang »

Можно просто по IP адресу разрешать доступ, например сервера bitbucket имеют два IP:
131.103.20.165
131.103.20.166
пруф
Ответить