Browse Source

service-updater v1.0

master
Maxim Lihachev 8 years ago
commit
a0921219c2
  1. 28
      README.md
  2. 35
      config.ini
  3. 216
      fabfile.py
  4. BIN
      fabfile.pyc

28
README.md

@ -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

35
config.ini

@ -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

216
fabfile.py vendored

@ -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")

BIN
fabfile.pyc

Binary file not shown.
Loading…
Cancel
Save