Exemplo n.º 1
0
    def _update_bird_conf_file(self, operation):
        """Update BIRD configuration.

        It adds to or removes IP prefix from BIRD configuration. It also
        updates generation time stamp in the configuration file.

        Main program will exit if configuration file cant be read/written.

        Arguments:
            operation (obj): Either an AddOperation or DeleteOperation object

        Returns:
            True if BIRD configuration was updated otherwise False.

        """
        conf_updated = False
        prefixes = []
        ip_version = operation.ip_version
        config_file = self.bird_configuration[ip_version]['config_file']
        variable_name = self.bird_configuration[ip_version]['variable_name']
        changes_counter =\
            self.bird_configuration[ip_version]['changes_counter']
        dummy_ip_prefix =\
            self.bird_configuration[ip_version]['dummy_ip_prefix']

        try:
            prefixes = get_ip_prefixes_from_bird(config_file)
        except OSError as error:
            self.log.error(
                "failed to open Bird configuration %s, this is a "
                "FATAL error, thus exiting main program", error)
            sys.exit(1)

        if not prefixes:
            self.log.error(
                "found empty bird configuration %s, this is a FATAL"
                " error, thus exiting main program", config_file)
            sys.exit(1)

        if dummy_ip_prefix not in prefixes:
            self.log.warning(
                "dummy IP prefix %s wasn't found in bird "
                "configuration, adding it. This shouldn't have "
                "happened!", dummy_ip_prefix)
            prefixes.insert(0, dummy_ip_prefix)
            conf_updated = True

        ip_prefixes_without_check = set(prefixes).difference(
            self.ip_prefixes[ip_version])
        if ip_prefixes_without_check:
            self.log.warning(
                "found %s IP prefixes in Bird configuration but "
                "we aren't configured to run health checks on "
                "them. Either someone modified the configuration "
                "manually or something went horrible wrong. We "
                "remove them from Bird configuration",
                ','.join(ip_prefixes_without_check))
            # This is faster than using lambda and filter.
            # NOTE: We don't use remove method as we want to remove more than
            # occurrences of the IP prefixes without check.
            prefixes[:] = (ip for ip in prefixes
                           if ip not in ip_prefixes_without_check)
            conf_updated = True

        # Update the list of IP prefixes based on the status of health check.
        if operation.update(prefixes):
            conf_updated = True

        if not conf_updated:
            self.log.info('no updates for bird configuration')
            return conf_updated

        if self.bird_configuration[ip_version]['keep_changes']:
            archive_bird_conf(config_file, changes_counter)

        # some IP prefixes are either removed or added, create
        # configuration with new data.
        tempname = write_temp_bird_conf(dummy_ip_prefix, config_file,
                                        variable_name, prefixes)
        try:
            os.rename(tempname, config_file)
        except OSError as error:
            self.log.critical(
                "failed to create Bird configuration %s, this "
                "is a FATAL error, thus exiting main program", error)
            sys.exit(1)
        else:
            self.log.info("Bird configuration for IPv%s is updated",
                          ip_version)

        # dummy_ip_prefix is always there
        if len(prefixes) == 1:
            self.log.warning("Bird configuration doesn't have IP prefixes for "
                             "any of the services we monitor! It means local "
                             "node doesn't receive any traffic")

        return conf_updated
    def _update_bird_conf_file(self, operation):
        """Updates BIRD configuration.

        Adds/removes entries from a list and updates generation time stamp.
        Main program will exit if configuration file cant be read/written.

        Arguments:
            operation (obj): Either an AddOperation or DeleteOperation object

        Returns:
            True if BIRD configuration was updated otherwise False.

        """
        conf_updated = False
        prefixes = []
        ip_version = operation.ip_version
        config_file = self.bird_configuration[ip_version]['config_file']
        variable_name = self.bird_configuration[ip_version]['variable_name']
        changes_counter =\
            self.bird_configuration[ip_version]['changes_counter']
        dummy_ip_prefix =\
            self.bird_configuration[ip_version]['dummy_ip_prefix']

        try:
            prefixes = get_ip_prefixes_from_bird(config_file)
        except OSError as error:
            msg = ("failed to open Bird configuration {e}, this is a FATAL "
                   "error, thus exiting main program"
                   .format(e=error))
            self.log.error(msg, priority=80)
            sys.exit(1)

        if not prefixes:
            msg = ("found empty bird configuration:{f}, this is a FATAL "
                   "error, thus exiting main program"
                   .format(f=config_file))
            self.log.error(msg, priority=80)
            sys.exit(1)

        if dummy_ip_prefix not in prefixes:
            msg = ("dummy IP prefix {i} wasn't found in bird configuration, "
                   "adding it. This shouldn't have happened!"
                   .format(i=dummy_ip_prefix))
            self.log.warning(msg, priority=20)
            prefixes.insert(0, dummy_ip_prefix)
            conf_updated = True

        ip_prefixes_without_check = set(prefixes).difference(
            self.ip_prefixes[ip_version])
        if ip_prefixes_without_check:
            msg = ("found {i} IP prefixes in Bird configuration but we aren't "
                   "configured to run health checks on them. Either someone "
                   "modified the configuration manually or something went "
                   "horrible wrong. We remove them from Bird configuration"
                   .format(i=','.join(ip_prefixes_without_check)))
            self.log.warning(msg, priority=20)
            # This is faster than using lambda and filter.
            # NOTE: We don't use remove method as we want to remove more than
            # occurrences of the IP prefixes without check.
            prefixes[:] = (ip for ip in prefixes
                           if ip not in ip_prefixes_without_check)
            conf_updated = True

        # Update the list of IP prefixes based on the status of health check.
        if operation.update(prefixes):
            conf_updated = True

        if not conf_updated:
            self.log.info('no updates for bird configuration')
            return conf_updated

        if self.bird_configuration[ip_version]['keep_changes']:
            archive_bird_conf(self.log, config_file, changes_counter)

        # some IP prefixes are either removed or added, create
        # configuration with new data.
        tempname = write_temp_bird_conf(
            self.log,
            dummy_ip_prefix,
            config_file,
            variable_name,
            prefixes
        )
        try:
            os.rename(tempname, config_file)
        except OSError as error:
            msg = ('failed to create Bird configuration {e}, this is a FATAL '
                   'error, thus exiting main program'
                   .format(e=error))
            self.log.critical(msg, priority=80)
            sys.exit(1)
        else:
            self.log.info("Bird configuration for IPv{v} is updated"
                          .format(v=ip_version))

        # dummy_ip_prefix is always there
        if len(prefixes) == 1:
            self.log.warning("Bird configuration doesn't have IP prefixes for "
                             "any of the services we monitor! It means local "
                             "node doesn't receive any traffic", priority=80)

        return conf_updated
