Enable Basic and https certificate authentication for http publisher
Change-Id: I3735db7a37eff9e822e5180349eb8f86002fd0ef
This commit is contained in:
parent
d3caa24565
commit
191748a403
@ -35,9 +35,20 @@ class HttpPublisher(publisher.ConfigPublisherBase):
|
|||||||
`timeout` and `max_retries` will be set to 5 and 2 respectively. Additional
|
`timeout` and `max_retries` will be set to 5 and 2 respectively. Additional
|
||||||
parameters are:
|
parameters are:
|
||||||
|
|
||||||
- ssl can be enabled by setting `verify_ssl`
|
- ssl certificate verification can be disabled by setting `verify_ssl`
|
||||||
|
to False
|
||||||
- batching can be configured by `batch`
|
- batching can be configured by `batch`
|
||||||
- connection pool size configured using `poolsize`
|
- connection pool size configured using `poolsize`
|
||||||
|
- Basic authentication can be configured using the URL authentication
|
||||||
|
scheme: http://username:password@example.com
|
||||||
|
- For certificate authentication, `clientcert` and `clientkey` are the
|
||||||
|
paths to the certificate and key files respectively. `clientkey` is
|
||||||
|
only required if the clientcert file doesn't already contain the key.
|
||||||
|
|
||||||
|
All of the parameters mentioned above get removed during processing,
|
||||||
|
with the remaining portion of the URL being used as the actual endpoint.
|
||||||
|
e.g. https://username:password@example.com/path?verify_ssl=False&q=foo
|
||||||
|
will result in a call to https://example.com/path?q=foo
|
||||||
|
|
||||||
To use this publisher for samples, add the following section to the
|
To use this publisher for samples, add the following section to the
|
||||||
/etc/ceilometer/pipeline.yaml file or simply add it to an existing
|
/etc/ceilometer/pipeline.yaml file or simply add it to an existing
|
||||||
@ -63,7 +74,6 @@ class HttpPublisher(publisher.ConfigPublisherBase):
|
|||||||
|
|
||||||
def __init__(self, conf, parsed_url):
|
def __init__(self, conf, parsed_url):
|
||||||
super(HttpPublisher, self).__init__(conf, parsed_url)
|
super(HttpPublisher, self).__init__(conf, parsed_url)
|
||||||
self.target = parsed_url.geturl()
|
|
||||||
|
|
||||||
if not parsed_url.hostname:
|
if not parsed_url.hostname:
|
||||||
raise ValueError('The hostname of an endpoint for '
|
raise ValueError('The hostname of an endpoint for '
|
||||||
@ -83,12 +93,32 @@ class HttpPublisher(publisher.ConfigPublisherBase):
|
|||||||
self.poster = (
|
self.poster = (
|
||||||
self._do_post if strutils.bool_from_string(self._get_param(
|
self._do_post if strutils.bool_from_string(self._get_param(
|
||||||
params, 'batch', True)) else self._individual_post)
|
params, 'batch', True)) else self._individual_post)
|
||||||
|
verify_ssl = self._get_param(params, 'verify_ssl', True)
|
||||||
try:
|
try:
|
||||||
self.verify_ssl = strutils.bool_from_string(
|
self.verify_ssl = strutils.bool_from_string(verify_ssl,
|
||||||
self._get_param(params, 'verify_ssl', None), strict=True)
|
strict=True)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.verify_ssl = (self._get_param(params, 'verify_ssl', None)
|
self.verify_ssl = (verify_ssl or True)
|
||||||
or True)
|
|
||||||
|
username = parsed_url.username
|
||||||
|
password = parsed_url.password
|
||||||
|
if username:
|
||||||
|
self.client_auth = (username, password)
|
||||||
|
netloc = parsed_url.netloc.replace(username+':'+password+'@', '')
|
||||||
|
else:
|
||||||
|
self.client_auth = None
|
||||||
|
netloc = parsed_url.netloc
|
||||||
|
|
||||||
|
clientcert = self._get_param(params, 'clientcert', None)
|
||||||
|
clientkey = self._get_param(params, 'clientkey', None)
|
||||||
|
if clientcert:
|
||||||
|
if clientkey:
|
||||||
|
self.client_cert = (clientcert, clientkey)
|
||||||
|
else:
|
||||||
|
self.client_cert = clientcert
|
||||||
|
else:
|
||||||
|
self.client_cert = None
|
||||||
|
|
||||||
self.raw_only = strutils.bool_from_string(
|
self.raw_only = strutils.bool_from_string(
|
||||||
self._get_param(params, 'raw_only', False))
|
self._get_param(params, 'raw_only', False))
|
||||||
|
|
||||||
@ -96,7 +126,16 @@ class HttpPublisher(publisher.ConfigPublisherBase):
|
|||||||
kwargs = {'max_retries': self.max_retries,
|
kwargs = {'max_retries': self.max_retries,
|
||||||
'pool_connections': pool_size, 'pool_maxsize': pool_size}
|
'pool_connections': pool_size, 'pool_maxsize': pool_size}
|
||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
# FIXME(gordc): support https in addition to http
|
|
||||||
|
# authentication & config params have been removed, so use URL with
|
||||||
|
# updated query string
|
||||||
|
self.target = urlparse.urlunsplit([
|
||||||
|
parsed_url.scheme,
|
||||||
|
netloc,
|
||||||
|
parsed_url.path,
|
||||||
|
urlparse.urlencode(params),
|
||||||
|
parsed_url.fragment])
|
||||||
|
|
||||||
self.session.mount(self.target, adapters.HTTPAdapter(**kwargs))
|
self.session.mount(self.target, adapters.HTTPAdapter(**kwargs))
|
||||||
|
|
||||||
LOG.debug('HttpPublisher for endpoint %s is initialized!' %
|
LOG.debug('HttpPublisher for endpoint %s is initialized!' %
|
||||||
@ -105,8 +144,8 @@ class HttpPublisher(publisher.ConfigPublisherBase):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_param(params, name, default_value, cast=None):
|
def _get_param(params, name, default_value, cast=None):
|
||||||
try:
|
try:
|
||||||
return cast(params.get(name)[-1]) if cast else params.get(name)[-1]
|
return cast(params.pop(name)[-1]) if cast else params.pop(name)[-1]
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError, KeyError):
|
||||||
LOG.debug('Default value %(value)s is used for %(name)s' %
|
LOG.debug('Default value %(value)s is used for %(name)s' %
|
||||||
{'value': default_value, 'name': name})
|
{'value': default_value, 'name': name})
|
||||||
return default_value
|
return default_value
|
||||||
@ -124,6 +163,8 @@ class HttpPublisher(publisher.ConfigPublisherBase):
|
|||||||
try:
|
try:
|
||||||
res = self.session.post(self.target, data=data,
|
res = self.session.post(self.target, data=data,
|
||||||
headers=self.headers, timeout=self.timeout,
|
headers=self.headers, timeout=self.timeout,
|
||||||
|
auth=self.client_auth,
|
||||||
|
cert=self.client_cert,
|
||||||
verify=self.verify_ssl)
|
verify=self.verify_ssl)
|
||||||
res.raise_for_status()
|
res.raise_for_status()
|
||||||
LOG.debug('Message posting to %s: status code %d.',
|
LOG.debug('Message posting to %s: status code %d.',
|
||||||
|
@ -232,6 +232,27 @@ class TestHttpPublisher(base.BaseTestCase):
|
|||||||
publisher.publish_samples(self.sample_data)
|
publisher.publish_samples(self.sample_data)
|
||||||
self.assertEqual('/path/to/cert.crt', post.call_args[1]['verify'])
|
self.assertEqual('/path/to/cert.crt', post.call_args[1]['verify'])
|
||||||
|
|
||||||
|
def test_post_basic_auth(self):
|
||||||
|
parsed_url = urlparse.urlparse(
|
||||||
|
'http://alice:l00kingGla$$@localhost:90/path1?')
|
||||||
|
publisher = http.HttpPublisher(self.CONF, parsed_url)
|
||||||
|
|
||||||
|
with mock.patch.object(requests.Session, 'post') as post:
|
||||||
|
publisher.publish_samples(self.sample_data)
|
||||||
|
self.assertEqual(('alice', 'l00kingGla$$'),
|
||||||
|
post.call_args[1]['auth'])
|
||||||
|
|
||||||
|
def test_post_client_cert_auth(self):
|
||||||
|
parsed_url = urlparse.urlparse('http://localhost:90/path1?'
|
||||||
|
'clientcert=/path/to/cert.crt&'
|
||||||
|
'clientkey=/path/to/cert.key')
|
||||||
|
publisher = http.HttpPublisher(self.CONF, parsed_url)
|
||||||
|
|
||||||
|
with mock.patch.object(requests.Session, 'post') as post:
|
||||||
|
publisher.publish_samples(self.sample_data)
|
||||||
|
self.assertEqual(('/path/to/cert.crt', '/path/to/cert.key'),
|
||||||
|
post.call_args[1]['cert'])
|
||||||
|
|
||||||
def test_post_raw_only(self):
|
def test_post_raw_only(self):
|
||||||
parsed_url = urlparse.urlparse('http://localhost:90/path1?raw_only=1')
|
parsed_url = urlparse.urlparse('http://localhost:90/path1?raw_only=1')
|
||||||
publisher = http.HttpPublisher(self.CONF, parsed_url)
|
publisher = http.HttpPublisher(self.CONF, parsed_url)
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- In the 'publishers' section of a meter/event pipeline definition, https://
|
||||||
|
can now be used in addition to http://. Furthermore, either Basic or
|
||||||
|
client-certificate authentication can be used (obviously, client cert only
|
||||||
|
makes sense in the https case).
|
||||||
|
For Basic authentication, use the form http://username:password@hostname/.
|
||||||
|
For client certificate authentication pass the client certificate's path
|
||||||
|
(and the key file path, if the key is not in the certificate file) using
|
||||||
|
the parameters 'clientcert' and 'clientkey', e.g.
|
||||||
|
https://hostname/path?clientcert=/path/to/cert&clientkey=/path/to/key.
|
||||||
|
Any parameters or credentials used for http(s) publishers are removed from
|
||||||
|
the URL before the actual HTTP request is made.
|
||||||
|
|
@ -231,6 +231,7 @@ ceilometer.sample.publisher =
|
|||||||
direct = ceilometer.publisher.direct:DirectPublisher
|
direct = ceilometer.publisher.direct:DirectPublisher
|
||||||
kafka = ceilometer.publisher.kafka_broker:KafkaBrokerPublisher
|
kafka = ceilometer.publisher.kafka_broker:KafkaBrokerPublisher
|
||||||
http = ceilometer.publisher.http:HttpPublisher
|
http = ceilometer.publisher.http:HttpPublisher
|
||||||
|
https = ceilometer.publisher.http:HttpPublisher
|
||||||
gnocchi = ceilometer.publisher.direct:DirectPublisher
|
gnocchi = ceilometer.publisher.direct:DirectPublisher
|
||||||
database = ceilometer.publisher.direct:DirectPublisher
|
database = ceilometer.publisher.direct:DirectPublisher
|
||||||
file_alt = ceilometer.publisher.direct:DirectPublisher
|
file_alt = ceilometer.publisher.direct:DirectPublisher
|
||||||
@ -242,6 +243,7 @@ ceilometer.event.publisher =
|
|||||||
notifier = ceilometer.publisher.messaging:EventNotifierPublisher
|
notifier = ceilometer.publisher.messaging:EventNotifierPublisher
|
||||||
kafka = ceilometer.publisher.kafka_broker:KafkaBrokerPublisher
|
kafka = ceilometer.publisher.kafka_broker:KafkaBrokerPublisher
|
||||||
http = ceilometer.publisher.http:HttpPublisher
|
http = ceilometer.publisher.http:HttpPublisher
|
||||||
|
https = ceilometer.publisher.http:HttpPublisher
|
||||||
gnocchi = ceilometer.publisher.direct:DirectPublisher
|
gnocchi = ceilometer.publisher.direct:DirectPublisher
|
||||||
database = ceilometer.publisher.direct:DirectPublisher
|
database = ceilometer.publisher.direct:DirectPublisher
|
||||||
file_alt = ceilometer.publisher.direct:DirectPublisher
|
file_alt = ceilometer.publisher.direct:DirectPublisher
|
||||||
|
Loading…
x
Reference in New Issue
Block a user