Gerrit — это инструмент для code-review при совместной разработке командой девелоперов: http://code.google.com/p/gerrit/. Он тесно интегрирован с репозиторием Git. В нашей компании мы используем оба эти решения, и я как системный администратор отвечаю за их установку и поддержку.
Как часто бывает у свободно распространяемых продуктов, процедура их установка не универсальна и не всегда проходит гладко. В данной статье я не стараюсь заменить официальную документацию, а лишь опишу некоторые проблемы, которые возникли у меня при установке Gerrit версии 2.4 на машину с CentOS 6.3 x64. Официальная же документация по установке расположена здесь: http://gerrit-documentation.googlecode.com/svn/Documentation/2.4/index.html
Java
Пакет Java идущий в дистрибутиве CentOS’а java-1.5.0-gcj-1.5.0.0-29.1 работать не захотел. С ним при установке gerrit выдается ошибка:
$ java -jar gerrit- 2.4 .war init -d /home/gerrit2 fatal: Gerrit Code Review requires Java 6 or later (trying to run on Java 1.5 ) $ |
В дистрибутиве CentOS 6.3 отсутствует Java 1.6 поэтому пришлось установить пакет jre-6u35-linux-amd64.rpm с официального сайта Java: http://www.java.com/ru/download/index.jsp. С этой версией инсталлятор gerrit’а заработал. Вы можете держать в системе оба этих пакета — пакет из дистрибутива СentOS и пакет с официального сайта, но вы должны выбрать «правильную» версию Java, которая будет использоваться по умолчанию:
# alternatives --config java There are 2 programs which provide 'java' . Selection Command ----------------------------------------------- *+ 1 /usr/lib/jvm/jre- 1.5 . 0 -gcj/bin/java 2 /usr/java/latest/bin/java Enter to keep the current selection[+], or type selection number: 2 |
MySQL Database
База данных MySQL требует небольшого тюнинга.
В документации рекомендуют создавать базу с кодировкой latin1. Но для нас это не годится, т.к. мы планируем использовать русский язык в комментариях к коду, посему нам нужна кодировка utf8. Но просто сменив кодировку на utf8, мы все равно получаем при установке gerrit’а ошибку:
Exception in thread "main" com.google.gwtorm.server.OrmException: Cannot apply SQL CREATE TABLE account_project_watches ( notify_new_changes CHAR( 1 ) DEFAULT 'N' NOT NULL CHECK (notify_new_changes IN ( 'Y' , 'N' )), notify_all_comments CHAR( 1 ) DEFAULT 'N' NOT NULL CHECK (notify_all_comments IN ( 'Y' , 'N' )), notify_submitted_changes CHAR( 1 ) DEFAULT 'N' NOT NULL CHECK (notify_submitted_changes IN ( 'Y' , 'N' )), account_id INT DEFAULT 0 NOT NULL, project_name VARCHAR( 255 ) BINARY DEFAULT '' NOT NULL, filter VARCHAR( 255 ) BINARY DEFAULT '' NOT NULL ,PRIMARY KEY(account_id,project_name,filter) ) at com.google.gwtorm.jdbc.JdbcExecutor.execute(JdbcExecutor.java: 44 ) at com.google.gwtorm.jdbc.JdbcSchema.createRelations(JdbcSchema.java: 84 ) at com.google.gwtorm.jdbc.JdbcSchema.updateSchema(JdbcSchema.java: 54 ) at com.google.gerrit.server.schema.SchemaCreator.create(SchemaCreator.java: 108 ) at com.google.gerrit.server.schema.SchemaUpdater.update(SchemaUpdater.java: 55 ) at com.google.gerrit.pgm.Init$SiteRun.upgradeSchema(Init.java: 181 ) at com.google.gerrit.pgm.Init.run(Init.java: 79 ) at com.google.gerrit.pgm.util.AbstractProgram.main(AbstractProgram.java: 67 ) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java: 57 ) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: 43 ) at java.lang.reflect.Method.invoke(Method.java: 616 ) at com.google.gerrit.launcher.GerritLauncher.invokeProgram(GerritLauncher.java: 167 ) at com.google.gerrit.launcher.GerritLauncher.mainImpl(GerritLauncher.java: 91 ) at com.google.gerrit.launcher.GerritLauncher.main(GerritLauncher.java: 49 ) at Main.main(Main.java: 25 ) Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Specified key was too long ; max key length is 1000 bytes at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java: 57 ) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java: 45 ) at java.lang.reflect.Constructor.newInstance(Constructor.java: 532 ) at com.mysql.jdbc.Util.handleNewInstance(Util.java: 406 ) at com.mysql.jdbc.Util.getInstance(Util.java: 381 ) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java: 1030 ) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java: 956 ) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java: 3558 ) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java: 3490 ) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java: 1959 ) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java: 2109 ) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java: 2642 ) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java: 2571 ) at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java: 782 ) at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java: 625 ) at com.google.gwtorm.jdbc.JdbcExecutor.execute(JdbcExecutor.java: 42 ) ... 15 more |
Осмыслив описание проблемы в Java-эксепшене «Specified key was too long; max key length is 1000 bytes» и просуммировав в уме длины полей первичного ключа таблицы (255 + 255 + sizeof(INT)) видим несоответствие. Эксепшен возникает из-за физического ограничения типа хранилища MyISAM. А несоответствие в цифрах объясняется тем, что в типе VARCHAR при использовании кодировки utf-8 один символ кодируется не одним, а двумя байтами. Отсюда и получается превышение лимита. Так что лучше не экспериментируйте, а сразу создавайте таблицы в типе InnoDB. Сделать это проще всего с помощью включения в секцию [mysqld] конфига MySQL /etc/my.cnf следующей директивы:
default -storage-engine=InnoDB |
а также добавления строчек с основными настройками InnoDB:
# Uncomment the following if you are using InnoDB tables innodb_data_home_dir = /var/lib/mysql innodb_data_file_path = ibdata1:10M:autoextend innodb_log_group_home_dir = /var/lib/mysql |
После рестарта mysql сервера уже можем создавать базу данных:
CREATE USER 'gerrit2' @ 'localhost' IDENTIFIED BY 'secret' ; CREATE DATABASE reviewdb; ALTER DATABASE reviewdb charset=utf8; GRANT ALL ON reviewdb.* TO 'gerrit2' @ 'localhost' ; FLUSH PRIVILEGES; |
Установка веб-интерфейса
sudo adduser gerrit2 sudo su gerrit2 |
Небольшое отличие от настроек по умолчанию — мы используем HTTP-авторизацию, а также, как было указано выше, java с официального сайта, поэтому этот шаг инсталляции проходим следующим образом:
# java -jar gerrit- 2.4 .war init -d /home/gerrit2 *** Gerrit Code Review 2.4 *** *** Git Repositories *** Location of Git repositories [git]: *** SQL Database *** Database server type [H2/?]: mysql Server hostname [localhost]: Server port [(MYSQL default )]: Database name [reviewdb]: Database username [gerrit2]: gerrit2's password : secret confirm password : secret *** User Authentication *** Authentication method [OPENID/?]: http Get username from custom HTTP header [y/N]? SSO logout URL : *** Email Delivery *** SMTP server hostname [localhost]: SMTP server port [( default )]: SMTP encryption [NONE/?]: SMTP username : *** Container Process *** Run as [gerrit2]: Java runtime [/usr/lib/jvm/jre- 1.5 . 0 -gcj]: /usr/java/jre1. 6 .0_35 Copy gerrit.war to /home/gerrit2/bin/gerrit.war [Y/n]? Copying gerrit.war to /home/gerrit2/bin/gerrit.war *** SSH Daemon *** Listen on address [*]: Listen on port [ 29418 ]: Gerrit Code Review is not shipped with Bouncy Castle Crypto v144 If available, Gerrit can take advantage of features in the library, but will also function without it. Download and install it now [Y/n]? Downloading http: //www.bouncycastle.org/download/bcprov-jdk16-144.jar ... OK Checksum bcprov-jdk16- 144 .jar OK Generating SSH host key ... rsa... dsa... done *** HTTP Daemon *** Behind reverse proxy [y/N]? y Proxy uses SSL (https: //) [y/N]? y Subdirectory on proxy server [/]: Listen on address [*]: Listen on port [ 8081 ]: Canonical URL [https: //gerrit.mydomain.ru/]: Initialized /home/gerrit2 |
Обязательный тюнинг конфигов
Вот здесь начинается самое интересное.
Первым делом создаем файл /etc/default/gerritcodereview. В нем обязательно должна быть как минимум одна строка:
GERRIT_SITE=/home/gerrit2 |
Редактируем /home/gerrit2/etc/gerrit.config. Часть этих настроек уже может присутствовать.
# Путь к репозиториям git. В нашем случае это /home/gerrit2/git # canonicalWebUrl - URL. В документации пишут что оно не обязательно, но без него у меня наблюдались проблемы. [gerrit] basePath = git canonicalWebUrl = https: //gerrit.mydomain.ru # Информация о базе данных. Обратите внимание на запись url. # Без нее большие проблемы с отображением и хранением русских букв, т.е. с кодировкой. # url - настроки для доступа к базе данных. Я нашел эту информацию в документации по MySQL. # Без такого url'а русский язык отображаться не будет. [database] type = MYSQL hostname = localhost database = reviewdb username = gerrit2 url = jdbc:mysql: //localhost/reviewdb?useUnicode=true&characterEncoding=utf8&characterSetResult=utf8&connectionCollation=utf8_bin # Тип аутентификации. У нас это HTTP [auth] type = HTTP # Почта [sendemail] smtpServer = localhost # Месторасположение JAVA [container] javaHome = /usr/java/jre1. 6 .0_35/ # Параметры встроенного ssh-сервера. maxAuthTries - по умолчанию 6 , в рабочих условиях мне было мало. [sshd] listenAddress = *: 29418 maxAuthTries = 10 # Встроенный proxy-сервер. Apache описываемый далее, авторизует пользователей по HTTP и перенаправляет запросы на этот встроенный HTTP-сервер организованый на jetty. [httpd] listenUrl = proxy-https: //127.0.0.1:8081/ requestLog = true # Дисковый кэш. У нас это /home/gerrit2/cache [cache] directory = cache # Уже не помню для чего именно я это прописывал, но что-то без этого не работало. [user] email = sysadm @mydomain .ru # Мелкая красявость в review [commentlink "changeid" ] match = (I[ 0 -9a-f]{ 8 , 40 }) link = "#q,$1,n,z" # В release note к версии gerrit 2.4 . 2 категорически рекомендуется или обновиться или сделать нижеследущие настройки [cache "permission_sort" ] memoryLimit = 0 maxAge = 1s # Месторасположение gitweb'а в CentOS 6.3 отличается от настроек gerrit по умолчанию. [gitweb] cgi = /var/www/git/gitweb.cgi |
Редактируем /home/gerrit2/etc/secure.config. В нём тоже самое, что и в предыдущем конфиге. Но хранится он отдельно, для большей безопастности.
# Пароль к базе данных [database] password = secret # Хэш генерирующийся автоматически во время установки. Используется gerrit'ом для собственных нужд. [auth] registerEmailPrivateKey = LONGHASHKEYXXXXXXXXXXXXXXX |
Apache
Использую следующие настройки /etc/httpd/conf.d/gerrit_mydomain_ru.conf
ServerName gerrit.mydomain.ru SetEnvIf User-Agent ".*MSIE.*" \ nokeepalive ssl-unclean-shutdown \ downgrade- 1.0 force-response- 1.0 LogLevel warn SSLEngine on SSLProtocol all -SSLv2 SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW SSLCertificateFile sslcert/server.crt SSLCertificateKeyFile sslcert/server.key SSLCertificateChainFile sslcert/server.crt SSLVerifyClient none ProxyRequests Off ProxyVia Off ProxyPreserveHost On
Order deny,allow Allow from all
AuthType Basic AuthName "Gerrit Code Review" AuthUserFile /home/gerrit2/etc/.htpasswd Require valid-user
# проксируемся к 8081 порту ProxyPass / http: //127.0.0.1:8081/ |
При данных настройках не забываем включать модули апача: ssl, proxy, proxy_http. А также добавлять пользователей с паролями в файл /home/gerrit2/etc/.htpasswd. Первый залогинившийся пользователь получает права администратора.