__author__ = 'jralph'
__version__ = '1.0.0'
import configparser
import os
import sys
import logging
import subprocess
import shlex
import socket
import datetime
import requests
# set hostname.
hostname = socket.gethostname()
# set date now.
now = datetime.datetime.now()
# obtain script name and assign to variable.
script_name = sys.argv[0].split('.')[0]
# sanity check for configuration environment variable.
if "INI_PATH" not in os.environ.keys():
print('INI_PATH is not set, check the .bashrc')
sys.exit(1)
# parse the configuration sections of the ini file.
config = configparser.ConfigParser()
try:
config.read(os.environ['INI_PATH'] + '/pg_table_sync_dev_prod.ini')
config.sections()
log_file = config.get('logging', 'log_file')
log_path = config.get('logging', 'log_path')
slack_hook = config.get('slack', 'webhook')
except configparser.NoSectionError as e:
print('FATAL: Command failed with error [{0}]'.format(e))
# setup logging.
try:
logging.basicConfig(filename='%s/%s' % (log_path, log_file),
format='%(asctime)s %(message)s',
datefmt='%m-%d-%Y %I:%M:%S %p -',
level=logging.DEBUG)
except NameError as e:
print('FATAL: Command failed with error [{0}]'.format(e))
# get hosts and tablenames.
try:
pg_tables_to_sync = dict(config.items('pg_table_source_dest'))
source_db = config.get('hosts', 'source_db')
dest_db = config.get('hosts', 'dest_db')
dump_location = config.get('dump_location', 'local_location')
dev_db = config.get('database', 'dev_db')
prod_db = config.get('database', 'prod_db')
except (configparser.NoSectionError, NameError) as e:
logging.critical('FATAL: Command failed with error [{0}]'.format(e))
# pg_dump function.
def pg_dump():
cmd_list = []
tables = {}
try:
tables = sorted(pg_tables_to_sync.items())
except NameError as e:
logging.critical('FATAL: Command failed with error [{0}]'.format(e))
for key, value in tables:
dump_cmd = 'pg_dump -Fc -h {0} -d {1} -t {2} -f {4}{2}.{3}.pgdump'.format(
source_db, dev_db, key, now.strftime("%Y%m%d"), dump_location)
cmd_list.append(dump_cmd)
return cmd_list
# pg_restore function.
def pg_restore():
cmd_list = []
tables = {}
try:
tables = sorted(pg_tables_to_sync.items())
except NameError as e:
logging.critical('FATAL: Command failed with error [{0}]'.format(e))
for key, value in tables:
dump_cmd = 'pg_restore -c -h {0} -d {1} {4}{2}.{3}.pgdump'.format(
dest_db, prod_db, key, now.strftime("%Y%m%d"), dump_location)
cmd_list.append(dump_cmd)
return cmd_list
# send to slack function.
def send_to_slack(slack_url, state, command, date_format, priority, target_os):
slack_data = {'attachments': [
{
"fallback": "Required plain-text summary of the attachment.",
"color": priority,
"pretext": "PG Table Sync",
"author_name": command,
"text": "%s" % date_format,
"fields": [
{
"title": "%s" % target_os,
"value": state,
"short": "false"
}
],
"footer": "AFS Slack",
"footer_icon": "https://platform.slack-edge.com"
"/img/default_application_icon.png"
}
]}
response = requests.post(
slack_url, json=slack_data)
if response.status_code != 200:
raise ValueError(
'Request to slack returned an error %s, the response is:\n%s'
% (response.status_code, response.text))
# execute with logging.
def execute_jobs(cmd):
try:
logging.info('Start Command: [%s]' % cmd)
subprocess.run(shlex.split(cmd), check=True)
logging.info('Command Success: [%s]' % cmd)
try:
send_to_slack(slack_hook, 'Ok', cmd,
datetime.datetime.today(), 'good', hostname)
except ValueError as e:
logging.critical('FATAL: Slack post failed with error [%s]'
% e)
except subprocess.CalledProcessError as e:
logging.critical('[%s] FATAL: Command failed with error [%s]'
% (cmd, e))
try:
send_to_slack(slack_hook, 'Critical', cmd,
datetime.datetime.today(), 'danger', hostname)
except ValueError as e:
logging.critical('FATAL: Slack post failed with error [%s]'
% e)
# main
def main():
for command in pg_dump():
execute_jobs(command)
for command in pg_restore():
execute_jobs(command)
logging.info('finished ' + script_name)
if __name__ == "__main__":
main()