#!/usr/bin/env python
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
# 
#   http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

import os
import sys
import re
import commands
from optparse import Option, OptionParser
from hawqpylib.hawqlib import HawqXMLParser, parse_hosts_file, check_file_exist_list
from gppylib.db import dbconn
from pygresql.pg import DatabaseError
from gppylib.gplog import get_default_logger, setup_hawq_tool_logging, quiet_stdout_logging, enable_verbose_logging
from gppylib.commands.unix import getLocalHostname, getUserName


def parseargs():
    parser = OptionParser(usage="HAWQ state options.")
    parser.add_option('-b', default=False, action='store_true', dest='show_brief_status',
                      help="Show brief status of cluster.")
    parser.add_option('-q', '--quiet', action='store_true', default=False)
    parser.add_option('-v', '--verbose', action='store_true', default=False)
    parser.add_option("-a", "--prompt", action="store_false",
                      dest="prompt", default=True,
                      help="Execute without prompt.")
    parser.add_option("-l", "--logdir", dest="logDir",
                      help="Sets the directory for log files")
    # None used option, keep it to be compatible with Ambari.
    parser.add_option("-d", "--datadir", dest="master_dir",
                      help="Sets HAWQ Master data directory.")
    (options, args) = parser.parse_args()
    return (options, args)


def check_status(status_value):
    if status_value == 'u':
        status_tag = 'Active'
    elif status_value == 'd':
        status_tag = 'Down'
    else:
        status_tag = 'Unknown'
    return status_tag

def get_guc_value(guc):
    try:
        master_host_name = hawq_site.hawq_dict['hawq_master_address_host']
        master_port_num = hawq_site.hawq_dict['hawq_master_address_port']
        dburl = dbconn.DbURL(hostname=master_host_name, port=master_port_num, dbname='template1')
        conn = dbconn.connect(dburl, True)
        query = "select name, setting from pg_catalog.pg_settings where name='%s';" % guc
        rows = dbconn.execSQL(conn, query)
        conn.close()
    except DatabaseError, ex:
        print "Failed to connect to database, this script can only be run when the database is up."
        sys.exit(1)
    for row in rows:
        if row[0] == guc:
            return row[1]

def check_rps_status(master_or_standby):
    hawq_rps_address_host = get_guc_value(master_or_standby)
    hawq_rps_address_port = get_guc_value("hawq_rps_address_port")
    hawq_rps_address_suffix = "rps"
    params = ["curl --connect-timeout 2 http://", hawq_rps_address_host.strip(), ":", hawq_rps_address_port.strip(), "/", hawq_rps_address_suffix.strip(), "/version"]
    check_cmd = ''.join(params)
    status, output = commands.getstatusoutput(check_cmd)
    pattern1 = re.compile("\"version\":\"\d\.\d\.\d\.\d\"")
    pattern2 = re.compile("Connection refused")
    if pattern1.search(output):
        status = 'Active'
    elif pattern2.search(output):
        status = 'Down'
    else:
        status = 'Unknown'
    return status

