Конфигурация приложений с помощью github

213b463541704fc4a3c7d3bb54294798.png

Конфигурация является такой же важной частью как и код, особенно в крупных проектах. Но часто отношение к ней, как к второсортному артефакту разработки и эксплуатации ПО. Плохо если конфигурация не проходит тот же полный цикл, что и ПО. Про аудит изменений и версионирование забывают, либо проводят не самым подходящим для этого инструментарием.

Я видел много проектов, где конфигурация подкладывается в файловую систему в виде properties/json/xml файлов с непостижимыми уму переоределениями в момент загрузки. И что же на самом деле использует приложение становится ясно только после просмотра лог файлов компонента либо во время отладки.
Скрипт для автоустановки своего Git репозитария можете найти в разделе «Конфигурация в собственном git репозитарии».

При выборе git можно использовать весь тот инструментарий, что используется в разработке. Делать ревью, сравнивать конфигурацию, поддерживать разные ветки конфигурации, ссылаться на теги, пользоваться как визуальными инструментами так и инструментарием в командной строке.

Чтобы воспользоваться всем этим мощным арсеналом нам надо лишь научиться считывать конфигурацию из git репозитария.

Для этого используем Java класс для считывания конфигурации. Он основан на обертке вокруг hawtio-git (который в свою очередь под капотом использует JGit) и доступен на github git-configuration и в maven central.

Видя конфигурационный хаос вокруг попытаюсь напомню о светлом и прекрасном.
Впервые идея хранения конфигурации в git вдохновила после знакомства с fuse fabric/fabric8.

Хранить конфигурацию в git репозитарии умеет и великолепный проект spring-cloud-config. Но если нам не нужна зависимость на spring и его PropertySource абстракцию, то решение из этой публикации лучше подойдет для приложения на jvm.

Конфигурация на github

Начнем с чтения конфигурации, которую мы разместили в гитхаб репозитарии…

Java


Configuration.java
package com.github.igorsuhorukov.configuration;

import com.github.igorsuhorukov.codehaus.plexus.util.IOUtil;
import com.github.igorsuhorukov.smreed.dropship.MavenClassLoader;
import io.hawt.git.GitConfigurationHelper;

import java.io.InputStream;

public class Configuration {
    public static void main(String[] args) throws Exception{
        GitConfigurationHelper gitConfigurationHelper = new GitConfigurationHelper("https://github.com/igor-suhorukov/aspectj-scripting.git");
        System.out.println("CONFIGURATION FROM GIT: HEAD REVISON ----------------------------------");
        System.out.println(gitConfigurationHelper.getFileContent("master","pom.xml"));
        System.out.println("CONFIGURATION FROM GIT: BY TAG ----------------------------------------");
        System.out.println(gitConfigurationHelper.getFileContent("master","aspectj-scripting-1.2", "pom.xml"));
        gitConfigurationHelper.destroy();

        System.out.println("CONFIGURATION FROM MAVEN REPO -----------------------------------------");
        InputStream configStream = MavenClassLoader.usingCentralRepo().resolveArtifact("com.github.igor-suhorukov:aspectj-scripting:pom:1.3").openStream();
        System.out.println(IOUtil.toString(configStream));
    }
}

Зависимости, необходимые для работы примера:


    com.github.igor-suhorukov
    git-configuration
    1.0


    com.github.igor-suhorukov
    mvn-classloader
    1.4




Для получения конфигурации нужно указать путь к нашему репозитарию:

new GitConfigurationHelper("https://github.com/igor-suhorukov/aspectj-scripting.git")


Возможны варианты

  • Использовать последнюю версию файла из указанного бранча:
    gitConfigurationHelper.getFileContent("master","pom.xml")
    
    
  • Или получить конкретную версию по тегу (в примере это тег «aspectj-scripting-1.2») или по ревизии:
    gitConfigurationHelper.getFileContent("master","aspectj-scripting-1.2", "pom.xml")
    
    


И в завершении работы закрыть соединение с репозитарием:

gitConfigurationHelper.destroy()

В качестве приятного дополнения к возможности хранения конфигурации в git — можно считывать конфигурацию и из maven репозитария. Для этого нужна библиотека mvn-classloader:1.4, которая уже входит в состав groovy-grape-aether:2.4.5.2.

URL artifact = MavenClassLoader.usingCentralRepo ().resolveArtifact («com.github.igor-suhorukov: aspectj-scripting: pom:1.3»)

  • usingCentralRepo () — из центрального репозитария.
  • using (repositoryPath) — для вашего корпоративного репозитария.

Дальше работать с артефактом довольно просто. Вызов метода artifact.getFile () позволяет получить ссылку на артефакт в локальной файловой системе, а artifact.openStream () открывает InputStream к этому файлу.

В каком формате хранить конфигурацию и чем разбирать эти файлы дальше — зависит от задачи и предпочтений и решать вам. Конфигурация может представлять из себя как простой java.util.Properties, так и Json (Gson/jackson), JAXB/XStream, либо конфигурацию в виде скриптов на groovy, scala, javascript…

