среда, 10 апреля 2013 г.

Знакомство с Jenkins


Данное руководство содержит пошаговые инструкции для установки системы непрерывной разработки Jenkins. Развёртывание системы происходило на виртуальной машине под управлением Proxmox. Этапы настройки Proxmox и создания виртуальной машины опущены.
  1. Установка и настройка операционной системы.
    1.1. Cтавим голый CentOS. Я брал дистрибутив network install вот отсюда: http://centos.arcticnetwork.ca/6.3/isos/i386/CentOS-6.3-i386-netinstall.iso, однако на специфическом железе лучше скачать DVD, т.к. может понадобиться, например, собирать драйверы на сетевую карту.
    1.2. По умолчанию на свежей системе поднят только loopback интерфейс, поэтому при необходимости конфигурируем путём изменения файла /etc/sysconfig/network-scpipts/ifcfg-eth0 (установить параметр ONBOOT=”yes”) и запускаем скриптом ifup-eth0.
    1.3. Устанавливаем Midnight Commander, просто так, на всякий случай: yum install mc, При необходимости устанавливаем sshd: yum install openssh-server (вообще-то по дефолту ssh server уже должен быть установлен).
    1.4. Устанавливаем hostname (в файле /etc/sysconfig/network), меняем пароль рута, поскольку через Java-апплет управления, предоставляемый PROXMOX, как-то было неудобно эти параметры сразу нормально выставить.

    Затем смотрим ip-адрес ifconfig и конннектимся через SSH: ssh root@192.168.10.235
На этом этапе я забекапил виртуалку:
/var/lib/vz/backups//dump/vzdump-qemu-501-2012_10_09-18_06_01.tar.gz
  1. Установка и настройка Mercurial.
    2.1. Посмотрим, что у нас есть в репозиториях:
[root@jenkins-edi ~]# yum search mercurial
...
mercurial.i686 : A fast, lightweight distributed source control management system
...
[root@jenkins-edi ~]# yum info mercurial.i686
...
Version : 1.4
Release : 3.el6
Size : 1.5 M
...

Версии староваты. Поэтому подключим дополнительные репозитории по этому мануалу: http://repoforge.org/use/
[root@jenkins-edi ~]# rpm -Uvh http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.i686.rpm
...


Далее нам нужно включить репозиторий rpmforge-extra. Это осуществляется правкой конфигурационного файла /etc/yum.repos.d/rpmforge.repo. Нужная строка выделена жирным.

[rpmforge-extras]
...
enabled = 1
...

Проверяем версию доступного для установки Mercurial:

[root@jenkins-edi yum.repos.d]# yum info mercurial.i686
...
Version : 2.2.2
Release : 1.el6.rfx
Size : 2.8 M
Repo : rpmforge-extras
...

Теперь версия свежая. Вот её и установим.

[root@jenkins-edi yum.repos.d]# yum install mercurial.i686


Тут я решил создать ещё один бекап:
/var/lib/vz/backups//dump/vzdump-qemu-501-2012_10_10-12_14_44.tar.gz'


2.2. Теперь необходимо настроить ssh-доступ к репозиторию. Создаём нового пользователя и директорию для нашего будущего репозитория:

[root@jenkins-edi yum.repos.d]# adduser hg
[root@jenkins-edi yum.repos.d]# passwd hg
[root@jenkins-edi /]# su hg
[hg@jenkins-edi /]$ mkdir /home/hg/repo
[hg@jenkins-edi /]$ cd /home/hg
[hg@jenkins-edi ~]$ chmod 700 repo/
[hg@jenkins-edi ~]$ ll
итого 4
drwx------. 2 hg hg 4096 Окт 10 13:54 repo

Подготавливаем клиента. У меня это будет виртуальная машина с Windows XP. С официального сайта http://mercurial.selenic.com/ скачан дистрибутив Mercurial и установлен с указанием прописать в path путь до исполняемых модулей приложения.
Помимо этого установим Eclipse c JDK для создания тестового проекта, который мы будем размещать на наш сервер-репозитарий.
Для успешной работы Mercurial необходимо указать имя пользователя, которое будет фигурировать в каждом коммите. В нашем случае оно указывается в конфигурационном файле:
C:\Program Files\Mercurial\Mercurial.ini
Там мы в разделе [ui] прописываем следующее:
username = Dmirty Myasnikov <d****v@***.ru>
Также для успешного доступа к удалённому репозиторию через ssh нам необходимо указать используемый ssh-клиент под Windows. Я для этих целей установил TortoiseHG и в том же разделе конфигурационного файла Mercurial прописал (раскомментировал):
ssh = "C:\Progra~1\TortoiseHg\TortoisePlink.exe" -ssh -2
Первый тестовый проект разместим в каком-нибудь каталоге. Запустим командную строку Windows и перейдём в этот каталог. Затем будем выполнять команды для работы с репозиторием:

