#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2013-2022:
# This file is part of Shinken Enterprise, all rights reserved.

import optparse
import os
import sys

import pymongo
from bson import BSON

OVERLOAD_FILE = u'/etc/shinken-user/configuration/daemons/synchronizers/synchronizer_cfg_overload.cfg'
SYNCHRONIZER_FILE = u'/etc/shinken/synchronizer.cfg'
SYNCHRONIZER_INFO = u'synchronizer-info'

CLEAN_COMMAND = {
    u'_id'         : u'ee4d4311970d11e88f18f8bc126497d6',
    u'command_line': u'/bin/printf \'clean command\'',
    u'command_name': u'clean_command',
    u'_SYNC_KEYS'  : [u'clean_command']
}
# List of properties and their new value. If value is None, property will be deleted
PROPERTIES_TO_CLEAN = [
    (u'address', u'clean address'),
    (u'check_command', u'clean_command'),
    (u'password', u'clean'),
    (u'poller_tag', None),
    (u'reactionner_tag', None),
    (u'realm', None),
    (u'@metadata', None)
]

property_anonymous = set()


def read_cfg_file(cfg_file):
    try:
        with open(cfg_file, 'r') as f:
            buff = f.readlines()
    except Exception as e:
        print u'Cannot read the file %s to know which fields to clean : %s' % (cfg_file, e.__str__())
        sys.exit(2)
    return buff


def get_protected_data_list():
    # First try to read from overload
    synchronizer_cfg = read_cfg_file(OVERLOAD_FILE)
    for line in synchronizer_cfg:
        if u'protect_fields__substrings_matching_fields' in line:
            return line.replace(u'\n', u'').split(u'=')[1].split(u',')
    
    # If there is no overload, read from the synchronizer itself
    synchronizer_cfg = read_cfg_file(SYNCHRONIZER_FILE)
    for line in synchronizer_cfg:
        if u'protect_fields__substrings_matching_fields' in line:
            return line.replace(u'\n', u'').split(u'=')[1].split(u',')
    
    return []


def clean_properties(item, protected_data):
    last_modification_change = item.get(u'last_modification', {}).get(u'change', None)
    if last_modification_change:
        _clean_last_modification(last_modification_change, protected_data)
    
    last_modification_change = item.get(u'change', None)
    if last_modification_change:
        _clean_last_modification(last_modification_change, protected_data)
    
    work_area_info_diff_item = item.get(u'work_area_info', {}).get(u'diff_item', None)
    if work_area_info_diff_item:
        for diff_item in work_area_info_diff_item:
            if diff_item[u'prop'] in [i[0] for i in PROPERTIES_TO_CLEAN]:
                diff_item[u'new'] = u'clean'
                diff_item[u'stagging'] = u'old clean'
                property_anonymous.add(diff_item[u'prop'])
            elif diff_item[u'prop'].startswith(u'_'):
                for protected_field in protected_data:
                    if protected_field.upper() in diff_item[u'prop'].upper():
                        diff_item[u'new'] = u'clean'
                        diff_item[u'stagging'] = u'old clean'
                        property_anonymous.add(diff_item[u'prop'])
    
    link_service_overrides = item.get(u'service_overrides', {}).get(u'links', None)
    if link_service_overrides:
        for link in link_service_overrides:
            if link[u'key'].startswith(u'_'):
                for protected_field in protected_data:
                    if protected_field.upper() in link[u'key'].upper():
                        link[u'value'] = u'clean'
                        property_anonymous.add(link[u'key'])
    
    for property_name, new_value in PROPERTIES_TO_CLEAN:
        if item.get(property_name, None):
            if new_value:
                item[property_name] = new_value
            else:
                del item[property_name]
            property_anonymous.add(property_name)
    
    if protected_data:
        for prop_name in item.iterkeys():
            if prop_name.startswith('_'):
                for protected_field in protected_data:
                    if protected_field.upper() in prop_name.upper():
                        item[prop_name] = u'clean'
                        property_anonymous.add(prop_name)


def _clean_last_modification(last_modification_change, protected_data):
    for change in last_modification_change:
        if change[u'prop'] in [i[0] for i in PROPERTIES_TO_CLEAN]:
            change[u'new'] = u'clean'
            change[u'old'] = u'old clean'
            property_anonymous.add(change[u'prop'])
        elif change[u'prop'].startswith(u'_'):
            for protected_field in protected_data:
                if protected_field.upper() in change[u'prop'].upper():
                    change[u'new'] = u'clean'
                    change[u'old'] = u'old clean'
                    property_anonymous.add(change[u'prop'])


def main():
    parser = optparse.OptionParser(u'%prog ', description=u'Used to anonymize configuration database')
    parser.add_option(u'-u', u'--url', dest=u'url', default=u'localhost', help=u'URL of the mongo db [default : localhost]')
    parser.add_option(u'', u'--db', dest=u'database', default=u'synchronizer', help=u'database')
    parser.add_option(u'', u'--directory', dest=u'directory', default=u'dump-configuration', help=u'Directory backup')
    
    opts, args = parser.parse_args()
    
    protected_data = get_protected_data_list()
    if not protected_data:
        print u'No protected fields were found in file %s. Continue without protected_fields' % OVERLOAD_FILE
    
    # STEP : check if directory exists
    if not os.path.exists(opts.directory):
        os.mkdir(opts.directory)
    final_directory = os.path.join(opts.directory, opts.database)
    if not os.path.exists(final_directory):
        os.mkdir(final_directory)
    
    mongodb_con = pymongo.MongoClient(u'mongodb://%s' % opts.url, fsync=False)
    mongodb_db = getattr(mongodb_con, opts.database)
    
    synchronizer_info = getattr(mongodb_db, SYNCHRONIZER_INFO)
    file_name = os.path.join(final_directory, u'%s.bson' % SYNCHRONIZER_INFO)
    with open(file_name, u'wb+') as f:
        for doc in synchronizer_info.find():
            if doc[u'_id'] == u'protected_fields_info':
                doc[u'protect_fields__activate_database_encryption'] = False
            f.write(BSON.encode(doc))
    
    for collection_name in mongodb_db.collection_names(include_system_collections=False):
        if not collection_name.startswith(u'configuration') and collection_name != u'history':
            continue
        
        file_name = os.path.join(final_directory, u'%s.bson' % collection_name)
        with open(file_name, u'ab+') as f:
            
            if collection_name in (u'configuration-production-command', u'configuration-stagging-command'):
                f.write(BSON.encode(CLEAN_COMMAND))
            
            collection = getattr(mongodb_db, collection_name)
            items = collection.find()
            for item in items:
                clean_properties(item, protected_data)
                f.write(BSON.encode(item))


if __name__ == u'__main__':
    main()
