diff options
Diffstat (limited to 'src/helpers')
| -rwxr-xr-x | src/helpers/vyos-failover.py | 88 | 
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')  | 
