commit
a0921219c2
4 changed files with 279 additions and 0 deletions
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
**service-updater** - Script for updating service/application |
||||
|
||||
## Description |
||||
|
||||
Scenario update application on remote server with full back up of configuration |
||||
files and database. |
||||
|
||||
## Requirements |
||||
|
||||
# install python-dev libffi-dev |
||||
# pip install configparser |
||||
# pip install fabric |
||||
|
||||
## Usage |
||||
|
||||
backup_db Back up distributive |
||||
backup_db_copy Backround upload of backup to remote server |
||||
backup_files Back up files |
||||
copy_config Copy configuration files |
||||
copy_custom_conf Upload custom.conf to remote server |
||||
copy_libs Copy libs |
||||
diff_config Comparison of configuration files |
||||
make_dist Make distributive (play dist) |
||||
start Start service |
||||
stop Stop service |
||||
update Update service |
||||
upload_dist Upload distributive to remote server |
||||
|
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
[DEFAULT] |
||||
|
||||
config_dirs: [['daemon/root/conf/', 'conf/'], ['daemon/root/modules/catalogs/', 'catalogs/'] |
||||
|
||||
config_exclude: ['custom.conf', 'custom.conf.template'] |
||||
|
||||
[java] |
||||
play: play |
||||
|
||||
[release] |
||||
app_path_stand: /opt/daemon-rc |
||||
app_path_dist: ${release:app_path_stand}/daemon/root/target/universal |
||||
|
||||
make_dist_script: make_dist.sh |
||||
|
||||
custom_conf_template: ${release:app_path_stand}/daemon/root/conf/custom.conf.template |
||||
|
||||
[product] |
||||
host: user@127.0.0.1:10022 |
||||
|
||||
app_path_stand: /root/daemon/ |
||||
app_path_dist: ${product:app_path_stand}/../dist |
||||
app_path_libs: ${product:app_path_stand}/daemon/root/lib |
||||
|
||||
app_pid_file: ${product:app_path_stand}/daemon/root/RUNNING_PID |
||||
|
||||
app_start_script: start_app.sh |
||||
|
||||
backup_files: ['catalogs', 'daemon/catalogs', 'daemon/root/lib', 'conf'] |
||||
|
||||
backup_db_script: /root/scripts/db-backup.sh |
||||
backup_db_copy_script: /root/scripts/db-backup-upload.sh |
||||
|
||||
custom_conf_template: ${product:app_path_stand}/conf/custom.conf.template |
||||
|
@ -0,0 +1,216 @@
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env python |
||||
# -*- coding: utf-8 -*- |
||||
|
||||
# |
||||
# Script for updating service/application on remote server using Fabric. |
||||
# |
||||
# (c) envrm |
||||
# |
||||
|
||||
#Installing fabric: |
||||
# apt-get install python-dev libffi-dev |
||||
# pip install configparser |
||||
# pip install fabric |
||||
|
||||
from __future__ import with_statement |
||||
from fabric.api import * |
||||
|
||||
import os |
||||
import ast |
||||
import glob |
||||
import datetime |
||||
import subprocess |
||||
import configparser |
||||
|
||||
from contextlib import contextmanager |
||||
|
||||
#----------------------------------------------------------------------------- |
||||
# Class for errors catching |
||||
class FabricException(Exception): |
||||
pass |
||||
|
||||
#----------------------------------------------------------------------------- |
||||
|
||||
#Color highlighting of errors |
||||
env.colorize_errors = True |
||||
#Generating exceprions instead fails |
||||
env.abort_exception=FabricException |
||||
|
||||
#----------------------------------------------------------------------------- |
||||
|
||||
@contextmanager |
||||
def if_needed(): |
||||
'''Execution with ignore errors''' |
||||
try: |
||||
yield |
||||
except: |
||||
pass |
||||
|
||||
def readConfig(config_file): |
||||
'''Read config file''' |
||||
global settings |
||||
settings = configparser.ConfigParser() |
||||
settings._interpolation = configparser.ExtendedInterpolation() |
||||
settings.read(config_file) |
||||
return settings |
||||
|
||||
@contextmanager |
||||
def timestamp(*args): |
||||
print '[' + current_time() + ']', args |
||||
yield |
||||
|
||||
def opt(parameter): |
||||
'''Get options''' |
||||
setting = parameter.split(":") |
||||
return settings.get(setting[0], setting[1]) |
||||
|
||||
def background_run(command): |
||||
'''Background execution of commands on remote servers''' |
||||
subprocess.Popen(["nohup", command]) |
||||
|
||||
def current_time(): |
||||
'''Current time in HH:MM:SS format''' |
||||
return datetime.datetime.now().time().strftime('%X') |
||||
|
||||
#----------------------------------------------------------------------------- |
||||
|
||||
@task |
||||
def make_dist(): |
||||
'''Make distributive (play dist)''' |
||||
with lcd(opt('release:app_path_stand')): |
||||
local("sh ./%s" % opt('release:make_dist_script')) |
||||
|
||||
@task |
||||
def diff_config(): |
||||
'''Comparison of configuration files''' |
||||
old_config = opt('product:custom_conf_template') |
||||
new_config = opt('release:custom_conf_template') |
||||
tmp_config = os.path.join('/tmp/', os.path.basename(old_config)) |
||||
|
||||
with hide('commands'): |
||||
get(old_config, '/tmp/') |
||||
|
||||
diff = os.system("diff -w -B %s %s" % (tmp_config, new_config)) |
||||
|
||||
local("rm -f %s" % tmp_config) |
||||
|
||||
if diff == 0: |
||||
return False |
||||
else: |
||||
return True |
||||
|
||||
def copy_dirs(directories): |
||||
'''Upload local directories to remote server''' |
||||
for src_dir, dst_dir in ast.literal_eval(directories): |
||||
for config_file in glob.glob(src_dir + "/*"): |
||||
if os.path.basename(config_file) not in opt('product:config_exclude'): |
||||
src_root = src_dir.split('*')[0] |
||||
config_file_path = config_file.replace(src_root, '') |
||||
remote_file = os.path.join(opt('product:app_path_stand'), dst_dir.split('*')[0], config_file_path) |
||||
|
||||
put(config_file, remote_file) |
||||
|
||||
@task |
||||
def upload_dist(): |
||||
'''Upload distributive to remote server''' |
||||
dist_dir = os.path.join(opt('product:app_path_dist'), date) |
||||
run('mkdir -p %s' % dist_dir) |
||||
|
||||
#Uploading archive |
||||
with lcd(opt('release:app_path_dist')): |
||||
put('*.zip', dist_dir) |
||||
|
||||
#Extracting files |
||||
with cd(dist_dir): |
||||
run('yes All | unzip *.zip') |
||||
|
||||
@task |
||||
def copy_config(): |
||||
'''Copy configuration files''' |
||||
if diff_config(): |
||||
print "#### [WARN] Configuration files on the servers are different. Check them manually" |
||||
print "#### or execute `fab copy_custom_conf' for force upload custom.conf.template" |
||||
exit(1) |
||||
|
||||
copy_dirs(opt('release:config_dirs')) |
||||
|
||||
@task |
||||
def copy_custom_conf(): |
||||
'''Upload custom.conf to remote server''' |
||||
put(opt('release:custom_conf_template'), opt('product:custom_conf_template')) |
||||
|
||||
@task |
||||
def backup_files(): |
||||
'''Back up files''' |
||||
with cd(opt('product:app_path_stand')): |
||||
run('mkdir -p backup/%s' % date) |
||||
for to_backup in ast.literal_eval(opt('product:backup_files')): |
||||
run('cp -rv %s ../backup/%s' % (os.path.join(opt('product:app_path_stand'), to_backup), date)) |
||||
|
||||
@task |
||||
def backup_db(): |
||||
'''Back up distributive''' |
||||
with cd(opt('product:app_path_stand')): |
||||
run("%s" % opt('product:backup_db_script')) |
||||
|
||||
@task |
||||
def backup_db_copy(): |
||||
'''Backround upload of backup to remote server''' |
||||
with cd(opt('product:app_path_stand')): |
||||
background_run(opt('product:backup_db_copy_script')) |
||||
|
||||
@task |
||||
def stop(): |
||||
'''Stop service''' |
||||
run('kill $(cat %s)' % opt('product:app_pid_file')) |
||||
|
||||
def remove_libs(): |
||||
'''Remove previous version''' |
||||
run('rm -rfv %s' % opt('product:app_path_libs')) |
||||
|
||||
@task |
||||
def copy_libs(): |
||||
'''Copy libs''' |
||||
with cd(opt('product:app_path_stand')): |
||||
run('cp -rv %s %s' % (os.path.join(opt('product:app_path_dist'), date, '*/lib'), opt('product:app_path_libs'))) |
||||
|
||||
@task |
||||
def start(): |
||||
'''Start service''' |
||||
with cd(opt('product:app_path_stand')): |
||||
run("sh %s >> nohup.out 2>> nohup.out < /dev/null &" % opt('product:app_start_script'), pty=True) |
||||
|
||||
#----------------------------------------------------------------------------- |
||||
@task |
||||
def update(): |
||||
'''Update service''' |
||||
make_dist() |
||||
upload_dist() |
||||
copy_config() |
||||
backup_files() |
||||
|
||||
with timestamp("MAKING BACKUP"): |
||||
backup_db() |
||||
with timestamp("UPLOADING BACKUP"): |
||||
backup_db_copy() |
||||
with timestamp("NEXT STEP"): |
||||
pass |
||||
|
||||
with if_needed(): stop() |
||||
|
||||
remove_libs() |
||||
copy_libs() |
||||
|
||||
start() |
||||
|
||||
#----------------------------------------------------------------------------- |
||||
|
||||
settings = [] |
||||
|
||||
readConfig('config.ini') |
||||
|
||||
#Remote host |
||||
env.host_string = opt('product:host') |
||||
|
||||
date = datetime.datetime.now().strftime("%Y-%m-%d") |
||||
|
Binary file not shown.
Loading…
Reference in new issue