Source code for ceilometer.api.controllers.v2.root
#
# Copyright 2012 New Dream Network, LLC (DreamHost)
# Copyright 2013 IBM Corp.
# Copyright 2013 eNovance <licensing@enovance.com>
# Copyright Ericsson AB 2013. All rights reserved
# Copyright 2014 Hewlett-Packard Company
# Copyright 2015 Huawei Technologies Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from keystoneauth1 import exceptions
from oslo_config import cfg
from oslo_log import log
from oslo_utils import strutils
import pecan
from ceilometer.api.controllers.v2 import capabilities
from ceilometer.api.controllers.v2 import meters
from ceilometer.api.controllers.v2 import query
from ceilometer.api.controllers.v2 import resources
from ceilometer.api.controllers.v2 import samples
from ceilometer.i18n import _, _LW
from ceilometer import keystone_client
API_OPTS = [
cfg.BoolOpt('gnocchi_is_enabled',
help=('Set True to disable resource/meter/sample URLs. '
'Default autodetection by querying keystone.')),
cfg.BoolOpt('aodh_is_enabled',
help=('Set True to redirect alarms URLs to aodh. '
'Default autodetection by querying keystone.')),
cfg.StrOpt('aodh_url',
help=('The endpoint of Aodh to redirect alarms URLs '
'to Aodh API. Default autodetection by querying '
'keystone.')),
cfg.BoolOpt('panko_is_enabled',
help=('Set True to redirect events URLs to Panko. '
'Default autodetection by querying keystone.')),
cfg.StrOpt('panko_url',
help=('The endpoint of Panko to redirect events URLs '
'to Panko API. Default autodetection by querying '
'keystone.')),
]
LOG = log.getLogger(__name__)
def gnocchi_abort():
pecan.abort(410, ("This telemetry installation is configured to use "
"Gnocchi. Please use the Gnocchi API available on "
"the metric endpoint to retrieve data."))
def aodh_abort():
pecan.abort(410, _("alarms URLs is unavailable when Aodh is "
"disabled or unavailable."))
def _redirect(url):
pecan.redirect(location=url + pecan.request.path_qs,
code=308)
[docs]class QueryController(object):
def __init__(self, gnocchi_is_enabled=False,
aodh_url=None):
self.gnocchi_is_enabled = gnocchi_is_enabled
self.aodh_url = aodh_url
@pecan.expose()
def _lookup(self, kind, *remainder):
if kind == 'alarms' and self.aodh_url:
_redirect(self.aodh_url)
elif kind == 'alarms':
aodh_abort()
elif kind == 'samples' and self.gnocchi_is_enabled:
gnocchi_abort()
elif kind == 'samples':
return query.QuerySamplesController(), remainder
else:
pecan.abort(404)
[docs]class V2Controller(object):
"""Version 2 API controller root."""
capabilities = capabilities.CapabilitiesController()
def __init__(self):
self._gnocchi_is_enabled = None
self._aodh_is_enabled = None
self._aodh_url = None
self._panko_is_enabled = None
self._panko_url = None
@property
def gnocchi_is_enabled(self):
if self._gnocchi_is_enabled is None:
if pecan.request.cfg.api.gnocchi_is_enabled is not None:
self._gnocchi_is_enabled = (
pecan.request.cfg.api.gnocchi_is_enabled)
elif ("gnocchi" not in pecan.request.cfg.meter_dispatchers
or "database" in pecan.request.cfg.meter_dispatchers):
self._gnocchi_is_enabled = False
else:
try:
catalog = keystone_client.get_service_catalog(
keystone_client.get_client(pecan.request.cfg))
catalog.url_for(service_type='metric')
except exceptions.EndpointNotFound:
self._gnocchi_is_enabled = False
except exceptions.ClientException:
LOG.warning(_LW("Can't connect to keystone, assuming "
"gnocchi is disabled and retry later"))
else:
self._gnocchi_is_enabled = True
LOG.warning(_LW("ceilometer-api started with gnocchi "
"enabled. The resources/meters/samples "
"URLs are disabled."))
return self._gnocchi_is_enabled
@property
def aodh_url(self):
if self._aodh_url is None:
if pecan.request.cfg.api.aodh_is_enabled is False:
self._aodh_url = ""
elif pecan.request.cfg.api.aodh_url is not None:
self._aodh_url = self._normalize_url(
pecan.request.cfg.api.aodh_url)
else:
try:
catalog = keystone_client.get_service_catalog(
keystone_client.get_client(pecan.request.cfg))
self._aodh_url = self._normalize_url(
catalog.url_for(service_type='alarming'))
except exceptions.EndpointNotFound:
self._aodh_url = ""
except exceptions.ClientException:
LOG.warning(_LW("Can't connect to keystone, assuming aodh "
"is disabled and retry later."))
else:
LOG.warning(_LW("ceilometer-api started with aodh "
"enabled. Alarms URLs will be redirected "
"to aodh endpoint."))
return self._aodh_url
@property
def panko_url(self):
if self._panko_url is None:
if pecan.request.cfg.api.panko_is_enabled is False:
self._panko_url = ""
elif pecan.request.cfg.api.panko_url is not None:
self._panko_url = self._normalize_url(
pecan.request.cfg.api.panko_url)
else:
try:
catalog = keystone_client.get_service_catalog(
keystone_client.get_client(pecan.request.cfg))
self._panko_url = self._normalize_url(
catalog.url_for(service_type='event'))
except exceptions.EndpointNotFound:
self._panko_url = ""
except exceptions.ClientException:
LOG.warning(
_LW("Can't connect to keystone, assuming Panko "
"is disabled and retry later."))
else:
LOG.warning(_LW("ceilometer-api started with Panko "
"enabled. Events URLs will be redirected "
"to Panko endpoint."))
return self._panko_url
@pecan.expose()
def _lookup(self, kind, *remainder):
if (kind in ['meters', 'resources', 'samples']
and self.gnocchi_is_enabled):
if kind == 'meters' and pecan.request.method == 'POST':
direct = pecan.request.params.get('direct', '')
if strutils.bool_from_string(direct):
pecan.abort(400, _('direct option cannot be true when '
'Gnocchi is enabled.'))
return meters.MetersController(), remainder
gnocchi_abort()
elif kind == 'meters':
return meters.MetersController(), remainder
elif kind == 'resources':
return resources.ResourcesController(), remainder
elif kind == 'samples':
return samples.SamplesController(), remainder
elif kind == 'query':
return QueryController(
gnocchi_is_enabled=self.gnocchi_is_enabled,
aodh_url=self.aodh_url,
), remainder
elif kind == 'alarms' and (not self.aodh_url):
aodh_abort()
elif kind == 'alarms' and self.aodh_url:
_redirect(self.aodh_url)
elif kind == 'events' and self.panko_url:
return _redirect(self.panko_url)
elif kind == 'event_types' and self.panko_url:
return _redirect(self.panko_url)
else:
pecan.abort(404)
@staticmethod
def _normalize_url(url):
if url.endswith("/"):
return url[:-1]
return url