From ba0b570054f89c72d261e2e2d0aedd55c4fe2344 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Thu, 22 Jun 2017 12:18:03 -0400 Subject: [PATCH] Resolve Macros when copying templates During stack updates in the legacy path, we copy resource definitions back and forth between templates. In the case where the definitions contain macros (which in practice means the If macro for conditionals), they may rely on external state (in practice, the conditional definitions) that is not available in the template they're being copied into (e.g. in the case of an If macro referencing a new condition). This change means that when we copy a template, the macros get resolved so that only the chosen path of the If macro is represented. This resolves the issue where trying to signal a resource during an update fails when one of the already-updated resources in the template contains an If macro that refers to a condition definition that is newly-added in the new template. Change-Id: I6d08507f43b0fcc4c0b5e848e97fa26033d839b2 Closes-Bug: #1699463 --- heat/engine/function.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/heat/engine/function.py b/heat/engine/function.py index 6c28b09947..1aed951660 100644 --- a/heat/engine/function.py +++ b/heat/engine/function.py @@ -188,6 +188,20 @@ class Macro(Function): """ return dep_attrs(self.parsed, resource_name) + def __reduce__(self): + """Return a representation of the macro result suitable for pickling. + + This allows the copy module (which works by pickling and then + unpickling objects) to copy a template. Functions in the copy will + return to their original (JSON) form (i.e. a single-element map). + + Unlike other functions, macros are *not* preserved during a copy. The + the processed (but unparsed) output is returned in their place. + """ + if isinstance(self.parsed, Function): + return self.parsed.__reduce__() + return type(self.parsed), (self.parsed,) + def _repr_result(self): return repr(self.parsed)