|
|
2b0ae0 |
From c3a1b3a5d7abe51a1facbdae71aca4b2bca7d6aa Mon Sep 17 00:00:00 2001
|
|
|
2b0ae0 |
From: Eduardo Otubo <otubo@redhat.com>
|
|
|
2b0ae0 |
Date: Wed, 28 Oct 2020 20:43:33 +0100
|
|
|
2b0ae0 |
Subject: [PATCH 2/3] Add config modules for controlling IBM PowerVM RMC.
|
|
|
2b0ae0 |
(#584)
|
|
|
2b0ae0 |
|
|
|
2b0ae0 |
RH-Author: Eduardo Terrell Ferrari Otubo (eterrell)
|
|
|
2b0ae0 |
RH-MergeRequest: 12: Support for cloud-init config modules for PowerVM Hypervisor in Red Hat cloud-init
|
|
|
2b0ae0 |
RH-Commit: [1/1] d175c3607a8d4f473573ba0ce42e0f311dbc31ed (eterrell/cloud-init)
|
|
|
2b0ae0 |
RH-Bugzilla: 1886430
|
|
|
2b0ae0 |
|
|
|
2b0ae0 |
commit f99d4f96b00a9cfec1c721d364cbfd728674e5dc (upstream/master)
|
|
|
2b0ae0 |
Author: Aman306 <45781773+Aman306@users.noreply.github.com>
|
|
|
2b0ae0 |
Date: Wed Oct 28 23:36:09 2020 +0530
|
|
|
2b0ae0 |
|
|
|
2b0ae0 |
Add config modules for controlling IBM PowerVM RMC. (#584)
|
|
|
2b0ae0 |
|
|
|
2b0ae0 |
Reliable Scalable Cluster Technology (RSCT) is a set of software
|
|
|
2b0ae0 |
components that together provide a comprehensive clustering
|
|
|
2b0ae0 |
environment(RAS features) for IBM PowerVM based virtual machines. RSCT
|
|
|
2b0ae0 |
includes the Resource Monitoring and Control (RMC) subsystem. RMC is a
|
|
|
2b0ae0 |
generalized framework used for managing, monitoring, and manipulating
|
|
|
2b0ae0 |
resources. RMC runs as a daemon process on individual machines and needs
|
|
|
2b0ae0 |
creation of unique node id and restarts during VM boot.
|
|
|
2b0ae0 |
|
|
|
2b0ae0 |
LP: #1895979
|
|
|
2b0ae0 |
|
|
|
2b0ae0 |
Co-authored-by: Scott Moser <smoser@brickies.net>
|
|
|
2b0ae0 |
|
|
|
2b0ae0 |
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
|
|
2b0ae0 |
---
|
|
|
2b0ae0 |
cloudinit/config/cc_refresh_rmc_and_interface.py | 159 +++++++++++++++++++++
|
|
|
2b0ae0 |
cloudinit/config/cc_reset_rmc.py | 143 ++++++++++++++++++
|
|
|
2b0ae0 |
config/cloud.cfg.tmpl | 2 +
|
|
|
2b0ae0 |
.../test_handler_refresh_rmc_and_interface.py | 109 ++++++++++++++
|
|
|
2b0ae0 |
tools/.github-cla-signers | 1 +
|
|
|
2b0ae0 |
5 files changed, 414 insertions(+)
|
|
|
2b0ae0 |
create mode 100644 cloudinit/config/cc_refresh_rmc_and_interface.py
|
|
|
2b0ae0 |
create mode 100644 cloudinit/config/cc_reset_rmc.py
|
|
|
2b0ae0 |
create mode 100644 tests/unittests/test_handler/test_handler_refresh_rmc_and_interface.py
|
|
|
2b0ae0 |
|
|
|
2b0ae0 |
diff --git a/cloudinit/config/cc_refresh_rmc_and_interface.py b/cloudinit/config/cc_refresh_rmc_and_interface.py
|
|
|
2b0ae0 |
new file mode 100644
|
|
|
2b0ae0 |
index 0000000..146758a
|
|
|
2b0ae0 |
--- /dev/null
|
|
|
2b0ae0 |
+++ b/cloudinit/config/cc_refresh_rmc_and_interface.py
|
|
|
2b0ae0 |
@@ -0,0 +1,159 @@
|
|
|
2b0ae0 |
+# (c) Copyright IBM Corp. 2020 All Rights Reserved
|
|
|
2b0ae0 |
+#
|
|
|
2b0ae0 |
+# Author: Aman Kumar Sinha <amansi26@in.ibm.com>
|
|
|
2b0ae0 |
+#
|
|
|
2b0ae0 |
+# This file is part of cloud-init. See LICENSE file for license information.
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+"""
|
|
|
2b0ae0 |
+Refresh IPv6 interface and RMC
|
|
|
2b0ae0 |
+------------------------------
|
|
|
2b0ae0 |
+**Summary:** Ensure Network Manager is not managing IPv6 interface
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+This module is IBM PowerVM Hypervisor specific
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+Reliable Scalable Cluster Technology (RSCT) is a set of software components
|
|
|
2b0ae0 |
+that together provide a comprehensive clustering environment(RAS features)
|
|
|
2b0ae0 |
+for IBM PowerVM based virtual machines. RSCT includes the Resource
|
|
|
2b0ae0 |
+Monitoring and Control (RMC) subsystem. RMC is a generalized framework used
|
|
|
2b0ae0 |
+for managing, monitoring, and manipulating resources. RMC runs as a daemon
|
|
|
2b0ae0 |
+process on individual machines and needs creation of unique node id and
|
|
|
2b0ae0 |
+restarts during VM boot.
|
|
|
2b0ae0 |
+More details refer
|
|
|
2b0ae0 |
+https://www.ibm.com/support/knowledgecenter/en/SGVKBA_3.2/admin/bl503_ovrv.htm
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+This module handles
|
|
|
2b0ae0 |
+- Refreshing RMC
|
|
|
2b0ae0 |
+- Disabling NetworkManager from handling IPv6 interface, as IPv6 interface
|
|
|
2b0ae0 |
+ is used for communication between RMC daemon and PowerVM hypervisor.
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+**Internal name:** ``cc_refresh_rmc_and_interface``
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+**Module frequency:** per always
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+**Supported distros:** RHEL
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+"""
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+from cloudinit import log as logging
|
|
|
2b0ae0 |
+from cloudinit.settings import PER_ALWAYS
|
|
|
2b0ae0 |
+from cloudinit import util
|
|
|
2b0ae0 |
+from cloudinit import subp
|
|
|
2b0ae0 |
+from cloudinit import netinfo
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+import errno
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+frequency = PER_ALWAYS
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+LOG = logging.getLogger(__name__)
|
|
|
2b0ae0 |
+# Ensure that /opt/rsct/bin has been added to standard PATH of the
|
|
|
2b0ae0 |
+# distro. The symlink to rmcctrl is /usr/sbin/rsct/bin/rmcctrl .
|
|
|
2b0ae0 |
+RMCCTRL = 'rmcctrl'
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def handle(name, _cfg, _cloud, _log, _args):
|
|
|
2b0ae0 |
+ if not subp.which(RMCCTRL):
|
|
|
2b0ae0 |
+ LOG.debug("No '%s' in path, disabled", RMCCTRL)
|
|
|
2b0ae0 |
+ return
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ LOG.debug(
|
|
|
2b0ae0 |
+ 'Making the IPv6 up explicitly. '
|
|
|
2b0ae0 |
+ 'Ensuring IPv6 interface is not being handled by NetworkManager '
|
|
|
2b0ae0 |
+ 'and it is restarted to re-establish the communication with '
|
|
|
2b0ae0 |
+ 'the hypervisor')
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ ifaces = find_ipv6_ifaces()
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ # Setting NM_CONTROLLED=no for IPv6 interface
|
|
|
2b0ae0 |
+ # making it down and up
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ if len(ifaces) == 0:
|
|
|
2b0ae0 |
+ LOG.debug("Did not find any interfaces with ipv6 addresses.")
|
|
|
2b0ae0 |
+ else:
|
|
|
2b0ae0 |
+ for iface in ifaces:
|
|
|
2b0ae0 |
+ refresh_ipv6(iface)
|
|
|
2b0ae0 |
+ disable_ipv6(sysconfig_path(iface))
|
|
|
2b0ae0 |
+ restart_network_manager()
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def find_ipv6_ifaces():
|
|
|
2b0ae0 |
+ info = netinfo.netdev_info()
|
|
|
2b0ae0 |
+ ifaces = []
|
|
|
2b0ae0 |
+ for iface, data in info.items():
|
|
|
2b0ae0 |
+ if iface == "lo":
|
|
|
2b0ae0 |
+ LOG.debug('Skipping localhost interface')
|
|
|
2b0ae0 |
+ if len(data.get("ipv4", [])) != 0:
|
|
|
2b0ae0 |
+ # skip this interface, as it has ipv4 addrs
|
|
|
2b0ae0 |
+ continue
|
|
|
2b0ae0 |
+ ifaces.append(iface)
|
|
|
2b0ae0 |
+ return ifaces
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def refresh_ipv6(interface):
|
|
|
2b0ae0 |
+ # IPv6 interface is explicitly brought up, subsequent to which the
|
|
|
2b0ae0 |
+ # RMC services are restarted to re-establish the communication with
|
|
|
2b0ae0 |
+ # the hypervisor.
|
|
|
2b0ae0 |
+ subp.subp(['ip', 'link', 'set', interface, 'down'])
|
|
|
2b0ae0 |
+ subp.subp(['ip', 'link', 'set', interface, 'up'])
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def sysconfig_path(iface):
|
|
|
2b0ae0 |
+ return '/etc/sysconfig/network-scripts/ifcfg-' + iface
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def restart_network_manager():
|
|
|
2b0ae0 |
+ subp.subp(['systemctl', 'restart', 'NetworkManager'])
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def disable_ipv6(iface_file):
|
|
|
2b0ae0 |
+ # Ensuring that the communication b/w the hypervisor and VM is not
|
|
|
2b0ae0 |
+ # interrupted due to NetworkManager. For this purpose, as part of
|
|
|
2b0ae0 |
+ # this function, the NM_CONTROLLED is explicitly set to No for IPV6
|
|
|
2b0ae0 |
+ # interface and NetworkManager is restarted.
|
|
|
2b0ae0 |
+ try:
|
|
|
2b0ae0 |
+ contents = util.load_file(iface_file)
|
|
|
2b0ae0 |
+ except IOError as e:
|
|
|
2b0ae0 |
+ if e.errno == errno.ENOENT:
|
|
|
2b0ae0 |
+ LOG.debug("IPv6 interface file %s does not exist\n",
|
|
|
2b0ae0 |
+ iface_file)
|
|
|
2b0ae0 |
+ else:
|
|
|
2b0ae0 |
+ raise e
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ if 'IPV6INIT' not in contents:
|
|
|
2b0ae0 |
+ LOG.debug("Interface file %s did not have IPV6INIT", iface_file)
|
|
|
2b0ae0 |
+ return
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ LOG.debug("Editing interface file %s ", iface_file)
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ # Dropping any NM_CONTROLLED or IPV6 lines from IPv6 interface file.
|
|
|
2b0ae0 |
+ lines = contents.splitlines()
|
|
|
2b0ae0 |
+ lines = [line for line in lines if not search(line)]
|
|
|
2b0ae0 |
+ lines.append("NM_CONTROLLED=no")
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ with open(iface_file, "w") as fp:
|
|
|
2b0ae0 |
+ fp.write("\n".join(lines) + "\n")
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def search(contents):
|
|
|
2b0ae0 |
+ # Search for any NM_CONTROLLED or IPV6 lines in IPv6 interface file.
|
|
|
2b0ae0 |
+ return(
|
|
|
2b0ae0 |
+ contents.startswith("IPV6ADDR") or
|
|
|
2b0ae0 |
+ contents.startswith("IPADDR6") or
|
|
|
2b0ae0 |
+ contents.startswith("IPV6INIT") or
|
|
|
2b0ae0 |
+ contents.startswith("NM_CONTROLLED"))
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def refresh_rmc():
|
|
|
2b0ae0 |
+ # To make a healthy connection between RMC daemon and hypervisor we
|
|
|
2b0ae0 |
+ # refresh RMC. With refreshing RMC we are ensuring that making IPv6
|
|
|
2b0ae0 |
+ # down and up shouldn't impact communication between RMC daemon and
|
|
|
2b0ae0 |
+ # hypervisor.
|
|
|
2b0ae0 |
+ # -z : stop Resource Monitoring & Control subsystem and all resource
|
|
|
2b0ae0 |
+ # managers, but the command does not return control to the user
|
|
|
2b0ae0 |
+ # until the subsystem and all resource managers are stopped.
|
|
|
2b0ae0 |
+ # -s : start Resource Monitoring & Control subsystem.
|
|
|
2b0ae0 |
+ try:
|
|
|
2b0ae0 |
+ subp.subp([RMCCTRL, '-z'])
|
|
|
2b0ae0 |
+ subp.subp([RMCCTRL, '-s'])
|
|
|
2b0ae0 |
+ except Exception:
|
|
|
2b0ae0 |
+ util.logexc(LOG, 'Failed to refresh the RMC subsystem.')
|
|
|
2b0ae0 |
+ raise
|
|
|
2b0ae0 |
diff --git a/cloudinit/config/cc_reset_rmc.py b/cloudinit/config/cc_reset_rmc.py
|
|
|
2b0ae0 |
new file mode 100644
|
|
|
2b0ae0 |
index 0000000..1cd7277
|
|
|
2b0ae0 |
--- /dev/null
|
|
|
2b0ae0 |
+++ b/cloudinit/config/cc_reset_rmc.py
|
|
|
2b0ae0 |
@@ -0,0 +1,143 @@
|
|
|
2b0ae0 |
+# (c) Copyright IBM Corp. 2020 All Rights Reserved
|
|
|
2b0ae0 |
+#
|
|
|
2b0ae0 |
+# Author: Aman Kumar Sinha <amansi26@in.ibm.com>
|
|
|
2b0ae0 |
+#
|
|
|
2b0ae0 |
+# This file is part of cloud-init. See LICENSE file for license information.
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+"""
|
|
|
2b0ae0 |
+Reset RMC
|
|
|
2b0ae0 |
+------------
|
|
|
2b0ae0 |
+**Summary:** reset rsct node id
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+Reset RMC module is IBM PowerVM Hypervisor specific
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+Reliable Scalable Cluster Technology (RSCT) is a set of software components,
|
|
|
2b0ae0 |
+that together provide a comprehensive clustering environment (RAS features)
|
|
|
2b0ae0 |
+for IBM PowerVM based virtual machines. RSCT includes the Resource monitoring
|
|
|
2b0ae0 |
+and control (RMC) subsystem. RMC is a generalized framework used for managing,
|
|
|
2b0ae0 |
+monitoring, and manipulating resources. RMC runs as a daemon process on
|
|
|
2b0ae0 |
+individual machines and needs creation of unique node id and restarts
|
|
|
2b0ae0 |
+during VM boot.
|
|
|
2b0ae0 |
+More details refer
|
|
|
2b0ae0 |
+https://www.ibm.com/support/knowledgecenter/en/SGVKBA_3.2/admin/bl503_ovrv.htm
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+This module handles
|
|
|
2b0ae0 |
+- creation of the unique RSCT node id to every instance/virtual machine
|
|
|
2b0ae0 |
+ and ensure once set, it isn't changed subsequently by cloud-init.
|
|
|
2b0ae0 |
+ In order to do so, it restarts RSCT service.
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+Prerequisite of using this module is to install RSCT packages.
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+**Internal name:** ``cc_reset_rmc``
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+**Module frequency:** per instance
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+**Supported distros:** rhel, sles and ubuntu
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+"""
|
|
|
2b0ae0 |
+import os
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+from cloudinit import log as logging
|
|
|
2b0ae0 |
+from cloudinit.settings import PER_INSTANCE
|
|
|
2b0ae0 |
+from cloudinit import util
|
|
|
2b0ae0 |
+from cloudinit import subp
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+frequency = PER_INSTANCE
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+# RMCCTRL is expected to be in system PATH (/opt/rsct/bin)
|
|
|
2b0ae0 |
+# The symlink for RMCCTRL and RECFGCT are
|
|
|
2b0ae0 |
+# /usr/sbin/rsct/bin/rmcctrl and
|
|
|
2b0ae0 |
+# /usr/sbin/rsct/install/bin/recfgct respectively.
|
|
|
2b0ae0 |
+RSCT_PATH = '/opt/rsct/install/bin'
|
|
|
2b0ae0 |
+RMCCTRL = 'rmcctrl'
|
|
|
2b0ae0 |
+RECFGCT = 'recfgct'
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+LOG = logging.getLogger(__name__)
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+NODE_ID_FILE = '/etc/ct_node_id'
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def handle(name, _cfg, cloud, _log, _args):
|
|
|
2b0ae0 |
+ # Ensuring node id has to be generated only once during first boot
|
|
|
2b0ae0 |
+ if cloud.datasource.platform_type == 'none':
|
|
|
2b0ae0 |
+ LOG.debug('Skipping creation of new ct_node_id node')
|
|
|
2b0ae0 |
+ return
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ if not os.path.isdir(RSCT_PATH):
|
|
|
2b0ae0 |
+ LOG.debug("module disabled, RSCT_PATH not present")
|
|
|
2b0ae0 |
+ return
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ orig_path = os.environ.get('PATH')
|
|
|
2b0ae0 |
+ try:
|
|
|
2b0ae0 |
+ add_path(orig_path)
|
|
|
2b0ae0 |
+ reset_rmc()
|
|
|
2b0ae0 |
+ finally:
|
|
|
2b0ae0 |
+ if orig_path:
|
|
|
2b0ae0 |
+ os.environ['PATH'] = orig_path
|
|
|
2b0ae0 |
+ else:
|
|
|
2b0ae0 |
+ del os.environ['PATH']
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def reconfigure_rsct_subsystems():
|
|
|
2b0ae0 |
+ # Reconfigure the RSCT subsystems, which includes removing all RSCT data
|
|
|
2b0ae0 |
+ # under the /var/ct directory, generating a new node ID, and making it
|
|
|
2b0ae0 |
+ # appear as if the RSCT components were just installed
|
|
|
2b0ae0 |
+ try:
|
|
|
2b0ae0 |
+ out = subp.subp([RECFGCT])[0]
|
|
|
2b0ae0 |
+ LOG.debug(out.strip())
|
|
|
2b0ae0 |
+ return out
|
|
|
2b0ae0 |
+ except subp.ProcessExecutionError:
|
|
|
2b0ae0 |
+ util.logexc(LOG, 'Failed to reconfigure the RSCT subsystems.')
|
|
|
2b0ae0 |
+ raise
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def get_node_id():
|
|
|
2b0ae0 |
+ try:
|
|
|
2b0ae0 |
+ fp = util.load_file(NODE_ID_FILE)
|
|
|
2b0ae0 |
+ node_id = fp.split('\n')[0]
|
|
|
2b0ae0 |
+ return node_id
|
|
|
2b0ae0 |
+ except Exception:
|
|
|
2b0ae0 |
+ util.logexc(LOG, 'Failed to get node ID from file %s.' % NODE_ID_FILE)
|
|
|
2b0ae0 |
+ raise
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def add_path(orig_path):
|
|
|
2b0ae0 |
+ # Adding the RSCT_PATH to env standard path
|
|
|
2b0ae0 |
+ # So thet cloud init automatically find and
|
|
|
2b0ae0 |
+ # run RECFGCT to create new node_id.
|
|
|
2b0ae0 |
+ suff = ":" + orig_path if orig_path else ""
|
|
|
2b0ae0 |
+ os.environ['PATH'] = RSCT_PATH + suff
|
|
|
2b0ae0 |
+ return os.environ['PATH']
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def rmcctrl():
|
|
|
2b0ae0 |
+ # Stop the RMC subsystem and all resource managers so that we can make
|
|
|
2b0ae0 |
+ # some changes to it
|
|
|
2b0ae0 |
+ try:
|
|
|
2b0ae0 |
+ return subp.subp([RMCCTRL, '-z'])
|
|
|
2b0ae0 |
+ except Exception:
|
|
|
2b0ae0 |
+ util.logexc(LOG, 'Failed to stop the RMC subsystem.')
|
|
|
2b0ae0 |
+ raise
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+def reset_rmc():
|
|
|
2b0ae0 |
+ LOG.debug('Attempting to reset RMC.')
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ node_id_before = get_node_id()
|
|
|
2b0ae0 |
+ LOG.debug('Node ID at beginning of module: %s', node_id_before)
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ # Stop the RMC subsystem and all resource managers so that we can make
|
|
|
2b0ae0 |
+ # some changes to it
|
|
|
2b0ae0 |
+ rmcctrl()
|
|
|
2b0ae0 |
+ reconfigure_rsct_subsystems()
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ node_id_after = get_node_id()
|
|
|
2b0ae0 |
+ LOG.debug('Node ID at end of module: %s', node_id_after)
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ # Check if new node ID is generated or not
|
|
|
2b0ae0 |
+ # by comparing old and new node ID
|
|
|
2b0ae0 |
+ if node_id_after == node_id_before:
|
|
|
2b0ae0 |
+ msg = 'New node ID did not get generated.'
|
|
|
2b0ae0 |
+ LOG.error(msg)
|
|
|
2b0ae0 |
+ raise Exception(msg)
|
|
|
2b0ae0 |
diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl
|
|
|
2b0ae0 |
index 2beb9b0..7171aaa 100644
|
|
|
2b0ae0 |
--- a/config/cloud.cfg.tmpl
|
|
|
2b0ae0 |
+++ b/config/cloud.cfg.tmpl
|
|
|
2b0ae0 |
@@ -135,6 +135,8 @@ cloud_final_modules:
|
|
|
2b0ae0 |
- chef
|
|
|
2b0ae0 |
- mcollective
|
|
|
2b0ae0 |
- salt-minion
|
|
|
2b0ae0 |
+ - reset_rmc
|
|
|
2b0ae0 |
+ - refresh_rmc_and_interface
|
|
|
2b0ae0 |
- rightscale_userdata
|
|
|
2b0ae0 |
- scripts-vendor
|
|
|
2b0ae0 |
- scripts-per-once
|
|
|
2b0ae0 |
diff --git a/tests/unittests/test_handler/test_handler_refresh_rmc_and_interface.py b/tests/unittests/test_handler/test_handler_refresh_rmc_and_interface.py
|
|
|
2b0ae0 |
new file mode 100644
|
|
|
2b0ae0 |
index 0000000..e13b779
|
|
|
2b0ae0 |
--- /dev/null
|
|
|
2b0ae0 |
+++ b/tests/unittests/test_handler/test_handler_refresh_rmc_and_interface.py
|
|
|
2b0ae0 |
@@ -0,0 +1,109 @@
|
|
|
2b0ae0 |
+from cloudinit.config import cc_refresh_rmc_and_interface as ccrmci
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+from cloudinit import util
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+from cloudinit.tests import helpers as t_help
|
|
|
2b0ae0 |
+from cloudinit.tests.helpers import mock
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+from textwrap import dedent
|
|
|
2b0ae0 |
+import logging
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+LOG = logging.getLogger(__name__)
|
|
|
2b0ae0 |
+MPATH = "cloudinit.config.cc_refresh_rmc_and_interface"
|
|
|
2b0ae0 |
+NET_INFO = {
|
|
|
2b0ae0 |
+ 'lo': {'ipv4': [{'ip': '127.0.0.1',
|
|
|
2b0ae0 |
+ 'bcast': '', 'mask': '255.0.0.0',
|
|
|
2b0ae0 |
+ 'scope': 'host'}],
|
|
|
2b0ae0 |
+ 'ipv6': [{'ip': '::1/128',
|
|
|
2b0ae0 |
+ 'scope6': 'host'}], 'hwaddr': '',
|
|
|
2b0ae0 |
+ 'up': 'True'},
|
|
|
2b0ae0 |
+ 'env2': {'ipv4': [{'ip': '8.0.0.19',
|
|
|
2b0ae0 |
+ 'bcast': '8.0.0.255', 'mask': '255.255.255.0',
|
|
|
2b0ae0 |
+ 'scope': 'global'}],
|
|
|
2b0ae0 |
+ 'ipv6': [{'ip': 'fe80::f896:c2ff:fe81:8220/64',
|
|
|
2b0ae0 |
+ 'scope6': 'link'}], 'hwaddr': 'fa:96:c2:81:82:20',
|
|
|
2b0ae0 |
+ 'up': 'True'},
|
|
|
2b0ae0 |
+ 'env3': {'ipv4': [{'ip': '90.0.0.14',
|
|
|
2b0ae0 |
+ 'bcast': '90.0.0.255', 'mask': '255.255.255.0',
|
|
|
2b0ae0 |
+ 'scope': 'global'}],
|
|
|
2b0ae0 |
+ 'ipv6': [{'ip': 'fe80::f896:c2ff:fe81:8221/64',
|
|
|
2b0ae0 |
+ 'scope6': 'link'}], 'hwaddr': 'fa:96:c2:81:82:21',
|
|
|
2b0ae0 |
+ 'up': 'True'},
|
|
|
2b0ae0 |
+ 'env4': {'ipv4': [{'ip': '9.114.23.7',
|
|
|
2b0ae0 |
+ 'bcast': '9.114.23.255', 'mask': '255.255.255.0',
|
|
|
2b0ae0 |
+ 'scope': 'global'}],
|
|
|
2b0ae0 |
+ 'ipv6': [{'ip': 'fe80::f896:c2ff:fe81:8222/64',
|
|
|
2b0ae0 |
+ 'scope6': 'link'}], 'hwaddr': 'fa:96:c2:81:82:22',
|
|
|
2b0ae0 |
+ 'up': 'True'},
|
|
|
2b0ae0 |
+ 'env5': {'ipv4': [],
|
|
|
2b0ae0 |
+ 'ipv6': [{'ip': 'fe80::9c26:c3ff:fea4:62c8/64',
|
|
|
2b0ae0 |
+ 'scope6': 'link'}], 'hwaddr': '42:20:86:df:fa:4c',
|
|
|
2b0ae0 |
+ 'up': 'True'}}
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+class TestRsctNodeFile(t_help.CiTestCase):
|
|
|
2b0ae0 |
+ def test_disable_ipv6_interface(self):
|
|
|
2b0ae0 |
+ """test parsing of iface files."""
|
|
|
2b0ae0 |
+ fname = self.tmp_path("iface-eth5")
|
|
|
2b0ae0 |
+ util.write_file(fname, dedent("""\
|
|
|
2b0ae0 |
+ BOOTPROTO=static
|
|
|
2b0ae0 |
+ DEVICE=eth5
|
|
|
2b0ae0 |
+ HWADDR=42:20:86:df:fa:4c
|
|
|
2b0ae0 |
+ IPV6INIT=yes
|
|
|
2b0ae0 |
+ IPADDR6=fe80::9c26:c3ff:fea4:62c8/64
|
|
|
2b0ae0 |
+ IPV6ADDR=fe80::9c26:c3ff:fea4:62c8/64
|
|
|
2b0ae0 |
+ NM_CONTROLLED=yes
|
|
|
2b0ae0 |
+ ONBOOT=yes
|
|
|
2b0ae0 |
+ STARTMODE=auto
|
|
|
2b0ae0 |
+ TYPE=Ethernet
|
|
|
2b0ae0 |
+ USERCTL=no
|
|
|
2b0ae0 |
+ """))
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ ccrmci.disable_ipv6(fname)
|
|
|
2b0ae0 |
+ self.assertEqual(dedent("""\
|
|
|
2b0ae0 |
+ BOOTPROTO=static
|
|
|
2b0ae0 |
+ DEVICE=eth5
|
|
|
2b0ae0 |
+ HWADDR=42:20:86:df:fa:4c
|
|
|
2b0ae0 |
+ ONBOOT=yes
|
|
|
2b0ae0 |
+ STARTMODE=auto
|
|
|
2b0ae0 |
+ TYPE=Ethernet
|
|
|
2b0ae0 |
+ USERCTL=no
|
|
|
2b0ae0 |
+ NM_CONTROLLED=no
|
|
|
2b0ae0 |
+ """), util.load_file(fname))
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ @mock.patch(MPATH + '.refresh_rmc')
|
|
|
2b0ae0 |
+ @mock.patch(MPATH + '.restart_network_manager')
|
|
|
2b0ae0 |
+ @mock.patch(MPATH + '.disable_ipv6')
|
|
|
2b0ae0 |
+ @mock.patch(MPATH + '.refresh_ipv6')
|
|
|
2b0ae0 |
+ @mock.patch(MPATH + '.netinfo.netdev_info')
|
|
|
2b0ae0 |
+ @mock.patch(MPATH + '.subp.which')
|
|
|
2b0ae0 |
+ def test_handle(self, m_refresh_rmc,
|
|
|
2b0ae0 |
+ m_netdev_info, m_refresh_ipv6, m_disable_ipv6,
|
|
|
2b0ae0 |
+ m_restart_nm, m_which):
|
|
|
2b0ae0 |
+ """Basic test of handle."""
|
|
|
2b0ae0 |
+ m_netdev_info.return_value = NET_INFO
|
|
|
2b0ae0 |
+ m_which.return_value = '/opt/rsct/bin/rmcctrl'
|
|
|
2b0ae0 |
+ ccrmci.handle(
|
|
|
2b0ae0 |
+ "refresh_rmc_and_interface", None, None, None, None)
|
|
|
2b0ae0 |
+ self.assertEqual(1, m_netdev_info.call_count)
|
|
|
2b0ae0 |
+ m_refresh_ipv6.assert_called_with('env5')
|
|
|
2b0ae0 |
+ m_disable_ipv6.assert_called_with(
|
|
|
2b0ae0 |
+ '/etc/sysconfig/network-scripts/ifcfg-env5')
|
|
|
2b0ae0 |
+ self.assertEqual(1, m_restart_nm.call_count)
|
|
|
2b0ae0 |
+ self.assertEqual(1, m_refresh_rmc.call_count)
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ @mock.patch(MPATH + '.netinfo.netdev_info')
|
|
|
2b0ae0 |
+ def test_find_ipv6(self, m_netdev_info):
|
|
|
2b0ae0 |
+ """find_ipv6_ifaces parses netdev_info returning those with ipv6"""
|
|
|
2b0ae0 |
+ m_netdev_info.return_value = NET_INFO
|
|
|
2b0ae0 |
+ found = ccrmci.find_ipv6_ifaces()
|
|
|
2b0ae0 |
+ self.assertEqual(['env5'], found)
|
|
|
2b0ae0 |
+
|
|
|
2b0ae0 |
+ @mock.patch(MPATH + '.subp.subp')
|
|
|
2b0ae0 |
+ def test_refresh_ipv6(self, m_subp):
|
|
|
2b0ae0 |
+ """refresh_ipv6 should ip down and up the interface."""
|
|
|
2b0ae0 |
+ iface = "myeth0"
|
|
|
2b0ae0 |
+ ccrmci.refresh_ipv6(iface)
|
|
|
2b0ae0 |
+ m_subp.assert_has_calls([
|
|
|
2b0ae0 |
+ mock.call(['ip', 'link', 'set', iface, 'down']),
|
|
|
2b0ae0 |
+ mock.call(['ip', 'link', 'set', iface, 'up'])])
|
|
|
2b0ae0 |
diff --git a/tools/.github-cla-signers b/tools/.github-cla-signers
|
|
|
2b0ae0 |
index c67db43..802a35b 100644
|
|
|
2b0ae0 |
--- a/tools/.github-cla-signers
|
|
|
2b0ae0 |
+++ b/tools/.github-cla-signers
|
|
|
2b0ae0 |
@@ -1,4 +1,5 @@
|
|
|
2b0ae0 |
AlexBaranowski
|
|
|
2b0ae0 |
+Aman306
|
|
|
2b0ae0 |
beezly
|
|
|
2b0ae0 |
bipinbachhao
|
|
|
2b0ae0 |
BirknerAlex
|
|
|
2b0ae0 |
--
|
|
|
2b0ae0 |
1.8.3.1
|
|
|
2b0ae0 |
|