#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4
#
# Copyright (C) 2016 Samsung
#
#    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 2
#    of the License.
#
#    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, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
"""
This code is called by digest issue checker
"""

import os
import sys
import time
from datetime import datetime
import subprocess
import re
import json
from pprint import pprint

from common.buildservice import BuildService
from osc import core


FAULTY_SLOTS = os.getenv('SLOTS')
SEARCH_ROOT = os.getenv('SEARCH_ROOT')
SEARCH_COUNT = os.getenv('SEARCH_COUNT')
SEARCH_SIZE = os.getenv('SEARCH_SIZE')
SEARCH_MINUTES = os.getenv('SEARCH_MINUTES')


def datetime_from_utc_to_local(utc_datetime):
    now_timestamp = time.time()
    offset = datetime.fromtimestamp(now_timestamp) - datetime.utcfromtimestamp(now_timestamp)
    return utc_datetime + offset

def list_project():
    os.system('ls -1At {} | head -{} > .project.list'.format(SEARCH_ROOT, SEARCH_COUNT))
    with open('.project.list', 'r') as rf:
        project_list = rf.read()
    return [ x for x in project_list.split('\n') if x != '' ]


def find_logfiles(project_name):
    command = 'find {}/{}/ -type f -name logfile -size -{} -mmin -{} -exec ls {} +' \
              .format(SEARCH_ROOT, project_name, SEARCH_SIZE, SEARCH_MINUTES, '{}')
    os.system('{} > .logfile.list'.format(command))
    with open('.logfile.list', 'r') as rf:
        logfile_list = rf.read()
    return [ x for x in logfile_list.split('\n') if x != '' ]


def rebuild_project_package(PROJECT, PACKAGE, REPO, ARCH, HOST_TYPE, HOST_SLOT, ROOT_NUM, TIME):
    with open('DIGEST_REBUILD_{}_{}_{}_{}.env'.format(PROJECT, PACKAGE, REPO, ARCH), 'w') as df:
        df.write('PROJECT={}\n'.format(PROJECT))
        df.write('PACKAGE={}\n'.format(PACKAGE))
        df.write('SRCPKG={}\n'.format(PACKAGE))
        df.write('REPO={}\n'.format(REPO))
        df.write('ARCH={}\n'.format(ARCH))
        df.write('COMMENT={} ({}/{}) {}{}:{}::::{}\n'.format('Digest mismatch', \
                  REPO, ARCH, HOST_TYPE, HOST_SLOT, ROOT_NUM, TIME))
        df.write('DECISION={}\n'.format('rebuild'))


def get_obs_instance():
    obs_api = os.getenv("OBS_API_URL")
    obs_user = os.getenv("OBS_API_USERNAME")
    obs_passwd = os.getenv("OBS_API_PASSWD")
    return BuildService(obs_api, obs_user, obs_passwd)


def is_build_status_failed(project, package, repo, arch):
    build = get_obs_instance()
    results = core.get_results(build.apiurl, \
                  project, package)
    for res in results:
        r, a, s = res.split()
        if r ==  repo and a == arch and s == 'failed':
            return True
    return False


