ea2e3bf24f
Add OVS to OVN migration at the end of the regular gate test. This adds only 5-10 minutes to each job and we want to confirm this works from focal-ussuri and onwards as this is the point where we recomend our end users to migrate from OVS to OVN. Do ch-sync. Merge after https://github.com/juju/charm-helpers/pull/511 Change-Id: I506f499c8c506d999e79f223f03a58abc29b8746 Depends-On: Ifa99988612eaaeb9d60a0d99db172f97e27cfc93
170 lines
5.2 KiB
Python
Executable File
170 lines
5.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright 2020 Canonical Ltd
|
|
#
|
|
# 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.
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import traceback
|
|
|
|
sys.path.append('hooks/')
|
|
|
|
import charmhelpers.core as ch_core
|
|
import charmhelpers.contrib.openstack.utils as ch_openstack_utils
|
|
import charmhelpers.contrib.network.ovs as ch_ovs
|
|
import charmhelpers.contrib.network.ovs.ovsdb as ch_ovsdb
|
|
|
|
|
|
class BaseDocException(Exception):
|
|
"""Use docstring as default message for exception."""
|
|
|
|
def __init__(self, message=None):
|
|
self.message = message or self.__doc__
|
|
|
|
def __repr__(self):
|
|
return self.message
|
|
|
|
def __str__(self):
|
|
return self.message
|
|
|
|
|
|
class UnitNotPaused(BaseDocException):
|
|
"""Action requires unit to be paused but it was not paused."""
|
|
pass
|
|
|
|
|
|
class MandatoryConfigurationNotSet(BaseDocException):
|
|
"""Action requires certain configuration to be set to operate correctly."""
|
|
pass
|
|
|
|
|
|
def remove_patch_ports(bridge):
|
|
"""Remove patch ports from both ends starting with named bridge.
|
|
|
|
:param bridge: Name of bridge to look for patch ports to remove.
|
|
:type bridge: str
|
|
"""
|
|
# NOTE: We need to consume all output from the `patch_ports_on_bridge`
|
|
# generator prior to removing anything otherwise it will raise an error.
|
|
for patch in list(ch_ovs.patch_ports_on_bridge(bridge)):
|
|
ch_ovs.del_bridge_port(
|
|
patch.this_end.bridge,
|
|
patch.this_end.port,
|
|
linkdown=False)
|
|
ch_ovs.del_bridge_port(
|
|
patch.other_end.bridge,
|
|
patch.other_end.port,
|
|
linkdown=False)
|
|
|
|
|
|
def remove_per_bridge_controllers():
|
|
"""Remove per bridge controllers."""
|
|
bridges = ch_ovsdb.SimpleOVSDB('ovs-vsctl').bridge
|
|
for bridge in bridges:
|
|
if bridge['controller']:
|
|
bridges.clear(str(bridge['_uuid']), 'controller')
|
|
|
|
|
|
def neutron_ipset_cleanup():
|
|
"""Perform Neutron ipset cleanup."""
|
|
subprocess.check_call(
|
|
(
|
|
'neutron-ipset-cleanup',
|
|
'--config-file=/etc/neutron/neutron.conf',
|
|
'--config-file=/etc/neutron/plugins/ml2/openvswitch_agent.ini',
|
|
))
|
|
|
|
|
|
def neutron_netns_cleanup():
|
|
"""Perform Neutron netns cleanup."""
|
|
# FIXME: remove once package dependencies have been backported LP: #1881852
|
|
subprocess.check_call(('apt', '-y', 'install', 'net-tools'))
|
|
_tmp_filters = '/etc/neutron/rootwrap.d/charm-n-ovs.filters'
|
|
with open(_tmp_filters, 'w') as fp:
|
|
fp.write(
|
|
'[Filters]\nneutron.cmd.netns_cleanup: CommandFilter, ip, root\n')
|
|
subprocess.check_call(
|
|
(
|
|
'neutron-netns-cleanup',
|
|
'--force',
|
|
*[
|
|
# Existence of these files depend on our configuration.
|
|
'--config-file={}'.format(cfg) for cfg in (
|
|
'/etc/neutron/neutron.conf',
|
|
'/etc/neutron/l3_agent.ini',
|
|
'/etc/neutron/fwaas_driver.ini',
|
|
'/etc/neutron/dhcp_agent.ini',
|
|
) if os.path.exists(cfg)]
|
|
))
|
|
os.unlink(_tmp_filters)
|
|
|
|
|
|
def cleanup(args):
|
|
"""Clean up after Neutron agents."""
|
|
# Check that prerequisites for operation are met
|
|
if not ch_openstack_utils.is_unit_paused_set():
|
|
raise UnitNotPaused()
|
|
if not ch_core.hookenv.action_get('i-really-mean-it'):
|
|
raise MandatoryConfigurationNotSet(
|
|
'Action requires the `i-really-mean-it` parameter to be set to '
|
|
'"true".')
|
|
|
|
# The names used for the integration- and tunnel-bridge are
|
|
# configurable, but this configuration is not exposed in the charm.
|
|
#
|
|
# Assume default names are used.
|
|
remove_patch_ports('br-int')
|
|
ch_ovs.del_bridge('br-tun')
|
|
|
|
# The Neutron Open vSwitch agent configures each Open vSwitch bridge to
|
|
# establish an active OVSDB connection back to the Neutron Agent.
|
|
#
|
|
# Remove these
|
|
remove_per_bridge_controllers()
|
|
|
|
# Remove namespaces set up by Neutron
|
|
neutron_netns_cleanup()
|
|
|
|
# Remove ipsets set up by Neutron
|
|
neutron_ipset_cleanup()
|
|
|
|
|
|
# A dictionary of all the defined actions to callables (which take
|
|
# parsed arguments).
|
|
ACTIONS = {'cleanup': cleanup}
|
|
|
|
|
|
def main(args):
|
|
action_name = os.path.basename(args[0])
|
|
try:
|
|
action = ACTIONS[action_name]
|
|
except KeyError:
|
|
msg = 'Action "{}" undefined'.format(action_name)
|
|
ch_core.hookenv.action_fail(msg)
|
|
return msg
|
|
else:
|
|
try:
|
|
action(args)
|
|
except Exception as e:
|
|
msg = 'Action "{}" failed: "{}"'.format(action_name, str(e))
|
|
ch_core.hookenv.log(
|
|
'{} "{}"'.format(msg, traceback.format_exc()),
|
|
level=ch_core.hookenv.ERROR)
|
|
ch_core.hookenv.action_fail(msg)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main(sys.argv))
|