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 <josh@pcsforeducation.com> Partial-bug: #1526219
This commit is contained in:
parent
88303cc56c
commit
84bf48431c
@ -1538,6 +1538,37 @@
|
|||||||
|
|
||||||
[metrics]
|
[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 = <None>
|
||||||
|
|
||||||
#
|
#
|
||||||
# From ironic_lib.metrics
|
# From ironic_lib.metrics
|
||||||
#
|
#
|
||||||
@ -1566,6 +1597,21 @@
|
|||||||
|
|
||||||
[metrics_statsd]
|
[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
|
# From ironic_lib.metrics_statsd
|
||||||
#
|
#
|
||||||
|
@ -33,6 +33,8 @@ from ironic.conf import inspector
|
|||||||
from ironic.conf import ipmi
|
from ironic.conf import ipmi
|
||||||
from ironic.conf import irmc
|
from ironic.conf import irmc
|
||||||
from ironic.conf import keystone
|
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 neutron
|
||||||
from ironic.conf import oneview
|
from ironic.conf import oneview
|
||||||
from ironic.conf import seamicro
|
from ironic.conf import seamicro
|
||||||
@ -61,6 +63,8 @@ inspector.register_opts(CONF)
|
|||||||
ipmi.register_opts(CONF)
|
ipmi.register_opts(CONF)
|
||||||
irmc.register_opts(CONF)
|
irmc.register_opts(CONF)
|
||||||
keystone.register_opts(CONF)
|
keystone.register_opts(CONF)
|
||||||
|
metrics.register_opts(CONF)
|
||||||
|
metrics_statsd.register_opts(CONF)
|
||||||
neutron.register_opts(CONF)
|
neutron.register_opts(CONF)
|
||||||
oneview.register_opts(CONF)
|
oneview.register_opts(CONF)
|
||||||
seamicro.register_opts(CONF)
|
seamicro.register_opts(CONF)
|
||||||
|
55
ironic/conf/metrics.py
Normal file
55
ironic/conf/metrics.py
Normal file
@ -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')
|
36
ironic/conf/metrics_statsd.py
Normal file
36
ironic/conf/metrics_statsd.py
Normal file
@ -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')
|
@ -54,6 +54,8 @@ _opts = [
|
|||||||
('iscsi', ironic.drivers.modules.iscsi_deploy.iscsi_opts),
|
('iscsi', ironic.drivers.modules.iscsi_deploy.iscsi_opts),
|
||||||
('keystone', ironic.conf.keystone.opts),
|
('keystone', ironic.conf.keystone.opts),
|
||||||
('neutron', ironic.conf.neutron.opts),
|
('neutron', ironic.conf.neutron.opts),
|
||||||
|
('metrics', ironic.conf.metrics.opts),
|
||||||
|
('metrics_statsd', ironic.conf.metrics_statsd.opts),
|
||||||
('oneview', ironic.conf.oneview.opts),
|
('oneview', ironic.conf.oneview.opts),
|
||||||
('pxe', itertools.chain(
|
('pxe', itertools.chain(
|
||||||
ironic.drivers.modules.iscsi_deploy.pxe_opts,
|
ironic.drivers.modules.iscsi_deploy.pxe_opts,
|
||||||
|
@ -729,6 +729,10 @@ class BaseAgentVendor(AgentDeployMixin, base.VendorInterface):
|
|||||||
Currently, we don't handle the instance where the agent doesn't have
|
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).
|
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::
|
kwargs should have the following format::
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -781,8 +785,27 @@ class BaseAgentVendor(AgentDeployMixin, base.VendorInterface):
|
|||||||
strutils.mask_password(ndict['driver_info'], "******"))
|
strutils.mask_password(ndict['driver_info'], "******"))
|
||||||
|
|
||||||
return {
|
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,
|
'heartbeat_timeout': CONF.agent.heartbeat_timeout,
|
||||||
'node': ndict,
|
'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):
|
def _get_interfaces(self, inventory):
|
||||||
|
@ -20,6 +20,7 @@ import time
|
|||||||
import types
|
import types
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
from ironic.common import boot_devices
|
from ironic.common import boot_devices
|
||||||
from ironic.common import exception
|
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.db import utils as db_utils
|
||||||
from ironic.tests.unit.objects import utils as object_utils
|
from ironic.tests.unit.objects import utils as object_utils
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
INSTANCE_INFO = db_utils.get_test_agent_instance_info()
|
INSTANCE_INFO = db_utils.get_test_agent_instance_info()
|
||||||
DRIVER_INFO = db_utils.get_test_agent_driver_info()
|
DRIVER_INFO = db_utils.get_test_agent_driver_info()
|
||||||
DRIVER_INTERNAL_INFO = db_utils.get_test_agent_driver_internal_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())
|
expected = copy.deepcopy(self.node.as_dict())
|
||||||
if not show_password:
|
if not show_password:
|
||||||
expected['driver_info']['ipmi_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
|
find_mock.return_value = self.node
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
node = self.passthru.lookup(task.context, **kwargs)
|
node = self.passthru.lookup(task.context, **kwargs)
|
||||||
self.assertEqual(expected, node['node'])
|
self.assertEqual(expected, node['node'])
|
||||||
|
self.assertEqual(expected_metrics, node['config'])
|
||||||
|
|
||||||
def test_lookup_v2_show_password(self):
|
def test_lookup_v2_show_password(self):
|
||||||
self._test_lookup_v2(show_password=True)
|
self._test_lookup_v2(show_password=True)
|
||||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user