#!/usr/bin/env python2
"""
Serialize data from task spooler, gather system data and ship to elasticsearch

This library will help gather data from task spooler and help
send it to elasticsearch, or return json.
"""

import re
import os
import datetime
import sys

from subprocess import check_output, call
from elasticsearch import Elasticsearch
from socket import getfqdn


class Tsp:
    """
    Gather data from task spooler and send it away
    """

    def __init__(self):
        self.output = []
        self.results = []
        self.toremove = []

    def get_output(self, search=None):
        """
        Get output from taskspooler about finished jobs
        """
        tspout = check_output('tsp').split('\n')
        for i in tspout[1:-1]:
            if i.split()[1] == 'finished':
                if search:
                    if re.compile(search).findall(i):
                        self.output.append(i.split())
                else:
                    self.output.append(i.split())

    def get_results(self):
        """
        Gather exit code and job file for a tsp job
        """
        for i in self.output:
            results = {}
            toremove = {}
            index = self.output[self.output.index(i)]
            tspfile = index[2]
            toremove['tspid'] = index[0]
            toremove['tspfile'] = tspfile
            results['title'] = index[-1].split('/')[-1]
            results['worker'] = getfqdn()
            results['exit_code'] = index[3]
            results['timestamp'] = str(os.path.getmtime(tspfile)).split('.')[0]
            results['mtime'] = self.get_timestamp(tspfile)
            results['command'] = index[5:]
            results['primary_storage'] = self.check_nfs_source(results['title'])
            results['host_url'] = self.get_target_fqdn(index)
            tspfile = toremove['tspfile']
            if os.path.isfile(tspfile):
                results['changes'] = self.read_file(tspfile)
                err_file = str('{}.e'.format(tspfile))
                if os.path.isfile(err_file):
                    results['errors'] = self.read_file(err_file)
            self.results.append(results)
            self.toremove.append(toremove)
        self.check_if_changes()

    def check_if_changes(self, out='changes', err='errors'):
        """
        Checks for content in changes and errors. Populates has_changes / has _errors
        """
        for i in self.results:
            if i[out]: # Check if there are any changes
                i['has_{}'.format(out)] = True
            else:
                i['has_{}'.format(out)] = False
                del i[out]
            if i.get(err):
                if i[err]:
                    i['has_{}'.format(err)] = True
                else:
                    i['has_{}'.format(err)] = False
                    del i[err]

    def clean_up(self, tspid, filename):
        """
        Remove tsp job record and tmp file
        """
        self.remove_task(tspid)
        os.remove(filename)

    @staticmethod
    def get_timestamp(filename):
        """
        Get a formated timestamp of the last modified time of a file
        """
        file_mtime = os.path.getmtime(filename)
        time_format = '%Y-%m-%d %H:%M:%S'
        mtime = datetime.datetime.fromtimestamp(file_mtime).strftime(time_format)
        return mtime

    @staticmethod
    def read_file(filename):
        """
        Get the output of a file and return a list
        """
        file_out = []
        for i in open(filename):
            file_out.append(i.strip())
        return file_out

    @staticmethod
    def check_nfs_source(title):
        """
        Checks /etc/fstab for source of a nfs mount
        """
        for i in open('/etc/fstab'):
            if re.compile(title).findall(i):
                if re.compile('^{}$'.format(title)).findall(i.split()[1].split('/')[-1]):
                    return i.split(':')[0]

    @staticmethod
    def get_target_fqdn(source, user='zpr_proxy'):
        """
        Get the fqdn of the job target
        """
        for i in source:
            if re.compile('^{}@'.format(user)).findall(i):
                return i.split('@')[-1].split(':')[0]

    @staticmethod
    def remove_task(taskid):
        """
        Remove a job from the taskspooler list
        """
        call(['tsp', '-r', taskid])

    @staticmethod
    def send_to_elasticsearch(
            index,
            doc,
            content,
            url='elasticsearch.ops.puppetlabs.net'
        ):
        """
        Send results to elasticsearch in the specified index
        """
        es = Elasticsearch([{'host': url, 'port': 9200}])
        if es.ping():
            es.index(index, doc, content, id=None)
        else:
            sys.exit(1)

    @staticmethod
    def list_files(startpath):
        """
        List a file tree in json
        """
        tree = []
        for root, dirs, files in os.walk(startpath):
            root_list = {'directory': '{}/'.format(os.path.basename(root))}
            file_list = []
            for filename in files:
                file_list.append(filename)
            root_list['files'] = file_list
            tree.append(root_list)
        return tree

@@ -2394,17 +2394,16 @@
 es / has
- 
 _errors%0A
@@ -2850,16 +2850,201 @@
 l i%5Berr%5D
+%0A            else:%0A                if i%5B'exit_code'%5D == '0':%0A                    i%5B'has_%7B%7D'.format(err)%5D = False%0A                else:%0A                    i%5B'has_%7B%7D'.format(err)%5D = True
 %0A%0A    de

Set has errors based on exit code if no stderr present