#. -*- 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(): """displays motd in log as welcome message""" logger.info('# proxmaster ][ (c) 2015-2017 deflax.net #') def selector(fn, req): """ try to exec commands """ json = req.context['doc'] #print(json) 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()