
Существенное отличие состоит в том, что Bear с самого начала предназначен для платформы JVM. Это означает привычное джависту рабочее окружение — отладчик, автодополнение кода, рефакторинг, статическую типизацию и поддержку нескольких языков программирования.
У Bear есть:
Cтраница на GitHub
Небольшая Wiki
Артифакт в Maven Central
Предыстория
Несколько месяцев назад я ушел и компании, проработав в ней чуть более чем полгода и решил, что неплохо было бы иметь собственный открытый проект, чтобы, например, придти в другую компанию не с пустыми руками. Да и вообще новый опыт, и перемены — это всегда интересно. В общем, захотелось мне творить.
Мотивация
В своих прошлых проектах у меня уже был опыт реализации скриптов удаленного развертывания, и нельзя назвать этот опыт самым приятным. Связано это обычно с тем, что разветывание в общем непростая процедура, которую часто перекладывают на плечи админов, которые создают не всегда понятные shell-скрипты. Изменять такие крипты сложно, нетривиальные случаи вроде мониторинга запуска, удаленной сборки или отката на предыдущую версию, они обычно не предусматривают и часто приходится ждать, пока админ переделает свой скрипт. В общем в моей практике деплоймент всегда был довольно болезненным процессом.
Изучать средства вроде Capistrano мне, как джависту, не очень хотелось — и хотя язык Ruby мне знаком, Capistrano использует свой DSL, и как отлаживать, да и вообще работать с ним, если что-то пойдет не так — мне, человеку, незнакомому с современными средствами разработки Ruby, неясно.
Поэтому при создании Bear у меня была следующая мотивация, предоставить пользователю:
- Привычное рабочее окружение: Java IDE пользователя, отладчик для проверки скриптов, юнит-тесты
- Статические типы для быстрой разработки с помощью IDE
- Библиотека параллельного выполнения задач
- Простой, но современный UI. Все-таки стыдно выдавать пользователю консоль, когда сингулярность уже близко
- Поддержка JVM-языков
- Подключаемость Maven-библиотека
- Примеры развертывания с GitHub для популярных технологий (Node.js, Grails, Play! Framework, Tomcat)
- Конфигурация через лямбды (как в Capistrano), контекст сессии и глобальный контекст лямбды (чтобы, например, можно было переопределить пароль для определенного хоста), проверка ошибок времени компиляции
- Поддержка multi-instance развертываний из коробки
Установка Медведя
Для запуска демо-проекта вам понадобится:
- Maven 3+
- JDK 7+, рекомендуется JDK 8 из-за багфиксов в WebView
- Удаленный хост — например, виртуальная машина CentOS или Ubuntu.
Bear можно использовать как Maven-зависимость. Среди читателей хабры есть много продвинутых пользователей, знакомых с Maven. Они могут пропустить инструкцию ниже и добавить Bear как зависимость Maven в свой проект. Далее зайти на страницу GitHub и скопировать примеры в свой проект. Каждый проект — это независимый класс, написанный на Groovy.
Установка медведя, в командной строке:
$ mvn com.chaschev:installation-maven-plugin:1.4:install -Dartifact=com.chaschev:bear
Минимальный проект — удаленный ls, листинг директории
Создание пустого проекта медведя, перейдите в папку вашего проекта или просто в пустую папку:
$ cd my-project
$ bear --create my --user имя-пользователя --password ssh-пароль --host хост
Это создаст папку
.bear
и в ней — pom.xml
и файл проекта MyProject.groovy
.Created project file: .bear\MyProject.groovy
Created Maven pom: .bear\pom.xml
Для запуска удаленного листинга директории наберите:
$ bear my.ls
my
— сокращенное имя проектаls
— название автоматически сгенерированного методаВот его текст:
@Method
def ls(){
run([named("ls task", { _, task ->
println _.sys.lsQuick(".")
} as TaskCallable)])
}
В примере выше происходит запуск Groovy-замыкания (для джавистов, которые не знакомы с Groovy, замыкание — это анонимный класс вроде ActionEvent в Swing) на нашем кластере, пока еще состоящем из одной машины. Комментарии к коду:
_
— это контекст сессии, универсальный объект вроде $
из jQuery_.sys
— объект, отвечающие за системные командыlsQuick
— краткая форма вызова ls, обычно используются fluent interfaces, например, println _.sys.ls('.').run().throwIfError().getPath();
Так выглядит интерфейс Bear после запуска:

