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
56b6cb53
Commit
56b6cb53
authored
Oct 08, 2014
by
Michael DeHaan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Teaching objects to load themselves, making the JSON/YAML parsing ambidexterous.
parent
c75aeca4
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
146 additions
and
25 deletions
+146
-25
test/v2/parsing/__init__.py
+1
-0
test/v2/parsing/test_general.py
+85
-0
test/v2/parsing/test_mod_args.py
+4
-1
test/v2/parsing/yaml/__init__.py
+0
-1
test/v2/playbook/test_task.py
+0
-2
v2/ansible/errors/__init__.py
+27
-0
v2/ansible/parsing/__init__.py
+17
-0
v2/ansible/parsing/mod_args.py
+8
-17
v2/ansible/parsing/yaml/__init__.py
+0
-1
v2/ansible/playbook/attribute.py
+0
-1
v2/ansible/playbook/base.py
+4
-1
v2/ansible/playbook/task.py
+0
-1
No files found.
test/v2/parsing/__init__.py
View file @
56b6cb53
test/v2/parsing/test_general.py
0 → 100644
View file @
56b6cb53
# TODO: header
import
unittest
from
ansible.parsing
import
load
from
ansible.errors
import
AnsibleParserError
import
json
class
MockFile
(
file
):
def
__init__
(
self
,
ds
,
method
=
'json'
):
self
.
ds
=
ds
self
.
method
=
method
def
read
(
self
):
if
method
==
'json'
:
return
json
.
dumps
(
ds
)
elif
method
==
'yaml'
:
return
yaml
.
dumps
(
ds
)
elif
method
==
'fail'
:
return
"""
AAARGGGGH
THIS WON'T PARSE !!!
NOOOOOOOOOOOOOOOOOO
"""
else
:
raise
Exception
(
"untestable serializer"
)
def
close
(
self
):
pass
class
TestGeneralParsing
(
unittest
.
TestCase
):
def
__init__
(
self
):
pass
def
setUp
(
self
):
pass
def
tearDown
(
self
):
pass
def
parse_json_from_string
(
self
):
input
=
"""
{
"asdf" : "1234",
"jkl" : 5678
}
"""
output
=
load
(
input
)
assert
output
[
'asdf'
]
==
'1234'
assert
output
[
'jkl'
]
==
5678
def
parse_json_from_file
(
self
):
output
=
load
(
MockFile
(
dict
(
a
=
1
,
b
=
2
,
c
=
3
)),
'json'
)
assert
ouput
==
dict
(
a
=
1
,
b
=
2
,
c
=
3
)
def
parse_yaml_from_dict
(
self
):
input
=
"""
asdf: '1234'
jkl: 5678
"""
output
=
load
(
input
)
assert
output
[
'asdf'
]
==
'1234'
assert
output
[
'jkl'
]
==
5678
def
parse_yaml_from_file
(
self
):
output
=
load
(
MockFile
(
dict
(
a
=
1
,
b
=
2
,
c
=
3
),
'yaml'
))
assert
output
==
dict
(
a
=
1
,
b
=
2
,
c
=
3
)
def
parse_fail
(
self
):
input
=
"""
TEXT
***
NOT VALID
"""
self
.
failUnlessRaises
(
load
(
input
),
AnsibleParserError
)
def
parse_fail_from_file
(
self
):
self
.
failUnlessRaises
(
load
(
MockFile
(
None
,
'fail'
)),
AnsibleParserError
)
def
parse_fail_invalid_type
(
self
):
self
.
failUnlessRaises
(
3000
,
AnsibleParsingError
)
self
.
failUnlessRaises
(
dict
(
a
=
1
,
b
=
2
,
c
=
3
),
AnsibleParserError
)
test/v2/parsing/test_mod_args.py
View file @
56b6cb53
...
...
@@ -5,6 +5,10 @@ import unittest
class
TestModArgsDwim
(
unittest
.
TestCase
):
# TODO: add tests that construct ModuleArgsParser with a task reference
# TODO: verify the AnsibleError raised on failure knows the task
# and the task knows the line numbers
def
setUp
(
self
):
self
.
m
=
ModuleArgsParser
()
pass
...
...
@@ -78,4 +82,3 @@ class TestModArgsDwim(unittest.TestCase):
assert
mod
==
'copy'
assert
args
==
dict
(
src
=
'a'
,
dest
=
'b'
)
assert
to
is
'localhost'
test/v2/parsing/yaml/__init__.py
View file @
56b6cb53
# TODO: header
test/v2/playbook/test_task.py
View file @
56b6cb53
...
...
@@ -67,5 +67,3 @@ class TestTask(unittest.TestCase):
def
test_delegate_to_parses
(
self
):
pass
v2/ansible/errors/__init__.py
View file @
56b6cb53
...
...
@@ -16,4 +16,31 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
class
AnsibleError
(
Exception
):
def
__init__
(
self
,
message
,
object
=
None
):
self
.
message
=
message
self
.
object
=
object
# TODO: nice __repr__ message that includes the line number if the object
# it was constructed with had the line number
# TODO: tests for the line number functionality
class
AnsibleParserError
(
AnsibleError
):
''' something was detected early that is wrong about a playbook or data file '''
pass
class
AnsibleInternalError
(
AnsibleError
):
''' internal safeguards tripped, something happened in the code that should never happen '''
pass
class
AnsibleRuntimeError
(
AnsibleError
):
''' ansible had a problem while running a playbook '''
pass
class
AnsibleModuleError
(
AnsibleRuntimeError
):
''' a module failed somehow '''
pass
class
AnsibleConnectionFailure
(
AnsibleRuntimeError
):
''' the transport / connection_plugin had a fatal error '''
pass
v2/ansible/parsing/__init__.py
View file @
56b6cb53
# TODO: header
from
ansible.errors
import
AnsibleError
,
AnsibleInternalError
def
load
(
self
,
data
):
if
instanceof
(
data
,
file
):
fd
=
open
(
f
)
data
=
fd
.
read
()
fd
.
close
()
if
instanceof
(
data
,
basestring
):
try
:
return
json
.
loads
(
data
)
except
:
return
safe_load
(
data
)
raise
AnsibleInternalError
(
"expected file or string, got
%
s"
%
type
(
data
))
v2/ansible/parsing/mod_args.py
View file @
56b6cb53
...
...
@@ -55,15 +55,16 @@ class ModuleArgsParser(object):
will tell you about the modules in a predictable way.
"""
def
__init__
(
self
):
def
__init__
(
self
,
task
=
None
):
self
.
_ds
=
None
self
.
_task
=
task
def
_get_delegate_to
(
self
):
'''
Returns the value of the delegate_to key from the task datastructure,
or None if the value was not directly specified
'''
return
self
.
_ds
.
get
(
'delegate_to'
)
return
self
.
_ds
.
get
(
'delegate_to'
,
None
)
def
_get_old_style_action
(
self
):
'''
...
...
@@ -108,29 +109,24 @@ class ModuleArgsParser(object):
if
'module'
in
other_args
:
del
other_args
[
'module'
]
args
.
update
(
other_args
)
elif
isinstance
(
action_data
,
basestring
):
action_data
=
action_data
.
strip
()
if
not
action_data
:
# TODO: change to an AnsibleParsingError so that the
# filename/line number can be reported in the error
raise
AnsibleError
(
"when using 'action:' or 'local_action:', the module name must be specified"
)
raise
AnsibleError
(
"when using 'action:' or 'local_action:', the module name must be specified"
,
object
=
self
.
_task
)
else
:
# split up the string based on spaces, where the first
# item specified must be a valid module name
parts
=
action_data
.
split
(
' '
,
1
)
action
=
parts
[
0
]
if
action
not
in
module_finder
:
# TODO: change to an AnsibleParsingError so that the
# filename/line number can be reported in the error
raise
AnsibleError
(
"the module '
%
s' was not found in the list of loaded modules"
)
raise
AnsibleError
(
"the module '
%
s' was not found in the list of loaded modules"
%
action
,
object
=
self
.
_task
)
if
len
(
parts
)
>
1
:
args
=
self
.
_get_args_from_action
(
action
,
' '
.
join
(
parts
[
1
:]))
else
:
args
=
{}
else
:
# TODO: change to an AnsibleParsingError so that the
# filename/line number can be reported in the error
raise
AnsibleError
(
'module args must be specified as a dictionary or string'
)
raise
AnsibleError
(
'module args must be specified as a dictionary or string'
,
object
=
self
.
_task
)
return
dict
(
action
=
action
,
args
=
args
,
delegate_to
=
delegate_to
)
...
...
@@ -286,9 +282,7 @@ class ModuleArgsParser(object):
# where 'action' or 'local_action' is the key
result
=
self
.
_get_old_style_action
()
if
result
is
None
:
# TODO: change to an AnsibleParsingError so that the
# filename/line number can be reported in the error
raise
AnsibleError
(
'no action specified for this task'
)
raise
AnsibleError
(
'no action specified for this task'
,
object
=
self
.
_task
)
# if the action is set to 'shell', we switch that to 'command' and
# set the special parameter '_uses_shell' to true in the args dict
...
...
@@ -302,11 +296,8 @@ class ModuleArgsParser(object):
specified_delegate_to
=
self
.
_get_delegate_to
()
if
specified_delegate_to
is
not
None
:
if
result
[
'delegate_to'
]
is
not
None
:
# TODO: change to an AnsibleParsingError so that the
# filename/line number can be reported in the error
raise
AnsibleError
(
'delegate_to cannot be used with local_action'
)
else
:
result
[
'delegate_to'
]
=
specified_delegate_to
return
(
result
[
'action'
],
result
[
'args'
],
result
[
'delegate_to'
])
v2/ansible/parsing/yaml/__init__.py
View file @
56b6cb53
...
...
@@ -4,4 +4,3 @@ from ansible.parsing.yaml.loader import AnsibleLoader
def
safe_load
(
stream
):
''' implements yaml.safe_load(), except using our custom loader class '''
return
load
(
stream
,
AnsibleLoader
)
v2/ansible/playbook/attribute.py
View file @
56b6cb53
...
...
@@ -31,4 +31,3 @@ class Attribute(object):
class
FieldAttribute
(
Attribute
):
pass
v2/ansible/playbook/base.py
View file @
56b6cb53
...
...
@@ -16,6 +16,7 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from
ansible.playbook.attribute
import
Attribute
,
FieldAttribute
from
ansible.parsing
import
load
as
ds_load
class
Base
(
object
):
...
...
@@ -39,6 +40,9 @@ class Base(object):
assert
ds
is
not
None
if
isinstance
(
ds
,
basestring
)
or
isinstance
(
ds
,
file
):
ds
=
ds_load
(
ds
)
# we currently don't do anything with private attributes but may
# later decide to filter them out of 'ds' here.
...
...
@@ -107,4 +111,3 @@ class Base(object):
return
self
.
_attributes
[
needle
]
raise
AttributeError
(
"attribute not found:
%
s"
%
needle
)
v2/ansible/playbook/task.py
View file @
56b6cb53
...
...
@@ -342,4 +342,3 @@ LEGACY = """
raise AnsibleError("with_(plugin), and first_available_file are mutually incompatible in a single task")
"""
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