192 lines
5.3 KiB
Lua
192 lines
5.3 KiB
Lua
#!/usr/bin/lua
|
|
-- WANT_JSON
|
|
|
|
local Ansible = require("ansible")
|
|
local File = require("fileutils")
|
|
local os = require("os")
|
|
|
|
|
|
function adjust_recursive_directory_permissions(pre_existing_dir, new_directory_list, index, module, directory_args, changed)
|
|
-- Walk the new directories list and make sure that permissions are as we would expect
|
|
|
|
local changed = false
|
|
|
|
if index <= #new_directory_list then
|
|
local working_dir = File.join(pre_existing_dir, new_directory_list[i])
|
|
directory_args['path'] = working_dir
|
|
changed = File.set_fs_attributes_if_different(module, directory_args, changed, nil)
|
|
changed = adjust_recursive_directory_permissions(working_dir, new_directory_list, index+1, module, directory_args, changed)
|
|
end
|
|
|
|
return changed
|
|
end
|
|
|
|
function main(arg)
|
|
local module = Ansible.new(
|
|
{ src = { required=true }
|
|
, original_basename = { required=false }
|
|
, content = { required=false }
|
|
, path = { aliases={'dest'}, required=true }
|
|
, backup = { default=false, type='bool' }
|
|
, force = { default=true, aliases={'thirsty'}, type='bool' }
|
|
, validate = { required=false, type='str' }
|
|
, directory_mode = { required=false }
|
|
, remote_src = { required=false, type='bool' }
|
|
|
|
|
|
-- file common args
|
|
-- , src = {}
|
|
, mode = { type='raw' }
|
|
, owner = {}
|
|
, group = {}
|
|
|
|
-- Selinux to ignore
|
|
, seuser = {}
|
|
, serole = {}
|
|
, selevel = {}
|
|
, setype = {}
|
|
|
|
, follow = {type='bool', default=false}
|
|
|
|
-- not taken by the file module, but other modules call file so it must ignore them
|
|
, content = {}
|
|
, backup = {}
|
|
-- , force = {}
|
|
, remote_src = {}
|
|
, regexp = {}
|
|
, delimiter = {}
|
|
-- , directory_mode = {}
|
|
}
|
|
)
|
|
|
|
module:parse(arg[1])
|
|
|
|
local p = module:get_params()
|
|
|
|
local src = File.expanduser(p['src'])
|
|
local dest = File.expanduser(p['path'])
|
|
local backup = p['backup']
|
|
local force = p['force']
|
|
local original_basename = p['original_basename']
|
|
local validate = p['validate']
|
|
local follow = p['follow']
|
|
local mode = p['mode']
|
|
local remote_src = p['remote_src']
|
|
|
|
if not File.exists(src) then
|
|
module:fail_json({msg="Source " .. src .. " not found"})
|
|
end
|
|
if not File.readable(src) then
|
|
module:fail_json({msg="Source " .. src .. " not readable"})
|
|
end
|
|
if File.isdir(src) then
|
|
module:fail_json({msg="Remote copy does not support recursive copy of directory: " .. src})
|
|
end
|
|
|
|
local checksum_src = File.sha1(module, src)
|
|
local checksum_dest = nil
|
|
local md5sum_src = File.md5(module, src)
|
|
|
|
local changed = false
|
|
|
|
-- Special handling for recursive copy - create intermediate dirs
|
|
if original_basename and string.match(dest, "/$") then
|
|
dest = File.join(dest, orignal_basename)
|
|
local dirname = File.dirname(dest)
|
|
if not File.exists(dirname) and File.isabs(dirname) then
|
|
local pre_existing_dir, new_directory_list = File.split_pre_existing_dir(dirname)
|
|
File.mkdirs(dirname)
|
|
local directory_args = p
|
|
local direcotry_mode = p['directory_mode']
|
|
adjust_recursive_directory_permissions(pre_existing_dir, new_directory_list, 1, module, directory_args, changed)
|
|
end
|
|
end
|
|
|
|
if File.exists(dest) then
|
|
if File.islnk(dest) and follow then
|
|
dest = File.realpath(dest)
|
|
end
|
|
if not force then
|
|
module:exit_json({msg="file already exists", src=src, dest=dest, changed=false})
|
|
end
|
|
if File.isdir(dest) then
|
|
local basename = File.basename(src)
|
|
if original_basename then
|
|
basename = original_basename
|
|
end
|
|
dest = File.join(dest, basename)
|
|
end
|
|
if File.readable(dest) then
|
|
checksum_dest = File.sha1(module, dest)
|
|
end
|
|
else
|
|
if not File.exists(File.dirname(dest)) then
|
|
if nil == File.stat(File.dirname(dest)) then
|
|
module:fail_json({msg="Destination directory " .. File.dirname(dest) .. " is not accessible"})
|
|
end
|
|
module:fail_json({msg="Destination directory " .. File.dirname(dest) .. " does not exist"})
|
|
end
|
|
end
|
|
|
|
if not File.writeable(File.dirname(dest)) then
|
|
module:fail_json({msg="Destination " .. File.dirname(dest) .. " not writeable"})
|
|
end
|
|
|
|
local backup_file = nil
|
|
if checksum_src ~= checksum_dest or File.islnk(dest) then
|
|
if not module:check_mode() then
|
|
if backup and File.exists(dest) then
|
|
backup_file = module:backup_local(dest)
|
|
end
|
|
|
|
local function err(res, msg)
|
|
if not res then
|
|
module:fail_json({msg="failed to copy: " .. src .. " to " .. dest .. ": " .. msg})
|
|
end
|
|
end
|
|
|
|
local res, msg
|
|
-- allow for conversion from symlink
|
|
if File.islnk(dest) then
|
|
res, msg = File.unlink(dest)
|
|
err(res, msg)
|
|
res, msg = File.touch(dest)
|
|
err(res, msg)
|
|
end
|
|
if validate then
|
|
-- FIXME: Validate is currently unsupported
|
|
end
|
|
if remote_src then
|
|
local tmpname, msg = File.mkstemp(File.dirname(dest) .. "/ansibltmp_XXXXXX")
|
|
err(tmpname, msg)
|
|
res, msg = module:copy(src, tmpdest)
|
|
err(res, msg)
|
|
res, msg = module:move(tmpdest, dest)
|
|
err(res, msg)
|
|
else
|
|
res, msg = module:move(src, dest)
|
|
err(res, msg)
|
|
end
|
|
end
|
|
changed = true
|
|
else
|
|
changed = false
|
|
end
|
|
|
|
res_args = { dest=dest, src=src, md5sum=md5sum_src, checksum=checksum_src, changed=changed }
|
|
if backup_file then
|
|
res_args['backup_file'] = backup_file
|
|
end
|
|
|
|
p['dest'] = dest
|
|
if not module:check_mode() then
|
|
local file_args = p
|
|
res_args['changed'] = File.set_fs_attributes_if_different(module, file_args, res_args['changed'], nil)
|
|
end
|
|
|
|
res_args['msg'] = "Dummy"
|
|
|
|
module:exit_json(res_args)
|
|
end
|
|
|
|
main(arg)
|