monasca-agent/monagent/forwarder/api/__init__.py

89 lines
3.4 KiB
Python

import json
import logging
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 an exception so the transaction calling this is not committed
"""
def __init__(self, config):
"""
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()
if config['use_keystone']:
# Get a new token
self._refresh_token()
else:
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 = [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
given [Measurement, ...], format the request and post to the monitoring api
"""
# Add default dimensions
for measurement in measurements:
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