Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add check feature 'on_exit' #28

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ Below are the default settings for all service checks, see `Configuring checks f
:check_fail: 2
:check_disabled: true
:on_disabled: withdraw
:on_exit: withdraw
:ip_check_disabled: false
:custom_bird_reconfigure_cmd_timeout: 2

Expand Down Expand Up @@ -447,6 +448,7 @@ Here are few examples::
check_rise = 2
check_disabled = false
on_disabled = withdraw
on_exit = none
ip_prefix = 10.52.12.1/32

[foo6.bar.com]
Expand All @@ -456,6 +458,7 @@ Here are few examples::
check_fail = 2
check_disabled = false
on_disabled = withdraw
on_exit = none
ip_prefix = fd12:aba6:57db:ffff::1/128
ip_check_disabled = false

Expand Down Expand Up @@ -489,6 +492,14 @@ A service is considered HEALTHY after these many consecutive successful health c

What to do when check is disabled, either ``withdraw`` or ``advertise``

* **on_exit** Defaults to **none**

What to do when anycast-healthchecker exits, either ``none`` or ``withdraw`` or ``advertise``.

* ``none`` keep state how it was from checks
* ``advertise`` ensure the ip_prefix to be advertised
* ``withdraw`` ensure the ip_prefix to be withdrawn

* **ip_prefix** Unset by default

IP prefix associated with the service. It **must be** assigned to the interface set in ``interface`` parameter unless ``ip_check_disabled`` is set to ``true``. Prefix length is optional and defaults to 32 for IPv4 addresses and to 128 for IPv6 addresses.
Expand Down
1 change: 1 addition & 0 deletions anycast_healthchecker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
'check_fail': 2,
'check_disabled': 'true',
'on_disabled': 'withdraw',
'on_exit': 'none',
'ip_check_disabled': 'false',
'custom_bird_reconfigure_cmd_timeout': 2,
},
Expand Down
47 changes: 47 additions & 0 deletions anycast_healthchecker/healthchecker.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
from anycast_healthchecker.utils import (SERVICE_OPTIONS_TYPE,
get_ip_prefixes_from_bird,
get_ip_prefixes_from_config,
get_ip_prefixes_from_config_on_exit,
reconfigure_bird,
write_temp_bird_conf,
archive_bird_conf,
AddOperation,
DeleteOperation,
ServiceCheckDiedError,
run_custom_bird_reconfigure)

Expand Down Expand Up @@ -226,3 +229,47 @@ def run(self):
self.bird_configuration[ip_version]['reconfigure_cmd'])
else:
run_custom_bird_reconfigure(operation)

def on_exit(self):
for ip_version in self.bird_configuration:
config_file = self.bird_configuration[ip_version]['config_file']
ip_prefixes_in_bird = get_ip_prefixes_from_bird(config_file)
_ip_prefix_withdraw = get_ip_prefixes_from_config_on_exit(
self.config,
self.services,
ip_version,
'withdraw')
_ip_prefix_advertise = get_ip_prefixes_from_config_on_exit(
self.config,
self.services,
ip_version,
'advertise')

for withdraw_ip_prefix in set(ip_prefixes_in_bird).intersection(_ip_prefix_withdraw):
_delete_operation = DeleteOperation(
name='on_exit',
ip_prefix=withdraw_ip_prefix,
ip_version=ip_version,
bird_reconfigure_timeout=(
self.config['daemon'].get('custom_bird_reconfigure_cmd_timeout')
),
bird_reconfigure_cmd=(
self.config['daemon'].get('custom_bird_reconfigure_cmd')
)
)
self._update_bird_conf_file(_delete_operation)

for add_ip_prefix in set(_ip_prefix_advertise).difference(ip_prefixes_in_bird):
_add_operation = AddOperation(
name='on_exit',
ip_prefix=add_ip_prefix,
ip_version=ip_version,
bird_reconfigure_timeout=(
self.config['daemon'].get('custom_bird_reconfigure_cmd_timeout')
),
bird_reconfigure_cmd=(
self.config['daemon'].get('custom_bird_reconfigure_cmd')
)
)
self._update_bird_conf_file(_add_operation)

5 changes: 3 additions & 2 deletions anycast_healthchecker/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ def main():
pidfile = config.get('daemon', 'pidfile')
update_pidfile(pidfile)

checker = healthchecker.HealthChecker(config, bird_configuration)

# Register our shutdown handler to various termination signals.
shutdown_handler = partial(shutdown, pidfile)
shutdown_handler = partial(shutdown, pidfile, checker)
signal.signal(signal.SIGHUP, shutdown_handler)
signal.signal(signal.SIGTERM, shutdown_handler)
signal.signal(signal.SIGABRT, shutdown_handler)
Expand All @@ -93,7 +95,6 @@ def main():
ip_prefixes_sanity_check(config, bird_configuration)

# Create our master process.
checker = healthchecker.HealthChecker(config, bird_configuration)
logger.info("starting %s version %s", PROGRAM_NAME, __version__)
checker.run()

Expand Down
36 changes: 35 additions & 1 deletion anycast_healthchecker/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'check_fail': 'getint',
'check_disabled': 'getboolean',
'on_disabled': 'get',
'on_exit': 'get',
'ip_prefix': 'get',
'interface': 'get',
'ip_check_disabled': 'getboolean',
Expand Down Expand Up @@ -144,6 +145,27 @@ def get_ip_prefixes_from_config(config, services, ip_version):

return ip_prefixes

def get_ip_prefixes_from_config_on_exit(config, services, ip_version, on_exit_status):
"""Build a set of IP prefixes found in service configuration files.

Arguments:
config (obg): A configparser object which holds our configuration.
services (list): A list of section names which are the name of the
service checks.
ip_version (int): IP protocol version

Returns:
A set of IP prefixes.

"""
ip_prefixes = set()

for service in services:
if config.get(service, 'on_exit') == on_exit_status:
ip_prefix = ipaddress.ip_network(config.get(service, 'ip_prefix'))
if ip_prefix.version == ip_version:
ip_prefixes.add(ip_prefix.with_prefixlen)
return ip_prefixes

def ip_prefixes_sanity_check(config, bird_configuration):
"""Sanity check on IP prefixes.
Expand Down Expand Up @@ -414,6 +436,17 @@ def service_configuration_check(config):
val=config.get(service, 'on_disabled')))
raise ValueError(msg)


if (config.get(service, 'on_exit') != 'withdraw' and
config.get(service, 'on_exit') != 'advertise' and
config.get(service, 'on_exit') != 'none'):
msg = ("'on_exit' option has invalid value ({val}) for "
"service check {name}, 'on_exit option should be set "
"either to 'withdraw' or to 'advertise' or to 'none'"
.format(name=service,
val=config.get(service, 'on_exit')))
raise ValueError(msg)

ip_prefixes.append(config.get(service, 'ip_prefix'))

if not valid_ip_prefix(config.get(service, 'ip_prefix')):
Expand Down Expand Up @@ -923,7 +956,7 @@ def write_pid(pidfile):
sys.exit("failed to write pidfile:{e}".format(e=exc))


def shutdown(pidfile, signalnb=None, frame=None):
def shutdown(pidfile, healthchecker, signalnb=None, frame=None):
"""Clean up pidfile upon shutdown.

Notice:
Expand All @@ -942,6 +975,7 @@ def shutdown(pidfile, signalnb=None, frame=None):
"""
log = logging.getLogger(PROGRAM_NAME)
log.info("received %s at %s", signalnb, frame)
healthchecker.on_exit()
log.info("going to remove pidfile %s", pidfile)
# no point to catch possible errors when we delete the pid file
os.unlink(pidfile)
Expand Down