Adds a peer-departed state #5

Merged
merged 6 commits into from Jun 7, 2016
View
@@ -1,69 +1,42 @@
from charms.reactive import RelationBase
from charms.reactive import hook
from charms.reactive import scopes
-from charms.reactive import not_unless
class EtcdPeer(RelationBase):
- ''' ETCD Peering works in tandem with the leader node to establish a cluster
- as sanely as possible. This works statically behind a firewall without
- any need for an external service to function as the discovery mechanism
+ '''This class handles peer relation communication by setting states that
+ the reactive code can respond to. '''
- Every peer participating in the cluster declares themselves to the
- cluster. The leader then ingests the data and leader-set's the cluster
- state (string, status, token) for the peers to ingest and participate.
- '''
scope = scopes.UNIT
- # kevin - auto_accessors are cool.
- auto_accessors = ['public_address', 'unit_name', 'port']
-
@hook('{peers:etcd}-relation-joined')
- def peers_joined(self):
- # As i understand this, this only operates on the conversation in
- # current scope.
+ def peer_joined(self):
+ '''A new peer has joined, set the state on the unit so we can track
+ when they are departed. '''
conv = self.conversation()
- conv.set_state('{relation_name}.declare_self')
+ conv.set_state('{relation_name}.joined')
- @hook('{peers:etcd}-relation-changed')
- def peers_changed(self):
- # As i understand this, this only operates on the conversation in
- # current scope.
+ @hook('{peers:etcd}-relation-departed')
+ def peers_going_away(self):
+ '''Trigger a state on the unit that it is leaving. We can use this
+ state in conjunction with the joined state to determine which unit to
+ unregister from the etcd cluster. '''
conv = self.conversation()
- # if we get a unit_name, we'll assume we have all the data....
- if conv.get_remote('unit_name'):
- conv.set_state('{relation_name}.joining')
-
- def private_address(self):
- return self.get_remote('private-address')
+ conv.remove_state('{relation_name}.joined')
+ conv.set_state('{relation_name}.departing')
- def list_peers(self):
- """
- Return a list of units requesting peering.
- Example usage::
- for unit in etcd.list_peers():
- public_address = unit_get('public-address')
- etcd.provide_cluster_details(**create_peerstring(etcd))
- """
- for conversation in self.conversations():
- unit = conversation.scope
- # yield the current conversation object for the connecting peer
- yield unit
-
- @not_unless('{relation_name}.joining')
- def provide_cluster_details(self, scope, public_address, port, unit_name):
+ def dismiss(self):
+ '''Remove the departing state from all other units in the conversation,
+ and we can resume normal operation.
'''
- Declare yourself to the cluster as a participating member.
- of etcd. This is used on the leader to calculate the cluster string and
- state of the cluster.
+ for conv in self.conversations():
+ conv.remove_state('{relation_name}.departing')
- @param: scope - conversation scope yielded from list_peers
- @param: public_address - units public-address
- @param: port - public port in connection string
- @param: unit_name - charm name/unit# with the / stripped. eg: etcd1
+ def get_peers(self):
+ '''Return a list of peer names participating in the conversation scope
'''
- conversation = self.conversation(scope=scope)
- conversation.set_remote(port=port, unit_name=unit_name,
- public_address=public_address)
- conversation.remove_state('{relation_name}.joining')
- conversation.remove_state('{relation_name}.declare_self')
+ peers = []
@mbruzek

mbruzek Jun 7, 2016

Contributor

There is a python one liner for these four lines. This way is fine, just flexing my python muscles.

+ # Iterate over all the conversations of this type.
+ for conversation in self.conversations():
+ peers.append(conversation.scope)
+ return peers