diff options
author | James Ramsaran <45861913+MooseAnthem@users.noreply.github.com> | 2024-11-14 04:46:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-14 04:46:57 +0100 |
commit | e14f9fe725e1fb1cf37a0aac932d9b9c1f1c65a3 (patch) | |
tree | 6b4606b06088f9b55b313857f78be5dcd718481c | |
parent | vars/varnames more examles more varied (#84300) (diff) | |
download | ansible-e14f9fe725e1fb1cf37a0aac932d9b9c1f1c65a3.tar.xz ansible-e14f9fe725e1fb1cf37a0aac932d9b9c1f1c65a3.zip |
Sequence query fix (#83758)
Co-authored-by: flowerysong <junk+github@flowerysong.com>
-rw-r--r-- | changelogs/fragments/fix-lookup-sequence-keyword-args-only.yml | 2 | ||||
-rw-r--r-- | lib/ansible/plugins/lookup/sequence.py | 24 | ||||
-rw-r--r-- | test/integration/targets/lookup_sequence/tasks/main.yml | 29 |
3 files changed, 48 insertions, 7 deletions
diff --git a/changelogs/fragments/fix-lookup-sequence-keyword-args-only.yml b/changelogs/fragments/fix-lookup-sequence-keyword-args-only.yml new file mode 100644 index 0000000000..ae9f8716b9 --- /dev/null +++ b/changelogs/fragments/fix-lookup-sequence-keyword-args-only.yml @@ -0,0 +1,2 @@ +bugfixes: + - sequence lookup - sequence query/lookups without positional arguments now return a valid list if their kwargs comprise a valid sequence expression (https://github.com/ansible/ansible/issues/82921).
\ No newline at end of file diff --git a/lib/ansible/plugins/lookup/sequence.py b/lib/ansible/plugins/lookup/sequence.py index 9efe7cef53..5f34d44e65 100644 --- a/lib/ansible/plugins/lookup/sequence.py +++ b/lib/ansible/plugins/lookup/sequence.py @@ -171,6 +171,12 @@ class LookupModule(LookupBase): setattr(self, f, self.get_option(f)) def sanity_check(self): + """ + Returns True if options comprise a valid sequence expression + Raises AnsibleError if options are an invalid expression + Returns false if options are valid but result in an empty sequence - these cases do not raise exceptions + in order to maintain historic behavior + """ if self.count is None and self.end is None: raise AnsibleError("must specify count or end in with_sequence") elif self.count is not None and self.end is not None: @@ -180,17 +186,18 @@ class LookupModule(LookupBase): if self.count != 0: self.end = self.start + self.count * self.stride - 1 else: - self.start = 0 - self.end = 0 - self.stride = 0 - del self.count + return False if self.stride > 0 and self.end < self.start: raise AnsibleError("to count backwards make stride negative") if self.stride < 0 and self.end > self.start: raise AnsibleError("to count forward don't make stride negative") + if self.stride == 0: + return False if self.format.count('%') != 1: raise AnsibleError("bad formatting string: %s" % self.format) + return True + def generate_sequence(self): if self.stride >= 0: adjust = 1 @@ -210,6 +217,10 @@ class LookupModule(LookupBase): def run(self, terms, variables, **kwargs): results = [] + if kwargs and not terms: + # All of the necessary arguments can be provided as keywords, but we still need something to loop over + terms = [''] + for term in terms: try: # set defaults/global @@ -223,10 +234,9 @@ class LookupModule(LookupBase): raise AnsibleError("unknown error parsing with_sequence arguments: %r. Error was: %s" % (term, e)) self.set_fields() - self.sanity_check() - - if self.stride != 0: + if self.sanity_check(): results.extend(self.generate_sequence()) + except AnsibleError: raise except Exception as e: diff --git a/test/integration/targets/lookup_sequence/tasks/main.yml b/test/integration/targets/lookup_sequence/tasks/main.yml index 3d74339e8c..e640d42b4c 100644 --- a/test/integration/targets/lookup_sequence/tasks/main.yml +++ b/test/integration/targets/lookup_sequence/tasks/main.yml @@ -196,3 +196,32 @@ - ansible_failed_result.msg == expected vars: expected: "bad formatting string: d" + +# Tests for lookup()/plugin() jinja invocation: +# Many of these tests check edge case behaviors that are only possible when invoking query/lookup sequence through jinja. +# While they aren't particularly intuitive, these tests ensure playbooks that could be relying on these behaviors don't +# break in future +- name: Test lookup with keyword args only + assert: + that: + - query("ansible.builtin.sequence", count=5, start=10) == ["10", "11", "12", "13", "14"] + +- name: Test that multiple positional args produces concatenated sequence + assert: + that: + - query("ansible.builtin.sequence", "count=5 start=1", "count=3 start=10 stride=2") == ["1", "2", "3", "4", "5", "10", "12", "14"] + +- name: Test that keyword arguments are applied to all positional expressions + assert: + that: + - query("ansible.builtin.sequence", "count=5 start=0", "count=5 start=20", stride=2) == ["0", "2", "4", "6", "8", "20", "22", "24", "26", "28"] + +- name: Test that keyword arguments do not overwrite parameters present in positional expressions + assert: + that: + - query("ansible.builtin.sequence", "count=5 start=0", "count=5", start=20) == ["0", "1", "2", "3", "4", "20", "21", "22", "23", "24"] + +- name: Test that call with no arguments produces an empty list + assert: + that: + - query("ansible.builtin.sequence") == [] |