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
f8a30fae
Commit
f8a30fae
authored
Aug 27, 2014
by
James Cammarata
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'default-omit-updated' into devel
parents
b6a30a73
35dac66a
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
99 additions
and
18 deletions
+99
-18
docsite/rst/playbooks_variables.rst
+21
-0
lib/ansible/runner/__init__.py
+31
-9
lib/ansible/runner/filter_plugins/core.py
+2
-1
lib/ansible/utils/__init__.py
+15
-8
test/integration/roles/test_good_parsing/tasks/main.yml
+30
-0
No files found.
docsite/rst/playbooks_variables.rst
View file @
f8a30fae
...
...
@@ -180,6 +180,27 @@ Jinja2 provides a useful 'default' filter, that is often a better approach to fa
In the above example, if the variable 'some_variable' is not defined, the value used will be 5, rather than an error
being raised.
.. _omitting_undefined_variables:
Omitting Undefined Variables and Parameters
-------------------------------------------
As of Ansible 1.8, it is possible to use the default filter to omit variables and module parameters using the special
`omit` variable::
- name: touch files with an optional mode
file: dest={{item.path}} state=touch mode={{item.mode|default(omit)}}
with_items:
- path: /tmp/foo
- path: /tmp/bar
- path: /tmp/baz
mode: "0444"
For the first two files in the list, the default mode will be determined by the umask of the system as the `mode=`
parameter will not be sent to the file module while the final file will receive the `mode=0444` option.
.. _list_filters:
List Filters
...
...
lib/ansible/runner/__init__.py
View file @
f8a30fae
...
...
@@ -46,12 +46,17 @@ import connection
from
return_data
import
ReturnData
from
ansible.callbacks
import
DefaultRunnerCallbacks
,
vv
from
ansible.module_common
import
ModuleReplacer
from
ansible.module_utils.splitter
import
split_args
from
ansible.module_utils.splitter
import
split_args
,
unquote
from
ansible.cache
import
FactCache
from
ansible.utils
import
update_hash
module_replacer
=
ModuleReplacer
(
strip_comments
=
False
)
try
:
from
hashlib
import
md5
as
_md5
except
ImportError
:
from
md5
import
md5
as
_md5
HAS_ATFORK
=
True
try
:
from
Crypto.Random
import
atfork
...
...
@@ -202,6 +207,7 @@ class Runner(object):
self
.
su_user_var
=
su_user
self
.
su_user
=
None
self
.
su_pass
=
su_pass
self
.
omit_token
=
'__omit_place_holder__
%
s'
%
_md5
(
os
.
urandom
(
64
))
.
hexdigest
()
self
.
vault_pass
=
vault_pass
self
.
no_log
=
no_log
self
.
run_once
=
run_once
...
...
@@ -623,6 +629,7 @@ class Runner(object):
inject
[
'defaults'
]
=
self
.
default_vars
inject
[
'environment'
]
=
self
.
environment
inject
[
'playbook_dir'
]
=
os
.
path
.
abspath
(
self
.
basedir
)
inject
[
'omit'
]
=
self
.
omit_token
# template this one is available, callbacks use this
delegate_to
=
self
.
module_vars
.
get
(
'delegate_to'
)
...
...
@@ -740,14 +747,6 @@ class Runner(object):
if
self
.
su_user_var
is
not
None
:
self
.
su_user
=
template
.
template
(
self
.
basedir
,
self
.
su_user_var
,
inject
)
# allow module args to work as a dictionary
# though it is usually a string
new_args
=
""
if
type
(
module_args
)
==
dict
:
for
(
k
,
v
)
in
module_args
.
iteritems
():
new_args
=
new_args
+
"
%
s='
%
s' "
%
(
k
,
v
)
module_args
=
new_args
# module_name may be dynamic (but cannot contain {{ ansible_ssh_user }})
module_name
=
template
.
template
(
self
.
basedir
,
module_name
,
inject
)
...
...
@@ -872,6 +871,11 @@ class Runner(object):
if
self
.
_early_needs_tmp_path
(
module_name
,
handler
):
tmp
=
self
.
_make_tmp_path
(
conn
)
# allow module args to work as a dictionary
# though it is usually a string
if
isinstance
(
module_args
,
dict
):
module_args
=
utils
.
serialize_args
(
module_args
)
# render module_args and complex_args templates
try
:
# When templating module_args, we need to be careful to ensure
...
...
@@ -892,6 +896,24 @@ class Runner(object):
except
jinja2
.
exceptions
.
UndefinedError
,
e
:
raise
errors
.
AnsibleUndefinedVariable
(
"One or more undefined variables:
%
s"
%
str
(
e
))
# filter omitted arguments out from complex_args
if
complex_args
:
complex_args
=
dict
(
filter
(
lambda
x
:
x
[
1
]
!=
self
.
omit_token
,
complex_args
.
iteritems
()))
# Filter omitted arguments out from module_args.
# We do this with split_args instead of parse_kv to ensure
# that things are not unquoted/requoted incorrectly
args
=
split_args
(
module_args
)
final_args
=
[]
for
arg
in
args
:
if
'='
in
arg
:
k
,
v
=
arg
.
split
(
'='
,
1
)
if
unquote
(
v
)
!=
self
.
omit_token
:
final_args
.
append
(
arg
)
else
:
# not a k=v param, append it
final_args
.
append
(
arg
)
module_args
=
' '
.
join
(
final_args
)
result
=
handler
.
run
(
conn
,
tmp
,
module_name
,
module_args
,
inject
,
complex_args
)
# Code for do until feature
...
...
lib/ansible/runner/filter_plugins/core.py
View file @
f8a30fae
...
...
@@ -31,6 +31,7 @@ from distutils.version import LooseVersion, StrictVersion
from
random
import
SystemRandom
from
jinja2.filters
import
environmentfilter
def
to_nice_yaml
(
*
a
,
**
kw
):
'''Make verbose, human readable yaml'''
return
yaml
.
safe_dump
(
*
a
,
indent
=
4
,
allow_unicode
=
True
,
default_flow_style
=
False
,
**
kw
)
...
...
@@ -234,6 +235,7 @@ def rand(environment, end, start=None, step=None):
else
:
raise
errors
.
AnsibleFilterError
(
'random can only be used on sequences and integers'
)
class
FilterModule
(
object
):
''' Ansible core jinja2 filters '''
...
...
@@ -306,4 +308,3 @@ class FilterModule(object):
# random numbers
'random'
:
rand
,
}
lib/ansible/utils/__init__.py
View file @
f8a30fae
...
...
@@ -61,6 +61,7 @@ LOOKUP_REGEX = re.compile(r'lookup\s*\(')
PRINT_CODE_REGEX
=
re
.
compile
(
r'(?:{[{
%
]|[
%
}]})'
)
CODE_REGEX
=
re
.
compile
(
r'(?:{
%
|
%
})'
)
try
:
import
json
except
ImportError
:
...
...
@@ -110,6 +111,7 @@ try:
except
ImportError
:
pass
###############################################################
# Abstractions around keyczar
###############################################################
...
...
@@ -543,6 +545,18 @@ def parse_json(raw_data, from_remote=False, from_inventory=False):
return
results
def
serialize_args
(
args
):
'''
Flattens a dictionary args to a k=v string
'''
module_args
=
""
for
(
k
,
v
)
in
args
.
iteritems
():
if
isinstance
(
v
,
basestring
):
module_args
=
"
%
s=
%
s
%
s"
%
(
k
,
pipes
.
quote
(
v
),
module_args
)
elif
isinstance
(
v
,
bool
):
module_args
=
"
%
s=
%
s
%
s"
%
(
k
,
str
(
v
),
module_args
)
return
module_args
.
strip
()
def
merge_module_args
(
current_args
,
new_args
):
'''
merges either a dictionary or string of k=v pairs with another string of k=v pairs,
...
...
@@ -557,14 +571,7 @@ def merge_module_args(current_args, new_args):
elif
isinstance
(
new_args
,
basestring
):
new_args_kv
=
parse_kv
(
new_args
)
final_args
.
update
(
new_args_kv
)
# then we re-assemble into a string
module_args
=
""
for
(
k
,
v
)
in
final_args
.
iteritems
():
if
isinstance
(
v
,
basestring
):
module_args
=
"
%
s=
%
s
%
s"
%
(
k
,
pipes
.
quote
(
v
),
module_args
)
elif
isinstance
(
v
,
bool
):
module_args
=
"
%
s=
%
s
%
s"
%
(
k
,
str
(
v
),
module_args
)
return
module_args
.
strip
()
return
serialize_args
(
final_args
)
def
parse_yaml
(
data
,
path_hint
=
None
):
''' convert a yaml string to a data structure. Also supports JSON, ssssssh!!!'''
...
...
test/integration/roles/test_good_parsing/tasks/main.yml
View file @
f8a30fae
...
...
@@ -172,3 +172,33 @@
assert
:
that
:
-
nested_include_var is undefined
-
name
:
test omit in complex args
set_fact
:
foo
:
bar
spam
:
"
{{
omit
}}"
should_not_omit
:
"
prefix{{
omit
}}"
-
assert
:
that
:
-
foo == 'bar'
-
spam is undefined
-
should_not_omit is defined
-
name
:
test omit in module args
set_fact
:
>
yo=whatsup
eggs="{{ omit }}"
default_omitted="{{ not_exists|default(omit) }}"
should_not_omit_1="prefix{{ omit }}"
should_not_omit_2="{{ omit }}suffix"
should_not_omit_3="__omit_place_holder__afb6b9bc3d20bfeaa00a1b23a5930f89"
-
assert
:
that
:
-
yo == 'whatsup'
-
eggs is undefined
-
default_omitted is undefined
-
should_not_omit_1 is defined
-
should_not_omit_2 is defined
-
should_not_omit_3 == "__omit_place_holder__afb6b9bc3d20bfeaa00a1b23a5930f89"
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