Exemplo n.º 3
0
    def _update_bird_conf_file(self, operation):
        """Updates BIRD configuration.

        Adds/removes entries from a list and updates generation time stamp.
        Main program will exit if configuration file cant be read/written.

        Arguments:
            operation (obj): Either an AddOperation or DeleteOperation object

        Returns:
            True if BIRD configuration was updated otherwise False.

        """
        conf_updated = False
        prefixes = []

        try:
            prefixes = get_ip_prefixes_from_bird(self.bird_conf_file)
        except OSError as error:
            msg = ("failed to open Bird configuration {e}, this is a FATAL "
                   "error, thus exiting main program"
                   .format(e=error))
            self.log.error(msg, priority=80)
            sys.exit(1)

        if not prefixes:
            msg = ("found empty bird configuration:{f}, this is a FATAL "
                   "error, thus exiting main program"
                   .format(f=self.bird_conf_file))
            self.log.error(msg, priority=80)
            sys.exit(1)

        if self.dummy_ip_prefix not in prefixes:
            msg = ("dummy IP prefix {i} wasn't found in bird configuration, "
                   "adding it. This shouldn't have happened!"
                   .format(i=self.dummy_ip_prefix))
            self.log.warning(msg, priority=20)
            prefixes.insert(0, self.dummy_ip_prefix)
            conf_updated = True

        # Remove IP prefixes for which we don't have a configuration for them.
        notconfigured_ip_prefixes = ip_prefixes_without_config(prefixes,
                                                               self.config,
                                                               self.services)
        if notconfigured_ip_prefixes:
            msg = ("found {i} IP prefixes in Bird configuration but we aren't "
                   "configured to run health checks on them. Either someone "
                   "modified the configuration manually or something went "
                   "horrible wrong. Thus, we remove them from Bird "
                   "configuration"
                   .format(i=','.join(notconfigured_ip_prefixes)))
            self.log.warning(msg, priority=20)
            # This is faster than using lambda and filter.
            # NOTE: We don't use remove method as we want to remove more than
            # occurrences of the IP prefixes without check.
            prefixes[:] = (ip for ip in prefixes
                           if ip not in notconfigured_ip_prefixes)
            conf_updated = True

        # Update the list of IP prefixes based on the status of health check.
        if operation.update(prefixes):
            conf_updated = True

        if not conf_updated:
            self.log.info('no updates for bird configuration')
            return conf_updated

        if self.keep_bird_changes:
            archive_bird_conf(self.log,
                              self.bird_conf_file,
                              self.changes_counter)

        # some IP prefixes are either removed or added, create
        # configuration with new data.
        tempname = write_temp_bird_conf(self.log,
                                        self.dummy_ip_prefix,
                                        self.bird_conf_file,
                                        self.bird_constant_name,
                                        prefixes)
        try:
            os.rename(tempname, self.bird_conf_file)
        except OSError as error:
            msg = ('failed to create Bird configuration {e}, this is a FATAL '
                   'error, thus exiting main program'
                   .format(e=error))
            self.log.critical(msg, priority=80)
            sys.exit(1)
        else:
            self.log.info('Bird configuration is updated')

        # dummy_ip_prefix is always there
        if len(prefixes) == 1:
            self.log.warning("Bird configuration doesn't have IP prefixes for "
                             "any of the services we monitor! It means local "
                             "node doesn't receive any traffic", priority=80)

        return conf_updated
