#!/opt/vmware/bin/python

# Copyright 2016 VMware, Inc.  All rights reserved. -- VMware Confidential

"""
This file describes the actions to be performed post restore of a VC.
"""

import os
import sys
import argparse
import getpass

sys.path.append(os.environ['VMWARE_PYTHON_PATH'])
import logging
from cis.utils import (get_deployment_nodetype, StartType,
                       invoke_command, setupLogging, osIsSystemd)
from cis.defaults import (def_by_os, get_cis_install_dir,
                          get_component_home_dir)
from cis.exceptions import (InvokeCommandException,
                            SetServiceStartTypeException,
                            ServiceNotFoundException)
from cis.svcsController import update_services_startuptype


log_dir = os.path.join(os.environ['VMWARE_LOG_DIR'], 'restore')
setupLogging('vcenter-restore', logMechanism='file', logDir=log_dir)

str_err = lambda err: err.getErrorInfo().detail[0].l10nMsg.translate()


def log_and_print(msg, err=False):
    '''
    Helper function to print output on screen and write to logs.
    '''
    msg = str(msg)
    print msg if not err else 'ERROR: ' + msg
    logging.info(msg) if not err else logging.error(msg)


def get_input(msg, passwd=False, retry=3):
    '''
    Obtains the username and password from command prompt.
    Prompts for username/password for 'retry' times before giving up.
    '''
    disp_msg = 'Please enter %s: ' % msg
    for i in range(0, retry):
        inp = getpass.getpass(disp_msg) if passwd else raw_input(disp_msg)
        if inp:
            return inp
    else:
        log_and_print('Failed to obtain %s. Exiting Restore.' % msg,
                      err=True)
        sys.exit(1)


def parse_args():
    parser = argparse.ArgumentParser(
        description='Restore a failed management node.')
    parser.add_argument('-u', '--username', required=False,
                        dest='username', help='SSO Admin Username. '
                        'Will be prompted if not provided. '
                        '(Ex: username@local.domain)')
    parser.add_argument('-p', '--password', required=False,
                        dest='password', help='SSO Admin Password. '
                        'Will be prompted if not provided.')
    args = parser.parse_args()
    username = args.username
    password = args.password
    if not username:
        msg = 'SSO Admin username'
        args.username = get_input(msg)
    if not password:
        msg = 'SSO Admin Password'
        args.password = get_input(msg, passwd=True)
    return args


def activate_service(svc_name):
    '''
    Helper method to unmask a masked service.
    '''
    if osIsSystemd:
        command = ['systemctl', 'unmask', svc_name]
        invoke_command(command, quiet=False)


def svc_ctrl_op(op, svc=None, profile='ALL'):
    '''
    Helper function that starts/stops a given service.
    If no service is provided, performs the op on 'all' services.
    '''
    cis_home = get_cis_install_dir()
    svc_ctrl_path = def_by_os('/bin/service-control',
                              cis_home + '/bin/service-control.bat')
    svc_ctrl_cmd = [os.path.normpath(svc_ctrl_path)]
    svc_ctrl_cmd.append('--%s' % op)
    if os.name != "posix":
        svc_ctrl_cmd.append('--all' if svc is None else svc)
    elif svc is not None:
        svc_ctrl_cmd.append(svc)
    else:
        svc_ctrl_cmd.extend(
            ['--all', '--vmon-profile', profile])

    invoke_command(svc_ctrl_cmd, quiet=False)


def reset_machine_password(sso_username, sso_password, repl_partner=None):
    '''
    Resets the machine account password in lotus. Assumes that
    vmafd and vmdir services are running.
    '''
    log_and_print('Resetting machine account password in lotus..')
    vmafd_home = get_component_home_dir(def_by_os('vmafd', 'vmafdd'))
    dir_cli = def_by_os(os.path.join(vmafd_home, 'bin', 'dir-cli'),
                        os.path.join(vmafd_home, 'dir-cli.exe'))
    dir_cli_cmd = [os.path.normpath(dir_cli), 'computer', 'password-reset',
                   '--login', sso_username, '--password', sso_password]
    if repl_partner is not None:
        dir_cli_cmd.extend(['--live-dc-hostname', repl_partner])

    invoke_command(dir_cli_cmd, quiet=True)


def restore_mgmt_node(args):
    '''
    Main logic to restore a management node. Workflow:
      - Start vmafd service.
      - Reset the machine account password in lotus.
    '''
    # Resetting machine password requires vmafd to be up.
    if os.name != 'posix':
        log_and_print('Starting vmware-cis-config service..')
        svc_ctrl_op('start', svc='vmware-cis-config')
    log_and_print('Starting vmafd service..')
    svc_ctrl_op('start', svc=def_by_os('vmafdd', 'VMWareAfdService'))

    reset_machine_password(args.username, args.password)


def main():
    args = parse_args()
    try:
        deployment_type = get_deployment_nodetype()
        if deployment_type != 'management':
            log_and_print('Restore of %s node is not supported via this '
                          'script. Exiting.' % deployment_type)
            sys.exit(0)

        # Ensure that all vmon services are stopped in non-vcha scenario.
        # Ensure that all services except vmon, vmafdd, vcha and statsmonitor
        # are stopped in a vcha system
        log_and_print('Stopping services..')
        svc_ctrl_op('stop', profile='HAActive')

        restore_mgmt_node(args)

        # Start remaining services.
        if os.name == 'posix':
            # Reset vmware-vmon service start type to AUTO
            log_and_print('Changing vmware-vmon service start type to AUTO..')
            update_services_startuptype('start', StartType.AUTO, False,
                                        False, False, svc_names=['vmware-vmon'])

        log_and_print('Starting remaining services..')
        svc_ctrl_op('start', profile='ALL')
        log_and_print('Successfully started remaining services.')
        log_and_print('Restore Complete.')
        sys.exit(0)
    except (SetServiceStartTypeException, ServiceNotFoundException) as e:
        log_and_print('Failed to change start type of vmware-vmon service '
                      'to AUTO.\nError: %s' % str_err(e), err=True)
    except InvokeCommandException as e:
        log_and_print('Failed to invoke command.\nError: %s' %
                      str_err(e), err=True)
    except Exception as e:
        log_and_print(e, err=True)

    log_and_print('Operation Failed. Please make sure the SSO username and '
                  'password are correct and rerun the script.\n'
                  'If problem persists, contact VMware support.')
    sys.exit(1)


# This script should be executed as main.
if __name__ == '__main__':
    main()
