пятница, 17 октября 2014 г.

Java ME на Freescale FRDM-K64F

The statements and opinions expressed here are my own and do not necessarily represent those of Oracle Corporation.
Всё, что написано ниже, я выдумал, предаваясь фантазиям. Воспринимайте это как шутку.

Главное

Вышел early-access релиз Java ME Embedded для девелоперской платы Freescale FRDM-K64F.
Если у вас есть такой дружок, можно, ознакомившись с краткой инструкцией по быстрому старту, сконфигурировать устройство для запуска на нём мидлетов и немного поиграться. Я тут попишу немного про подключение к устройству, написание небольшого демо-приложения с раскрытием структуры проекта и работу с device acces API, ок?
Главное - это в процессе конфигурирования не забыть в конце файла jwc_properties.ini прописать сетевые параметры устройства, чтобы потом можно было подключить его к device-manager'у из состава Java ME SDK, соответствующую версию EA 8.1 которого тоже необходимо предварительно скачать и установить. В принципе, если у нас в системе установлены USB-драйверы устройства, то мы сможем подключаться к нему и по COM-интерфейсу, но это будет работать заметно медленнее.

Подключение к устройству

Ну, ладно. Microsd-карточку с преднастроенными параметрами в плату воткнули, нужную версию файла java.bin на flash-устройство, которым девайс определился в системе положили, попробуем подключиться и посмотреть, что у нас есть. Сделать это можно несколькими способами:
  • Способ первый - тру-хардкор-коммандлайн для бородатых ребят. В каталоге с установленной Java ME SDK ищем файл toolkit-lib\lib\proxy.jar. Можно, кстати, взять его и из дистрибутива платформы для K64, там он лежит в каталоге util. Ну, и применяем из командной строки к нему такой подход: java -jar proxy.jar -socket X.X.X.X -debug, где вместо X.X.X.X требуется подставить ip-адрес устройства, который мы предусмотрительно прописали в файле jwc_properties.ini. После этого можно каким-нибудь клиентом типа putty в RAW-режиме подключиться на localhost:65002 и узреть там примерно следующее: 
    Это так называемая ams-консоль, через которую можно и по устройству пошариться, и мидлетами поуправлять. 
  • Способ второй - с кнопочками. Опять же идём в каталог Java ME SDK и запускаем bin\device-manager.exe. Тут же в системном трее появится значок, дважды кликнув на который, вы увидите окно, в котором по нажатию кнопки Add можно будет вписать IP-адрес очередного устройства (или же по COM-порту подключиться, избрав не наш путь). Устройство получит не особо о чём-то говорящее имя вроде EmbeddedExternalDeviceX, и проверить его можно, если кликнуть по тому же значку device-manager'а в системном трее правой кнопкой и выбрать пункт Registered devices. Если же хочется его поменять, то рекомендую открыть файл в домашнем каталоге пользователя, из-под учётной записи которого запускается Java ME SDK, что-то типа такого вот C:\Users\%ИМЯ_ПОЛЬЗОВАТЕЛЯ%\javame-sdk\%ВЕРСИЯ_SDK%\device-detection\connections.xml и поправить в нём поле <void property="deviceName"> <string>%ИМЯ_УСТРОЙСТВА%</string></void> соответствующей борды. Легко найти. У меня оно переименовано в fsk64 теперь выглядит так: 
    Сконфигурировав подключение, запускаем из каталога Java ME SDK бинарник эмулятора с такими ключами:
    bin\emulator.exe -Xjam -Xdevice:fsk64,
    после чего радуемся открытому окну, в меню которого можно почитать логи и поуправлять устройством. Кстати, данный способ не лишает нас радостей и ams-консоли. После запуска этого эмулятора мы так же можем подсоединиться на localhost:65002 и сделать всё, что нужно.
  • Способ третий - самый ленивый и является продолжением второго. Ставим NetBeans (так уж получилось, что на настоящий момент эта IDE лучше вех интегрируется с JavaME), указываем в настройках Tools - Java Platforms путь до нашей Java ME SDK и создаём Java ME проект, в свойствах которого указываем необходимость запуска приложение на девайсе fsk64:

Напишем что-нибудь

Девайс оборудован несколькими кнопками, LED-индикаторами и акселерометром. К этим устройствам можно обращаться через Java ME DAAPI. Писать я буду примитивный детектор тряски, собирающий показания с акселерометра и зажигающий индикатор при изменении показателей в пределах погрешности. Полезным будет почитать datasheet акселерометра и ознакомиться вот с этими исходниками.
Чтобы получить список всех устройств на борту платы, не прибегая к чтению спецификаций, можно задействовать примерно такой код:

Iterator l = DeviceManager.list();
while(l.hasNext())
{
   DeviceDescriptor d = (DeviceDescriptor) l.next();
   System.out.println(d.getName()+"; "+d.getID()+"; "+d.getConfiguration());
}

Получив на выходе что-то типа списка:

