From 84bf48431c2b3cdee47dbb6bb46cf808ac79cf99 Mon Sep 17 00:00:00 2001 From: Jay Faulkner Date: Tue, 5 Apr 2016 21:03:50 +0000 Subject: [PATCH] Pass agent metrics config via conductor This adds agent config options for metrics as described in the spec, and allows those config options to be sent to IPA on lookup. We're configuring heartbeat timeout this way, and this change matches nicely with that style. Additionally, this sets heartbeat_timeout under the new config namespace for consistency, however, we'll allow the old way to be deprecated when the vendor_passthru for agent lookups is deprecated. Change-Id: I94d81b95feabe46999dbbc02522508cd542a89f8 Co-Authored-By: Josh Gachnang Partial-bug: #1526219 --- etc/ironic/ironic.conf.sample | 46 ++++++++++++++++ ironic/conf/__init__.py | 4 ++ ironic/conf/metrics.py | 55 +++++++++++++++++++ ironic/conf/metrics_statsd.py | 36 ++++++++++++ ironic/conf/opts.py | 2 + ironic/drivers/modules/agent_base_vendor.py | 23 ++++++++ .../drivers/modules/test_agent_base_vendor.py | 22 ++++++++ ...g-to-agent-on-lookup-6db9ae187c4e8151.yaml | 7 +++ 8 files changed, 195 insertions(+) create mode 100644 ironic/conf/metrics.py create mode 100644 ironic/conf/metrics_statsd.py create mode 100644 releasenotes/notes/pass-metrics-config-to-agent-on-lookup-6db9ae187c4e8151.yaml diff --git a/etc/ironic/ironic.conf.sample b/etc/ironic/ironic.conf.sample index b4b4937b65..998f29a7e7 100644 --- a/etc/ironic/ironic.conf.sample +++ b/etc/ironic/ironic.conf.sample @@ -1538,6 +1538,37 @@ [metrics] +# +# From ironic +# + +# Backend for the agent ramdisk to use for metrics. Default +# possible backends are "noop" and "statsd". (string value) +#agent_backend = noop + +# Prepend the hostname to all metric names sent by the agent +# ramdisk. The format of metric names is +# [global_prefix.][uuid.][host_name.]prefix.metric_name. +# (boolean value) +#agent_prepend_host = false + +# Prepend the node's Ironic uuid to all metric names sent by +# the agent ramdisk. The format of metric names is +# [global_prefix.][uuid.][host_name.]prefix.metric_name. +# (boolean value) +#agent_prepend_uuid = false + +# Split the prepended host value by "." and reverse it for +# metrics sent by the agent ramdisk (to better match the +# reverse hierarchical form of domain names). (boolean value) +#agent_prepend_host_reverse = true + +# Prefix all metric names sent by the agent ramdisk with this +# value. The format of metric names is +# [global_prefix.][uuid.][host_name.]prefix.metric_name. +# (string value) +#agent_global_prefix = + # # From ironic_lib.metrics # @@ -1566,6 +1597,21 @@ [metrics_statsd] +# +# From ironic +# + +# Host for the agent ramdisk to use with the statsd backend. +# This must be accessible from networks the agent is booted +# on. (string value) +#agent_statsd_host = localhost + +# Port for the agent ramdisk to use with the statsd backend. +# (port value) +# Minimum value: 0 +# Maximum value: 65535 +#agent_statsd_port = 8125 + # # From ironic_lib.metrics_statsd # diff --git a/ironic/conf/__init__.py b/ironic/conf/__init__.py index a9dd7fc990..1ec5ee33c8 100644 --- a/ironic/conf/__init__.py +++ b/ironic/conf/__init__.py @@ -33,6 +33,8 @@ from ironic.conf import inspector from ironic.conf import ipmi from ironic.conf import irmc from ironic.conf import keystone +from ironic.conf import metrics +from ironic.conf import metrics_statsd from ironic.conf import neutron from ironic.conf import oneview from ironic.conf import seamicro @@ -61,6 +63,8 @@ inspector.register_opts(CONF) ipmi.register_opts(CONF) irmc.register_opts(CONF) keystone.register_opts(CONF) +metrics.register_opts(CONF) +metrics_statsd.register_opts(CONF) neutron.register_opts(CONF) oneview.register_opts(CONF) seamicro.register_opts(CONF) diff --git a/ironic/conf/metrics.py b/ironic/conf/metrics.py new file mode 100644 index 0000000000..8f64c00faa --- /dev/null +++ b/ironic/conf/metrics.py @@ -0,0 +1,55 @@ +# Copyright 2016 Intel Corporation +# Copyright 2014 Rackspace, Inc. +# Copyright 2015 Red Hat, Inc. +# +# 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 oslo_config import cfg + +from ironic.common.i18n import _ + + +opts = [ + # IPA config options: used by IPA to configure how it reports metric data + cfg.StrOpt('agent_backend', + default='noop', + help=_('Backend for the agent ramdisk to use for metrics. ' + 'Default possible backends are "noop" and "statsd".')), + cfg.BoolOpt('agent_prepend_host', + default=False, + help=_('Prepend the hostname to all metric names sent by the ' + 'agent ramdisk. The format of metric names is ' + '[global_prefix.][uuid.][host_name.]prefix.' + 'metric_name.')), + cfg.BoolOpt('agent_prepend_uuid', + default=False, + help=_('Prepend the node\'s Ironic uuid to all metric names ' + 'sent by the agent ramdisk. The format of metric names ' + 'is [global_prefix.][uuid.][host_name.]prefix.' + 'metric_name.')), + cfg.BoolOpt('agent_prepend_host_reverse', + default=True, + help=_('Split the prepended host value by "." and reverse it ' + 'for metrics sent by the agent ramdisk (to better ' + 'match the reverse hierarchical form of domain ' + 'names).')), + cfg.StrOpt('agent_global_prefix', + help=_('Prefix all metric names sent by the agent ramdisk ' + 'with this value. The format of metric names is ' + '[global_prefix.][uuid.][host_name.]prefix.' + 'metric_name.')) +] + + +def register_opts(conf): + conf.register_opts(opts, group='metrics') diff --git a/ironic/conf/metrics_statsd.py b/ironic/conf/metrics_statsd.py new file mode 100644 index 0000000000..c1d3fc11dd --- /dev/null +++ b/ironic/conf/metrics_statsd.py @@ -0,0 +1,36 @@ +# Copyright 2016 Intel Corporation +# Copyright 2014 Rackspace, Inc. +# Copyright 2015 Red Hat, Inc. +# +# 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 oslo_config import cfg + +from ironic.common.i18n import _ + + +opts = [ + cfg.StrOpt('agent_statsd_host', + default='localhost', + help=_('Host for the agent ramdisk to use with the statsd ' + 'backend. This must be accessible from networks the ' + 'agent is booted on.')), + cfg.PortOpt('agent_statsd_port', + default=8125, + help=_('Port for the agent ramdisk to use with the statsd ' + 'backend.')), +] + + +def register_opts(conf): + conf.register_opts(opts, group='metrics_statsd') diff --git a/ironic/conf/opts.py b/ironic/conf/opts.py index 4eae792bbe..18d608791c 100644 --- a/ironic/conf/opts.py +++ b/ironic/conf/opts.py @@ -54,6 +54,8 @@ _opts = [ ('iscsi', ironic.drivers.modules.iscsi_deploy.iscsi_opts), ('keystone', ironic.conf.keystone.opts), ('neutron', ironic.conf.neutron.opts), + ('metrics', ironic.conf.metrics.opts), + ('metrics_statsd', ironic.conf.metrics_statsd.opts), ('oneview', ironic.conf.oneview.opts), ('pxe', itertools.chain( ironic.drivers.modules.iscsi_deploy.pxe_opts, diff --git a/ironic/drivers/modules/agent_base_vendor.py b/ironic/drivers/modules/agent_base_vendor.py index ec2092573d..51a6fc40e0 100644 --- a/ironic/drivers/modules/agent_base_vendor.py +++ b/ironic/drivers/modules/agent_base_vendor.py @@ -729,6 +729,10 @@ class BaseAgentVendor(AgentDeployMixin, base.VendorInterface): Currently, we don't handle the instance where the agent doesn't have a matching node (i.e. a brand new, never been in Ironic node). + Additionally, we may pass on useful configurations to the agent, which + it would then be responsible for applying if relevant. Today these are + limited to heartbeat_timeout and metrics configuration. + kwargs should have the following format:: { @@ -781,8 +785,27 @@ class BaseAgentVendor(AgentDeployMixin, base.VendorInterface): strutils.mask_password(ndict['driver_info'], "******")) return { + # heartbeat_timeout is a config, so moving it into the + # config namespace. Instead of a separate deprecation, + # this will die when the vendor_passthru version of + # lookup goes away. 'heartbeat_timeout': CONF.agent.heartbeat_timeout, 'node': ndict, + 'config': { + 'metrics': { + 'backend': CONF.metrics.agent_backend, + 'prepend_host': CONF.metrics.agent_prepend_host, + 'prepend_uuid': CONF.metrics.agent_prepend_uuid, + 'prepend_host_reverse': + CONF.metrics.agent_prepend_host_reverse, + 'global_prefix': CONF.metrics.agent_global_prefix + }, + 'metrics_statsd': { + 'statsd_host': CONF.metrics_statsd.agent_statsd_host, + 'statsd_port': CONF.metrics_statsd.agent_statsd_port + }, + 'heartbeat_timeout': CONF.agent.heartbeat_timeout + } } def _get_interfaces(self, inventory): diff --git a/ironic/tests/unit/drivers/modules/test_agent_base_vendor.py b/ironic/tests/unit/drivers/modules/test_agent_base_vendor.py index 389b9f0bc6..78791bc58b 100644 --- a/ironic/tests/unit/drivers/modules/test_agent_base_vendor.py +++ b/ironic/tests/unit/drivers/modules/test_agent_base_vendor.py @@ -20,6 +20,7 @@ import time import types import mock +from oslo_config import cfg from ironic.common import boot_devices from ironic.common import exception @@ -37,6 +38,8 @@ from ironic.tests.unit.db import base as db_base from ironic.tests.unit.db import utils as db_utils from ironic.tests.unit.objects import utils as object_utils +CONF = cfg.CONF + INSTANCE_INFO = db_utils.get_test_agent_instance_info() DRIVER_INFO = db_utils.get_test_agent_driver_info() DRIVER_INTERNAL_INFO = db_utils.get_test_agent_driver_internal_info() @@ -114,10 +117,29 @@ class TestBaseAgentVendor(db_base.DbTestCase): expected = copy.deepcopy(self.node.as_dict()) if not show_password: expected['driver_info']['ipmi_password'] = '******' + + self.config(agent_backend='statsd', group='metrics') + expected_metrics = { + 'metrics': { + 'backend': 'statsd', + 'prepend_host': CONF.metrics.agent_prepend_host, + 'prepend_uuid': CONF.metrics.agent_prepend_uuid, + 'prepend_host_reverse': + CONF.metrics.agent_prepend_host_reverse, + 'global_prefix': CONF.metrics.agent_global_prefix + }, + 'metrics_statsd': { + 'statsd_host': CONF.metrics_statsd.agent_statsd_host, + 'statsd_port': CONF.metrics_statsd.agent_statsd_port + }, + 'heartbeat_timeout': CONF.agent.heartbeat_timeout + } + find_mock.return_value = self.node with task_manager.acquire(self.context, self.node.uuid) as task: node = self.passthru.lookup(task.context, **kwargs) self.assertEqual(expected, node['node']) + self.assertEqual(expected_metrics, node['config']) def test_lookup_v2_show_password(self): self._test_lookup_v2(show_password=True) diff --git a/releasenotes/notes/pass-metrics-config-to-agent-on-lookup-6db9ae187c4e8151.yaml b/releasenotes/notes/pass-metrics-config-to-agent-on-lookup-6db9ae187c4e8151.yaml new file mode 100644 index 0000000000..08b908c207 --- /dev/null +++ b/releasenotes/notes/pass-metrics-config-to-agent-on-lookup-6db9ae187c4e8151.yaml @@ -0,0 +1,7 @@ +--- +features: + - Adds the ability for ironic conductor to pass + configurations for agent metrics on lookup. + When paired with a sufficiently new ironic + python agent, this will configure the metrics + backends.