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.