-
Notifications
You must be signed in to change notification settings - Fork 151
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding a couple of actors to help migrate quagga to frr (#467)
Migrate Quagga to FRR Quagga has been replaced by FRR on RHEL 8 systems: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_and_managing_networking/setting-your-routing-protocols_configuring-and-managing-networking Actors automatically migrate the Quagga setup to FRR, except on systems using the babeld daemon which has been dropped from FRR because of licensing issues. If the use of the babeld daemon is detected, IPU is inhibited and user is notified to reconfigure the system to use otherservices instead.
- Loading branch information
Showing
11 changed files
with
482 additions
and
0 deletions.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
repos/system_upgrade/el7toel8/actors/quaggadaemons/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor.quaggadaemons import process_daemons | ||
from leapp.libraries.common.rpms import has_package | ||
from leapp.models import InstalledRedHatSignedRPM, QuaggaToFrrFacts | ||
from leapp.tags import FactsPhaseTag, IPUWorkflowTag | ||
|
||
|
||
class QuaggaDaemons(Actor): | ||
""" | ||
Active quagga daemons check. | ||
Checking for daemons that are currently running in the system. | ||
These should be enabled in /etc/frr/daemons later in the process. | ||
The tools will check for config files later on since these should stay in the system. | ||
""" | ||
|
||
name = 'quagga_daemons' | ||
consumes = (InstalledRedHatSignedRPM,) | ||
produces = (QuaggaToFrrFacts,) | ||
tags = (FactsPhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
if has_package(InstalledRedHatSignedRPM, 'quagga'): | ||
self.produce(process_daemons()) |
37 changes: 37 additions & 0 deletions
37
repos/system_upgrade/el7toel8/actors/quaggadaemons/libraries/quaggadaemons.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
from leapp.libraries.stdlib import CalledProcessError, api, run | ||
from leapp.models import QuaggaToFrrFacts | ||
|
||
QUAGGA_DAEMONS = [ | ||
'babeld', | ||
'bgpd', | ||
'isisd', | ||
'ospf6d', | ||
'ospfd', | ||
'ripd', | ||
'ripngd', | ||
'zebra' | ||
] | ||
|
||
|
||
def _check_service(name, state): | ||
try: | ||
run(['systemctl', 'is-{}'.format(state), name]) | ||
api.current_logger().debug('%s is %s', name, state) | ||
except CalledProcessError: | ||
api.current_logger().debug('%s is not %s', name, state) | ||
return False | ||
|
||
return True | ||
|
||
|
||
def process_daemons(): | ||
active_daemons = [daemon for daemon in QUAGGA_DAEMONS if _check_service(daemon, 'active')] | ||
enabled_daemons = [daemon for daemon in QUAGGA_DAEMONS if _check_service(daemon, 'enabled')] | ||
|
||
if active_daemons: | ||
api.current_logger().debug('active quaggadaemons: %s', ', '.join(active_daemons)) | ||
|
||
if enabled_daemons: | ||
api.current_logger().debug('enabled quaggadaemons: %s', ', '.join(enabled_daemons)) | ||
|
||
return QuaggaToFrrFacts(active_daemons=active_daemons, enabled_daemons=enabled_daemons) |
21 changes: 21 additions & 0 deletions
21
repos/system_upgrade/el7toel8/actors/quaggadaemons/tests/test_unit_quaggadaemons.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from leapp.libraries.actor import quaggadaemons | ||
from leapp.models import QuaggaToFrrFacts | ||
|
||
# daemons for mocked _check_service function | ||
TEST_DAEMONS = ['bgpd', 'ospfd', 'zebra'] | ||
|
||
|
||
def mock_check_service(name, state): | ||
if name in TEST_DAEMONS: | ||
return True | ||
|
||
return False | ||
|
||
|
||
def test_process_daemons(): | ||
quaggadaemons._check_service = mock_check_service | ||
|
||
facts = quaggadaemons.process_daemons() | ||
assert isinstance(facts, QuaggaToFrrFacts) | ||
assert facts.active_daemons == TEST_DAEMONS | ||
assert facts.enabled_daemons == TEST_DAEMONS |
50 changes: 50 additions & 0 deletions
50
repos/system_upgrade/el7toel8/actors/quaggareport/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
from leapp import reporting | ||
from leapp.actors import Actor | ||
from leapp.models import QuaggaToFrrFacts, Report | ||
from leapp.reporting import create_report | ||
from leapp.tags import ChecksPhaseTag, IPUWorkflowTag | ||
|
||
COMMON_REPORT_TAGS = [ | ||
reporting.Tags.NETWORK, | ||
reporting.Tags.SERVICES | ||
] | ||
|
||
|
||
class QuaggaReport(Actor): | ||
""" | ||
Checking for babeld on RHEL-7. | ||
This actor is supposed to report that babeld was used on RHEL-7 | ||
and it is no longer available in RHEL-8. | ||
""" | ||
|
||
name = 'quagga_report' | ||
consumes = (QuaggaToFrrFacts, ) | ||
produces = (Report, ) | ||
tags = (ChecksPhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
try: | ||
quagga_facts = next(self.consume(QuaggaToFrrFacts)) | ||
except StopIteration: | ||
return | ||
if 'babeld' in quagga_facts.active_daemons or 'babeld' in quagga_facts.enabled_daemons: | ||
create_report([ | ||
reporting.Title('Babeld is not available in FRR'), | ||
reporting.ExternalLink( | ||
url='https://access.redhat.com/' | ||
'documentation/en-us/red_hat_enterprise_linux/8/html/' | ||
'configuring_and_managing_networking/setting-your-rou' | ||
'ting-protocols_configuring-and-managing-networking', | ||
title='Setting routing protocols in RHEL8'), | ||
reporting.Summary( | ||
'babeld daemon which was a part of quagga implementation in RHEL7 ' | ||
'is not available in RHEL8 in FRR due to licensing issues.' | ||
), | ||
reporting.Severity(reporting.Severity.HIGH), | ||
reporting.Tags(COMMON_REPORT_TAGS), | ||
reporting.Flags([reporting.Flags.INHIBITOR]), | ||
reporting.Remediation(hint='Please use RIP, OSPF or EIGRP instead of Babel') | ||
]) | ||
else: | ||
self.log.debug('babeld not used, moving on.') |
40 changes: 40 additions & 0 deletions
40
repos/system_upgrade/el7toel8/actors/quaggareport/tests/test_quaggareport.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import pytest | ||
|
||
from leapp.models import QuaggaToFrrFacts | ||
from leapp.snactor.fixture import ActorContext | ||
|
||
|
||
# TODO We can't use caplog here as logs from other processes is | ||
# hard to capture and caplog not see it. | ||
@pytest.mark.parametrize( | ||
("quagga_facts", "active_daemons", "has_report", "msg_in_log"), | ||
[ | ||
(True, ["babeld"], True, None), | ||
(True, ["something_else"], False, "babeld not used, moving on"), | ||
(False, [], False, None), | ||
], | ||
) | ||
def test_quaggareport( | ||
monkeypatch, | ||
current_actor_context, | ||
quagga_facts, | ||
active_daemons, | ||
has_report, | ||
msg_in_log, | ||
): | ||
"""Test quaggareport. | ||
:type current_actor_context:ActorContext | ||
""" | ||
if quagga_facts: | ||
current_actor_context.feed( | ||
QuaggaToFrrFacts( | ||
active_daemons=active_daemons, | ||
enabled_daemons=["bgpd", "ospfd", "zebra"], | ||
) | ||
) | ||
current_actor_context.run() | ||
if has_report: | ||
assert current_actor_context.messages()[0]["type"] == "Report" | ||
if msg_in_log: | ||
assert not current_actor_context.messages() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor.quaggatofrr import process_facts | ||
from leapp.models import QuaggaToFrrFacts | ||
from leapp.tags import ApplicationsPhaseTag, IPUWorkflowTag | ||
|
||
|
||
class QuaggaToFrr(Actor): | ||
""" | ||
Edit frr configuration on the new system. | ||
Take gathered info about quagga from RHEL 7 and apply these to frr in RHEL 8. | ||
""" | ||
|
||
name = 'quagga_to_frr' | ||
consumes = (QuaggaToFrrFacts, ) | ||
produces = () | ||
tags = (ApplicationsPhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
quagga_facts = next(self.consume(QuaggaToFrrFacts), None) | ||
|
||
if quagga_facts: | ||
process_facts(quagga_facts) |
87 changes: 87 additions & 0 deletions
87
repos/system_upgrade/el7toel8/actors/quaggatofrr/libraries/quaggatofrr.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import os | ||
import re | ||
import shutil | ||
|
||
from leapp.libraries.stdlib import CalledProcessError, api, run | ||
|
||
DAEMON_FILE = '/etc/frr/daemons' | ||
# if this file sitll exists after the removal of quagga, it has been modified | ||
CONFIG_FILE = '/etc/sysconfig/quagga.rpmsave' | ||
QUAGGA_CONF_FILES = '/etc/quagga/' | ||
FRR_CONF_FILES = '/etc/frr/' | ||
|
||
regex = re.compile(r'\w+(?<!WATCH)(?<!BABELD)_OPTS=".*"') | ||
|
||
|
||
def _get_config_data(path): | ||
conf_data = {} | ||
with open(path) as f: | ||
for line in f: | ||
if regex.match(line): | ||
k, v = line.rstrip().split("=") | ||
conf_data[k.split("_")[0].lower()] = v.strip('"') | ||
|
||
return conf_data | ||
|
||
|
||
def _edit_new_config(path, active_daemons, config_data): | ||
with open(path, 'r') as f: | ||
data = f.read() | ||
|
||
# replace no as yes in /etc/frr/daemons | ||
for daemon in active_daemons: | ||
data = re.sub(r'{}=no'.format(daemon), r'{}=yes'.format(daemon), data, flags=re.MULTILINE) | ||
|
||
if config_data: | ||
for daemon in config_data: | ||
data = re.sub(r'{}_options=\(".*"\)'.format(daemon), | ||
r'{}_options=("{}")'.format(daemon, config_data[daemon]), | ||
data, flags=re.MULTILINE) | ||
|
||
return data | ||
|
||
|
||
# 1. parse /etc/sysconfig/quagga.rpmsave if it exists | ||
# 2. change =no to =yes with every enabled daemon | ||
# 3. use data from data from quagga.rpmsave in new daemon file | ||
def _change_config(quagga_facts): | ||
config_data = {} | ||
if os.path.isfile(CONFIG_FILE): | ||
config_data = _get_config_data(CONFIG_FILE) | ||
|
||
# This file should definitely exist, if not, something went wrong with the upgrade | ||
if os.path.isfile(DAEMON_FILE): | ||
data = _edit_new_config(DAEMON_FILE, quagga_facts.active_daemons, config_data) | ||
with open(DAEMON_FILE, 'w') as f: | ||
f.write(data) | ||
|
||
|
||
# In quagga, each daemon needed to be started individually | ||
# In frr, only frr is started as a daemon, the rest is started based on the daemons file | ||
# So as long as at least one daemon was active in quagga, frr should be enabled | ||
def _enable_frr(quagga_facts): | ||
# remove babeld? | ||
if quagga_facts.enabled_daemons: | ||
try: | ||
run(['systemctl', 'enable', 'frr']) | ||
except CalledProcessError: | ||
return False | ||
|
||
return True | ||
|
||
|
||
# due to an error in quagga, the conf files are not deleted after uninstall | ||
# we can copy them as they are | ||
def _copy_config_files(src_path, dest_path): | ||
conf_files = os.listdir(src_path) | ||
for file_name in conf_files: | ||
full_path = os.path.join(src_path, file_name) | ||
if os.path.isfile(full_path): | ||
shutil.copy(full_path, dest_path) | ||
api.current_logger().debug('Copying %s to %s%s', full_path, dest_path, file_name) | ||
|
||
|
||
def process_facts(quagga_facts): | ||
_change_config(quagga_facts) | ||
_copy_config_files(QUAGGA_CONF_FILES, FRR_CONF_FILES) | ||
_enable_frr(quagga_facts) |
82 changes: 82 additions & 0 deletions
82
repos/system_upgrade/el7toel8/actors/quaggatofrr/tests/files/daemons
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# This file tells the frr package which daemons to start. | ||
# | ||
# Entries are in the format: <daemon>=(yes|no|priority) | ||
# 0, "no" = disabled | ||
# 1, "yes" = highest priority | ||
# 2 .. 10 = lower priorities | ||
# | ||
# For daemons which support multiple instances, a 2nd line listing | ||
# the instances can be added. Eg for ospfd: | ||
# ospfd=yes | ||
# ospfd_instances="1,2" | ||
# | ||
# Priorities were suggested by Dancer <[email protected]>. | ||
# They're used to start the FRR daemons in more than one step | ||
# (for example start one or two at network initialization and the | ||
# rest later). The number of FRR daemons being small, priorities | ||
# must be between 1 and 9, inclusive (or the initscript has to be | ||
# changed). /etc/init.d/frr then can be started as | ||
# | ||
# /etc/init.d/frr <start|stop|restart|<priority>> | ||
# | ||
# where priority 0 is the same as 'stop', priority 10 or 'start' | ||
# means 'start all' | ||
# | ||
# Sample configurations for these daemons can be found in | ||
# /usr/share/doc/frr/examples/. | ||
# | ||
# ATTENTION: | ||
# | ||
# When activation a daemon at the first time, a config file, even if it is | ||
# empty, has to be present *and* be owned by the user and group "frr", else | ||
# the daemon will not be started by /etc/init.d/frr. The permissions should | ||
# be u=rw,g=r,o=. | ||
# When using "vtysh" such a config file is also needed. It should be owned by | ||
# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. | ||
# | ||
watchfrr_enable=yes | ||
watchfrr_options="-r '/usr/lib/frr/frr restart %s' -s '/usr/lib/frr/frr start %s' -k '/usr/lib/frr/frr stop %s'" | ||
# | ||
zebra=no | ||
bgpd=no | ||
ospfd=no | ||
ospf6d=no | ||
ripd=no | ||
ripngd=no | ||
isisd=no | ||
pimd=no | ||
nhrpd=no | ||
eigrpd=no | ||
sharpd=no | ||
pbrd=no | ||
staticd=no | ||
bfdd=no | ||
fabricd=no | ||
|
||
# | ||
# Command line options for the daemons | ||
# | ||
zebra_options=("-A 127.0.0.1") | ||
bgpd_options=("-A 127.0.0.1") | ||
ospfd_options=("-A 127.0.0.1") | ||
ospf6d_options=("-A ::1") | ||
ripd_options=("-A 127.0.0.1") | ||
ripngd_options=("-A ::1") | ||
isisd_options=("-A 127.0.0.1") | ||
pimd_options=("-A 127.0.0.1") | ||
nhrpd_options=("-A 127.0.0.1") | ||
eigrpd_options=("-A 127.0.0.1") | ||
sharpd_options=("-A 127.0.0.1") | ||
pbrd_options=("-A 127.0.0.1") | ||
staticd_options=("-A 127.0.0.1") | ||
bfdd_options=("-A 127.0.0.1") | ||
fabricd_options=("-A 127.0.0.1") | ||
|
||
# | ||
# If the vtysh_enable is yes, then the unified config is read | ||
# and applied if it exists. If no unified frr.conf exists | ||
# then the per-daemon <daemon>.conf files are used) | ||
# If vtysh_enable is no or non-existant, the frr.conf is ignored. | ||
# it is highly suggested to have this set to yes | ||
vtysh_enable=yes | ||
|
24 changes: 24 additions & 0 deletions
24
repos/system_upgrade/el7toel8/actors/quaggatofrr/tests/files/quagga
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# | ||
# Default: Bind all daemon vtys to the loopback(s) only | ||
# | ||
BABELD_OPTS="--daemon -A 192.168.100.1" | ||
BGPD_OPTS="--daemon -A 10.10.100.1" | ||
ISISD_OPTS="--daemon -A ::1" | ||
OSPF6D_OPTS="-A ::1" | ||
OSPFD_OPTS="-A 127.0.0.1" | ||
RIPD_OPTS="-A 127.0.0.1" | ||
RIPNGD_OPTS="-A ::1" | ||
ZEBRA_OPTS="-s 90000000 --daemon -A 127.0.0.1" | ||
|
||
# Watchquagga configuration for LSB initscripts | ||
# | ||
# (Not needed with systemd: the service files are configured to automatically | ||
# restart any daemon on failure. If zebra fails, all running daemons will be | ||
# stopped; zebra will be started again; and then the previously running daemons | ||
# will be started again.) | ||
# | ||
# Uncomment and edit this line to reflect the daemons you are actually using: | ||
#WATCH_DAEMONS="zebra bgpd ospfd ospf6d ripd ripngd" | ||
# | ||
# Timer values can be adjusting by editing this line: | ||
WATCH_OPTS="-Az -b_ -r/sbin/service_%s_restart -s/sbin/service_%s_start -k/sbin/service_%s_stop" |
Oops, something went wrong.