PC2; 101; jdk.dio.counter.PulseCounterConfig@9f3ec512
PC1; 100; jdk.dio.counter.PulseCounterConfig@9820de3e
PWM1; 301; jdk.dio.pwm.PWMChannelConfig@2a63e1f7
ADC5_PTC10; 505; jdk.dio.adc.ADCChannelConfig@fd339546
FXOS8700CQ; 300; jdk.dio.i2cbus.I2CDeviceConfig@11e7c3f
ADC4_PTC11; 504; jdk.dio.adc.ADCChannelConfig@fd16fc55
ADC3_PTB11; 503; jdk.dio.adc.ADCChannelConfig@fcfa6364
ADC2_PTB10; 502; jdk.dio.adc.ADCChannelConfig@fcddca73
SPI_Slave; 12; jdk.dio.spibus.SPIDeviceConfig@279b1931
ADC1_PTB3; 501; jdk.dio.adc.ADCChannelConfig@fcc13182
ADC0_PTB2; 500; jdk.dio.adc.ADCChannelConfig@fca49891
UART3; 40; jdk.dio.uart.UARTConfig@30605d5
DAC0; 700; jdk.dio.dac.DACChannelConfig@3350d998
LEDS; 8; jdk.dio.gpio.GPIOPortConfig@e16b5918
SW3; 6; jdk.dio.gpio.GPIOPinConfig@a53bead
SW2; 5; jdk.dio.gpio.GPIOPinConfig@a56fc99
LED3; 3; jdk.dio.gpio.GPIOPinConfig@34faede4
LED2; 2; jdk.dio.gpio.GPIOPinConfig@34fb3292
LED1; 1; jdk.dio.gpio.GPIOPinConfig@34fafb7d

Мы будем работать с двумя устройствами: снимать показания с акселерометра FXOS8700CQ и при изменении данных показаний зажжём светодиод LED3.
Весь код проекта традиционно лежит на гитхабе.
Вот как это выглядит в жизни:

четверг, 25 сентября 2014 г.

JTHarness и его TestSuites

The statements and opinions expressed here are my own and do not necessarily represent those of Oracle Corporation.
Всё нижеописанное - выдумка автора и противоречит здравому смыслу и взглядам компаний всего мира.

Что? Зачем?

Java ME тут тестирую волею судеб, саму платформу то есть. Тестирование происходит путём написания приложения, работающего на поддерживаемой платформе. А как протестировать приложение или библиотеку, которая крутится где-то на удалённой железке? Нужно же и разместить его там, и запустить, и результаты выполнения получить. Для таких дел пацаны и запилили ME Framework, а на его основе – JT Harness. Ща понапишем чего-нибудь, используя эти штуковины.
Вообще, JTHarness – это такое говно мамонта теперь OpenSource-проект со страничкой на java.net, однако там почему-то нет последних известий о переводе его на mercurial-репозиторий, а вот, например, в здешних обновлениях – есть. На всякий случай – ссылки на репозиторий и страницу, с которой можно скачать все версии данного продукта, а то они, конечно, гуглятся, но внутри данных проектов расположены как-то неочевидно.

Разработаем первый тест

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

Соберём всё в кучу

Для начала ознакомимся с документиком по диагонали. А для верности высосем его себе. Помимо него есть мануал посвежей. Также на всякий случай сохранённый.
Из софта нам понадобится JDK, JT Harness и Java ME SDK (на момент 09.2014 реализована только на платформе MS Windows). Выкачиваем, устанавливаем, пляшем.
Я возьму себе версию JTHarness 4.4.1, чтобы не натыкаться на свежие баги. Распаковываем этот архив куда-нибудь и изучаем золотые слова из мануала:
Процесс выполнения набора тестов.
Распаковалось. Хорошо. Можно посмотреть на примеры в папке Examples, содержащей внутри себя Entrylevel-туфту, а можно пилить и собственный TestSuite. Для написания своего набора тестов придётся проделать следующие процедуры:
  1. Создать директорию, где мы будем копить тесты, их исходники, описания и прочую шелупонь;
  2. Создать описание набора тестов;
  3. Подготовить библиотеки для запуска JTHarness и удовлетворения всяческих зависимостей;
  4. Подготовить директорию classes;
  5. Написать тест(ы);
  6. Скомпилировать;
  7. Запустить и посмотреть, как оно там.
Этим и займёмся.

Подготовка директории для набора тестов

Тут всё очень просто – создаём директорию с названием нашего TestSuite, а в ней – поддиректории:
  • tests, для складирования исходных кодов наших тестов, они понадобятся для того, чтобы круто выглядеть в отчётах, демонстрируя, что же именно у нас попадало;
  • lib, для всяких зависимостей, а также основной библиотеки javatest.jar;
  • classes, для скомпилированных классов-тестов, потому что глупенький JTHarness будет собирать из них пакеты для пересылки на тестируемую платформу, а ещё туда придётся вытащить классы-зависимости из библиотек, расположенных в директории lib.
