214 lines
7.0 KiB
Python
214 lines
7.0 KiB
Python
from charmhelpers.core import hookenv
|
|
from charms.reactive import RelationBase
|
|
from charms.reactive import hook
|
|
from charms.reactive import scopes
|
|
|
|
|
|
class MySQLSharedRequires(RelationBase):
|
|
scope = scopes.GLOBAL
|
|
|
|
# These remote data fields will be automatically mapped to accessors
|
|
# with a basic documentation string provided.
|
|
auto_accessors = ['access-network', 'db_host', 'db_port',
|
|
'ssl_ca', 'ssl_cert', 'ssl_key',
|
|
'cluster-series-upgrading', 'wait_timeout']
|
|
|
|
@hook('{requires:mysql-shared}-relation-joined')
|
|
def joined(self):
|
|
self.set_state('{relation_name}.connected')
|
|
|
|
@hook('{requires:mysql-shared}-relation-changed')
|
|
def changed(self):
|
|
if self.cluster_series_upgrading() == 'True':
|
|
self.remove_state('{relation_name}.available')
|
|
self.remove_state('{relation_name}.available.access_network')
|
|
self.remove_state('{relation_name}.available.ssl')
|
|
else:
|
|
if self.base_data_complete() and self.unit_allowed_all_dbs():
|
|
self.set_state('{relation_name}.available')
|
|
if self.access_network_data_complete():
|
|
self.set_state('{relation_name}.available.access_network')
|
|
if self.ssl_data_complete():
|
|
self.set_state('{relation_name}.available.ssl')
|
|
|
|
@hook('{requires:mysql-shared}-relation-{broken,departed}')
|
|
def departed(self):
|
|
# Clear state
|
|
self.remove_state('{relation_name}.connected')
|
|
self.remove_state('{relation_name}.available')
|
|
self.remove_state('{relation_name}.available.access_network')
|
|
self.remove_state('{relation_name}.available.ssl')
|
|
# Check if this is the last unit
|
|
for conversation in self.conversations():
|
|
for rel_id in conversation.relation_ids:
|
|
if len(hookenv.related_units(rel_id)) > 0:
|
|
# This is not the last unit so reevaluate state
|
|
self.joined()
|
|
self.changed()
|
|
|
|
def configure(self, database, username, hostname=None, prefix=None):
|
|
"""
|
|
Called by charm layer that uses this interface to configure a database.
|
|
"""
|
|
if not hostname:
|
|
conversation = self.conversation()
|
|
try:
|
|
hostname = hookenv.network_get_primary_address(
|
|
conversation.relation_name
|
|
)
|
|
except NotImplementedError:
|
|
hostname = hookenv.unit_private_ip()
|
|
|
|
if prefix:
|
|
relation_info = {
|
|
prefix + '_database': database,
|
|
prefix + '_username': username,
|
|
prefix + '_hostname': hostname,
|
|
}
|
|
self.set_prefix(prefix)
|
|
else:
|
|
relation_info = {
|
|
'database': database,
|
|
'username': username,
|
|
'hostname': hostname,
|
|
}
|
|
self.set_remote(**relation_info)
|
|
self.set_local(**relation_info)
|
|
|
|
def set_prefix(self, prefix):
|
|
"""
|
|
Store all of the database prefixes in a list.
|
|
"""
|
|
prefixes = self.get_local('prefixes')
|
|
if prefixes:
|
|
if prefix not in prefixes:
|
|
self.set_local('prefixes', prefixes + [prefix])
|
|
else:
|
|
self.set_local('prefixes', [prefix])
|
|
|
|
def get_prefixes(self):
|
|
"""
|
|
Return the list of saved prefixes.
|
|
"""
|
|
return self.get_local('prefixes')
|
|
|
|
def database(self, prefix=None):
|
|
"""
|
|
Return a configured database name.
|
|
"""
|
|
if prefix:
|
|
return self.get_local(prefix + '_database')
|
|
return self.get_local('database')
|
|
|
|
def username(self, prefix=None):
|
|
"""
|
|
Return a configured username.
|
|
"""
|
|
if prefix:
|
|
return self.get_local(prefix + '_username')
|
|
return self.get_local('username')
|
|
|
|
def hostname(self, prefix=None):
|
|
"""
|
|
Return a configured hostname.
|
|
"""
|
|
if prefix:
|
|
return self.get_local(prefix + '_hostname')
|
|
return self.get_local('hostname')
|
|
|
|
def password(self, prefix=None):
|
|
"""
|
|
Return a database password.
|
|
"""
|
|
if prefix:
|
|
return self.get_remote(prefix + '_password')
|
|
return self.get_remote('password')
|
|
|
|
def allowed_units(self, prefix=None):
|
|
"""
|
|
Return a database's allowed_units.
|
|
"""
|
|
if prefix:
|
|
return self.get_remote(prefix + '_allowed_units')
|
|
return self.get_remote('allowed_units')
|
|
|
|
def base_data_complete(self):
|
|
"""
|
|
Check if required base data is complete.
|
|
"""
|
|
data = {
|
|
'db_host': self.db_host(),
|
|
}
|
|
if self.get_prefixes():
|
|
suffixes = ['_password', '_allowed_units']
|
|
for prefix in self.get_prefixes():
|
|
for suffix in suffixes:
|
|
key = prefix + suffix
|
|
data[key] = self.get_remote(key)
|
|
else:
|
|
data['password'] = self.get_remote('password')
|
|
data['allowed_units'] = self.get_remote('allowed_units')
|
|
if all(data.values()):
|
|
return True
|
|
return False
|
|
|
|
def unit_allowed_db(self, prefix=None):
|
|
""""
|
|
Check unit can access requested database.
|
|
|
|
:param prefix: Prefix used to distinguish multiple db requests.
|
|
:type prefix: str
|
|
:returns: Whether db acl has been setup.
|
|
:rtype: bool
|
|
"""
|
|
allowed = False
|
|
allowed_units = self.allowed_units(prefix=prefix) or ''
|
|
hookenv.log("Checking {} is in {}".format(
|
|
hookenv.local_unit(),
|
|
allowed_units.split()))
|
|
if allowed_units and hookenv.local_unit() in allowed_units.split():
|
|
allowed = True
|
|
hookenv.log("Unit allowed: {}".format(allowed))
|
|
return allowed
|
|
|
|
def unit_allowed_all_dbs(self):
|
|
""""
|
|
Check unit can access all requested databases.
|
|
|
|
:returns: Whether db acl has been setup for all dbs.
|
|
:rtype: bool
|
|
"""
|
|
if self.get_prefixes():
|
|
_allowed = [self.unit_allowed_db(prefix=p)
|
|
for p in self.get_prefixes()]
|
|
else:
|
|
_allowed = [self.unit_allowed_db()]
|
|
hookenv.log("Allowed: {}".format(_allowed))
|
|
if all(_allowed):
|
|
hookenv.log("Returning unit_allowed_all_dbs True")
|
|
return True
|
|
hookenv.log("Returning unit_allowed_all_dbs False")
|
|
return False
|
|
|
|
def access_network_data_complete(self):
|
|
"""
|
|
Check if optional access network data provided by mysql is complete.
|
|
"""
|
|
data = {
|
|
'access-network': self.access_network(),
|
|
}
|
|
if all(data.values()):
|
|
return True
|
|
return False
|
|
|
|
def ssl_data_complete(self):
|
|
"""
|
|
Check if optional ssl data provided by mysql is complete.
|
|
"""
|
|
data = {
|
|
'ssl_ca': self.ssl_ca(),
|
|
}
|
|
if all(data.values()):
|
|
return True
|
|
return False
|