Merge in lbaas_mgm code and fix pep8 on it
This commit is contained in:
		
							
								
								
									
										0
									
								
								lbaas_mgm/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								lbaas_mgm/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										62
									
								
								lbaas_mgm/faults.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								lbaas_mgm/faults.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| #!/usr/bin/env python | ||||
| # Copyright 2012 Hewlett-Packard Development Company, L.P. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
| # not use this file except in compliance with the License. You may obtain | ||||
| # a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| # License for the specific language governing permissions and limitations | ||||
| # under the License. | ||||
|  | ||||
| import json | ||||
|  | ||||
|  | ||||
| class ServiceFault(object): | ||||
|     def __init__(self, code, message, details): | ||||
|         self.code = code | ||||
|         self.message = message | ||||
|         self.details = details | ||||
|  | ||||
|     def to_json(self): | ||||
|         data = { | ||||
|             "serviceFault": { | ||||
|                 "code": self.code, | ||||
|                 "message": self.message, | ||||
|                 "details": self.details | ||||
|             } | ||||
|         } | ||||
|         return data | ||||
|  | ||||
|     def __str__(self): | ||||
|         return json.dumps(self.to_json(), indent=4) | ||||
|  | ||||
|  | ||||
| class BadRequest(ServiceFault): | ||||
|     def __init__(self, | ||||
|                  validation_errors, | ||||
|                  code="400", | ||||
|                  message="Validation fault", | ||||
|                  details="The object is not valid"): | ||||
|         ServiceFault.__init__(self, code, message, details) | ||||
|         self.validation_errors = validation_errors | ||||
|  | ||||
|     def to_json(self): | ||||
|         data = { | ||||
|             "badRequest": { | ||||
|                 "code": self.code, | ||||
|                 "message": self.message, | ||||
|                 "details": self.details, | ||||
|                 "validationErrors": { | ||||
|                     "message": self.validation_errors | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return data | ||||
|  | ||||
|     def __str__(self): | ||||
|         return json.dumps(self.to_json(), indent=4) | ||||
							
								
								
									
										36
									
								
								lbaas_mgm/json_gearman.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								lbaas_mgm/json_gearman.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| #!/usr/bin/env python | ||||
| # Copyright 2012 Hewlett-Packard Development Company, L.P. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
| # not use this file except in compliance with the License. You may obtain | ||||
| # a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| # License for the specific language governing permissions and limitations | ||||
| # under the License. | ||||
|  | ||||
| import json | ||||
| from gearman import GearmanWorker, DataEncoder | ||||
|  | ||||
|  | ||||
| class JSONDataEncoder(DataEncoder): | ||||
|     """ Class to transform data that the worker either receives or sends. """ | ||||
|  | ||||
|     @classmethod | ||||
|     def encode(cls, encodable_object): | ||||
|         """ Encode JSON object as string """ | ||||
|         return json.dumps(encodable_object) | ||||
|  | ||||
|     @classmethod | ||||
|     def decode(cls, decodable_string): | ||||
|         """ Decode string to JSON object """ | ||||
|         return json.loads(decodable_string) | ||||
|  | ||||
|  | ||||
| class JSONGearmanWorker(GearmanWorker): | ||||
|     """ Overload the Gearman worker class so we can set the data encoder. """ | ||||
|     data_encoder = JSONDataEncoder | ||||
							
								
								
									
										49
									
								
								lbaas_mgm/listener.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								lbaas_mgm/listener.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| #!/usr/bin/env python | ||||
| # Copyright 2012 Hewlett-Packard Development Company, L.P. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
| # not use this file except in compliance with the License. You may obtain | ||||
| # a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| # License for the specific language governing permissions and limitations | ||||
| # under the License. | ||||
|  | ||||
| import json | ||||
| import socket | ||||
|  | ||||
| from json_gearman import JSONGearmanWorker | ||||
| from lbaas_mgm.faults import BadRequest | ||||
|  | ||||
|  | ||||
| class Listener(object): | ||||
|     def __init__(self, logger): | ||||
|         self.logger = logger | ||||
|  | ||||
|     def run(self): | ||||
|         my_ip = socket.gethostbyname(socket.gethostname()) | ||||
|         task_name = "lbaas-mgm-%s" % my_ip | ||||
|         self.logger.debug("Registering task %s" % task_name) | ||||
|  | ||||
|         worker = JSONGearmanWorker(['localhost:4730']) | ||||
|         worker.set_client_id(my_ip) | ||||
|         worker.register_task(task_name, self.task) | ||||
|  | ||||
|     def task(self, worker, job): | ||||
|         data = json.loads(job.data) | ||||
|  | ||||
|         if 'command' not in data: | ||||
|             return BadRequest("Missing 'command' element").to_json() | ||||
|  | ||||
|         command = data['command'] | ||||
|         self.logger.debug('Command: {cmd}'.format(cmd=command)) | ||||
|         if command == 'get': | ||||
|             self.logger.debug('Get one node from pool') | ||||
|         else: | ||||
|             return BadRequest("Invalid command").to_json() | ||||
|  | ||||
|         return data | ||||
							
								
								
									
										87
									
								
								lbaas_mgm/mgm.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								lbaas_mgm/mgm.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| #!/usr/bin/env python | ||||
| # Copyright 2012 Hewlett-Packard Development Company, L.P. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
| # not use this file except in compliance with the License. You may obtain | ||||
| # a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| # License for the specific language governing permissions and limitations | ||||
| # under the License. | ||||
|  | ||||
| import logging | ||||
| import argparse | ||||
| import daemon | ||||
| import signal | ||||
| import sys | ||||
|  | ||||
| from lbaas_mgm.listener import Listener | ||||
|  | ||||
|  | ||||
| class Server(object): | ||||
|     def __init__(self, logger, nodes): | ||||
|         self.logger = logger | ||||
|         self.nodes = nodes | ||||
|  | ||||
|     def main(self): | ||||
|         self.logger.info( | ||||
|             'LBaaS Pool Manager started with {nodes} nodes' | ||||
|             .format(nodes=self.nodes) | ||||
|         ) | ||||
|         signal.signal(signal.SIGINT, self.exit_handler) | ||||
|         signal.signal(signal.SIGTERM, self.exit_handler) | ||||
|         listner = Listener(self.logger) | ||||
|         try: | ||||
|             listner.run() | ||||
|         except Exception as e: | ||||
|             self.logger.critical( | ||||
|                 'Exception: {eclass}, {exception}' | ||||
|                 .format(eclass=e.__class__, exception=e) | ||||
|             ) | ||||
|             self.shutdown(True) | ||||
|         self.shutdown(False) | ||||
|  | ||||
|     def exit_handler(self, signum, frame): | ||||
|         signal.signal(signal.SIGINT, signal.SIG_IGN) | ||||
|         signal.signal(signal.SIGTERM, signal.SIG_IGN) | ||||
|  | ||||
|     def shutdown(self, error): | ||||
|         if not error: | ||||
|             self.logger.info('Safely shutting down') | ||||
|             sys.exit(0) | ||||
|         else: | ||||
|             self.logger.info('Shutting down due to error') | ||||
|             sys.exit(1) | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     parser = argparse.ArgumentParser( | ||||
|         description='LBaaS Node Management Daemon' | ||||
|     ) | ||||
|     parser.add_argument('nodes', metavar='N', type=int, | ||||
|                         help='number of nodes to maintain') | ||||
|     parser.add_argument('-d', dest='nodaemon', action='store_true', | ||||
|                         help='do not run in daemon mode') | ||||
|     options = parser.parse_args() | ||||
|  | ||||
|     logging.basicConfig( | ||||
|         format='%(asctime)-6s: %(name)s - %(levelname)s - %(message)s', | ||||
|         filename='/var/log/lbaas/lbaas_mgm.log' | ||||
|     ) | ||||
|     logger = logging.getLogger('lbaas_mgm') | ||||
|     logger.setLevel(logging.INFO) | ||||
|  | ||||
|     pid_fn = '/var/run/lbaas_mgm/lbaas_mgm.pid' | ||||
|     pid = daemon.pidlockfile.TimeoutPIDLockFile(pid_fn, 10) | ||||
|  | ||||
|     server = Server(logger, options.nodes) | ||||
|  | ||||
|     if options.nodaemon: | ||||
|         server.main() | ||||
|     else: | ||||
|         with daemon.DaemonContext(pidfile=pid): | ||||
|             server.main() | ||||
							
								
								
									
										7
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								setup.py
									
									
									
									
									
								
							| @@ -32,12 +32,13 @@ setuptools.setup( | ||||
|     name="lbaas_worker", | ||||
|     description="Python LBaaS Gearman Worker", | ||||
|     version="1.0", | ||||
|     author="David Shrewsbury", | ||||
|     author_email="shrewsbury.dave@gmail.com", | ||||
|     author="David Shrewsbury <shrewsbury.dave@gmail.com>, \ | ||||
|         Andrew Hutchings <andrew@linuxjedi.co.uk>", | ||||
|     packages=setuptools.find_packages(exclude=["*.tests"]), | ||||
|     entry_points={ | ||||
|         'console_scripts': [ | ||||
|             'lbaas_worker = lbaas_worker.worker:main' | ||||
|             'lbaas_worker = lbaas_worker.worker:main', | ||||
|             'lbaas_pool_mgm = lbaas_mgm.mgm:main' | ||||
|         ] | ||||
|     }, | ||||
|     cmdclass={'test': PyTest}, | ||||
|   | ||||
							
								
								
									
										0
									
								
								tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										30
									
								
								tests/mock.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								tests/mock.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| import json | ||||
| import logging | ||||
|  | ||||
|  | ||||
| class FakeJob(object): | ||||
|     def __init__(self, data): | ||||
|         """ | ||||
|         data: JSON object to convert to a string | ||||
|         """ | ||||
|         self.data = json.dumps(data) | ||||
|  | ||||
|  | ||||
| class MockLoggingHandler(logging.Handler): | ||||
|     """Mock logging handler to check for expected logs.""" | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         self.reset() | ||||
|         logging.Handler.__init__(self, *args, **kwargs) | ||||
|  | ||||
|     def emit(self, record): | ||||
|         self.messages[record.levelname.lower()].append(record.getMessage()) | ||||
|  | ||||
|     def reset(self): | ||||
|         self.messages = { | ||||
|             'debug': [], | ||||
|             'info': [], | ||||
|             'warning': [], | ||||
|             'error': [], | ||||
|             'critical': [], | ||||
|         } | ||||
							
								
								
									
										37
									
								
								tests/test_lbaas_mgm.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								tests/test_lbaas_mgm.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| import unittest | ||||
| import logging | ||||
|  | ||||
| import tests.mock | ||||
|  | ||||
| from lbaas_mgm.listener import Listener | ||||
|  | ||||
|  | ||||
| class TestLBaaSMgmTask(unittest.TestCase): | ||||
|     def setUp(self): | ||||
|         self.logger = logging.getLogger('lbass_mgm_test') | ||||
|         self.lh = tests.mock.MockLoggingHandler() | ||||
|         self.logger.setLevel(logging.DEBUG) | ||||
|         self.logger.addHandler(self.lh) | ||||
|  | ||||
|     def tearDown(self): | ||||
|         pass | ||||
|  | ||||
|     def testTaskGet(self): | ||||
|         listener = Listener(self.logger) | ||||
|         data = {'command': 'get'} | ||||
|         job = tests.mock.FakeJob(data) | ||||
|         result = listener.task(None, job) | ||||
|         self.assertIn('Command: get', self.lh.messages['debug']) | ||||
|         self.assertEqual(result['command'], data['command']) | ||||
|  | ||||
|     def testTaskBad(self): | ||||
|         listener = Listener(self.logger) | ||||
|         data = {'command': 'bad'} | ||||
|         job = tests.mock.FakeJob(data) | ||||
|         result = listener.task(None, job) | ||||
|         self.assertIn("badRequest", result) | ||||
|         self.assertIn("validationErrors", result['badRequest']) | ||||
|         self.assertEqual( | ||||
|             "Invalid command", | ||||
|             result['badRequest']['validationErrors']['message'] | ||||
|         ) | ||||
		Reference in New Issue
	
	Block a user
	 Andrew Hutchings
					Andrew Hutchings