"Fossies" - the Fresh Open Source Software Archive

Member "cloudkitty-13.0.0/cloudkitty/collector/monasca.py" (14 Oct 2020, 8276 Bytes) of package /linux/misc/openstack/cloudkitty-13.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "monasca.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 12.1.0_vs_13.0.0.

    1 # -*- coding: utf-8 -*-
    2 # Copyright 2017 Objectif Libre
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 #
   16 from keystoneauth1 import loading as ks_loading
   17 from oslo_config import cfg
   18 from oslo_log import log as logging
   19 from voluptuous import All
   20 from voluptuous import In
   21 from voluptuous import Length
   22 from voluptuous import Required
   23 from voluptuous import Schema
   24 
   25 from cloudkitty import collector
   26 from cloudkitty.common import monasca_client as mon_client_utils
   27 from cloudkitty import dataframe
   28 from cloudkitty import utils as ck_utils
   29 
   30 LOG = logging.getLogger(__name__)
   31 
   32 MONASCA_API_VERSION = '2_0'
   33 COLLECTOR_MONASCA_OPTS = 'collector_monasca'
   34 
   35 collector_monasca_opts = [
   36     cfg.StrOpt(
   37         'interface',
   38         default='internal',
   39         help='Endpoint URL type (defaults to internal)',
   40     ),
   41     cfg.StrOpt(
   42         'monasca_service_name',
   43         default='monasca',
   44         help='Name of the Monasca service (defaults to monasca)',
   45     ),
   46 ]
   47 
   48 CONF = cfg.CONF
   49 
   50 CONF.register_opts(collector_monasca_opts, COLLECTOR_MONASCA_OPTS)
   51 ks_loading.register_auth_conf_options(CONF, COLLECTOR_MONASCA_OPTS)
   52 ks_loading.register_session_conf_options(CONF, COLLECTOR_MONASCA_OPTS)
   53 
   54 MONASCA_EXTRA_SCHEMA = {
   55     Required('extra_args', default={}): {
   56         # Key corresponding to the resource id in a metric's dimensions
   57         # Allows to adapt the resource identifier. Should not need to be
   58         # modified in a standard OpenStack installation
   59         Required('resource_key', default='resource_id'):
   60             All(str, Length(min=1)),
   61         Required('aggregation_method', default='max'):
   62             In(['max', 'mean', 'min']),
   63         # In case the metrics in Monasca do not belong to the project
   64         # cloudkitty is identified in
   65         Required('forced_project_id', default=''): str,
   66     },
   67 }
   68 
   69 
   70 class MonascaCollector(collector.BaseCollector):
   71     collector_name = 'monasca'
   72 
   73     @staticmethod
   74     def check_configuration(conf):
   75         conf = collector.BaseCollector.check_configuration(conf)
   76         metric_schema = Schema(collector.METRIC_BASE_SCHEMA).extend(
   77             MONASCA_EXTRA_SCHEMA)
   78 
   79         output = {}
   80         for metric_name, metric in conf.items():
   81             met = output[metric_name] = metric_schema(metric)
   82 
   83             if met['extra_args']['resource_key'] not in met['groupby']:
   84                 met['groupby'].append(met['extra_args']['resource_key'])
   85 
   86         return output
   87 
   88     def __init__(self, **kwargs):
   89         super(MonascaCollector, self).__init__(**kwargs)
   90         self._conn = mon_client_utils.get_monasca_client(
   91             CONF, COLLECTOR_MONASCA_OPTS)
   92 
   93     def _get_metadata(self, metric_name, conf):
   94         info = {}
   95         info['unit'] = conf['metrics'][metric_name]['unit']
   96 
   97         dimension_names = self._conn.metric.list_dimension_names(
   98             metric_name=metric_name)
   99         info['metadata'] = [d['dimension_name'] for d in dimension_names]
  100         return info
  101 
  102     # NOTE(lukapeschke) if anyone sees a better way to do this,
  103     # please make a patch
  104     @classmethod
  105     def get_metadata(cls, resource_type, conf):
  106         tmp = cls(period=conf['period'])
  107         return tmp._get_metadata(resource_type, conf)
  108 
  109     def _get_dimensions(self, metric_name, project_id, q_filter):
  110         dimensions = {}
  111         scope_key = CONF.collect.scope_key
  112         if project_id:
  113             dimensions[scope_key] = project_id
  114         if q_filter:
  115             dimensions.update(q_filter)
  116         return dimensions
  117 
  118     def _fetch_measures(self, metric_name, start, end,
  119                         project_id=None, q_filter=None):
  120         """Get measures for given metric during the timeframe.
  121 
  122         :param metric_name: metric name to filter on.
  123         :type metric_name: str
  124         :param start: Start of the timeframe.
  125         :param end: End of the timeframe if needed.
  126         :param project_id: Filter on a specific tenant/project.
  127         :type project_id: str
  128         :param q_filter: Append a custom filter.
  129         :type q_filter: list
  130         """
  131 
  132         dimensions = self._get_dimensions(metric_name, project_id, q_filter)
  133         group_by = self.conf[metric_name]['groupby']
  134 
  135         # NOTE(lpeschke): One aggregated measure per collect period
  136         period = int((end - start).total_seconds())
  137 
  138         extra_args = self.conf[metric_name]['extra_args']
  139         kwargs = {}
  140         if extra_args['forced_project_id']:
  141             if extra_args['forced_project_id'] == 'SCOPE_ID' and project_id:
  142                 kwargs['tenant_id'] = project_id
  143                 dimensions.pop(CONF.collect.scope_key, None)
  144             else:
  145                 kwargs['tenant_id'] = extra_args['forced_project_id']
  146 
  147         return self._conn.metrics.list_statistics(
  148             name=metric_name,
  149             merge_metrics=True,
  150             dimensions=dimensions,
  151             start_time=start,
  152             end_time=end,
  153             period=period,
  154             statistics=extra_args['aggregation_method'],
  155             group_by=group_by,
  156             **kwargs)
  157 
  158     def _fetch_metrics(self, metric_name, start, end,
  159                        project_id=None, q_filter=None):
  160         """List active metrics during the timeframe.
  161 
  162         :param metric_name: metric name to filter on.
  163         :type metric_name: str
  164         :param start: Start of the timeframe.
  165         :param end: End of the timeframe if needed.
  166         :param project_id: Filter on a specific tenant/project.
  167         :type project_id: str
  168         :param q_filter: Append a custom filter.
  169         :type q_filter: list
  170         """
  171         dimensions = self._get_dimensions(metric_name, project_id, q_filter)
  172         metrics = self._conn.metrics.list(
  173             name=metric_name,
  174             dimensions=dimensions,
  175             start_time=start,
  176             end_time=end,
  177         )
  178 
  179         resource_key = self.conf[metric_name]['extra_args']['resource_key']
  180 
  181         return {metric['dimensions'][resource_key]:
  182                 metric['dimensions'] for metric in metrics}
  183 
  184     def _format_data(self, metconf, data, resources_info=None):
  185         """Formats Monasca data to CK data.
  186 
  187         Returns metadata, groupby and qty
  188 
  189         """
  190         groupby = data['dimensions']
  191 
  192         resource_key = metconf['extra_args']['resource_key']
  193         metadata = dict()
  194         if resources_info:
  195             resource = resources_info[groupby[resource_key]]
  196             for i in metconf['metadata']:
  197                 metadata[i] = resource.get(i, '')
  198 
  199         qty = data['statistics'][0][1]
  200         converted_qty = ck_utils.convert_unit(
  201             qty, metconf['factor'], metconf['offset'])
  202         mutated_qty = ck_utils.mutate(converted_qty, metconf['mutate'])
  203         return metadata, groupby, mutated_qty
  204 
  205     def fetch_all(self, metric_name, start, end,
  206                   project_id=None, q_filter=None):
  207         met = self.conf[metric_name]
  208 
  209         data = self._fetch_measures(
  210             metric_name,
  211             start,
  212             end,
  213             project_id=project_id,
  214             q_filter=q_filter,
  215         )
  216 
  217         resources_info = None
  218         if met['metadata']:
  219             resources_info = self._fetch_metrics(
  220                 metric_name,
  221                 start,
  222                 end,
  223                 project_id=project_id,
  224                 q_filter=q_filter,
  225             )
  226 
  227         formated_resources = list()
  228         for d in data:
  229             if len(d['statistics']):
  230                 metadata, groupby, qty = self._format_data(
  231                     met, d, resources_info)
  232                 formated_resources.append(dataframe.DataPoint(
  233                     met['unit'],
  234                     qty,
  235                     0,
  236                     groupby,
  237                     metadata,
  238                 ))
  239         return formated_resources