proxmaster/proxmaster.py
2018-03-18 14:54:20 +02:00

228 lines
6.8 KiB
Python

#. -*- coding: utf-8 -
# import site packages
import logging
import falcon
import sys
import json
#import local packages
import ioconfig
import grid
import plugin
config = ioconfig.parser
logger = ioconfig.logger
def welcome():
logger.info('# proxmaster ][ (c) 2015-2018 deflax.net #')
def selector(fn, req):
""" try to exec commands """
json = req.context['doc']
apipass = json['apikey']
if apipass != config.get('general', 'apipass'):
status = falcon.HTTP_403
body = falcon.HTTP_403
logger.error('grid> access denied. bad api key!')
return status, body
try:
if fn == 'create':
body = plugin.create(json)
elif fn == 'remove':
body = plugin.remove(json)
elif fn == 'status':
body = plugin.status(json)
elif fn == 'query':
body = grid.read(json)
elif fn == 'start':
body = plugin.start(json)
elif fn == 'shutdown':
body = plugin.shutdown(json)
elif fn == 'stop':
body = plugin.stop(json)
elif fn == 'suspend':
body = plugin.suspend(json)
elif fn == 'resume':
body = plugin.resume(json)
elif fn == 'vmrrd':
body = plugin.vmrrd(json)
elif fn == 'vmvnc':
body = plugin.vmvnc(json)
except:
logger.critical('grid> {} error'.format(fn))
status = falcon.HTTP_404
raise
else:
#logger.info('grid> {}'.format(fn))
status = falcon.HTTP_202
return status, body
class RequireJSON(object):
def process_request(self, req, resp):
if not req.client_accepts_json:
raise falcon.HTTPNotAcceptable(
'This API only supports responses encoded as JSON.',
href='http://docs.examples.com/api/json')
if req.method in ('POST', 'PUT'):
if 'application/json' not in req.content_type:
raise falcon.HTTPUnsupportedMediaType(
'This API only supports requests encoded as JSON.',
href='http://docs.examples.com/api/json')
class JSONTranslator(object):
def process_request(self, req, resp):
# req.stream corresponds to the WSGI wsgi.input environ variable,
# and allows you to read bytes from the request body.
#
# See also: PEP 3333
if req.content_length in (None, 0):
# Nothing to do
return
body = req.stream.read()
if not body:
raise falcon.HTTPBadRequest('Empty request body',
'A valid JSON document is required.')
try:
req.context['doc'] = json.loads(body.decode('utf-8'))
except (ValueError, UnicodeDecodeError):
raise falcon.HTTPError(falcon.HTTP_400,
'Malformed JSON',
'Could not decode the request body. The '
'JSON was incorrect or not encoded as '
'UTF-8.')
def process_response(self, req, resp, resource):
if 'result' not in req.context:
return
resp.body = json.dumps(req.context['result'])
def max_body(limit):
def hook(req, resp, resource, params):
length = req.content_length
if length is not None and length > limit:
msg = ('The size of the request is too large. The body must not '
'exceed ' + str(limit) + ' bytes in length.')
raise falcon.HTTPRequestEntityTooLarge(
'Request body is too large', msg)
return hook
class CreateUnit(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" creates an unit """
resp.status, response = selector('create', req)
req.context['result'] = response
class RemoveUnit(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" removes unit completely"""
resp.status, response = selector('remove', req)
req.context['result'] = response
class StatusUnit(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" checks unit status """
resp.status, response = selector('status', req)
req.context['result'] = response
class QueryUnit(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" query unit info """
resp.status, response = selector('query', req)
req.context['result'] = response
class SuspendUnit(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" Temporary suspend the instance """
resp.status, response = selector('suspend', req)
req.context['result'] = response
class ResumeUnit(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" Unuspend the instance """
resp.status, response = selector('resume', req)
req.context['result'] = response
class StartUnit(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" Start the instance """
resp.status, response = selector('start', req)
req.context['result'] = response
class ShutdownUnit(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" ACPI Shutdown the instance """
resp.status, response = selector('shutdown', req)
req.context['result'] = response
class StopUnit(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" Stop the instance """
resp.status, response = selector('stop', req)
req.context['result'] = response
class RRDVM(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" Generate rrd pngs """
resp.status, response = selector('vmrrd', req)
req.context['result'] = response
class VNCVM(object):
@falcon.before(max_body(64 * 1024))
def on_post(self, req, resp):
""" Create a VNC link to the instance """
resp.status, response = selector('vmvnc', req)
req.context['result'] = response
if __name__ == '__main__':
sys.exit("invoke proxmaster via uwsgi. thanks. bye. o/")
wsgi_app = api = application = falcon.API(middleware=[
RequireJSON(),
JSONTranslator(),
])
# setup routes
api.add_route('/create', CreateUnit())
api.add_route('/remove', RemoveUnit())
api.add_route('/status', StatusUnit())
api.add_route('/query', QueryUnit())
api.add_route('/start', StartUnit())
api.add_route('/suspend', SuspendUnit())
api.add_route('/resume', ResumeUnit())
api.add_route('/shutdown', ShutdownUnit())
api.add_route('/stop', StopUnit())
api.add_route('/vmrrd', RRDVM())
api.add_route('/vmvnc', VNCVM())
#display motd
welcome()