diff --git a/reclass/datatypes/parameters.py b/reclass/datatypes/parameters.py index ea803251..02418ebe 100644 --- a/reclass/datatypes/parameters.py +++ b/reclass/datatypes/parameters.py @@ -317,6 +317,16 @@ def _interpolate_inner(self, path, inventory): # list or dict has already been visited by _interpolate_inner del self._unrendered[path] return + # Refresh internal ref cache for the unrendered value with our current context + # to ensure that flattened cached references are updated if necessary if the + # value is part of the parameters tree of multiple nodes. + # + # Side-note (@simu,2022-05-27): I haven't quite determined when a value becomes + # part of the parameters tree of multiple nodes, but I've observed it to be the + # case by looking at `hex(id(value))` for the same parameters key in multiple + # targets in an example inventory which results in a ResolveError without the + # line below. + value.assembleRefs(self._base) self._unrendered[path] = False self._interpolate_references(path, value, inventory) new = self._interpolate_render_value(path, value, inventory) diff --git a/reclass/tests/data/07/classes/base.yml b/reclass/tests/data/07/classes/base.yml new file mode 100644 index 00000000..1cc9fa86 --- /dev/null +++ b/reclass/tests/data/07/classes/base.yml @@ -0,0 +1,14 @@ +parameters: + base: + =_mixed_lookup: + v1: + registry: ghcr.io + repository: path/to/image + tag: v1.2.0 + v2: ${base:image} + + version: v2 + image: + registry: ghcr.io + repository: path/to/image + tag: v2.4.0 diff --git a/reclass/tests/data/07/classes/build.yml b/reclass/tests/data/07/classes/build.yml new file mode 100644 index 00000000..d1b443bc --- /dev/null +++ b/reclass/tests/data/07/classes/build.yml @@ -0,0 +1,5 @@ +parameters: + build: + inputs: + - type: https + source: https://example.com/downloads/${base:_mixed_lookup:${base:version}:tag}/ diff --git a/reclass/tests/data/07/classes/global.yml b/reclass/tests/data/07/classes/global.yml new file mode 100644 index 00000000..7f196232 --- /dev/null +++ b/reclass/tests/data/07/classes/global.yml @@ -0,0 +1,3 @@ +parameters: + base: + version: v1 diff --git a/reclass/tests/data/07/classes/target.yml b/reclass/tests/data/07/classes/target.yml new file mode 100644 index 00000000..199b2854 --- /dev/null +++ b/reclass/tests/data/07/classes/target.yml @@ -0,0 +1,3 @@ +parameters: + instance: + version: v2 diff --git a/reclass/tests/data/07/nodes/t1.yml b/reclass/tests/data/07/nodes/t1.yml new file mode 100644 index 00000000..01b1b041 --- /dev/null +++ b/reclass/tests/data/07/nodes/t1.yml @@ -0,0 +1,13 @@ +classes: + - base + - build + - global + - target +parameters: + _instance: t1 + kapitan: + vars: + target: t1 + +# Expected value for `parameters.build.inputs.0.source: +# https://example.com/downloads/v1.2.0 diff --git a/reclass/tests/data/07/nodes/t2.yml b/reclass/tests/data/07/nodes/t2.yml new file mode 100644 index 00000000..ea73579f --- /dev/null +++ b/reclass/tests/data/07/nodes/t2.yml @@ -0,0 +1,15 @@ +classes: + - base + - build + - global + - target +parameters: + _instance: t2 + base: ${instance} + instance: {} + kapitan: + vars: + target: t2 + +# Expected value for `parameters.build.inputs.0.source: +# https://example.com/downloads/v2.4.0 diff --git a/reclass/tests/test_core.py b/reclass/tests/test_core.py index dd51f3a0..cdebe65c 100644 --- a/reclass/tests/test_core.py +++ b/reclass/tests/test_core.py @@ -123,5 +123,14 @@ def test_application_removal(self): self.assertEqual(A_node['applications'], A_node['parameters']['expected_apps']) self.assertEqual(B_node['applications'], B_node['parameters']['expected_apps']) + def test_mixed_value_constant_parameter_lookup(self): + reclass = self._core("07") + + t1 = reclass.nodeinfo("t1") + t2 = reclass.nodeinfo("t2") + + self.assertEqual(t1["parameters"]["build"]["inputs"][0]["source"], "https://example.com/downloads/v1.2.0/") + self.assertEqual(t2["parameters"]["build"]["inputs"][0]["source"], "https://example.com/downloads/v2.4.0/") + if __name__ == '__main__': unittest.main()