На этом пока всё. Нормальные пацаны ещё частенько src и doc создают, но нам этого пока не нужно.

Создание описания набора тестов
Это файл с именем testsuite.jtt, содержащий в себе описание теста, точнее имена соответствующих используемых классов. Думаю, написание таких классов оставим на будущее, а пока, согласно рекомендациям в документе, наполним файл следующим содержимым:
# Test Suite properties file for DemoTCK test suite 
# with tag-style tests
name=My Test Suite
id=1.0
finder=com.sun.javatest.finder.TagTestFinder
script=com.sun.javatest.lib.StdTestScript
interview=com.sun.javatest.interview.SimpleInterviewParameters
Типа, у нас тут всё по дефолту.

Собираем JAR-файлы 

В каталог lib необходимо положить javatest.jar и jh.jar из скачанного дистрибутива JT Harness. Это сейчас, в примитивном тесте. А вообще, туда придётся складывать все библиотеки, использованные при написании тестов.

Подготавливаем директорию classes

Вообще, в мануале предлагают экспортировать туда используемые class-файлы из библиотеки javatest.jar вот такой командой:
jar -xvf ..\lib\javatest.jar com\sun\javatest\Test.class
com\sun\javatest\Status.class
Но я ленив, и просто пропишу в дальнейшем в classpath теста путь до целой библиотеки.

Пишем сам тест

Исходники теста необходимо положить в каталог tests (или там же прямо их и писать). Откомпилированный результат - в каталоге classes. В качестве примера я засвинячил коварный тест, который псевдослучайным образом то, хрипя, заваливается набок, то успешно проходит. Подлый исходник прилагаю картинкой:
Исходник теста
Тут нужно обратить внимание на закомментированную секцию перед объявлением класса. В ней указаны инструкции для JT Harness, чтобы он распознал тест из исходника. А вот и таблица из оригинального мануала, которую мне лень переводить:
Расшифровка параметров
Почти всё. Мы, в принципе, готовы к компиляции и запуску, однако встаёт один вопрос -- как организовать работу со всем этим хозяйством. Можно положить сорцы в каталог tests и компилировать/перекладывать руками, а можно и какой-нибудь системой автоматической сборки воспользоваться. Я решил угореть по Maven. Собственно, каноничная структура проекта такова:
Золотые слова
У меня же, получается, будет отдельный Maven-проект со своими зависимостями, который при вызове mvn prepare-package будет по кусочкам собирать TestSuite в каталоге target. Залил эту фигню на Гитхаб, где и буду далее над ней издеваться. На текущий момент - вот, что представляет собой вышеописанное:
https://github.com/savermyas/JTHarnessSimpleTest/releases/tag/v1.0
Интересного там пока не очень много:
- Скрипт, выкачивающий архивы JTHarness и инсталлирующий их в локальный Maven-репозиторий (в сетевых-то репах этого добра нет, хехехе) - install_dependency.sh
- Описание проекта pom.xml. Всего пара интересных мест - это сборка проекта в каталоге target:

и запуск JavaTest с необходимыми параметрами:
После того, как откроется основное окно JTHarness, необходимо настроить запуск теста, указав путь до бинарника Java. Это делается следующим образом: Configure -> Edit configuration -> Java Virtual Machine. Ну, а потом можно кликать по кнопке запуска тестов, наслаждаясь случайным результатом.
Понятно, что представленный пример тривиален, и из него совершенно невозможно выжать то, для чего нужен этот JTHarness. А нужен он для распределённого запуска тестов, снятия результатов тестирования с удалённых устройств, сбора информации в одном месте, генерации отчётов и прочих штуковин, которые будут рассмотрены в будущем.


вторник, 12 ноября 2013 г.

Dell MD3200. Работа с логическими томами, подключение к vSphere.

Предисловие

Привет, бложек. Есть одно хранилище, DAS Dell MD3200. Чтобы не забыть, как создавать в нём всякие группы дисков, настраивать подключение к VmWare и прочее, запишу-ка я это дело сюда. Полка хранилища уже смонтирована в стойку, подключена SAS-кабелями к хостам, сетевыми кабелями к коммутатору, туда же подключена рабочая станция с управляющим ПО PowerVault MD Storage Manager, сконфигурирована для работы с сетью и забита дисками. Возьмём 4 таких свежевоткнутых диска и создадим на них что-нибудь полезное.

Создание группы дисков

Открываем Storage Manager и видим следующее:
Рис. 1
Можно, конечно, прямо здесь нажать на Create Storage под значком Unconfigured, но мы зайдём на вкладку Storage & Copy Services и посмотрим, что у нас есть в пункте Total Unconfigured Capacity, нажав на нём правой кнопкой мыши.

Рис. 2
А там можно посмотреть, какие физические диски предоставляют пространство для выделенной несконфигурированной группы. 

Рис. 3
Посмотрели, убедились, что мы сейчас будем конфигурировать именно те диски. Используемых дисков у нас меньше 11, так что Disk Pool мы создать не можем, поэтому создадим Disk Group. Собственно, жмём Create Disk Group, жмём Next и задаём имя (в нашем случае будет backup_8Tb)

Рис. 4
Выбираем тип RAID-а и его объём, зависящий от количества дисков (мы выберем RAID10 из четырёх HDD):
 Рис. 5
После этого жмём Finish, а далее можем либо сразу согласиться на создание виртуального диска, либо нажать No, проверить, что всё ок, а потом нажать правой кнопкой на Free Capacity в свежесозданной дисковой группе и выбрать Create Virtual Disk.
Рис. 6
В окне создания виртуального диска необходимо указать его имя, ёмкость, хост или группу хостов, к которой диск можно подключить и тип характеристик. На скриншоте всё это видно. Ждём некоторое время, пока диск собирается, и идём дальше.

Настройка подключения хостов на MD3200

Каждый хост подключается по SAS-кабелю через свой контроллер. У нас, например, конфигурация с двумя контроллерами в хранилище и двумя SAS-разъёмами на HBA-плате. Физически подключение имеет следующий вид:
Рис. 7
Рисунок, кстати, спёрт из этой статьи. В ней ещё некоторые вопросы кабельного подключения рассматриваются.
Подключенные хосты можно через Storage Manager обнаружить в разделе Host Mappings. Если есть какие-то необработанные подключения, то они должны быть здесь:
Рис.  8
Правильным подходом будет создать группу хостов и поместить туда хосты в соответствии с логикой доступа хостов к группам дисков. У нас все имеют доступ ко всем, поэтому хосты просто добавлены в одну группу.

Конфигурирование VMFS хранилища на хосте vSphere

После настройки и предоставления прав доступа хостов на полке MD3200 нам необходимо подключить соответствующие виртуальные диски к хостам гипервизора. Для этого сначала убедимся, что гипервизор видит необходимое оборудование. Залогинимся в наш vCenter, зайдём в Inventory - Hosts and Clusters, выберем один из подключенных к хранилищу хостов и перейдём на закладку Configuration - Storage Adapters:
Рис. 9
В данном разделе мы можем пощёлкать по адаптерам и посмотреть их состояние, а также какие разделы на данных адаптерах доступны. Убедившись, что всё ок, переходим в Inventory - Datastores and Datastore Clusters и выбираем пункт Add a Datastore. Запускается мастер, в котором сначала предлагается выбрать хост, подключенный к хранилищу, затем выбрать тип (LUN или NFS, мы выбираем LUN), а затем выбрать идентификатор подключенного тома. Ещё на этапе создания виртуального диска в MD3200 мы уже запомнили нужный нам LUN, поэтому выбираем его тут:
Рис. 10
Далее выбираем тип файловой системы, подтверждаем свой выбор, задаём имя хранилища, его размер и приступаем к созданию (рис. 11-15):
Рис. 11
 
 Рис. 12
 Рис. 13
 Рис. 14
Рис. 15
После этого мы должны создать Datastore Cluster и добавить туда созданное хранилище. Готово!

понедельник, 11 ноября 2013 г.

Alcatel-Lucent OXE. Патчим CPU, роумим DECT, лезем в LDAP

Вторая, но, возможно, не последняя статья из цикла былого опыта. Пригодится.

Установка патча на CPU-плату.

Перед началом установки патча необходимо выбрать рабочую станцию или сервер, с которой телефонная станция будет забирать обновления. На выбранной машине у нас должны быть права администратора, чтобы установить OmniPCX Enterprise PC Installer и запустить tftp-сервер. Обязательно нужно проверить, видит ли АТС выбранную станцию командой ping. Можно, конечно, извернуться и поднять сервер на *nix-тачке, но мы же entry-level администраторы и не ищем сложных путей, поэтому:

1) На выбранной машине устанавливаем программу OmniPCX Enterprise PC Installer. Её дистрибутив лежит в каждом релизе патча. Вот здесь (на примере 50-го патча):
\dhs3mgr\h130150\pcmao\boot_res\pcinstall

2) Затем на данной машине нужно остановить брандмауэр, запустить службу обозревателя и запустить инсталлятор в режиме Call handling or patch. Окно будет выглядеть примерно так (ну, кроме надписей в полях ввода):


Рис. 1

Поскольку мои АТС-ки были представлены в двухпроцессорных конфигурациях, была возможность обновлять софт, не прерывая работы станции. На некоторое время отвалятся лишь IP-соединения при переходе телефонии с основной платы на резервную. Для начала нам нужно понять, которая из плат в данный момент активна, а которая находится в режиме STAND-BY. Традиционно на всех станция основной платой являлась CPU с именем xb…, которая соответствует плате, установленной в слоте номер 6 (решение, возможно, спорное и необязательное, но так уж всё было настроено на всех узлах ABC-F сети, и проще было в дальнейшем придерживаться этой идеи, чем всё переконфигурировать). Текущую роль платы можно посмотреть, выполнив команду role.
Также проверяем, синхронизированы ли платы командой twin. Если нет, то необходимо вручную выполнить перенос всех баз с основной платы на резервную. Может быть, это будет рассмотрено в другом мануале.

3) Итак, командой role мы выяснили, которая из плат находится в режиме STAND-BY. Если нам необходимо установить динамический патч (с буквой после полного номера релиза), то телефонию можно не останавливать, и вообще устанавливать патч «на горячую». Однако в случае статического патча делаем следующее (залогинившись по ssh или telnet на плату под пользователем mtcl):
- swinst (пароль SoftInst)
- 1 Easy menu
- 7 Stop the telephone

4) Ставим патч:
- swinst
- 2 Expert menu
- 2 Deliveres installation
- 1 Install delivery from server

На запрос Enter the name of the server (default xxx.xxx.xxx.xxx) ->  вводим ip-адрес компьютера, на котором запущен OmniPCX Enterprise PC Installer). Далее ввод выделен полужирным шрифтом:

The installation of the binaries will modify the current installed version
Please, confirm the installation of a new version (y/n, default y): y
Enter the full path of the delivery on the server
example for Unix server: /twdhs3/dhs3ref/dhs3ref_d2/E2.504/LIVRAISON
for Windows server: /dhs3mgr/E2504
-> /dhs3mgr/h130150a (относительный путь до патча, в данном примере приведён динамический патч)
Confirm the full path /dhs3mgr/h130150a (y/n, default y): y
The path of the delivery is /dhs3mgr/h130150a
Do you wish to secure the installation (y/n): n

Если мы ставим сначала статический, а затем динамический патч, то данный пункт можно и даже желательно сразу же повторить ещё раз, уже для динамического патча. При этом не стоит пугаться, если сразу после установки статического патча мы увидим что-то вроде:
End of post installation
In order to run the Linux packages
In order to run the emulation layer
YOU HAVE TO REBOOT THE SYSTEM
Press return
In order to install the swinst package
you are reconnected as swinst user.
End of operation!
Local and twin cpus have different software number
- on local cpu : DELIVERY h1.301.50
- on twin cpu : DELIVERY h1.301.50.a
running new swinst profile
Confirm that 'ru' will be used as EXPORT version (y/n, default y):
*** Creation of the missing main directories
*** Creation of the missing swinst directories
A periodic backup is already registered
Last installed delivery
DELIVERY h1.301.50

значит, всё нормально! Патч встал! При последовательной установке сразу нескольких патчей перезагружать плату между инсталляциями необходимости нет.

5) Включаем автостарт сервисов телефонии (если ранее она была остановлена):
- swinst
- 2 Expert menu
- 6 System management
- 2 Autostart management
- 1 Set autostart

6) После того, как все патчи установлены, если среди установленных патчей у нас имелся хоть один статический, то нужно перезапустить плату, на которой мы его устанавливали:
shutdown -r now

7) Проверяем, всё ли поднялось, командой twin. Выполнять данную команду можно на любой из процессорных плат:
(105)xa001005> twin
Tue Jan 31 16:57:19 GMT-4 2012
Usage : twin [Redundancy Cpu Enable (y/n)]
Role and CPU positions:
Role of the CPU : STAND BY
CPU position : 20
CPU address : aaa.aaa.aaa.aaa
Twin CPU position : 06
Twin CPU address : bbb.bbb.bbb.bbb
Redundancy State:
Duplicated configuration : YES
Wished sig. transfer mode : C1 signalling channel
Used sig. transfer mode : C1 signalling channel
Transmission CPU-CPU : READY
monitel redundancy : READY
memloader redundancy : KO
All applications redundancy : READY

В нашем случае memloader redundancy будет не синхронизирован из-за разной версии ПО на двух платах CPU. После того, как командой bascul (на  активной плате) мы переведём телефонию на резервную плату и повторим все пункты, начиная с №3 для той платы, которая изначально была основной, синхронизация должна будет выровняться.

Роуминг DECT


Для начала нужно выяснить, какие лицензии у нас есть, и что мы можем наконфигурировать.

Лицензии на роуминг

Чтобы узнать, какие возможности перед нами открыты, залогинимся на станцию, и выполним команду spadmin:
(105)xb001005> spadmin
ooo Reading string-file /DHS3bin/oneshot/mtcl/objects.US0 ...
ooo Reading string-file /DHS3bin/oneshot/mtcl/spadmin.dct ...
ooo Reading string-file /DHS3bin/oneshot/mtcl/err2lov.dct ...
Display current counters ........................... 1
Display active file ................................ 2
Check active file coherency ........................ 3
Install a new file ................................. 4
Read the system CPUID .............................. 5
CPU-Ids management ................................. 6
Display active and new file ........................ 7
Display OPS limits ................................. 8
Display ACK code ................................... 9
Exit ............................................... 0
choice :

