# Copyright 2020-2021 VMware, Inc. All rights reserved. -- VMware Confidential

"""
Utils to modify the /etc/vmware-vpx/vcdb.properties file.
"""

import logging
import os
import shutil
import stat
import sys
import uuid
from urllib.parse import urlparse, parse_qs, ParseResult
from collections import OrderedDict


logger = logging.getLogger(__name__)


VCDB_PROPERTIES_FILE = "/etc/vmware-vpx/vcdb.properties"
EQUAL = "="
PROP_SEPARATOR = "&"
SSL_MODE = "sslmode"
SSL_DISABLE = "disable"
URL_KEY = "url"
DB_TYPE_KEY = "dbtype"


def is_append_required_to_jdbc_url(url_str):
    result = urlparse(url_str)
    if result.query == "":
        return True
    # Check whether sslmode=disable string is present.
    if result.query.find(SSL_MODE + EQUAL + SSL_DISABLE) < 0:
        return True
    return False


def append_property_to_jdbc_url(url_str):
    """
    Parse the jdbc url to extract the query from the url and convert the query
    to dictionary. Get the sslmode key value pairs and replace this key value
    with sslmode=disable in query string.
    Example: This method will update the url
    jdbc:postgresql://localhost:5432/VCDB to
    jdbc:postgresql://localhost:5432/VCDB?sslmode=disable or url
    jdbc:postgresql://localhost:5432/VCDB?sslmode=verify&ssl to
    jdbc:postgresql://localhost:5432/VCDB?sslmode=disable&ssl
    """
    parse_result = urlparse(url_str)
    queryStr = parse_result.query
    query_result = parse_qs(parse_result.query)
    if query_result.get(SSL_MODE) == None:
        if len(queryStr) == 0:
            queryStr += SSL_MODE + EQUAL + SSL_DISABLE
        else:
            queryStr += PROP_SEPARATOR + SSL_MODE + EQUAL + SSL_DISABLE
    else:
        oldStr = SSL_MODE + EQUAL + query_result[SSL_MODE][0]
        newStr = SSL_MODE + EQUAL + SSL_DISABLE
        queryStr = queryStr.replace(oldStr, newStr)
    # Construct the updated url through ParseResult instance.
    url = ParseResult(parse_result.scheme, parse_result.netloc,
        parse_result.path, parse_result.params, queryStr, parse_result.fragment)
    return url.geturl()


def update_vcdb_properties(vcdb_prop_path=VCDB_PROPERTIES_FILE):
    """
    Updates the vcdb.properties file by appending the sslmode=disable property
    to jdbc url.
    """
    # Parse the vcdb.properties file to construct the OderedDict of properties.
    prop_dict = OrderedDict()
    separator = "="
    with open(vcdb_prop_path, 'r') as prop_file:
        for line in prop_file:
            if separator in line:
                name, value = line.split(separator, 1)
                # Assign key value pair to dict
                # strip() removes white space from the ends of strings
                prop_dict[name.strip()] = value.strip()
    db_type = prop_dict[DB_TYPE_KEY]
    jdbc_url = prop_dict[URL_KEY]
    file_update_needed = False
    if db_type == "PostgreSQL" and is_append_required_to_jdbc_url(jdbc_url):
        prop_dict[URL_KEY] = append_property_to_jdbc_url(jdbc_url)
        file_update_needed = True
    if file_update_needed:
        # Create new temp file with updated properties value and move it back
        # to vcdb.properties file.
        temp_file = vcdb_prop_path + str(uuid.uuid4())
        with open(temp_file, 'w') as configfile:
            for key, value in prop_dict.items():
                configfile.write(key + " " + EQUAL + " " + value + "\n")
            configfile.flush()
            os.fsync(configfile.fileno())
        # Get the owner and group of vcdb.properties file.
        vcdb_prop_file_stat = os.stat(vcdb_prop_path)
        # Copy permissions & last access details of vcdb.properties to temp
        # file.
        shutil.copystat(vcdb_prop_path, temp_file)
        # Copy owner and group to temp file.
        os.chown(temp_file, vcdb_prop_file_stat[stat.ST_UID],
                    vcdb_prop_file_stat[stat.ST_GID])
        shutil.move(temp_file, vcdb_prop_path)
        logger.info("Completed patching %s to append %s to %s in url",
                    vcdb_prop_path, SSL_MODE, SSL_DISABLE)
    return file_update_needed
