#!/usr/bin/python3
# -*- coding: UTF-8 -*-

# Copyright (C) 2015-2016 Avencall
#
# 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, either version 3 of the License, or
# (at your option) any later version.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>

import argparse
import json
import logging
import os.path
import subprocess
import sys
from xivo.xivo_logging import setup_logging

LOG_FORMAT='%(asctime)s [%(process)d] (%(levelname)s): %(message)s'
REMOTE_USER = 'root'
SSH_KEY = '/root/.ssh/xivo_id_rsa'
SYNC_DIRECTORIES = [
    '/etc/asterisk/extensions_extra.d',
    '/etc/xivo/asterisk',
    '/var/lib/asterisk/agi-bin',
    '/var/lib/asterisk/moh',
    '/var/lib/consul/raft',
    '/var/lib/xivo/sounds/acd',
    '/var/lib/xivo/sounds/playback',
    '/var/lib/xivo/certificates',
]

logger = logging.getLogger()


def main():
    args = parse_args()

    setup_logging('/var/log/xivo-sync.log', foreground=True, log_format=LOG_FORMAT)
    try:
        ha_conf = read_ha_conf()
        if args.init:
            init(ha_conf)
        else:
            sync(ha_conf)
    except Exception:
        logger.exception('Unexpected error:')
        sys.exit(1)


def init(ha_conf):
    if not ha_conf.is_master():
        print('HA not configured or not a master node', file=sys.stderr)
        sys.exit(1)
    if ssh_key_exists():
        print('SSH key {} already exist'.format(SSH_KEY), file=sys.stderr)
        sys.exit(1)

    print('Generating SSH key {}...'.format(SSH_KEY))
    subprocess.call(['ssh-keygen', '-q', '-t', 'rsa', '-N', '', '-C', 'XiVO HA', '-f', SSH_KEY])
    print('Copying SSH key to {} (using ssh-copy-id)...'.format(ha_conf.remote_address()))
    subprocess.call(['ssh-copy-id', '-i', SSH_KEY, '{}@{}'.format(REMOTE_USER, ha_conf.remote_address())])


def sync(ha_conf):
    if not ha_conf.is_master():
        logger.error('HA not configured or not a master node')
        sys.exit(1)
    if not ssh_key_exists():
        logger.info('SSH key %s not found: not synchronizing', SSH_KEY)
        sys.exit(0)

    logger.info('Synchronizing to %s...', ha_conf.remote_address())
    command = [
        'rsync',
        '-q', '-aR', '--delete-after',
        '-e', 'ssh -i {} -o PreferredAuthentications=publickey'.format(SSH_KEY),
    ]
    command.extend(SYNC_DIRECTORIES)
    command.append('{}@{}:/'.format(REMOTE_USER, ha_conf.remote_address()))
    p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    output = p.communicate()[0]
    if p.returncode:
        logger.error('Synchronization failure: rsync exit status %s with output:\n%s', p.returncode, output)
        sys.exit(1)
    else:
        logger.info('Synchronization successful')


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('-i', '--init', action='store_true')
    return parser.parse_args()


def read_ha_conf():
    try:
        with open('/etc/xivo/ha.conf') as fobj:
            return HAConfig(json.load(fobj))
    except IOError:
        return HAConfig(None)


class HAConfig(object):

    def __init__(self, obj):
        self._obj = obj

    def is_master(self):
        return self._obj and self._obj['node_type'] == 'master'

    def remote_address(self):
        return self._obj['remote_address']


def ssh_key_exists():
    return os.path.isfile(SSH_KEY)


main()
