Change in vdsm[ovirt-3.6]: hooks:checkips: add checkips hook
alukiano at redhat.com
alukiano at redhat.com
Sun Apr 17 12:37:10 UTC 2016
Artyom Lukianov has uploaded a new change for review.
Change subject: hooks:checkips: add checkips hook
......................................................................
hooks:checkips: add checkips hook
Give possibilty to check connectivity between host and given addresses.
Update network stats with state of addresses.
Change-Id: I53cec37310f0f1844d6fe244419fd8c10e9b7ebb
Bug-Url: https://bugzilla.redhat.com/994170
Signed-off-by: Lukianov Artyom <alukiano at redhat.com>
---
M .gitignore
M configure.ac
M vdsm.spec.in
M vdsm_hooks/Makefile.am
A vdsm_hooks/checkips/Makefile.am
A vdsm_hooks/checkips/README
A vdsm_hooks/checkips/after_get_stats.py
A vdsm_hooks/checkips/checkips_utils.py
A vdsm_hooks/checkips/checkipsd
A vdsm_hooks/checkips/vdsm-checkips.service.in
10 files changed, 445 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/51/56251/1
diff --git a/.gitignore b/.gitignore
index 78af6fc..2e6c58d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,3 +71,4 @@
vdsm_hooks/openstacknet/sudoers
vdsm_hooks/ovs/sudoers
vdsm_hooks/persist-vdsm-hooks
+vdsm_hooks/checkips/vdsm-checkips.service
diff --git a/configure.ac b/configure.ac
index 7c19fd9..ef3700f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -165,6 +165,9 @@
AC_SUBST([SNLKGROUP], [sanlock])
AC_SUBST([CDROMGROUP], [cdrom])
+# Systemd units default path
+AC_SUBST([SYSTEMD_UNIT_DIR], ['/usr/lib/systemd/system'])
+
# VDSM default paths
AC_SUBST([vdsmdir], ['${datarootdir}/vdsm'])
AC_SUBST([vdsmconfdir], ['${sysconfdir}/vdsm'])
@@ -364,6 +367,7 @@
vdsm_hooks/Makefile
vdsm_hooks/allocate_net/Makefile
vdsm_hooks/checkimages/Makefile
+ vdsm_hooks/checkips/Makefile
vdsm_hooks/diskunmap/Makefile
vdsm_hooks/ethtool_options/Makefile
vdsm_hooks/extnet/Makefile
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 19edaac..a2c77e9 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -379,6 +379,19 @@
VDSM hook used to perform consistency check on a qcow2 format disk image
using the QEMU disk image utility.
+%package hook-checkips
+Summary: Check connectivity from the host to designated IPs
+Requires: %{name} = %{version}-%{release}
+
+%description hook-checkips
+VDSM hook used to check connectivity from the host network to designated IPs
+
+%post hook-checkips
+%systemd_post vdsm-checkips.service
+
+%preun hook-checkips
+%systemd_preun vdsm-checkips.service
+
%package hook-diskunmap
Summary: Activate UNMAP for disk/lun devices
BuildArch: noarch
@@ -1299,6 +1312,13 @@
%defattr(-, root, root, -)
%{_libexecdir}/%{vdsm_name}/hooks/before_vm_start/60_checkimages
+%files hook-checkips
+%defattr(-, root, root, -)
+%{_libexecdir}/%{vdsm_name}/hooks/after_get_stats/10_checkips
+%{_libexecdir}/%{vdsm_name}/hooks/checkipsd
+%{_libexecdir}/%{vdsm_name}/hooks/after_get_stats/checkips_utils.py*
+%{_unitdir}/vdsm-checkips.service
+
%files hook-diskunmap
%defattr(-, root, root, -)
%{_libexecdir}/%{vdsm_name}/hooks/before_vm_start/50_diskunmap
diff --git a/vdsm_hooks/Makefile.am b/vdsm_hooks/Makefile.am
index 44856f1..6fca9bb 100644
--- a/vdsm_hooks/Makefile.am
+++ b/vdsm_hooks/Makefile.am
@@ -36,6 +36,7 @@
SUBDIRS += \
allocate_net \
checkimages \
+ checkips \
diskunmap \
extnet \
fileinject \
diff --git a/vdsm_hooks/checkips/Makefile.am b/vdsm_hooks/checkips/Makefile.am
new file mode 100644
index 0000000..4b25acd
--- /dev/null
+++ b/vdsm_hooks/checkips/Makefile.am
@@ -0,0 +1,72 @@
+#
+# Copyright 2016 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
+#
+# Refer to the README and COPYING files for full details of the license
+#
+#
+
+utilsfile=checkips_utils.py
+servicefile=checkipsd
+unitfile=vdsm-checkips.service
+
+include $(top_srcdir)/build-aux/Makefile.subs
+
+nodist_noinst_DATA = \
+ vdsm-checkips.service \
+ config.log
+
+CLEANFILES = \
+ $(nodist_noinst_DATA)
+
+EXTRA_DIST = \
+ after_get_stats.py \
+ vdsm-checkips.service.in \
+ $(servicefile) \
+ $(utilsfile)
+
+
+install-data-local: install-data-utils install-data-service install-unit-service
+ $(MKDIR_P) $(DESTDIR)$(vdsmhooksdir)/after_get_stats
+ $(INSTALL_SCRIPT) $(srcdir)/after_get_stats.py \
+ $(DESTDIR)$(vdsmhooksdir)/after_get_stats/10_checkips
+
+install-data-utils:
+ $(MKDIR_P) $(DESTDIR)$(vdsmhooksdir)/after_get_stats
+ $(INSTALL_DATA) $(srcdir)/$(utilsfile) \
+ $(DESTDIR)$(vdsmhooksdir)/after_get_stats/$(utilsfile)
+
+install-data-service:
+ $(MKDIR_P) $(DESTDIR)$(vdsmhooksdir)
+ $(INSTALL_SCRIPT) $(srcdir)/$(servicefile) \
+ $(DESTDIR)$(vdsmhooksdir)/$(servicefile)
+
+install-unit-service:
+ $(MKDIR_P) $(DESTDIR)$(SYSTEMD_UNIT_DIR)
+ $(INSTALL_SCRIPT) -Dm 0644 $(srcdir)/$(unitfile) \
+ $(DESTDIR)$(SYSTEMD_UNIT_DIR)/$(unitfile)
+
+uninstall-local: uninstall-data-utils uninstall-data-service uninstall-unit-service
+ $(RM) $(DESTDIR)$(vdsmhooksdir)/after_get_stats/10_checkips
+
+uninstall-data-utils:
+ $(RM) $(DESTDIR)$(vdsmhooksdir)/after_get_stats/$(utilsfile)
+
+uninstall-data-service:
+ $(RM) $(DESTDIR)$(vdsmhooksdir)/$(servicefile)
+
+uninstall-unit-service:
+ $(RM) $(DESTDIR)$(SYSTEMD_UNIT_DIR)/$(unitfile)
diff --git a/vdsm_hooks/checkips/README b/vdsm_hooks/checkips/README
new file mode 100644
index 0000000..f9e31cd
--- /dev/null
+++ b/vdsm_hooks/checkips/README
@@ -0,0 +1,41 @@
+checkips vdsm hook
+=====================
+This hook check connectivity from host to given addresses
+
+This hook is useful in cases where you need to check connectivity from host to
+specific VLAN, you just need to add custom property checkipv4 or checkipv6,
+depend on what type of IP do you want to check, to network.
+
+Syntax:
+ checkipv4=IPV4 or FQDN
+ checkipv6=IPV6 or FQDN
+
+Where:
+ IPV4 is ip address in IPV4 format
+ IPV6 is ip address in IPV6 format
+
+Example:
+ checkipv4=127.0.0.1
+ checkipv6=::1
+
+Installation:
+ - Use the engine-config to append the proper custom property:
+ $ sudo engine-config -s UserDefinedNetworkCustomProperties='checkipv4=^[0-9\.a-fA-F]+$;checkipv6=^[0-9\.a-fA-F\:]+$'
+ - Verify that the checkipv4 and checkipv6 custom properties was properly added:
+ $ sudo engine-config -g UserDefinedNetworkCustomProperties
+ - Restart ovirt-engine service to apply changes
+ $ sudo service ovirt-engine restart
+ - The hook should be installed on all hosts,
+ and its accompanying service should be enabled and started
+ systemctl vdsm-checkips enable
+ systemctl vdsm-checkips start
+
+Usage:
+ In the host setup network configuration window, choose edit assigned
+ logical network, select custom property checkipv4 or checkipv6 and
+ enter VLAN IP or FQDN that you want to check for
+ connectivity(examples 8.8.8.8,2001:4860:4860::8888). So if you defined
+ checkipv4 and checkipv6 custom properties and if the host fails to ping
+ both IP's, it will drop the network's state to down.
+ If the network is defined as "required",
+ the host would become non-operational.
diff --git a/vdsm_hooks/checkips/after_get_stats.py b/vdsm_hooks/checkips/after_get_stats.py
new file mode 100644
index 0000000..8d829d6
--- /dev/null
+++ b/vdsm_hooks/checkips/after_get_stats.py
@@ -0,0 +1,152 @@
+#!/usr/bin/env python
+#
+# Copyright 2016 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
+#
+# Refer to the README and COPYING files for full details of the license
+#
+import os
+import six
+import sys
+import tempfile
+import time
+import traceback
+
+import checkips_utils
+import hooking
+from vdsm import constants
+import vdsm.netconfpersistence as persist_net
+
+HELP_ARG = '-h'
+TEST_ARG = '-t'
+HELP_TEXT = """usage: %(prog)s [%(help)s] [%(test)s]
+
+Check connectivity from host to specific addresses via ping
+
+optional arguments:
+ %(help)s show this help message and exit
+ %(test)s run a dry test for the hook
+""" % {
+ 'help': HELP_ARG,
+ 'test': TEST_ARG,
+ 'prog': sys.argv[0]
+}
+
+CONNECTIVITY_TIMEOUT = 60
+
+
+def _is_network_accessible(net, stats_dir):
+ file_path = os.path.join(stats_dir, net)
+ if os.path.exists(file_path):
+ return (
+ time.time() - os.stat(file_path).st_mtime <=
+ CONNECTIVITY_TIMEOUT
+ )
+ return False
+
+
+def update_networks_state(stats_json, networks, stats_dir):
+ for net, net_attrs in six.iteritems(networks):
+ ping_addresses = checkips_utils.get_ping_addresses(net_attrs)
+ if ping_addresses and not _is_network_accessible(net, stats_dir):
+ net_if = None
+ if 'nic' in net_attrs:
+ net_if = net_attrs['nic']
+ elif 'bonding' in net_attrs:
+ net_if = net_attrs['bonding']
+ if net_if:
+ stats_json['network'][net_if]['state'] = 'down'
+
+
+def test():
+ temp_dir = tempfile.mkdtemp()
+ checkips_utils.touch('check_ipv4', temp_dir)
+ checkips_utils.touch('check_ipv6', temp_dir)
+ try:
+ networks = {
+ 'check_ipv4': {
+ 'nic': 'eth0_ipv4',
+ 'custom': {
+ 'checkipv4': '127.0.0.1'
+ }
+ },
+ 'check_ipv6': {
+ 'bonding': 'bond_ipv6',
+ 'custom': {
+ 'checkipv6': '::1'
+ }
+ },
+ 'check_fqdn': {
+ 'nic': 'eth_fqdn',
+ 'custom': {
+ 'checkipv4': 'test.test'
+ }
+ }
+ }
+ network_stats = {
+ 'network': {
+ 'eth0_ipv4': {
+ 'state': 'up'
+ },
+ 'bond_ipv6': {
+ 'state': 'up'
+ },
+ 'eth_fqdn': {
+ 'state': 'up'
+ }
+ }
+ }
+ update_networks_state(network_stats, networks, temp_dir)
+ expected_states = {
+ 'eth0_ipv4': 'up',
+ 'bond_ipv6': 'up',
+ 'eth_fqdn': 'down'
+ }
+ for interface, state in six.iteritems(expected_states):
+ test_msg = 'pass'
+ if network_stats['network'][interface]['state'] != state:
+ test_msg = 'fail'
+ print(
+ 'test %s: interface %s has state %s' %
+ (test_msg, interface, state)
+ )
+ finally:
+ os.unlink(os.path.join(temp_dir, 'check_ipv4'))
+ os.unlink(os.path.join(temp_dir, 'check_ipv6'))
+ os.rmdir(temp_dir)
+
+
+def main():
+ stats_json = hooking.read_json()
+ networks = persist_net.PersistentConfig().networks
+ update_networks_state(stats_json, networks, constants.P_VDSM_RUN)
+ hooking.write_json(stats_json)
+
+
+if __name__ == '__main__':
+ if HELP_ARG in sys.argv:
+ hooking.exit_hook(HELP_TEXT)
+
+ try:
+ if TEST_ARG in sys.argv:
+ test()
+ else:
+ main()
+ except:
+ hooking.exit_hook(
+ 'checkips hook: [unexpected error]: %s\n' %
+ traceback.format_exc()
+ )
diff --git a/vdsm_hooks/checkips/checkips_utils.py b/vdsm_hooks/checkips/checkips_utils.py
new file mode 100644
index 0000000..44ee5af
--- /dev/null
+++ b/vdsm_hooks/checkips/checkips_utils.py
@@ -0,0 +1,43 @@
+#!/usr/bin/python
+#
+# Copyright 2008-2016 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
+#
+# Refer to the README and COPYING files for full details of the license
+#
+import os
+
+CHECKIPV4 = 'checkipv4'
+CHECKIPV6 = 'checkipv6'
+
+
+def touch(net, file_dir):
+ file_path = os.path.join(file_dir, net)
+ with open(file_path, 'a'):
+ os.utime(file_path, None)
+
+
+def get_ping_addresses(net_attrs):
+ ping_addresses = []
+ if 'custom' in net_attrs:
+ for address_type in (CHECKIPV4, CHECKIPV6):
+ if address_type in net_attrs['custom']:
+ ping_addresses.append(
+ (
+ address_type, net_attrs['custom'][address_type]
+ )
+ )
+ return ping_addresses
diff --git a/vdsm_hooks/checkips/checkipsd b/vdsm_hooks/checkips/checkipsd
new file mode 100644
index 0000000..8e081b1
--- /dev/null
+++ b/vdsm_hooks/checkips/checkipsd
@@ -0,0 +1,96 @@
+#!/usr/bin/python
+#
+# Copyright 2008-2016 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
+#
+# Refer to the README and COPYING files for full details of the license
+#
+import os
+import six
+import subprocess
+import sys
+import syslog
+import time
+import threading
+
+from vdsm import constants
+import vdsm.netconfpersistence as persist_net
+
+sys.path.append(os.path.join(constants.P_VDSM_HOOKS, 'after_get_stats'))
+import checkips_utils
+
+PING_TIMEOUT = 15
+PING_SAMPLE_TIME = 20
+CHECKIPV4 = 'checkipv4'
+CHECKIPV6 = 'checkipv6'
+VDSM_CHECKIPS = 'vdsm-checkips'
+
+
+def _ping_address(address, address_type, network):
+ ping_cmd = 'ping' if address_type == CHECKIPV4 else 'ping6'
+ command = [
+ ping_cmd,
+ '-c', '1',
+ '-w', str(PING_TIMEOUT),
+ address
+ ]
+ p = subprocess.Popen(
+ command, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
+ out, _ = p.communicate()
+ if not p.returncode:
+ checkips_utils.touch(network, constants.P_VDSM_RUN)
+ # Not sure about this, flood the journalctl log
+ elif out:
+ syslog.syslog(
+ "%s: failed to ping address %s: %s" %
+ (VDSM_CHECKIPS, address, out)
+ )
+
+
+def _ping_addresses():
+ threads = []
+ networks = persist_net.PersistentConfig().networks
+ for net, net_attrs in six.iteritems(networks):
+ ping_addresses = checkips_utils.get_ping_addresses(net_attrs)
+ if ping_addresses:
+ for address_type, address in ping_addresses:
+ ping_thread = threading.Thread(
+ target=_ping_address,
+ args=(address, address_type, net)
+ )
+ ping_thread.start()
+ threads.append(ping_thread)
+
+ for ping_thread in threads:
+ ping_thread.join()
+
+
+def main():
+ try:
+ while True:
+ time_before_ping = time.time()
+ _ping_addresses()
+ time.sleep(
+ PING_SAMPLE_TIME - (time.time() - time_before_ping)
+ )
+ except Exception as e:
+ syslog.syslog("%s: service failed to start: %s" % (VDSM_CHECKIPS, e))
+ return 1
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/vdsm_hooks/checkips/vdsm-checkips.service.in b/vdsm_hooks/checkips/vdsm-checkips.service.in
new file mode 100644
index 0000000..568e8a3
--- /dev/null
+++ b/vdsm_hooks/checkips/vdsm-checkips.service.in
@@ -0,0 +1,15 @@
+[Unit]
+Description=Service that ping given ips each 60 seconds
+
+[Service]
+Type=simple
+LimitCORE=infinity
+ExecStart=@HOOKSDIR@/checkipsd
+Restart=on-failure
+RestartSec=10
+User=@VDSMUSER@
+Group=@VDSMGROUP@
+TimeoutStopSec=@SERVICE_STOP_TIMEOUT@
+
+[Install]
+WantedBy=multi-user.target
--
To view, visit https://gerrit.ovirt.org/56251
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I53cec37310f0f1844d6fe244419fd8c10e9b7ebb
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: ovirt-3.6
Gerrit-Owner: Artyom Lukianov <alukiano at redhat.com>
More information about the vdsm-patches
mailing list