diff options
Diffstat (limited to 'src/conf_mode/vrrp.py')
-rwxr-xr-x | src/conf_mode/vrrp.py | 170 |
1 files changed, 37 insertions, 133 deletions
diff --git a/src/conf_mode/vrrp.py b/src/conf_mode/vrrp.py index b17f1ce82..8683faca7 100755 --- a/src/conf_mode/vrrp.py +++ b/src/conf_mode/vrrp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2018 VyOS maintainers and contributors +# Copyright (C) 2018-2020 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -13,135 +13,26 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# import os -import sys import subprocess -import ipaddress -import json -import jinja2 + +from sys import exit +from ipaddress import ip_address, ip_interface, IPv4Interface, IPv6Interface, IPv4Address, IPv6Address +from jinja2 import FileSystemLoader, Environment +from json import dumps +from pathlib import Path import vyos.config import vyos.keepalived +from vyos.defaults import directories as vyos_data_dir from vyos import ConfigError -from pathlib import Path daemon_file = "/etc/default/keepalived" config_file = "/etc/keepalived/keepalived.conf" config_dict_path = "/run/keepalived_config.dict" -config_tmpl = """ -# Autogenerated by VyOS -# Do not edit this file, all your changes will be lost -# on next commit or reboot - -global_defs { - dynamic_interfaces - script_user root - notify_fifo /run/keepalived_notify_fifo - notify_fifo_script /usr/libexec/vyos/system/keepalived-fifo.py -} - -{% for group in groups -%} - -{% if group.health_check_script -%} -vrrp_script healthcheck_{{ group.name }} { - script "{{ group.health_check_script }}" - interval {{ group.health_check_interval }} - fall {{ group.health_check_count }} - rise 1 - -} -{% endif %} - -vrrp_instance {{ group.name }} { - {% if group.description -%} - # {{ group.description }} - {% endif -%} - - state BACKUP - interface {{ group.interface }} - virtual_router_id {{ group.vrid }} - priority {{ group.priority }} - advert_int {{ group.advertise_interval }} - - {% if group.preempt -%} - preempt_delay {{ group.preempt_delay }} - {% else -%} - nopreempt - {% endif -%} - - {% if group.peer_address -%} - unicast_peer { {{ group.peer_address }} } - {% endif -%} - - {% if group.hello_source -%} - {%- if group.peer_address -%} - unicast_src_ip {{ group.hello_source }} - {%- else -%} - mcast_src_ip {{ group.hello_source }} - {%- endif %} - {% endif -%} - - {% if group.use_vmac and group.peer_address -%} - use_vmac {{group.interface}}v{{group.vrid}} - vmac_xmit_base - {% elif group.use_vmac -%} - use_vmac {{group.interface}}v{{group.vrid}} - {% endif -%} - - {% if group.auth_password -%} - authentication { - auth_pass "{{ group.auth_password }}" - auth_type {{ group.auth_type }} - } - {% endif -%} - - virtual_ipaddress { - {% for addr in group.virtual_addresses -%} - {{ addr }} - {% endfor -%} - } - - {% if group.health_check_script -%} - track_script { - healthcheck_{{ group.name }} - } - {% endif -%} -} - -{% endfor -%} - -{% for sync_group in sync_groups -%} -vrrp_sync_group {{ sync_group.name }} { - group { - {% for member in sync_group.members -%} - {{ member }} - {% endfor -%} - } - - {% if sync_group.conntrack_sync -%} - notify_master "/opt/vyatta/sbin/vyatta-vrrp-conntracksync.sh master {{ sync_group.name }}" - notify_backup "/opt/vyatta/sbin/vyatta-vrrp-conntracksync.sh backup {{ sync_group.name }}" - notify_fault "/opt/vyatta/sbin/vyatta-vrrp-conntracksync.sh fault {{ sync_group.name }}" - {% endif -%} -} - -{% endfor -%} - -""" - -daemon_tmpl = """ -# Autogenerated by VyOS -# Options to pass to keepalived - -# DAEMON_ARGS are appended to the keepalived command-line -DAEMON_ARGS="--snmp" -""" - - def get_config(): vrrp_groups = [] sync_groups = [] @@ -209,7 +100,7 @@ def get_config(): vrrp_groups.append(group) - config.set_level("") + config.set_level("") # Get the sync group used for conntrack-sync conntrack_sync_group = None @@ -227,11 +118,17 @@ def get_config(): if conntrack_sync_group == sync_group_name: sync_group["conntrack_sync"] = True + # add transition script configuration + sync_group["master_script"] = config.return_value("transition-script master") + sync_group["backup_script"] = config.return_value("transition-script backup") + sync_group["fault_script"] = config.return_value("transition-script fault") + sync_group["stop_script"] = config.return_value("transition-script stop") + sync_groups.append(sync_group) # create a file with dict with proposed configuration with open("{}.temp".format(config_dict_path), 'w') as dict_file: - dict_file.write(json.dumps({'vrrp_groups': vrrp_groups, 'sync_groups': sync_groups})) + dict_file.write(dumps({'vrrp_groups': vrrp_groups, 'sync_groups': sync_groups})) return (vrrp_groups, sync_groups) @@ -256,31 +153,31 @@ def verify(data): # XXX: filter on map object is destructive, so we force it to list. # Additionally, filter objects always evaluate to True, empty or not, # so we force them to lists as well. - vaddrs = list(map(lambda i: ipaddress.ip_interface(i), group["virtual_addresses"])) - vaddrs4 = list(filter(lambda x: isinstance(x, ipaddress.IPv4Interface), vaddrs)) - vaddrs6 = list(filter(lambda x: isinstance(x, ipaddress.IPv6Interface), vaddrs)) + vaddrs = list(map(lambda i: ip_interface(i), group["virtual_addresses"])) + vaddrs4 = list(filter(lambda x: isinstance(x, IPv4Interface), vaddrs)) + vaddrs6 = list(filter(lambda x: isinstance(x, IPv6Interface), vaddrs)) if vaddrs4 and vaddrs6: raise ConfigError("VRRP group {0} mixes IPv4 and IPv6 virtual addresses, this is not allowed. Create separate groups for IPv4 and IPv6".format(group["name"])) if vaddrs4: if group["hello_source"]: - hsa = ipaddress.ip_address(group["hello_source"]) - if isinstance(hsa, ipaddress.IPv6Address): + hsa = ip_address(group["hello_source"]) + if isinstance(hsa, IPv6Address): raise ConfigError("VRRP group {0} uses IPv4 but its hello-source-address is IPv6".format(group["name"])) if group["peer_address"]: - pa = ipaddress.ip_address(group["peer_address"]) - if isinstance(pa, ipaddress.IPv6Address): + pa = ip_address(group["peer_address"]) + if isinstance(pa, IPv6Address): raise ConfigError("VRRP group {0} uses IPv4 but its peer-address is IPv6".format(group["name"])) if vaddrs6: if group["hello_source"]: - hsa = ipaddress.ip_address(group["hello_source"]) - if isinstance(hsa, ipaddress.IPv4Address): + hsa = ip_address(group["hello_source"]) + if isinstance(hsa, IPv4Address): raise ConfigError("VRRP group {0} uses IPv6 but its hello-source-address is IPv4".format(group["name"])) if group["peer_address"]: - pa = ipaddress.ip_address(group["peer_address"]) - if isinstance(pa, ipaddress.IPv4Address): + pa = ip_address(group["peer_address"]) + if isinstance(pa, IPv4Address): raise ConfigError("VRRP group {0} uses IPv6 but its peer-address is IPv4".format(group["name"])) # Disallow same VRID on multiple interfaces @@ -304,6 +201,11 @@ def verify(data): def generate(data): + # Prepare Jinja2 template loader from files + tmpl_path = os.path.join(vyos_data_dir['data'], 'templates', 'vrrp') + fs_loader = FileSystemLoader(tmpl_path) + env = Environment(loader=fs_loader) + vrrp_groups, sync_groups = data # Remove disabled groups from the sync group member lists @@ -315,13 +217,15 @@ def generate(data): # Filter out disabled groups vrrp_groups = list(filter(lambda x: x["disable"] is not True, vrrp_groups)) - tmpl = jinja2.Template(config_tmpl) + tmpl = env.get_template('keepalived.conf.tmpl') config_text = tmpl.render({"groups": vrrp_groups, "sync_groups": sync_groups}) with open(config_file, 'w') as f: f.write(config_text) + tmpl = env.get_template('daemon.tmpl') + config_text = tmpl.render() with open(daemon_file, 'w') as f: - f.write(daemon_tmpl) + f.write(config_text) return None @@ -362,4 +266,4 @@ if __name__ == '__main__': apply(c) except ConfigError as e: print("VRRP error: {0}".format(str(e))) - sys.exit(1) + exit(1) |