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
c83a8337
Commit
c83a8337
authored
Oct 08, 2014
by
James Cammarata
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New v2 ModuleArgsParser code and fixing up tests/other task code
parent
bbd9921d
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
91 additions
and
89 deletions
+91
-89
test/v2/parsing/test_mod_args.py
+30
-28
test/v2/playbook/test_task.py
+5
-4
v2/ansible/parsing/mod_args.py
+0
-0
v2/ansible/parsing/splitter.py
+31
-4
v2/ansible/playbook/task.py
+25
-53
No files found.
test/v2/parsing/test_mod_args.py
View file @
c83a8337
...
...
@@ -13,67 +13,69 @@ class TestModArgsDwim(unittest.TestCase):
pass
def
test_action_to_shell
(
self
):
mod
,
args
,
to
=
self
.
m
.
parse
(
'action'
,
'shell echo hi'
)
assert
mod
==
'
shell
'
mod
,
args
,
to
=
self
.
m
.
parse
(
dict
(
action
=
'shell echo hi'
)
)
assert
mod
==
'
command
'
assert
args
==
dict
(
free_form
=
'echo hi'
,
use_shell
=
True
_raw_params
=
'echo hi'
,
_uses_shell
=
True
,
)
assert
to
is
None
def
test_basic_shell
(
self
):
mod
,
args
,
to
=
self
.
m
.
parse
(
'shell'
,
'echo hi'
)
assert
mod
==
'
shell
'
mod
,
args
,
to
=
self
.
m
.
parse
(
dict
(
shell
=
'echo hi'
)
)
assert
mod
==
'
command
'
assert
args
==
dict
(
free_form
=
'echo hi'
,
use_shell
=
True
_raw_params
=
'echo hi'
,
_uses_shell
=
True
,
)
assert
to
is
None
def
test_basic_command
(
self
):
mod
,
args
,
to
=
self
.
m
.
parse
(
'command'
,
'echo hi'
)
mod
,
args
,
to
=
self
.
m
.
parse
(
dict
(
command
=
'echo hi'
)
)
assert
mod
==
'command'
assert
args
==
dict
(
free_form
=
'echo hi'
,
use_shell
=
False
_raw_params
=
'echo hi'
,
)
assert
to
is
None
def
test_shell_with_modifiers
(
self
):
mod
,
args
,
to
=
self
.
m
.
parse
(
'shell'
,
'/bin/foo creates=/tmp/baz removes=/tmp/bleep'
)
assert
mod
==
'
shell
'
mod
,
args
,
to
=
self
.
m
.
parse
(
dict
(
shell
=
'/bin/foo creates=/tmp/baz removes=/tmp/bleep'
)
)
assert
mod
==
'
command
'
assert
args
==
dict
(
free_form
=
'echo hi
'
,
use_shell
=
False
,
creates
=
'/tmp/baz
'
,
removes
=
'/tmp/bleep'
creates
=
'/tmp/baz
'
,
removes
=
'/tmp/bleep'
,
_raw_params
=
'/bin/foo
'
,
_uses_shell
=
True
,
)
assert
to
is
None
def
test_normal_usage
(
self
):
mod
,
args
,
to
=
self
.
m
.
parse
(
'copy'
,
'src=a dest=b'
)
mod
,
args
,
to
=
self
.
m
.
parse
(
dict
(
copy
=
'src=a dest=b'
)
)
assert
mod
==
'copy'
assert
args
==
dict
(
src
=
'a'
,
dest
=
'b'
)
assert
to
is
None
def
test_complex_args
(
self
):
mod
,
args
,
to
=
self
.
m
.
parse
(
'copy'
,
dict
(
src
=
a
,
dest
=
b
))
mod
,
args
,
to
=
self
.
m
.
parse
(
dict
(
copy
=
dict
(
src
=
'a'
,
dest
=
'b'
)
))
assert
mod
==
'copy'
assert
args
==
dict
(
src
=
'a'
,
dest
=
'b'
)
assert
args
==
dict
(
src
=
'a'
,
dest
=
'b'
)
assert
to
is
None
def
test_action_with_complex
(
self
):
mod
,
args
,
to
=
self
.
m
.
parse
(
'action'
,
dict
(
module
=
'copy'
,
src
=
'a'
,
dest
=
'b'
))
assert
mod
==
'action'
assert
args
==
dict
(
src
=
'a'
,
dest
=
'b'
)
mod
,
args
,
to
=
self
.
m
.
parse
(
dict
(
action
=
dict
(
module
=
'copy'
,
src
=
'a'
,
dest
=
'b'
)))
assert
mod
==
'copy'
assert
args
==
dict
(
src
=
'a'
,
dest
=
'b'
)
assert
to
is
None
def
test_action_with_complex_and_complex_args
(
self
):
mod
,
args
,
to
=
self
.
m
.
parse
(
dict
(
action
=
dict
(
module
=
'copy'
,
args
=
dict
(
src
=
'a'
,
dest
=
'b'
))))
assert
mod
==
'copy'
assert
args
==
dict
(
src
=
'a'
,
dest
=
'b'
)
assert
to
is
None
def
test_local_action_string
(
self
):
mod
,
args
,
to
=
self
.
m
.
parse
(
'local_action'
,
'copy src=a dest=b'
)
mod
,
args
,
to
=
self
.
m
.
parse
(
dict
(
local_action
=
'copy src=a dest=b'
)
)
assert
mod
==
'copy'
assert
args
==
dict
(
src
=
a
,
dest
=
b
)
assert
args
==
dict
(
src
=
'a'
,
dest
=
'b'
)
assert
to
is
'localhost'
test/v2/playbook/test_task.py
View file @
c83a8337
...
...
@@ -36,13 +36,14 @@ class TestTask(unittest.TestCase):
t
=
Task
.
load
(
basic_shell_task
)
assert
t
is
not
None
assert
t
.
name
==
basic_shell_task
[
'name'
]
assert
t
.
action
==
'
shell
'
assert
t
.
args
==
'echo hi'
assert
t
.
action
==
'
command
'
assert
t
.
args
==
dict
(
_raw_params
=
'echo hi'
,
_uses_shell
=
True
)
def
test_load_task_kv_form
(
self
):
t
=
Task
.
load
(
kv_shell_task
)
assert
t
.
action
==
'shell'
#assert t.args == 'echo hi'
print
"task action is
%
s"
%
t
.
action
assert
t
.
action
==
'command'
assert
t
.
args
==
dict
(
_raw_params
=
'echo hi'
,
_uses_shell
=
True
)
def
test_task_auto_name
(
self
):
assert
'name'
not
in
kv_shell_task
...
...
v2/ansible/parsing/mod_args.py
View file @
c83a8337
This diff is collapsed.
Click to expand it.
v2/ansible/parsing/splitter.py
View file @
c83a8337
...
...
@@ -15,8 +15,14 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
def
parse_kv
(
args
):
''' convert a string of key/value items to a dict '''
def
parse_kv
(
args
,
check_raw
=
False
):
'''
Convert a string of key/value items to a dict. If any free-form params
are found and the check_raw option is set to True, they will be added
to a new parameter called '_raw_params'. If check_raw is not enabled,
they will simply be ignored.
'''
options
=
{}
if
args
is
not
None
:
try
:
...
...
@@ -26,10 +32,31 @@ def parse_kv(args):
raise
errors
.
AnsibleError
(
"error parsing argument string, try quoting the entire line."
)
else
:
raise
raw_params
=
[]
for
x
in
vargs
:
if
"="
in
x
:
k
,
v
=
x
.
split
(
"="
,
1
)
options
[
k
.
strip
()]
=
unquote
(
v
.
strip
())
k
,
v
=
x
.
split
(
"="
,
1
)
# only internal variables can start with an underscore, so
# we don't allow users to set them directy in arguments
if
k
.
startswith
(
'_'
):
raise
AnsibleError
(
"invalid parameter specified: '
%
s'"
%
k
)
# FIXME: make the retrieval of this list of shell/command
# options a function, so the list is centralized
if
check_raw
and
k
not
in
(
'creates'
,
'removes'
,
'chdir'
,
'executable'
,
'warn'
):
raw_params
.
append
(
x
)
else
:
options
[
k
.
strip
()]
=
unquote
(
v
.
strip
())
else
:
raw_params
.
append
(
x
)
# recombine the free-form params, if any were found, and assign
# them to a special option for use later by the shell/command module
if
len
(
raw_params
)
>
0
:
options
[
'_raw_params'
]
=
' '
.
join
(
raw_params
)
return
options
def
_get_quote_state
(
token
,
quote_char
):
...
...
v2/ansible/playbook/task.py
View file @
c83a8337
...
...
@@ -18,13 +18,10 @@
from
ansible.playbook.base
import
Base
from
ansible.playbook.attribute
import
Attribute
,
FieldAttribute
# from ansible.playbook.conditional import Conditional
from
ansible.errors
import
AnsibleError
# TODO: it would be fantastic (if possible) if a task new where in the YAML it was defined for describing
# it in error conditions
from
ansible.parsing.splitter
import
parse_kv
from
ansible.parsing.mod_args
import
ModuleArgsParser
from
ansible.plugins
import
module_finder
,
lookup_finder
class
Task
(
Base
):
...
...
@@ -45,7 +42,6 @@ class Task(Base):
# validate_<attribute_name>
# will be used if defined
# might be possible to define others
_args
=
FieldAttribute
(
isa
=
'dict'
)
_action
=
FieldAttribute
(
isa
=
'string'
)
...
...
@@ -60,9 +56,6 @@ class Task(Base):
_first_available_file
=
FieldAttribute
(
isa
=
'list'
)
_ignore_errors
=
FieldAttribute
(
isa
=
'bool'
)
# FIXME: this should not be a Task
# include = FieldAttribute(isa='string')
_loop
=
FieldAttribute
(
isa
=
'string'
,
private
=
True
)
_loop_args
=
FieldAttribute
(
isa
=
'list'
,
private
=
True
)
_local_action
=
FieldAttribute
(
isa
=
'string'
)
...
...
@@ -102,16 +95,19 @@ class Task(Base):
elif
self
.
name
:
return
self
.
name
else
:
return
"
%
s
%
s"
%
(
self
.
action
,
self
.
_merge_kv
(
self
.
args
))
flattened_args
=
self
.
_merge_kv
(
self
.
args
)
return
"
%
s
%
s"
%
(
self
.
action
,
flattened_args
)
def
_merge_kv
(
self
,
ds
):
if
ds
is
None
:
return
""
elif
isinstance
(
ds
,
basestring
):
return
ds
elif
instance
(
ds
,
dict
):
elif
i
si
nstance
(
ds
,
dict
):
buf
=
""
for
(
k
,
v
)
in
ds
.
iteritems
():
if
k
.
startswith
(
'_'
):
continue
buf
=
buf
+
"
%
s=
%
s "
%
(
k
,
v
)
buf
=
buf
.
strip
()
return
buf
...
...
@@ -125,27 +121,6 @@ class Task(Base):
''' returns a human readable representation of the task '''
return
"TASK:
%
s"
%
self
.
get_name
()
def
_parse_old_school_action
(
self
,
v
):
''' given a action/local_action line, return the module and args '''
tokens
=
v
.
split
()
if
len
(
tokens
)
<
2
:
return
[
v
,{}]
else
:
if
v
not
in
[
'command'
,
'shell'
]:
joined
=
" "
.
join
(
tokens
[
1
:])
return
[
tokens
[
0
],
parse_kv
(
joined
)]
else
:
return
[
tokens
[
0
],
joined
]
def
_munge_action
(
self
,
ds
,
new_ds
,
k
,
v
):
''' take a module name and split into action and args '''
if
self
.
_action
.
value
is
not
None
or
'action'
in
ds
or
'local_action'
in
ds
:
raise
AnsibleError
(
"duplicate action in task:
%
s"
%
k
)
new_ds
[
'action'
]
=
k
new_ds
[
'args'
]
=
v
def
_munge_loop
(
self
,
ds
,
new_ds
,
k
,
v
):
''' take a lookup plugin name and store it correctly '''
...
...
@@ -154,22 +129,6 @@ class Task(Base):
new_ds
[
'loop'
]
=
k
new_ds
[
'loop_args'
]
=
v
def
_munge_action2
(
self
,
ds
,
new_ds
,
k
,
v
,
local
=
False
):
''' take an old school action/local_action and reformat it '''
if
isinstance
(
v
,
basestring
):
tokens
=
self
.
_parse_old_school_action
(
v
)
new_ds
[
'action'
]
=
tokens
[
0
]
if
'args'
in
ds
:
raise
AnsibleError
(
"unexpected and redundant 'args'"
)
new_ds
[
'args'
]
=
args
if
local
:
if
'delegate_to'
in
ds
:
raise
AnsbileError
(
"local_action and action conflict"
)
new_ds
[
'delegate_to'
]
=
'localhost'
else
:
raise
AnsibleError
(
"unexpected use of 'action'"
)
def
munge
(
self
,
ds
):
'''
tasks are especially complex arguments so need pre-processing.
...
...
@@ -178,18 +137,31 @@ class Task(Base):
assert
isinstance
(
ds
,
dict
)
# the new, cleaned datastructure, which will have legacy
# items reduced to a standard structure suitable for the
# attributes of the task class
new_ds
=
dict
()
# use the args parsing class to determine the action, args,
# and the delegate_to value from the various possible forms
# supported as legacy
args_parser
=
ModuleArgsParser
()
(
action
,
args
,
delegate_to
)
=
args_parser
.
parse
(
ds
)
new_ds
[
'action'
]
=
action
new_ds
[
'args'
]
=
args
new_ds
[
'delegate_to'
]
=
delegate_to
for
(
k
,
v
)
in
ds
.
iteritems
():
if
k
in
module_finder
:
self
.
_munge_action
(
ds
,
new_ds
,
k
,
v
)
if
k
in
(
'action'
,
'local_action'
,
'args'
,
'delegate_to'
)
or
k
==
action
:
# we don't want to re-assign these values, which were
# determined by the ModuleArgsParser() above
continue
elif
"with_
%
s"
%
k
in
lookup_finder
:
self
.
_munge_loop
(
ds
,
new_ds
,
k
,
v
)
elif
k
==
'action'
:
self
.
_munge_action2
(
ds
,
new_ds
,
k
,
v
)
elif
k
==
'local_action'
:
self
.
_munge_action2
(
ds
,
new_ds
,
k
,
v
,
local
=
True
)
else
:
new_ds
[
k
]
=
v
return
new_ds
...
...
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