From d4397cc2f9ac787428a6b9a5c34b01c88fa6ee80 Mon Sep 17 00:00:00 2001 From: David Shrewsbury Date: Thu, 21 Mar 2013 10:48:47 -0400 Subject: [PATCH] Add driver API infrastructure for archiving logs. This adds an API call to the worker driver interface that will allow for supporting archiving of the load balancer logs. Only archiving logs to Swift is supported for now. Note that this does not add implementation of this new API method to the HAProxy driver. Change-Id: I0441cc99261058d23a6e5148ab7899291f28761d --- libra/worker/controller.py | 67 +++++++++++++++++++++++++ libra/worker/drivers/base.py | 4 ++ tests/test_worker_controller.py | 88 +++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) diff --git a/libra/worker/controller.py b/libra/worker/controller.py index 94a3073a..575d691f 100644 --- a/libra/worker/controller.py +++ b/libra/worker/controller.py @@ -24,7 +24,12 @@ class LBaaSController(object): RESPONSE_SUCCESS = "PASS" ACTION_FIELD = 'hpcs_action' RESPONSE_FIELD = 'hpcs_response' + ERROR_FIELD = 'hpcs_error' LBLIST_FIELD = 'loadBalancers' + OBJ_STORE_TYPE_FIELD = 'hpcs_object_store_type' + OBJ_STORE_BASEPATH_FIELD = 'hpcs_object_store_basepath' + OBJ_STORE_ENDPOINT_FIELD = 'hpcs_object_store_endpoint' + OBJ_STORE_TOKEN_FIELD = 'hpcs_object_store_token' def __init__(self, logger, driver, json_msg): self.logger = logger @@ -56,6 +61,8 @@ class LBaaSController(object): return self._action_delete() elif action == 'DISCOVER': return self._action_discover() + elif action == 'ARCHIVE': + return self._action_archive() else: self.logger.error("Invalid `%s` value: %s" % (self.ACTION_FIELD, action)) @@ -264,3 +271,63 @@ class LBaaSController(object): else: self.msg[self.RESPONSE_FIELD] = self.RESPONSE_SUCCESS return self.msg + + def _action_archive(self): + """ Archive LB log files. """ + + valid_methods = ['swift'] + method = None + params = {} + + if self.OBJ_STORE_TYPE_FIELD not in self.msg: + return BadRequest( + "Missing '%s' element" % self.OBJ_STORE_TYPE_FIELD + ).to_json() + else: + method = self.msg[self.OBJ_STORE_TYPE_FIELD].lower() + + # Validate method type + if method not in valid_methods: + return BadRequest( + "'%s' is not a valid store type" % method + ).to_json() + + # Get parameters for Swift storage + if method == 'swift': + if self.OBJ_STORE_BASEPATH_FIELD not in self.msg: + return BadRequest( + "Missing '%s' element" % self.OBJ_STORE_BASEPATH_FIELD + ).to_json() + if self.OBJ_STORE_ENDPOINT_FIELD not in self.msg: + return BadRequest( + "Missing '%s' element" % self.OBJ_STORE_ENDPOINT_FIELD + ).to_json() + if self.OBJ_STORE_TOKEN_FIELD not in self.msg: + return BadRequest( + "Missing '%s' element" % self.OBJ_STORE_TOKEN_FIELD + ).to_json() + if self.LBLIST_FIELD not in self.msg: + return BadRequest( + "Missing '%s' element" % self.LBLIST_FIELD + ).to_json() + + lb_list = self.msg[self.LBLIST_FIELD] + params['protocol'] = lb_list[0]['protocol'] + params['basepath'] = self.msg[self.OBJ_STORE_BASEPATH_FIELD] + params['endpoint'] = self.msg[self.OBJ_STORE_ENDPOINT_FIELD] + params['token'] = self.msg[self.OBJ_STORE_TOKEN_FIELD] + + try: + self.driver.archive(method, params) + except NotImplementedError: + error = "Selected driver does not support ARCHIVE action." + self.logger.error(error) + self.msg[self.RESPONSE_FIELD] = self.RESPONSE_FAILURE + self.msg[self.ERROR_FIELD] = error + except Exception as e: + self.logger.error("ARCHIVE failed: %s, %s" % (e.__class__, e)) + self.msg[self.RESPONSE_FIELD] = self.RESPONSE_FAILURE + self.msg[self.ERROR_FIELD] = str(e) + else: + self.msg[self.RESPONSE_FIELD] = self.RESPONSE_SUCCESS + return self.msg diff --git a/libra/worker/drivers/base.py b/libra/worker/drivers/base.py index b1b47d63..154c086f 100644 --- a/libra/worker/drivers/base.py +++ b/libra/worker/drivers/base.py @@ -75,3 +75,7 @@ class LoadBalancerDriver(object): def get_stats(self, protocol): """ Get load balancer statistics for specified protocol. """ raise NotImplementedError() + + def archive(self, method, params): + """ Archive the load balancer logs using the specified method. """ + raise NotImplementedError() diff --git a/tests/test_worker_controller.py b/tests/test_worker_controller.py index cc79f488..c963c0bc 100644 --- a/tests/test_worker_controller.py +++ b/tests/test_worker_controller.py @@ -2,6 +2,7 @@ import logging import testtools import tests.mock_objects from libra.worker.controller import LBaaSController as c +from libra.worker.drivers.base import LoadBalancerDriver from libra.worker.drivers.haproxy.driver import HAProxyDriver @@ -141,3 +142,90 @@ class TestWorkerController(testtools.TestCase): response = controller.run() self.assertIn('version', response) self.assertEquals(response[c.RESPONSE_FIELD], c.RESPONSE_SUCCESS) + + def testArchiveMissingMethod(self): + msg = { + c.ACTION_FIELD: 'ARCHIVE' + } + null_driver = LoadBalancerDriver() + controller = c(self.logger, null_driver, msg) + response = controller.run() + self.assertIn('badRequest', response) + + def testArchiveInvalidMethod(self): + msg = { + c.ACTION_FIELD: 'ARCHIVE', + c.OBJ_STORE_TYPE_FIELD: 'bad' + } + null_driver = LoadBalancerDriver() + controller = c(self.logger, null_driver, msg) + response = controller.run() + self.assertIn('badRequest', response) + + def testArchiveSwiftRequiredParams(self): + null_driver = LoadBalancerDriver() + + # Missing basepath field + msg = { + c.ACTION_FIELD: 'ARCHIVE', + c.OBJ_STORE_TYPE_FIELD: 'Swift', + c.OBJ_STORE_ENDPOINT_FIELD: "https://example.com", + c.OBJ_STORE_TOKEN_FIELD: "XXXX", + c.LBLIST_FIELD: [{'protocol': 'http'}] + } + controller = c(self.logger, null_driver, msg) + response = controller.run() + self.assertIn('badRequest', response) + + # Missing endpoint field + msg = { + c.ACTION_FIELD: 'ARCHIVE', + c.OBJ_STORE_TYPE_FIELD: 'Swift', + c.OBJ_STORE_BASEPATH_FIELD: "/lbaaslogs", + c.OBJ_STORE_TOKEN_FIELD: "XXXX", + c.LBLIST_FIELD: [{'protocol': 'http'}] + } + controller = c(self.logger, null_driver, msg) + response = controller.run() + self.assertIn('badRequest', response) + + # Missing token field + msg = { + c.ACTION_FIELD: 'ARCHIVE', + c.OBJ_STORE_TYPE_FIELD: 'Swift', + c.OBJ_STORE_BASEPATH_FIELD: "/lbaaslogs", + c.OBJ_STORE_ENDPOINT_FIELD: "https://example.com", + c.LBLIST_FIELD: [{'protocol': 'http'}] + } + controller = c(self.logger, null_driver, msg) + response = controller.run() + self.assertIn('badRequest', response) + + # Missing load balancer field + msg = { + c.ACTION_FIELD: 'ARCHIVE', + c.OBJ_STORE_TYPE_FIELD: 'Swift', + c.OBJ_STORE_BASEPATH_FIELD: "/lbaaslogs", + c.OBJ_STORE_ENDPOINT_FIELD: "https://example.com", + c.OBJ_STORE_TOKEN_FIELD: "XXXX" + } + controller = c(self.logger, null_driver, msg) + response = controller.run() + self.assertIn('badRequest', response) + + def testArchiveNotImplemented(self): + msg = { + c.ACTION_FIELD: 'ARCHIVE', + c.OBJ_STORE_TYPE_FIELD: 'Swift', + c.OBJ_STORE_BASEPATH_FIELD: "/lbaaslogs", + c.OBJ_STORE_ENDPOINT_FIELD: "https://example.com", + c.OBJ_STORE_TOKEN_FIELD: "XXXX", + c.LBLIST_FIELD: [{'protocol': 'http'}] + } + null_driver = LoadBalancerDriver() + controller = c(self.logger, null_driver, msg) + response = controller.run() + self.assertEquals(response[c.RESPONSE_FIELD], c.RESPONSE_FAILURE) + self.assertIn(c.ERROR_FIELD, response) + self.assertEquals(response[c.ERROR_FIELD], + "Selected driver does not support ARCHIVE action.")