Refactor stat.py so that it would be more friendly for unittests. (#4462)
* Refactor stat.py so that it would be more friendly for unittests. * PEP8ify since we're moving most of the lines in the file and there's no open PRs
This commit is contained in:
parent
4f09d6065f
commit
07e79ac683
1 changed files with 125 additions and 95 deletions
|
@ -34,7 +34,8 @@ options:
|
||||||
default: no
|
default: no
|
||||||
get_md5:
|
get_md5:
|
||||||
description:
|
description:
|
||||||
- Whether to return the md5 sum of the file. Will return None if we're unable to use md5 (Common for FIPS-140 compliant systems)
|
- Whether to return the md5 sum of the file. Will return None if we're
|
||||||
|
unable to use md5 (Common for FIPS-140 compliant systems)
|
||||||
required: false
|
required: false
|
||||||
default: yes
|
default: yes
|
||||||
get_checksum:
|
get_checksum:
|
||||||
|
@ -45,7 +46,8 @@ options:
|
||||||
version_added: "1.8"
|
version_added: "1.8"
|
||||||
checksum_algorithm:
|
checksum_algorithm:
|
||||||
description:
|
description:
|
||||||
- Algorithm to determine checksum of file. Will throw an error if the host is unable to use specified algorithm.
|
- Algorithm to determine checksum of file. Will throw an error if the
|
||||||
|
host is unable to use specified algorithm.
|
||||||
required: false
|
required: false
|
||||||
choices: [ 'sha1', 'sha224', 'sha256', 'sha384', 'sha512' ]
|
choices: [ 'sha1', 'sha224', 'sha256', 'sha384', 'sha512' ]
|
||||||
default: sha1
|
default: sha1
|
||||||
|
@ -53,7 +55,8 @@ options:
|
||||||
version_added: "2.0"
|
version_added: "2.0"
|
||||||
mime:
|
mime:
|
||||||
description:
|
description:
|
||||||
- Use file magic and return data about the nature of the file. this uses the 'file' utility found on most Linux/Unix systems.
|
- Use file magic and return data about the nature of the file. this uses
|
||||||
|
the 'file' utility found on most Linux/Unix systems.
|
||||||
- This will add both `mime_type` and 'charset' fields to the return, if possible.
|
- This will add both `mime_type` and 'charset' fields to the return, if possible.
|
||||||
required: false
|
required: false
|
||||||
choices: [ Yes, No ]
|
choices: [ Yes, No ]
|
||||||
|
@ -265,12 +268,14 @@ stat:
|
||||||
sample: /home/foobar/21102015-1445431274-908472971
|
sample: /home/foobar/21102015-1445431274-908472971
|
||||||
md5:
|
md5:
|
||||||
description: md5 hash of the path
|
description: md5 hash of the path
|
||||||
returned: success, path exists and user can read stats and path supports hashing and md5 is supported
|
returned: success, path exists and user can read stats and path
|
||||||
|
supports hashing and md5 is supported
|
||||||
type: string
|
type: string
|
||||||
sample: f88fa92d8cf2eeecf4c0a50ccc96d0c0
|
sample: f88fa92d8cf2eeecf4c0a50ccc96d0c0
|
||||||
checksum_algorithm:
|
checksum_algorithm:
|
||||||
description: hash of the path
|
description: hash of the path
|
||||||
returned: success, path exists, user can read stats, path supports hashing and supplied checksum algorithm is available
|
returned: success, path exists, user can read stats, path supports
|
||||||
|
hashing and supplied checksum algorithm is available
|
||||||
type: string
|
type: string
|
||||||
sample: 50ba294cdf28c0d5bcde25708df53346825a429f
|
sample: 50ba294cdf28c0d5bcde25708df53346825a429f
|
||||||
aliases: ['checksum', 'checksum_algo']
|
aliases: ['checksum', 'checksum_algo']
|
||||||
|
@ -286,12 +291,16 @@ stat:
|
||||||
sample: www-data
|
sample: www-data
|
||||||
mime_type:
|
mime_type:
|
||||||
description: file magic data or mime-type
|
description: file magic data or mime-type
|
||||||
returned: success, path exists and user can read stats and installed python supports it and the `mime` option was true, will return 'unknown' on error.
|
returned: success, path exists and user can read stats and
|
||||||
|
installed python supports it and the `mime` option was true, will
|
||||||
|
return 'unknown' on error.
|
||||||
type: string
|
type: string
|
||||||
sample: PDF document, version 1.2
|
sample: PDF document, version 1.2
|
||||||
charset:
|
charset:
|
||||||
description: file character set or encoding
|
description: file character set or encoding
|
||||||
returned: success, path exists and user can read stats and installed python supports it and the `mime` option was true, will return 'unknown' on error.
|
returned: success, path exists and user can read stats and
|
||||||
|
installed python supports it and the `mime` option was true, will
|
||||||
|
return 'unknown' on error.
|
||||||
type: string
|
type: string
|
||||||
sample: us-ascii
|
sample: us-ascii
|
||||||
readable:
|
readable:
|
||||||
|
@ -311,27 +320,106 @@ stat:
|
||||||
sample: False
|
sample: False
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import os
|
import errno
|
||||||
import sys
|
|
||||||
from stat import *
|
|
||||||
import pwd
|
|
||||||
import grp
|
import grp
|
||||||
|
import os
|
||||||
|
import pwd
|
||||||
|
import stat
|
||||||
|
|
||||||
|
# import module snippets
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.pycompat24 import get_exception
|
||||||
|
|
||||||
|
|
||||||
|
def format_output(module, path, st, follow, get_md5, get_checksum,
|
||||||
|
checksum_algorithm, mimetype=None, charset=None):
|
||||||
|
mode = st.st_mode
|
||||||
|
|
||||||
|
# back to ansible
|
||||||
|
output = dict(
|
||||||
|
exists=True,
|
||||||
|
path=path,
|
||||||
|
mode="%04o" % stat.S_IMODE(mode),
|
||||||
|
isdir=stat.S_ISDIR(mode),
|
||||||
|
ischr=stat.S_ISCHR(mode),
|
||||||
|
isblk=stat.S_ISBLK(mode),
|
||||||
|
isreg=stat.S_ISREG(mode),
|
||||||
|
isfifo=stat.S_ISFIFO(mode),
|
||||||
|
islnk=stat.S_ISLNK(mode),
|
||||||
|
issock=stat.S_ISSOCK(mode),
|
||||||
|
uid=st.st_uid,
|
||||||
|
gid=st.st_gid,
|
||||||
|
size=st.st_size,
|
||||||
|
inode=st.st_ino,
|
||||||
|
dev=st.st_dev,
|
||||||
|
nlink=st.st_nlink,
|
||||||
|
atime=st.st_atime,
|
||||||
|
mtime=st.st_mtime,
|
||||||
|
ctime=st.st_ctime,
|
||||||
|
wusr=bool(mode & stat.S_IWUSR),
|
||||||
|
rusr=bool(mode & stat.S_IRUSR),
|
||||||
|
xusr=bool(mode & stat.S_IXUSR),
|
||||||
|
wgrp=bool(mode & stat.S_IWGRP),
|
||||||
|
rgrp=bool(mode & stat.S_IRGRP),
|
||||||
|
xgrp=bool(mode & stat.S_IXGRP),
|
||||||
|
woth=bool(mode & stat.S_IWOTH),
|
||||||
|
roth=bool(mode & stat.S_IROTH),
|
||||||
|
xoth=bool(mode & stat.S_IXOTH),
|
||||||
|
isuid=bool(mode & stat.S_ISUID),
|
||||||
|
isgid=bool(mode & stat.S_ISGID),
|
||||||
|
readable=os.access(path, os.R_OK),
|
||||||
|
writeable=os.access(path, os.W_OK),
|
||||||
|
excutable=os.access(path, os.X_OK),
|
||||||
|
)
|
||||||
|
|
||||||
|
if stat.S_ISLNK(mode):
|
||||||
|
output['lnk_source'] = os.path.realpath(path)
|
||||||
|
|
||||||
|
if stat.S_ISREG(mode) and get_md5 and os.access(path, os.R_OK):
|
||||||
|
# Will fail on FIPS-140 compliant systems
|
||||||
|
try:
|
||||||
|
output['md5'] = module.md5(path)
|
||||||
|
except ValueError:
|
||||||
|
output['md5'] = None
|
||||||
|
|
||||||
|
if stat.S_ISREG(mode) and get_checksum and os.access(path, os.R_OK):
|
||||||
|
output['checksum'] = module.digest_from_file(path, checksum_algorithm)
|
||||||
|
|
||||||
|
try:
|
||||||
|
pw = pwd.getpwuid(st.st_uid)
|
||||||
|
|
||||||
|
output['pw_name'] = pw.pw_name
|
||||||
|
|
||||||
|
grp_info = grp.getgrgid(st.st_gid)
|
||||||
|
output['gr_name'] = grp_info.gr_name
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not (mimetype is None and charset is None):
|
||||||
|
output['mime_type'] = mimetype
|
||||||
|
output['charset'] = charset
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec = dict(
|
argument_spec=dict(
|
||||||
path = dict(required=True, type='path'),
|
path=dict(required=True, type='path'),
|
||||||
follow = dict(default='no', type='bool'),
|
follow=dict(default='no', type='bool'),
|
||||||
get_md5 = dict(default='yes', type='bool'),
|
get_md5=dict(default='yes', type='bool'),
|
||||||
get_checksum = dict(default='yes', type='bool'),
|
get_checksum=dict(default='yes', type='bool'),
|
||||||
checksum_algorithm = dict(default='sha1', type='str', choices=['sha1', 'sha224', 'sha256', 'sha384', 'sha512'], aliases=['checksum_algo', 'checksum']),
|
checksum_algorithm=dict(default='sha1', type='str',
|
||||||
mime = dict(default=False, type='bool', aliases=['mime_type', 'mime-type']),
|
choices=['sha1', 'sha224', 'sha256', 'sha384', 'sha512'],
|
||||||
|
aliases=['checksum_algo', 'checksum']),
|
||||||
|
mime=dict(default=False, type='bool', aliases=['mime_type', 'mime-type']),
|
||||||
),
|
),
|
||||||
supports_check_mode = True
|
supports_check_mode=True
|
||||||
)
|
)
|
||||||
|
|
||||||
path = module.params.get('path')
|
path = module.params.get('path')
|
||||||
follow = module.params.get('follow')
|
follow = module.params.get('follow')
|
||||||
|
get_mime = module.params.get('mime')
|
||||||
get_md5 = module.params.get('get_md5')
|
get_md5 = module.params.get('get_md5')
|
||||||
get_checksum = module.params.get('get_checksum')
|
get_checksum = module.params.get('get_checksum')
|
||||||
checksum_algorithm = module.params.get('checksum_algorithm')
|
checksum_algorithm = module.params.get('checksum_algorithm')
|
||||||
|
@ -344,90 +432,32 @@ def main():
|
||||||
except OSError:
|
except OSError:
|
||||||
e = get_exception()
|
e = get_exception()
|
||||||
if e.errno == errno.ENOENT:
|
if e.errno == errno.ENOENT:
|
||||||
d = { 'exists' : False }
|
output = {'exists': False}
|
||||||
module.exit_json(changed=False, stat=d)
|
module.exit_json(changed=False, stat=output)
|
||||||
|
|
||||||
module.fail_json(msg = e.strerror)
|
module.fail_json(msg=e.strerror)
|
||||||
|
|
||||||
mode = st.st_mode
|
mimetype = None
|
||||||
|
charset = None
|
||||||
|
if get_mime:
|
||||||
|
mimetype = 'unknown'
|
||||||
|
charset = 'unknown'
|
||||||
|
|
||||||
# back to ansible
|
filecmd = [module.get_bin_path('file', True), '-i', path]
|
||||||
d = {
|
|
||||||
'exists' : True,
|
|
||||||
'path' : path,
|
|
||||||
'mode' : "%04o" % S_IMODE(mode),
|
|
||||||
'isdir' : S_ISDIR(mode),
|
|
||||||
'ischr' : S_ISCHR(mode),
|
|
||||||
'isblk' : S_ISBLK(mode),
|
|
||||||
'isreg' : S_ISREG(mode),
|
|
||||||
'isfifo' : S_ISFIFO(mode),
|
|
||||||
'islnk' : S_ISLNK(mode),
|
|
||||||
'issock' : S_ISSOCK(mode),
|
|
||||||
'uid' : st.st_uid,
|
|
||||||
'gid' : st.st_gid,
|
|
||||||
'size' : st.st_size,
|
|
||||||
'inode' : st.st_ino,
|
|
||||||
'dev' : st.st_dev,
|
|
||||||
'nlink' : st.st_nlink,
|
|
||||||
'atime' : st.st_atime,
|
|
||||||
'mtime' : st.st_mtime,
|
|
||||||
'ctime' : st.st_ctime,
|
|
||||||
'wusr' : bool(mode & stat.S_IWUSR),
|
|
||||||
'rusr' : bool(mode & stat.S_IRUSR),
|
|
||||||
'xusr' : bool(mode & stat.S_IXUSR),
|
|
||||||
'wgrp' : bool(mode & stat.S_IWGRP),
|
|
||||||
'rgrp' : bool(mode & stat.S_IRGRP),
|
|
||||||
'xgrp' : bool(mode & stat.S_IXGRP),
|
|
||||||
'woth' : bool(mode & stat.S_IWOTH),
|
|
||||||
'roth' : bool(mode & stat.S_IROTH),
|
|
||||||
'xoth' : bool(mode & stat.S_IXOTH),
|
|
||||||
'isuid' : bool(mode & stat.S_ISUID),
|
|
||||||
'isgid' : bool(mode & stat.S_ISGID),
|
|
||||||
'readable' : os.access(path, os.R_OK),
|
|
||||||
'writeable' : os.access(path, os.W_OK),
|
|
||||||
'excutable' : os.access(path, os.X_OK),
|
|
||||||
}
|
|
||||||
|
|
||||||
if S_ISLNK(mode):
|
|
||||||
d['lnk_source'] = os.path.realpath(path)
|
|
||||||
|
|
||||||
if S_ISREG(mode) and get_md5 and os.access(path,os.R_OK):
|
|
||||||
# Will fail on FIPS-140 compliant systems
|
|
||||||
try:
|
|
||||||
d['md5'] = module.md5(path)
|
|
||||||
except ValueError:
|
|
||||||
d['md5'] = None
|
|
||||||
|
|
||||||
if S_ISREG(mode) and get_checksum and os.access(path,os.R_OK):
|
|
||||||
d['checksum'] = module.digest_from_file(path, checksum_algorithm)
|
|
||||||
|
|
||||||
try:
|
|
||||||
pw = pwd.getpwuid(st.st_uid)
|
|
||||||
|
|
||||||
d['pw_name'] = pw.pw_name
|
|
||||||
|
|
||||||
grp_info = grp.getgrgid(st.st_gid)
|
|
||||||
d['gr_name'] = grp_info.gr_name
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if module.params.get('mime'):
|
|
||||||
d['mime_type'] = 'unknown'
|
|
||||||
d['charset'] = 'unknown'
|
|
||||||
|
|
||||||
filecmd = [module.get_bin_path('file', True),'-i', path]
|
|
||||||
try:
|
try:
|
||||||
rc, out, err = module.run_command(filecmd)
|
rc, out, err = module.run_command(filecmd)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
mtype, chset = out.split(':')[1].split(';')
|
mimetype, charset = out.split(':')[1].split(';')
|
||||||
d['mime_type'] = mtype.strip()
|
mimetype = mimetype.strip()
|
||||||
d['charset'] = chset.split('=')[1].strip()
|
charset = charset.split('=')[1].strip()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
module.exit_json(changed=False, stat=d)
|
output = format_output(module, path, st, follow, get_md5, get_checksum,
|
||||||
|
checksum_algorithm, mimetype=mimetype,
|
||||||
|
charset=charset)
|
||||||
|
|
||||||
# import module snippets
|
module.exit_json(changed=False, stat=output)
|
||||||
from ansible.module_utils.basic import *
|
|
||||||
|
|
||||||
main()
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
Loading…
Reference in a new issue