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.")