Выберем 2. На экране появится список всех возможностей, доступных в текущей лицензии на станцию. Нас интересует три пункта:
82 Nb of DECT terminals
90 Roaming DECT/PWT
175 Mobile users
В п. 82 указано общее (оплаченное по лицензии) доступное количество пользователей (абонентов) DECT. Причем в это количество также входят и так называемые «виртуальные» номера, создаваемые на станции для того, чтобы было возможно осуществлять роуминг.
В п. 90 указано количество внутренних абонентов DECT на станции, которым мы имеем право присвоить права роуминга на другие станции ABCF-сети. При этом необходимо помнить, что для того, чтобы роуминг работал на второй, гостевой станции к моменту попадания трубки в зону действия DECT должен быть свободный «виртуальный» номер.
В п. 175 можно посмотреть, какое количество лицензий уже использовано, включая т.н. «виртуальные» номера. 

Чтобы посмотреть на станции, какие абоненты имеют право на роуминг, проще всего в системе OmniVista задать следующий фильтр:
Рис. 2.

Настройка роуминга

У каждой системы DECT есть определённый идентификатор – PARI-номер. Его можно посмотреть в следующем месте: Dect System – IBS System (или RBS System). См. рис. 3.

Рис. 3.

Каждой трубке присваивается PLI-номер. Я, если честно, не знаю его формального определения, но значение PLI-номера соответствует количеству байтов PARI-номера, которые должны быть одинаковыми на двух станциях, чтобы между ними был возможен роуминг DECT. Переведём PARI-номера наших станций в двоичный вид и сравним. В скобках записан шестнадцатеричный вид PARI-номера.

1 станция: 100 0001 1100 0100 0111 1001 0100 0010 0010 (4 1C47 9422)
2 станция: 100 0001 1100 0100 0111 1001 0100 0100 0000 (4 1C47 9440)
...
7 станция: 100 0001 1100 0100 0111 1001 0100 0101 1110 (4 1C47 945E)

Жёлтым цветом выделено 27 байтов. Это значение PLI, которое должны иметь трубки, у которые есть право DECT-роуминга. У остальных трубок значение PLI равняется 31.
Но это ещё не всё. Для работы роуминга требуется ещё, чтобы на той станции, куда приходит гость, был зарегистрирован так называемый Shell. При этом станция, откуда пришёл этот гость, должна знать, где обитает данный Shell. У нас это реализовано следующим образом (рассматриваем на примере двух абстрактых станций 1 и 2):
На станции 1 создано 5 пользователей (Рис. 3)

Рис. 4.

На станции 2 создано 5 соответствующих префиксов, имеющих значение Dect Mobile и ссылающихся на станцию 1 (Рис. 4)

Рис. 5.

Нужным абонентам станции 2 поставлены права Network Mobile Rights и PLI 27. Таким образом, 5 первых таких пользователей, попавших в зону действия DECT станции 1, зарегистрируются на станции и будут успешно разговаривать с абонентами станции 2.

И, в заключение, небольшая ...

Недокументированная возможность

На LDAP-сервере OmniVista есть один пользователь, существование которого не описано ни в одном официальном мануале. Это суперпользователь сервера каталогов, о существовании которого я узнал из какого-то раздела на Alcatel Unleashed :
Имя пользователя: cn=Directory Manager
Пароль: 123456789


Пользуемся

Для начала нам нужен какой-нибудь LDAP-браузер. Я использую для этих целей LdapAdminИспользование данного софта интуитивно понятно, поэтому я просто размещу скриншоты.


1)​ Настраиваем новое соединение. Единожды настроив, потом можно будет им пользоваться:


Рис. 6

2)​ Подключаемся, жмём «Yes»:

Рис. 7

3)​ Разворачиваем дерево каталога до нужного пользователя, как показано на скриншоте, нажимаем на пользователе правую кнопку мыши, выбираем пункт Set Password:


Рис. 8

Всё! При следующей попытке входа в OmniVista пользователю будет предложено создать новый пароль. И сделали мы это, не используя учётную запись администратора.

понедельник, 21 октября 2013 г.

Alcatel-Lucent OXE. Перезагрузка платы CPU, резервное копирование, смена роли платы.

Предисловие

За четыре года администрирования телефонных станций Alcatel-Lucent у меня накопилось некоторое количество мануалов, которые я писал для себя. Прошло некоторое время с той поры, и я решил вывалить это добро в сеть.

Самая суть

OXE поддерживает возможность резервирования CPU. В конфигурации, с которой мне довелось работать, на каждой телефонной станции было установлено по две платы CPU (CPU7-2). Одна из этих плат находится в рабочем (активном) режиме, вторая – в резервном. Каждой станции соответствуют три IP-адреса:
  • Первый – IP-адрес основной платы, 
  • Второй – IP-адрес резервной платы, 
  • Третий – «виртуальный» адрес, который всегда ссылается на ту плату, которая в данный момент работает в активном режиме. 
Через систему управления OmniVista можно в режиме конфигурации зайти на любую станцию и посмотреть установленные платы, их адреса и в каком режиме они находятся (см. Рис. 1):

