#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 Red Hat, Inc.
#
# 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., 51 Franklin Street, Fifth Floor, Boston,
# MA  02110-1301, USA.  A copy of the GNU General Public License is
# also available at http://www.gnu.org/copyleft/gpl.html.
import socket
import sys
import logging

from distutils.util import strtobool

import ovirtnode.ovirtfunctions as _functions

from ovirt.node import valid
from ovirt.node.config.defaults import SSH
from ovirt.node.utils import system, process
from ovirt.node.config.defaults import NodeConfigFileSection

from ovirt.node.setup.vdsm.engine_page import RegistrationTriggered, \
    NodeManagement

from systemd import journal


class PwdSetToEngineInstall(NodeConfigFileSection):
    """
    Return OVIRT_ENGINE_PWD_SET value from /etc/default/ovirt
    via retrieve() or update this value via update() if
    registration was triggered
    """
    keys = ("OVIRT_ENGINE_ADMIN_PWD_SET",)

    @NodeConfigFileSection.map_and_update_defaults_decorator
    def update(self, engine_pwd_set):
        valid.Boolean()(engine_pwd_set)
        return {"OVIRT_ENGINE_ADMIN_PWD_SET": "True"
                if engine_pwd_set else None}

    def retrieve(self):
        cfg = dict(NodeConfigFileSection.retrieve(self))
        try:
            if cfg['engine_pwd_set'] is not None:
                return strtobool(cfg['engine_pwd_set'])
        except ValueError:
            LOGGER.error("OVIRT_ENGINE_ADMIN_PWD_SET must be a bool!")

        return False


def _set_logger():
    """
    Set the logging schema
    """
    log = logging.getLogger(__name__)
    log.propagate = False
    log.setLevel(logging.DEBUG)
    formatter = logging.Formatter("%(message)s")
    jhandler = journal.JournalHandler()
    jhandler.setLevel(logging.DEBUG)
    jhandler.setFormatter(formatter)
    log.addHandler(jhandler)

    return log

LOGGER = _set_logger()


def get_kargs():
    """
    Find in the boot kernel arguments from /var/log/messages,
    the autoinstall keys that start with "management_"

    Return a dict with the keys
    """
    kargs = {}
    key_word_karg = "Command line"
    with open('/var/log/messages', 'r') as f:
        for line in f:
            if key_word_karg in line and "management_server" in line:
                kargs = system.kernel_cmdline_arguments(
                    line.split(key_word_karg)[1]
                )
                break

    return kargs


def enable_ssh_set_root(root_pwd):
    """
    Check if keys: rhevm_admin_password or engine_admin_password is set
    if it's present, set root passwd and enable SSH daemon

    Note: To generate password to use with rhevm_admin_password and
          engine_admin_password you must execute:
             $ openssl passwd -salt SALT or openssl passwd -1
    """
    _functions.unmount_config("/etc/shadow")
    _functions.unmount_config("/etc/passwd")

    process.call(["/usr/sbin/usermod", "-p", root_pwd, "root"])
    process.call(["chage", "-E", "-1", "root"])

    LOGGER.info("autoinstall: Password updated for user root!")

    # Enable SSHD
    SSH().update(pwauth=True)
    SSH().commit()
    LOGGER.info("autoinstall: SSH Enabled!")


def main():
    LOGGER.info("=======================================")
    LOGGER.info("Auto-Registering the node")
    LOGGER.info("=======================================")

    # For autoinstall using check-fqdn = False as previous autoinstall
    # doesn't check CA cert
    reg_tool_cmd = ['vdsm-tool', 'register', '--check-fqdn', 'False',
                    '--node-name', socket.gethostname()]
    node = NodeManagement().retrieve()

    kargs = get_kargs()
    pwdset = PwdSetToEngineInstall().retrieve()
    if 'engine_admin_password' in kargs and not pwdset:
        enable_ssh_set_root(kargs['engine_admin_password'])
        PwdSetToEngineInstall().update(True)

    if 'rhevm_admin_password' in kargs and not pwdset:
        enable_ssh_set_root(kargs['rhevm_admin_password'])
        PwdSetToEngineInstall().update(True)

    if not RegistrationTriggered().retrieve():
        LOGGER.info("OVIRT_NODE_REGISTER is NOT set, "
                    "starting auto-register..")

        if not node['mserver']:
            LOGGER.info(
                "autoinstall: management_server must be set!"
            )
            return 0
    else:
        LOGGER.info(
            "No need to auto-register, OVIRT_NODE_REGISTER is set!"
        )
        return 0

    reg_tool_cmd.extend(['--engine-fqdn', node['mserver']])

    if node['mport']:
        reg_tool_cmd.extend(['--engine-https-port', node['mport']])

    if node['fprint']:
        reg_tool_cmd.extend(['--fingerprint', node['fprint']])

    LOGGER.info("autoinstall: register command")
    LOGGER.info("{c}".format(c=reg_tool_cmd))

    ret = process.call(reg_tool_cmd)
    if ret != 0:
        raise RuntimeError("autoinstall: register FAILED!")

    # Registration triggered with success, set OVIRT_NODE_REGISTER
    RegistrationTriggered().update(True)
    LOGGER.info("== autoinstall successfully finished ==")

    return 0

if __name__ == "__main__":
    sys.exit(main())
