charmhelpers.core.reactive.relations¶
AutoAccessors |
Metaclass that converts fields referenced by auto_accessors into accessor methods with very basic doc strings. |
Conversation |
Converations are the persistent, evolving, two-way communication between this service and one or more remote services. |
RelationBase |
The base class for all relation implementations. |
relation_call |
Invoke a method on the class implementing a relation via the CLI |
scopes |
These are the recommended scope values for relation implementations. |
-
class
charmhelpers.core.reactive.relations.
AutoAccessors
¶ Bases:
type
Metaclass that converts fields referenced by
auto_accessors
into accessor methods with very basic doc strings.
-
class
charmhelpers.core.reactive.relations.
Conversation
(relation_name=None, units=None, scope=None)¶ Bases:
object
Converations are the persistent, evolving, two-way communication between this service and one or more remote services.
Conversations are not limited to a single Juju hook context. They represent the entire set of interactions between the end-points from the time the relation is joined until it is departed.
Conversations evolve over time, moving from one semantic state to the next as the communication progresses.
Conversations may encompass multiple remote services or units. While a database client would connect to only a single database, that database will likely serve several other services. On the other hand, while the database is only concerned about providing a database to each service as a whole, a load-balancing proxy must consider each unit of each service individually.
Conversations use the idea of
scope
to determine how units and services are grouped together.-
depart
()¶ Remove the current remote unit, for the active hook context, from this conversation. This should be called from a -departed hook.
TODO: Need to figure out a way to have this called implicitly, to ensure cleaning up of conversations that are no longer needed.
-
classmethod
deserialize
(conversation)¶ Deserialize a
serialized
conversation.
-
get_local
(key, default=None)¶ Retrieve some data previously set via
set_local()
for this conversation.
-
get_remote
(key, default=None)¶ Get a value from the remote end(s) of this conversation.
Note that if a conversation’s scope encompasses multiple units, then those units are expected to agree on their data, whether that is through relying on a single leader to set the data or by all units eventually converging to identical data. Thus, this method returns the first value that it finds set by any of its units.
-
classmethod
join
(scope)¶ Get or create a conversation for the given scope and active hook context.
The current remote unit for the active hook context will be added to the conversation.
Note: This uses
charmhelpers.core.unitdata
and requires thatflush()
be called.
-
key
¶ The key under which this conversation will be stored.
-
classmethod
load
(keys)¶ Load a set of conversations by their keys.
-
relation_ids
¶ The set of IDs of the specific relation instances that this conversation is communicating with.
-
remove_state
(state)¶ Remove this conversation from the given state, and potentially deactivate the state if no more conversations are in it.
The relation name will be interpolated in the state name, and it is recommended that it be included to avoid conflicts with states from other relations. For example:
conversation.remove_state('{relation_name}.state')
If called from a converation handling the relation “foo”, this will remove the conversation from the “foo.state” state, and, if no more conversations are in this the state, will deactivate it.
-
classmethod
serialize
(conversation)¶ Serialize a conversation instance for storage.
-
set_local
(key=None, value=None, data=None, **kwdata)¶ Locally store some data associated with this conversation.
Data can be passed in either as a single dict, or as key-word args.
For example, if you need to store the previous value of a remote field to determine if it has changed, you can use the following:
prev = conversation.get_local('field') curr = conversation.get_remote('field') if prev != curr: handle_change(prev, curr) conversation.set_local('field', curr)
Note: This uses
charmhelpers.core.unitdata
and requires thatflush()
be called.Parameters: - key (str) – The name of a field to set.
- value – A value to set.
- data (dict) – A mapping of keys to values.
- **kwdata – A mapping of keys to values, as keyword arguments.
-
set_remote
(key=None, value=None, data=None, **kwdata)¶ Set data for the remote end(s) of this conversation.
Data can be passed in either as a single dict, or as key-word args.
Note that, in Juju, setting relation data is inherently service scoped. That is, if the conversation only includes a single unit, the data will still be set for that unit’s entire service.
However, if this conversation’s scope encompasses multiple services, the data will be set for all of those services.
Parameters: - key (str) – The name of a field to set.
- value – A value to set.
- data (dict) – A mapping of keys to values.
- **kwdata – A mapping of keys to values, as keyword arguments.
-
set_state
(state)¶ Activate and put this conversation into the given state.
The relation name will be interpolated in the state name, and it is recommended that it be included to avoid conflicts with states from other relations. For example:
conversation.set_state('{relation_name}.state')
If called from a converation handling the relation “foo”, this will activate the “foo.state” state, and will add this conversation to that state.
Note: This uses
charmhelpers.core.unitdata
and requires thatflush()
be called.
-
-
class
charmhelpers.core.reactive.relations.
RelationBase
(relation_name, conversations=None)¶ Bases:
object
The base class for all relation implementations.
-
auto_accessors
= []¶ Remote field names to be automatically converted into accessors with basic documentation.
These accessors will just call
get_remote()
using thedefault conversation
. Note that it is highly recommended that this be used only withscopes.GLOBAL
scope.
-
conversation
(scope=None)¶ Get a single conversation, by scope, that this relation is currently handling.
If the scope is not given, the correct scope is inferred by the current hook execution context. If there is no current hook execution context, it is assume that there is only a single global conversation scope for this relation. If this relation’s scope is not global and there is no current hook execution context, then an error is raised.
-
conversations
()¶ Return a list of the conversations that this relation is currently handling.
Note that “currently handling” means for the current state or hook context, and not all conversations that might be active for this relation for other states.
-
classmethod
from_name
(relation_name, conversations=None)¶ Find relation implementation in the current charm, based on the ID of the relation.
Returns: A Relation instance, or None
-
classmethod
from_state
(state)¶ Find relation implementation in the current charm, based on the name of an active state.
-
get_local
(key, default=None, scope=None)¶ Retrieve some data previously set via
set_local()
.In Python, this is equivalent to:
relation.conversation(scope).get_local(key, default)
See
conversation()
andConversation.get_local()
.
-
get_remote
(key, default=None, scope=None)¶ Get data from the remote end(s) of the
Conversation
with the given scope.In Python, this is equivalent to:
relation.conversation(scope).get_remote(key, default)
See
conversation()
andConversation.get_remote()
.
-
relation_name
¶ Name of the relation this instance is handling.
-
remove_state
(state, scope=None)¶ Remove the state for the
Conversation
with the given scope.In Python, this is equivalent to:
relation.conversation(scope).remove_state(state)
-
scope
= 'unit'¶ Conversation scope for this relation.
The conversation scope controls how communication with connected units is aggregated into related
Conversations
, and can be any of the predefinedscopes
, or any arbitrary string. Connected units which share the same scope will be considered part of the same conversation. Data sent to a conversation is sent to all units that are a part of that conversation, and units that are part of a conversation are expected to agree on the data that they send, whether via eventual consistency or by having a single leader set the data.The default scope is
scopes.UNIT
.
-
set_local
(key=None, value=None, data=None, scope=None, **kwdata)¶ Locally store some data, namespaced by the current or given
Conversation
scope.In Python, this is equivalent to:
relation.conversation(scope).set_local(data, scope, **kwdata)
See
conversation()
andConversation.set_local()
.
-
set_remote
(key=None, value=None, data=None, scope=None, **kwdata)¶ Set data for the remote end(s) of the
Conversation
with the given scope.In Python, this is equivalent to:
relation.conversation(scope).set_remote(data, scope, **kwdata)
See
conversation()
andConversation.set_remote()
.
-
set_state
(state, scope=None)¶ Set the state for the
Conversation
with the given scope.In Python, this is equivalent to:
relation.conversation(scope).set_state(state)
See
conversation()
andConversation.set_state()
.
-
-
charmhelpers.core.reactive.relations.
relation_call
(method, relation_name=None, state=None, *args)¶ Invoke a method on the class implementing a relation via the CLI
-
class
charmhelpers.core.reactive.relations.
scopes
¶ Bases:
object
These are the recommended scope values for relation implementations.
To use, simply set the
scope
class variable to one of these:class MyRelationClient(RelationBase): scope = scopes.SERVICE
-
GLOBAL
= 'global'¶ All connected services and units for this relation will share a single conversation. The same data will be broadcast to every remote unit, and retrieved data will be aggregated across all remote units and is expected to either eventually agree or be set by a single leader.
-
SERVICE
= 'service'¶ Each connected service for this relation will have its own conversation. The same data will be broadcast to every unit of each service’s conversation, and data from all units of each service will be aggregated and is expected to either eventually agree or be set by a single leader.
-
UNIT
= 'unit'¶ Each connected unit for this relation will have its own conversation. This is the default scope. Each unit’s data will be retrieved individually, but note that due to how Juju works, the same data is still broadcast to all units of a single service.
-