Запуск тестов окружения и демо-проектов
Чтобы распаковать демо-проекты, наберите в командной строке:
$ bear --unpack-demos
Откройте файл
.bear/examples/demo/SmokeProject.groovy
и отредактируйте хосты и stages. Для запуска тестов наберите в консоли:$ bear smoke.runTests -q
Чтобы запустить вместе c UI:
$ bear smoke.runTests --ui
Если тесты пройдут успешно, на выходе должно быть что-то вроде:
command execution time: 44.2ms/command
finished: Stats{time: "8.8s", partiesArrived: 2, partiesOk: 2, partiesPending: 0, partiesFailed: 0}
Далее можно выбрать любой проект из папки
.bear/examples/demo
и запустить его:$ bear drywall.setup --ui
$ bear drywall.deploy --ui
Первая команда выполнит настройку окружения — установит Node.js и все необходимые зависимости. Вторая — выполнит удаленное развертывание проекта. Примечание: демо проекта Grails/Tomcat называется petclinic.
Можно также запустить из вашей IDE как обычный Groovy/Java класс:
public static void main(String[] args){
new DrywallDemoProject().deploy()
}
Пример проекта
В заключение приведу пример проекта Bear с комментариями в коде:
// Конфигурация проекта по умолчанию через переменные. Также возможны другие способы:
// через переменные окружения, .properties файл, в коде, из командной строки
// Конфигурация может быть переопределена для метода или во время исполнения деплоя.
@Project(shortName = "drywall-demo", name = "Drywall Demo Deployment")
@Configuration(
properties = ".bear/demos", // имя файла свойств .properties
stage = "u-3", // stage, текущий кластер
vcs = "https://github.com/jedireza/drywall.git", // адрес проекта на GitHub
branch = "master", // используемая ветка
useUI = true, // использовать ли UI по умолчанию
user = "andrey" // имя пользователя для ssh
)
public class DrywallDemoProject extends BearProject<DrywallDemoProject> {
// Используемые плагины
// Их зависимости автоматически устанавливаются во время project.setup()
GitCLIPlugin git
NodeJsPlugin nodeJs
MongoDbPlugin mongoPlugin
DeploymentPlugin deployment
ReleasesPlugin releases
DumpManagerPlugin dumpManager
public TaskDef deployProject;
// таска копирования
def copyConfiguration = new TaskDef({_, task ->
final String dir = _.var(releases.pendingRelease).path
if(!_.sys.exists(dir + "/config.js")){
_.sys.move("config.example.js").to("config.js").inDir(dir).run().throwIfError();
}
OK
} as TaskCallable);
@Override
protected GlobalContext configureMe(GlobalContextFactory factory) throws Exception
{
// установка используемых версий
// можно вынести эту часть в .properties файл, но автору по душе автономность проекта
nodeJs.version.set("0.10.22");
nodeJs.projectPath.setEqualTo(bear.vcsBranchLocalPath);
// конфигурация портов для развертывания, можно через запятую указать несколько instances
nodeJs.instancePorts.set("3000")
// есть минималистичный dump manager, здесь устанавливается БД для него
dumpManager.dbType.set(mongo.toString());
// данный проект для запуска использует Grunt
nodeJs.createScriptText.setEqualTo(nodeJs.simpleGruntUpstart);
bear.stages.set(new Stages(global)
.addQuick("one", "vm01")
.addQuick("two", "vm01, vm02")
.addQuick("three", "vm01, vm02, vm03")
.addQuick("u-1", "vm04")
.addQuick("u-2", "vm04, vm05")
.addQuick("u-3", "vm04, vm05, vm06")
);
// Конфигурация деплоймент-задачи.
// Задачи из плагинов раскиданы по фазам развертывания.
// Поддерживается откат на предыдущую версию.
// watch - это отслеживание запуска инстанса по логам.
defaultDeployment = deployment.newBuilder()
.CheckoutFiles_2({_, task -> _.run(global.tasks.vcsUpdate); } as TaskCallable)
.BuildAndCopy_3({_, task -> _.run(nodeJs.build, copyConfiguration); } as TaskCallable)
.StopService_4({_, task -> _.run(nodeJs.stop); OK; } as TaskCallable)
.StartService_6({_, task -> _.run(nodeJs.start, nodeJs.watchStart); } as TaskCallable)
.endDeploy()
.ifRollback()
.beforeLinkSwitch({_, task -> _.run(nodeJs.stop); } as TaskCallable)
.afterLinkSwitch({_, task -> _.run(nodeJs.start, nodeJs.watchStart); } as TaskCallable)
.endRollback();
return global;
}
static main(args)
{
new DrywallDemoProject().start()
}
// Дополнительная установка зависимости проекта ImageMagick во время setup-задачи
public GlobalTaskRunner setup()
{
global.tasks.setup.before({_, task -> _.sys.packageManager.installPackage("ImageMagick"); OK } as TaskCallable)
super.setup()
}
}
Заключение
Некоторые технические моменты реализации
- UI сделан с помощью AngularJS+Twitter Bootstrap+Bootstrap-Admin-Template и WebView из JavaFX (движок на основе WebKit)
- Самая большая проблема разработки AngularJS/JavaFX — отсутствие нормальной отладки. Я использовал Firebug Lite, в дальнейшем попробую писать юнит-тесты для Angular или делать заглушки для Java-вызовов.
- Интеграция Java и JS в WebView пока очень сырая, иногда бывают Heap Dump-ы, приходится конвертировать объекты в JSON для передачи между JS и Java. Я отправил feature request на трекер Oracle JavaFX с поддержкой JSR-223 в WebView — там написали, что интеграцию возможно улучшат в Java 9
- Для быстрой установки Bear из мавен-репозитория был написан мавен-плагин, он есть на GitHub, подобие утилит gem, apt или yum на других платформах. Честно говоря, это была большая боль — угадать, как и какие версии библиотек использовать, чтобы новый Maven Aether от Eclipse начал работать.
- Для синхронизации задач был разработан мини-фреймворк ComputingGrid. Вкратце, это таблица, в которой столбцы — это хосты, строки — это задачи. Ячейки — это Future/Promise с результатом выполнения задачи. Это позволяет выполнить практические произвольную синхронизацию между сессиями.
Больше информации о Медведе есть на Вики проекта.
Вот таким получился Медведь. Я планирую развивать и дополнять этот проект и жду отзывов пользователей. В ближайшее время буду работать над юзабилити, упрощением пользования и багфиксингом. Планы на далекое будущее — поддержка удаленных агентов для улучшения качества связи с серверами (сейчас иногда Ubuntu обрывает связь во время мониторинга логов после запуска приложения), а также поддержка localhost и других языков — Python, Ruby, Scala. Если будет спрос, вынесу AngularJS+JavaFX в отдельную библиотеку.
Если вам интересно увидеть продолжение статей о Медведе, напишите мне об этом, пожалуйста. Всем спасибо за внимание и успехов в ваших проектах!