Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
Already on GitHub? Sign in to your account
Adds a peer-departed state #5
Merged
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
c58568c
Fixes etcd scale-down issue
chuckbutler d294cab
State rework per @johnsca
chuckbutler c32a0e5
Adds dismiss method
chuckbutler 8bc129a
Adding the peer relation data setter and map return.
mbruzek f76d479
Patched conversation behavior to reflect scope:unit when transmitting
chuckbutler 26b31bf
Removing cluster_unit_id details in relation-data
chuckbutler
Jump to file or symbol
Failed to load files and symbols.
| @@ -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 = [] | ||
|
|
||
| + # Iterate over all the conversations of this type. | ||
| + for conversation in self.conversations(): | ||
| + peers.append(conversation.scope) | ||
| + return peers | ||
There is a python one liner for these four lines. This way is fine, just flexing my python muscles.