Add several tokens to control events between resources

This commit is contained in:
Dmitry Shulyak 2015-07-30 18:04:36 +03:00
parent cfa6c7be72
commit 6451f62628
5 changed files with 103 additions and 22 deletions

View File

@ -24,11 +24,11 @@ Propagating events when there is no data changed
Control for specifying events: Control for specifying events:
on <emitter>.<emmiter_action> <event> <subscriber>.<subsciber_action> on <emitter>.<emmiter_action> <event> <subscriber>.<subsciber_action>
# on mariadb.run changed keystone.run on mariadb.run changed keystone.run
# on keystone.run changed keystone_config.run on keystone.run changed keystone_config.run
# on keystone_config.run changed haproxy.reload on keystone_config.run changed haproxy.reload
+---------------------+ +---------------------+
| mariadb.run | | mariadb.run |
@ -46,13 +46,13 @@ Control for specifying events:
| haproxy.reload | | haproxy.reload |
+---------------------+ +---------------------+
<u> - <event>:<action> - <v> <u>.<action> - <event> - <v>.<action>
When connection between several resources created - events connections should When data connection between several resources created - events connections should
be created as well, resource a connect resource b: be created as well, resource a connect resource b:
on a changed b reload on a.run changed b.reload
on a removed b run on a.remove changed b.run
------------------------------------------------- -------------------------------------------------
Resolving cycles on a data plane Resolving cycles on a data plane
@ -73,9 +73,9 @@ rmq.2.cluster_join, rmq.2.cluster_join
Also cluster operation should happen only when rmq.cluster is changed. Also cluster operation should happen only when rmq.cluster is changed.
on rmq.cluster changed rmq.1 cluster_create on rmq.cluster changed rmq.1.cluster_create
on rmq.1.cluster_create changed rmq.2 cluster_join on rmq.1.cluster_create changed rmq.2.cluster_join
on rmq.1.cluster_create changed rmq.3 cluster_join on rmq.1.cluster_create changed rmq.3.cluster_join
+----------------------+ +----------------------+
| rmq.1.run | | rmq.1.run |
@ -102,7 +102,7 @@ on rmq.1.cluster_create changed rmq.3 cluster_join
| rmq.3.run | | | rmq.3.run | |
+----------------------+ | +----------------------+ |
| | | |
| cahnged | | changed |
v | v |
+----------------------+ | +----------------------+ |
| rmq.3.cluster_join | <+ | rmq.3.cluster_join | <+
@ -113,7 +113,7 @@ on rmq.1.cluster_create changed rmq.3 cluster_join
--------------------------------------------------- ---------------------------------------------------
Resolve cycles on a execution level Resolve cycles on a execution level
Lets say we have 5 objects, which forms 2 pathes We have 5 objects, which forms 2 pathes
- keystone-config -> keystone-service -> haproxy-sevice - keystone-config -> keystone-service -> haproxy-sevice
- glance-config -> glance-service -> haproxy-service - glance-config -> glance-service -> haproxy-service

View File

View File

@ -0,0 +1,75 @@
"""
Available controls:
*depends_on* implements relationship that will guarantee that depended action
on resource will be executed after parent, if parent will be executed. It means
that this control contributes only to ordering, and wont trigger any action
if dependent resource isnt changed.
depends_on:
- parent:run -> ok -> dependent:run
*react_on* - relationship which will guarantee that action on dependent resource
will be executed if parent action is going to be executed. This control will
trigger action even if no changes noticed on dependent resource.
react_on:
- parent:update -> ok -> dependent:update
"""
import re
from solar.core.log import log
EVENT = re.compile(r'\s+->\s+')
class Event(object):
def __init__(self, event):
self.parent, self.dependent, self.state = EVENT.split(event)
self.parent_node, self.parent_action = self.parent.split(':')
self.dep_node, self.dep_action = self.dependent.split(':')
def __repr__(self):
return '{}({} -> {} -> {})'.format(
self.__class__.__name__,
self.parent, self.dependent, self.state)
class Dependency(Event):
def add(self, changed_resources, changes_graph):
if self.parent in changes_graph:
changes_graph.add_edge(
self.parent, self.dependent, state=self.state)
class React(Event):
def add(self, changed_resources, changes_graph):
changes_graph.add_edge(self.parent, self.dependent, state=self.state)
changed_resources.append(self.dep_node)
def build_edges(changed_resources, changes_graph, events):
"""
:param changed_resources: list of resource names that were changed
:param changes_graph: nx.DiGraph object with actions to be executed
:param events:
"""
stack = changed_resources[:]
while stack:
node = stack.pop()
events_objects = []
if node in events:
log.debug('Events %s for resource %s', events[node], node)
for e in events[node].get('react_on', ()):
React(e).add(stack, changes_graph)
for e in events[node].get('depends_on', ()):
Dependency(e).add(stack, changes_graph)
return changes_graph

View File

@ -10,7 +10,7 @@ from solar import errors
class RedisDB(object): class RedisDB(object):
COLLECTIONS = Enum( COLLECTIONS = Enum(
'Collections', 'Collections',
'connection resource state_data state_log' 'connection resource state_data state_log events'
) )
DB = { DB = {
'host': 'localhost', 'host': 'localhost',

View File

@ -3,6 +3,7 @@ import networkx as nx
from pytest import fixture from pytest import fixture
@fixture @fixture
def simple(): def simple():
dg = nx.DiGraph() dg = nx.DiGraph()
@ -10,24 +11,29 @@ def simple():
dg.add_edge('keystone_config.run', 'haproxy.reload', event='changed') dg.add_edge('keystone_config.run', 'haproxy.reload', event='changed')
return dg return dg
def test_simple(simple): def test_simple(simple):
nx.write_dot(simple, 'simple.dot') pass
@fixture @fixture
def rmq(): def rmq():
"""Example of a case when we have cycles on a data plane.""" """Example of a case when we have cycles on a data plane."""
dg = nx.DiGraph() dg = nx.DiGraph()
dg.add_edge('rmq.1.run', 'rmq.1.cluster_create', event='changed') dg.add_edge('rmq_cluster.run', 'rmq_cluster.1.create', event='changed')
dg.add_edge('rmq.1.cluster_create', 'rmq.2.cluster_join', event='changed') dg.add_edge('rmq_cluster.run', 'rmq_cluster.2.join', event='changed')
dg.add_edge('rmq.1.cluster_create', 'rmq.3.cluster_join', event='changed') dg.add_edge('rmq_cluster.run', 'rmq_cluster.3.join', event='changed')
dg.add_edge('rmq.2.run', 'rmq.2.cluster_join', event='changed') dg.add_edge('rmq.1.run', 'rmq_cluster.1.create', event='changed')
dg.add_edge('rmq.3.run', 'rmq.3.cluster_join', event='changed') dg.add_edge('rmq.2.run', 'rmq_cluster.2.join', event='changed')
dg.add_edge('rmq.3.run', 'rmq_cluster.3.join', event='changed')
dg.add_edge('rmq_cluster.1.create', 'rmq_cluster.2.join', event='changed')
dg.add_edge('rmq_cluster.1.create', 'rmq_cluster.3.join', event='changed')
return dg return dg
def test_rmq(rmq): def test_rmq(rmq):
nx.write_dot(rmq, 'rmq.dot') pass
@fixture @fixture
@ -43,4 +49,4 @@ def haproxy():
def test_haproxy(haproxy): def test_haproxy(haproxy):
nx.write_dot(haproxy, 'haproxy.dot') pass