|
|
|
@ -1,16 +1,19 @@
@@ -1,16 +1,19 @@
|
|
|
|
|
#!/usr/bin/env python |
|
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
|
|
|
|
# Copyright (C) 2017, Maxim Lihachev, <envrm@yandex.ru> |
|
|
|
|
# |
|
|
|
|
# Script for updating service/application on remote server using Fabric. |
|
|
|
|
# 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. |
|
|
|
|
# |
|
|
|
|
# (c) envrm |
|
|
|
|
# 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. |
|
|
|
|
# |
|
|
|
|
|
|
|
|
|
#Installing fabric: |
|
|
|
|
# apt-get install python-dev libffi-dev |
|
|
|
|
# pip install configparser |
|
|
|
|
# pip install fabric |
|
|
|
|
# You should have received a copy of the GNU General Public License along with |
|
|
|
|
# this program. If not, see <https://www.gnu.org/licenses/>. |
|
|
|
|
|
|
|
|
|
from __future__ import with_statement |
|
|
|
|
from fabric.api import * |
|
|
|
@ -24,19 +27,23 @@ import configparser
@@ -24,19 +27,23 @@ import configparser
|
|
|
|
|
|
|
|
|
|
from contextlib import contextmanager |
|
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- |
|
|
|
|
# Class for errors catching |
|
|
|
|
class FabricException(Exception): |
|
|
|
|
pass |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
|
|
|
# ---------------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
#Color highlighting of errors |
|
|
|
|
|
|
|
|
|
# Color highlighting of errors |
|
|
|
|
env.colorize_errors = True |
|
|
|
|
#Generating exceprions instead fails |
|
|
|
|
env.abort_exception=FabricException |
|
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
|
|
|
# Generating exceprions instead fails |
|
|
|
|
env.abort_exception = FabricException |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
@contextmanager |
|
|
|
|
def if_needed(): |
|
|
|
@ -46,6 +53,7 @@ def if_needed():
@@ -46,6 +53,7 @@ def if_needed():
|
|
|
|
|
except: |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def readConfig(config_file): |
|
|
|
|
'''Read config file''' |
|
|
|
|
global settings |
|
|
|
@ -54,25 +62,30 @@ def readConfig(config_file):
@@ -54,25 +62,30 @@ def readConfig(config_file):
|
|
|
|
|
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(): |
|
|
|
@ -99,6 +112,7 @@ def diff_config():
@@ -99,6 +112,7 @@ def diff_config():
|
|
|
|
|
else: |
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def copy_dirs(directories): |
|
|
|
|
'''Upload local directories to remote server''' |
|
|
|
|
for src_dir, dst_dir in ast.literal_eval(directories): |
|
|
|
@ -110,20 +124,22 @@ def copy_dirs(directories):
@@ -110,20 +124,22 @@ def copy_dirs(directories):
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
# Uploading archive |
|
|
|
|
with lcd(opt('release:app_path_dist')): |
|
|
|
|
put('*.zip', dist_dir) |
|
|
|
|
|
|
|
|
|
#Extracting files |
|
|
|
|
# Extracting files |
|
|
|
|
with cd(dist_dir): |
|
|
|
|
run('yes All | unzip *.zip') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@task |
|
|
|
|
def copy_config(): |
|
|
|
|
'''Copy configuration files''' |
|
|
|
@ -134,11 +150,13 @@ def copy_config():
@@ -134,11 +150,13 @@ def copy_config():
|
|
|
|
|
|
|
|
|
|
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''' |
|
|
|
@ -147,40 +165,47 @@ def backup_files():
@@ -147,40 +165,47 @@ def backup_files():
|
|
|
|
|
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''' |
|
|
|
@ -196,21 +221,22 @@ def update():
@@ -196,21 +221,22 @@ def update():
|
|
|
|
|
with timestamp("NEXT STEP"): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
with if_needed(): stop() |
|
|
|
|
with if_needed(): |
|
|
|
|
stop() |
|
|
|
|
|
|
|
|
|
remove_libs() |
|
|
|
|
copy_libs() |
|
|
|
|
|
|
|
|
|
start() |
|
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
settings = [] |
|
|
|
|
|
|
|
|
|
readConfig('config.ini') |
|
|
|
|
|
|
|
|
|
#Remote host |
|
|
|
|
# Remote host |
|
|
|
|
env.host_string = opt('product:host') |
|
|
|
|
|
|
|
|
|
date = datetime.datetime.now().strftime("%Y-%m-%d") |
|
|
|
|
|
|
|
|
|