#!/bin/sh
""":"
for interp in python python2 ; do
   command -v > /dev/null "$interp" && exec "$interp" "$0" "$@"
done
echo >&2 "No Python interpreter found!"
exit 1
":"""
####
#
#  Copyright (c) 2008-2019 Aerospike, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
####
#
# A short utility program which pings a given host and requests the 'info' about
# either all names or a certain name
#
#

import os
import sys
from subprocess import Popen, PIPE

__version__ = '3.25.1'

DEFAULTPASSWORD="SomeRandomDefaultPassword"

def print_config_help():
    print ("\n")
    print ("Usage: asinfo [OPTIONS]")
    print ("---------------------------------------------------------------------------------------\n")

    print (" -V --version         Show the version of asinfo and exit")
    print (" -E --help            Show program usage.")
    print (" -v --value           Fetch single value (Default: all).")
    print (" -l --line-separator  Print in separate lines (Default: False).")
    print (" --timeout=value      Set timeout value in seconds. \n"
           "                      TLS connection does not support timeout. Default: 5 seconds")

    print_config_file_option()
    config_file_help()

def print_config_file_option():
	print ("\n")
	print ("Configuration File Allowed Options")
	print ("----------------------------------\n")
	print ("[cluster]")
	print (" -h HOST, --host=HOST\n"
           "                      HOST is \"<host1>[:<tlsname1>][:<port1>],...\" \n"
           "                      Server seed hostnames or IP addresses. The tlsname is \n"
           "                      only used when connecting with a secure TLS enabled \n"
           "                      server. Default: localhost:3000\n"
           "                      Examples:\n"
           "                        host1\n"
           "                        host1:3000,host2:3000\n"
           "                        192.168.1.10:cert1:3000,192.168.1.20:cert2:3000")
	print (" -p PORT, --port=PORT \n"
           "                      Server default port. Default: 3000")
	print (" -U USER, --user=USER \n"
           "                      User name used to authenticate with cluster. Default: none")
	print (" -P, --password\n"
           "                      Password used to authenticate with cluster. Default: none\n"
           "                      User will be prompted on command line if -P specified and no\n"
           "                      password is given.")
	print (" --auth=AUTHENTICATION_MODE \n"
           "                      Authentication mode. Values: ['EXTERNAL', 'EXTERNAL_INSECURE', 'INTERNAL'].\n"
           "                      Default: INTERNAL")
	print (" --tls-enable         Enable TLS on connections. By default TLS is disabled.")
	# Deprecated
	# print(" --tls-encrypt-only   Disable TLS certificate verification.\n")
	print (" --tls-cafile=TLS_CAFILE <path>\n"
           "                      Path to a trusted CA certificate file.")
	print (" --tls-capath=TLS_CAPATH <path>\n"
           "                      Path to a directory of trusted CA certificates.")
	print (" --tls-protocols=TLS_PROTOCOLS\n"
           "                      Set the TLS protocol selection criteria. This format\n"
           "                      is the same as Apache's SSLProtocol documented at http\n"
           "                      s://httpd.apache.org/docs/current/mod/mod_ssl.html#ssl\n"
           "                      protocol . If not specified the asinfo will use '-all\n"
           "                      +TLSv1.2' if has support for TLSv1.2,otherwise it will\n"
           "                      be '-all +TLSv1'.")
	print (" --tls-cipher-suite=TLS_CIPHER_SUITE\n"
           "                      Set the TLS cipher selection criteria. The format is\n"
           "                      the same as Open_sSL's Cipher List Format documented\n"
           "                      at https://www.openssl.org/docs/man1.0.1/apps/ciphers.\n"
           "                      html")
	print (" --tls-keyfile=TLS_KEYFILE <path>\n"
           "                      Path to the key for mutual authentication (if\n"
           "                      Aerospike Cluster is supporting it).")
	print (" --tls-keyfile-password=password\n"
           "                      Password to load protected tls-keyfile.\n"
           "                      It can be one of the following:\n"
           "                      1) Environment varaible: 'env:<VAR>'\n"
           "                      2) File: 'file:<PATH>'\n"
           "                      3) String: 'PASSWORD'\n"
           "                      Default: none\n"
           "                      User will be prompted on command line if --tls-keyfile-password specified and no\n"
           "                      password is given.")
	print (" --tls-certfile=TLS_CERTFILE <path>\n"
           "                      Path to the chain file for mutual authentication (if\n"
           "                      Aerospike Cluster is supporting it).")
	print (" --tls-cert-blacklist <path>\n"
           "                      Path to a certificate blacklist file. The file should\n"
           "                      contain one line for each blacklisted certificate.\n"
           "                      Each line starts with the certificate serial number\n"
           "                      expressed in hex. Each entry may optionally specify\n"
           "                      the issuer name of the certificate (serial numbers are\n"
           "                      only required to be unique per issuer).Example:\n"
           "                      867EC87482B2\n"
           "                      /C=US/ST=CA/O=Acme/OU=Engineering/CN=TestChainCA")

	print (" --tls-crl-check      Enable CRL checking for leaf certificate. An error\n"
	       "                      occurs if a valid CRL files cannot be found in\n"
           "                      tls_capath.")
	print (" --tls-crl-check-all  Enable CRL checking for entire certificate chain. An\n"
           "                      error occurs if a valid CRL files cannot be found in\n"
           "                      tls_capath.")
	print ("")

