From 8033017c23c8ac921b7a470ff5ccb04f77cfedbd Mon Sep 17 00:00:00 2001 From: Evgeniy L Date: Wed, 27 May 2015 15:12:03 +0200 Subject: [PATCH] Add connect action --- solar/solar/cli.py | 12 ++++++ solar/solar/core/connections.py | 68 +++++++++++++++++++++++++++++++++ solar/solar/core/profile.py | 1 + solar/solar/core/resource.py | 19 +++++++-- solar/solar/core/utils.py | 1 - 5 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 solar/solar/core/connections.py diff --git a/solar/solar/cli.py b/solar/solar/cli.py index ea119d6a..25bbd51a 100644 --- a/solar/solar/cli.py +++ b/solar/solar/cli.py @@ -29,6 +29,7 @@ from solar import extensions from solar import utils from solar.core import data from solar.core.resource import assign_resources_to_nodes +from solar.core.resource import connect_resources from solar.core.tags_set_parser import Expression from solar.interfaces.db import get_db @@ -88,6 +89,13 @@ class Cmd(object): parser.add_argument('-n', '--nodes') parser.add_argument('-r', '--resources') + # Perform resources connection + parser = self.subparser.add_parser('connect') + parser.set_defaults(func=getattr(self, 'connect')) + parser.add_argument( + '-p', + '--profile') + def profile(self, args): if args.create: params = {'tags': args.tags, 'id': args.id} @@ -108,6 +116,10 @@ class Cmd(object): def discover(self, args): Discovery({'id': 'discovery'}).discover() + def connect(self, args): + profile = self.db.get_record('profiles', args.profile) + connect_resources(profile) + def assign(self, args): nodes = filter( lambda n: Expression(args.nodes, n.get('tags', [])).evaluate(), diff --git a/solar/solar/core/connections.py b/solar/solar/core/connections.py new file mode 100644 index 00000000..7d25786d --- /dev/null +++ b/solar/solar/core/connections.py @@ -0,0 +1,68 @@ + +import copy +import json + +from itertools import imap, ifilter + +import networkx as nx +import jinja2 +import mock + +from jinja2 import Template + + +def depends_on(init_value, value=None, tags=None): + if tags is None: + tags = [] + + if value is None: + value = init_value + + called_with_tags = [] + + if isinstance(value, dict): + if value.get('first_resource'): + called_with_tags.extend(value.get('first_resource')) + elif value.get('filter_resources'): + called_with_tags.extend(value.get('filter_resources')) + + for k, v in value.items(): + depends_on(init_value, value=v, tags=tags) + elif isinstance(value, list): + for e in value: + depends_on(init_value, value=e, tags=tags) + elif isinstance(value, str): + return value + + tags.extend(called_with_tags) + + return tags + + +class ResourcesConnectionGraph(object): + + def __init__(self, connections, resources, *args, **kwargs): + super(ResourcesConnectionGraph, self).__init__(*args, **kwargs) + self.connections = connections + self.resources = resources + + def iter_connections(self): + for connection in self.connections: + connections_from = self.resources_with_tags(depends_on(connection)) + connections_to = self.resources_with_tags(connection['for_resources']) + mapping = self.make_mapping(connection) + + for connection_from in connections_from: + for connection_to in connections_to: + if connection_from == connection_to: + continue + + yield {'from': connection_from, 'to': connection_to, 'mapping': mapping} + + def resources_with_tags(self, tags): + """Filter all resources which have tags + """ + return filter(lambda r: set(r.tags) & set(tags), self.resources) + + def make_mapping(self, connection): + return connection['mapping'] diff --git a/solar/solar/core/profile.py b/solar/solar/core/profile.py index f477aa28..c0fa0343 100644 --- a/solar/solar/core/profile.py +++ b/solar/solar/core/profile.py @@ -5,6 +5,7 @@ class Profile(object): self._profile = profile self.tags = set(profile['tags']) self.extensions = profile.get('extensions', []) + self.connections = profile.get('connections', []) def get(self, key): return self._profile.get(key, None) diff --git a/solar/solar/core/resource.py b/solar/solar/core/resource.py index df6da373..39fe2a63 100644 --- a/solar/solar/core/resource.py +++ b/solar/solar/core/resource.py @@ -15,6 +15,8 @@ from solar.core import signals from solar.core import utils from solar.core import validation +from solar.core.connections import ResourcesConnectionGraph + class Resource(object): def __init__(self, name, metadata, args, base_dir, tags=None): @@ -24,6 +26,9 @@ class Resource(object): self.actions = metadata['actions'].keys() if metadata['actions'] else None self.args = {} for arg_name, arg_value in args.items(): + if not self.metadata['input'].get(arg_name): + continue + metadata_arg = self.metadata['input'][arg_name] type_ = validation.schema_input_type(metadata_arg.get('schema', 'str')) @@ -108,7 +113,6 @@ class Resource(object): meta_file = os.path.join(self.base_dir, 'meta.yaml') with open(meta_file, 'w') as f: - f.write(yaml.dump(metadata)) f.write(yaml.dump(metadata, default_flow_style=False)) @@ -128,13 +132,12 @@ def create(name, base_path, dest_path, args, connections={}): meta['id'] = name meta['version'] = '1.0.0' meta['actions'] = {} - meta['tags'] = [] if os.path.exists(actions_path): for f in os.listdir(actions_path): meta['actions'][os.path.splitext(f)[0]] = f - resource = Resource(name, meta, args, dest_path) + resource = Resource(name, meta, args, dest_path, tags=args['tags']) signals.assign_connections(resource, connections) # save @@ -178,7 +181,6 @@ def assign_resources_to_nodes(resources, nodes, dst_dir): merged = deepcopy(resource) # Node specific setting should override resource's merged.update(deepcopy(node)) - # Tags for specific resource is set of tags from node and from resource merged['tags'] = list(set(node.get('tags', [])) | set(resource.get('tags', []))) @@ -187,3 +189,12 @@ def assign_resources_to_nodes(resources, nodes, dst_dir): resource['dir_path'], dst_dir, merged) + + +def connect_resources(profile): + connections = profile.get('connections', []) + resources = load_all('/vagrant/tmp/resource-instances/') + graph = ResourcesConnectionGraph(connections, resources.values()) + + for connection in graph.iter_connections(): + signals.connect(connection['from'], connection['to'], connection['mapping']) diff --git a/solar/solar/core/utils.py b/solar/solar/core/utils.py index cb58ed4f..605765bc 100644 --- a/solar/solar/core/utils.py +++ b/solar/solar/core/utils.py @@ -40,4 +40,3 @@ def save_to_config_file(key, data): with open(fpath, 'w') as f: encoder = ext_encoder(fpath) encoder.dump(data, f) -