Change interface to simplify transfer of configuration information
The interface between the manila charm and manila configuration charms has been simplified so that backend charms can render their configuration section using, say, jinja2. Change-Id: I76866007e3c89bb16bc7985a692fbd8f3e136a71
This commit is contained in:
parent
a4f85602af
commit
4c8d468393
45
provides.py
45
provides.py
|
@ -36,9 +36,15 @@ class ManilaPluginProvides(reactive.RelationBase):
|
|||
# with a basic documentation string provided.
|
||||
auto_accessors = ['_authentication_data']
|
||||
|
||||
class states(reactive.bus.StateList):
|
||||
connected = reactive.bus.State('{relation_name}.connected')
|
||||
available = reactive.bus.State('{relation_name}.available')
|
||||
changed = reactive.bus.State('{relation_name}.changed')
|
||||
|
||||
@reactive.hook('{provides:manila-plugin}-relation-joined')
|
||||
def joined(self):
|
||||
self.set_state('{relation_name}.connected')
|
||||
conversation = self.conversation()
|
||||
conversation.set_state(self.states.connected)
|
||||
self.update_status()
|
||||
|
||||
@reactive.hook('{provides:manila-plugin}-relation-changed')
|
||||
|
@ -54,9 +60,10 @@ class ManilaPluginProvides(reactive.RelationBase):
|
|||
|
||||
@reactive.hook('{provides:manila-plugin}-relation-{broken,departed}')
|
||||
def departed(self):
|
||||
self.remove_state('{relation_name}.changed')
|
||||
self.remove_state('{relation_name}.available')
|
||||
self.remove_state('{relation_name}.connected')
|
||||
conversation = self.conversation()
|
||||
conversation.remove_state(self.states.connected)
|
||||
conversation.remove_state(self.states.available)
|
||||
conversation.remove_state(self.states.changed)
|
||||
|
||||
def update_status(self):
|
||||
"""Set the .available and .changed state if both the plugin name and
|
||||
|
@ -68,15 +75,26 @@ class ManilaPluginProvides(reactive.RelationBase):
|
|||
configuration files as needed.
|
||||
|
||||
The interface will NOT set .changed without having .available at the
|
||||
same time.
|
||||
same time. Also, the interface will not set .changed unless the
|
||||
authentication data has changed.
|
||||
"""
|
||||
if self._authentication_data() is not None:
|
||||
self.set_state('{relation_name}.available')
|
||||
self.set_state('{relation_name}.changed')
|
||||
auth_data = self._authentication_data()
|
||||
conversation = self.conversation()
|
||||
if auth_data is not None:
|
||||
conversation.set_state(self.states.available)
|
||||
scope = conversation.scope
|
||||
local_auth_data = self.get_local('_authentication_data',
|
||||
default=None,
|
||||
scope=scope)
|
||||
if (local_auth_data is None or local_auth_data != auth_data):
|
||||
conversation.set_state(self.states.changed)
|
||||
conversation.set_local(_authentication_data=auth_data,
|
||||
scope=scope)
|
||||
|
||||
def clear_changed(self):
|
||||
"""Provide a convenient method to clear the .changed relation"""
|
||||
self.remove_state('{relation_name}.changed')
|
||||
conversation = self.conversation()
|
||||
conversation.remove_state(self.states.changed)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -148,13 +166,12 @@ class ManilaPluginProvides(reactive.RelationBase):
|
|||
The format of the data is:
|
||||
{
|
||||
"complete": <boolean>,
|
||||
'<config file>': {
|
||||
'<section>: (
|
||||
(key, value),
|
||||
(key, value),
|
||||
)
|
||||
'<config file>': ""
|
||||
}
|
||||
|
||||
Note that the string for the <config file> should be suitable for
|
||||
replacing/adding into the configuration file specified.
|
||||
|
||||
Thus data has to be JSONable.
|
||||
|
||||
:param data: object that describes the plugin data to be sent.
|
||||
|
|
99
requires.py
99
requires.py
|
@ -21,19 +21,14 @@ import charms.reactive as reactive
|
|||
class ManilaPluginRequires(reactive.RelationBase):
|
||||
"""The is the Manila 'end' of the relation.
|
||||
|
||||
The auto accessors are underscored as for some reason RelationBase only
|
||||
provides these as 'calls'; i.e. they have to be used as `self._name()`.
|
||||
This class therefore provides @properties `name` and `plugin_data` that can
|
||||
be used directly.
|
||||
The auto accessors are underscored as RelationBase only provides these as
|
||||
'calls'; i.e. they have to be used as `self._name()`. This class therefore
|
||||
provides @properties `name` and `plugin_data` that can be used directly.
|
||||
|
||||
This side of the interface sends the manila service user authentication
|
||||
information to the plugin charm (which is a subordinate) and gets
|
||||
configuration segments for the various files that the manila charm 'owns'
|
||||
and, therefore, writes out.
|
||||
|
||||
The most important property is the 'ready' property which indicates that
|
||||
the configuration data on the interface is valid and thus can be written to
|
||||
the configuration files by the manila charm.
|
||||
"""
|
||||
scope = reactive.scopes.UNIT
|
||||
|
||||
|
@ -41,6 +36,11 @@ class ManilaPluginRequires(reactive.RelationBase):
|
|||
# with a basic documentation string provided.
|
||||
auto_accessors = ['_name', '_configuration_data']
|
||||
|
||||
class states(reactive.bus.StateList):
|
||||
connected = reactive.bus.State('{relation_name}.connected')
|
||||
available = reactive.bus.State('{relation_name}.available')
|
||||
changed = reactive.bus.State('{relation_name}.changed')
|
||||
|
||||
@reactive.hook('{requires:manila-plugin}-relation-joined')
|
||||
def joined(self):
|
||||
"""At least one manila-plugin has joined. Thus we set the connected
|
||||
|
@ -48,7 +48,8 @@ class ManilaPluginRequires(reactive.RelationBase):
|
|||
|
||||
We also update the status, as this may or may not be another plugin.
|
||||
"""
|
||||
self.set_state('{relation_name}.connected')
|
||||
conversation = self.conversation()
|
||||
conversation.set_state(self.states.connected)
|
||||
self.update_status()
|
||||
|
||||
@reactive.hook('{requires:manila-plugin}-relation-changed')
|
||||
|
@ -89,7 +90,7 @@ class ManilaPluginRequires(reactive.RelationBase):
|
|||
count_conversations += 1
|
||||
# try to see if we've already had this conversation
|
||||
conversation_available = self.get_local(
|
||||
'_available', default=None, scope=conversation.scope)
|
||||
'_available', default=False, scope=conversation.scope)
|
||||
name = self.get_remote(
|
||||
'_name', default=None, scope=conversation.scope)
|
||||
configuration_data = self.get_remote(
|
||||
|
@ -108,18 +109,19 @@ class ManilaPluginRequires(reactive.RelationBase):
|
|||
|
||||
# now update the relation states to convey what is happening.
|
||||
if count_changed:
|
||||
self.set_state('{relation_name}.changed')
|
||||
self.set_state(self.states.changed)
|
||||
if count_available:
|
||||
self.set_state('{relation_name}.available')
|
||||
self.set_state(self.states.available)
|
||||
else:
|
||||
self.remove_state('{relation_name}.available')
|
||||
self.remove_state(self.states.available)
|
||||
if not count_conversations:
|
||||
self.remove_state('{relation_name}.connected')
|
||||
self.remove_state('{relation_name}.changed')
|
||||
self.remove_state(self.states.connected)
|
||||
self.remove_state(self.states.changed)
|
||||
|
||||
def clear_changed(self):
|
||||
"""Provide a convenient method to clear the .changed relation"""
|
||||
self.remove_state('{relation_name}.changed')
|
||||
conversation = self.conversation()
|
||||
conversation.remove_state(self.states.changed)
|
||||
|
||||
def set_authentication_data(self, value, name=None):
|
||||
"""Set the authentication data to the plugin charm. This is to enable
|
||||
|
@ -201,35 +203,60 @@ class ManilaPluginRequires(reactive.RelationBase):
|
|||
def get_configuration_data(self, name=None):
|
||||
"""Return the configuration_data from the plugin if it is available.
|
||||
|
||||
The format of the data returned is:
|
||||
{
|
||||
'<config file>': {
|
||||
'<section>: (
|
||||
(key, value),
|
||||
(key, value),
|
||||
"or string",
|
||||
)
|
||||
}
|
||||
|
||||
if 'name' is provided, then only the configuration data for that name
|
||||
If 'name' is provided, then only the configuration data for that name
|
||||
is returned, otherwise all of the configuration data for all
|
||||
conversations is returned as an amalgamated dict.
|
||||
|
||||
Note, that multiple backends are supported through this one interface.
|
||||
so this function needs to potentially return all of the results for all
|
||||
of the backends, which also may be wanting to write configuration to
|
||||
the same configuration file.
|
||||
|
||||
This is for the files that the manila charm owns. If a configuration
|
||||
charm has its own files, not managed by the manila charm, then it
|
||||
doesn't (and shouldn't) send them over this interface -- it should just
|
||||
write them locally.
|
||||
|
||||
Each backend sends it's data in the following format:
|
||||
|
||||
{
|
||||
"<config file path>": <string>,
|
||||
"<config file path 2>": <string>
|
||||
}
|
||||
|
||||
This function amalgamates the data from multiple backends by using the
|
||||
name of the backend as the key to a dictionary:
|
||||
|
||||
{
|
||||
"<name1>": {
|
||||
"<config file path>": <string>,
|
||||
"<config file path 2>": <string>
|
||||
},
|
||||
"<name2>": {
|
||||
"<config file path>": <string>,
|
||||
},
|
||||
}
|
||||
|
||||
NOTE: this function will only return results if the subordinate sets
|
||||
the _name parameter. Otherwise, it will not return anything.
|
||||
|
||||
:param name: OPTIONAL: specify the name of the interface (_name)
|
||||
:returns: data object that was passed.
|
||||
:returns: data object described above
|
||||
"""
|
||||
result = {}
|
||||
for conversation in self.conversations():
|
||||
if conversation.scope is None:
|
||||
# the conversation has gone away; ignore it
|
||||
continue
|
||||
if name:
|
||||
_name = self.get_remote('_name', default=None,
|
||||
scope=conversation.scope)
|
||||
if _name != name:
|
||||
continue
|
||||
config = self.get_remote('_configuration_data', default=None,
|
||||
_name = self.get_remote('_name', default=None,
|
||||
scope=conversation.scope)
|
||||
# if name is not None then check to see if this is the one that is
|
||||
# wanted.
|
||||
if name and _name != name:
|
||||
continue
|
||||
config = self.get_remote('_configuration_data',
|
||||
default=None,
|
||||
scope=conversation.scope)
|
||||
if config:
|
||||
result.update(json.loads(config)["data"])
|
||||
if _name and config:
|
||||
result[_name] = json.loads(config)["data"]
|
||||
return result
|
||||
|
|
Loading…
Reference in New Issue