574a0c2837
A charm may request principal to perform a DB migration. The charm may also optionally flag that interface availability should be gated on the completion of the requested DB migration. Change-Id: Id9ed69880f06b835ff2385721d4cb22e47f37c5d Depends-On: Iaefcb81fff5ed8a9441c93ac4c8bac3fa12eef15
172 lines
7.3 KiB
Python
172 lines
7.3 KiB
Python
import uuid
|
|
import json
|
|
|
|
import charms.reactive as reactive
|
|
|
|
from charms.reactive import hook
|
|
from charms.reactive import RelationBase
|
|
from charms.reactive import scopes
|
|
|
|
|
|
class NeutronPluginAPISubordinate(RelationBase):
|
|
scope = scopes.GLOBAL
|
|
|
|
@hook(
|
|
'{provides:neutron-plugin-api-subordinate}-relation-{joined,changed}')
|
|
def changed(self):
|
|
"""Set connected state and assess available state"""
|
|
self.set_state('{relation_name}.connected')
|
|
if self.neutron_api_ready() and not self.db_migration_pending():
|
|
self.set_state('{relation_name}.available')
|
|
|
|
@hook(
|
|
'{provides:neutron-plugin-api-subordinate}-relation-{broken,departed}')
|
|
def broken(self):
|
|
"""Remove connected state"""
|
|
self.remove_state('{relation_name}.available')
|
|
self.remove_state('{relation_name}.connected')
|
|
|
|
@property
|
|
def neutron_config_data(self):
|
|
"""Retrive and decode ``neutron_config_data`` from relation"""
|
|
return json.loads(self.get_remote('neutron_config_data', "{}"))
|
|
|
|
def neutron_api_ready(self):
|
|
"""Assess remote readiness"""
|
|
if self.get_remote('neutron-api-ready') == 'yes':
|
|
return True
|
|
return False
|
|
|
|
def configure_plugin(self, neutron_plugin, core_plugin=None,
|
|
neutron_plugin_config=None, service_plugins=None,
|
|
subordinate_configuration=None,
|
|
extension_drivers=None, mechanism_drivers=None,
|
|
tenant_network_types=None,
|
|
neutron_security_groups=None):
|
|
"""Send principle plugin information
|
|
|
|
:param neutron_plugin: Neutron plugin name
|
|
:type neutron_plugin: str
|
|
:param core_plugin: Entry point eg neutron.plugins.ml2.plugin.Ml2Plugin
|
|
:type core_plugin: str
|
|
:param neutron-plugin-config: /etc/neutron/plugins/ml2/ml2_conf.ini
|
|
:type neutron-plugin-config: str
|
|
:param service-plugins: Comma delimited list of service plugins eg
|
|
router,firewall,lbaas,vpnaas,metering
|
|
:type service-plugins: str
|
|
:param subordinate_configuration: Configuration for the principle
|
|
to inject into a configuration
|
|
file it is managing eg:
|
|
# Add sections and tuples to insert values into neutron-server's
|
|
# neutron.conf e.g.
|
|
# {
|
|
# "neutron-api": {
|
|
# "/etc/neutron/neutron.conf": {
|
|
# "sections": {
|
|
# 'DEFAULT': [
|
|
# ('key1', 'val1')
|
|
# ('key2', 'val2')
|
|
# ],
|
|
# 'agent': [
|
|
# ('key3', 'val3')
|
|
# ],
|
|
# }
|
|
# }
|
|
# }
|
|
# }
|
|
:type subordinate_configuration:
|
|
Dict[str, Dict[
|
|
str Dict[
|
|
str, List[
|
|
Union[str, str]]]]]
|
|
:param extension_drivers: Extension drivers eg dns,port_security
|
|
:type extension_drivers: str
|
|
:param mechanism_drivers: Mechanism drivers eg openvswitch,hyperv
|
|
:type mechanism_drivers: str
|
|
:param tenant_network_types: Tenant network types eg local,gre
|
|
Note that this also configures
|
|
``type_drivers``
|
|
:type tenant_network_types: str
|
|
:param neutron_security_groups: 'true' to enable security groups
|
|
:type neutron_security_groups: str
|
|
"""
|
|
if subordinate_configuration is None:
|
|
subordinate_configuration = {}
|
|
relation_info = {
|
|
'neutron-plugin': neutron_plugin,
|
|
'core-plugin': core_plugin,
|
|
'neutron-plugin-config': neutron_plugin_config,
|
|
'service-plugins': service_plugins,
|
|
'extension-drivers': extension_drivers,
|
|
'mechanism-drivers': mechanism_drivers,
|
|
'tenant-network-types': tenant_network_types,
|
|
'neutron-security-groups': neutron_security_groups,
|
|
'subordinate_configuration': json.dumps(subordinate_configuration),
|
|
}
|
|
self.set_remote(**relation_info)
|
|
|
|
def request_restart(self, service_type=None):
|
|
"""Request a restart of a set of remote services
|
|
|
|
:param service_type: string Service types to be restarted eg 'neutron'.
|
|
If ommitted a request to restart all
|
|
services is sent
|
|
"""
|
|
if service_type:
|
|
key = 'restart-trigger-{}'.format(service_type)
|
|
else:
|
|
key = 'restart-trigger'
|
|
relation_info = {
|
|
key: str(uuid.uuid4()),
|
|
}
|
|
self.set_remote(**relation_info)
|
|
|
|
def request_db_migration(self):
|
|
"""Request principal to perform a DB migration"""
|
|
if not self.neutron_api_ready():
|
|
# Ignore the charm request until we are in a relation-changed hook
|
|
# where the prinicpal charm has declared itself ready.
|
|
return
|
|
nonce = str(uuid.uuid4())
|
|
relation_info = {
|
|
'migrate-database-nonce': nonce,
|
|
}
|
|
self.set_remote(**relation_info)
|
|
# NOTE: we use flags instead of RelationBase state here both because of
|
|
# easier interaction with charm code, and because of how states
|
|
# interact with RelationBase conversations leading to crashes
|
|
# when used prior to relation being fully established.
|
|
reactive.set_flag('{relation_name}.db_migration'
|
|
.format(relation_name=self.relation_name))
|
|
reactive.set_flag('{relation_name}.db_migration.'
|
|
.format(relation_name=self.relation_name)+nonce)
|
|
reactive.clear_flag('{relation_name}.available'
|
|
.format(relation_name=self.relation_name))
|
|
|
|
def db_migration_pending(self):
|
|
"""Assess presence and state of optional DB migration request"""
|
|
# NOTE: we use flags instead of RelationBase state here both because of
|
|
# easier interaction with charm code, and because of how states
|
|
# interact with RelationBase conversations leading to crashes
|
|
# when used prior to relation being fully established.
|
|
flag_prefix = ('{relation_name}.db_migration'
|
|
.format(relation_name=self.relation_name))
|
|
if not reactive.is_flag_set(flag_prefix):
|
|
return False
|
|
flag_nonce = '.'.join(
|
|
(flag_prefix,
|
|
self.get_remote('migrate-database-nonce', '')))
|
|
if reactive.is_flag_set(flag_nonce):
|
|
# hooks fire in a nondeterministic order, and there will be
|
|
# occations where a different hook run between the
|
|
# ``migrate-database-nonce`` being set and it being returned to us
|
|
# a subsequent relation-changed hook.
|
|
#
|
|
# to avoid buildup of unreaped db_migration nonce flags we remove
|
|
# all of them each time we have a match for one.
|
|
for flag in reactive.get_flags():
|
|
if flag.startswith(flag_prefix):
|
|
reactive.clear_flag(flag)
|
|
return False
|
|
return True
|