Рис. 1.
В полке ACT платы CPU располагаются по центру кристалла, в слотах 6 и 20. При этом, как правило, если станция функционирует в штатном режиме, роль основной платы выполняет та, которая установлена в слоте №6. При доступе на эту плату через telnet она имеет имя вида xb….
Для доступа через telnet к платам CPU лучше пользоваться программным обеспечением putty или его форком kitty

Проверка состояния платы

Залогинившись на плату, первым делом смотрим на строку приглашения. Она должна выглядеть следующим образом (боевой пример с 6-го узла ABC-F-сети, состоящей из семи станций):
(106)xb001006>
В скобках указывается номер узла в сети ABC-F. Если в скобках находится буква E, значит, что-то не так, и на плате не запущены сервисы телефонии.
Чтобы узнать роль платы, на которую мы залогинились, необходимо выполнить команду role:
(106)xb001006> role
MAIN
Если бы плата была резервной, мы бы получили ответ STAND-BY.
Теперь необходимо проверить состояние синхронизации с резервной платой CPU, выполнив команду twin:
(106)xb001006> twin
Tue Nov 15 08:17:07 GMT-4 2011
Usage : twin [Redundancy Cpu Enable (y/n)]
Role and CPU positions:
Role of the CPU : MAIN
CPU position : 06
CPU address : 10.162.67.70
Twin CPU position : 20
Twin CPU address : 10.162.67.69
Redundancy State:
Duplicated configuration : YES
Wished sig. transfer mode : C1 signalling channel
Used sig. transfer mode : C1 signalling channel
Transmission CPU-CPU : READY
Telephony redundancy : READY
monitel redundancy : READY
memloader redundancy : READY
All applications redundancy : READY

В выводе данной команды мы видим, в каких позициях установлены основная и резервная плата, их IP-адреса, а также состояние сервисов репликации данных между платами. Если состояние сервисов отлично от READY, значит синхронизация между платами нарушена, и менять роли плат не рекомендуется. В таком случае нужно залогиниться на резервную плату и вручную скопировать базы с основной через интерфейс команды swinst. Об этом речь пойдёт позже.
Ещё перед тем как всё ломать, рекомендуется проверить состояние остальных плат конструктива при помощи команды config. Аргумент для этой команды – номер кабинета ACT (к примеру, в станции ГУ их два: 0 и 2). Можно выполнить команду config all, и тогда мы сможем увидеть все сконфигурированные кристаллы станции, в т.ч. виртуальные:
(106)xb001006> config 0
Tue Nov 15 08:32:49 GMT-4 2011
+-------------------------------------------------------------------+
| Cr | cpl| cpl type | hw type | cpl state | coupler ID |
|----|----|------------|-----------|--------------|-----------------|
| 0 | 0 | NPRAE|---------- | IN SERVICE | 3BA23254ABJE02 |
| 0 | 2 | eUA32|---------- | IN SERVICE | 3BA23266AAJA03 |
| 0 | 4 | eUA32|---------- | IN SERVICE | 3BA23266AAJA03 |
| 0 | 6 | CPU7_STEP2|---------- | IN SERVICE | BAD PCMS CODE |
| 0 | 8 | NDDI2|---------- | IN SERVICE | 3BA23171ABBE02 |
| 0 | 9 | eUA32|---------- | IN SERVICE | 3BA23266AAJA03 |
| 0 | 11 | eUA32|---------- | IN SERVICE | 3BA23266AAJA03 |
| 0 | 12 | eZ32|---------- | IN SERVICE | 3BA23265ABLB03 |
| 0 | 14 | EMTL|---------- | IN SERVICE | 3BA53116AAAB |
| 0 | 15 | INTIPA| INT-IP | IN SERVICE | 3BA23193ACJF05 |
| 0 | 17 | BRA2|---------- | IN SERVICE | 3BA23073ABJD04 |
| 0 | 20 | CPU7_STEP2|---------- | IN SERVICE | BAD PCMS CODE |
| 0 | 22 | BRA2|---------- | IN SERVICE | 3BA23073ABJD04 |
| 0 | 24 | BRA2|---------- | IN SERVICE | 3BA23073ABJD04 |
| 0 | 25 | GPA2|---------- | IN SERVICE | 3BA23241AAJC05 |
| 0 | 26 | RMA|---------- |ONLY MAO FILE | BAD PCMS CODE |
| 0 | 27 | NDDI2|---------- | IN SERVICE | 3BA23171ABBE02 |
+-------------------------------------------------------------------+
> Reference rack not set

В идеале в столбце cpl state все состояния плат кроме RMA должны быть IN SERVICE, а в поле coupler ID напротив всех плат кроме CPU и RMA должны находиться идентификаторы плат. Если состояние какой-нибудь платы не соответствует описанному, можно попробовать сбросить её командой rstcpl x y, где x – значение первого, а y – значение второго столбца из таблицы, выдаваемой командой config
Это, соответственно, номер кристалла и номер платы.
Ещё будет не лишним проверить таблицу инцидентов, выполнив команду incvisu. Смотрим сообщения, анализируем, ищем информацию в сети или запрашиваем её у сервисных инженеров, если есть оплаченная техподдержка.

