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
5d8c9d3f
Commit
5d8c9d3f
authored
Mar 17, 2014
by
James Cammarata
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'file_fixes_clean' of
https://github.com/bcoca/ansible
into bcoca-file_fixes_clean
parents
7edee91a
2d25577e
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
112 additions
and
115 deletions
+112
-115
lib/ansible/module_utils/basic.py
+6
-15
library/files/file
+87
-100
test/integration/roles/test_file/tasks/main.yml
+19
-0
No files found.
lib/ansible/module_utils/basic.py
View file @
5d8c9d3f
...
@@ -464,7 +464,7 @@ class AnsibleModule(object):
...
@@ -464,7 +464,7 @@ class AnsibleModule(object):
changed
=
True
changed
=
True
return
changed
return
changed
def
set_f
ile
_attributes_if_different
(
self
,
file_args
,
changed
):
def
set_f
s
_attributes_if_different
(
self
,
file_args
,
changed
):
# set modes owners and context as needed
# set modes owners and context as needed
changed
=
self
.
set_context_if_different
(
changed
=
self
.
set_context_if_different
(
file_args
[
'path'
],
file_args
[
'secontext'
],
changed
file_args
[
'path'
],
file_args
[
'secontext'
],
changed
...
@@ -481,19 +481,10 @@ class AnsibleModule(object):
...
@@ -481,19 +481,10 @@ class AnsibleModule(object):
return
changed
return
changed
def
set_directory_attributes_if_different
(
self
,
file_args
,
changed
):
def
set_directory_attributes_if_different
(
self
,
file_args
,
changed
):
changed
=
self
.
set_context_if_different
(
return
self
.
set_fs_attributes_if_different
(
file_args
,
changed
)
file_args
[
'path'
],
file_args
[
'secontext'
],
changed
)
def
set_file_attributes_if_different
(
self
,
file_args
,
changed
):
changed
=
self
.
set_owner_if_different
(
return
self
.
set_fs_attributes_if_different
(
file_args
,
changed
)
file_args
[
'path'
],
file_args
[
'owner'
],
changed
)
changed
=
self
.
set_group_if_different
(
file_args
[
'path'
],
file_args
[
'group'
],
changed
)
changed
=
self
.
set_mode_if_different
(
file_args
[
'path'
],
file_args
[
'mode'
],
changed
)
return
changed
def
add_path_info
(
self
,
kwargs
):
def
add_path_info
(
self
,
kwargs
):
'''
'''
...
@@ -963,7 +954,7 @@ class AnsibleModule(object):
...
@@ -963,7 +954,7 @@ class AnsibleModule(object):
context
=
self
.
selinux_default_context
(
dest
)
context
=
self
.
selinux_default_context
(
dest
)
try
:
try
:
# Optimistically try a rename, solves some corner cases and can avoid useless work.
# Optimistically try a rename, solves some corner cases and can avoid useless work
, throws exception if not atomic
.
os
.
rename
(
src
,
dest
)
os
.
rename
(
src
,
dest
)
except
(
IOError
,
OSError
),
e
:
except
(
IOError
,
OSError
),
e
:
# only try workarounds for errno 18 (cross device), 1 (not permited) and 13 (permission denied)
# only try workarounds for errno 18 (cross device), 1 (not permited) and 13 (permission denied)
...
...
library/files/file
View file @
5d8c9d3f
...
@@ -139,9 +139,6 @@ EXAMPLES = '''
...
@@ -139,9 +139,6 @@ EXAMPLES = '''
def
main
():
def
main
():
# FIXME: pass this around, should not use global
global
module
module
=
AnsibleModule
(
module
=
AnsibleModule
(
argument_spec
=
dict
(
argument_spec
=
dict
(
state
=
dict
(
choices
=
[
'file'
,
'directory'
,
'link'
,
'hard'
,
'touch'
,
'absent'
],
default
=
None
),
state
=
dict
(
choices
=
[
'file'
,
'directory'
,
'link'
,
'hard'
,
'touch'
,
'absent'
],
default
=
None
),
...
@@ -151,6 +148,7 @@ def main():
...
@@ -151,6 +148,7 @@ def main():
force
=
dict
(
required
=
False
,
default
=
False
,
type
=
'bool'
),
force
=
dict
(
required
=
False
,
default
=
False
,
type
=
'bool'
),
diff_peek
=
dict
(
default
=
None
),
diff_peek
=
dict
(
default
=
None
),
validate
=
dict
(
required
=
False
,
default
=
None
),
validate
=
dict
(
required
=
False
,
default
=
None
),
src
=
dict
(
required
=
False
,
default
=
None
),
),
),
add_file_common_args
=
True
,
add_file_common_args
=
True
,
supports_check_mode
=
True
supports_check_mode
=
True
...
@@ -159,10 +157,14 @@ def main():
...
@@ -159,10 +157,14 @@ def main():
params
=
module
.
params
params
=
module
.
params
state
=
params
[
'state'
]
state
=
params
[
'state'
]
force
=
params
[
'force'
]
force
=
params
[
'force'
]
diff_peek
=
params
[
'diff_peek'
]
src
=
params
[
'src'
]
# modify source as we later reload and pass, specially relevant when used by other modules.
params
[
'path'
]
=
path
=
os
.
path
.
expanduser
(
params
[
'path'
])
params
[
'path'
]
=
path
=
os
.
path
.
expanduser
(
params
[
'path'
])
# short-circuit for diff_peek
# short-circuit for diff_peek
if
params
.
get
(
'diff_peek'
,
None
)
is
not
None
:
if
diff_peek
is
not
None
:
appears_binary
=
False
appears_binary
=
False
try
:
try
:
f
=
open
(
path
)
f
=
open
(
path
)
...
@@ -174,8 +176,8 @@ def main():
...
@@ -174,8 +176,8 @@ def main():
pass
pass
module
.
exit_json
(
path
=
path
,
changed
=
False
,
appears_binary
=
appears_binary
)
module
.
exit_json
(
path
=
path
,
changed
=
False
,
appears_binary
=
appears_binary
)
# Find out current state
prev_state
=
'absent'
prev_state
=
'absent'
if
os
.
path
.
lexists
(
path
):
if
os
.
path
.
lexists
(
path
):
if
os
.
path
.
islink
(
path
):
if
os
.
path
.
islink
(
path
):
prev_state
=
'link'
prev_state
=
'link'
...
@@ -187,76 +189,60 @@ def main():
...
@@ -187,76 +189,60 @@ def main():
# could be many other things, but defaulting to file
# could be many other things, but defaulting to file
prev_state
=
'file'
prev_state
=
'file'
if
prev_state
is
not
None
and
state
is
None
:
# state should default to file, but since that creates many conflicts,
# set state to current type of file
# default to 'current' when it exists.
state
=
prev_state
if
state
is
None
:
elif
state
is
None
:
if
prev_state
!=
'absent'
:
# set default state to file
state
=
prev_state
state
=
'file'
else
:
state
=
'file'
# source is both the source of a symlink or an informational passing of the src for a template module
# source is both the source of a symlink or an informational passing of the src for a template module
# or copy module, even if this module never uses it, it is needed to key off some things
# or copy module, even if this module never uses it, it is needed to key off some things
if
src
is
not
None
:
src
=
params
.
get
(
'src'
,
None
)
if
src
:
src
=
os
.
path
.
expanduser
(
src
)
src
=
os
.
path
.
expanduser
(
src
)
if
src
is
not
None
and
os
.
path
.
isdir
(
path
)
and
state
not
in
[
"link"
,
"absent"
]:
# original_basename is used by other modules that depend on file.
if
params
[
'original_basename'
]:
if
os
.
path
.
isdir
(
path
)
and
state
not
in
[
"link"
,
"absent"
,
"directory"
]:
basename
=
params
[
'original_basename'
]
if
params
[
'original_basename'
]:
else
:
basename
=
params
[
'original_basename'
]
basename
=
os
.
path
.
basename
(
src
)
else
:
params
[
'path'
]
=
path
=
os
.
path
.
join
(
path
,
basename
)
basename
=
os
.
path
.
basename
(
src
)
params
[
'path'
]
=
path
=
os
.
path
.
join
(
path
,
basename
)
else
:
if
state
in
[
'link'
,
'hard'
]:
module
.
fail_json
(
msg
=
'src and dest are required for creating links'
)
file_args
=
module
.
load_file_common_arguments
(
params
)
file_args
=
module
.
load_file_common_arguments
(
params
)
if
state
in
[
'link'
,
'hard'
]
and
(
src
is
None
or
path
is
None
):
module
.
fail_json
(
msg
=
'src and dest are required for creating links'
)
elif
path
is
None
:
module
.
fail_json
(
msg
=
'path is required'
)
changed
=
False
changed
=
False
recurse
=
params
[
'recurse'
]
recurse
=
params
[
'recurse'
]
if
recurse
and
state
!=
'directory'
:
module
.
fail_json
(
path
=
path
,
msg
=
"recurse option requires state to be 'directory'"
)
if
recurse
and
state
==
'file'
and
prev_state
==
'directory'
:
if
state
==
'absent'
:
state
=
'directory'
if
state
!=
prev_state
:
if
not
module
.
check_mode
:
if
prev_state
!=
'absent'
and
state
==
'absent'
:
if
prev_state
==
'directory'
:
try
:
if
prev_state
==
'directory'
:
if
os
.
path
.
islink
(
path
):
if
module
.
check_mode
:
module
.
exit_json
(
changed
=
True
)
os
.
unlink
(
path
)
else
:
try
:
try
:
if
module
.
check_mode
:
module
.
exit_json
(
changed
=
True
)
shutil
.
rmtree
(
path
,
ignore_errors
=
False
)
shutil
.
rmtree
(
path
,
ignore_errors
=
False
)
except
Exception
,
e
:
except
Exception
,
e
:
module
.
fail_json
(
msg
=
"rmtree failed:
%
s"
%
str
(
e
))
module
.
fail_json
(
msg
=
"rmtree failed:
%
s"
%
str
(
e
))
else
:
else
:
if
module
.
check_mode
:
try
:
module
.
exit_json
(
changed
=
True
)
os
.
unlink
(
path
)
os
.
unlink
(
path
)
except
Exception
,
e
:
except
Exception
,
e
:
module
.
fail_json
(
path
=
path
,
msg
=
"unlinking failed:
%
s "
%
str
(
e
))
module
.
fail_json
(
path
=
path
,
msg
=
str
(
e
))
module
.
exit_json
(
path
=
path
,
changed
=
True
)
module
.
exit_json
(
path
=
path
,
changed
=
True
)
else
:
module
.
exit_json
(
path
=
path
,
changed
=
False
)
if
prev_state
!=
'absent'
and
prev_state
!=
state
:
if
not
(
force
and
(
prev_state
==
'file'
or
prev_state
==
'hard'
or
prev_state
==
'directory'
)
and
state
==
'link'
)
and
state
!=
'touch'
:
module
.
fail_json
(
path
=
path
,
msg
=
'refusing to convert between
%
s and
%
s for
%
s'
%
(
prev_state
,
state
,
src
))
if
prev_state
==
'absent'
and
state
==
'absent'
:
module
.
exit_json
(
path
=
path
,
changed
=
False
)
if
state
==
'file'
:
if
prev_state
!=
'file'
:
elif
state
==
'file'
:
module
.
fail_json
(
path
=
path
,
msg
=
'file (
%
s) does not exist, use copy or template module to create'
%
path
)
if
state
!=
prev_state
:
# file is not absent and any other state is a conflict
module
.
fail_json
(
path
=
path
,
msg
=
'file (
%
s) is
%
s, cannot continue'
%
(
path
,
prev_state
))
changed
=
module
.
set_f
ile
_attributes_if_different
(
file_args
,
changed
)
changed
=
module
.
set_f
s
_attributes_if_different
(
file_args
,
changed
)
module
.
exit_json
(
path
=
path
,
changed
=
changed
)
module
.
exit_json
(
path
=
path
,
changed
=
changed
)
elif
state
==
'directory'
:
elif
state
==
'directory'
:
...
@@ -266,31 +252,29 @@ def main():
...
@@ -266,31 +252,29 @@ def main():
os
.
makedirs
(
path
)
os
.
makedirs
(
path
)
changed
=
True
changed
=
True
changed
=
module
.
set_directory_attributes_if_different
(
file_args
,
changed
)
changed
=
module
.
set_fs_attributes_if_different
(
file_args
,
changed
)
if
recurse
:
if
recurse
:
for
root
,
dirs
,
files
in
os
.
walk
(
file_args
[
'path'
]
):
for
root
,
dirs
,
files
in
os
.
walk
(
file_args
[
'path'
]
):
for
dir
in
dir
s
:
for
fsobj
in
dirs
+
file
s
:
dirname
=
os
.
path
.
join
(
root
,
dir
)
fsname
=
os
.
path
.
join
(
root
,
fsobj
)
tmp_file_args
=
file_args
.
copy
()
tmp_file_args
=
file_args
.
copy
()
tmp_file_args
[
'path'
]
=
dirname
tmp_file_args
[
'path'
]
=
fsname
changed
=
module
.
set_directory_attributes_if_different
(
tmp_file_args
,
changed
)
changed
=
module
.
set_fs_attributes_if_different
(
tmp_file_args
,
changed
)
for
file
in
files
:
filename
=
os
.
path
.
join
(
root
,
file
)
tmp_file_args
=
file_args
.
copy
()
tmp_file_args
[
'path'
]
=
filename
changed
=
module
.
set_file_attributes_if_different
(
tmp_file_args
,
changed
)
module
.
exit_json
(
path
=
path
,
changed
=
changed
)
module
.
exit_json
(
path
=
path
,
changed
=
changed
)
elif
state
in
[
'link'
,
'hard'
]:
elif
state
in
[
'link'
,
'hard'
]:
if
not
os
.
path
.
exists
(
src
)
and
not
force
:
module
.
fail_json
(
path
=
path
,
src
=
src
,
msg
=
'src file does not exist'
)
if
state
==
'hard'
:
if
state
==
'hard'
:
if
os
.
path
.
isabs
(
src
):
if
not
os
.
path
.
isabs
(
src
):
abs_src
=
src
else
:
module
.
fail_json
(
msg
=
"absolute paths are required"
)
module
.
fail_json
(
msg
=
"absolute paths are required"
)
if
not
os
.
path
.
exists
(
abs_src
)
and
not
force
:
elif
prev_state
in
[
'file'
,
'hard'
,
'directory'
]
and
not
force
:
module
.
fail_json
(
path
=
path
,
src
=
src
,
msg
=
'src file does not exist'
)
module
.
fail_json
(
path
=
path
,
msg
=
'refusing to convert between
%
s and
%
s for
%
s'
%
(
prev_state
,
state
,
src
)
)
if
prev_state
==
'absent'
:
if
prev_state
==
'absent'
:
changed
=
True
changed
=
True
...
@@ -300,26 +284,29 @@ def main():
...
@@ -300,26 +284,29 @@ def main():
changed
=
True
changed
=
True
elif
prev_state
==
'hard'
:
elif
prev_state
==
'hard'
:
if
not
(
state
==
'hard'
and
os
.
stat
(
path
)
.
st_ino
==
os
.
stat
(
src
)
.
st_ino
):
if
not
(
state
==
'hard'
and
os
.
stat
(
path
)
.
st_ino
==
os
.
stat
(
src
)
.
st_ino
):
changed
=
True
if
not
force
:
if
not
force
:
module
.
fail_json
(
dest
=
path
,
src
=
src
,
msg
=
'Cannot link, different hard link exists at destination'
)
module
.
fail_json
(
dest
=
path
,
src
=
src
,
msg
=
'Cannot link, different hard link exists at destination'
)
changed
=
True
elif
prev_state
in
[
'file'
,
'directory'
]:
elif
prev_state
==
'file'
:
if
not
force
:
module
.
fail_json
(
dest
=
path
,
src
=
src
,
msg
=
'Cannot link, file exists at destination'
)
changed
=
True
changed
=
True
elif
prev_state
==
'directory'
:
if
not
force
:
if
not
force
:
module
.
fail_json
(
dest
=
path
,
src
=
src
,
msg
=
'Cannot link, directory exists at destination'
)
module
.
fail_json
(
dest
=
path
,
src
=
src
,
msg
=
'Cannot link,
%
s exists at destination'
%
prev_state
)
changed
=
True
else
:
else
:
module
.
fail_json
(
dest
=
path
,
src
=
src
,
msg
=
'unexpected position reached'
)
module
.
fail_json
(
dest
=
path
,
src
=
src
,
msg
=
'unexpected position reached'
)
if
changed
and
not
module
.
check_mode
:
if
changed
and
not
module
.
check_mode
:
if
prev_state
!=
'absent'
:
if
prev_state
!=
'absent'
:
# try to replace atomically
tmppath
=
".
%
s.
%
s.
%
s.tmp"
%
(
path
,
os
.
getpid
(),
time
.
time
())
try
:
try
:
os
.
unlink
(
path
)
if
state
==
'hard'
:
os
.
link
(
src
,
tmppath
)
else
:
os
.
symlink
(
src
,
tmppath
)
os
.
rename
(
tmppath
,
path
)
except
OSError
,
e
:
except
OSError
,
e
:
module
.
fail_json
(
path
=
path
,
msg
=
'Error while removing existing target:
%
s'
%
str
(
e
))
os
.
unlink
(
tmppath
)
module
.
fail_json
(
path
=
path
,
msg
=
'Error while replacing:
%
s'
%
str
(
e
))
try
:
try
:
if
state
==
'hard'
:
if
state
==
'hard'
:
os
.
link
(
src
,
path
)
os
.
link
(
src
,
path
)
...
@@ -328,30 +315,30 @@ def main():
...
@@ -328,30 +315,30 @@ def main():
except
OSError
,
e
:
except
OSError
,
e
:
module
.
fail_json
(
path
=
path
,
msg
=
'Error while linking:
%
s'
%
str
(
e
))
module
.
fail_json
(
path
=
path
,
msg
=
'Error while linking:
%
s'
%
str
(
e
))
changed
=
module
.
set_f
ile
_attributes_if_different
(
file_args
,
changed
)
changed
=
module
.
set_f
s
_attributes_if_different
(
file_args
,
changed
)
module
.
exit_json
(
dest
=
path
,
src
=
src
,
changed
=
changed
)
module
.
exit_json
(
dest
=
path
,
src
=
src
,
changed
=
changed
)
elif
state
==
'touch'
:
elif
state
==
'touch'
:
if
module
.
check_mode
:
if
not
module
.
check_mode
:
module
.
exit_json
(
path
=
path
,
skipped
=
True
)
if
prev_state
==
'absent'
:
try
:
open
(
path
,
'w'
)
.
close
()
except
OSError
,
e
:
module
.
fail_json
(
path
=
path
,
msg
=
'Error, could not touch target:
%
s'
%
str
(
e
))
elif
prev_state
in
[
'file'
,
'directory'
]:
try
:
os
.
utime
(
path
,
None
)
except
OSError
,
e
:
module
.
fail_json
(
path
=
path
,
msg
=
'Error while touching existing target:
%
s'
%
str
(
e
))
else
:
module
.
fail_json
(
msg
=
'Cannot touch other than files and directories'
)
module
.
set_fs_attributes_if_different
(
file_args
,
True
)
if
prev_state
not
in
[
'file'
,
'directory'
,
'absent'
]:
module
.
fail_json
(
msg
=
'Cannot touch other than files and directories'
)
if
prev_state
!=
'absent'
:
try
:
os
.
utime
(
path
,
None
)
except
OSError
,
e
:
module
.
fail_json
(
path
=
path
,
msg
=
'Error while touching existing target:
%
s'
%
str
(
e
))
else
:
try
:
open
(
path
,
'w'
)
.
close
()
except
OSError
,
e
:
module
.
fail_json
(
path
=
path
,
msg
=
'Error, could not touch target:
%
s'
%
str
(
e
))
module
.
set_file_attributes_if_different
(
file_args
,
True
)
module
.
exit_json
(
dest
=
path
,
changed
=
True
)
module
.
exit_json
(
dest
=
path
,
changed
=
True
)
else
:
module
.
fail_json
(
path
=
path
,
msg
=
'unexpected position reached'
)
module
.
fail_json
(
path
=
path
,
msg
=
'unexpected position reached'
)
# import module snippets
# import module snippets
from
ansible.module_utils.basic
import
*
from
ansible.module_utils.basic
import
*
...
...
test/integration/roles/test_file/tasks/main.yml
View file @
5d8c9d3f
...
@@ -164,5 +164,24 @@
...
@@ -164,5 +164,24 @@
that
:
that
:
-
"
file11_result.uid
==
1235"
-
"
file11_result.uid
==
1235"
-
name
:
fail to create soft link to non existant file
file
:
src=/noneexistant dest={{output_dir}}/soft2.txt state=link force=no
register
:
file12_result
ignore_errors
:
true
-
name
:
verify that link was not created
assert
:
that
:
-
"
file12_result.failed
==
true"
-
name
:
force creation soft link to non existant
file
:
src=/noneexistant dest={{output_dir}}/soft2.txt state=link force=yes
register
:
file13_result
-
name
:
verify that link was created
assert
:
that
:
-
"
file13_result.changed
==
true"
-
name
:
remote directory foobar
-
name
:
remote directory foobar
file
:
path={{output_dir}}/foobar state=absent
file
:
path={{output_dir}}/foobar state=absent
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