# Copyright (C) 2012-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.
from __future__ import absolute_import
import argparse
import getpass
import hashlib
import logging
import os
import pwd
import ssl
import sys
import tempfile

import requests
import selinux

from . import expose
from .. import utils

from vdsm.utils import getHostUUID, tobool


class Register(object):

    def __init__(self, engine_fqdn, engine_https_port=None,
                 fingerprint=None, ssh_port=None,
                 ssh_user=None, check_fqdn=True,
                 vdsm_port=None, node_address=None,
                 vdsm_uuid=None, node_name=None):
        """
        Attributes:

        engine_fqdn       - Engine FQDN or IP address
        engine_https_port - Engine https port
        fingeprint        - Fingerprint to be validated
        ssh_user          - SSH user that will establish the connection
                            from Engine
        ssh_port          - Port of ssh daemon is running
        check_fqdn        - Validate Engine FQDN against CA (True or False)
                            Default is TRUE
        vdsm_port         - VDSM listen port
        node_address      - Specify node address or FQDN
        node_name         - Specify node name
        vdsm_uuid         - Provide host UUID to be used instead vdsm.utils.
                            Useful for hosts with blank or buggy DMI
        """
        self.logger = self._set_logger()
        self.logger.debug("=======================================")
        self.logger.debug("Registering the node")
        self.logger.debug("=======================================")
        self.logger.debug("Received the following attributes:")

        self.engine_fqdn = engine_fqdn
        self.logger.debug("Engine FQDN: {fqdn}".format(fqdn=self.engine_fqdn))

        self.engine_url = "https://{e}".format(e=engine_fqdn)
        if engine_https_port is None:
            self.engine_port = "443"
        else:
            self.engine_port = engine_https_port
            self.engine_url = "https://{e}:{p}".format(e=self.engine_fqdn,
                                                       p=self.engine_port)

        self.logger.debug("Engine URL: {url}".format(url=self.engine_url))
        self.logger.debug("Engine https port: {hp}".format(
                          hp=self.engine_port))

        if check_fqdn is None:
            self.check_fqdn = True
        else:
            self.check_fqdn = tobool(check_fqdn)
        self.logger.debug("Check FQDN: {v}".format(v=self.check_fqdn))

        self.fprint = fingerprint
        self.logger.debug("Fingerprint: {fp}".format(fp=self.fprint))

        self.node_address = node_address
        self.logger.debug("Node address: {nf}".format(nf=self.node_address))

        self.node_name = node_name
        self.logger.debug("Node name: {na}".format(na=self.node_name))

        if ssh_user is None:
            self.ssh_user = getpass.getuser()
        else:
            self.ssh_user = ssh_user
        self.logger.debug("SSH User: {su}".format(su=self.ssh_user))

        if ssh_port is None:
            self.ssh_port = "22"
        else:
            self.ssh_port = ssh_port
        self.logger.debug("SSH Port: {sp}".format(sp=self.ssh_port))

        if vdsm_port is None:
            self.vdsm_port = "54321"
        else:
            self.vdsm_port = vdsm_port
        self.logger.debug("VDSM Port: {sp}".format(sp=self.vdsm_port))

        self.vdsm_uuid = vdsm_uuid
        self.logger.debug("VDSM UUID: {uuid_provided}".format(
                          uuid_provided=self
.vdsm_uuid))

        self.ca_dir = "/etc/pki/ovirt-engine/"
        self.ca_engine = "{d}{f}".format(d=self.ca_dir, f="ca.pem")
        self.logger.debug("Engine CA: {ca}".format(ca=self.ca_engine))

    def handshake(self):
        """
        Initial communication with Engine to validate
        th
e registration.
        """

        self.logger.info("Starting registration...")

        ucmd = "/ovirt-engine/services/host-register?version=1&command="
        __GET_VERSION = "https://{e}{u}{c}".format(e=self.engine_fqdn,
                                                   u=ucmd,
                                                   c="get-version")

        self.logger.debug("Get version via: {0}".format(__GET_VERSION))

        res = requests.get(__GET_VERSION, verify=False)
        if res.status_code != 200:
            raise RuntimeError("Cannot get registration version from Engine!")

        self.url_CA = "{e}{uc}{c}".format(e=self.engine_url,
                                          uc=ucmd,
                                          c="get-pki-trust")

        self.url_ssh_key = "{e}{uc}{c}".format(e=self.engine_url,
                                               uc=ucmd,
                                               c="get-ssh-trust")

        ureg = "{uc}register&sshUser={sshu}&" \
               "sshPort={sshp}&port={mp}".format(uc=ucmd,
                                                 sshu=self.ssh_user,
                                                 sshp=self.ssh_port,
                                                 mp=self.vdsm_port)

        if self.node_name is not None:
            ureg += "&name={name}".format(name=self.node_name)

        if self.node_address is not None:
            ureg += "&address={addr}".format(addr=self.node_address)

        self.url_reg = "{e}{u}".format(e=self.engine_url, u=ureg)

        self.logger.debug("Download CA via: {u}".format(u=self.url_CA))
        self.logger.debug("Download SSH via: {u}".format(u=self.url_ssh_key))

    def _set_logger(self):
        """
        The logging settings
        Saving log in: /var/log/vdsm/register.log
        """
        logger = logging.getLogger(__name__)
        logger.setLevel(logging.DEBUG)
        logger.propagate = False

        fh = logging.FileHandler("/var/log/vdsm/register.log")
        fh.setLevel(logging.DEBUG)
        debug_fmt = logging.Formatter("%(asctime)s %(message)s",
                                      "%m/%d/%Y %I:%M:%S %p")

        ih = logging.StreamHandler(stream=sys.stdout)
        ih.setLevel(logging.INFO)
        info_fmt = logging.Formatter("%(message)s",
                                     "%m/%d/%Y %I:%M:%S %p")

        fh.setFormatter(debug_fmt)
        ih.setFormatter(info_fmt)

        logger.addHandler(fh)
        logger.addHandler(ih)

        logging.captureWarnings(True)

        return logger

    def _execute_http_request(self, url, cert_validation=True):
        """
        Execute http requests
        url -- URL to be requested
        cert_validation -- SSL cert will be verified

        Returns: Content of http request
        """
        if self.check_fqdn:
            cert_validation = self.ca_engine
        else:
            cert_validation = False

        res = requests.get("{u}".format(u=url), verify=cert_validation)
        if res.status_code != 200:
            raise requests.RequestException(
                "http response was non OK, code {r}".format(r=res.status_code)
            )

        return res.content

    def _silent_restorecon(self, path):
        """
        Execute selinux restorecon cmd to determined file

        Args
        path -- full path to file
        """

        try:
            if selinux.is_selinux_enabled():
                selinux.restorecon(path)
        except:
            self.log