Смена ролей между основной и резервной платой

Если всё хорошо, то есть платы CPU синхронизированы, все платы в рабочем состоянии, можем менять роли. Для этого мы должны, будучи залогиненными на основной плате, выполнить команду bascul. При этом на некоторое время (несколько минут) пропадут IP-соединения между станцией, на которой осуществляется перенос ролей и всеми остальными станциями. Все внутренние разговоры, а также внешние голосовые соединения по аналоговым соединительным линиями и по цифровым потокам не должны прерываться.
Зачем вообще нужен перенос ролей? Он полезен в одном из следующих случаев:​ 
  • Какая-либо неисправность основной платы; 
  • Необходимость перезагрузки платы (в случае смены времени, например) ; 
  • Резервное копирование данных с жесткого диска платы; 
  • Установка обновлений; 
Смена роли в данных случаях позволяет не прерывать работу станции.

Потеря синхронизации между платами

Если в ответ на команду twin нам вываливается информация о том, что между платами нарушена синхронизация, то необходимо, залогинившись на резервной плате выполнить следующие действия:
  1. Остановить телефонию;
  2. Выполнить команду swinst (пароль по дефолту: SoftInst, но ДОЛЖЕН быть сменён);
  3. Выбрать последовательно: Expert Menu - Cloning & duplicate operations - CPU cloning;
  4. По очереди выполнить команды: Cloning Linux data, Cloning delivery и Cloning databases. Со всем соглашаться.

Резервное копирование HDD станции

Теперь, когда мы всё умеем проверять, рассказываю методику резервного копирования жёстких дисков АТС, осуществлять которую заставила меня судьба.
Для успешного осуществления резервного копирования нам понадобится следующее барахло:
  • Ноутбук или десктоп. Там должен быть COM-порт (подойдёт USB-переходник), Ethernet-порт, CD-ROM, два USB-порта. 
  • Переходник SATA-USB. 
  • Загрузочный CD-ROM Acronis True Image. 
  • Отвёртка с насадкой типа «звёздочка». 
  • Кабель для COM. 
  • Ethernet патч-корд. 
По идее здесь должна быть информация о том, как законнектиться на COM-порт или воткнуть сетевой кабель в Ethernet-разъём АТС-ки, чтобы можно было получить telnet-доступ к плате, но я пока опущу эти базовые сведения. Будем считать, что мы уже залогинились.
  1. Логинимся на основную плату CPU (20-й слот).
  2. Проверяем всё так, как описано во втором пункте данного руководства.
  3. Меняем роли плат.
  4. Выключаем плату, ставшую резервной, при помощи команды shutdown.
  5. Вынимаем плату из АТС. Откручиваем три болта крепления переходника HDD, откручиваем три болта крепления HDD к переходнику, вынимаем HDD из переходника.
  6. Подключаем HDD к переходнику SATA-USB, переходник втыкаем в рабочую станцию. Загружаемся с диска, бекапим.
  7. Втыкаем диск обратно в плату, плату в АТС. Включаем.
  8. Логинимся на вторую плату CPU (6-й слот). Проверяем, что забекапленная плата поднялась, находится в режиме STAND-BY, синхронизация ок, телефония на ней запустилась.
  9. Повторяем пункты 2-8 для второй платы.

Резервное копирование настроек станции по сети

Ежедневные архивы настроек станции лежат на самой станции, на активной процессорной плате, в каталоге /usr4/BACKUP/DAY. Всё, что нам нужно – это забрать эти настройки по FTP.
На гитхаб лежит готовый скрипт с комментариями, конфигурационный файл для скрипта, содержащий построчно имя станции, IP-адрес, имя и пароль пользователя для FTP-подключения и путь, куда сохранять скачанное.

Получение OPS-файлов по сети

OPS-файлы тоже можно забрать по FTP, они на станции в каталоге /usr4/BACKUP/OPS/. Однако, перед тем, как забрать файлы, необходимо сформировать их свежую версию, выполнив на станции следующие действия:
  1. Залогиниться на основную плату под пользователем mtcl;
  2. Запустить swinst;
  3. Выбрать п. 1 Easy menu;
  4. Выбрать п. 5 Backup OPS files on cpu disk;
  5. Подтвердить бекап файлов Confirm the backup of OPS files (y/n, default y): y
Все эти действия можно выполнить автоматически, используя программное обеспечение под названием Telnet Scripting Tool. Для этого необходимо сформировать Telnet-script в формате данной программы и скормить его ей.
На гитхабе также лежит скрипт сбора OPS-файлов, пример конфигурационного файл станций и исполняемый модуль Telnet Scripting Tool. По каждой станции также ведётся лог выполненных команд, который пишется в этот же каталог.

среда, 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: