#!/usr/bin/env python

#
# Copyright (c) 2013 EMC Corporation.  All rights reserved.
#

import sys
import isi
import isi.misc
from optparse import OptionParser
import isi.km.isi_km as isi_km
import isi.km.isi_km_utils as kmutils

from isi.km.isi_km import IsiKm, km_domain_types, KmSimple

# CLI Options:
def get_opts():
    # Verb
    operation_help = "usage: %prog [status,count,list] <arg>\n\
		status - Current status of key manager subsystem.\n\
		count  - Total keys in keystore for specified domain.\n\
		list   - Key-Id's in keystore for specified domain."
    parser = OptionParser(operation_help)

    # options
    domain_help = 'Valid values for domain are "SEDS" and "CLOUDPOOLS" only.'
    parser.add_option('', '--domain', dest='domain', action='store', type='choice', choices = ['SEDS', 'seds', 'CLOUDPOOLS', 'cloudpools'], help=domain_help)

    startindex_help = 'Index of key-identifier to start enumerating for the specified domain. Optionally specified with list command'
    parser.add_option('', '--start', dest='start', type='int', action='store', default=0, help=startindex_help)

    limit_help = 'Limit of key-identifiers to enumerate from specified start_index for the specified domain. Optionally specified with list command.'
    parser.add_option('', '--limit', dest='limit', type='int', action='store', default=0, help=limit_help)
    return parser

# Method to get keymanager status.
def dump_km_status():
   print 'Key Manager status:'
   ret = 0

   km_daemon_alive = kmutils.get_pid()
   if not km_daemon_alive:
	print 'Key Manager Service is not running.'
	sys.exit(1);
   else:
	print 'Key Manager Service running - OK.'

   km_rpc_alive = kmutils.verify_rpc_state()
   if not km_rpc_alive:
	print 'Key Manager - RPC communication state - Failed.'
	sys.exit(1);
   else:
	print 'Key Manager - RPC communication state - OK.'

   keystore_partition_state = kmutils.verify_mount_state()
   if not keystore_partition_state:
	print 'Key Manager - SEDS keystore partition not available.'
   else:
	print 'Key Manager - SEDS keystore partition mounted - OK.'

   # check if /ifs is mounted.
   ifs_partition_mount_state = isi.misc.ifs_mounted()
   if not ifs_partition_mount_state:
	print 'Key Manager - CLOUDPOOLS keystore partition not available.'
   else:
	print 'Key Manager - CLOUDPOOLS keystore partition mounted - OK.'

   # check if /ifs is ready.
   ifs_partition_ready_state = isi.misc.ifs_ready()
   if not ifs_partition_ready_state:
	print 'Key Manager - CLOUDPOOLS keystore partition not ready.'
   else:
	print 'Key Manager - CLOUDPOOLS keystore partition I/O status - OK.'

   # Get version is agnostic of domain type, hence using SEDS here.
   with KmSimple("km_diag", km_domain_types.ISI_KM_DOMAIN_SEDS, False) as km:
	ret, ver_info = km.getversion()
	if (ret == 0):
		print 'Version = %d.%d' % (ver_info.major_version, ver_info.minor_version)
		_isikm = IsiKm()
		for i in range(isi.km.isi_km.ISI_KM_MAX_DOMAINS_SUPPORTED):
			print 'keystore domain [%s] status = [%d, [%s]]' % (getkmdomain_str(ver_info.keystores[i].domain), ver_info.keystores[i].status, _isikm.kmErrorToUserString(ver_info.keystores[i].status))
   return ret

# Method to return a string given domain enum.
def getkmdomain_str(domain):
   if (domain == km_domain_types.ISI_KM_DOMAIN_NULL):
	return ('NULL')
   if (domain == km_domain_types.ISI_KM_DOMAIN_SEDS):
	return ('SEDS')
   if (domain == km_domain_types.ISI_KM_DOMAIN_CLOUDPOOLS):
	return ('CLOUDPOOLS')
   return ('')

# Method to return a domain enum given a domain string.
def getkmdomain_enum(domainstr):
   domain = km_domain_types.ISI_KM_DOMAIN_MAX
   if (domainstr.upper() == 'SEDS'):
	domain = km_domain_types.ISI_KM_DOMAIN_SEDS

   if (domainstr.upper() == 'CLOUDPOOLS'):
	domain = km_domain_types.ISI_KM_DOMAIN_CLOUDPOOLS

   return domain

# Method to get the keycount from keystore for a given domain.
def dump_keycount(opts):
   domain = getkmdomain_enum(opts.domain)

   with KmSimple("km_diag", domain, False) as isi_km:
	ret, keycount = isi_km.get_keycount()
	if (ret == 0):
		if (keycount == 0):
			print 'There are no keys stored in keystore for %s domain. ' % opts.domain.upper()
		else:
			print 'Total keys in keystore for %s domain = [%d].' % (opts.domain.upper(), keycount)
	return ret

# Method to get keyId's from keystore for a given domain.
def enumerate_keyids(opts):
   domain = getkmdomain_enum(opts.domain)
   ret = 0
   with KmSimple("km_diag", domain, False) as kms:
	if (opts.limit < 0):
		print 'ERROR: Invalid value for limit specified. '
		return ret

	ret, key_id_list, msg = kms.enumerate_keyid(opts.start, opts.limit)

	if (msg != ''):
		print msg
		return ret

	if (ret == 0):
		if (len(key_id_list) == 0):
			print 'There are no keys in keystore for domain %s' % opts.domain.upper()
			return ret

		print 'Key Identifier:'
		for key in key_id_list:
			key_str = ''.join('%c' % ch for ch in key[:isi_km.ISI_KM_MAX_KEY_ID_LENGTH_WITH_NULL_TERMINATOR])
 			print key_str
	return ret

def do_run(opts, args):
    ret = 0
    if ('status' in args):
	ret = dump_km_status()
    if ('count' in args):
	ret = dump_keycount(opts)
    if ('list' in args):
	ret = enumerate_keyids(opts)
    return ret

# Validate all input args/options.
def valid_opts(opts, args):
    if (len(args) != 1):
	print 'Error:Incorrect command sequence. Supported commands are one of "status", "count" and "list" '
	return False
    if ((('list' in args) or ('count' in args)) and (not opts.domain)):
	print 'Error:Mandatory parameter *domain* missing. Please retry with valid *domain*.'
	return False
    if (('status' in args) and opts.domain):
	print 'Info: parameter domain is not required, ignoring the parameter.'
    return True

if __name__ == '__main__':
    parser = get_opts()
    opts, args = parser.parse_args()
    if valid_opts(opts, args):
        result = do_run(opts, args)
	if (result != 0):
		_isikm = IsiKm()
		print 'Error encountered during diagnostics. Error code [%d], [%s]' % (result, _isikm.kmErrorToUserString(result))
    else:
        print parser.print_help()
        sys.exit(1)
    parser.destroy()
    sys.exit(result)
