From 8a6386d5ac218922b04fd9f26e19d0d7b3523394 Mon Sep 17 00:00:00 2001 From: gary-hessler Date: Fri, 16 May 2014 11:13:44 -0600 Subject: [PATCH] Integrating python-monclient into agent --- monagent/forwarder/api/__init__.py | 77 ++++++++++++++++++++---------- monagent/forwarder/api/keystone.py | 3 +- packaging/Makefile | 1 + setup.py | 3 +- 4 files changed, 56 insertions(+), 28 deletions(-) diff --git a/monagent/forwarder/api/__init__.py b/monagent/forwarder/api/__init__.py index 659b3060..b6921034 100644 --- a/monagent/forwarder/api/__init__.py +++ b/monagent/forwarder/api/__init__.py @@ -1,56 +1,65 @@ import json import logging -import requests - +from threading import Timer from keystone import Keystone from monagent.common.util import get_hostname - +from monclient import client +import monclient.exc as exc log = logging.getLogger(__name__) class MonAPI(object): """Sends measurements to MonAPI - Any errors should raise and exception so the transaction calling this is not committed + Any errors should raise an exception so the transaction calling this is not committed """ def __init__(self, config): """ - Initialize Mon api connection. + Initialize Mon api client connection. """ self.url = config['url'] + self.api_version = '2_0' self.default_dimensions = config['dimensions'] + self.token_expiration = 1438 if not 'hostname' in self.default_dimensions: # Verify the hostname is set as a dimension self.default_dimensions['hostname'] = get_hostname() - #todo we should always use keystone, for development the keystone object should just return a dummy token if config['use_keystone']: - self.keystone = Keystone(config['keystone_url']) - token = self.keystone.get_token_password_auth(config['username'], config['password'], config['project_id']) - self.headers = {'content-type': 'application/json', - 'X-Auth-Token': token} + # Get a new token + self._refresh_token() else: - self.headers = {'content-type': 'application/json', - 'X-Tenant-Id': config['project_id']} + self.token = config['project_id'] + + # construct the mon client + kwargs = { + 'token': self.token + } + self.mon_client = client.Client(self.api_version, self.url, **kwargs) def _post(self, measurements): """Does the actual http post measurements is a list of Measurement """ - data = json.dumps([m.__dict__ for m in measurements]) - - response = requests.post(self.url, data=data, headers=self.headers) - if 200 <= response.status_code <= 299: - # Good status from web service - log.debug("Message sent successfully: {0}".format(str(data))) - elif 400 <= response.status_code <= 499: - # Good status from web service but some type of issue with the data - error_msg = "Successful web service call but there were issues (Status: {0}," + \ - "Status Message: {1}, Message Content: {1})" - log.error(error_msg.format(response.status_code, response.reason, response.text)) - response.raise_for_status() - else: # Not a good status - response.raise_for_status() + data = [m.__dict__ for m in measurements] + kwargs = { + 'jsonbody': data + } + try: + response = self.mon_client.metrics.create(**kwargs) + if 200 <= response.status_code <= 299: + # Good status from web service + log.debug("Message sent successfully: {0}".format(str(data))) + elif 400 <= response.status_code <= 499: + # Good status from web service but some type of issue with the data + error_msg = "Successful web service call but there were issues (Status: {0}," + \ + "Status Message: {1}, Message Content: {1})" + log.error(error_msg.format(response.status_code, response.reason, response.text)) + response.raise_for_status() + else: # Not a good status + response.raise_for_status() + except exc.HTTPException as he: + log.error("Error sending message to mon-api: {0}".format(str(he.message))) def post_metrics(self, measurements): """post_metrics @@ -61,3 +70,19 @@ class MonAPI(object): measurement.dimensions.update(self.default_dimensions) self._post(measurements) + + def _refresh_token(self): + """_refresh_token + Gets a new token from Keystone and resets the validity timer + """ + token = None + try: + log.debug("Getting token from Keystone") + keystone = Keystone(config['keystone_url'], config['use_keystone']) + self.token = keystone.get_token_password_auth(config['username'], config['password'], config['project_id']) + log.debug("Setting Keystone token expiration timer for {0} minutes".format(str(self.token_expiration))) + self.timer = Timer(self.token_expiration,self._refresh_token) + self.timer.start() + except Exception as ex: + log.error("Error getting token from Keystone: {0}".format(str(ex.message))) + raise ex diff --git a/monagent/forwarder/api/keystone.py b/monagent/forwarder/api/keystone.py index fe7f6757..989364f4 100644 --- a/monagent/forwarder/api/keystone.py +++ b/monagent/forwarder/api/keystone.py @@ -54,8 +54,9 @@ class Keystone(object): } } - def __init__(self, endpoint): + def __init__(self, endpoint, use_keystone): self.endpoint = endpoint + self.use_keystone def get_token_password_auth(self, user_id, password, project_id): self.password_auth['auth']['identity']['password']['user']['id'] = user_id diff --git a/packaging/Makefile b/packaging/Makefile index 6c6bd91d..900e68b7 100644 --- a/packaging/Makefile +++ b/packaging/Makefile @@ -89,6 +89,7 @@ $(FPM_BUILD) -t deb \ -d "python-httplib2" \ -d "python-ntplib" \ -d "python-yaml" \ +-d "python-monclient" \ --post-install mon-agent-deb/postinst \ --post-uninstall mon-agent-deb/postrm \ --pre-uninstall mon-agent-deb/prerm \ diff --git a/setup.py b/setup.py index c518475e..dc43d5a9 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,8 @@ install_requires=[ 'PyYAML', 'redis', 'simplejson', - 'tornado' + 'tornado', + 'python-monclient', ] if sys.platform == 'win32':