diff --git a/resources/haproxy_config/meta.yaml b/resources/haproxy_config/meta.yaml index 10c8d44a..45eeb53b 100644 --- a/resources/haproxy_config/meta.yaml +++ b/resources/haproxy_config/meta.yaml @@ -10,7 +10,7 @@ input: value: {src: /etc/solar/haproxy, dst: /etc/haproxy} config: schema: [{backends: [{server: str!, port: int!}], listen_port: int!, protocol: str!, name: str!}] - value: [] + value: [{}] # ssh_user: # schema: str! # value: diff --git a/solar/solar/cli/resource.py b/solar/solar/cli/resource.py index 0207aaa6..20a2aea2 100644 --- a/solar/solar/cli/resource.py +++ b/solar/solar/cli/resource.py @@ -82,9 +82,10 @@ def backtrack_single(i): @resource.command() @click.option('-v', '--values', default=False, is_flag=True) +@click.option('-r', '--real_values', default=False, is_flag=True) @click.option('-i', '--input', default=None) @click.argument('resource') -def backtrack_inputs(resource, input, values): +def backtrack_inputs(resource, input, values, real_values): r = sresource.load(resource) db_obj = r.db_obj @@ -101,7 +102,7 @@ def backtrack_inputs(resource, input, values): for (rname, rinput), _, meta in se: l.append(dict(resource=resource, name=name)) val = single(rname, rinput, get_val) - if meta: + if meta and isinstance(val, dict): val['meta'] = meta l.append(val) return l @@ -115,6 +116,8 @@ def backtrack_inputs(resource, input, values): for name, values in inps.iteritems(): click.echo(yaml.safe_dump({name: values}, default_flow_style=False)) + if real_values: + click.echo('! Real value: %r' % sresource.load(resource).db_obj.inputs[name] , nl=True) @resource.command() def compile_all(): diff --git a/solar/solar/dblayer/solar_models.py b/solar/solar/dblayer/solar_models.py index 329d8d01..4524e1db 100644 --- a/solar/solar/dblayer/solar_models.py +++ b/solar/solar/dblayer/solar_models.py @@ -185,6 +185,9 @@ class InputsFieldWrp(IndexFieldWrp): def _connect_other_hash(self, my_resource, my_inp_name, other_resource, other_inp_name, my_type, other_type): return self._connect_other_simple(my_resource, my_inp_name, other_resource, other_inp_name, my_type, other_type) + def _connect_other_list_hash(self, my_resource, my_inp_name, other_resource, other_inp_name, my_type, other_type): + return self._connect_other_simple(my_resource, my_inp_name, other_resource, other_inp_name, my_type, other_type) + def _connect_my_list(self, my_resource, my_inp_name, other_resource, other_inp_name, my_type, other_type): ret = self._connect_my_simple(my_resource, my_inp_name, other_resource, other_inp_name, my_type, other_type) return ret @@ -218,14 +221,17 @@ class InputsFieldWrp(IndexFieldWrp): other_type = self._input_type(other_resource, other_inp_name) my_type = self._input_type(my_resource, my_inp_name) - if my_type == other_type: - # if the type is the same map 1:1 + if my_type == other_type and not ':' in my_inp_name: + # if the type is the same map 1:1, and flat my_type = InputTypes.simple other_type = InputTypes.simple elif my_type == InputTypes.list_hash and other_type == InputTypes.hash: # whole dict to list with dicts # TODO: solve this problem - my_type = InputTypes.list + if ':' in my_inp_name: + my_type = InputTypes.hash + else: + my_type = InputTypes.list # set my side my_meth = getattr(self, '_connect_my_{}'.format(my_type.name)) @@ -447,16 +453,17 @@ class InputsFieldWrp(IndexFieldWrp): else: _, _, emitter_key, emitter_inp, my_tag, my_val, mapping_type = splitted_val cres = Resource.get(emitter_key).inputs._get_field_val(emitter_inp, other) + mapping_type = splitted_val[-1] items.append((my_tag, my_val, cres)) tmp_res = {} - for my_tag, my_val, value in items: + for first, my_val, value in items: if my_val is None: - tmp_res[my_tag] = value + tmp_res[first] = value else: try: - tmp_res[my_tag][my_val] = value + tmp_res[first][my_val] = value except KeyError: - tmp_res[my_tag] = {my_val: value} + tmp_res[first] = {my_val: value} res = tmp_res.values() self._cache[name] = res return res @@ -691,7 +698,6 @@ class Resource(Model): # name there? if not emitter[0] == self.key: return False - # TODO: `delete_hash` test works with receiver[1], while lists works with emitter[1] key = emitter[1] if not key in converted: return False diff --git a/solar/solar/dblayer/test/test_real.py b/solar/solar/dblayer/test/test_real.py index 4a26f6c0..bdabb036 100644 --- a/solar/solar/dblayer/test/test_real.py +++ b/solar/solar/dblayer/test/test_real.py @@ -554,3 +554,71 @@ def test_delete_hash(rk): if 'recv' in index[0] or 'emit' in index[0]: recv_emit_bin.append(index) assert recv_emit_bin == [] + + +def test_nested_simple_listdict(rk): + k1 = next(rk) + k2 = next(rk) + k3 = next(rk) + k4 = next(rk) + k5 = next(rk) + + r1 = create_resource(k1, {'name': 'first', + 'inputs': {'config': [{"backends": [{}], + 'listen_port': 1}]}}) + r2 = create_resource(k2, {'name': 'second', + 'inputs': {'backend': {}}}) + r3 = create_resource(k3, {'name': 'third', + 'inputs': {'backend': {}}}) + r5 = create_resource(k5, {'name': 'fifth', + 'inputs': {"port": 5, + "host": "fifth_host"}}) + r4 = create_resource(k4, {'name': 'fourth', + 'inputs': {"port": 4, + "host": "fourth_host"}}) + + r4.connect(r2, {'port': "backend:port", + 'host': 'backend:host'}) + r5.connect(r3, {'port': "backend:port", + 'host': 'backend:host'}) + + + assert r2.inputs['backend'] == {'host': 'fourth_host', 'port': 4} + assert r3.inputs['backend'] == {'host': 'fifth_host', 'port': 5} + + r2.connect(r1, {'backend': 'config:backends'}) + r3.connect(r1, {'backend': 'config:backends'}) + + Resource.save_all_lazy() + + backends = next(x['backends'] for x in r1.inputs['config'] if 'backends' in x) + assert len(backends) == 2 + + +def test_nested_two_listdict(rk): + k1 = next(rk) + k2 = next(rk) + k3 = next(rk) + + r1 = create_resource(k1, {'name': 'first', + 'inputs': {'config': [{"backends": [{}], + 'something': 0}]}}) + r2 = create_resource(k2, {'name': 'second', + 'inputs': {"backends": [{"host": "second_host", "port": 2}], + 'something': 1}}) + r3 = create_resource(k3, {'name': 'third', + 'inputs': {"backends": [{"host": "third_host", "port": 3}], + 'something': 2}}) + + r2.connect(r1, {'backends': 'config:backends', + 'something': 'config:something'}) + r3.connect(r1, {'backends': 'config:backends', + 'something': 'config:something'}) + + Resource.save_all_lazy() + + for sc in r1.inputs['config']: + assert 'something' in sc + assert 'backends' in sc + assert isinstance(sc['backends'], list) + assert isinstance(sc['something'], int)