2017-11-02 20:55:29 +00:00
|
|
|
#!/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/>.
|
|
|
|
|
2017-11-02 21:54:58 +00:00
|
|
|
"""
|
|
|
|
Manipulate manager khaganat
|
2017-11-02 20:55:29 +00:00
|
|
|
|
2017-11-02 21:54:58 +00:00
|
|
|
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
|
2017-11-02 20:55:29 +00:00
|
|
|
|
2017-11-02 21:54:58 +00:00
|
|
|
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"
|
|
|
|
"""
|
2017-11-02 20:55:29 +00:00
|
|
|
|
|
|
|
import argparse
|
|
|
|
import logging
|
|
|
|
import logging.config
|
|
|
|
import http.client
|
|
|
|
import json
|
2017-11-13 20:18:48 +00:00
|
|
|
import socket
|
|
|
|
import ssl
|
2017-11-02 20:55:29 +00:00
|
|
|
|
|
|
|
def cmp_to_key():
|
2017-11-02 21:54:58 +00:00
|
|
|
'compare key (check if int or other)'
|
2017-11-02 20:55:29 +00:00
|
|
|
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
|
|
|
|
|
2017-11-13 20:18:48 +00:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
2017-11-02 20:55:29 +00:00
|
|
|
def send_json(jsonin={}, command='GET', path='/', host='localhost', port=8000, raw_data=False, remove_color=False,
|
2017-11-13 20:18:48 +00:00
|
|
|
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)
|
2017-11-02 20:55:29 +00:00
|
|
|
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))
|
|
|
|
|
|
|
|
|
2017-11-13 20:18:48 +00:00
|
|
|
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):
|
2017-11-02 20:55:29 +00:00
|
|
|
# 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')
|
2017-11-02 21:54:58 +00:00
|
|
|
# Send command
|
2017-11-02 20:55:29 +00:00
|
|
|
if command == 'START' or command == 'STOP':
|
2017-11-13 20:18:48 +00:00
|
|
|
send_json({'name': program}, 'POST', "/" + command, host, port, key_file=key_file,
|
|
|
|
cert_file=cert_file, ca_cert=ca_cert)
|
2017-11-02 20:55:29 +00:00
|
|
|
elif command == 'STATUS':
|
2017-11-13 20:18:48 +00:00
|
|
|
send_json({'name': program}, 'GET', "/" + command, host, port, key_file=key_file,
|
|
|
|
cert_file=cert_file, ca_cert=ca_cert)
|
2017-11-02 20:55:29 +00:00
|
|
|
elif command == 'ACTION':
|
2017-11-13 20:18:48 +00:00
|
|
|
send_json({'name': program, 'action' : action}, 'POST', "/" + command, host, port,
|
|
|
|
key_file=key_file, cert_file=cert_file, ca_cert=ca_cert)
|
2017-11-02 20:55:29 +00:00
|
|
|
elif command == 'LOG':
|
2017-11-13 20:18:48 +00:00
|
|
|
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)
|
2017-11-02 20:55:29 +00:00
|
|
|
elif command == 'LIST':
|
2017-11-13 20:18:48 +00:00
|
|
|
send_json({}, 'GET', "/" + command, host, port, key_file=key_file,
|
|
|
|
cert_file=cert_file, ca_cert=ca_cert)
|
2017-11-02 20:55:29 +00:00
|
|
|
elif command == 'SHUTDOWN' or command == 'STARTALL' or command == 'STOPALL':
|
2017-11-13 20:18:48 +00:00
|
|
|
send_json({}, 'POST', "/" + command, host, port, key_file=key_file,
|
|
|
|
cert_file=cert_file, ca_cert=ca_cert)
|
2017-11-02 20:55:29 +00:00
|
|
|
elif command == 'STATUSALL':
|
2017-11-13 20:18:48 +00:00
|
|
|
send_json({}, 'GET', "/" + command, host, port, key_file=key_file,
|
|
|
|
cert_file=cert_file, ca_cert=ca_cert)
|
2017-11-02 20:55:29 +00:00
|
|
|
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)
|
2017-11-13 20:18:48 +00:00
|
|
|
parser.add_argument('--ca_cert', help='ca_cert file', default=None)
|
|
|
|
parser.add_argument('--host', help='server khganat', default='127.0.0.1')
|
2017-11-02 20:55:29 +00:00
|
|
|
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()
|
2017-11-13 20:18:48 +00:00
|
|
|
main(host = args.host, action = args.action, firstline = args.firstline,
|
2017-11-02 20:55:29 +00:00
|
|
|
command = args.command, program = args.program, fileLog = args.filelog,
|
|
|
|
logLevel=args.log, show_log_console=args.show_log_console,
|
|
|
|
raw_data = args.raw_data,
|
2017-11-13 20:18:48 +00:00
|
|
|
key_file=args.key, cert_file=args.cert, ca_cert=args.ca_cert,
|
2017-11-02 20:55:29 +00:00
|
|
|
remove_color=not args.keep_color)
|