Automatic discovery of TripleO Overcloud hardware
-geting IP addresses from Undercloud nova, allowing to poll all Overcloud nodes via SNMP -adding support of basic auth, user_name and password used in TripleO by default Change-Id: I189dbba9579055c8a1a878a769760a72e9174c6d
This commit is contained in:
parent
1f87c36a67
commit
670736a2b6
|
@ -0,0 +1,62 @@
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# 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 ceilometer import nova_client
|
||||||
|
from ceilometer.openstack.common.gettextutils import _
|
||||||
|
from ceilometer.openstack.common import log
|
||||||
|
from ceilometer import plugin
|
||||||
|
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
OPTS = [
|
||||||
|
cfg.StrOpt('url_scheme',
|
||||||
|
default='snmp://',
|
||||||
|
help='URL scheme to use for hardware nodes'),
|
||||||
|
cfg.StrOpt('readonly_user_name',
|
||||||
|
default='ro_snmp_user',
|
||||||
|
help='SNMPd user name of all nodes running in the cloud.'),
|
||||||
|
cfg.StrOpt('readonly_user_password',
|
||||||
|
default='password',
|
||||||
|
help='SNMPd password of all the nodes running in the cloud'),
|
||||||
|
]
|
||||||
|
cfg.CONF.register_opts(OPTS, group='hardware')
|
||||||
|
|
||||||
|
|
||||||
|
class NodesDiscoveryTripleO(plugin.DiscoveryBase):
|
||||||
|
def __init__(self):
|
||||||
|
super(NodesDiscoveryTripleO, self).__init__()
|
||||||
|
self.nova_cli = nova_client.Client()
|
||||||
|
|
||||||
|
def discover(self, param=None):
|
||||||
|
"""Discover resources to monitor."""
|
||||||
|
|
||||||
|
instances = self.nova_cli.instance_get_all()
|
||||||
|
ip_addresses = []
|
||||||
|
for instance in instances:
|
||||||
|
try:
|
||||||
|
ip_address = instance.addresses['ctlplane'][0]['addr']
|
||||||
|
final_address = (
|
||||||
|
cfg.CONF.hardware.url_scheme +
|
||||||
|
cfg.CONF.hardware.readonly_user_name + ':' +
|
||||||
|
cfg.CONF.hardware.readonly_user_password + '@' +
|
||||||
|
ip_address)
|
||||||
|
ip_addresses.append(final_address)
|
||||||
|
except KeyError:
|
||||||
|
LOG.error(_("Couldn't obtain IP address of"
|
||||||
|
"instance %s") % instance.id)
|
||||||
|
|
||||||
|
return ip_addresses
|
|
@ -18,7 +18,6 @@
|
||||||
"""Inspector for collecting data over SNMP"""
|
"""Inspector for collecting data over SNMP"""
|
||||||
|
|
||||||
from pysnmp.entity.rfc3413.oneliner import cmdgen
|
from pysnmp.entity.rfc3413.oneliner import cmdgen
|
||||||
from six.moves.urllib import parse as urlparse
|
|
||||||
|
|
||||||
from ceilometer.hardware.inspector import base
|
from ceilometer.hardware.inspector import base
|
||||||
|
|
||||||
|
@ -73,9 +72,8 @@ class SNMPInspector(base.Inspector):
|
||||||
_interface_received_oid = "1.3.6.1.2.1.2.2.1.10"
|
_interface_received_oid = "1.3.6.1.2.1.2.2.1.10"
|
||||||
_interface_transmitted_oid = "1.3.6.1.2.1.2.2.1.16"
|
_interface_transmitted_oid = "1.3.6.1.2.1.2.2.1.16"
|
||||||
_interface_error_oid = "1.3.6.1.2.1.2.2.1.20"
|
_interface_error_oid = "1.3.6.1.2.1.2.2.1.20"
|
||||||
# Default port and security name
|
# Default port
|
||||||
_port = 161
|
_port = 161
|
||||||
_security_name = 'public'
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(SNMPInspector, self).__init__()
|
super(SNMPInspector, self).__init__()
|
||||||
|
@ -88,7 +86,8 @@ class SNMPInspector(base.Inspector):
|
||||||
else:
|
else:
|
||||||
func = self._cmdGen.nextCmd
|
func = self._cmdGen.nextCmd
|
||||||
ret_func = lambda x: x
|
ret_func = lambda x: x
|
||||||
ret = func(cmdgen.CommunityData(self._get_security_name(host)),
|
|
||||||
|
ret = func(self._get_auth_strategy(host),
|
||||||
cmdgen.UdpTransportTarget((host.hostname,
|
cmdgen.UdpTransportTarget((host.hostname,
|
||||||
host.port or self._port)),
|
host.port or self._port)),
|
||||||
oid)
|
oid)
|
||||||
|
@ -100,6 +99,15 @@ class SNMPInspector(base.Inspector):
|
||||||
else:
|
else:
|
||||||
return ret_func(data)
|
return ret_func(data)
|
||||||
|
|
||||||
|
def _get_auth_strategy(self, host):
|
||||||
|
if host.password:
|
||||||
|
auth_strategy = cmdgen.UsmUserData(host.username,
|
||||||
|
authKey=host.password)
|
||||||
|
else:
|
||||||
|
auth_strategy = cmdgen.CommunityData(host.username or 'public')
|
||||||
|
|
||||||
|
return auth_strategy
|
||||||
|
|
||||||
def _get_value_from_oid(self, oid, host):
|
def _get_value_from_oid(self, oid, host):
|
||||||
return self._get_or_walk_oid(oid, host, True)
|
return self._get_or_walk_oid(oid, host, True)
|
||||||
|
|
||||||
|
@ -186,10 +194,6 @@ class SNMPInspector(base.Inspector):
|
||||||
error=int(error))
|
error=int(error))
|
||||||
yield (interface, stats)
|
yield (interface, stats)
|
||||||
|
|
||||||
def _get_security_name(self, host):
|
|
||||||
options = urlparse.parse_qs(host.query)
|
|
||||||
return options.get('security_name', [self._security_name])[-1]
|
|
||||||
|
|
||||||
def _get_ip_for_interface(self, host, interface_id):
|
def _get_ip_for_interface(self, host, interface_id):
|
||||||
ip_addresses = self._walk_oid(self._interface_ip_oid, host)
|
ip_addresses = self._walk_oid(self._interface_ip_oid, host)
|
||||||
for ip in ip_addresses:
|
for ip in ip_addresses:
|
||||||
|
|
|
@ -131,6 +131,14 @@ class Client(object):
|
||||||
detailed=True,
|
detailed=True,
|
||||||
search_opts=search_opts))
|
search_opts=search_opts))
|
||||||
|
|
||||||
|
@logged
|
||||||
|
def instance_get_all(self):
|
||||||
|
"""Returns list of all instances."""
|
||||||
|
search_opts = {'all_tenants': True}
|
||||||
|
return self.nova_client.servers.list(
|
||||||
|
detailed=True,
|
||||||
|
search_opts=search_opts)
|
||||||
|
|
||||||
@logged
|
@logged
|
||||||
def floating_ip_get_all(self):
|
def floating_ip_get_all(self):
|
||||||
"""Returns all floating ips."""
|
"""Returns all floating ips."""
|
||||||
|
|
|
@ -214,13 +214,6 @@ class TestSNMPInspector(Base, test_base.BaseTestCase):
|
||||||
self.useFixture(mockpatch.PatchObject(
|
self.useFixture(mockpatch.PatchObject(
|
||||||
self.inspector._cmdGen, 'nextCmd', new=faux_nextCmd))
|
self.inspector._cmdGen, 'nextCmd', new=faux_nextCmd))
|
||||||
|
|
||||||
def test_get_security_name(self):
|
|
||||||
self.assertEqual(self.inspector._get_security_name(self.host),
|
|
||||||
self.inspector._security_name)
|
|
||||||
host2 = network_utils.urlsplit("snmp://foo:80?security_name=fake")
|
|
||||||
self.assertEqual(self.inspector._get_security_name(host2),
|
|
||||||
'fake')
|
|
||||||
|
|
||||||
def test_get_cmd_error(self):
|
def test_get_cmd_error(self):
|
||||||
self.useFixture(mockpatch.PatchObject(
|
self.useFixture(mockpatch.PatchObject(
|
||||||
self.inspector, '_memory_total_oid', new='failure'))
|
self.inspector, '_memory_total_oid', new='failure'))
|
||||||
|
|
|
@ -96,6 +96,16 @@ class TestNovaClient(test.BaseTestCase):
|
||||||
self.assertEqual(11, instances[0].kernel_id)
|
self.assertEqual(11, instances[0].kernel_id)
|
||||||
self.assertEqual(21, instances[0].ramdisk_id)
|
self.assertEqual(21, instances[0].ramdisk_id)
|
||||||
|
|
||||||
|
def test_instance_get_all(self):
|
||||||
|
with mock.patch.object(self.nv.nova_client.servers, 'list',
|
||||||
|
side_effect=self.fake_servers_list):
|
||||||
|
instances = self.nv.instance_get_all()
|
||||||
|
|
||||||
|
self.assertEqual(2, len(instances))
|
||||||
|
self.assertEqual(42, instances[0].id)
|
||||||
|
self.assertEqual(1, instances[0].flavor['id'])
|
||||||
|
self.assertEqual(1, instances[0].image['id'])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fake_servers_list_unknown_flavor(*args, **kwargs):
|
def fake_servers_list_unknown_flavor(*args, **kwargs):
|
||||||
a = mock.MagicMock()
|
a = mock.MagicMock()
|
||||||
|
|
|
@ -81,6 +81,7 @@ ceilometer.discover =
|
||||||
ipsec_connections = ceilometer.network.services.discovery:IPSecConnectionsDiscovery
|
ipsec_connections = ceilometer.network.services.discovery:IPSecConnectionsDiscovery
|
||||||
fw_services = ceilometer.network.services.discovery:FirewallDiscovery
|
fw_services = ceilometer.network.services.discovery:FirewallDiscovery
|
||||||
fw_policy = ceilometer.network.services.discovery:FirewallPolicyDiscovery
|
fw_policy = ceilometer.network.services.discovery:FirewallPolicyDiscovery
|
||||||
|
tripleo_overcloud_nodes = ceilometer.hardware.discovery:NodesDiscoveryTripleO
|
||||||
|
|
||||||
ceilometer.poll.compute =
|
ceilometer.poll.compute =
|
||||||
disk.read.requests = ceilometer.compute.pollsters.disk:ReadRequestsPollster
|
disk.read.requests = ceilometer.compute.pollsters.disk:ReadRequestsPollster
|
||||||
|
|
Loading…
Reference in New Issue