def status_polling():
    for project in list_project():
        if not os.path.isdir(os.path.join(SEARCH_ROOT, project)):
            continue
        logfile_list = find_logfiles(project)
        if logfile_list and len(logfile_list) > 0:
            for logfile in logfile_list:
                res = re.search(r'{}/(.*)/(.*)/(.*)/(.*)/logfile$' \
                                .format(SEARCH_ROOT), logfile)
                if res and res.groups() and len(res.groups()) != 4:
                    continue
                with open(logfile, 'r') as logf:
                    log_contents = logf.read()
                skip = True
                if 'cpio: Digest mismatch' in log_contents:
                    skip = False
                if 'Segmentation fault' in log_contents and 'build-pkg-rpm' in log_contents:
                    skip = False
                if skip == True:
                    continue
                PROJECT, REPO, ARCH, PACKAGE = list(res.groups())
                res = re.search(r'.* (obspw|obsnw)([0-9]+) failed .*', log_contents)
                if res and res.groups() and len(res.groups()) == 2:
                    HOST_TYPE, HOST_SLOT = list(res.groups())
                else:
                    print('HOST_TYPE, SLOT not found')
                    print(log_contents)
                    continue
                res = re.search(r'.*Using BUILD_ROOT=\/var\/cache\/build\/root_([0-9]+).*', log_contents)
                ROOT_NUM = '0'
                if res and res.groups() and len(res.groups()) == 1:
                    ROOT_NUM = res.groups()[0]
                if is_build_status_failed(PROJECT, PACKAGE, REPO, ARCH):
                    print('ISSUE FOUND FOR {}/{}/{}/{} => {}:{}:{}'.format( \
                              PROJECT, REPO, ARCH, PACKAGE, HOST_TYPE, HOST_SLOT, ROOT_NUM))
                    sys.stdout.flush()
                    if not os.path.isfile('DIGEST_MISMATCH.env'):
                        with open('DIGEST_MISMATCH.env', 'w') as dmf:
                            dmf.write('BACKEND_SELECTION="master"\n')
                            dmf.write('SLOTS=')
                    with open('DIGEST_MISMATCH.env', 'a') as dmf:
                        dmf.write('{}.{} '.format(HOST_TYPE, HOST_SLOT))

                    TIME = None
                    try:
                        dd = re.search(r'.*(obspw|obsnw)([0-9]+) started .* at (.*).', log_contents)
                        do = datetime.strptime(dd.groups()[2], "%a %b %d %H:%M:%S %Z %Y")
                        TIME = do.strftime("%Y-%m-%d %H:%M:%S")
                        #TIME = datetime_from_utc_to_local(do).strftime("%Y-%m-%d %H:%M:%S")
                    except Exception as err:
                        pass

                    rebuild_project_package(PROJECT, PACKAGE, REPO, ARCH, HOST_TYPE, HOST_SLOT, ROOT_NUM, TIME)
                    #os.system("sudo sed -i 's/cpio: Digest mismatch/cpio: Digest X mismatch/g' {}".format(logfile))
                    #os.system("sudo sed -i 's/Segmentation fault/Segmentation X fault/g' {}".format(logfile))
                else:
                    print('Already rebuild issued')


def ping_aws_instance(worker_type, slot):
    SCRIPT_NAME = '/var/lib/jenkins/jenkins-scripts/common/aws_ec2.py'
    command = '{} ping -t Name:obsworker{},hostname:obsworker{}{}' \
              .format(SCRIPT_NAME, worker_type, worker_type, slot)
    os.system('{} > .aws.info'.format(command))
    with open('.aws.info', 'r') as rf:
        aws_info = rf.read()
    aws_info = re.search(r'.*\n-----BEGIN RC OUTPUT-----\n(.*)\n-----END RC OUTPUT-----\n.*', aws_info)
    if aws_info and aws_info.groups():
        return json.loads(aws_info.groups()[0].replace("'", '"').replace('None', '""'))
    return None


def stop_obs_worker(private_ip_address):
    if os.getenv('STOP_OBS_WORKER', None) != 'TRUE':
        return

    worker_stop_command = 'obs_worker rcobsworker stop'
    command = 'ssh -o StrictHostKeyChecking=no -X build.jenkins@{} sudo docker exec {}' \
               .format(private_ip_address, worker_stop_command)
    os.system(command)


def shutdown_obs_worker(private_ip_address):
    if os.getenv('SHUTDOWN_OBS_WORKER', None) != 'TRUE':
        return
    #echo "Terminating ${slot} ${private_ip_address} ${instance_id}"
    #/var/lib/jenkins/jenkins-scripts/common/aws_ec2.py terminate -i ${instance_id} || true


def stop_worker(slot):
    worker_type, slot = slot.split('.')
    if worker_type == 'obspw':
        worker_type = 'power'
    elif worker_type == 'obsnw':
        worker_type = 'normal'
    aws_info = ping_aws_instance(worker_type, slot)

    if not aws_info:
        return

    instance_id = '{}'.format(aws_info.keys()[0])
    private_ip_address = '{}'.format(aws_info.get(instance_id).get('private_ip_address'))
    status = '{}'.format(aws_info.get(instance_id).get('state'))

    print('INSTANCE: {}'.format(instance_id))
    print('IP: {}'.format(private_ip_address))
    print('STATE: {}'.format(status))

    stop_obs_worker(private_ip_address)


if FAULTY_SLOTS is None:
    status_polling()
else:
    print('We got slots...')
    SLOTS = list(set(FAULTY_SLOTS.split()))
    pprint(SLOTS)
    for slot in SLOTS:
        stop_worker(slot)
    sys.exit(-1)