Groovy


То же самое из прошлого заголовка про java гораздо лаконичнее записывается в groovy. Запустить пример можно командой:
java -jar groovy-grape-aether-2.4.5.2.jar readGitConfig.groovy

readGitConfig.groovy

import com.github.igorsuhorukov.smreed.dropship.MavenClassLoader
@Grab(group = 'com.github.igor-suhorukov', module = 'git-configuration', version = '1.0')
import io.hawt.git.GitConfigurationHelper

def gitConfigurationHelper = new GitConfigurationHelper('https://github.com/igor-suhorukov/aspectj-scripting.git')
println 'CONFIGURATION FROM GIT: HEAD REVISON ----------------------------------'
println gitConfigurationHelper.getFileContent('master','pom.xml')
println 'CONFIGURATION FROM GIT: BY TAG ----------------------------------------'
println gitConfigurationHelper.getFileContent('master','aspectj-scripting-1.2', 'pom.xml')
gitConfigurationHelper.destroy()

println 'CONFIGURATION FROM MAVEN REPO -----------------------------------------'
def configStream = MavenClassLoader.usingCentralRepo().resolveArtifact('com.github.igor-suhorukov:aspectj-scripting:pom:1.3').openStream()
println configStream.text

Конфигурация в собственном git репозитарии

В качестве in-house репозитария выбрал Gitblit — для знающих java его проще установить и поддерживать, а механизм push hooks на Groovy позволяет творить чудеса. В качестве альтернативы можно выбрать Gogs — Go Git Service или любой другой сервер Git репозитариев.

Запуск и конфигурацию Gitblit сервера выполним с помощью groovy скрипта автоустановки.

java -jar groovy-grape-aether-2.4.5.2.jar gitblit.groovy

gitblit.groovy

import com.github.igorsuhorukov.smreed.dropship.MavenClassLoader
@Grab(group='org.codehaus.plexus', module='plexus-archiver', version='2.10.2')
import org.codehaus.plexus.archiver.zip.ZipUnArchiver
@Grab(group='org.codehaus.plexus', module='plexus-container-default', version='1.6')
import org.codehaus.plexus.logging.console.ConsoleLogger
@Grab(group = 'org.eclipse.jetty', module = 'jetty-runner', version = '9.3.7.RC1' )
import org.eclipse.jetty.runner.Runner

def gitblit = new File(MavenClassLoader.using('http://gitblit.github.io/gitblit-maven').resolveArtifact('com.gitblit:gitblit:war:1.7.1').getFile())

File gitblitDirectory = new File(System.getProperty('user.home'), gitblit.getName().replace('.war',''))

if(!gitblitDirectory.exists()){
    gitblitDirectory.mkdir()
    ZipUnArchiver unArchiver = new ZipUnArchiver()
    unArchiver.setSourceFile(gitblit)
    unArchiver.enableLogging(new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG,"Logger"))
    unArchiver.setDestDirectory(gitblitDirectory)
    unArchiver.extract()

    def dataPath = new File(System.getProperty('user.home'), '.gitblit_data')
    if(!dataPath.exists()){ dataPath.mkdir() }
    def webXml = new File(gitblitDirectory.getAbsoluteFile(), 'WEB-INF/web.xml')
    webXmlText = webXml.text
    webXml.withWriter { w -> w << webXmlText.replace('${contextFolder}/WEB-INF/data', dataPath.getAbsolutePath()) }
}

Runner.main([gitblitDirectory] as String[])

Скрипт скачивает gitblit.war из репозитария проекта, распаковывает его в домашнюю директорию пользователя и заменяет в конфигурации gitblit путь к хранилищу репозитариев. После этого запускает jetty сервер и gitblit внутри него.

b6723ea8c53042ad810b38c96ad330f5.png

Приведу последовательность команд, которые использовал для создания конфигурации в новом репозитарии ssh://admin@localhost:29418/configuration.git

vim configuration.properties
git add configuration.properties 
git commit -m "import config"
git tag -a ver1.0 -m "configuration version 1.0"
vim configuration.properties
git add configuration.properties 
git commit -m "update config"
git push -u origin master --tags

Код чтения конфигурации ничем не отличается от предыдущих примеров. Остается только создать в коде объект:

new GitConfigurationHelper("http://admin@localhost:8080/r/configuration.git")


И использовать тот же API, что и в github примере.

635675c693c8491191dc5c77215b9e1f.png

Итоги

В публикации мы рассмотрели как считывать конфигурацию в java/groovy из git и maven репозитариев. С помощью groovy скрипта смогли установить и сконфигурировать gitblit репозитарий в автоматическом режиме.

Код из статьи применим в jvm проектах и было бы интересно услышать от вас как эта же задача решается в других языках программирования и на других платформах.

© Habrahabr.ru