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",
 | 
					    name="lbaas_worker",
 | 
				
			||||||
    description="Python LBaaS Gearman Worker",
 | 
					    description="Python LBaaS Gearman Worker",
 | 
				
			||||||
    version="1.0",
 | 
					    version="1.0",
 | 
				
			||||||
    author="David Shrewsbury",
 | 
					    author="David Shrewsbury <shrewsbury.dave@gmail.com>, \
 | 
				
			||||||
    author_email="shrewsbury.dave@gmail.com",
 | 
					        Andrew Hutchings <andrew@linuxjedi.co.uk>",
 | 
				
			||||||
    packages=setuptools.find_packages(exclude=["*.tests"]),
 | 
					    packages=setuptools.find_packages(exclude=["*.tests"]),
 | 
				
			||||||
    entry_points={
 | 
					    entry_points={
 | 
				
			||||||
        'console_scripts': [
 | 
					        'console_scripts': [
 | 
				
			||||||
            'lbaas_worker = lbaas_worker.worker:main'
 | 
					            'lbaas_worker = lbaas_worker.worker:main',
 | 
				
			||||||
 | 
					            'lbaas_pool_mgm = lbaas_mgm.mgm:main'
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    cmdclass={'test': PyTest},
 | 
					    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