summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ramsaran <45861913+MooseAnthem@users.noreply.github.com>2024-11-14 04:46:57 +0100
committerGitHub <noreply@github.com>2024-11-14 04:46:57 +0100
commite14f9fe725e1fb1cf37a0aac932d9b9c1f1c65a3 (patch)
tree6b4606b06088f9b55b313857f78be5dcd718481c
parentvars/varnames more examles more varied (#84300) (diff)
downloadansible-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.yml2
-rw-r--r--lib/ansible/plugins/lookup/sequence.py24
-rw-r--r--test/integration/targets/lookup_sequence/tasks/main.yml29
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") == []