khanat-code-old/code/khaganat/tools/client.py
2017-11-13 21:18:48 +01:00

237 lines
10 KiB
Python
Executable file

#!/usr/bin/python3
#
# script to send command to manager khaganat process
#
# Copyright (C) 2017 AleaJactaEst
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Manipulate manager khaganat
We can end some command to manager.
Global:
SHUTDOWN : Stop manager & Stop all programs
STARTALL : Start all programs
STATUSALL : Get status of all programs
STOPALL : Stop all programs
LIST : List all programs available
For one program :
START : Start program
STOP : Stop program
STATUS : Get status
LOG : Get log
firstline : option to define first line we need send
ACTION : Send action (command) in stdin
action : option to define which action you need send to stdin
Example :
./client.py --log="debug" --show-log-console --server='172.17.0.2' --program="aes" --command="START"
./client.py --log="debug" --show-log-console --server='172.17.0.2' --program="aes" --command="STATUS"
./client.py --log="debug" --show-log-console --server='172.17.0.2' --program="aes" --command="ACTION" --action="coucou"
./client.py --log="debug" --show-log-console --server='172.17.0.2' --program="aes" --command="LOG" --firstline=0
./client.py --log="debug" --show-log-console --server='172.17.0.2' --program="aes" --command="STOP"
./client.py --log="debug" --show-log-console --server='172.17.0.2' --command="LIST"
./client.py --log="debug" --show-log-console --server='172.17.0.2' --command="SHUTDOWN"
./client.py --log="debug" --show-log-console --server='172.17.0.2' --command="STARTALL"
./client.py --log="debug" --show-log-console --server='172.17.0.2' --command="STATUSALL"
./client.py --key="/home/gameserver/khanat/key.pem" --cert="/home/gameserver/khanat/cert.pem" --log="debug" --show-log-console --command="STATUSALL"
"""
import argparse
import logging
import logging.config
import http.client
import json
import socket
import ssl
def cmp_to_key():
'compare key (check if int or other)'
class K(object):
def __init__(self, obj, *args):
self.obj = obj
def __lt__(self, other):
try:
return int(self.obj) < int(other.obj)
except:
return self.obj < other.obj
def __gt__(self, other):
try:
return int(self.obj) > int(other.obj)
except:
return self.obj > other.obj
def __eq__(self, other):
try:
return int(self.obj) == int(other.obj)
except:
return self.obj == other.obj
def __le__(self, other):
try:
return int(self.obj) <= int(other.obj)
except:
return self.obj <= other.obj
def __ge__(self, other):
try:
return int(self.obj) >= int(other.obj)
except:
return self.obj >= other.obj
def __ne__(self, other):
try:
return int(self.obj) != int(other.obj)
except:
return self.obj != other.obj
return K
class HTTPSConnectionCertificate(http.client.HTTPConnection):
""" Class HTTP connection with check certificate (if certicate is defined) """
def __init__(self, key_file, cert_file, ca_cert, host='localhost', port=8000, timeout=10):
"""
Constructor
"""
logging.debug("constructor")
http.client.HTTPConnection.__init__(self, host, port, timeout)
self.key_file = key_file
self.cert_file = cert_file
self.ca_cert = ca_cert
self.host = host
self.port = port
def connect(self):
"""
connect in https (and check certificate if defined)
"""
logging.debug("connect launched")
sock = socket.create_connection((self.host, self.port), self.timeout)
# If there's no CA File, don't force Server Certificate Check
if self.ca_cert:
logging.debug("key_file: " + self.key_file)
logging.debug("cert_file: " + self.cert_file)
logging.debug("ca_cert: " + self.ca_cert)
self.sock = ssl.wrap_socket(sock,
self.key_file,
self.cert_file,
ca_certs=self.ca_cert,
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1_2 #PROTOCOL_SSLv23 #, ciphers="ADH-AES256-SHA"
)
else:
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, cert_reqs=ssl.CERT_NONE)
def send_json(jsonin={}, command='GET', path='/', host='localhost', port=8000, raw_data=False, remove_color=False,
key_file=None, cert_file=None, ca_cert=None, timeout=10):
"""
send command with https & json format
"""
conn = HTTPSConnectionCertificate(host=host, port=port, key_file=key_file, cert_file=cert_file, ca_cert=ca_cert, timeout=timeout)
conn.putrequest(command, path)
out=json.dumps(jsonin)
conn.putheader('Content-type', 'application/json')
conn.putheader('Content-length', len(out))
conn.endheaders()
conn.send(bytes(out, "utf-8"))
response = conn.getresponse()
if raw_data:
print(response.read())
else:
if remove_color:
endText = '\x1b[0m'
else:
endText = ''
if response.status != 200:
logging.error("Error detected (html code:%d)" % response.status)
print(response.read())
return
ret = response.read().decode()
try:
msgjson = json.loads(ret)
except:
logging.error("Impossible to decode Json output")
print(ret)
return
for key in sorted(msgjson, key=cmp_to_key()):
print("%s: %s %s" % (key, msgjson[key], endText))
def main(host, command, program, action, firstline, fileLog, logLevel, show_log_console, port=8000,
raw_data=False, remove_color=False, key_file=None, cert_file=None, ca_cert=None):
# Manage log
logging.getLogger('logging')
numeric_level = getattr(logging, logLevel.upper(), None)
if not isinstance(numeric_level, int):
raise ValueError('Invalid log level: %s' % logLevel)
handlers=[]
if show_log_console:
handlers.append(logging.StreamHandler())
if fileLog:
handlers.append(logging.FileHandler(fileLog.name))
logging.basicConfig(handlers=handlers, level=numeric_level,
format='%(asctime)s %(levelname)s [pid:%(process)d] [%(funcName)s:%(lineno)d] %(message)s')
# Send command
if command == 'START' or command == 'STOP':
send_json({'name': program}, 'POST', "/" + command, host, port, key_file=key_file,
cert_file=cert_file, ca_cert=ca_cert)
elif command == 'STATUS':
send_json({'name': program}, 'GET', "/" + command, host, port, key_file=key_file,
cert_file=cert_file, ca_cert=ca_cert)
elif command == 'ACTION':
send_json({'name': program, 'action' : action}, 'POST', "/" + command, host, port,
key_file=key_file, cert_file=cert_file, ca_cert=ca_cert)
elif command == 'LOG':
send_json({'name': program, 'first-line' : firstline }, 'GET', "/" + command, host, port, raw_data,
remove_color, key_file=key_file, cert_file=cert_file, ca_cert=ca_cert)
elif command == 'LIST':
send_json({}, 'GET', "/" + command, host, port, key_file=key_file,
cert_file=cert_file, ca_cert=ca_cert)
elif command == 'SHUTDOWN' or command == 'STARTALL' or command == 'STOPALL':
send_json({}, 'POST', "/" + command, host, port, key_file=key_file,
cert_file=cert_file, ca_cert=ca_cert)
elif command == 'STATUSALL':
send_json({}, 'GET', "/" + command, host, port, key_file=key_file,
cert_file=cert_file, ca_cert=ca_cert)
else:
logging.error("command unknown (%s)" % command)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Manipulate khaganat process')
parser.add_argument('--version', action='version', version='%(prog)s 1.0')
parser.add_argument( '--show-log-console', action='store_true',
help='show message in console', default=False)
parser.add_argument('--filelog', type=argparse.FileType('wt'),
default=None, help='log file')
parser.add_argument('--log',
default='INFO', help='log level [DEBUG, INFO, WARNING, ERROR')
parser.add_argument('--key', help='key file', default=None)
parser.add_argument('--cert', help='cert file', default=None)
parser.add_argument('--ca_cert', help='ca_cert file', default=None)
parser.add_argument('--host', help='server khganat', default='127.0.0.1')
parser.add_argument('--command', help='command send to khganat', default='/STATUS')
parser.add_argument('--program', help='program khaganat id ', default='aes')
parser.add_argument('--action', help='action ', default='')
parser.add_argument('--firstline', type=int,
help='define fistline read for log command', default=0)
parser.add_argument( '--raw-data', action='store_true',
help='show raw message', default=False)
parser.add_argument( '--keep-color', action='store_true',
help='some message have color define, by default we reset the color (this option keep current color state)', default=False)
args = parser.parse_args()
main(host = args.host, action = args.action, firstline = args.firstline,
command = args.command, program = args.program, fileLog = args.filelog,
logLevel=args.log, show_log_console=args.show_log_console,
raw_data = args.raw_data,
key_file=args.key, cert_file=args.cert, ca_cert=args.ca_cert,
remove_color=not args.keep_color)