#!/usr/bin/env python

#
# Copyright 2019 VMware, Inc.  All rights reserved. -- VMware Confidential
#
"""
Patch script that does the following:
Add gRPC endpoints for Trust Management
Add machine solution user to SyncUsers group

"""
import logging
import os
import re
import sys
import warnings

vmware_python_path = os.getenv('VMWARE_PYTHON_PATH')
if vmware_python_path and os.path.exists(vmware_python_path):
    sys.path.append(vmware_python_path)

from cis.cisreglib import LookupServiceClient, SsoClient, VmafdClient, _get_syscfg_info
from cis.utils import run_command
from cis.vecs import SsoGroup, cli_path, vmafd_machine_id
import cis.cisreglib as crlib
from fss_utils import getTargetFSS

logger = logging.getLogger(__name__)

# Suppress warnings coming from vmafd and identity imports.
with warnings.catch_warnings():
    warnings.simplefilter('ignore', RuntimeWarning)
    import vmafdpy3
    from identity.vmkeystore import VmKeyStore

TM_PRODUCT_ID = 'com.vmware.trustmanagement'
TM_TYPE_ID = 'trustmanagement'
MACHINE_NAME = 'machine'
# PATCH_VERSION = '3'
COMPONENT_NAME = 'trustmanagement'
SYNC_PROPERTY_NAME = 'Syncable'
SYNC_PROPERTY_VALUE = 'ELM,SPOG'
GRPC_ENDPOINT_PROTOCOL = 'gRPC'
GRPC_ENDPOINT_PORT = 4000
SUBSCRIBABLE_ATTRIBUTE_NAME = 'Subscribable'
SUBSCRIBABLE_ATTRIBUTE_TRUE_VALUE = 'true'

SYNC_SSO_GROUP = 'SyncUsers'
MACHINE_SOLUTION_USER = "machine"

def doPatching(ctx):
    if getTargetFSS("HybridVC_SyncaaS"):
        logger.info("TrustManagement patch: being executed %s", ctx)
        logger.info("Updating grpc endpoint.")
        update_endpoints()
    logger.info("Adding machine solution user to SyncUsers group")
    add_machine_solution_user_to_sync_users()

def get_config_dir():
    return '/usr/lib/vmware-%s/config' % COMPONENT_NAME


def update_endpoints():

    logger.info("Connecting to Lookup Service")
    ls_url, domain_name = _get_syscfg_info()
    ls_obj = LookupServiceClient(ls_url, retry_count=5)
    logger.info("Getting STS endpoint")
    sts_url, sts_cert_data = ls_obj.get_sts_endpoint_data()

    logger.info("Logging into SSO AdminClient as machine solution user")
    cert = None
    key = None

    try:
        with VmKeyStore('VKS') as ks:
            ks.load(MACHINE_NAME)
            cert = ks.get_certificate(MACHINE_NAME)
            key = ks.get_key(MACHINE_NAME)

        sso_client = SsoClient(sts_url, sts_cert_data, None, None, cert=cert,
                               key=key)
        ls_obj.set_sso_client(sso_client)

        logger.info("Fetching service Info for the Trustmanagement from Lookup Service")
        tm_service_info = ls_obj.get_local_service_info(TM_PRODUCT_ID, TM_TYPE_ID)

        # Get the service info in the format the reregister API accepts
        service_info = ls_obj.service_content.serviceRegistration.Get(tm_service_info.serviceId)
        mutable_spec = ls_obj._svcinfo_to_setspec(service_info)


        logger.info("Adding Endpoint and Syncable property to Trustmanagement")
        addSyncableAttribute(mutable_spec)
        logger.info("Adding Subscribable  property to Trustmanagement")
        addSubscribableAttribute(mutable_spec)
        addGrpcEndpoint(mutable_spec)
        ls_obj.reregister_service(service_info.serviceId, mutable_spec)

        sso_client.cleanup()
    except BaseException as e:
        logger.error("Failed to reregister TrustManagement with Lookup Service")
        raise e

def addSyncableAttribute(mutable_spec):
    attribute = crlib.lookup.ServiceRegistration.Attribute()
    attribute.key = SYNC_PROPERTY_NAME
    attribute.value = SYNC_PROPERTY_VALUE
    mutable_spec.serviceAttributes.append(attribute)

def addSubscribableAttribute(mutable_spec):
    subscribablAttribute = crlib.lookup.ServiceRegistration.Attribute()
    subscribablAttribute.key = SUBSCRIBABLE_ATTRIBUTE_NAME
    subscribablAttribute.value = SUBSCRIBABLE_ATTRIBUTE_TRUE_VALUE
    mutable_spec.serviceAttributes.append(subscribablAttribute)

def addGrpcEndpoint(mutable_spec):
    endpoint = crlib.lookup.ServiceRegistration.Endpoint()

    vmafd_client = VmafdClient()
    endpoint_url = 'https://' + vmafd_client.get_pnid() + ':'  + str(GRPC_ENDPOINT_PORT)
    logger.info("Endpoint Url for gRPC endpoint: " + endpoint_url)
    endpoint.url = endpoint_url

    endpoint_type = crlib.lookup.ServiceRegistration.EndpointType()
    endpoint_type.protocol = GRPC_ENDPOINT_PROTOCOL
    endpoint_type.type = TM_TYPE_ID
    endpoint.endpointType = endpoint_type
    endpoint.sslTrust = mutable_spec.serviceEndpoints[0].sslTrust

    mutable_spec.serviceEndpoints.append(endpoint)

def add_machine_solution_user_to_sync_users():
    if sync_users_group_exists():
        vmafdClient = vmafdpy3.client('localhost')
        username = vmafdClient.GetMachineName()
        password = vmafdClient.GetMachinePassword()
        machine_id = vmafd_machine_id()
        solution_user_id = '%s-%s' % (MACHINE_SOLUTION_USER, machine_id)
        logger.info("Logging into SSO Admin")
        sso_group = SsoGroup(username, password)
        logger.info("Adding %s to %s" % (solution_user_id, SYNC_SSO_GROUP))
        sso_group.add_user(SYNC_SSO_GROUP, solution_user_id)

def sync_users_group_exists():
    vmafdClient = vmafdpy3.client('localhost')
    username = vmafdClient.GetMachineName()
    password = vmafdClient.GetMachinePassword()
    cli = cli_path('dir-cli')
    cmd = [cli, 'group', 'list', '--name', 'SyncUsers', '--login', username]
    ret, _, stderr = run_command(cmd, stdin=password,
                                     encoding=sys.getfilesystemencoding())
    if ret == 0:
        logger.info("SyncUsers sso group exists")
        return True
    else:
        logger.info("SyncUsers sso group does not exists.")
        return False