def show_brief_status(hawq_site, segment_list, standby_host):
    try:
        master_host_name = hawq_site.hawq_dict['hawq_master_address_host']
        master_port_num = hawq_site.hawq_dict['hawq_master_address_port']
        dburl = dbconn.DbURL(hostname=master_host_name, port=master_port_num, dbname='template1')
        conn = dbconn.connect(dburl, True)
        query = "select role, status, port, hostname, address from gp_segment_configuration;"
        rows = dbconn.execSQL(conn, query)
        conn.close()
    except DatabaseError, ex:
        print "Failed to connect to database, this script can only be run when the database is up."
        sys.exit(1)
    seg_host_list = {}
    valid_seg_host_list = {}
    master_status = ''
    standby_status = ''
    for row in rows:
        if row[0] == 'm':
            master_host = row[3]
            master_status = check_status(row[1])
        elif row[0] == 's':
            standby_host = row[3]
            if row[1] == "u":
                standby_status = "Standby host passive"
            else:
                standby_status = "Unknown"
        elif row[0] == 'p':
            seg_host_list[row[3]] = row[1]
            if row[1] == 'u':
                valid_seg_host_list[row[3]] = row[1]

    total_seg_num = len(segment_list)
    total_seg_num_from_catalog = len(seg_host_list)
    total_seg_num_valid = len(valid_seg_host_list)
    total_seg_num_failure = total_seg_num - total_seg_num_valid
    seg_pid_file_path = hawq_site.hawq_dict['hawq_segment_directory'] + "/postmaster.pid"
    total_seg_pid_file_found = len(check_file_exist_list(seg_pid_file_path, segment_list, '' ))
    total_seg_pid_file_miss = total_seg_num - total_seg_pid_file_found
    hawq_acl_type = "standalone"
    if 'hawq_acl_type' in hawq_site.hawq_dict:
        hawq_acl_type = hawq_site.hawq_dict['hawq_acl_type']
    logger.info("- HAWQ instance status summary")
    logger.info("-----------------------------------------------------")
    logger.info("-   Master instance                                = %s" % master_status)
    if 'hawq_standby_address_host' in hawq_site.hawq_dict:
        logger.info("-   Master standby                                 = %s" % standby_host)
        logger.info("-   Standby master state                           = %s" % standby_status)
    else:
        logger.info("-   No Standby master defined                           ")
    logger.info("-   Total segment instance count from config file  = %s"% total_seg_num)
    logger.info("-----------------------------------------------------")
    logger.info("-   Current HAWQ acl type                          = %s" % hawq_acl_type)
    if hawq_acl_type == "ranger":
        hawq_master_rps_status = check_rps_status('hawq_master_address_host')
        logger.info("-   HAWQ master Ranger plugin service state        = %s" % hawq_master_rps_status)
        if 'hawq_standby_address_host' in hawq_site.hawq_dict:
            hawq_standby_rps_status = check_rps_status('hawq_standby_address_host')
            logger.info("-   HAWQ standby Ranger plugin service state       = %s" % hawq_standby_rps_status)
    logger.info("----------------------------------------------------- ")
    logger.info("-   Segment Status                                    ")
    logger.info("----------------------------------------------------- ")
    logger.info("-   Total segments count from catalog      = %s" % total_seg_num_from_catalog)
    logger.info("-   Total segment valid (at master)        = %s" % total_seg_num_valid)
    logger.info("-   Total segment failures (at master)     = %s" % total_seg_num_failure)
    logger.info("-   Total number of postmaster.pid files missing   = %s" % total_seg_pid_file_miss)
    logger.info("-   Total number of postmaster.pid files found     = %s" % total_seg_pid_file_found)
    #logger.info("-   Total number of postmaster.pid PIDs missing    = %s" % total_seg_pid_miss)
    #logger.info("-   Total number of postmaster.pid PIDs found      = %s" % total_seg_pid_found)
    #logger.info("-   Total number of /tmp lock files missing        = %s" % total_seg_lock_file_miss)
    #logger.info("-   Total number of /tmp lock files found          = %s" % total_seg_lock_file_found)
    #logger.info("-   Total number postmaster processes missing      = %s" % total_seg_process_miss)
    #logger.info("-   Total number postmaster processes found        = %s" % total_seg_process_found)
    #logger.info("----------------------------------------------------- ")

if __name__ == '__main__':
    options, args = parseargs()

    if options.verbose and options.quiet:
        print "Multiple actions specified.  See the --help info."
        sys.exit(1)

    if options.verbose:
        enable_verbose_logging()
    if options.quiet:
        quiet_stdout_logging()

    logger, log_filename = setup_hawq_tool_logging('hawq_state',getLocalHostname(),getUserName(), options.logDir) 

    GPHOME = os.getenv('GPHOME')
    if not GPHOME:
        sys.exit("GPHOME environment variable not set, exit")

    hawq_site = HawqXMLParser(GPHOME)
    hawq_site.get_all_values()
    segment_list = parse_hosts_file(GPHOME)
    master_host = hawq_site.hawq_dict['hawq_master_address_host']
    host_list = segment_list + [master_host]
    if 'hawq_standby_address_host' in hawq_site.hawq_dict:
        standby_host = hawq_site.hawq_dict['hawq_standby_address_host']
        if standby_host not in ('None', 'none', ''):
            host_list = host_list + [standby_host]

    if options.show_brief_status:
        show_brief_status(hawq_site, segment_list, standby_host="None") 
    else:
        show_brief_status(hawq_site, segment_list, standby_host="None")