def config_file_help():
	print "\n\n"
	print ("Default configuration files are read from the following files in the given order:\n"
          "/etc/aerospike/astools.conf ~/.aerospike/astools.conf\n"
          "The following sections are read: (cluster include)\n"
          "The following options effect configuration file behavior\n")
	print (" --no-config-file\n"
           "                      Do not read any config file. Default: disabled")
	print (" --instance <name>\n"
           "                      Section with these instance is read. e.g in case instance \n"
           "                      `a` is specified section cluster_a is read.")
	print (" --config-file <path>\n"
           "                      Read this file after default configuration file.")
	print (" --only-config-file <path>\n"
           "                      Read only this configuration file.")
	print ("\n")

def get_cli_args():
	have_argparse = True
	try:
		import argparse
		parser = argparse.ArgumentParser(add_help=False, conflict_handler='resolve')
		add_fn = parser.add_argument
	except Exception:
		import optparse
		have_argparse = False
		usage = "usage: %prog [options]"
		parser = optparse.OptionParser(usage, add_help_option=False)
		add_fn = parser.add_option

	add_fn("-V", "--version", action="store_true")
	add_fn("-E", "--help", action="store_true")
	add_fn("-v", "--value")
	add_fn("-l", "--line-separator", dest="line-separator", action="store_true")

	add_fn("-h", "--host")
	add_fn("-p", "--port", type=int)
	add_fn("-U", "--user")
	if have_argparse:
		add_fn("-P", "--password", nargs="?")
	else:
		add_fn("-P", "--password", dest="password", action="store_const", const=DEFAULTPASSWORD)

	add_fn("--auth")
	add_fn("-t", "--tls-name")
	add_fn("--tls-enable", dest="tls-enable", action="store_true")
	add_fn("--tls-cafile", dest="tls-cafile")
	add_fn("--tls-capath", dest="tls-capath")
	add_fn("--tls-protocols", dest="tls-protocols")
	add_fn("--tls-cipher-suite", dest="tls-cipher-suite")
	add_fn("--tls-keyfile", dest="tls-keyfile")
	if have_argparse:
		add_fn("--tls-keyfile-password", nargs="?", dest="tls-keyfile-password", const=DEFAULTPASSWORD)
	else:
		parser.add_option("--tls-keyfile-password", dest="tls-keyfile-password", action="store_const", const=DEFAULTPASSWORD)
	add_fn("--tls-certfile", dest="tls-certfile")
	add_fn("--tls-cert-blacklist", dest="tls-cert-blacklist")
	add_fn("--tls-crl-check", dest="tls-crl-check", action="store_true")
	add_fn("--tls-crl-check-all", dest="tls-crl-check-all",  action="store_true")

	add_fn("--config-file", dest="config-file")
	add_fn("--instance")
	add_fn("--no-config-file", dest="no-config-file", action="store_true")
	add_fn("--only-config-file", dest="only-config-file")

	# Old style parameter with underscore
	# Todo: deprecate old style parameters
	add_fn("--tls_name")
	add_fn("--tls_enable", action="store_true")
	add_fn("--tls_cafile")
	add_fn("--tls_capath")
	add_fn("--tls_protocols")
	add_fn("--tls_cipher_suite")
	add_fn("--tls_keyfile")
	add_fn("--tls_certfile")
	add_fn("--tls_cert_blacklist")
	add_fn("--tls_crl_check",  action="store_true")
	add_fn("--tls_crl_check_all", action="store_true")

	add_fn("--timeout", type=float)

	if have_argparse:
		return parser.parse_args()

	(cli_args, args) = parser.parse_args()
	return cli_args

args = get_cli_args()

if args.help:
	print_config_help()
	exit(0)

if args.version:
	print "Aerospike Information Tool"
	print "Version " + str(__version__)
	exit(0)

if args.value == "stats":
	args.value = "statistics"

# Add self path as first in $PATH to resolve asadm
# Add directory of self path also:
# for PEX it has whole path till environment "/opt/aerospike/bin/asinfo"
# add directory of this path
# sys.path[0] can contain "/opt/aerospike/bin/asinfo/.bootstrap" when using pex <= 1.4.5
# Cannot upgrade pex as we are stuck with python 2.6 on centos6
# pex (>1.2.10) dropped support for python 2.6.

if sys.path[0].endswith(".bootstrap"):
        sys.path[0] = os.path.dirname(os.path.realpath(sys.path[0]))

os.environ["PATH"] = sys.path[0] + ":" + os.path.dirname(os.path.realpath(sys.path[0])) + ":" + os.getenv("PATH")

# asadm ( >= 0.1.22)
cmd = "asadm"
asinfo_cmd = ""

# default password in asadm is DEFAULTPASSWORD, so no need to pass default
# tls-keyfile-password is by default None in asadm, so need to pass its default
pwd_args = ["password"]

for arg, val in vars(args).iteritems():
	if arg == "value":
		if val:
			asinfo_cmd += "\'%s\'"%(str(val))
	else:
		if val is not None and val is not False and (arg not in pwd_args or val != DEFAULTPASSWORD):
			# If not a default values then only pass to asadm.
			cmd += " --%s " %(str(arg))
			if val is not True:
				# If not enable/disable argument then pass value also.
				# Some values may have space in it, to make it correct we need quotes.
				cmd += " \"%s\" " %(val)

# asinfo works with only single node (seed node)
cmd += " --asinfo-mode"

# final asadm command
if asinfo_cmd:
	cmd += " -e \"%s\""%(asinfo_cmd)

p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
if err:
	if out:
		print out

	print str(err)
	exit(1)

elif out:
	out = str(out).strip()

	connection_errors = ["Not able to connect any cluster", "Could not connect to node"]
	if any(ce in out for ce in connection_errors):
		# print "request to ",args.host,":",args.port," returned error"
		print out
		exit(1)

	if  "error:" in out.lower():
		print str(out)
		exit(1)

	if p.returncode:
		print "request to ",args.host,":",args.port," returned error"
		if out:
			print out
		exit(1)

	print out.strip()
