Browse Source

java-app-updater v1.0

master
Maxim Lihachev 8 years ago
commit
9c73dcfcb4
  1. 27
      README.md
  2. 68
      config.ini
  3. 265
      service.py

27
README.md

@ -0,0 +1,27 @@
**service-updater** - Script for upgrading java/play application from git
## Description
Scenario upgrade java/play application in production directory
## Requirements
CentOS: yum -y install python-pip
Debian: apt-get install python-pip
pip install configparser
## Usage
service.py [service] <start|stop|restart|build|update|upgrade>
start - Start service
stop - Stop service
restart - Restart service
build - Build service. [stand|modules|all]
update - Update current service from repository
upgrade - Update developing service from repository
To build a specific service you need to pass a parameter [service]:
./service.py application build all

68
config.ini

@ -0,0 +1,68 @@
[service]
projects: {'application': 'app', 'daemon': 'srv'}
default: application
#Default parameters can be used in other sections.
[DEFAULT]
java_options: -Xmx2g
path: ${home}/$$SERVICE
bin: ${path}/target/universal/stage/bin/$$SERVICE
pid: ${path}/target/universal/stage/RUNNING_PID
modules_dir: ${home}/modules/
modules_list: ${modules_dir}/modules.list
class_path: ${path}/target/universal/stage/lib/
git_path: ${home}/git/
#clean all
targets: ${path}/modules/*/target
config_file_path: ${path}/conf/application.conf
restarts_log: ${home}/restarts.log
update_log: ${home}/update.log
build_log_file: ${home}/build.log
server: play.core.server.ServerStart
http_port: 10000
#Java options
play: activator -Duser.home=${home}/user_home -Dsbt.ivy.home=${home}/user_home/repository -Divy-home=${home}/user_home/repository
modules_log: ${home}/modules.updated
sbt_config: @${home}/sbt.boot.properties
sbt_opts: -Dsbt.boot.directory=${home}/user_home/.sbt
[build]
java_options: -J-Xms2g -J-Xmx4g
git_branch: dev
#Current directory
[develop]
home: PATH/TO/DIRECTORY
git_path: ${home}
[app]
home: PATH
path: ${home}/git/app
http_port: 10001
[srv]
home: PATH
path: ${home}/git/srv
class_path: ${path}/target/universal/stage/lib/
http_port: 10002

265
service.py

@ -0,0 +1,265 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Script for upgrading java/play application from git
#
# (c) envrm
#
#Requirements
#
# CentOS: yum -y install python-pip
# Debian: apt-get install python-pip
#
# pip install configparser
#
import re
import os
import ast
import sys
import shutil
import signal
import datetime
import subprocess
import configparser
from string import Template
from contextlib import contextmanager
@contextmanager
def if_needed():
'''Execute with error ignoring'''
try:
yield
except:
pass
class Dir:
'''Execute procedures in directory'''
def __init__(self, directory):
self.current_dir = directory
def __enter__(self):
self.previous_dir = os.getcwd()
os.chdir(self.current_dir)
def __exit__(self, type, value, traceback):
os.chdir(self.previous_dir)
#-----------------------------------------------------------------------
def readConfig(config_file):
'''Loading configuration file'''
global settings
settings = configparser.ConfigParser()
settings._interpolation = configparser.ExtendedInterpolation()
settings.read(config_file)
return settings
def opt(parameter):
'''Getting parameters from file'''
setting = parameter.split(":")
value = settings.get(setting[0], setting[1])
variables = re.findall(r"\$(\w+)", value)
substr = {v: globals()[v] for v in variables if v in globals()}
return Template(value).safe_substitute(**substr)
def saveTimestamp(outfile, mode="a"):
'''Saving timestamt to file'''
with open(outfile, mode) as log:
now = datetime.datetime.now()
log.write(now.strftime("%Y-%m-%d %H:%M:%S\n"))
#-----------------------------------------------------------------------
def git(command, stand="develop"):
'''Executing git command'''
with Dir(opt(stand + ':git_path')):
git_output = subprocess.check_output('git ' + command, shell=True)
return git_output
def stop(stand="develop"):
'''Stop service'''
if os.path.isfile(opt(stand + ':pid')):
pid = opt(stand + ':pid')
else:
pid = os.path.join(opt(stand + ':path'), 'RUNNING_PID')
print pid
with if_needed():
with open(pid, 'r') as pid_file:
os.kill(int(pid_file.read()), signal.SIGTERM)
os.remove(pid)
print "#### Application stopped"
def start(stand):
'''Start service'''
service_dir = opt(stand + ':path')
server = opt(stand + ':server')
start_cmd = 'nohup java ' + opt(stand + ':java_options') \
+ ' -Dfile.encoding=UTF-8 -Dconfig.file=' + service_dir + '/conf/application.conf ' \
+ ' -Dhttp.port=' + opt(stand + ':http_port') + ' -cp "' + service_dir + '/conf/:' + opt(stand + ':class_path') + '/*" ' \
+ server + ' ' + service_dir + ' | tee -a ' + opt(stand + ':home') + '/nohup.out &'
print start_cmd
with Dir(service_dir):
return_code = os.system(start_cmd)
if return_code == 0:
print "#### Application started"
else:
print return_code
exit(1)
def restart(stand="develop"):
'''Restart service'''
stop(stand)
start(stand)
saveTimestamp(opt(stand + ':restarts_log'))
def clean_all():
'''Remove artefacts'''
os.system("rm -rfv " + opt('develop:targets'))
def build(target="stand", modules=None):
'''Build service. [stand|modules|all]'''
play_cmd = opt(SERVICE + ':play') + " " + opt(SERVICE + ':sbt_config')
print "OK"
if target == "modules" or target == "all":
with Dir(opt('develop:modules_dir')):
if modules == None:
modules = os.walk(".").next()[1]
modules = filter(None, set(modules))
with open(opt('develop:modules_list')) as f:
modules_deps = f.read().splitlines()
for mod in modules_deps:
if mod in modules:
with Dir(os.path.join(opt('develop:modules_dir'), mod)):
print "#### Update module " + mod
return_code = os.system(play_cmd + " publishLocal")
if return_code != 0:
exit(1)
if target == "stand" or target == "all":
print "#### Update application"
with Dir(opt('develop:path')):
with if_needed():
shutil.rmtree("target")
print play_cmd + " " + opt('build:java_options') + " stage | tee " + opt('develop:build_log_file')
return_code = os.system(play_cmd + " " + opt('build:java_options') + " stage | tee " + opt('develop:build_log_file'))
if return_code != 0:
exit(1)
def update_from_git():
'''Update app with modules'''
git('checkout ' + opt('build:git_branch'))
git('branch --set-upstream-to=origin/' + opt('build:git_branch') + ' ' + opt('build:git_branch'))
print git('fetch')
git_log = git('diff --name-only HEAD..origin/' + opt('build:git_branch'))
git('pull')
modules = []
for line in git_log.splitlines():
module = re.findall(r'commonmodules/([^/]*)/.*', line)
if module:
modules.extend(module)
build("all", modules)
def copy_libs():
'''Copy libraries'''
with if_needed():
shutil.rmtree(opt(SERVICE + ':class_path'))
shutil.copytree(opt('develop:class_path'), opt(SERVICE + ':class_path'))
def update():
'''Update current service from repository'''
saveTimestamp(opt('develop:restarts_log'))
stop()
update_from_git()
start()
saveTimestamp(opt('develop:update_log'), 'w')
def upgrade():
'''Update developing service from repository'''
update_from_git()
saveTimestamp(opt(SERVICE + ':restarts_log'))
stop(SERVICE)
git("pull", SERVICE)
copy_libs()
start(SERVICE)
saveTimestamp(opt(SERVICE + ':update_log'), 'w')
#-----------------------------------------------------------------------
def show_help():
exe = os.path.basename(sys.argv[0])
'''Show help'''
print "USAGE: " + exe + " [service] <" + "|".join(allowed_tasks) + ">"
for task in allowed_tasks:
print "\t" + task + "\t- " + globals()[task].__doc__
print "\nTo build a specific service you need to pass a parameter [service]:"
print "\t./" + exe, opt('service:default'), "\b build all"
print "\n[service] can be one of «" + "», «".join(ast.literal_eval(opt('service:projects')).keys()) + "»."
print "\nDefault value of [service] is", opt('service:default'), "\n"
settings = []
readConfig('config.ini')
allowed_tasks = ['start', 'stop', 'restart', 'build', 'update', 'upgrade']
#Services allowed for building
services = ast.literal_eval(opt('service:projects'))
#Default service
SERVICE = ast.literal_eval(opt('service:projects'))[opt('service:default')]
#Command line arguments parsing
if len(sys.argv) > 2 and sys.argv[2] in allowed_tasks:
arg_index = 2
if sys.argv[1] in services:
SERVICE = ast.literal_eval(opt('service:projects'))[sys.argv[1]]
elif len(sys.argv) > 1 and sys.argv[1] in allowed_tasks:
arg_index = 1
else:
show_help()
exit(1)
#Procedure for execution
task = globals()[sys.argv[arg_index]]
if task:
target = {
'update' : 'develop',
'upgrade': 'mroot'
}.get(sys.argv[1], "develop")
if len(sys.argv) > 2 and sys.argv[2] in ['start','stop','restart']:
SERVICE = ast.literal_eval(opt('service:projects'))[sys.argv[1]]
print "CMD: " + sys.argv[1] + " " + sys.argv[2], "| SERVICE: ", SERVICE
task(SERVICE)
elif len(sys.argv) > (arg_index + 1):
print "CMD: " + sys.argv[arg_index] + " " + sys.argv[arg_index + 1]
task(sys.argv[arg_index + 1])
else:
print "CMD: " + sys.argv[arg_index]
task()
Loading…
Cancel
Save