Exemplo n.º 4
0
    def _update_bird_prefix_conf(self, operation):
        """Updates BIRD configuration.

        Adds/removes entries from a list and updates generation time stamp.
        Main program will exit if configuration file cant be read/written.

        Arguments:
            operation (obj): Either an AddOperation or DeleteOperation object

        Returns:
            True if BIRD configuration was updated otherwise False.

        """
        conf_updated = False
        prefixes = []
        comment = ("# {} is a dummy IP Prefix. It should NOT be used and "
                   "REMOVED from the constant.".format(self.dummy_ip_prefix))

        try:
            prefixes = get_ip_prefixes_from_bird(self.bird_conf_file, die=False)
        except OSError as err:
            self.log.error("Failed to open bird configuration, {}".format(err))
            self.log.critical("This is a FATAL error, exiting")
            sys.exit(1)

        if not prefixes:
            self.log.error("Found empty bird configuration:{}".format(
                self.bird_conf_file))
            self.log.critical("This is a FATAL error, exiting")
            sys.exit(1)

        if self.dummy_ip_prefix not in prefixes:
            self.log.warning("Dummy IP prefix {} wasn't found in bird "
                             "configuration, adding it. This shouldn't have "
                             "happened!".format(self.dummy_ip_prefix))
            prefixes.insert(0, self.dummy_ip_prefix)
            conf_updated = True

        # Update the list of IP prefixes.
        conf_updated = operation.update(prefixes)
        if not conf_updated:
            self.log.info("No updates for bird configuration")
            return conf_updated

        # some IP prefixes are either removed or added, truncate configuration
        # with new data.
        try:
            with open(self.bird_conf_file, 'r+') as bird_conf:
                bird_conf.seek(0)
                bird_conf.write("# Generated {time} by anycast-healthchecker"
                                "\n".format(time=time.ctime()))
                bird_conf.write("{}\n".format(comment))
                bird_conf.write("define {} =\n".format(self.bird_constant_name))
                bird_conf.write("{}[\n".format(4 * ' '))
                # all entries of the array constant need a trailing comma
                # except the last one. A single element array doesn't need the
                # trailing comma.
                bird_conf.write(',\n'.join(map(lambda p: ' '*8 + p, prefixes)))
                bird_conf.write("\n{spaces}];\n".format(spaces=4 * ' '))
                bird_conf.truncate()
                bird_conf.close()
                self.log.info("Bird configuration is updated")
        except OSError as error:
            self.log.critical("Failed to update bird configuration")
            self.log.critical(error)
            self.log.critical("This is a FATAL error, exiting")
            sys.exit(1)

        return conf_updated
