#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Project: PabPlug (https://github.com/Pablites/PabPlug)
# Author: Paweł Wichary
# Date: 21 July 2015
# Licence: available on github
'''
Initialization of PabPlug
'''
# generowanie statusu do kontrolera 

import imp 
from multiprocessing.pool import Pool
from starcluster.clustersetup import ClusterSetup
from starcluster.logger import log
import sys
import time


class PabPlug(ClusterSetup):
    
    __nodes = []
    __master = None
    __user = None
    __user_shell = None
    __volumes = [] 
    __file_location = None
    __installed_nodes = []
    __not_installed_nodes = []
    __stopped_nodes = []
    __working_nodes = []
    __is_expert_user = False
    
    def __init__(self, file_location, user_type):
        self.__file_location = file_location
        if user_type.lower() == 'expert':
            self.__is_expert_user = True
        else:
            self.__is_expert_user = False
    
    def __load_module(self, path, module_name):
        sys.path.append(path)
        (f, filename, desc) = imp.find_module(module_name)
        return imp.load_module(module_name, f, filename, desc)
        
    def __remote_check_directory_existance(self, node, path_file):
        command_output = node.ssh.execute('if [ -d ' + path_file + ' ]; then echo "success";else echo "fail"; fi')
        if command_output[0] == 'success':
            return True
        else:
            return False


    def __refresh_cluster_status(self, nodes):
        assert len(nodes) != 0, 'PabPlug >>> Error: no nodes spotted in cluster'
        self.__installed_nodes = []
        self.__not_installed_nodes = []
        self.__working_nodes = []
        self.__stopped_nodes = []
        for node in nodes:            
            if self.__remote_check_directory_existance(node, '/opt/pvfs2/build/'):
                self.__installed_nodes.append(node)
            else:
                self.__not_installed_nodes.append(node)   
            if self.__remote_check_directory_existance(node, '/opt/pvfs2/build/storage/meta/'):
                mounts_on_node = node.ssh.execute('df -Th')
                for mount in mounts_on_node:
                    if 'tcp://master:3334/pvfs2-fs' in mount:
                        self.__working_nodes.append(node)      
                if node not in self.__working_nodes:
                    self.__stopped_nodes.append(node)

    def __get_cluster_pvfs_status(self, nodes):
        assert len(nodes) != 0, 'PabPlug >>> Error: no nodes spotted in cluster'
        get_alias_func = lambda x: x.alias
        self.__refresh_cluster_status(nodes)
        result = []
        result.append('PABPLUG - cluster status')    
        result.append('\n-> Nodes available in cluster:\n\t' + ','.join(map(get_alias_func, nodes)))
        result.append('\n-> Nodes with PVFS not installed:\n\t' + ','.join(map(get_alias_func, self.__not_installed_nodes)))
        result.append('\n-> Nodes with PVFS installed:\n\t' + ','.join(map(get_alias_func, self.__installed_nodes)))
        result.append('\n-> Nodes with PVFS stopped:\n\t' + ','.join(map(get_alias_func, self.__stopped_nodes)))
        result.append('\n-> Nodes with PVFS working:\n\t' + ','.join(map(get_alias_func, self.__working_nodes)))
        return ''.join(result)
        
    def __install_pvfs_software(self, node, controller):
        assert controller != None, 'PabPlug >>> Error: no controller connected'
        controller.cleaning_process(node)
        controller.create_folders(node)       
        if node.is_master():
            controller.transfer_files_master(node)
        else:
            controller.transfer_files_worker(node)          
        controller.fix_fetch(node)           
        controller.dependency_instalation(node) 
        controller.orangefs_instalation(node) 
    
    def __start_pvfs_mounts(self, controller, master, nodes):
        assert master.is_master(), 'PabPlug >>> Error: master node is not a cluster master'
        assert controller != None, 'PabPlug >>> Error: no controller connected'
        for node in nodes:
            controller.overwrite_pvfs_entry_file(node) 
        controller.overwrite_workers_list_file(master, nodes)  
        controller.overwrite_pvfs_config(master)
        controller.pvfs_startup(master)
        
    def __restart_pvfs_mounts(self, controller, master, nodes):
        assert master.is_master(), 'PabPlug >>> Error: master node is not a cluster master'
        assert controller != None, 'PabPlug >>> Error: no controller connected'
        controller.pvfs_restart(master, nodes)
    
    def __stop_pvfs_mounts(self, controller, master, nodes):
        assert master.is_master(), 'PabPlug >>> Error: master node is not a cluster master'
        assert controller != None, 'PabPlug >>> Error: no controller connected'
        controller.pvfs_stop(master, nodes)
    
    def __remove_pvfs_mounts(self, controller, master, nodes):
        assert master.is_master(), 'PabPlug >>> Error: master node is not a cluster master'
        assert controller != None, 'PabPlug >>> Error: no controller connected'
        controller.pvfs_stop(master, nodes)
        controller.pvfs_remove(master, nodes)
        

    def __expert_menu(self, nodes, master, user, user_shell, volumes, config_gen_class, controller):
        var = '-1'
        while var != '0':
            menu_str_builder = []
            menu_str_builder.append('\n################################################################\n')
            menu_str_builder.append(self.__get_cluster_pvfs_status(nodes))
            menu_str_builder.append('\n################################################################')
            menu_str_builder.append('\nPABPLUG - main menu\n')
            menu_str_builder.append('\n-> 1) Install pvfs software')
            menu_str_builder.append('\n-> 2) Start pvfs mounts')
            menu_str_builder.append('\n-> 3) Restart pvfs mounts')
            menu_str_builder.append('\n-> 4) Stop pvfs mounts')
            menu_str_builder.append('\n-> 5) Stop and Remove mounts')
            menu_str_builder.append('\n-> 0) Exit')
            print ''.join(menu_str_builder)
            var = raw_input("\nPlease type option number: ")
            config_gen = config_gen_class.ConfigGenerator(self.__file_location + '/pabplug/pabplug_config', nodes)
            config_gen.generate_pvfs_config(self.__file_location + '/pabplug/files/pvfs2-fs.conf')
            if var == '1':
                for node in nodes:
                    self.__install_pvfs_software(node, controller)
            elif var == '2':
                self.__start_pvfs_mounts(controller, master, self.__installed_nodes)
            elif var == '3':
                self.__restart_pvfs_mounts(controller, master, self.__stopped_nodes)
            elif var == '4':
                self.__stop_pvfs_mounts(controller, master, self.__working_nodes)
            elif var == '5':
                self.__remove_pvfs_mounts(controller, master, self.__working_nodes)
            elif var == '0':
                log.info('Pabplug finish work with success')

    def run(self, nodes, master, user, user_shell, volumes):
        self.__nodes = nodes
        self.__master = master
        self.__user = user
        self.__user_shell = user_shell
        self.__volumes = volumes
        assert master.is_master(), 'PabPlug >>> Error: master node is not a cluster master'
        assert len(nodes) != 0, 'PabPlug >>> Error: no nodes spotted in cluster'
        self.__refresh_cluster_status(nodes)
        controller_class = self.__load_module(self.__file_location + '/pabplug/src', 'pvfs_controller')
        config_gen_class = self.__load_module(self.__file_location + '/pabplug/src', 'config_generator')
        controller = controller_class.Controller(self.__file_location)            
        if self.__is_expert_user:
            self.__expert_menu(nodes, master, user, user_shell, volumes, config_gen_class, controller)  
        else:
            config_gen = config_gen_class.ConfigGenerator(self.__file_location + '/pabplug/pabplug_config', nodes)
            config_gen.generate_pvfs_config(self.__file_location + '/pabplug/files/pvfs2-fs.conf')
            for node in nodes:
                self.__install_pvfs_software(node, controller)
            self.__start_pvfs_mounts(controller, master, nodes)        
 
    def on_add_node(self, node, nodes, master, user, user_shell, volumes):
        assert master.is_master(), 'PabPlug >>> Error: master node is not a cluster master'
        assert len(nodes) != 0, 'PabPlug >>> Error: no nodes spotted in cluster'
        self.__refresh_cluster_status(nodes)
        controller_class = self.__load_module(self.__file_location + '/pabplug/src', 'pvfs_controller')
        config_gen_class = self.__load_module(self.__file_location + '/pabplug/src', 'config_generator')
        controller = controller_class.Controller(self.__file_location)            
        
        if self.__is_expert_user:
            self.__expert_menu(nodes, master, user, user_shell, volumes, config_gen_class, controller)  
        else:
            config_gen = config_gen_class.ConfigGenerator(self.__file_location + '/pabplug/pabplug_config', nodes)
            config_gen.generate_pvfs_config(self.__file_location + '/pabplug/files/pvfs2-fs.conf') 
            self.__refresh_cluster_status(nodes)
            self.__remove_pvfs_mounts(controller, master, self.__working_nodes) 
            self.__install_pvfs_software(node, controller)
            self.__start_pvfs_mounts(controller, master, self.__installed_nodes)    
    
    def stop_node(self, node):
        assert self.__master.is_master(), 'PabPlug >>> Error: master node is not a cluster master'
        assert len(self.__nodes) != 0, 'PabPlug >>> Error: no nodes spotted in cluster'
        self.__refresh_cluster_status(self.__nodes)
        controller_class = self.__load_module(self.__file_location + '/pabplug/src', 'pvfs_controller')
        config_gen_class = self.__load_module(self.__file_location + '/pabplug/src', 'config_generator')
        controller = controller_class.Controller(self.__file_location)            
        
        if self.__is_expert_user:
            self.__expert_menu(self.__nodes, self.__master, self.__user, self.__user_shell, self.__volumes, config_gen_class, controller)
        else: 
            self.__remove_pvfs_mounts(controller, self.__master, self.__working_nodes)
            self.__installed_nodes.remove(node)
            self.__refresh_cluster_status(self.__nodes)
            self.__start_pvfs_mounts(controller, self.__master, self.__installed_nodes)
            
    def on_remove_node(self, node, nodes, master, user, user_shell, volumes):
        assert master.is_master(), 'PabPlug >>> Error: master node is not a cluster master'
        assert len(nodes) != 0, 'PabPlug >>> Error: no nodes spotted in cluster'
        self.__refresh_cluster_status(nodes)
        controller_class = self.__load_module(self.__file_location + '/pabplug/src', 'pvfs_controller')
        config_gen_class = self.__load_module(self.__file_location + '/pabplug/src', 'config_generator')
        controller = controller_class.Controller(self.__file_location)            
        
        if self.__is_expert_user:
            self.__expert_menu(nodes, master, user, user_shell, volumes, config_gen_class, controller)
        else: 
            self.__remove_pvfs_mounts(controller, master, self.__working_nodes)
            self.__installed_nodes.remove(node)
            self.__refresh_cluster_status(nodes)
            self.__start_pvfs_mounts(controller, master, self.__installed_nodes)    
             

    def on_shutdown(self, nodes, master, user, user_shell, volumes):
        assert master.is_master(), 'PabPlug >>> Error: master node is not a cluster master'
        assert len(nodes) != 0, 'PabPlug >>> Error: no nodes spotted in cluster'
        self.__refresh_cluster_status(nodes)
        controller_class = self.__load_module(self.__file_location + '/pabplug/src', 'pvfs_controller')
        config_gen_class = self.__load_module(self.__file_location + '/pabplug/src', 'config_generator')
        controller = controller_class.Controller(self.__file_location)            
        
        if self.__is_expert_user:
            self.__expert_menu(nodes, master, user, user_shell, volumes, config_gen_class, controller) 
        else:
            self.__stop_pvfs_mounts(controller, master, self.__working_nodes) 
