Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
ansible
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
ansible
Commits
9b646dea
Commit
9b646dea
authored
May 12, 2015
by
Serge van Ginderachter
Committed by
James Cammarata
May 12, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add optional 'skip_missing' flag to subelements
parent
1ca8cb85
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
157 additions
and
17 deletions
+157
-17
docsite/rst/playbooks_loops.rst
+32
-1
lib/ansible/plugins/lookup/subelements.py
+57
-15
test/integration/roles/test_iterators/tasks/main.yml
+34
-1
test/integration/roles/test_iterators/vars/main.yml
+34
-0
No files found.
docsite/rst/playbooks_loops.rst
View file @
9b646dea
...
...
@@ -147,9 +147,26 @@ How might that be accomplished? Let's assume you had the following defined and
authorized:
- /tmp/alice/onekey.pub
- /tmp/alice/twokey.pub
mysql:
password: mysql-password
hosts:
- "%"
- "127.0.0.1"
- "::1"
- "localhost"
privs:
- "*.*:SELECT"
- "DB1.*:ALL"
- name: bob
authorized:
- /tmp/bob/id_rsa.pub
mysql:
password: other-mysql-password
hosts:
- "db1"
privs:
- "*.*:SELECT"
- "DB2.*:ALL"
It might happen like so::
...
...
@@ -161,9 +178,23 @@ It might happen like so::
- users
- authorized
Subelements walks a list of hashes (aka dictionaries) and then traverses a list with a given key inside of those
Given the mysql hosts and privs subkey lists, you can also iterate over a list in a nested subkey::
- name: Setup MySQL users
mysql_user: name={{ item.0.user }} password={{ item.0.mysql.password }} host={{ item.1 }} priv={{ item.0.mysql.privs | join('/') }}
with_subelements:
- users
- mysql.hosts
Subelements walks a list of hashes (aka dictionaries) and then traverses a list with a given (nested sub-)key inside of those
records.
Optionally, you can add a third element to the subelements list, that holds a
dictionary of flags. Currently you can add the 'skip_missing' flag. If set to
True, the lookup plugin will skip the lists items that do not contain the given
subkey. Without this flag, or if that flag is set to False, the plugin will
yield an error and complain about the missing subkey.
The authorized_key pattern is exactly where it comes up most.
.. _looping_over_integer_sequences:
...
...
lib/ansible/plugins/lookup/subelements.py
View file @
9b646dea
...
...
@@ -20,40 +20,82 @@ __metaclass__ = type
from
ansible.errors
import
*
from
ansible.plugins.lookup
import
LookupBase
from
ansible.utils.listify
import
listify_lookup_plugin_terms
from
ansible.utils.boolean
import
boolean
FLAGS
=
(
'skip_missing'
,)
class
LookupModule
(
LookupBase
):
def
run
(
self
,
terms
,
variables
,
**
kwargs
):
terms
[
0
]
=
listify_lookup_plugin_terms
(
terms
[
0
],
variables
,
loader
=
self
.
_loader
)
def
_raise_terms_error
(
msg
=
""
):
raise
errors
.
AnsibleError
(
"subelements lookup expects a list of two or three items, "
+
msg
)
terms
=
listify_lookup_plugin_terms
(
terms
,
self
.
basedir
,
inject
)
terms
[
0
]
=
listify_lookup_plugin_terms
(
terms
[
0
],
self
.
basedir
,
inject
)
if
not
isinstance
(
terms
,
list
)
or
not
len
(
terms
)
==
2
:
raise
AnsibleError
(
"subelements lookup expects a list of two items, first a dict or a list, and second a string"
)
# check lookup terms - check number of terms
if
not
isinstance
(
terms
,
list
)
or
not
2
<=
len
(
terms
)
<=
3
:
_raise_terms_error
()
if
isinstance
(
terms
[
0
],
dict
):
# convert to list:
if
terms
[
0
]
.
get
(
'skipped'
,
False
)
!=
False
:
# first term should be a list (or dict), second a string holding the subkey
if
not
isinstance
(
terms
[
0
],
(
list
,
dict
))
or
not
isinstance
(
terms
[
1
],
basestring
):
_raise_terms_error
(
"first a dict or a list, second a string pointing to the subkey"
)
subelements
=
terms
[
1
]
.
split
(
"."
)
if
isinstance
(
terms
[
0
],
dict
):
# convert to list:
if
terms
[
0
]
.
get
(
'skipped'
,
False
)
is
not
False
:
# the registered result was completely skipped
return
[]
elementlist
=
[]
for
key
in
terms
[
0
]
.
iterkeys
():
elementlist
.
append
(
terms
[
0
][
key
])
else
:
else
:
elementlist
=
terms
[
0
]
subelement
=
terms
[
1
]
# check for optional flags in third term
flags
=
{}
if
len
(
terms
)
==
3
:
flags
=
terms
[
2
]
if
not
isinstance
(
flags
,
dict
)
and
not
all
([
isinstance
(
key
,
basestring
)
and
key
in
FLAGS
for
key
in
flags
]):
_raise_terms_error
(
"the optional third item must be a dict with flags
%
s"
%
FLAGS
)
# build_items
ret
=
[]
for
item0
in
elementlist
:
if
not
isinstance
(
item0
,
dict
):
raise
AnsibleError
(
"subelements lookup expects a dictionary, got '
%
s'"
%
item0
)
if
item0
.
get
(
'skipped'
,
False
)
!=
False
:
raise
errors
.
AnsibleError
(
"subelements lookup expects a dictionary, got '
%
s'"
%
item0
)
if
item0
.
get
(
'skipped'
,
False
)
is
not
False
:
# this particular item is to be skipped
continue
if
not
subelement
in
item0
:
raise
AnsibleError
(
"could not find '
%
s' key in iterated item '
%
s'"
%
(
subelement
,
item0
))
if
not
isinstance
(
item0
[
subelement
],
list
):
raise
AnsibleError
(
"the key
%
s should point to a list, got '
%
s'"
%
(
subelement
,
item0
[
subelement
]))
sublist
=
item0
.
pop
(
subelement
,
[])
continue
skip_missing
=
boolean
(
flags
.
get
(
'skip_missing'
,
False
))
subvalue
=
item0
lastsubkey
=
False
sublist
=
[]
for
subkey
in
subelements
:
if
subkey
==
subelements
[
-
1
]:
lastsubkey
=
True
if
not
subkey
in
subvalue
:
if
skip_missing
:
continue
else
:
raise
errors
.
AnsibleError
(
"could not find '
%
s' key in iterated item '
%
s'"
%
(
subkey
,
subvalue
))
if
not
lastsubkey
:
if
not
isinstance
(
subvalue
[
subkey
],
dict
):
if
skip_missing
:
continue
else
:
raise
errors
.
AnsibleError
(
"the key
%
s should point to a dictionary, got '
%
s'"
%
(
subkey
,
subvalue
[
subkey
]))
else
:
subvalue
=
subvalue
[
subkey
]
else
:
# lastsubkey
if
not
isinstance
(
subvalue
[
subkey
],
list
):
raise
errors
.
AnsibleError
(
"the key
%
s should point to a list, got '
%
s'"
%
(
subkey
,
subvalue
[
subkey
]))
else
:
sublist
=
subvalue
.
pop
(
subkey
,
[])
for
item1
in
sublist
:
ret
.
append
((
item0
,
item1
))
...
...
test/integration/roles/test_iterators/tasks/main.yml
View file @
9b646dea
...
...
@@ -39,7 +39,7 @@
set_fact
:
"
{{
item.0
+
item.1
}}=x"
with_nested
:
-
[
'
a'
,
'
b'
]
-
[
'
c'
,
'
d'
]
-
[
'
c'
,
'
d'
]
-
debug
:
var=ac
-
debug
:
var=ad
...
...
@@ -97,6 +97,39 @@
-
"
_ye
==
'e'"
-
"
_yf
==
'f'"
-
name
:
test with_subelements in subkeys
set_fact
:
"
{{
'_'+
item.0.id
+
item.1
}}={{
item.1
}}"
with_subelements
:
-
element_data
-
the.sub.key.list
-
name
:
verify with_subelements in subkeys results
assert
:
that
:
-
"
_xq
==
'q'"
-
"
_xr
==
'r'"
-
"
_yi
==
'i'"
-
"
_yo
==
'o'"
-
name
:
test with_subelements with missing key or subkey
set_fact
:
"
{{
'_'+
item.0.id
+
item.1
}}={{
item.1
}}"
with_subelements
:
-
element_data_missing
-
the.sub.key.list
-
skip_missing
:
yes
register
:
_subelements_missing_subkeys
-
debug
:
var=_subelements_missing_subkeys.skipped
-
debug
:
var=_subelements_missing_subkeys.results|length
-
name
:
verify with_subelements in subkeys results
assert
:
that
:
-
_subelements_missing_subkeys.skipped is not defined
-
_subelements_missing_subkeys.results|length == 2
-
"
_xk
==
'k'"
-
"
_xl
==
'l'"
# WITH_TOGETHER
-
name
:
test with_together
...
...
test/integration/roles/test_iterators/vars/main.yml
View file @
9b646dea
...
...
@@ -3,7 +3,41 @@ element_data:
the_list
:
-
"
f"
-
"
d"
the
:
sub
:
key
:
list
:
-
"
q"
-
"
r"
-
id
:
y
the_list
:
-
"
e"
-
"
f"
the
:
sub
:
key
:
list
:
-
"
i"
-
"
o"
element_data_missing
:
-
id
:
x
the_list
:
-
"
f"
-
"
d"
the
:
sub
:
key
:
list
:
-
"
k"
-
"
l"
-
id
:
y
the_list
:
-
"
f"
-
"
d"
-
id
:
z
the_list
:
-
"
e"
-
"
f"
the
:
sub
:
key
:
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment