#########################################################################
#
#   Copyright 2018-2019 VMware, Inc.
#   All rights reserved. VMware Confidential
#
#########################################################################
from cis.defaults import get_cis_tmp_dir
from cis.vecs import VecsEntry
from cis.utils import read_properties
from logging import getLogger

from os import environ
from subprocess import check_call, check_output
from tempfile import NamedTemporaryFile

_log = getLogger(__name__)
EAM_PROPERTIES_FILE = '/etc/vmware-eam/eam-vim.properties'
TRUSTED_ROOTS = 'TRUSTED_ROOTS'
VPXD_STORE_NAME = "MACHINE_SSL_CERT"
VPXD_ALIAS = "__MACHINE_CERT"
EAM_VC_PROXY_PORT = 'vc.proxy.port'
# We need the user domain in order to authenticate to vCenter
# with full 'username@domain'
OBTAIN_USER_DOMAIN = ('/usr/lib/vmware-vmafd/bin/vmafd-cli',
                      'get-domain-name',
                      '--server-name',
                      'localhost')
VPXD_CERT_ARG = "--vpxdCert={}"
VPXD_KEY_ARG = "--vpxdPrivateKey={}"
VCVA_CERT_ARG = "--vcCACert={}"
UPDATE_EXTENSION_TEMPLATE = (
    "/usr/lib/vmware-eam/firstboot/eaminstall/extensionOps.py",
    "--update","-i","localhost",
    "-v","vim.version.version12",
    "--extDescr=/etc/vmware-eam/firstboot/extension/",
    "-p"
)


def run(ctx):
   """
   Special patch for updating EAM extension.
   Updates EAM extension with latest build, version and localization
   information.

   :param: ctx : B2B context
   :type: ctx : PatchContext, B2B specific structure, please refer to B2B
                documentation.
   """
   _log.info('Updating EAM extension..')
   _log.info('Received user data for: {}'.format(ctx.userData.keys()))
   try:
      vecs = VecsEntry(TRUSTED_ROOTS)
      caCertOutPutFile = _obtainCaCertFile(vecs)
      port = _obtainReverseProxyHttpPort()
      localOsEnv = _prepareLocalOsEnv()
      vecsVpxdExt = VecsEntry(VPXD_STORE_NAME)
      vpxdExtCert = _getVpxdCert(vecsVpxdExt)
      vpxdPrivateKey = _getVpxdPrivateKey(vecsVpxdExt)
      updateEamExtensionExecutable = _composeEamExtensionCommand(
         ctx,
         port,
         vpxdExtCert,
         vpxdPrivateKey,
         caCertOutPutFile
      )
      _log.info(
         'Executing update extension API call: {}'.format(
             str(_composeEamExtensionCommand(
                 ctx,
                 port,
                 vpxdExtCert,
                 vpxdPrivateKey,
                 caCertOutPutFile
             ))
         )
      )
      check_call(updateEamExtensionExecutable, env=localOsEnv)
      _log.info('EAM extension updated successfully.')
   except Exception as e:
      _log.error('EAM extension update failed', e)
      raise e


def _composeEamExtensionCommand(ctx, port, vpxdExtCert, vpxdPrivateKey,
                                caCertOutPutFile):
      return UPDATE_EXTENSION_TEMPLATE + (
         str(port),
         VPXD_CERT_ARG.format(vpxdExtCert),
         VPXD_KEY_ARG.format(vpxdPrivateKey),
         VCVA_CERT_ARG.format(caCertOutPutFile)
       )


def _obtainReverseProxyHttpPort():
    props = read_properties(EAM_PROPERTIES_FILE, EAM_VC_PROXY_PORT)
    _log.debug(
       'Obtained following properties from EAM properties file: {}'.format(props)
    )
    port = props[EAM_VC_PROXY_PORT]
    _log.info('vCenter proxy port: {}'.format(port))
    return port


def _prepareLocalOsEnv():
   localOsEnv = environ.copy()
   localOsEnv["PYTHONPATH"] = localOsEnv["VMWARE_PYTHON_PATH"]
   return localOsEnv


def _obtainCaCertFile(vecs):
   _log.info('Obtaining vCenter CA certs.')
   caAliases = vecs.list()
   certFiles = tuple(_getCert(vecs, certAlias) for certAlias in caAliases)
   caTrust = ''.join(_readFile(certFile) for certFile in certFiles)

   caCertOutPutFile = _tempFile()
   with open(caCertOutPutFile, 'w') as fout:
      fout.write(caTrust)
   _log.info('Obtained vCenter CA certs successfully.')
   return caCertOutPutFile


def _getVpxdPrivateKey(vecs):
   _log.info('Obtaining VPXD private key.')
   keyFile = _tempFile()
   vecs.get_key(VPXD_ALIAS, keyFile)
   _log.info('Obtained VPXD private key successfully.')
   return keyFile


def _getVpxdCert(vecs):
   _log.info('Obtaining VPXD Extension certificate.')
   certFile = _tempFile()
   vecs.get_cert(VPXD_ALIAS, certFile)
   _log.info('Obtained VPXD Extension certificate successfully.')
   return certFile


def _getCert(certStore, certAlias):
   certFile = _tempFile()
   certStore.get_cert(certAlias, certFile)
   return certFile


def _readFile(filePath):
   with open(filePath, 'r') as f:
      return f.read()


def _tempFile():
   tmp_file = NamedTemporaryFile(dir=get_cis_tmp_dir(), delete=True)
   tmp_file.close()
   return tmp_file.name
