You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
8.1 KiB
282 lines
8.1 KiB
8 years ago
|
#!/usr/bin/env python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
6 years ago
|
# Copyright (C) 2017, Maxim Lihachev, <envrm@yandex.ru>
|
||
8 years ago
|
#
|
||
6 years ago
|
# This program is free software: you can redistribute it and/or modify it
|
||
|
# under the terms of the GNU General Public License as published by the Free
|
||
|
# Software Foundation, version 3.
|
||
8 years ago
|
#
|
||
6 years ago
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||
|
# more details.
|
||
8 years ago
|
#
|
||
6 years ago
|
# You should have received a copy of the GNU General Public License along with
|
||
|
# this program. If not, see <https://www.gnu.org/licenses/>.
|
||
8 years ago
|
|
||
|
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
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
@contextmanager
|
||
|
def if_needed():
|
||
|
'''Execute with error ignoring'''
|
||
|
try:
|
||
|
yield
|
||
|
except:
|
||
|
pass
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
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)
|
||
|
|
||
6 years ago
|
|
||
|
# ----------------------------------------------------------------------
|
||
8 years ago
|
|
||
|
def readConfig(config_file):
|
||
|
'''Loading configuration file'''
|
||
|
global settings
|
||
|
settings = configparser.ConfigParser()
|
||
|
settings._interpolation = configparser.ExtendedInterpolation()
|
||
|
settings.read(config_file)
|
||
|
return settings
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
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)
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
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"))
|
||
|
|
||
6 years ago
|
|
||
|
# ----------------------------------------------------------------------
|
||
8 years ago
|
|
||
|
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
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
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"
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
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)
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
def restart(stand="develop"):
|
||
|
'''Restart service'''
|
||
|
stop(stand)
|
||
|
start(stand)
|
||
|
saveTimestamp(opt(stand + ':restarts_log'))
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
def clean_all():
|
||
|
'''Remove artefacts'''
|
||
|
os.system("rm -rfv " + opt('develop:targets'))
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
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')):
|
||
6 years ago
|
if modules is None:
|
||
8 years ago
|
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)
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
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)
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
def copy_libs():
|
||
|
'''Copy libraries'''
|
||
|
with if_needed():
|
||
|
shutil.rmtree(opt(SERVICE + ':class_path'))
|
||
|
shutil.copytree(opt('develop:class_path'), opt(SERVICE + ':class_path'))
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
def update():
|
||
|
'''Update current service from repository'''
|
||
|
saveTimestamp(opt('develop:restarts_log'))
|
||
|
stop()
|
||
|
update_from_git()
|
||
6 years ago
|
start(SERVICE)
|
||
8 years ago
|
saveTimestamp(opt('develop:update_log'), 'w')
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
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')
|
||
|
|
||
6 years ago
|
|
||
|
# ----------------------------------------------------------------------
|
||
8 years ago
|
|
||
|
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"
|
||
|
|
||
6 years ago
|
|
||
8 years ago
|
settings = []
|
||
|
|
||
|
readConfig('config.ini')
|
||
|
|
||
|
allowed_tasks = ['start', 'stop', 'restart', 'build', 'update', 'upgrade']
|
||
|
|
||
6 years ago
|
# Services allowed for building
|
||
8 years ago
|
services = ast.literal_eval(opt('service:projects'))
|
||
|
|
||
6 years ago
|
# Default service
|
||
|
SERVICE = ast.literal_eval(opt('service:projects'))[opt('service:default')]
|
||
8 years ago
|
|
||
6 years ago
|
# Command line arguments parsing
|
||
8 years ago
|
if len(sys.argv) > 2 and sys.argv[2] in allowed_tasks:
|
||
|
arg_index = 2
|
||
|
if sys.argv[1] in services:
|
||
6 years ago
|
SERVICE = ast.literal_eval(opt('service:projects'))[sys.argv[1]]
|
||
8 years ago
|
elif len(sys.argv) > 1 and sys.argv[1] in allowed_tasks:
|
||
|
arg_index = 1
|
||
|
else:
|
||
|
show_help()
|
||
|
exit(1)
|
||
|
|
||
6 years ago
|
# Procedure for execution
|
||
8 years ago
|
task = globals()[sys.argv[arg_index]]
|
||
|
|
||
|
if task:
|
||
|
target = {
|
||
6 years ago
|
'update': 'develop',
|
||
8 years ago
|
'upgrade': 'mroot'
|
||
|
}.get(sys.argv[1], "develop")
|
||
|
|
||
6 years ago
|
if len(sys.argv) > 2 and sys.argv[2] in ['start', 'stop', 'restart']:
|
||
|
SERVICE = ast.literal_eval(opt('service:projects'))[sys.argv[1]]
|
||
8 years ago
|
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()
|