# Copyright (c) 2015 OpenStack Foundation. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from oslo_config import cfg from oslo_log import log as logging from neutron._i18n import _LE, _LI from neutron.agent.linux import ipset_manager from neutron.agent.linux import utils from neutron.common import config LOG = logging.getLogger(__name__) def setup_conf(): """Setup the cfg for the clean up utility. Use separate setup_conf for the utility because there are many options from the main config that do not apply during clean-up. """ cli_opts = [ cfg.BoolOpt('allsets', default=False, help=_('Destroy all IPsets.')), cfg.BoolOpt('force', default=False, help=_('Destroy IPsets even if there is an iptables ' 'reference.')), cfg.StrOpt('prefix', default=ipset_manager.NET_PREFIX, help=_('String prefix used to match IPset names.')), ] conf = cfg.CONF conf.register_cli_opts(cli_opts) return conf def remove_iptables_reference(ipset): # Remove any iptables reference to this IPset cmd = ['iptables-save'] if 'IPv4' in ipset else ['ip6tables-save'] iptables_save = utils.execute(cmd, run_as_root=True) if ipset in iptables_save: cmd = ['iptables'] if 'IPv4' in ipset else ['ip6tables'] LOG.info(_LI("Removing iptables rule for IPset: %s"), ipset) for rule in iptables_save.splitlines(): if '--match-set %s ' % ipset in rule and rule.startswith('-A'): # change to delete params = rule.split() params[0] = '-D' try: utils.execute(cmd + params, run_as_root=True) except Exception: LOG.exception(_LE('Error, unable to remove iptables rule ' 'for IPset: %s'), ipset) def destroy_ipset(conf, ipset): # If there is an iptables reference and we don't remove it, the # IPset removal will fail below if conf.force: remove_iptables_reference(ipset) LOG.info(_LI("Destroying IPset: %s"), ipset) cmd = ['ipset', 'destroy', ipset] try: utils.execute(cmd, run_as_root=True) except Exception: LOG.exception(_LE('Error, unable to destroy IPset: %s'), ipset) def cleanup_ipsets(conf): # Identify ipsets for destruction. LOG.info(_LI("Destroying IPsets with prefix: %s"), conf.prefix) cmd = ['ipset', '-L', '-n'] ipsets = utils.execute(cmd, run_as_root=True) for ipset in ipsets.split('\n'): if conf.allsets or ipset.startswith(conf.prefix): destroy_ipset(conf, ipset) LOG.info(_LI("IPset cleanup completed successfully")) def main(): """Main method for cleaning up IPsets. The utility is designed to clean-up after the forced or unexpected termination of Neutron agents. The --allsets flag should only be used as part of the cleanup of a devstack installation as it will blindly destroy all IPsets. """ conf = setup_conf() conf() config.setup_logging() cleanup_ipsets(conf)