C:\Documents and Settings\Admin>cd c:\java\projects
C:\java\projects>cd HelloMercurials
C:\java\projects\HelloMercurial>hg init
C:\java\projects\HelloMercurial>hg add
adding .classpath
adding .project
adding .settings\org.eclipse.jdt.core.prefs
adding bin\ru\ediweb\ci\MyMain.class
adding bin\test\TestMyMain.class
adding src\ru\ediweb\ci\MyMain.java
adding src\test\TestMyMain.java
C:\java\projects\HelloMercurial>hg commit -m "First version of project"

А теперь склонируем репозиторий на удалённый сервер (параметр -v указываем для вывода дополнительной информации):

C:\java\projects\HelloMercurial>hg clone . ssh://hg@192.168.10.235/repo/HelloMercurial -v
running "C:\Progra~1\TortoiseHg\TortoisePlink.exe" -ssh -2 hg@192.168.10.235 "hg init repo/HelloMercurial"
running "C:\Progra~1\TortoiseHg\TortoisePlink.exe" -ssh -2 hg@192.168.10.235 "hg -R repo/HelloMercurial serve --stdio"
searching for changes
1 changesets found
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 7 changes to 7 files

Получилось! Попробуем что-нибудь изменить в проекте. К примеру я создал новый класс. Выполним следующие команды, чтобы добавить новые файлы, просмотреть изменения по сравнению с исходным проектом и закоммитить эти изменения:

C:\java\projects\HelloMercurial>hg add
adding bin\ru\ediweb\ci\SimpleClass.class
adding src\ru\ediweb\ci\SimpleClass.java
C:\java\projects\HelloMercurial>hg diff
diff -r 8e52463bc091 bin/ru/ediweb/ci/SimpleClass.class
Binary file bin/ru/ediweb/ci/SimpleClass.class has changed
diff -r 8e52463bc091 src/ru/ediweb/ci/SimpleClass.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ru/ediweb/ci/SimpleClass.java Wed Oct 10 16:38:29 2012 +0400
@@ -0,0 +1,14 @@
+package ru.ediweb.ci;
+
+public class SimpleClass {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
C:\java\projects\HelloMercurial>hg commit -m "Adding new class"

Проталкиваем изменения на сервер:

C:\java\projects\HelloMercurial>hg push ssh://hg@192.168.10.235/repo/HelloMercurial -v
pushing to ssh://hg@192.168.10.235/repo/HelloMercurial
running "C:\Progra~1\TortoiseHg\TortoisePlink.exe" -ssh -2 hg@192.168.10.235 "hg -R repo/HelloMercurial serve --stdio"
searching for changes
1 changesets found
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 2 changes to 2 files
  1. Теперь у нас есть свой Mercurial сервер с доступом к репозиторию по SSH. По идее перед тем как устанавливать Jenkins было бы неплохо на этом сервере развернуть какую-нибудь систему сборки проектов и автоматизированного тестирования, которые брали бы проект из репозитория Mercurial, собирали и тестировали бы его. Мой тестовый проект написан на Java, поэтому для экспериментов я поставлю Ant и JUnit. Помимо них нам ещё понадобится JDK для сборки.
В случае работы с PHP-проектами нам нужно будет дополнительно поднять веб сервер с PHP-движком, систему сборки Phing и, очевидно, какой-нибудь PHPUnit.

Вообще, можно поступить хитрее и попробовать настроить некоторые вещи через Jenkins. Однако мы всё сделаем руками, чтобы знать, что, где и зачем. Настройка Jenkins в плане привязки установленного программного обеспечения рассмотрена в п. 4.2.

Перед тем как идти дальше, забекапим-ка нашу виртуальную машину:
/var/lib/vz/backups//dump/vzdump-qemu-501-2012_10_10-16_57_06.tar.gz'

             3.1. Cкачиваем JDK c сайта Oracle и копируем его на наш хост:
На сервере:

[root@jenkins-edi ~]# mkdir install

На клиенте:

Z:\home\install\win\putty>pscp "c:\Documents and Settings\Admin\Мои документы\Downloads\jdk-7u7-linux-i586.rpm" root@192.168.10.235:/root/install/
root@192.168.10.235's password:
jdk-7u7-linux-i586.rpm | 123515 kB | 4117.2 kB/s | ETA: 00:00:00 | 100%

На сервере:

[root@jenkins-edi ~]# cd install
[root@jenkins-edi install]# rpm -i jdk-7u7-linux-i586.rpm

Проверяем, установилась ли Java:

[root@jenkins-edi install]# java -version
java version "1.7.0_07"
Java(TM) SE Runtime Environment (build 1.7.0_07-b10)
Java HotSpot(TM) Client VM (build 23.3-b01, mixed mode, sharing

3.2. Устанавливаем Ant. Предварительно устанавливаем wget.

[root@jenkins-edi ~]# yum install wget
[root@jenkins-edi install]# wget http://www.apache.org/dist/ant/binaries/apache-ant-1.8.4-bin.tar.bz2 /root/install
[root@jenkins-edi install]# tar xvf apache-ant-1.8.4-bin.tar.bz2
[root@jenkins-edi install]# mv apache-ant-1.8.4 /opt
[root@jenkins-edi install]# export JAVA_HOME=/usr/java/jdk1.7.0_07/
[root@jenkins-edi install]# export ANT_HOME=/opt/apache-ant-1.8.4/
[root@jenkins-edi install]# export PATH=$PATH:$ANT_HOME/bin

Последние три строки нужно бы добавить в ~/.bash_profile соответствующего пользователя, чтобы переменные окружения автоматически инициализировались при перезагрузке. Я работаю под рутом, поэтому в /root/.bash_profile добавил следующие строки:

JAVA_HOME=/usr/java/jdk1.7.0_07
export JAVA_HOME  
ANT_HOME=/opt/apache-ant-1.8.4/
export ANT_HOME
PATH=$PATH:$ANT_HOME/bin:$JAVA_HOME/bin
export PATH  

Проверяем, работает ли наш Ant.

[root@jenkins-edi install]# ant
Buildfile: build.xml does not exist!
Build failed

Ant работает. Теперь поколдуем над нашим тестовым проектом.

3.3. Скачаем JUnit на клиент, создадим Ant-скрипт, проверим работу всего этого на сервере.

На клиенте скачанный JUnit будет расположен в папке C:\Java в виде файла junit-4.10.jar. Попробуем для начала натравить JUnit на наш проект:

C:\java\projects\HelloMercurial>java -cp c:\java\junit-4.10.jar;.\bin\ junit.textui.TestRunner test.TestMyMain
..
Time: 0,016
OK (2 tests)

В сам проект добавим каталог /lib, куда поместим junit-4.10.jar (хотя это неправильно, но мы оставим так в тестовых целях, чтобы не править потом build.xml на сервере) и создадим buildfile для Ant следующего содержания:

<?xml version="1.0" encoding="UTF-8"?>
<project name="HelloMercurial" default="compile" basedir=".">
<path id="JUnit.classpath">
<pathelement location="./lib/junit-4.10.jar"/>
</path>

<path id="HelloMercurial.classpath">
<pathelement location="bin"/>
</path>

<target name ="compile" description="Compile project">
<javac srcdir="src" destdir="bin"/>
</target>
<target name ="test" description="Test project">
<junit printsummary="yes">
<classpath refid="JUnit.classpath" />
<classpath refid="HelloMercurial.classpath" />
<test name="test.TestMyMain"/>
</junit>
</target>
</project>

Весь это проект протолкнём в наш репозиторий:

C:\java\projects\HelloMercurial>hg add
adding build.xml
adding lib\junit-4.10.jar

C:\java\projects\HelloMercurial>hg commit -m "Tests, Ant build"
C:\java\projects\HelloMercurial>hg push ssh://hg@192.168.10.235/repo/HelloMercurial -v
pushing to ssh://hg@192.168.10.235/repo/HelloMercurial
running "C:\Progra~1\TortoiseHg\TortoisePlink.exe" -ssh -2 hg@192.168.10.235 "hg
-R repo/HelloMercurial serve --stdio"
searching for changes
1 changesets found
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 5 changes to 5 files

теперь на сервере сделаем следующее:

[root@jenkins-edi /]# cd /home/hg/repo/
[root@jenkins-edi repo]# hg clone HelloMercurial /root/HelloMercurial

обновляемся на ветку default

11 файлов обновлено, 0 слито, 0 удалено, 0 c конфликтами
[root@jenkins-edi repo]# cd /root/HelloMercurial/
[root@jenkins-edi HelloMercurial]# ant test
Buildfile: /root/HelloMercurial/build.xml

test:
[junit] Running test.TestMyMain
[junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0,002 sec

BUILD SUCCESSFUL
Total time: 0 seconds

И тут мы опять бекапимся! /var/lib/vz/backups//dump/vzdump-qemu-501-2012_10_11-17_21_58.tar.gz

  1. Отлично. Теперь на сервере у нас работают и Mercurial, и Ant и JUnit. Не совсем канонично настроенные, но вполне ок такие. Приступаем к установке Jenkins.
4.1. Добавляем нужные репозитории:

[root@jenkins-edi HelloMercurial]# wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
--2012-10-11 14:21:58-- http://pkg.jenkins-ci.org/redhat/jenkins.repo
Распознаётся pkg.jenkins-ci.org... 63.246.20.93
Устанавливается соединение с pkg.jenkins-ci.org|63.246.20.93|:80... соединение установлено.
Запрос HTTP послан, ожидается ответ... 200 OK
Длина: 75 [text/plain]
Saving to: «/etc/yum.repos.d/jenkins.repo»
100%[======================================>] 75 --.-K/s в 0s
2012-10-11 14:21:59 (11,4 MB/s) - «/etc/yum.repos.d/jenkins.repo» saved [75/75]
[root@jenkins-edi HelloMercurial]# rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key

Устанавливаем Jenkins:

[root@jenkins-edi HelloMercurial]# yum install jenkins

Открываем порт 8080 в IPTABLES

[root@jenkins-edi ~]# iptables -I INPUT 2 -p tcp -i eth0 --dport 8080 -j ACCEPT
[root@jenkins-edi ~]# iptables -A OUTPUT -p tcp --sport 8080 -j ACCEPT
[root@jenkins-edi ~]# /etc/init.d/iptables save

Запускаем Jenkins

[root@jenkins-edi ~]# /etc/init.d/jenkins start
Starting Jenkins [ OK ]

4.2.  Теперь мы можем обратиться к порту 8080 нашего хоста по http. Там мы должны увидеть веб-интерфейс Jenkins:
Рис. 1. Веб-интерфейс Jenkins.
Нажимаем на кнопку Manage Jenkins. На следующей странице нажимаем на Manage Plugins. Воспользовавшись поиском, поставим плагин Mercurial:

Рис. 2. Mercurial plugin.
Теперь нажимаем Manage Jenkins – Configure System. Указываем там параметры установленного на сервере JDK:
Рис. 3. Параметры JDK.
Параметры установленного Mercurial:
Рис. 4. Параметры Mercurial.
Параметры установленного Ant:
Рис. 5. Параметры Ant.
Нажмём кнопку Save, чтобы сохранить сделанные изменения и приступим к созданию нашего первого задания. Для этого нажмём на кнопку New Job и зададим имя заданию.
Рис. 6. Создание нового задания.
Настроим ежеминутную сборку нашего проекта, чтобы не пришлось долго ждать результата:


Рис. 7. Настройка проекта и планировщика сборки.
Далее на той же странице в разделе Build жмём кнопку Add build step и выбираем пункт Invoke Ant. Добавим два таких шага:
Рис. 8. Настройка сборки.
Сборка должна завершиться ошибкой. Ещё бы, ведь при доступе к репозиторию по SSH необходимо вводить пароль. Исправим это. Настроим SSH-авторизацию по RSA-ключу:
[root@jenkins-edi /]# sudo -u jenkins ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/var/lib/jenkins/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /var/lib/jenkins/.ssh/id_rsa.
Your public key has been saved in /var/lib/jenkins/.ssh/id_rsa.pub.
The key fingerprint is:
dd:78:a9:26:19:26:a8:ae:48:0f:04:29:80:9c:22:d1 jenkins@jenkins-edi
The key's randomart image is:
+--[ RSA 2048]----+
|=o. |
|=+E |
|* |
|o . . o . |
| . . . S o + |
|. . o o o |
| o. o o |
|o.o o |
|o... |
+-----------------+
[root@jenkins-edi /]# cat /var/lib/jenkins/.ssh/id_rsa.pub >> /home/hg/.ssh/authorized_keys

Добавим на хосте сами себя в список известных хостов:
[root@jenkins-edi bin]# sudo -u jenkins /usr/bin/ssh hg@192.168.10.235
The authenticity of host '192.168.10.235 (192.168.10.235)' can't be established.
RSA key fingerprint is f1:ff:dc:32:fe:42:50:84:74:7c:78:85:14:2d:df:5b.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.10.235' (RSA) to the list of known hosts.

В некоторых рекомендациях по конфигурированию Jenkins говорится следующее:
По умолчанию при выполнении задания у пользователя jenkins не определена переменная окружения HOME, поэтому он не знает, где ему искать параметры подключения к SSH-серверу. Поэтому необходимо в свойствах задания указать дополнительный параметр в разделе This build is parametrized.
У меня всё работает и без указания дополнительных параметров, однако на всякий случай я приведу скриншоты этих настроек. Думаю, они будут актуальны при хранении ssh-ключей в месте, отличном от JENKINS_HOME.

Рис. 9. Добавление строкового параметра.
Рис. 10. Необходимый параметр

Переходим на главную страницу и видим, что проект успешно собран:
Рис. 11. Первый успех.
Посмотрим, что у нас в потоке вывода. Подведём курсор мыши к нужному месту и выберем Console Output:
Рис. 12. Просмотр вывода сборщика проекта.
Вот что там у нас:

Started by timer
Building in workspace /var/lib/jenkins/jobs/MyFirstJob/workspace
[workspace] $ /usr/bin/hg showconfig paths.default
[workspace] $ /usr/bin/hg pull --rev default
[workspace] $ /usr/bin/hg update --clean --rev default
0 файлов обновлено, 0 слито, 0 удалено, 0 c конфликтами
[workspace] $ /usr/bin/hg log --rev . --template {node}
[workspace] $ /usr/bin/hg log --rev . --template {rev}
[workspace] $ /usr/bin/hg log --rev 67d89a607a40570bdd1a2b50c4cbd3eeac8fc9ac
[workspace] $ /usr/bin/hg log --template "<changeset node='{node}' author='{author|xmlescape}' rev='{rev}' date='{date}'><msg>{desc|xmlescape}</msg><added>{file_adds|stringify|xmlescape}</added><deleted>{file_dels|stringify|xmlescape}</deleted><files>{files|stringify|xmlescape}</files><parents>{parents}</parents></changeset>\n" --rev default:0 --follow --prune 67d89a607a40570bdd1a2b50c4cbd3eeac8fc9ac
[workspace] $ /opt/apache-ant-1.8.4/bin/ant test
Buildfile: /var/lib/jenkins/jobs/MyFirstJob/workspace/build.xml

test:
[junit] Running test.TestMyMain
[junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0,002 sec

BUILD SUCCESSFUL
Total time: 0 seconds
[workspace] $ /opt/apache-ant-1.8.4/bin/ant
Buildfile: /var/lib/jenkins/jobs/MyFirstJob/workspace/build.xml

compile:
[javac] /var/lib/jenkins/jobs/MyFirstJob/workspace/build.xml:13: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds

BUILD SUCCESSFUL
Total time: 0 seconds
Finished: SUCCESS

Тест и компиляция, заданные в соответствующем ant-скрипте проходят, как этого и следовало ожидать. С первичной настройкой сервера покончено.

Ссылки:

CentOS:
Официальный сайт Mercurial:
Графический клиент Mercurial под Windows:
Настройка сервера для работы с Mercurial:
Ant:
JUnit:
Jenkins:



среда, 3 апреля 2013 г.

Google Chrome + Keepass2 in Linux

Давно использую KeePass для хранения паролей, а автозаполнение форм почему-то не запиливал, занимаясь копипастом из приложения. Слегка погуглив, обнаружил, что можно сделать жизнь ещё проще.

1) Устанавливаем keepass2:
 root@meatx:/# apt-get install keepass2 mono-complete  
пакет mono-complete необходим для работы Keepass-плагина, обеспечивающего работу с расширением Google Chrome. Иначе можно было бы обойтись минимальной установкой mono для запуска Keepass.

2) Нужный нам плагин для Keepass называется keepasshttp. Проект этот располагается на Github по адресу https://github.com/pfn/keepasshttp. Скачиваем оттуда файлик KeePassHttp.plgx, который нужно поместить в директорию, в которой находится установленный Keepass:
 root@meatx:/home/saver# whereis keepass2  
 keepass2: /usr/bin/keepass2 /usr/lib/keepass2 /usr/bin/X11/keepass2 /usr/share/keepass2 /usr/share/man/man1/keepass2.1.gz  
 root@meatx:/home/saver# cp Downloads/KeePassHttp.plgx /usr/lib/keepass2/  

3) Запускаем Keepass и убеждаемся, что плагин подгрузился и работает:
4) Запускаем браузер, идём в Chrome Web Store и ищем плагин, который называется chromelPass. Устанавливаем.  Потом тыкаем на появившуюся иконку KeePass рядом с адресной строкой и жмём кнопку Connect. Плагин обращается к KeePassHttp и просит создать для него новый ключ. Придумываем ему какое-нибудь имя, сохраняем.

Теперь, в случае, если у записи в хранилище KeePass заполнено поле URL, браузер будет автоматически предлагать автозаполнение:
Ссылки: