Changed how variables work again

Script variables are not longer saved before entering a block. Only
variables declared as locals and loop variables are saved. This allows a
block to use `set_var` to change a variable.
This commit is contained in:
Emmanuel BENOîT 2022-09-17 10:10:18 +02:00
parent 46e675dedb
commit 0519be9316

View file

@ -111,31 +111,45 @@ INSTR_FIELDS = {k: set(v + INSTR_COMMON_FIELDS) for k, v in INSTR_OWN_FIELDS.ite
class VariableStorage(MutableMapping): class VariableStorage(MutableMapping):
def __init__(self, host_vars): def __init__(self, host_vars):
self._host_vars = host_vars self._host_vars = host_vars
self._script_stack = [{}] self._script_vars = {}
self._script_stack = []
self._cache = host_vars.copy() self._cache = host_vars.copy()
def _script_stack_push(self): def _script_stack_push(self, variables):
self._script_stack.append(self._script_stack[-1].copy()) data = {}
for v in variables:
if v in self._script_vars:
se = (True, self._script_vars[v])
else:
se = (False, None)
data[v] = se
self._script_stack.append(data)
def _script_stack_pop(self): def _script_stack_pop(self):
self._script_stack.pop() restore = self._script_stack.pop()
for vn, vv in restore.items():
existed, value = vv
if existed:
self._script_vars[vn] = value
elif vn in self._script_vars:
del self._script_vars[vn]
self._cache = self._host_vars.copy() self._cache = self._host_vars.copy()
self._cache.update(self._script_stack[-1]) self._cache.update(self._script_vars)
def _set_host_var(self, name, value): def _set_host_var(self, name, value):
self._host_vars[name] = value self._host_vars[name] = value
if name not in self._script_stack[-1]: if name not in self._script_vars:
self._cache[name] = value self._cache[name] = value
def __getitem__(self, k): def __getitem__(self, k):
return self._cache[k] return self._cache[k]
def __setitem__(self, k, v): def __setitem__(self, k, v):
self._script_stack[-1][k] = v self._script_vars[k] = v
self._cache[k] = v self._cache[k] = v
def __delitem__(self, k): def __delitem__(self, k):
del self._script_stack[-1][k] del self._script_vars[k]
if k in self._host_vars: if k in self._host_vars:
self._cache[k] = self._host_vars[k] self._cache[k] = self._host_vars[k]
else: else:
@ -339,9 +353,7 @@ class RcInstruction(abc.ABC):
self._display.vvvv("%s : running action %s" % (host_name, self._action)) self._display.vvvv("%s : running action %s" % (host_name, self._action))
return self.run_once(host_name, variables) return self.run_once(host_name, variables)
# Save previous loop variable state # Save previous loop variable state
had_loop_var = self._loop_var in variables variables._script_stack_push([self._loop_var])
if had_loop_var:
old_loop_var = variables[self._loop_var]
try: try:
# Loop over all values # Loop over all values
for value in self.evaluate_loop(host_name, variables): for value in self.evaluate_loop(host_name, variables):
@ -355,10 +367,7 @@ class RcInstruction(abc.ABC):
return True return True
finally: finally:
# Restore loop variable state # Restore loop variable state
if had_loop_var: variables._script_stack_pop()
variables[self._loop_var] = old_loop_var
else:
del variables[self._loop_var]
def run_once(self, host_name, variables): def run_once(self, host_name, variables):
"""Check the condition if it exists, then run the instruction. """Check the condition if it exists, then run the instruction.
@ -795,26 +804,28 @@ class RciBlock(RcInstruction):
or self._always is None or self._always is None
or self._locals is None or self._locals is None
) )
variables._script_stack_push() variables._script_stack_push(self._locals.keys())
self._templar.available_variables = variables
for key, value in self._locals.items():
result = self._templar.template(value)
variables[key] = result
self._display.vvv("- set block-local %s to %s" % (key, result))
try: try:
self._templar.available_variables = variables
for key, value in self._locals.items():
result = self._templar.template(value)
variables[key] = result
self._display.vvv("- set block-local %s to %s" % (key, result))
try: try:
self._display.vvv("- running 'block' instructions") try:
return self.run_block(self._block, host_name, variables) self._display.vvv("- running 'block' instructions")
except AnsibleError as e: return self.run_block(self._block, host_name, variables)
if not self._rescue: except AnsibleError as e:
self._display.vvv("- block failed") if not self._rescue:
raise self._display.vvv("- block failed")
self._display.vvv("- block failed, running 'rescue' instructions") raise
variables["reconstructed_error"] = str(e) self._display.vvv("- block failed, running 'rescue' instructions")
return self.run_block(self._rescue, host_name, variables) variables["reconstructed_error"] = str(e)
return self.run_block(self._rescue, host_name, variables)
finally:
self._display.vvv("- block exited, running 'always' instructions")
self.run_block(self._always, host_name, variables)
finally: finally:
self._display.vvv("- block exited, running 'always' instructions")
self.run_block(self._always, host_name, variables)
variables._script_stack_pop() variables._script_stack_pop()
def run_block(self, block, host_name, variables): def run_block(self, block, host_name, variables):