Exemplo n.º 5
0
    def _update_bird_prefix_conf(self, health_action):
        """Updates BIRD configuration.

        Adds/removes entries from a list and updates generation time stamp.
        Main program will exit if configuration file cant be read/written.

        Arguments:
            health_action (tuple): A 3 element tuple:
            1st: The name of the thread (str)
            2nd: ip_prefix (str)
            3nd: Action to take, either 'add' or 'del' (str)

        Returns:
            True if BIRD configuration was updated otherwise False.

        """
        conf_updated = False
        prefixes = []
        name = health_action[0]
        ip_prefix = health_action[1]
        action = health_action[2]
        comment = ("# {} is a dummy IP Prefix. It should NOT be used and "
                   "REMOVED from the constant.".format(self.dummy_ip_prefix))

        try:
            prefixes = get_ip_prefixes_from_bird(self.bird_conf_file, die=False)
        except OSError as err:
            self.log.error("Failed to open bird configuration, {}".format(err))
            self.log.critical("This is a FATAL error, exiting")
            sys.exit(1)

        if not prefixes:
            self.log.error("Found empty bird configuration:{}".format(
                self.bird_conf_file))
            self.log.critical("This is a FATAL error, exiting")
            sys.exit(1)

        if self.dummy_ip_prefix not in prefixes:
            self.log.warning("Dummy IP prefix {} wasn't found in bird "
                             "configuration, adding it. This shouldn't have "
                             "happened!".format(self.dummy_ip_prefix))
            prefixes.insert(0, self.dummy_ip_prefix)
            conf_updated = True

        if action == 'del' and ip_prefix in prefixes:
            self.log.info("Withdrawing {} for {}".format(ip_prefix, name))
            prefixes.remove(ip_prefix)
            conf_updated = True
        elif action == 'add' and ip_prefix not in prefixes:
            self.log.info("Announcing {} for {}".format(ip_prefix, name))
            prefixes.append(ip_prefix)
            conf_updated = True

        if not conf_updated:
            self.log.info("No updates for bird configuration")
            return conf_updated

        # some IP prefixes are either removed or added, truncate configuration
        # with new data.
        try:
            with open(self.bird_conf_file, 'r+') as bird_conf:
                bird_conf.seek(0)
                bird_conf.write("# Generated {time} by anycast-healthchecker"
                                "\n".format(time=time.ctime()))
                bird_conf.write("{}\n".format(comment))
                bird_conf.write("define {} =\n".format(self.bird_constant_name))
                bird_conf.write("{}[\n".format(4 * ' '))
                # all entries of the array constant need a trailing comma
                # except the last one. A single element array doesn't need the
                # trailing comma.
                for prefix in prefixes[:-1]:
                    bird_conf.write("{}{},\n".format(8 * ' ', prefix))
                bird_conf.write("{}{}\n".format(8 * ' ',
                                                prefixes[len(prefixes) - 1]))
                bird_conf.write("{}];\n".format(4 * ' '))
                bird_conf.truncate()
                bird_conf.close()
                self.log.info("Bird configuration is updated")
        except OSError as error:
            self.log.critical("Failed to update bird configuration")
            self.log.critical(error)
            self.log.critical("This is a FATAL error, exiting")
            sys.exit(1)

        return conf_updated