diff options
author | Ramesh Nachimuthu <rnachimu@redhat.com> | 2014-05-06 18:32:46 +0530 |
---|---|---|
committer | Sahina Bose <sabose@redhat.com> | 2015-05-19 02:01:33 -0700 |
commit | 44a1e8f43c04a8933311d6347d9bfe41a0aea78b (patch) | |
tree | 27d5c5ff24446ca2264e6ca0a02fa4734550df2a | |
parent | 8d1a17a906222feb3af6df7484fcba846673bae3 (diff) |
autoconf: validate the nagios server address in auto-config
Currently Nagios server address entered by the user during
auto config was not being verified. This patch helps to verify
the address entered by the user.
If IP address is given as the nagios server address then it
checks the pattern and verifies that it is mapped to one of the
non loopback device in the host
If user enters fqdn name, then it tries to resolve it,
also it verifies that resolved IP address maps to one of
the non loopback device in the host.
Bug-Url: https://bugzilla.redhat.com/1127657
Change-Id: I88d67cc6d8fa05f2934922fbc0d8e757b1d73e43
Signed-off-by: Ramesh Nachimuthu <rnachimu@redhat.com>
Reviewed-on: http://review.gluster.org/7740
Reviewed-by: darshan n <dnarayan@redhat.com>
Reviewed-by: Sahina Bose <sabose@redhat.com>
-rw-r--r-- | plugins/Makefile.am | 1 | ||||
-rwxr-xr-x | plugins/discovery.py | 34 | ||||
-rw-r--r-- | plugins/network_utils.py | 83 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/test_network_utils.py | 89 |
5 files changed, 191 insertions, 17 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 3365ae3..7b604b0 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -14,6 +14,7 @@ dist_glusternagiosplugins_PYTHON = \ submit_external_command.py \ brick_status_event_handler.py \ server_utils.py \ + network_utils.py \ $(NULL) EXTRA_DIST = \ diff --git a/plugins/discovery.py b/plugins/discovery.py index 46fee95..b17c81f 100755 --- a/plugins/discovery.py +++ b/plugins/discovery.py @@ -21,11 +21,13 @@ import datetime import os import shutil import sys +import socket from glusternagios import utils from glusternagios.glustercli import HostStatus from config_generator import GlusterNagiosConfManager import server_utils +import network_utils import submit_external_command from constants import DEFAULT_AUTO_CONFIG_DIR from constants import NAGIOS_CONFIG_FILE @@ -432,23 +434,21 @@ def getNagiosAddress(clusterName): nagiosAddress = autoConfigService['check_command'].split("!")[2] return nagiosAddress - (returncode, outputStr, err) = utils.execCmd([utils.hostnameCmdPath.cmd, - '--fqdn']) - if returncode == 0: - default = outputStr[0] - else: - (returncode, outputStr, err) = utils.execCmd( - [utils.hostnameCmdPath.cmd, '-I']) - if returncode == 0: - default = outputStr[0] - if default: - msg = "Enter Nagios server address [%s]: " % (default.strip()) - else: - msg = "Enter Nagios server address : " - ans = raw_input(msg) - if not ans: - ans = default - return ans + return getHostAddress() + + +def getHostAddress(): + fqdn = socket.getfqdn() + while True: + msg = 'Enter Nagios server address [%s]: ' % fqdn + address = raw_input(msg) + if not address: + address = fqdn + validationMsg = network_utils.validateHostAddress(address) + if validationMsg: + print 'Host address is not valid: %s' % validationMsg + else: + return address def getConfirmation(message, default): diff --git a/plugins/network_utils.py b/plugins/network_utils.py new file mode 100644 index 0000000..83fecc0 --- /dev/null +++ b/plugins/network_utils.py @@ -0,0 +1,83 @@ +#!/usr/bin/python +# network_utils.py Network utility +# Copyright (C) 2014 Red Hat Inc +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +# +import re +import socket +import ethtool +import logging + + +IPADDR_RE = re.compile(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') +DOMAIN_RE = re.compile( + flags=re.VERBOSE, + pattern=r""" + ^ + [\w\.\-\_]+ + \w+ + $ + """ +) + + +def getNonLoopbackAddresses(): + devices = ethtool.get_active_devices() + iplist = [] + + for device in devices: + try: + flags = ethtool.get_flags(device) + if flags and not (flags & ethtool.IFF_LOOPBACK): + iplist.append(ethtool.get_ipaddr(device)) + except IOError as e: + logging.error("unable to get ipaddr/flags for %s: %s" + % (device, e)) + return set(iplist) + + +def validateFQDNresolvability(fqdn): + try: + resolvedAddresses = set(socket.gethostbyname_ex(fqdn)[2]) + except socket.error: + return "%s did not resolve into an IP address" % fqdn + + if not resolvedAddresses.issubset(getNonLoopbackAddresses()): + return "The following addreses: '%s' can't be mapped to non " \ + "loopback devices on this host" % resolvedAddresses + + +def validateHostAddress(address): + if not address: + return "Please specify host Address" + + if IPADDR_RE.match(address): + if not address in getNonLoopbackAddresses(): + return "Address '%s' can't be mapped to non loopback devices " \ + "on this host" % address + else: + return + + if len(address) > 1000: + return "FQDN has invalid length" + + components = address.split('.', 1) + if len(components) < 2: + return "Host FQDN name '%s' has no domain suffix" % address + else: + if not DOMAIN_RE.match(components[1]): + return "Host FQDN name '%s' has invalid domain name" % address + return validateFQDNresolvability(address) diff --git a/tests/Makefile.am b/tests/Makefile.am index 8616007..f2bfc96 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -23,6 +23,7 @@ test_modules = \ test_notify_ovirt_engine_handler.py \ test_config_generator.py \ test_discovery.py \ + test_network_utils.py $(NULL) dist_nagiosserveraddonstests_DATA = \ diff --git a/tests/test_network_utils.py b/tests/test_network_utils.py new file mode 100644 index 0000000..f379e0c --- /dev/null +++ b/tests/test_network_utils.py @@ -0,0 +1,89 @@ +#!/usr/bin/python +# Copyright 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +# + +from plugins import network_utils +from testrunner import PluginsTestCase as TestCaseBase + + +class TestNetworkUtils(TestCaseBase): + def mockGetFlags(self, device): + if device == 'lo': + return 73 + else: + return 4163 + + def mockGetDevices(self): + return ['lo', 'etho', 'eth1'] + + def mockGetIpAddr(self, device): + if device == 'lo': + return '127.0.0.1' + else: + return '10.70.42.1' + + def mockGethostbyname_ex(self, host): + if host == 'test.host.com': + return host, [], ['10.70.42.1'] + else: + return host, [], ['82.94.164.162'] + + def setUpMocks(self): + network_utils.ethtool.get_active_devices = self.mockGetDevices + network_utils.ethtool.get_flags = self.mockGetFlags + network_utils.ethtool.get_ipaddr = self.mockGetIpAddr + network_utils.socket.gethostbyname_ex = self.mockGethostbyname_ex + + #Methods to test validateHostAddress(address) + def testValidateHostAddressWithEmptyAddress(self): + self.setUpMocks() + validationMsg = network_utils.validateHostAddress(None) + self.assertEqual('Please specify host Address', validationMsg) + + def testValidateHostAddressWithLoopBackAddress(self): + self.setUpMocks() + validationMsg = network_utils.validateHostAddress("127.0.0.1") + self.assertEqual("Address '127.0.0.1' can't be mapped to non loopback " + "devices on this host", validationMsg) + + def testValidateHostAddressWithValidAddress(self): + self.setUpMocks() + validationMsg = network_utils.validateHostAddress("10.70.42.1") + self.assertEqual(None, validationMsg) + + def testValidateHostAddressWithInvalidFQDN(self): + self.setUpMocks() + validationMsg = network_utils.validateHostAddress("this-is-" + "invalid-fqdn") + self.assertEqual("Host FQDN name 'this-is-invalid-fqdn' has no domain " + "suffix", validationMsg) + + validationMsg = network_utils.validateHostAddress("this.is." + "invalid.fqdn.") + self.assertEqual("Host FQDN name 'this.is.invalid.fqdn.' has invalid " + "domain name", validationMsg) + + validationMsg = network_utils.validateHostAddress("test.host." + "com.notfound") + self.assertEqual("The following addreses: 'set(['82.94.164.162'])' " + "can't be mapped to non loopback devices on this " + "host", validationMsg) + + def testValidateHostAddressWithValidFQDN(self): + self.setUpMocks() + validationMsg = network_utils.validateHostAddress("test.host.com") + self.assertEqual(None, validationMsg) |