Implemented vars clause
* Can be used on any instruction * Variables are evaluated before condition is checked
This commit is contained in:
parent
2fd5ba9bb4
commit
f2d1e2da50
2 changed files with 69 additions and 10 deletions
|
@ -95,7 +95,7 @@ instructions:
|
||||||
# Component group. We add the host directly if there is no subcomponent.
|
# Component group. We add the host directly if there is no subcomponent.
|
||||||
- when: inv__component is defined
|
- when: inv__component is defined
|
||||||
action: block
|
action: block
|
||||||
locals:
|
vars:
|
||||||
comp_group: "svcm_{{ inv__service }}_{{ inv__component }}"
|
comp_group: "svcm_{{ inv__service }}_{{ inv__component }}"
|
||||||
block:
|
block:
|
||||||
- action: create_group
|
- action: create_group
|
||||||
|
|
|
@ -93,7 +93,7 @@ DOCUMENTATION = """
|
||||||
default: host
|
default: host
|
||||||
"""
|
"""
|
||||||
|
|
||||||
INSTR_COMMON_FIELDS = ("when", "loop", "loop_var", "action", "run_once")
|
INSTR_COMMON_FIELDS = ("action", "loop", "loop_var", "run_once", "vars", "when")
|
||||||
"""Fields that may be present on all instructions."""
|
"""Fields that may be present on all instructions."""
|
||||||
|
|
||||||
INSTR_OWN_FIELDS = {
|
INSTR_OWN_FIELDS = {
|
||||||
|
@ -229,11 +229,13 @@ class RcInstruction(abc.ABC):
|
||||||
self._inventory = inventory
|
self._inventory = inventory
|
||||||
self._templar = templar
|
self._templar = templar
|
||||||
self._display = display
|
self._display = display
|
||||||
|
self._action = action
|
||||||
self._condition = None
|
self._condition = None
|
||||||
|
self._executed_once = None
|
||||||
self._loop = None
|
self._loop = None
|
||||||
self._loop_var = None
|
self._loop_var = None
|
||||||
self._action = action
|
self._vars = None
|
||||||
self._executed_once = None
|
self._save = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""Builds a compact debugging representation of the instruction, \
|
"""Builds a compact debugging representation of the instruction, \
|
||||||
|
@ -338,12 +340,52 @@ class RcInstruction(abc.ABC):
|
||||||
raise AnsibleParserError(
|
raise AnsibleParserError(
|
||||||
"%s: 'loop_var' clause found without 'loop'" % (self._action,)
|
"%s: 'loop_var' clause found without 'loop'" % (self._action,)
|
||||||
)
|
)
|
||||||
|
# Extract local variables
|
||||||
|
self._vars = self.parse_vars(record)
|
||||||
|
# Cache the list of variables to save before execution
|
||||||
|
save = list(self._vars.keys())
|
||||||
|
if self._loop is not None:
|
||||||
|
save.append(self._loop_var)
|
||||||
|
self._save = tuple(save)
|
||||||
# Handle instructions that may only be executed once
|
# Handle instructions that may only be executed once
|
||||||
if record.get("run_once", False):
|
if record.get("run_once", False):
|
||||||
self._executed_once = False
|
self._executed_once = False
|
||||||
# Process action-specific fields
|
# Process action-specific fields
|
||||||
self.parse_action(record)
|
self.parse_action(record)
|
||||||
|
|
||||||
|
def parse_vars(self, record):
|
||||||
|
"""Parse local variable definitions from the record.
|
||||||
|
|
||||||
|
This method checks for a ``vars`` section in the YAML data, and extracts
|
||||||
|
it if it exists.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
record: the YAML data for the instruction
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
a dictionnary that contains the variable definitions
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
AnsibleParserError: when the ``vars`` entry is invalid or contains \
|
||||||
|
invalid definitions
|
||||||
|
"""
|
||||||
|
if "vars" not in record:
|
||||||
|
return {}
|
||||||
|
if not isinstance(record["vars"], dict):
|
||||||
|
raise AnsibleParserError(
|
||||||
|
"%s: 'vars' should be a dictionnary" % (self._action,)
|
||||||
|
)
|
||||||
|
for k, v in record["vars"].items():
|
||||||
|
if not isinstance(k, string_types):
|
||||||
|
raise AnsibleParserError(
|
||||||
|
"%s: vars identifiers must be strings" % (self._action,)
|
||||||
|
)
|
||||||
|
if not isidentifier(k):
|
||||||
|
raise AnsibleParserError(
|
||||||
|
"%s: '%s' is not a valid identifier" % (self._action, k)
|
||||||
|
)
|
||||||
|
return record["vars"]
|
||||||
|
|
||||||
def parse_group_name(self, record, name):
|
def parse_group_name(self, record, name):
|
||||||
"""Parse a field containing the name of a group, or a template.
|
"""Parse a field containing the name of a group, or a template.
|
||||||
|
|
||||||
|
@ -409,12 +451,13 @@ class RcInstruction(abc.ABC):
|
||||||
return True
|
return True
|
||||||
if self._executed_once is False:
|
if self._executed_once is False:
|
||||||
self._executed_once = True
|
self._executed_once = True
|
||||||
if self._loop is None:
|
# Save previous loop and local variables state
|
||||||
self._display.vvvv("%s : running action %s" % (host_name, self._action))
|
variables._script_stack_push(self._save)
|
||||||
return self.run_iteration(host_name, variables)
|
|
||||||
# Save previous loop variable state
|
|
||||||
variables._script_stack_push([self._loop_var])
|
|
||||||
try:
|
try:
|
||||||
|
# Instructions without loops
|
||||||
|
if self._loop is None:
|
||||||
|
self._display.vvvv("%s : running action %s" % (host_name, self._action))
|
||||||
|
return self.run_iteration(host_name, variables)
|
||||||
# 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):
|
||||||
self._display.vvvv(
|
self._display.vvvv(
|
||||||
|
@ -440,6 +483,7 @@ class RcInstruction(abc.ABC):
|
||||||
``True`` if execution must continue, ``False`` if it must be
|
``True`` if execution must continue, ``False`` if it must be
|
||||||
interrupted
|
interrupted
|
||||||
"""
|
"""
|
||||||
|
self.compute_locals(host_name, variables)
|
||||||
if self.evaluate_condition(host_name, variables):
|
if self.evaluate_condition(host_name, variables):
|
||||||
rv = self.execute_action(host_name, variables)
|
rv = self.execute_action(host_name, variables)
|
||||||
if not rv:
|
if not rv:
|
||||||
|
@ -466,7 +510,6 @@ class RcInstruction(abc.ABC):
|
||||||
if self._condition is None:
|
if self._condition is None:
|
||||||
return True
|
return True
|
||||||
t = self._templar
|
t = self._templar
|
||||||
t.available_variables = variables
|
|
||||||
template = "%s%s%s" % (
|
template = "%s%s%s" % (
|
||||||
t.environment.variable_start_string,
|
t.environment.variable_start_string,
|
||||||
self._condition,
|
self._condition,
|
||||||
|
@ -479,6 +522,22 @@ class RcInstruction(abc.ABC):
|
||||||
)
|
)
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
def compute_locals(self, host_name, variables):
|
||||||
|
"""Compute local variables.
|
||||||
|
|
||||||
|
This method iterates through all local variable definitions and runs
|
||||||
|
them through the templar.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
host_name: the name of the host the instruction is being executed for
|
||||||
|
variables: the variable storage instance
|
||||||
|
"""
|
||||||
|
self._templar.available_variables = variables
|
||||||
|
for key, value in self._vars.items():
|
||||||
|
result = self._templar.template(value)
|
||||||
|
variables[key] = result
|
||||||
|
self._display.vvvv("- set local variable %s to %s" % (key, result))
|
||||||
|
|
||||||
def evaluate_loop(self, host_name, variables):
|
def evaluate_loop(self, host_name, variables):
|
||||||
"""Evaluate the values to iterate over when a ``loop`` is defined.
|
"""Evaluate the values to iterate over when a ``loop`` is defined.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue