Merge remote-tracking branch 'pigmej/orchestrator_os_hacking_guidelines' into pepmerge
This commit is contained in:
commit
788a667145
@ -21,16 +21,18 @@ import collections
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
import collections
|
||||||
from fabric import api as fabric_api
|
from fabric import api as fabric_api
|
||||||
import networkx as nx
|
import networkx as nx
|
||||||
|
|
||||||
|
from solar.core import resource as sresource
|
||||||
|
from solar.core import signals
|
||||||
|
|
||||||
from solar.cli import base
|
from solar.cli import base
|
||||||
from solar.cli.events import events
|
from solar.cli.events import events
|
||||||
from solar.cli.orch import orchestration
|
from solar.cli.orch import orchestration
|
||||||
from solar.cli.resource import resource as cli_resource
|
from solar.cli.resource import resource as cli_resource
|
||||||
from solar.cli.system_log import changes
|
from solar.cli.system_log import changes
|
||||||
from solar.core import resource as sresource
|
|
||||||
from solar.core import signals
|
|
||||||
|
|
||||||
|
|
||||||
# HELPERS
|
# HELPERS
|
||||||
|
@ -18,14 +18,14 @@ import time
|
|||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from solar.cli.uids_history import remember_uid
|
|
||||||
from solar.cli.uids_history import SOLARUID
|
|
||||||
from solar import errors
|
|
||||||
from solar.orchestration import filters
|
from solar.orchestration import filters
|
||||||
from solar.orchestration import graph
|
from solar.orchestration import graph
|
||||||
from solar.orchestration import tasks
|
from solar.orchestration import tasks
|
||||||
from solar.orchestration.traversal import states
|
from solar.orchestration.traversal import states
|
||||||
from solar.orchestration import utils
|
from solar.orchestration import utils
|
||||||
|
from solar.cli.uids_history import remember_uid
|
||||||
|
from solar.cli.uids_history import SOLARUID
|
||||||
|
from solar import errors
|
||||||
|
|
||||||
|
|
||||||
@click.group(name='orch')
|
@click.group(name='orch')
|
||||||
|
@ -259,6 +259,5 @@ def remove(name, tag, f):
|
|||||||
if f:
|
if f:
|
||||||
msg = 'Resource %s removed from database' % res.name
|
msg = 'Resource %s removed from database' % res.name
|
||||||
else:
|
else:
|
||||||
msg = 'Resource %s will be removed after commiting changes.'
|
click.echo(
|
||||||
msg = msg % res.name
|
'Resource %s will be removed after commiting changes.' % res.name)
|
||||||
click.echo(msg)
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import yaml
|
||||||
|
|
||||||
from bunch import Bunch
|
from bunch import Bunch
|
||||||
import yaml
|
import yaml
|
||||||
|
@ -23,7 +23,7 @@ def setup_logger():
|
|||||||
handler = logging.FileHandler('solar.log')
|
handler = logging.FileHandler('solar.log')
|
||||||
handler.setLevel(logging.DEBUG)
|
handler.setLevel(logging.DEBUG)
|
||||||
formatter = logging.Formatter(
|
formatter = logging.Formatter(
|
||||||
'%(asctime)s %(levelname)s %(funcName)s (%(filename)s::%(lineno)s)::%(message)s') # NOQA
|
'%(asctime)s %(levelname)s %(funcName)s (%(filename)s::%(lineno)s)::%(message)s')
|
||||||
handler.setFormatter(formatter)
|
handler.setFormatter(formatter)
|
||||||
log.addHandler(handler)
|
log.addHandler(handler)
|
||||||
|
|
||||||
|
@ -216,8 +216,7 @@ class Resource(object):
|
|||||||
for (emitter_resource, emitter_input), (receiver_resource, receiver_input), meta in self.graph().edges(data=True): # NOQA
|
for (emitter_resource, emitter_input), (receiver_resource, receiver_input), meta in self.graph().edges(data=True): # NOQA
|
||||||
if meta:
|
if meta:
|
||||||
receiver_input = '{}:{}|{}'.format(receiver_input,
|
receiver_input = '{}:{}|{}'.format(receiver_input,
|
||||||
meta['destination_key'],
|
meta['destination_key'], meta['tag'])
|
||||||
meta['tag'])
|
|
||||||
|
|
||||||
rst.add(
|
rst.add(
|
||||||
(emitter_resource, emitter_input,
|
(emitter_resource, emitter_input,
|
||||||
|
@ -112,9 +112,8 @@ def _get_template(name, content, kwargs, inputs):
|
|||||||
if input not in kwargs:
|
if input not in kwargs:
|
||||||
missing.append(input)
|
missing.append(input)
|
||||||
if missing:
|
if missing:
|
||||||
err = '[{0}] Validation error. Missing data in input: {1}'
|
raise Exception(
|
||||||
err = err.format(name, missing)
|
'[{0}] Validation error. Missing data in input: {1}'.format(name, missing))
|
||||||
raise Exception(err)
|
|
||||||
template = Template(content, trim_blocks=True, lstrip_blocks=True)
|
template = Template(content, trim_blocks=True, lstrip_blocks=True)
|
||||||
template = template.render(str=str, zip=zip, **kwargs)
|
template = template.render(str=str, zip=zip, **kwargs)
|
||||||
return template
|
return template
|
||||||
|
@ -83,8 +83,7 @@ def location_and_transports(emitter, receiver, orig_mapping):
|
|||||||
emitter_single_reverse = emitter_single.get('reverse')
|
emitter_single_reverse = emitter_single.get('reverse')
|
||||||
receiver_single_reverse = receiver_single.get('reverse')
|
receiver_single_reverse = receiver_single.get('reverse')
|
||||||
if inps_receiver is None and inps_emitter is not None:
|
if inps_receiver is None and inps_emitter is not None:
|
||||||
# we don't connect automaticaly when
|
# we don't connect automaticaly when receiver is None and emitter is not None
|
||||||
# receiver is None and emitter is not None
|
|
||||||
# for cases when we connect existing transports to other data
|
# for cases when we connect existing transports to other data
|
||||||
# containers
|
# containers
|
||||||
if receiver_single_reverse:
|
if receiver_single_reverse:
|
||||||
|
@ -20,11 +20,8 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import libtorrent as lt
|
|
||||||
|
|
||||||
state_str = ['queued', 'checking', 'downloading metadata',
|
state_str = ['queued', 'checking', 'downloading metadata',
|
||||||
'downloading', 'finished', 'seeding', 'allocating',
|
'downloading', 'finished', 'seeding', 'allocating', 'checking fastresume']
|
||||||
'checking fastresume']
|
|
||||||
|
|
||||||
|
|
||||||
class MultiTorrent(object):
|
class MultiTorrent(object):
|
||||||
@ -150,9 +147,9 @@ def _getter(torrents, max_seed_ratio=3):
|
|||||||
# mt.force_reannounce()
|
# mt.force_reannounce()
|
||||||
s = ses.status()
|
s = ses.status()
|
||||||
if i % 5 == 0:
|
if i % 5 == 0:
|
||||||
print('%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' %
|
print '%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % \
|
||||||
(mt.progress * 100, s.download_rate / 1000, s.upload_rate / 1000,
|
(mt.progress * 100, s.download_rate / 1000, s.upload_rate / 1000,
|
||||||
s.num_peers, mt.numbers()))
|
s.num_peers, mt.numbers())
|
||||||
now = time.time()
|
now = time.time()
|
||||||
current_state = (now, mt.progress)
|
current_state = (now, mt.progress)
|
||||||
if current_state[-1] != last_state[-1]:
|
if current_state[-1] != last_state[-1]:
|
||||||
|
@ -18,9 +18,10 @@ __all__ = ['add_dep', 'add_react', 'Dep', 'React', 'add_event']
|
|||||||
import networkx as nx
|
import networkx as nx
|
||||||
|
|
||||||
from solar.core.log import log
|
from solar.core.log import log
|
||||||
from solar.events.controls import Dep, React, StateChange
|
|
||||||
|
|
||||||
from solar.dblayer.solar_models import Resource
|
from solar.dblayer.solar_models import Resource
|
||||||
|
from solar.events.controls import Dep
|
||||||
|
from solar.events.controls import React
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_event(event_dict):
|
def create_event(event_dict):
|
||||||
@ -99,6 +100,7 @@ def all_events(resource):
|
|||||||
|
|
||||||
def bft_events_graph(start):
|
def bft_events_graph(start):
|
||||||
"""Builds graph of events traversing events in breadth-first order
|
"""Builds graph of events traversing events in breadth-first order
|
||||||
|
|
||||||
This graph doesnt necessary reflect deployment order, it is used
|
This graph doesnt necessary reflect deployment order, it is used
|
||||||
to show dependencies between resources
|
to show dependencies between resources
|
||||||
"""
|
"""
|
||||||
@ -127,7 +129,8 @@ def bft_events_graph(start):
|
|||||||
|
|
||||||
|
|
||||||
def build_edges(changes_graph, events):
|
def build_edges(changes_graph, events):
|
||||||
"""
|
"""Builds graph edges
|
||||||
|
|
||||||
:param changes_graph: nx.DiGraph object with actions to be executed
|
:param changes_graph: nx.DiGraph object with actions to be executed
|
||||||
:param events: {res: [controls.Event objects]}
|
:param events: {res: [controls.Event objects]}
|
||||||
"""
|
"""
|
||||||
@ -149,7 +152,8 @@ def build_edges(changes_graph, events):
|
|||||||
log.debug('No outgoing events based on %s', event_name)
|
log.debug('No outgoing events based on %s', event_name)
|
||||||
|
|
||||||
if event_name not in visited:
|
if event_name not in visited:
|
||||||
for parent, child, data in events_graph.edges(event_name, data=True):
|
for parent, child, data in events_graph.edges(event_name,
|
||||||
|
data=True):
|
||||||
succ_ev = data['event']
|
succ_ev = data['event']
|
||||||
succ_ev.insert(stack, changes_graph)
|
succ_ev.insert(stack, changes_graph)
|
||||||
visited.add(event_name)
|
visited.add(event_name)
|
||||||
|
@ -23,16 +23,18 @@ if dependent resource isnt changed.
|
|||||||
depends_on:
|
depends_on:
|
||||||
- parent:run -> ok -> dependent:run
|
- parent:run -> ok -> dependent:run
|
||||||
|
|
||||||
*react_on* - relationship which will guarantee that action on dependent resource
|
*react_on* - relationship which will guarantee that action on dependent
|
||||||
will be executed if parent action is going to be executed. This control will
|
resource will be executed if parent action is going to be executed.
|
||||||
trigger action even if no changes noticed on dependent resource.
|
This control will trigger action even
|
||||||
|
if no changes noticed on dependent resource.
|
||||||
|
|
||||||
react_on:
|
react_on:
|
||||||
- parent:update -> ok -> dependent:update
|
- parent:update -> ok -> dependent:update
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from solar.dblayer.solar_models import Resource
|
|
||||||
from solar.dblayer.model import DBLayerNotFound
|
from solar.dblayer.model import DBLayerNotFound
|
||||||
|
from solar.dblayer.solar_models import Resource
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Event(object):
|
class Event(object):
|
||||||
|
@ -14,9 +14,10 @@
|
|||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from solar.orchestration.runner import app
|
|
||||||
from celery import group
|
from celery import group
|
||||||
|
|
||||||
|
from solar.orchestration.runner import app
|
||||||
|
|
||||||
|
|
||||||
def celery_executor(dg, tasks, control_tasks=()):
|
def celery_executor(dg, tasks, control_tasks=()):
|
||||||
to_execute = []
|
to_execute = []
|
||||||
@ -28,7 +29,8 @@ def celery_executor(dg, tasks, control_tasks=()):
|
|||||||
task_id = '{}:{}'.format(dg.graph['uid'], task_name)
|
task_id = '{}:{}'.format(dg.graph['uid'], task_name)
|
||||||
task = app.tasks[dg.node[task_name]['type']]
|
task = app.tasks[dg.node[task_name]['type']]
|
||||||
|
|
||||||
if all_success(dg, dg.predecessors(task_name)) or task_name in control_tasks:
|
all_ok = all_success(dg, dg.predecessors(task_name))
|
||||||
|
if all_ok or task_name in control_tasks:
|
||||||
dg.node[task_name]['status'] = 'INPROGRESS'
|
dg.node[task_name]['status'] = 'INPROGRESS'
|
||||||
dg.node[task_name]['start_time'] = time.time()
|
dg.node[task_name]['start_time'] = time.time()
|
||||||
for t in generate_task(task, dg.node[task_name], task_id):
|
for t in generate_task(task, dg.node[task_name], task_id):
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
|
|
||||||
import networkx as nx
|
import networkx as nx
|
||||||
|
|
||||||
from .traversal import VISITED, states
|
from solar.orchestration.traversal import states
|
||||||
|
from solar.orchestration.traversal import VISITED
|
||||||
|
|
||||||
|
|
||||||
def get_dfs_postorder_subgraph(dg, nodes):
|
def get_dfs_postorder_subgraph(dg, nodes):
|
||||||
@ -26,6 +27,7 @@ def get_dfs_postorder_subgraph(dg, nodes):
|
|||||||
|
|
||||||
def end_at(dg, nodes):
|
def end_at(dg, nodes):
|
||||||
"""Returns subgraph that will guarantee that predecessors are visited
|
"""Returns subgraph that will guarantee that predecessors are visited
|
||||||
|
|
||||||
dg - directed graph
|
dg - directed graph
|
||||||
nodes - iterable with node names
|
nodes - iterable with node names
|
||||||
"""
|
"""
|
||||||
@ -33,8 +35,7 @@ def end_at(dg, nodes):
|
|||||||
|
|
||||||
|
|
||||||
def start_from(dg, start_nodes):
|
def start_from(dg, start_nodes):
|
||||||
"""Guarantee that all paths starting from specific *nodes* will be visited
|
"""Ensures that all paths starting from specific *nodes* will be visited"""
|
||||||
"""
|
|
||||||
visited = {n for n in dg if dg.node[n].get('status') in VISITED}
|
visited = {n for n in dg if dg.node[n].get('status') in VISITED}
|
||||||
|
|
||||||
# sorting nodes in topological order will guarantee that all predecessors
|
# sorting nodes in topological order will guarantee that all predecessors
|
||||||
@ -71,7 +72,8 @@ def validate(dg, start_nodes, end_nodes, err_msgs):
|
|||||||
|
|
||||||
|
|
||||||
def filter(dg, start=None, end=None, tasks=(), skip_with=states.SKIPPED.name):
|
def filter(dg, start=None, end=None, tasks=(), skip_with=states.SKIPPED.name):
|
||||||
"""
|
"""Filters a graph
|
||||||
|
|
||||||
TODO(dshulyak) skip_with should also support NOOP, which will instead
|
TODO(dshulyak) skip_with should also support NOOP, which will instead
|
||||||
of blocking task, and its successors, should mark task as visited
|
of blocking task, and its successors, should mark task as visited
|
||||||
|
|
||||||
|
@ -12,19 +12,18 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import uuid
|
from collections import Counter
|
||||||
import time
|
import time
|
||||||
|
import uuid
|
||||||
|
|
||||||
import networkx as nx
|
import networkx as nx
|
||||||
|
|
||||||
from solar import utils
|
|
||||||
from .traversal import states
|
|
||||||
from solar import errors
|
|
||||||
|
|
||||||
from collections import Counter
|
|
||||||
|
|
||||||
from solar.dblayer.solar_models import Task
|
|
||||||
from solar.dblayer.model import clear_cache
|
from solar.dblayer.model import clear_cache
|
||||||
|
from solar.dblayer.solar_models import Task
|
||||||
|
from solar import errors
|
||||||
|
from solar import utils
|
||||||
|
|
||||||
|
from solar.orchestration.traversal import states
|
||||||
|
|
||||||
|
|
||||||
def save_graph(graph):
|
def save_graph(graph):
|
||||||
@ -77,8 +76,7 @@ get_plan = get_graph
|
|||||||
|
|
||||||
|
|
||||||
def parse_plan(plan_path):
|
def parse_plan(plan_path):
|
||||||
""" parses yaml definition and returns graph
|
"""parses yaml definition and returns graph"""
|
||||||
"""
|
|
||||||
plan = utils.yaml_load(plan_path)
|
plan = utils.yaml_load(plan_path)
|
||||||
dg = nx.MultiDiGraph()
|
dg = nx.MultiDiGraph()
|
||||||
dg.graph['name'] = plan['name']
|
dg.graph['name'] = plan['name']
|
||||||
@ -123,8 +121,6 @@ def show(uid):
|
|||||||
|
|
||||||
|
|
||||||
def create_plan(plan_path, save=True):
|
def create_plan(plan_path, save=True):
|
||||||
"""
|
|
||||||
"""
|
|
||||||
dg = parse_plan(plan_path)
|
dg = parse_plan(plan_path)
|
||||||
return create_plan_from_graph(dg, save=save)
|
return create_plan_from_graph(dg, save=save)
|
||||||
|
|
||||||
@ -163,8 +159,9 @@ def report_topo(uid):
|
|||||||
|
|
||||||
|
|
||||||
def wait_finish(uid, timeout):
|
def wait_finish(uid, timeout):
|
||||||
"""Wait finish will periodically load graph and check if there is no
|
"""Check if graph is finished
|
||||||
PENDING or INPROGRESS
|
|
||||||
|
Will return when no PENDING or INPROGRESS otherwise yields summary
|
||||||
"""
|
"""
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
|
@ -47,7 +47,9 @@ def get_default_chain(dg, inprogress, added):
|
|||||||
|
|
||||||
|
|
||||||
def type_based_rule(dg, inprogress, item):
|
def type_based_rule(dg, inprogress, item):
|
||||||
"""condition will be specified like:
|
"""Checks type based rules
|
||||||
|
|
||||||
|
condition should be specified like:
|
||||||
type_limit: 2
|
type_limit: 2
|
||||||
"""
|
"""
|
||||||
_type = dg.node[item].get('resource_type')
|
_type = dg.node[item].get('resource_type')
|
||||||
|
@ -14,21 +14,22 @@
|
|||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
|
||||||
|
|
||||||
from celery.app import task
|
from celery.app import task
|
||||||
from celery.signals import task_prerun, task_postrun
|
from celery.signals import task_postrun
|
||||||
|
from celery.signals import task_prerun
|
||||||
|
|
||||||
from solar.orchestration import graph
|
|
||||||
from solar.core import actions
|
from solar.core import actions
|
||||||
from solar.core import resource
|
from solar.core import resource
|
||||||
from solar.system_log.tasks import commit_logitem, error_logitem
|
from solar.dblayer import ModelMeta
|
||||||
|
from solar.orchestration import executor
|
||||||
|
from solar.orchestration import graph
|
||||||
|
from solar.orchestration import limits
|
||||||
from solar.orchestration.runner import app
|
from solar.orchestration.runner import app
|
||||||
from solar.orchestration.traversal import traverse
|
from solar.orchestration.traversal import traverse
|
||||||
from solar.orchestration import limits
|
from solar.system_log.tasks import commit_logitem
|
||||||
from solar.orchestration import executor
|
from solar.system_log.tasks import error_logitem
|
||||||
from solar.dblayer import ModelMeta
|
import time
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['solar_resource', 'cmd', 'sleep',
|
__all__ = ['solar_resource', 'cmd', 'sleep',
|
||||||
'error', 'fault_tolerance', 'schedule_start', 'schedule_next']
|
'error', 'fault_tolerance', 'schedule_start', 'schedule_next']
|
||||||
|
@ -18,7 +18,8 @@ import networkx as nx
|
|||||||
|
|
||||||
|
|
||||||
def write_graph(plan):
|
def write_graph(plan):
|
||||||
"""
|
"""Writes graph to dot then to svg
|
||||||
|
|
||||||
:param plan: networkx Graph object
|
:param plan: networkx Graph object
|
||||||
"""
|
"""
|
||||||
colors = {
|
colors = {
|
||||||
|
@ -15,19 +15,20 @@
|
|||||||
import dictdiffer
|
import dictdiffer
|
||||||
import networkx as nx
|
import networkx as nx
|
||||||
|
|
||||||
from solar.system_log import data
|
|
||||||
from solar.core.log import log
|
from solar.core.log import log
|
||||||
from solar.core import signals
|
|
||||||
from solar.core import resource
|
from solar.core import resource
|
||||||
|
from solar.core.resource.resource import RESOURCE_STATE
|
||||||
|
from solar.core import signals
|
||||||
|
from solar.dblayer.solar_models import CommitedResource
|
||||||
|
from solar.dblayer.solar_models import LogItem
|
||||||
|
from solar.dblayer.solar_models import StrInt
|
||||||
|
from solar.events import api as evapi
|
||||||
|
from solar.orchestration import graph
|
||||||
|
from solar.system_log import data
|
||||||
from solar import utils
|
from solar import utils
|
||||||
|
|
||||||
from solar.orchestration import graph
|
from solar.core.consts import CHANGES
|
||||||
from solar.events import api as evapi
|
|
||||||
from .consts import CHANGES
|
|
||||||
from solar.core.resource.resource import RESOURCE_STATE
|
|
||||||
from solar.errors import CannotFindID
|
|
||||||
|
|
||||||
from solar.dblayer.solar_models import Resource, LogItem, CommitedResource, StrInt
|
|
||||||
|
|
||||||
|
|
||||||
def guess_action(from_, to):
|
def guess_action(from_, to):
|
||||||
@ -135,7 +136,9 @@ def parameters(res, action, data):
|
|||||||
|
|
||||||
|
|
||||||
def _get_args_to_update(args, connections):
|
def _get_args_to_update(args, connections):
|
||||||
"""For each resource we can update only args that are not provided
|
"""Returns args to update
|
||||||
|
|
||||||
|
For each resource we can update only args that are not provided
|
||||||
by connections
|
by connections
|
||||||
"""
|
"""
|
||||||
inherited = [i[3].split(':')[0] for i in connections]
|
inherited = [i[3].split(':')[0] for i in connections]
|
||||||
@ -146,7 +149,8 @@ def _get_args_to_update(args, connections):
|
|||||||
|
|
||||||
|
|
||||||
def revert_uids(uids):
|
def revert_uids(uids):
|
||||||
"""
|
"""Reverts uids
|
||||||
|
|
||||||
:param uids: iterable not generator
|
:param uids: iterable not generator
|
||||||
"""
|
"""
|
||||||
items = LogItem.multi_get(uids)
|
items = LogItem.multi_get(uids)
|
||||||
@ -165,15 +169,15 @@ def revert_uids(uids):
|
|||||||
|
|
||||||
|
|
||||||
def _revert_remove(logitem):
|
def _revert_remove(logitem):
|
||||||
"""Resource should be created with all previous connections
|
"""Resource should be created with all previous connections"""
|
||||||
"""
|
|
||||||
commited = CommitedResource.get(logitem.resource)
|
commited = CommitedResource.get(logitem.resource)
|
||||||
args = dictdiffer.revert(logitem.diff, commited.inputs)
|
args = dictdiffer.revert(logitem.diff, commited.inputs)
|
||||||
connections = dictdiffer.revert(
|
connections = dictdiffer.revert(
|
||||||
logitem.connections_diff, sorted(commited.connections))
|
logitem.connections_diff, sorted(commited.connections))
|
||||||
|
|
||||||
resource.Resource(logitem.resource, logitem.base_path,
|
resource.Resource(logitem.resource, logitem.base_path,
|
||||||
args=_get_args_to_update(args, connections), tags=commited.tags)
|
args=_get_args_to_update(args, connections),
|
||||||
|
tags=commited.tags)
|
||||||
for emitter, emitter_input, receiver, receiver_input in connections:
|
for emitter, emitter_input, receiver, receiver_input in connections:
|
||||||
emmiter_obj = resource.load(emitter)
|
emmiter_obj = resource.load(emitter)
|
||||||
receiver_obj = resource.load(receiver)
|
receiver_obj = resource.load(receiver)
|
||||||
@ -181,7 +185,7 @@ def _revert_remove(logitem):
|
|||||||
emitter_input: receiver_input})
|
emitter_input: receiver_input})
|
||||||
|
|
||||||
|
|
||||||
def _update_inputs_connections(res_obj, args, old_connections, new_connections):
|
def _update_inputs_connections(res_obj, args, old_connections, new_connections): # NOQA
|
||||||
|
|
||||||
removed = []
|
removed = []
|
||||||
for item in old_connections:
|
for item in old_connections:
|
||||||
@ -204,7 +208,8 @@ def _update_inputs_connections(res_obj, args, old_connections, new_connections):
|
|||||||
emmiter_obj.connect(receiver_obj, {emitter_input: receiver_input})
|
emmiter_obj.connect(receiver_obj, {emitter_input: receiver_input})
|
||||||
|
|
||||||
if removed or added:
|
if removed or added:
|
||||||
# TODO without save we will get error that some values can not be updated
|
# TODO without save we will get error
|
||||||
|
# that some values can not be updated
|
||||||
# even if connection was removed
|
# even if connection was removed
|
||||||
receiver_obj.db_obj.save()
|
receiver_obj.db_obj.save()
|
||||||
|
|
||||||
@ -212,8 +217,7 @@ def _update_inputs_connections(res_obj, args, old_connections, new_connections):
|
|||||||
|
|
||||||
|
|
||||||
def _revert_update(logitem):
|
def _revert_update(logitem):
|
||||||
"""Revert of update should update inputs and connections
|
"""Revert of update should update inputs and connections"""
|
||||||
"""
|
|
||||||
res_obj = resource.load(logitem.resource)
|
res_obj = resource.load(logitem.resource)
|
||||||
commited = res_obj.load_commited()
|
commited = res_obj.load_commited()
|
||||||
|
|
||||||
@ -222,7 +226,8 @@ def _revert_update(logitem):
|
|||||||
args = dictdiffer.revert(logitem.diff, commited.inputs)
|
args = dictdiffer.revert(logitem.diff, commited.inputs)
|
||||||
|
|
||||||
_update_inputs_connections(
|
_update_inputs_connections(
|
||||||
res_obj, _get_args_to_update(args, connections), commited.connections, connections)
|
res_obj, _get_args_to_update(args, connections),
|
||||||
|
commited.connections, connections)
|
||||||
|
|
||||||
|
|
||||||
def _revert_run(logitem):
|
def _revert_run(logitem):
|
||||||
@ -247,7 +252,9 @@ def _discard_update(item):
|
|||||||
args = dictdiffer.revert(item.diff, resource_obj.args)
|
args = dictdiffer.revert(item.diff, resource_obj.args)
|
||||||
|
|
||||||
_update_inputs_connections(
|
_update_inputs_connections(
|
||||||
resource_obj, _get_args_to_update(args, new_connections), old_connections, new_connections)
|
resource_obj, _get_args_to_update(args, new_connections),
|
||||||
|
old_connections, new_connections)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _discard_run(item):
|
def _discard_run(item):
|
||||||
@ -279,9 +286,8 @@ def discard_all():
|
|||||||
|
|
||||||
|
|
||||||
def commit_all():
|
def commit_all():
|
||||||
"""Helper mainly for ease of testing
|
"""Helper mainly for ease of testing"""
|
||||||
"""
|
from solar.system_log.operations import move_to_commited
|
||||||
from .operations import move_to_commited
|
|
||||||
for item in data.SL():
|
for item in data.SL():
|
||||||
move_to_commited(item.log_action)
|
move_to_commited(item.log_action)
|
||||||
|
|
||||||
|
@ -12,11 +12,13 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from solar.system_log import data
|
|
||||||
from solar.dblayer.solar_models import CommitedResource
|
|
||||||
from dictdiffer import patch
|
from dictdiffer import patch
|
||||||
|
|
||||||
from solar.core.resource import resource
|
from solar.core.resource import resource
|
||||||
from .consts import CHANGES
|
from solar.dblayer.solar_models import CommitedResource
|
||||||
|
from solar.system_log import data
|
||||||
|
|
||||||
|
from solar.system_log.consts import CHANGES
|
||||||
|
|
||||||
|
|
||||||
def set_error(log_action, *args, **kwargs):
|
def set_error(log_action, *args, **kwargs):
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from solar.orchestration.runner import app
|
from solar.orchestration.runner import app
|
||||||
from solar.system_log.operations import set_error, move_to_commited
|
from solar.system_log.operations import move_to_commited
|
||||||
|
from solar.system_log.operations import set_error
|
||||||
|
|
||||||
__all__ = ['error_logitem', 'commit_logitem']
|
__all__ = ['error_logitem', 'commit_logitem']
|
||||||
|
|
||||||
|
@ -198,7 +198,8 @@ class ResourceListTemplate(BaseTemplate):
|
|||||||
self.add_react(action_state, ResourceTemplate(r), action)
|
self.add_react(action_state, ResourceTemplate(r), action)
|
||||||
|
|
||||||
def filter(self, func):
|
def filter(self, func):
|
||||||
"""Return ResourceListeTemplate instance with resources filtered by func.
|
"""Return ResourceListeTemplate instance with resources filtered
|
||||||
|
by func.
|
||||||
|
|
||||||
func -- predictate function that takes (idx, resource) as parameter
|
func -- predictate function that takes (idx, resource) as parameter
|
||||||
(idx is the index of resource in self.resources list)
|
(idx is the index of resource in self.resources list)
|
||||||
@ -233,7 +234,8 @@ class ResourceListTemplate(BaseTemplate):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def connect_list_to_each(self, resources, mapping=None, events=None):
|
def connect_list_to_each(self, resources, mapping=None, events=None):
|
||||||
"""Connect each resource in self.resources to each resource in resources.
|
"""Connect each resource in self.resources to each resource in
|
||||||
|
resources.
|
||||||
|
|
||||||
mapping -- optional mapping
|
mapping -- optional mapping
|
||||||
"{emitter_num}" -- substitutes for emitter's index in mapping (from
|
"{emitter_num}" -- substitutes for emitter's index in mapping (from
|
||||||
@ -260,9 +262,8 @@ class ResourceListTemplate(BaseTemplate):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def on_each(self, resource_path, args=None):
|
def on_each(self, resource_path, args=None):
|
||||||
"""Create resource form resource_path
|
"""Create resource form resource_path on each resource in
|
||||||
|
self.resources.
|
||||||
on each resource in self.resources
|
|
||||||
"""
|
"""
|
||||||
args = args or {}
|
args = args or {}
|
||||||
|
|
||||||
|
@ -15,12 +15,13 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
|
||||||
import yaml
|
|
||||||
import time
|
import time
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
from solar.core.resource import virtual_resource as vr
|
from solar.core.resource import virtual_resource as vr
|
||||||
from solar.dblayer.model import Model, Replacer, ModelMeta, get_bucket
|
from solar.dblayer.model import Model
|
||||||
|
|
||||||
|
|
||||||
def patched_get_bucket_name(cls):
|
def patched_get_bucket_name(cls):
|
||||||
|
@ -14,11 +14,13 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from solar.core.resource import Resource
|
|
||||||
from solar.dblayer.model import Model, ModelMeta, get_bucket
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from solar.core.resource import Resource
|
||||||
|
from solar.dblayer.model import Model
|
||||||
|
from solar.dblayer.model import ModelMeta
|
||||||
|
from solar.dblayer.model import get_bucket
|
||||||
|
|
||||||
|
|
||||||
def patched_get_bucket_name(cls):
|
def patched_get_bucket_name(cls):
|
||||||
return cls.__name__ + str(time.time())
|
return cls.__name__ + str(time.time())
|
||||||
@ -49,13 +51,6 @@ def setup(request):
|
|||||||
model.bucket = get_bucket(None, model, ModelMeta)
|
model.bucket = get_bucket(None, model, ModelMeta)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def setup(request):
|
|
||||||
|
|
||||||
for model in ModelMeta._defined_models:
|
|
||||||
model.bucket = get_bucket(None, model, ModelMeta)
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_runtest_teardown(item, nextitem):
|
def pytest_runtest_teardown(item, nextitem):
|
||||||
ModelMeta.session_end(result=True)
|
ModelMeta.session_end(result=True)
|
||||||
return nextitem
|
return nextitem
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import networkx as nx
|
import networkx as nx
|
||||||
from pytest import fixture
|
|
||||||
from mock import patch
|
from mock import patch
|
||||||
|
from pytest import fixture
|
||||||
|
|
||||||
from solar.orchestration import executor
|
from solar.orchestration import executor
|
||||||
|
|
||||||
@ -29,7 +29,6 @@ def dg():
|
|||||||
|
|
||||||
@patch.object(executor, 'app')
|
@patch.object(executor, 'app')
|
||||||
def test_celery_executor(mapp, dg):
|
def test_celery_executor(mapp, dg):
|
||||||
"""Just check that it doesnt fail for now.
|
"""Just check that it doesnt fail for now."""
|
||||||
"""
|
|
||||||
assert executor.celery_executor(dg, ['t1'])
|
assert executor.celery_executor(dg, ['t1'])
|
||||||
assert dg.node['t1']['status'] == 'INPROGRESS'
|
assert dg.node['t1']['status'] == 'INPROGRESS'
|
||||||
|
@ -12,9 +12,9 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from dictdiffer import patch
|
||||||
|
from dictdiffer import revert
|
||||||
from pytest import fixture
|
from pytest import fixture
|
||||||
from dictdiffer import revert, patch
|
|
||||||
import networkx as nx
|
|
||||||
|
|
||||||
from solar.system_log import change
|
from solar.system_log import change
|
||||||
|
|
||||||
@ -28,8 +28,9 @@ def staged():
|
|||||||
'metadata': {},
|
'metadata': {},
|
||||||
'connections': [
|
'connections': [
|
||||||
['node.1', 'res.1', ['ip', 'ip']],
|
['node.1', 'res.1', ['ip', 'ip']],
|
||||||
['node.1', 'res.1', ['key', 'key']]]
|
['node.1', 'res.1', ['key', 'key']]
|
||||||
}
|
]}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
@ -40,8 +41,9 @@ def commited():
|
|||||||
'list_val': [1]},
|
'list_val': [1]},
|
||||||
'metadata': {},
|
'metadata': {},
|
||||||
'connections': [
|
'connections': [
|
||||||
['node.1', 'res.1', ['ip', 'ip']]]
|
['node.1', 'res.1', ['ip', 'ip']]
|
||||||
}
|
]}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
@ -56,17 +58,24 @@ def diff_for_update(staged, commited):
|
|||||||
|
|
||||||
def test_create_diff_with_empty_commited(full_diff):
|
def test_create_diff_with_empty_commited(full_diff):
|
||||||
# add will be executed
|
# add will be executed
|
||||||
expected = [('add', '', [('connections', [['node.1', 'res.1', ['ip', 'ip']], ['node.1', 'res.1', ['key', 'key']]]), ('input', {
|
expected = [('add', '',
|
||||||
'ip': {'value': '10.0.0.2'}, 'list_val': {'value': [1, 2]}}), ('metadata', {}), ('id', 'res.1'), ('tags', ['res', 'node.1'])])]
|
[('connections', [['node.1', 'res.1', ['ip', 'ip']],
|
||||||
|
['node.1', 'res.1', ['key', 'key']]]),
|
||||||
|
('input', {
|
||||||
|
'ip': {'value': '10.0.0.2'},
|
||||||
|
'list_val': {'value': [1, 2]}
|
||||||
|
}), ('metadata', {}), ('id', 'res.1'),
|
||||||
|
('tags', ['res', 'node.1'])])]
|
||||||
assert full_diff == expected
|
assert full_diff == expected
|
||||||
|
|
||||||
|
|
||||||
def test_create_diff_modified(diff_for_update):
|
def test_create_diff_modified(diff_for_update):
|
||||||
assert diff_for_update == [
|
assert diff_for_update == [
|
||||||
('add', 'connections',
|
('add', 'connections', [(1, ['node.1', 'res.1', ['key', 'key']])]),
|
||||||
[(1, ['node.1', 'res.1', ['key', 'key']])]),
|
('change', 'input.ip',
|
||||||
('change', 'input.ip', ('10.0.0.2', {'value': '10.0.0.2'})),
|
('10.0.0.2', {'value': '10.0.0.2'})), ('change', 'input.list_val',
|
||||||
('change', 'input.list_val', ([1], {'value': [1, 2]}))]
|
([1], {'value': [1, 2]}))
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_verify_patch_creates_expected(staged, diff_for_update, commited):
|
def test_verify_patch_creates_expected(staged, diff_for_update, commited):
|
||||||
@ -81,20 +90,17 @@ def test_revert_update(staged, diff_for_update, commited):
|
|||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
def resources():
|
def resources():
|
||||||
r = {'n.1':
|
r = {'n.1': {'uid': 'n.1',
|
||||||
{'uid': 'n.1',
|
'args': {'ip': '10.20.0.2'},
|
||||||
'args': {'ip': '10.20.0.2'},
|
'connections': [],
|
||||||
'connections': [],
|
'tags': []},
|
||||||
'tags': []},
|
'r.1': {'uid': 'r.1',
|
||||||
'r.1':
|
'args': {'ip': '10.20.0.2'},
|
||||||
{'uid': 'r.1',
|
'connections': [['n.1', 'r.1', ['ip', 'ip']]],
|
||||||
'args': {'ip': '10.20.0.2'},
|
'tags': []},
|
||||||
'connections': [['n.1', 'r.1', ['ip', 'ip']]],
|
'h.1': {'uid': 'h.1',
|
||||||
'tags': []},
|
'args': {'ip': '10.20.0.2',
|
||||||
'h.1':
|
'ips': ['10.20.0.2']},
|
||||||
{'uid': 'h.1',
|
'connections': [['n.1', 'h.1', ['ip', 'ip']]],
|
||||||
'args': {'ip': '10.20.0.2',
|
'tags': []}}
|
||||||
'ips': ['10.20.0.2']},
|
|
||||||
'connections': [['n.1', 'h.1', ['ip', 'ip']]],
|
|
||||||
'tags': []}}
|
|
||||||
return r
|
return r
|
||||||
|
@ -16,10 +16,8 @@
|
|||||||
import networkx as nx
|
import networkx as nx
|
||||||
from pytest import fixture
|
from pytest import fixture
|
||||||
|
|
||||||
from solar.events import api as evapi
|
|
||||||
from solar.dblayer.solar_models import Resource
|
from solar.dblayer.solar_models import Resource
|
||||||
|
from solar.events import api as evapi
|
||||||
from .base import BaseResourceTest
|
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
@ -76,9 +74,7 @@ def test_nova_api_run_after_nova(nova_deps):
|
|||||||
|
|
||||||
|
|
||||||
def test_nova_api_react_on_update(nova_deps):
|
def test_nova_api_react_on_update(nova_deps):
|
||||||
"""Test that nova_api:update will be called even if there is no changes
|
"""Test that nova_api:update will be called even if there is no changes in nova_api""" # NOQA
|
||||||
in nova_api
|
|
||||||
"""
|
|
||||||
changes_graph = nx.DiGraph()
|
changes_graph = nx.DiGraph()
|
||||||
changes_graph.add_node('nova.update')
|
changes_graph.add_node('nova.update')
|
||||||
evapi.build_edges(changes_graph, nova_deps)
|
evapi.build_edges(changes_graph, nova_deps)
|
||||||
@ -89,19 +85,25 @@ def test_nova_api_react_on_update(nova_deps):
|
|||||||
@fixture
|
@fixture
|
||||||
def rmq_deps():
|
def rmq_deps():
|
||||||
"""Example of a case when defaults are not good enough.
|
"""Example of a case when defaults are not good enough.
|
||||||
|
|
||||||
For example we need to run some stuff on first node before two others.
|
For example we need to run some stuff on first node before two others.
|
||||||
"""
|
"""
|
||||||
# NOTE(dshulyak) is it possible to put this create/join logic into
|
# NOTE(dshulyak) is it possible to put this create/join logic into
|
||||||
# puppet manifest? So that rmq_cluster.2 before joining will check if
|
# puppet manifest? So that rmq_cluster.2 before joining will check if
|
||||||
# cluster already exists?
|
# cluster already exists?
|
||||||
return {
|
return {
|
||||||
'rmq.1': [evapi.Dep('rmq.1', 'run', 'success', 'rmq_cluster.1', 'create')],
|
'rmq.1':
|
||||||
'rmq.2': [evapi.Dep('rmq.2', 'run', 'success', 'rmq_cluster.2', 'join')],
|
[evapi.Dep('rmq.1', 'run', 'success', 'rmq_cluster.1', 'create')],
|
||||||
'rmq.3': [evapi.Dep('rmq.3', 'run', 'success', 'rmq_cluster.3', 'join')],
|
'rmq.2':
|
||||||
|
[evapi.Dep('rmq.2', 'run', 'success', 'rmq_cluster.2', 'join')],
|
||||||
|
'rmq.3':
|
||||||
|
[evapi.Dep('rmq.3', 'run', 'success', 'rmq_cluster.3', 'join')],
|
||||||
'rmq_cluster.1': [
|
'rmq_cluster.1': [
|
||||||
evapi.Dep('rmq_cluster.1', 'create',
|
evapi.Dep('rmq_cluster.1', 'create', 'success', 'rmq_cluster.2',
|
||||||
'success', 'rmq_cluster.2', 'join'),
|
'join'), evapi.Dep('rmq_cluster.1', 'create', 'success',
|
||||||
evapi.Dep('rmq_cluster.1', 'create', 'success', 'rmq_cluster.3', 'join')]}
|
'rmq_cluster.3', 'join')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_rmq(rmq_deps):
|
def test_rmq(rmq_deps):
|
||||||
@ -115,29 +117,35 @@ def test_rmq(rmq_deps):
|
|||||||
evapi.build_edges(changes_graph, rmq_deps)
|
evapi.build_edges(changes_graph, rmq_deps)
|
||||||
|
|
||||||
assert set(changes_graph.successors('rmq_cluster.1.create')) == {
|
assert set(changes_graph.successors('rmq_cluster.1.create')) == {
|
||||||
'rmq_cluster.2.join', 'rmq_cluster.3.join'}
|
'rmq_cluster.2.join', 'rmq_cluster.3.join'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_riak():
|
def test_riak():
|
||||||
|
|
||||||
events = {
|
events = {
|
||||||
'riak_service1': [
|
'riak_service1': [
|
||||||
evapi.React('riak_service1', 'run', 'success',
|
evapi.React('riak_service1', 'run', 'success', 'riak_service2',
|
||||||
'riak_service2', 'run'),
|
'run'), evapi.React('riak_service1', 'run', 'success',
|
||||||
evapi.React('riak_service1', 'run', 'success', 'riak_service3', 'run')],
|
'riak_service3', 'run')
|
||||||
|
],
|
||||||
'riak_service3': [
|
'riak_service3': [
|
||||||
evapi.React('riak_service3', 'join', 'success',
|
evapi.React('riak_service3', 'join', 'success', 'riak_service1',
|
||||||
'riak_service1', 'commit'),
|
'commit'),
|
||||||
evapi.React('riak_service3', 'run', 'success', 'riak_service3', 'join')],
|
evapi.React('riak_service3', 'run', 'success', 'riak_service3',
|
||||||
|
'join')
|
||||||
|
],
|
||||||
'riak_service2': [
|
'riak_service2': [
|
||||||
evapi.React('riak_service2', 'run', 'success',
|
evapi.React('riak_service2', 'run', 'success', 'riak_service2',
|
||||||
'riak_service2', 'join'),
|
'join'),
|
||||||
evapi.React('riak_service2', 'join', 'success', 'riak_service1', 'commit')],
|
evapi.React('riak_service2', 'join', 'success', 'riak_service1',
|
||||||
|
'commit')
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
changes_graph = nx.MultiDiGraph()
|
changes_graph = nx.MultiDiGraph()
|
||||||
changes_graph.add_node('riak_service1.run')
|
changes_graph.add_node('riak_service1.run')
|
||||||
evapi.build_edges(changes_graph, events)
|
evapi.build_edges(changes_graph, events)
|
||||||
assert set(changes_graph.predecessors('riak_service1.commit')) == {
|
assert set(changes_graph.predecessors('riak_service1.commit')) == {
|
||||||
'riak_service2.join', 'riak_service3.join'}
|
'riak_service2.join', 'riak_service3.join'
|
||||||
|
}
|
||||||
|
@ -18,14 +18,12 @@ from pytest import fixture
|
|||||||
|
|
||||||
from solar.orchestration import graph
|
from solar.orchestration import graph
|
||||||
from solar.orchestration.traversal import states
|
from solar.orchestration.traversal import states
|
||||||
from solar.dblayer.model import ModelMeta
|
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
def simple():
|
def simple():
|
||||||
simple_path = os.path.join(
|
simple_path = os.path.join(
|
||||||
os.path.dirname(os.path.realpath(__file__)),
|
os.path.dirname(os.path.realpath(__file__)), 'orch_fixtures',
|
||||||
'orch_fixtures',
|
|
||||||
'simple.yaml')
|
'simple.yaml')
|
||||||
return graph.create_plan(simple_path)
|
return graph.create_plan(simple_path)
|
||||||
|
|
||||||
@ -59,7 +57,13 @@ def test_wait_finish(simple):
|
|||||||
simple.node[n]['status'] = states.SUCCESS.name
|
simple.node[n]['status'] = states.SUCCESS.name
|
||||||
graph.update_graph(simple)
|
graph.update_graph(simple)
|
||||||
assert next(graph.wait_finish(simple.graph['uid'], 10)) == {
|
assert next(graph.wait_finish(simple.graph['uid'], 10)) == {
|
||||||
'SKIPPED': 0, 'SUCCESS': 2, 'NOOP': 0, 'ERROR': 0, 'INPROGRESS': 0, 'PENDING': 0}
|
'SKIPPED': 0,
|
||||||
|
'SUCCESS': 2,
|
||||||
|
'NOOP': 0,
|
||||||
|
'ERROR': 0,
|
||||||
|
'INPROGRESS': 0,
|
||||||
|
'PENDING': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_several_updates(simple):
|
def test_several_updates(simple):
|
||||||
@ -67,10 +71,22 @@ def test_several_updates(simple):
|
|||||||
graph.update_graph(simple)
|
graph.update_graph(simple)
|
||||||
|
|
||||||
assert next(graph.wait_finish(simple.graph['uid'], 10)) == {
|
assert next(graph.wait_finish(simple.graph['uid'], 10)) == {
|
||||||
'SKIPPED': 0, 'SUCCESS': 0, 'NOOP': 0, 'ERROR': 1, 'INPROGRESS': 0, 'PENDING': 1}
|
'SKIPPED': 0,
|
||||||
|
'SUCCESS': 0,
|
||||||
|
'NOOP': 0,
|
||||||
|
'ERROR': 1,
|
||||||
|
'INPROGRESS': 0,
|
||||||
|
'PENDING': 1
|
||||||
|
}
|
||||||
|
|
||||||
simple.node['echo_stuff']['status'] = states.ERROR.name
|
simple.node['echo_stuff']['status'] = states.ERROR.name
|
||||||
graph.update_graph(simple)
|
graph.update_graph(simple)
|
||||||
|
|
||||||
assert next(graph.wait_finish(simple.graph['uid'], 10)) == {
|
assert next(graph.wait_finish(simple.graph['uid'], 10)) == {
|
||||||
'SKIPPED': 0, 'SUCCESS': 0, 'NOOP': 0, 'ERROR': 2, 'INPROGRESS': 0, 'PENDING': 0}
|
'SKIPPED': 0,
|
||||||
|
'SUCCESS': 0,
|
||||||
|
'NOOP': 0,
|
||||||
|
'ERROR': 2,
|
||||||
|
'INPROGRESS': 0,
|
||||||
|
'PENDING': 0
|
||||||
|
}
|
||||||
|
@ -14,14 +14,13 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import networkx as nx
|
||||||
from pytest import fixture
|
from pytest import fixture
|
||||||
from pytest import mark
|
from pytest import mark
|
||||||
import networkx as nx
|
|
||||||
|
|
||||||
from solar.orchestration import graph
|
|
||||||
from solar.orchestration import filters
|
from solar.orchestration import filters
|
||||||
|
from solar.orchestration import graph
|
||||||
from solar.orchestration.traversal import states
|
from solar.orchestration.traversal import states
|
||||||
from solar.utils import yaml_load
|
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
@ -44,8 +43,7 @@ def test_end_at(dg_ex1, end_nodes, visited):
|
|||||||
|
|
||||||
|
|
||||||
@mark.parametrize("start_nodes,visited", [
|
@mark.parametrize("start_nodes,visited", [
|
||||||
(['n3'], {'n3'}),
|
(['n3'], {'n3'}), (['n1'], {'n1', 'n2', 'n4'}),
|
||||||
(['n1'], {'n1', 'n2', 'n4'}),
|
|
||||||
(['n1', 'n3'], {'n1', 'n2', 'n3', 'n4', 'n5'})
|
(['n1', 'n3'], {'n1', 'n2', 'n3', 'n4', 'n5'})
|
||||||
])
|
])
|
||||||
def test_start_from(dg_ex1, start_nodes, visited):
|
def test_start_from(dg_ex1, start_nodes, visited):
|
||||||
@ -63,20 +61,21 @@ def dg_ex2():
|
|||||||
@fixture
|
@fixture
|
||||||
def riak_plan():
|
def riak_plan():
|
||||||
riak_path = os.path.join(
|
riak_path = os.path.join(
|
||||||
os.path.dirname(os.path.realpath(__file__)),
|
os.path.dirname(os.path.realpath(__file__)), 'orch_fixtures',
|
||||||
'orch_fixtures',
|
|
||||||
'riak.yaml')
|
'riak.yaml')
|
||||||
return graph.create_plan(riak_path, save=False)
|
return graph.create_plan(riak_path, save=False)
|
||||||
|
|
||||||
|
|
||||||
def test_riak_start_node1(riak_plan):
|
def test_riak_start_node1(riak_plan):
|
||||||
assert filters.start_from(riak_plan, ['node1.run']) == {
|
assert filters.start_from(riak_plan, ['node1.run']) == {
|
||||||
'node1.run', 'hosts_file1.run', 'riak_service1.run'}
|
'node1.run', 'hosts_file1.run', 'riak_service1.run'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_riak_end_hosts_file1(riak_plan):
|
def test_riak_end_hosts_file1(riak_plan):
|
||||||
assert filters.end_at(riak_plan, ['hosts_file1.run']) == {
|
assert filters.end_at(riak_plan, ['hosts_file1.run']) == {
|
||||||
'node1.run', 'hosts_file1.run'}
|
'node1.run', 'hosts_file1.run'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_start_at_two_nodes(riak_plan):
|
def test_start_at_two_nodes(riak_plan):
|
||||||
@ -87,8 +86,10 @@ def test_start_at_two_nodes(riak_plan):
|
|||||||
|
|
||||||
def test_initial_from_node1_traverse(riak_plan):
|
def test_initial_from_node1_traverse(riak_plan):
|
||||||
filters.filter(riak_plan, start=['node1.run'])
|
filters.filter(riak_plan, start=['node1.run'])
|
||||||
pending = {n for n in riak_plan if riak_plan.node[
|
pending = {n
|
||||||
n]['status'] == states.PENDING.name}
|
for n in riak_plan
|
||||||
|
if riak_plan.node[
|
||||||
|
n]['status'] == states.PENDING.name}
|
||||||
assert pending == {'hosts_file1.run', 'riak_service1.run', 'node1.run'}
|
assert pending == {'hosts_file1.run', 'riak_service1.run', 'node1.run'}
|
||||||
|
|
||||||
|
|
||||||
@ -97,18 +98,21 @@ def test_second_from_node2_with_node1_walked(riak_plan):
|
|||||||
for n in success:
|
for n in success:
|
||||||
riak_plan.node[n]['status'] = states.SUCCESS.name
|
riak_plan.node[n]['status'] = states.SUCCESS.name
|
||||||
filters.filter(riak_plan, start=['node2.run'])
|
filters.filter(riak_plan, start=['node2.run'])
|
||||||
pending = {n for n in riak_plan if riak_plan.node[
|
pending = {n
|
||||||
n]['status'] == states.PENDING.name}
|
for n in riak_plan
|
||||||
assert pending == {'hosts_file2.run', 'riak_service2.run',
|
if riak_plan.node[
|
||||||
'node2.run', 'riak_service2.join'}
|
n]['status'] == states.PENDING.name}
|
||||||
|
assert pending == {'hosts_file2.run', 'riak_service2.run', 'node2.run',
|
||||||
|
'riak_service2.join'}
|
||||||
|
|
||||||
|
|
||||||
def test_end_joins(riak_plan):
|
def test_end_joins(riak_plan):
|
||||||
filters.filter(
|
filters.filter(riak_plan,
|
||||||
riak_plan,
|
start=['node1.run', 'node2.run', 'node3.run'],
|
||||||
start=['node1.run', 'node2.run', 'node3.run'],
|
end=['riak_service2.join', 'riak_service3.join'])
|
||||||
end=['riak_service2.join', 'riak_service3.join'])
|
skipped = {n
|
||||||
skipped = {n for n in riak_plan if riak_plan.node[
|
for n in riak_plan
|
||||||
n]['status'] == states.SKIPPED.name}
|
if riak_plan.node[
|
||||||
|
n]['status'] == states.SKIPPED.name}
|
||||||
|
|
||||||
assert skipped == {'riak_service1.commit'}
|
assert skipped == {'riak_service1.commit'}
|
||||||
|
@ -14,40 +14,49 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from pytest import fixture
|
|
||||||
import networkx as nx
|
import networkx as nx
|
||||||
|
from pytest import fixture
|
||||||
|
|
||||||
from solar.orchestration import limits
|
|
||||||
from solar.orchestration import graph
|
from solar.orchestration import graph
|
||||||
|
from solar.orchestration import limits
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
def dg():
|
def dg():
|
||||||
ex = nx.DiGraph()
|
ex = nx.DiGraph()
|
||||||
ex.add_node('t1', status='PENDING', target='1',
|
ex.add_node('t1',
|
||||||
resource_type='node', type_limit=2)
|
status='PENDING',
|
||||||
ex.add_node('t2', status='PENDING', target='1',
|
target='1',
|
||||||
resource_type='node', type_limit=2)
|
resource_type='node',
|
||||||
ex.add_node('t3', status='PENDING', target='1',
|
type_limit=2)
|
||||||
resource_type='node', type_limit=2)
|
ex.add_node('t2',
|
||||||
|
status='PENDING',
|
||||||
|
target='1',
|
||||||
|
resource_type='node',
|
||||||
|
type_limit=2)
|
||||||
|
ex.add_node('t3',
|
||||||
|
status='PENDING',
|
||||||
|
target='1',
|
||||||
|
resource_type='node',
|
||||||
|
type_limit=2)
|
||||||
return ex
|
return ex
|
||||||
|
|
||||||
|
|
||||||
def test_target_rule(dg):
|
def test_target_rule(dg):
|
||||||
|
|
||||||
assert limits.target_based_rule(dg, [], 't1') == True
|
assert limits.target_based_rule(dg, [], 't1') is True
|
||||||
assert limits.target_based_rule(dg, ['t1'], 't2') == False
|
assert limits.target_based_rule(dg, ['t1'], 't2') is False
|
||||||
|
|
||||||
|
|
||||||
def test_type_limit_rule(dg):
|
def test_type_limit_rule(dg):
|
||||||
assert limits.type_based_rule(dg, ['t1'], 't2') == True
|
assert limits.type_based_rule(dg, ['t1'], 't2') is True
|
||||||
assert limits.type_based_rule(dg, ['t1', 't2'], 't3') == False
|
assert limits.type_based_rule(dg, ['t1', 't2'], 't3') is False
|
||||||
|
|
||||||
|
|
||||||
def test_items_rule(dg):
|
def test_items_rule(dg):
|
||||||
|
|
||||||
assert limits.items_rule(dg, ['1'] * 99, '2')
|
assert limits.items_rule(dg, ['1'] * 99, '2')
|
||||||
assert limits.items_rule(dg, ['1'] * 99, '2', limit=10) == False
|
assert limits.items_rule(dg, ['1'] * 99, '2', limit=10) is False
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
@ -68,8 +77,7 @@ def test_filtering_chain(target_dg):
|
|||||||
@fixture
|
@fixture
|
||||||
def seq_plan():
|
def seq_plan():
|
||||||
seq_path = os.path.join(
|
seq_path = os.path.join(
|
||||||
os.path.dirname(os.path.realpath(__file__)),
|
os.path.dirname(os.path.realpath(__file__)), 'orch_fixtures',
|
||||||
'orch_fixtures',
|
|
||||||
'sequential.yaml')
|
'sequential.yaml')
|
||||||
return graph.create_plan(seq_path, save=False)
|
return graph.create_plan(seq_path, save=False)
|
||||||
|
|
||||||
@ -78,6 +86,6 @@ def test_limits_sequential(seq_plan):
|
|||||||
stack_to_execute = seq_plan.nodes()
|
stack_to_execute = seq_plan.nodes()
|
||||||
while stack_to_execute:
|
while stack_to_execute:
|
||||||
left = stack_to_execute[0]
|
left = stack_to_execute[0]
|
||||||
assert list(limits.get_default_chain(
|
assert list(limits.get_default_chain(seq_plan, [],
|
||||||
seq_plan, [], stack_to_execute)) == [left]
|
stack_to_execute)) == [left]
|
||||||
stack_to_execute.pop(0)
|
stack_to_execute.pop(0)
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
from pytest import fixture
|
from pytest import fixture
|
||||||
|
|
||||||
from solar.core import resource
|
from solar.core import resource
|
||||||
from solar.dblayer.solar_models import Resource
|
|
||||||
from solar.dblayer.model import ModelMeta
|
from solar.dblayer.model import ModelMeta
|
||||||
|
from solar.dblayer.solar_models import Resource
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import base
|
import base
|
||||||
|
|
||||||
from solar.core import resource
|
from solar.core import resource
|
||||||
from solar.core import signals
|
from solar.core import signals
|
||||||
|
|
||||||
@ -31,9 +30,8 @@ input:
|
|||||||
value: 0
|
value: 0
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample1 = self.create_resource(
|
sample1 = self.create_resource('sample1', sample_meta_dir,
|
||||||
'sample1', sample_meta_dir, {'value': 1}
|
{'value': 1})
|
||||||
)
|
|
||||||
self.assertEqual(sample1.args['value'], 1)
|
self.assertEqual(sample1.args['value'], 1)
|
||||||
|
|
||||||
# test default value
|
# test default value
|
||||||
@ -41,7 +39,8 @@ input:
|
|||||||
self.assertEqual(sample2.args['value'], 0)
|
self.assertEqual(sample2.args['value'], 0)
|
||||||
|
|
||||||
def test_connections_recreated_after_load(self):
|
def test_connections_recreated_after_load(self):
|
||||||
"""
|
"""Test if connections are ok after load
|
||||||
|
|
||||||
Create resource in some process. Then in other process load it.
|
Create resource in some process. Then in other process load it.
|
||||||
All connections should remain the same.
|
All connections should remain the same.
|
||||||
"""
|
"""
|
||||||
@ -56,12 +55,9 @@ input:
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
def creating_process():
|
def creating_process():
|
||||||
sample1 = self.create_resource(
|
sample1 = self.create_resource('sample1', sample_meta_dir,
|
||||||
'sample1', sample_meta_dir, {'value': 1}
|
{'value': 1})
|
||||||
)
|
sample2 = self.create_resource('sample2', sample_meta_dir, )
|
||||||
sample2 = self.create_resource(
|
|
||||||
'sample2', sample_meta_dir,
|
|
||||||
)
|
|
||||||
signals.connect(sample1, sample2)
|
signals.connect(sample1, sample2)
|
||||||
self.assertEqual(sample1.args['value'], sample2.args['value'])
|
self.assertEqual(sample1.args['value'], sample2.args['value'])
|
||||||
|
|
||||||
@ -86,9 +82,7 @@ input:
|
|||||||
value: 0
|
value: 0
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample = self.create_resource(
|
sample = self.create_resource('sample', sample_meta_dir, {'value': 1})
|
||||||
'sample', sample_meta_dir, {'value': 1}
|
|
||||||
)
|
|
||||||
|
|
||||||
sample_l = resource.load('sample')
|
sample_l = resource.load('sample')
|
||||||
|
|
||||||
@ -107,12 +101,9 @@ input:
|
|||||||
value: 0
|
value: 0
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample1 = self.create_resource(
|
sample1 = self.create_resource('sample1', sample_meta_dir,
|
||||||
'sample1', sample_meta_dir, {'value': 1}
|
{'value': 1})
|
||||||
)
|
sample2 = self.create_resource('sample2', sample_meta_dir, {})
|
||||||
sample2 = self.create_resource(
|
|
||||||
'sample2', sample_meta_dir, {}
|
|
||||||
)
|
|
||||||
signals.connect(sample1, sample2)
|
signals.connect(sample1, sample2)
|
||||||
self.assertEqual(sample1.args['value'], sample2.args['value'])
|
self.assertEqual(sample1.args['value'], sample2.args['value'])
|
||||||
|
|
||||||
|
@ -12,12 +12,11 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import base
|
|
||||||
|
|
||||||
from solar.core import signals as xs
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
import base
|
||||||
|
from solar.core import signals as xs
|
||||||
|
|
||||||
|
|
||||||
class TestBaseInput(base.BaseResourceTest):
|
class TestBaseInput(base.BaseResourceTest):
|
||||||
|
|
||||||
@ -32,13 +31,11 @@ input:
|
|||||||
value:
|
value:
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample = self.create_resource(
|
sample = self.create_resource('sample', sample_meta_dir,
|
||||||
'sample', sample_meta_dir, {'value': 'x'}
|
{'value': 'x'})
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaisesRegexp(
|
with self.assertRaisesRegexp(Exception,
|
||||||
Exception,
|
'Trying to connect value-.* to itself'):
|
||||||
'Trying to connect value-.* to itself'):
|
|
||||||
xs.connect(sample, sample, {'value'})
|
xs.connect(sample, sample, {'value'})
|
||||||
|
|
||||||
def test_input_dict_type(self):
|
def test_input_dict_type(self):
|
||||||
@ -52,42 +49,23 @@ input:
|
|||||||
value: {}
|
value: {}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample1 = self.create_resource(
|
sample1 = self.create_resource('sample1', sample_meta_dir, {'values':
|
||||||
'sample1', sample_meta_dir, {'values': {'a': 1, 'b': 2}}
|
{'a': 1,
|
||||||
)
|
'b': 2}})
|
||||||
sample2 = self.create_resource(
|
sample2 = self.create_resource('sample2', sample_meta_dir)
|
||||||
'sample2', sample_meta_dir
|
|
||||||
)
|
|
||||||
xs.connect(sample1, sample2)
|
xs.connect(sample1, sample2)
|
||||||
self.assertEqual(
|
self.assertEqual(sample1.args['values'], sample2.args['values'])
|
||||||
sample1.args['values'],
|
|
||||||
sample2.args['values']
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check update
|
# Check update
|
||||||
sample1.update({'values': {'a': 2}})
|
sample1.update({'values': {'a': 2}})
|
||||||
self.assertEqual(
|
self.assertEqual(sample1.args['values'], {'a': 2})
|
||||||
sample1.args['values'],
|
self.assertEqual(sample1.args['values'], sample2.args['values'], )
|
||||||
{'a': 2}
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
sample1.args['values'],
|
|
||||||
sample2.args['values'],
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check disconnect
|
# Check disconnect
|
||||||
# TODO: should sample2.value be reverted to original value?
|
# TODO: should sample2.value be reverted to original value?
|
||||||
sample1.disconnect(sample2)
|
sample1.disconnect(sample2)
|
||||||
sample1.update({'values': {'a': 3}})
|
sample1.update({'values': {'a': 3}})
|
||||||
self.assertEqual(
|
self.assertEqual(sample1.args['values'], {'a': 3})
|
||||||
sample1.args['values'],
|
|
||||||
{'a': 3}
|
|
||||||
)
|
|
||||||
# self.assertEqual(
|
|
||||||
# sample2.args['values'],
|
|
||||||
# {'a': 2}
|
|
||||||
#)
|
|
||||||
#self.assertEqual(sample2.args['values'].emitter, None)
|
|
||||||
|
|
||||||
def test_multiple_resource_disjoint_connect(self):
|
def test_multiple_resource_disjoint_connect(self):
|
||||||
sample_meta_dir = self.make_resource_meta("""
|
sample_meta_dir = self.make_resource_meta("""
|
||||||
@ -121,31 +99,19 @@ input:
|
|||||||
value:
|
value:
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample = self.create_resource(
|
sample = self.create_resource('sample', sample_meta_dir,
|
||||||
'sample', sample_meta_dir, {'ip': None, 'port': None}
|
{'ip': None,
|
||||||
)
|
'port': None})
|
||||||
sample_ip = self.create_resource(
|
sample_ip = self.create_resource('sample-ip', sample_ip_meta_dir,
|
||||||
'sample-ip', sample_ip_meta_dir, {'ip': '10.0.0.1'}
|
{'ip': '10.0.0.1'})
|
||||||
)
|
sample_port = self.create_resource('sample-port', sample_port_meta_dir,
|
||||||
sample_port = self.create_resource(
|
{'port': 8000})
|
||||||
'sample-port', sample_port_meta_dir, {'port': 8000}
|
self.assertNotEqual(sample.resource_inputs()['ip'],
|
||||||
)
|
sample_ip.resource_inputs()['ip'], )
|
||||||
self.assertNotEqual(
|
|
||||||
sample.resource_inputs()['ip'],
|
|
||||||
sample_ip.resource_inputs()['ip'],
|
|
||||||
)
|
|
||||||
xs.connect(sample_ip, sample)
|
xs.connect(sample_ip, sample)
|
||||||
xs.connect(sample_port, sample)
|
xs.connect(sample_port, sample)
|
||||||
self.assertEqual(sample.args['ip'], sample_ip.args['ip'])
|
self.assertEqual(sample.args['ip'], sample_ip.args['ip'])
|
||||||
self.assertEqual(sample.args['port'], sample_port.args['port'])
|
self.assertEqual(sample.args['port'], sample_port.args['port'])
|
||||||
# self.assertEqual(
|
|
||||||
# sample.args['ip'].emitter,
|
|
||||||
# sample_ip.args['ip']
|
|
||||||
#)
|
|
||||||
# self.assertEqual(
|
|
||||||
# sample.args['port'].emitter,
|
|
||||||
# sample_port.args['port']
|
|
||||||
#)
|
|
||||||
|
|
||||||
def test_simple_observer_unsubscription(self):
|
def test_simple_observer_unsubscription(self):
|
||||||
sample_meta_dir = self.make_resource_meta("""
|
sample_meta_dir = self.make_resource_meta("""
|
||||||
@ -158,29 +124,18 @@ input:
|
|||||||
value:
|
value:
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample = self.create_resource(
|
sample = self.create_resource('sample', sample_meta_dir, {'ip': None})
|
||||||
'sample', sample_meta_dir, {'ip': None}
|
sample1 = self.create_resource('sample1', sample_meta_dir,
|
||||||
)
|
{'ip': '10.0.0.1'})
|
||||||
sample1 = self.create_resource(
|
sample2 = self.create_resource('sample2', sample_meta_dir,
|
||||||
'sample1', sample_meta_dir, {'ip': '10.0.0.1'}
|
{'ip': '10.0.0.2'})
|
||||||
)
|
|
||||||
sample2 = self.create_resource(
|
|
||||||
'sample2', sample_meta_dir, {'ip': '10.0.0.2'}
|
|
||||||
)
|
|
||||||
|
|
||||||
xs.connect(sample1, sample)
|
xs.connect(sample1, sample)
|
||||||
self.assertEqual(sample1.args['ip'], sample.args['ip'])
|
self.assertEqual(sample1.args['ip'], sample.args['ip'])
|
||||||
#self.assertEqual(len(list(sample1.args['ip'].receivers)), 1)
|
|
||||||
# self.assertEqual(
|
|
||||||
# sample.args['ip'].emitter,
|
|
||||||
# sample1.args['ip']
|
|
||||||
#)
|
|
||||||
|
|
||||||
xs.connect(sample2, sample)
|
xs.connect(sample2, sample)
|
||||||
self.assertEqual(sample2.args['ip'], sample.args['ip'])
|
self.assertEqual(sample2.args['ip'], sample.args['ip'])
|
||||||
# sample should be unsubscribed from sample1 and subscribed to sample2
|
# sample should be unsubscribed from sample1 and subscribed to sample2
|
||||||
#self.assertEqual(len(list(sample1.args['ip'].receivers)), 0)
|
|
||||||
#self.assertEqual(sample.args['ip'].emitter, sample2.args['ip'])
|
|
||||||
|
|
||||||
sample2.update({'ip': '10.0.0.3'})
|
sample2.update({'ip': '10.0.0.3'})
|
||||||
self.assertEqual(sample2.args['ip'], sample.args['ip'])
|
self.assertEqual(sample2.args['ip'], sample.args['ip'])
|
||||||
@ -198,15 +153,13 @@ input:
|
|||||||
value:
|
value:
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample1 = self.create_resource(
|
sample1 = self.create_resource('sample1', sample_meta_dir,
|
||||||
'sample1', sample_meta_dir, {'ip': '10.0.0.1'}
|
{'ip': '10.0.0.1'})
|
||||||
)
|
sample2 = self.create_resource('sample2', sample_meta_dir,
|
||||||
sample2 = self.create_resource(
|
{'ip': '10.0.0.2'})
|
||||||
'sample2', sample_meta_dir, {'ip': '10.0.0.2'}
|
|
||||||
)
|
|
||||||
xs.connect(sample1, sample2)
|
xs.connect(sample1, sample2)
|
||||||
|
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception): # NOQA
|
||||||
xs.connect(sample2, sample1)
|
xs.connect(sample2, sample1)
|
||||||
|
|
||||||
|
|
||||||
@ -232,68 +185,36 @@ input:
|
|||||||
value: []
|
value: []
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample1 = self.create_resource(
|
sample1 = self.create_resource('sample1', sample_meta_dir,
|
||||||
'sample1', sample_meta_dir, {'ip': '10.0.0.1'}
|
{'ip': '10.0.0.1'})
|
||||||
)
|
sample2 = self.create_resource('sample2', sample_meta_dir,
|
||||||
sample2 = self.create_resource(
|
{'ip': '10.0.0.2'})
|
||||||
'sample2', sample_meta_dir, {'ip': '10.0.0.2'}
|
|
||||||
)
|
|
||||||
list_input_single = self.create_resource(
|
list_input_single = self.create_resource(
|
||||||
'list-input-single', list_input_single_meta_dir, {'ips': []}
|
'list-input-single', list_input_single_meta_dir, {'ips': []})
|
||||||
)
|
|
||||||
|
|
||||||
sample1.connect(list_input_single, mapping={'ip': 'ips'})
|
sample1.connect(list_input_single, mapping={'ip': 'ips'})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(list_input_single.args['ips'], [
|
||||||
#[ip['value'] for ip in list_input_single.args['ips']],
|
sample1.args['ip'],
|
||||||
list_input_single.args['ips'],
|
])
|
||||||
[
|
|
||||||
sample1.args['ip'],
|
|
||||||
]
|
|
||||||
)
|
|
||||||
# self.assertListEqual(
|
|
||||||
# [(e['emitter_attached_to'], e['emitter']) for e in list_input_single.args['ips']],
|
|
||||||
# [(sample1.args['ip'].attached_to.name, 'ip')]
|
|
||||||
#)
|
|
||||||
|
|
||||||
sample2.connect(list_input_single, mapping={'ip': 'ips'})
|
sample2.connect(list_input_single, mapping={'ip': 'ips'})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(list_input_single.args['ips'], [
|
||||||
#[ip['value'] for ip in list_input_single.args['ips']],
|
sample1.args['ip'],
|
||||||
list_input_single.args['ips'],
|
sample2.args['ip'],
|
||||||
[
|
])
|
||||||
sample1.args['ip'],
|
|
||||||
sample2.args['ip'],
|
|
||||||
]
|
|
||||||
)
|
|
||||||
# self.assertListEqual(
|
|
||||||
# [(e['emitter_attached_to'], e['emitter']) for e in list_input_single.args['ips']],
|
|
||||||
# [(sample1.args['ip'].attached_to.name, 'ip'),
|
|
||||||
# (sample2.args['ip'].attached_to.name, 'ip')]
|
|
||||||
#)
|
|
||||||
|
|
||||||
# Test update
|
# Test update
|
||||||
sample2.update({'ip': '10.0.0.3'})
|
sample2.update({'ip': '10.0.0.3'})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(list_input_single.args['ips'], [
|
||||||
#[ip['value'] for ip in list_input_single.args['ips']],
|
sample1.args['ip'],
|
||||||
list_input_single.args['ips'],
|
sample2.args['ip'],
|
||||||
[
|
])
|
||||||
sample1.args['ip'],
|
|
||||||
sample2.args['ip'],
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test disconnect
|
# Test disconnect
|
||||||
sample2.disconnect(list_input_single)
|
sample2.disconnect(list_input_single)
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(list_input_single.args['ips'], [
|
||||||
#[ip['value'] for ip in list_input_single.args['ips']],
|
sample1.args['ip'],
|
||||||
list_input_single.args['ips'],
|
])
|
||||||
[
|
|
||||||
sample1.args['ip'],
|
|
||||||
]
|
|
||||||
)
|
|
||||||
# self.assertListEqual(
|
|
||||||
# [(e['emitter_attached_to'], e['emitter']) for e in list_input_single.args['ips']],
|
|
||||||
# [(sample1.args['ip'].attached_to.name, 'ip')]
|
|
||||||
#)
|
|
||||||
|
|
||||||
def test_list_input_multi(self):
|
def test_list_input_multi(self):
|
||||||
sample_meta_dir = self.make_resource_meta("""
|
sample_meta_dir = self.make_resource_meta("""
|
||||||
@ -321,70 +242,58 @@ input:
|
|||||||
value:
|
value:
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample1 = self.create_resource(
|
sample1 = self.create_resource('sample1', sample_meta_dir,
|
||||||
'sample1', sample_meta_dir, {'ip': '10.0.0.1', 'port': 1000}
|
{'ip': '10.0.0.1',
|
||||||
)
|
'port': 1000})
|
||||||
sample2 = self.create_resource(
|
sample2 = self.create_resource('sample2', sample_meta_dir,
|
||||||
'sample2', sample_meta_dir, {'ip': '10.0.0.2', 'port': 1001}
|
{'ip': '10.0.0.2',
|
||||||
)
|
'port': 1001})
|
||||||
list_input_multi = self.create_resource(
|
list_input_multi = self.create_resource('list-input-multi',
|
||||||
'list-input-multi', list_input_multi_meta_dir, args={'ips': [], 'ports': []}
|
list_input_multi_meta_dir,
|
||||||
)
|
args={'ips': [],
|
||||||
|
'ports': []})
|
||||||
|
|
||||||
xs.connect(sample1, list_input_multi, mapping={
|
xs.connect(sample1,
|
||||||
'ip': 'ips', 'port': 'ports'})
|
list_input_multi,
|
||||||
|
mapping={
|
||||||
|
'ip': 'ips',
|
||||||
|
'port': 'ports'
|
||||||
|
})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
#[ip['value'] for ip in list_input_multi.args['ips']],
|
|
||||||
list_input_multi.args['ips'],
|
list_input_multi.args['ips'],
|
||||||
[sample1.args['ip']]
|
[sample1.args['ip']])
|
||||||
)
|
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
#[p['value'] for p in list_input_multi.args['ports']],
|
|
||||||
list_input_multi.args['ports'],
|
list_input_multi.args['ports'],
|
||||||
[sample1.args['port']]
|
[sample1.args['port']])
|
||||||
)
|
|
||||||
|
|
||||||
xs.connect(sample2, list_input_multi, mapping={
|
xs.connect(sample2,
|
||||||
'ip': 'ips', 'port': 'ports'})
|
list_input_multi,
|
||||||
|
mapping={
|
||||||
|
'ip': 'ips',
|
||||||
|
'port': 'ports'
|
||||||
|
})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
#[ip['value'] for ip in list_input_multi.args['ips']],
|
|
||||||
list_input_multi.args['ips'],
|
list_input_multi.args['ips'],
|
||||||
[
|
[
|
||||||
sample1.args['ip'],
|
sample1.args['ip'],
|
||||||
sample2.args['ip'],
|
sample2.args['ip'],
|
||||||
]
|
])
|
||||||
)
|
|
||||||
# self.assertListEqual(
|
|
||||||
# [(e['emitter_attached_to'], e['emitter']) for e in list_input_multi.args['ips']],
|
|
||||||
# [(sample1.args['ip'].attached_to.name, 'ip'),
|
|
||||||
# (sample2.args['ip'].attached_to.name, 'ip')]
|
|
||||||
#)
|
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
#[p['value'] for p in list_input_multi.args['ports']],
|
|
||||||
list_input_multi.args['ports'],
|
list_input_multi.args['ports'],
|
||||||
[
|
[
|
||||||
sample1.args['port'],
|
sample1.args['port'],
|
||||||
sample2.args['port'],
|
sample2.args['port'],
|
||||||
]
|
])
|
||||||
)
|
|
||||||
# self.assertListEqual(
|
|
||||||
# [(e['emitter_attached_to'], e['emitter']) for e in list_input_multi.args['ports']],
|
|
||||||
# [(sample1.args['port'].attached_to.name, 'port'),
|
|
||||||
# (sample2.args['port'].attached_to.name, 'port')]
|
|
||||||
#)
|
|
||||||
|
|
||||||
# Test disconnect
|
# Test disconnect
|
||||||
sample2.disconnect(list_input_multi)
|
sample2.disconnect(list_input_multi)
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
#[ip['value'] for ip in list_input_multi.args['ips']],
|
|
||||||
list_input_multi.args['ips'],
|
list_input_multi.args['ips'],
|
||||||
[sample1.args['ip']]
|
[sample1.args['ip']])
|
||||||
)
|
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
#[p['value'] for p in list_input_multi.args['ports']],
|
|
||||||
list_input_multi.args['ports'],
|
list_input_multi.args['ports'],
|
||||||
[sample1.args['port']]
|
[sample1.args['port']])
|
||||||
)
|
|
||||||
|
|
||||||
# XXX: not used for now, not implemented in new db (jnowak)
|
# XXX: not used for now, not implemented in new db (jnowak)
|
||||||
# @pytest.mark.xfail(reason="Nested lists are not supported in new_db")
|
# @pytest.mark.xfail(reason="Nested lists are not supported in new_db")
|
||||||
@ -446,14 +355,13 @@ input:
|
|||||||
|
|
||||||
# sample1.connect(list_input, mapping={'ip': 'ips', 'port': 'ports'})
|
# sample1.connect(list_input, mapping={'ip': 'ips', 'port': 'ports'})
|
||||||
# sample2.connect(list_input, mapping={'ip': 'ips', 'port': 'ports'})
|
# sample2.connect(list_input, mapping={'ip': 'ips', 'port': 'ports'})
|
||||||
# list_input.connect(list_input_nested, mapping={'ips': 'ipss', 'ports': 'portss'})
|
# list_input.connect(list_input_nested,
|
||||||
|
# mapping={'ips': 'ipss', 'ports': 'portss'})
|
||||||
# self.assertListEqual(
|
# self.assertListEqual(
|
||||||
# #[ips['value'] for ips in list_input_nested.args['ipss']],
|
|
||||||
# list_input_nested.args['ipss'],
|
# list_input_nested.args['ipss'],
|
||||||
# [list_input.args['ips']]
|
# [list_input.args['ips']]
|
||||||
# )
|
# )
|
||||||
# self.assertListEqual(
|
# self.assertListEqual(
|
||||||
# #[ps['value'] for ps in list_input_nested.args['portss']],
|
|
||||||
# list_input_nested.args['portss'],
|
# list_input_nested.args['portss'],
|
||||||
# [list_input.args['ports']]
|
# [list_input.args['ports']]
|
||||||
# )
|
# )
|
||||||
@ -461,7 +369,6 @@ input:
|
|||||||
# # Test disconnect
|
# # Test disconnect
|
||||||
# xs.disconnect(sample1, list_input)
|
# xs.disconnect(sample1, list_input)
|
||||||
# self.assertListEqual(
|
# self.assertListEqual(
|
||||||
# #[[ip['value'] for ip in ips['value']] for ips in list_input_nested.args['ipss']],
|
|
||||||
# list_input_nested.args['ipss'],
|
# list_input_nested.args['ipss'],
|
||||||
# [[sample2.args['ip']]]
|
# [[sample2.args['ip']]]
|
||||||
# )
|
# )
|
||||||
@ -472,8 +379,8 @@ input:
|
|||||||
|
|
||||||
|
|
||||||
class TestHashInput(base.BaseResourceTest):
|
class TestHashInput(base.BaseResourceTest):
|
||||||
|
@pytest.mark.xfail(
|
||||||
@pytest.mark.xfail(reason="Connect should raise an error if already connected")
|
reason="Connect should raise an error if already connected")
|
||||||
def test_hash_input_basic(self):
|
def test_hash_input_basic(self):
|
||||||
sample_meta_dir = self.make_resource_meta("""
|
sample_meta_dir = self.make_resource_meta("""
|
||||||
id: sample
|
id: sample
|
||||||
@ -496,42 +403,51 @@ input:
|
|||||||
schema: {ip: str!, port: int!}
|
schema: {ip: str!, port: int!}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample1 = self.create_resource(
|
sample1 = self.create_resource('sample1',
|
||||||
'sample1', sample_meta_dir, args={'ip': '10.0.0.1', 'port': 5000}
|
sample_meta_dir,
|
||||||
)
|
args={'ip': '10.0.0.1',
|
||||||
sample2 = self.create_resource(
|
'port': 5000})
|
||||||
'sample2', sample_meta_dir, args={'ip': '10.0.0.2', 'port': 5001}
|
sample2 = self.create_resource('sample2',
|
||||||
)
|
sample_meta_dir,
|
||||||
sample3 = self.create_resource(
|
args={'ip': '10.0.0.2',
|
||||||
'sample3', sample_meta_dir, args={'ip': '10.0.0.3', 'port': 5002}
|
'port': 5001})
|
||||||
)
|
sample3 = self.create_resource('sample3',
|
||||||
receiver = self.create_resource(
|
sample_meta_dir,
|
||||||
'receiver', receiver_meta_dir
|
args={'ip': '10.0.0.3',
|
||||||
)
|
'port': 5002})
|
||||||
xs.connect(sample1, receiver, mapping={
|
receiver = self.create_resource('receiver', receiver_meta_dir)
|
||||||
'ip': 'server:ip', 'port': 'server:port'})
|
xs.connect(sample1,
|
||||||
|
receiver,
|
||||||
|
mapping={
|
||||||
|
'ip': 'server:ip',
|
||||||
|
'port': 'server:port'
|
||||||
|
})
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
{'ip': sample1.args['ip'], 'port': sample1.args['port']},
|
{'ip': sample1.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample1.args['port']},
|
||||||
)
|
receiver.args['server'], )
|
||||||
sample1.update({'ip': '10.0.0.2'})
|
sample1.update({'ip': '10.0.0.2'})
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
{'ip': sample1.args['ip'], 'port': sample1.args['port']},
|
{'ip': sample1.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample1.args['port']},
|
||||||
)
|
receiver.args['server'], )
|
||||||
# XXX: We need to disconnect first
|
# XXX: We need to disconnect first
|
||||||
# XXX: it should raise error when connecting already connected inputs
|
# XXX: it should raise error when connecting already connected inputs
|
||||||
xs.connect(sample2, receiver, mapping={'ip': 'server:ip'})
|
xs.connect(sample2, receiver, mapping={'ip': 'server:ip'})
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
{'ip': sample2.args['ip'], 'port': sample1.args['port']},
|
{'ip': sample2.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample1.args['port']},
|
||||||
)
|
receiver.args['server'], )
|
||||||
xs.connect(sample3, receiver, mapping={
|
xs.connect(sample3,
|
||||||
'ip': 'server:ip', 'port': 'server:port'})
|
receiver,
|
||||||
|
mapping={
|
||||||
|
'ip': 'server:ip',
|
||||||
|
'port': 'server:port'
|
||||||
|
})
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
{'ip': sample3.args['ip'], 'port': sample3.args['port']},
|
{'ip': sample3.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample3.args['port']},
|
||||||
)
|
receiver.args['server'], )
|
||||||
|
|
||||||
def test_hash_input_mixed(self):
|
def test_hash_input_mixed(self):
|
||||||
sample_meta_dir = self.make_resource_meta("""
|
sample_meta_dir = self.make_resource_meta("""
|
||||||
@ -555,22 +471,23 @@ input:
|
|||||||
schema: {ip: str!, port: int!}
|
schema: {ip: str!, port: int!}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample = self.create_resource(
|
sample = self.create_resource('sample',
|
||||||
'sample', sample_meta_dir, args={'ip': '10.0.0.1', 'port': 5000}
|
sample_meta_dir,
|
||||||
)
|
args={'ip': '10.0.0.1',
|
||||||
receiver = self.create_resource(
|
'port': 5000})
|
||||||
'receiver', receiver_meta_dir, args={'server': {'port': 5001}}
|
receiver = self.create_resource('receiver',
|
||||||
)
|
receiver_meta_dir,
|
||||||
|
args={'server': {'port': 5001}})
|
||||||
sample.connect(receiver, mapping={'ip': 'server:ip'})
|
sample.connect(receiver, mapping={'ip': 'server:ip'})
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
{'ip': sample.args['ip'], 'port': 5001},
|
{'ip': sample.args['ip'],
|
||||||
receiver.args['server'],
|
'port': 5001},
|
||||||
)
|
receiver.args['server'], )
|
||||||
sample.update({'ip': '10.0.0.2'})
|
sample.update({'ip': '10.0.0.2'})
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
{'ip': sample.args['ip'], 'port': 5001},
|
{'ip': sample.args['ip'],
|
||||||
receiver.args['server'],
|
'port': 5001},
|
||||||
)
|
receiver.args['server'], )
|
||||||
|
|
||||||
def test_hash_input_with_list(self):
|
def test_hash_input_with_list(self):
|
||||||
sample_meta_dir = self.make_resource_meta("""
|
sample_meta_dir = self.make_resource_meta("""
|
||||||
@ -594,33 +511,41 @@ input:
|
|||||||
schema: [{ip: str!, port: int!}]
|
schema: [{ip: str!, port: int!}]
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample1 = self.create_resource(
|
sample1 = self.create_resource('sample1',
|
||||||
'sample1', sample_meta_dir, args={'ip': '10.0.0.1', 'port': 5000}
|
sample_meta_dir,
|
||||||
)
|
args={'ip': '10.0.0.1',
|
||||||
receiver = self.create_resource(
|
'port': 5000})
|
||||||
'receiver', receiver_meta_dir
|
receiver = self.create_resource('receiver', receiver_meta_dir)
|
||||||
)
|
xs.connect(sample1,
|
||||||
xs.connect(sample1, receiver, mapping={
|
receiver,
|
||||||
'ip': 'server:ip', 'port': 'server:port'})
|
mapping={
|
||||||
|
'ip': 'server:ip',
|
||||||
|
'port': 'server:port'
|
||||||
|
})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
[{'ip': sample1.args['ip'], 'port': sample1.args['port']}],
|
[{'ip': sample1.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample1.args['port']}],
|
||||||
)
|
receiver.args['server'], )
|
||||||
sample2 = self.create_resource(
|
sample2 = self.create_resource('sample2',
|
||||||
'sample2', sample_meta_dir, args={'ip': '10.0.0.2', 'port': 5001}
|
sample_meta_dir,
|
||||||
)
|
args={'ip': '10.0.0.2',
|
||||||
xs.connect(sample2, receiver, mapping={
|
'port': 5001})
|
||||||
'ip': 'server:ip', 'port': 'server:port'})
|
xs.connect(sample2,
|
||||||
|
receiver,
|
||||||
|
mapping={
|
||||||
|
'ip': 'server:ip',
|
||||||
|
'port': 'server:port'
|
||||||
|
})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
[{'ip': sample1.args['ip'], 'port': sample1.args['port']},
|
[{'ip': sample1.args['ip'],
|
||||||
{'ip': sample2.args['ip'], 'port': sample2.args['port']}],
|
'port': sample1.args['port']}, {'ip': sample2.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample2.args['port']}],
|
||||||
)
|
receiver.args['server'], )
|
||||||
sample1.disconnect(receiver)
|
sample1.disconnect(receiver)
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
[{'ip': sample2.args['ip'], 'port': sample2.args['port']}],
|
[{'ip': sample2.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample2.args['port']}],
|
||||||
)
|
receiver.args['server'], )
|
||||||
|
|
||||||
def test_hash_input_with_multiple_connections(self):
|
def test_hash_input_with_multiple_connections(self):
|
||||||
sample_meta_dir = self.make_resource_meta("""
|
sample_meta_dir = self.make_resource_meta("""
|
||||||
@ -644,21 +569,14 @@ input:
|
|||||||
schema: {ip: str!}
|
schema: {ip: str!}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample = self.create_resource(
|
sample = self.create_resource('sample',
|
||||||
'sample', sample_meta_dir, args={'ip': '10.0.0.1'}
|
sample_meta_dir,
|
||||||
)
|
args={'ip': '10.0.0.1'})
|
||||||
receiver = self.create_resource(
|
receiver = self.create_resource('receiver', receiver_meta_dir)
|
||||||
'receiver', receiver_meta_dir
|
|
||||||
)
|
|
||||||
xs.connect(sample, receiver, mapping={'ip': ['ip', 'server:ip']})
|
xs.connect(sample, receiver, mapping={'ip': ['ip', 'server:ip']})
|
||||||
self.assertEqual(
|
self.assertEqual(sample.args['ip'], receiver.args['ip'])
|
||||||
sample.args['ip'],
|
self.assertDictEqual({'ip': sample.args['ip']},
|
||||||
receiver.args['ip']
|
receiver.args['server'], )
|
||||||
)
|
|
||||||
self.assertDictEqual(
|
|
||||||
{'ip': sample.args['ip']},
|
|
||||||
receiver.args['server'],
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_hash_input_multiple_resources_with_tag_connect(self):
|
def test_hash_input_multiple_resources_with_tag_connect(self):
|
||||||
sample_meta_dir = self.make_resource_meta("""
|
sample_meta_dir = self.make_resource_meta("""
|
||||||
@ -682,44 +600,49 @@ input:
|
|||||||
schema: [{ip: str!, port: int!}]
|
schema: [{ip: str!, port: int!}]
|
||||||
""")
|
""")
|
||||||
|
|
||||||
sample1 = self.create_resource(
|
sample1 = self.create_resource('sample1',
|
||||||
'sample1', sample_meta_dir, args={'ip': '10.0.0.1', 'port': 5000}
|
sample_meta_dir,
|
||||||
)
|
args={'ip': '10.0.0.1',
|
||||||
sample2 = self.create_resource(
|
'port': 5000})
|
||||||
'sample2', sample_meta_dir, args={'ip': '10.0.0.2', 'port': 5001}
|
sample2 = self.create_resource('sample2',
|
||||||
)
|
sample_meta_dir,
|
||||||
receiver = self.create_resource(
|
args={'ip': '10.0.0.2',
|
||||||
'receiver', receiver_meta_dir
|
'port': 5001})
|
||||||
)
|
receiver = self.create_resource('receiver', receiver_meta_dir)
|
||||||
sample1.connect(receiver, mapping={'ip': 'server:ip'})
|
sample1.connect(receiver, mapping={'ip': 'server:ip'})
|
||||||
sample2.connect(receiver, mapping={'port': 'server:port|sample1'})
|
sample2.connect(receiver, mapping={'port': 'server:port|sample1'})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
[{'ip': sample1.args['ip'], 'port': sample2.args['port']}],
|
[{'ip': sample1.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample2.args['port']}],
|
||||||
)
|
receiver.args['server'], )
|
||||||
sample3 = self.create_resource(
|
sample3 = self.create_resource('sample3',
|
||||||
'sample3', sample_meta_dir, args={'ip': '10.0.0.3', 'port': 5002}
|
sample_meta_dir,
|
||||||
)
|
args={'ip': '10.0.0.3',
|
||||||
sample3.connect(receiver, mapping={
|
'port': 5002})
|
||||||
'ip': 'server:ip', 'port': 'server:port'})
|
sample3.connect(receiver,
|
||||||
|
mapping={
|
||||||
|
'ip': 'server:ip',
|
||||||
|
'port': 'server:port'
|
||||||
|
})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
[{'ip': sample1.args['ip'], 'port': sample2.args['port']},
|
[{'ip': sample1.args['ip'],
|
||||||
{'ip': sample3.args['ip'], 'port': sample3.args['port']}],
|
'port': sample2.args['port']}, {'ip': sample3.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample3.args['port']}],
|
||||||
)
|
receiver.args['server'], )
|
||||||
sample4 = self.create_resource(
|
sample4 = self.create_resource('sample4',
|
||||||
'sample4', sample_meta_dir, args={'ip': '10.0.0.4', 'port': 5003}
|
sample_meta_dir,
|
||||||
)
|
args={'ip': '10.0.0.4',
|
||||||
|
'port': 5003})
|
||||||
sample4.connect(receiver, mapping={'port': 'server:port|sample3'})
|
sample4.connect(receiver, mapping={'port': 'server:port|sample3'})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
[{'ip': sample1.args['ip'], 'port': sample2.args['port']},
|
[{'ip': sample1.args['ip'],
|
||||||
{'ip': sample3.args['ip'], 'port': sample4.args['port']}],
|
'port': sample2.args['port']}, {'ip': sample3.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample4.args['port']}],
|
||||||
)
|
receiver.args['server'], )
|
||||||
# There can be no sample3 connections left now
|
# There can be no sample3 connections left now
|
||||||
sample4.connect(receiver, mapping={'ip': 'server:ip|sample3'})
|
sample4.connect(receiver, mapping={'ip': 'server:ip|sample3'})
|
||||||
self.assertItemsEqual(
|
self.assertItemsEqual(
|
||||||
[{'ip': sample1.args['ip'], 'port': sample2.args['port']},
|
[{'ip': sample1.args['ip'],
|
||||||
{'ip': sample4.args['ip'], 'port': sample4.args['port']}],
|
'port': sample2.args['port']}, {'ip': sample4.args['ip'],
|
||||||
receiver.args['server'],
|
'port': sample4.args['port']}],
|
||||||
)
|
receiver.args['server'], )
|
||||||
|
@ -13,25 +13,27 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
from pytest import fixture
|
|
||||||
from pytest import mark
|
from pytest import mark
|
||||||
|
|
||||||
|
from solar.core.resource import resource
|
||||||
|
from solar.core.resource import RESOURCE_STATE
|
||||||
|
from solar.core import signals
|
||||||
|
from solar.dblayer.model import ModelMeta
|
||||||
|
from solar.dblayer.solar_models import CommitedResource
|
||||||
|
from solar.dblayer.solar_models import Resource as DBResource
|
||||||
from solar.system_log import change
|
from solar.system_log import change
|
||||||
from solar.system_log import data
|
from solar.system_log import data
|
||||||
from solar.system_log import operations
|
from solar.system_log import operations
|
||||||
from solar.core import signals
|
|
||||||
from solar.core.resource import resource, RESOURCE_STATE
|
|
||||||
from solar.dblayer.solar_models import Resource as DBResource
|
|
||||||
from solar.dblayer.solar_models import CommitedResource
|
|
||||||
from solar.dblayer.model import ModelMeta
|
|
||||||
|
|
||||||
|
|
||||||
def test_revert_update():
|
def test_revert_update():
|
||||||
commit = {'a': '10'}
|
commit = {'a': '10'}
|
||||||
previous = {'a': '9'}
|
previous = {'a': '9'}
|
||||||
res = DBResource.from_dict('test1',
|
res = DBResource.from_dict('test1',
|
||||||
{'name': 'test1', 'base_path': 'x',
|
{'name': 'test1',
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'base_path': 'x',
|
||||||
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res.save()
|
res.save()
|
||||||
action = 'update'
|
action = 'update'
|
||||||
res.inputs['a'] = '9'
|
res.inputs['a'] = '9'
|
||||||
@ -40,9 +42,11 @@ def test_revert_update():
|
|||||||
assert resource_obj.args == previous
|
assert resource_obj.args == previous
|
||||||
|
|
||||||
log = data.SL()
|
log = data.SL()
|
||||||
logitem = change.create_logitem(
|
logitem = change.create_logitem(res.name,
|
||||||
res.name, action, change.create_diff(commit, previous), [],
|
action,
|
||||||
base_path=res.base_path)
|
change.create_diff(commit, previous),
|
||||||
|
[],
|
||||||
|
base_path=res.base_path)
|
||||||
log.append(logitem)
|
log.append(logitem)
|
||||||
resource_obj.update(commit)
|
resource_obj.update(commit)
|
||||||
operations.move_to_commited(logitem.log_action)
|
operations.move_to_commited(logitem.log_action)
|
||||||
@ -56,23 +60,29 @@ def test_revert_update():
|
|||||||
|
|
||||||
def test_revert_update_connected():
|
def test_revert_update_connected():
|
||||||
res1 = DBResource.from_dict('test1',
|
res1 = DBResource.from_dict('test1',
|
||||||
{'name': 'test1', 'base_path': 'x',
|
{'name': 'test1',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res1.inputs['a'] = '9'
|
res1.inputs['a'] = '9'
|
||||||
res1.save_lazy()
|
res1.save_lazy()
|
||||||
|
|
||||||
res2 = DBResource.from_dict('test2',
|
res2 = DBResource.from_dict('test2',
|
||||||
{'name': 'test2', 'base_path': 'x',
|
{'name': 'test2',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res2.inputs['a'] = ''
|
res2.inputs['a'] = ''
|
||||||
res2.save_lazy()
|
res2.save_lazy()
|
||||||
|
|
||||||
res3 = DBResource.from_dict('test3',
|
res3 = DBResource.from_dict('test3',
|
||||||
{'name': 'test3', 'base_path': 'x',
|
{'name': 'test3',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res3.inputs['a'] = ''
|
res3.inputs['a'] = ''
|
||||||
res3.save_lazy()
|
res3.save_lazy()
|
||||||
|
|
||||||
@ -113,15 +123,16 @@ def test_revert_update_connected():
|
|||||||
|
|
||||||
def test_revert_removal():
|
def test_revert_removal():
|
||||||
res = DBResource.from_dict('test1',
|
res = DBResource.from_dict('test1',
|
||||||
{'name': 'test1', 'base_path': 'x',
|
{'name': 'test1',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res.inputs['a'] = '9'
|
res.inputs['a'] = '9'
|
||||||
res.save_lazy()
|
res.save_lazy()
|
||||||
|
|
||||||
commited = CommitedResource.from_dict('test1',
|
commited = CommitedResource.from_dict('test1', {'inputs': {'a': '9'},
|
||||||
{'inputs': {'a': '9'},
|
'state': 'operational'})
|
||||||
'state': 'operational'})
|
|
||||||
commited.save_lazy()
|
commited.save_lazy()
|
||||||
|
|
||||||
resource_obj = resource.load(res.name)
|
resource_obj = resource.load(res.name)
|
||||||
@ -139,23 +150,31 @@ def test_revert_removal():
|
|||||||
|
|
||||||
with mock.patch.object(resource, 'read_meta') as mread:
|
with mock.patch.object(resource, 'read_meta') as mread:
|
||||||
mread.return_value = {
|
mread.return_value = {
|
||||||
'input': {'a': {'schema': 'str!'}}, 'id': 'mocked'}
|
'input': {'a': {'schema': 'str!'}},
|
||||||
|
'id': 'mocked'
|
||||||
|
}
|
||||||
change.revert(changes[0].uid)
|
change.revert(changes[0].uid)
|
||||||
ModelMeta.save_all_lazy()
|
ModelMeta.save_all_lazy()
|
||||||
assert len(DBResource.bucket.get('test1').siblings) == 1
|
assert len(DBResource.bucket.get('test1').siblings) == 1
|
||||||
|
|
||||||
resource_obj = resource.load('test1')
|
resource_obj = resource.load('test1')
|
||||||
assert resource_obj.args == {
|
assert resource_obj.args == {
|
||||||
'a': '9', 'location_id': '', 'transports_id': ''}
|
'a': '9',
|
||||||
|
'location_id': '',
|
||||||
|
'transports_id': ''
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@mark.xfail(reason='With current approach child will be notice changes after parent is removed')
|
@mark.xfail(
|
||||||
|
reason="""With current approach child will
|
||||||
|
notice changes after parent is removed"""
|
||||||
|
)
|
||||||
def test_revert_removed_child():
|
def test_revert_removed_child():
|
||||||
res1 = orm.DBResource(id='test1', name='test1', base_path='x')
|
res1 = orm.DBResource(id='test1', name='test1', base_path='x') # NOQA
|
||||||
res1.save()
|
res1.save()
|
||||||
res1.add_input('a', 'str', '9')
|
res1.add_input('a', 'str', '9')
|
||||||
|
|
||||||
res2 = orm.DBResource(id='test2', name='test2', base_path='x')
|
res2 = orm.DBResource(id='test2', name='test2', base_path='x') # NOQA
|
||||||
res2.save()
|
res2.save()
|
||||||
res2.add_input('a', 'str', 0)
|
res2.add_input('a', 'str', 0)
|
||||||
|
|
||||||
@ -184,9 +203,11 @@ def test_revert_removed_child():
|
|||||||
|
|
||||||
def test_revert_create():
|
def test_revert_create():
|
||||||
res = DBResource.from_dict('test1',
|
res = DBResource.from_dict('test1',
|
||||||
{'name': 'test1', 'base_path': 'x',
|
{'name': 'test1',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res.inputs['a'] = '9'
|
res.inputs['a'] = '9'
|
||||||
res.save_lazy()
|
res.save_lazy()
|
||||||
ModelMeta.save_all_lazy()
|
ModelMeta.save_all_lazy()
|
||||||
@ -211,16 +232,20 @@ def test_revert_create():
|
|||||||
|
|
||||||
def test_discard_all_pending_changes_resources_created():
|
def test_discard_all_pending_changes_resources_created():
|
||||||
res1 = DBResource.from_dict('test1',
|
res1 = DBResource.from_dict('test1',
|
||||||
{'name': 'test1', 'base_path': 'x',
|
{'name': 'test1',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res1.inputs['a'] = '9'
|
res1.inputs['a'] = '9'
|
||||||
res1.save_lazy()
|
res1.save_lazy()
|
||||||
|
|
||||||
res2 = DBResource.from_dict('test2',
|
res2 = DBResource.from_dict('test2',
|
||||||
{'name': 'test2', 'base_path': 'x',
|
{'name': 'test2',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res2.inputs['a'] = '0'
|
res2.inputs['a'] = '0'
|
||||||
res2.save_lazy()
|
res2.save_lazy()
|
||||||
ModelMeta.save_all_lazy()
|
ModelMeta.save_all_lazy()
|
||||||
@ -236,16 +261,20 @@ def test_discard_all_pending_changes_resources_created():
|
|||||||
|
|
||||||
def test_discard_connection():
|
def test_discard_connection():
|
||||||
res1 = DBResource.from_dict('test1',
|
res1 = DBResource.from_dict('test1',
|
||||||
{'name': 'test1', 'base_path': 'x',
|
{'name': 'test1',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res1.inputs['a'] = '9'
|
res1.inputs['a'] = '9'
|
||||||
res1.save_lazy()
|
res1.save_lazy()
|
||||||
|
|
||||||
res2 = DBResource.from_dict('test2',
|
res2 = DBResource.from_dict('test2',
|
||||||
{'name': 'test2', 'base_path': 'x',
|
{'name': 'test2',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res2.inputs['a'] = '0'
|
res2.inputs['a'] = '0'
|
||||||
res2.save_lazy()
|
res2.save_lazy()
|
||||||
ModelMeta.save_all_lazy()
|
ModelMeta.save_all_lazy()
|
||||||
@ -267,9 +296,11 @@ def test_discard_connection():
|
|||||||
|
|
||||||
def test_discard_removed():
|
def test_discard_removed():
|
||||||
res1 = DBResource.from_dict('test1',
|
res1 = DBResource.from_dict('test1',
|
||||||
{'name': 'test1', 'base_path': 'x',
|
{'name': 'test1',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res1.inputs['a'] = '9'
|
res1.inputs['a'] = '9'
|
||||||
res1.save_lazy()
|
res1.save_lazy()
|
||||||
ModelMeta.save_all_lazy()
|
ModelMeta.save_all_lazy()
|
||||||
@ -289,9 +320,11 @@ def test_discard_removed():
|
|||||||
|
|
||||||
def test_discard_update():
|
def test_discard_update():
|
||||||
res1 = DBResource.from_dict('test1',
|
res1 = DBResource.from_dict('test1',
|
||||||
{'name': 'test1', 'base_path': 'x',
|
{'name': 'test1',
|
||||||
|
'base_path': 'x',
|
||||||
'state': RESOURCE_STATE.created.name,
|
'state': RESOURCE_STATE.created.name,
|
||||||
'meta_inputs': {'a': {'value': None, 'schema': 'str'}}})
|
'meta_inputs': {'a': {'value': None,
|
||||||
|
'schema': 'str'}}})
|
||||||
res1.inputs['a'] = '9'
|
res1.inputs['a'] = '9'
|
||||||
res1.save_lazy()
|
res1.save_lazy()
|
||||||
ModelMeta.save_all_lazy()
|
ModelMeta.save_all_lazy()
|
||||||
|
@ -12,10 +12,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from solar.test import base
|
|
||||||
|
|
||||||
from solar import errors
|
|
||||||
from solar.core import validation as sv
|
from solar.core import validation as sv
|
||||||
|
from solar.test import base
|
||||||
|
|
||||||
|
|
||||||
class TestInputValidation(base.BaseResourceTest):
|
class TestInputValidation(base.BaseResourceTest):
|
||||||
|
@ -18,8 +18,9 @@ from StringIO import StringIO
|
|||||||
import pytest
|
import pytest
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from solar.events.controls import React, Dep
|
|
||||||
from solar.core.resource import virtual_resource as vr
|
from solar.core.resource import virtual_resource as vr
|
||||||
|
from solar.events.controls import Dep
|
||||||
|
from solar.events.controls import React
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -18,11 +18,13 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
|
import yaml
|
||||||
|
|
||||||
from jinja2 import Environment
|
from jinja2 import Environment
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
4
tox.ini
4
tox.ini
@ -12,7 +12,7 @@ deps = -r{toxinidir}/test-requirements.txt
|
|||||||
commands = ostestr --serial
|
commands = ostestr --serial
|
||||||
|
|
||||||
[testenv:pep8]
|
[testenv:pep8]
|
||||||
deps = hacking==0.10.2
|
deps = hacking==0.9.6
|
||||||
usedevelop = False
|
usedevelop = False
|
||||||
commands =
|
commands =
|
||||||
flake8 {posargs:solar/core}
|
flake8 {posargs:solar/core}
|
||||||
@ -27,7 +27,7 @@ envdir = devenv
|
|||||||
usedevelop = True
|
usedevelop = True
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore = H101,H236,E731
|
ignore = E731
|
||||||
exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools,__init__.py,docs
|
exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools,__init__.py,docs
|
||||||
show-pep8 = True
|
show-pep8 = True
|
||||||
show-source = True
|
show-source = True
|
||||||
|
Loading…
Reference in New Issue
Block a user