summaryrefslogtreecommitdiff
path: root/src/helpers/vyos-failover.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/helpers/vyos-failover.py')
-rwxr-xr-xsrc/helpers/vyos-failover.py88
1 files changed, 64 insertions, 24 deletions
diff --git a/src/helpers/vyos-failover.py b/src/helpers/vyos-failover.py
index 0de945f20..ce4cf8fa4 100755
--- a/src/helpers/vyos-failover.py
+++ b/src/helpers/vyos-failover.py
@@ -30,7 +30,7 @@ my_name = Path(__file__).stem
def is_route_exists(route, gateway, interface, metric):
"""Check if route with expected gateway, dev and metric exists"""
- rc, data = rc_cmd(f'sudo ip --json route show protocol failover {route} '
+ rc, data = rc_cmd(f'ip --json route show protocol failover {route} '
f'via {gateway} dev {interface} metric {metric}')
if rc == 0:
data = json.loads(data)
@@ -72,6 +72,7 @@ def get_best_route_options(route, debug=False):
f'best_metric: {best_metric}, best_iface: {best_interface}')
return best_gateway, best_interface, best_metric
+
def is_port_open(ip, port):
"""
Check connection to remote host and port
@@ -91,32 +92,70 @@ def is_port_open(ip, port):
finally:
s.close()
-def is_target_alive(target=None, iface='', proto='icmp', port=None, debug=False):
- """
- Host availability check by ICMP, ARP, TCP
- Return True if target checks is successful
- % is_target_alive('192.0.2.1', 'eth1', proto='arp')
- True
+def is_target_alive(target_list=None,
+ iface='',
+ proto='icmp',
+ port=None,
+ debug=False,
+ policy='any-available') -> bool:
+ """Check the availability of each target in the target_list using
+ the specified protocol ICMP, ARP, TCP
+
+ Args:
+ target_list (list): A list of IP addresses or hostnames to check.
+ iface (str): The name of the network interface to use for the check.
+ proto (str): The protocol to use for the check. Options are 'icmp', 'arp', or 'tcp'.
+ port (int): The port number to use for the TCP check. Only applicable if proto is 'tcp'.
+ debug (bool): If True, print debug information during the check.
+ policy (str): The policy to use for the check. Options are 'any-available' or 'all-available'.
+
+ Returns:
+ bool: True if all targets are reachable according to the policy, False otherwise.
+
+ Example:
+ % is_target_alive(['192.0.2.1', '192.0.2.5'], 'eth1', proto='arp', policy='all-available')
+ True
"""
if iface != '':
iface = f'-I {iface}'
- if proto == 'icmp':
- command = f'/usr/bin/ping -q {target} {iface} -n -c 2 -W 1'
- rc, response = rc_cmd(command)
- if debug: print(f' [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]')
- if rc == 0:
- return True
- elif proto == 'arp':
- command = f'/usr/bin/arping -b -c 2 -f -w 1 -i 1 {iface} {target}'
- rc, response = rc_cmd(command)
- if debug: print(f' [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]')
- if rc == 0:
+
+ num_reachable_targets = 0
+ for target in target_list:
+ match proto:
+ case 'icmp':
+ command = f'/usr/bin/ping -q {target} {iface} -n -c 2 -W 1'
+ rc, response = rc_cmd(command)
+ if debug:
+ print(f' [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]')
+ if rc == 0:
+ num_reachable_targets += 1
+ if policy == 'any-available':
+ return True
+
+ case 'arp':
+ command = f'/usr/bin/arping -b -c 2 -f -w 1 -i 1 {iface} {target}'
+ rc, response = rc_cmd(command)
+ if debug:
+ print(f' [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]')
+ if rc == 0:
+ num_reachable_targets += 1
+ if policy == 'any-available':
+ return True
+
+ case _ if proto == 'tcp' and port is not None:
+ if is_port_open(target, port):
+ num_reachable_targets += 1
+ if policy == 'any-available':
+ return True
+
+ case _:
+ return False
+
+ if policy == 'all-available' and num_reachable_targets == len(target_list):
return True
- elif proto == 'tcp' and port is not None:
- return True if is_port_open(target, port) else False
- else:
- return False
+
+ return False
if __name__ == '__main__':
@@ -155,6 +194,7 @@ if __name__ == '__main__':
conf_metric = int(nexthop_config.get('metric'))
port = nexthop_config.get('check').get('port')
port_opt = f'port {port}' if port else ''
+ policy = nexthop_config.get('check').get('policy')
proto = nexthop_config.get('check').get('type')
target = nexthop_config.get('check').get('target')
timeout = nexthop_config.get('check').get('timeout')
@@ -163,7 +203,7 @@ if __name__ == '__main__':
if not is_route_exists(route, next_hop, conf_iface, conf_metric):
if debug: print(f" [NEW_ROUTE_DETECTED] route: [{route}]")
# Add route if check-target alive
- if is_target_alive(target, conf_iface, proto, port, debug=debug):
+ if is_target_alive(target, conf_iface, proto, port, debug=debug, policy=policy):
if debug: print(f' [ ADD ] -- ip route add {route} via {next_hop} dev {conf_iface} '
f'metric {conf_metric} proto failover\n###')
rc, command = rc_cmd(f'ip route add {route} via {next_hop} dev {conf_iface} '
@@ -182,7 +222,7 @@ if __name__ == '__main__':
# Route was added, check if the target is alive
# We should delete route if check fails only if route exists in the routing table
- if not is_target_alive(target, conf_iface, proto, port, debug=debug) and \
+ if not is_target_alive(target, conf_iface, proto, port, debug=debug, policy=policy) and \
is_route_exists(route, next_hop, conf_iface, conf_metric):
if debug:
print(f'Nexh_hop {next_hop} fail, target not response')