introducing checkgauge, code beautifications

This commit is contained in:
Axel Kittenberger 2012-10-05 21:48:06 +02:00
parent 1bf1d13eaa
commit 6a862d6b8f
3 changed files with 722 additions and 520 deletions

View File

@ -28,6 +28,64 @@ end
default.rsync = { } default.rsync = { }
local rsync = default.rsync local rsync = default.rsync
-- uses default collect
--
-- used to ensure there aren't typos in the keys
--
rsync.checkgauge = {
default.checkgauge,
-- unsets default user action handlers
onCreate = false,
onModify = false,
onDelete = false,
onStartup = false,
onMove = false,
delete = true,
exclude = true,
source = true,
target = true,
rsync = {
-- rsync binary
binary = true,
-- rsync shortflags
verbose = true,
quiet = true,
checksum = true,
update = true,
links = true,
copy_links = true,
hard_links = true,
perms = true,
executability = true,
acls = true,
xattrs = true,
owner = true,
group = true,
times = true,
sparse = true,
dry_run = true,
whole_file = true,
one_file_system = true,
prune_empty_dirs = true,
ignore_times = true,
compress = true,
cvs_exclude = true,
protect_args = true,
ipv4 = true,
ipv6 = true,
-- further rsync options
rsh = true,
rsync_path = true,
},
}
-- --
-- Spawns rsync for a list of events -- Spawns rsync for a list of events
@ -163,10 +221,19 @@ end
-- --
rsync.init = function(event) rsync.init = function(event)
local config = event.config local config = event.config
local inlet = event.inlet local inlet = event.inlet
local excludes = inlet.getExcludes( ) local excludes = inlet.getExcludes( )
local delete = nil local delete = nil
local target = config.target
if not target then
if not config.host then
error('Internal fail, Neither target nor host is configured')
end
target = config.host .. ':' .. config.targetdir
end
if config.delete then if config.delete then
delete = { '--delete', '--ignore-errors' } delete = { '--delete', '--ignore-errors' }
@ -179,7 +246,7 @@ rsync.init = function(event)
'recursive startup rsync: ', 'recursive startup rsync: ',
config.source, config.source,
' -> ', ' -> ',
config.target target
) )
spawn( spawn(
@ -189,7 +256,7 @@ rsync.init = function(event)
config.rsync._computed, config.rsync._computed,
'-r', '-r',
config.source, config.source,
config.target target
) )
else else
@ -202,7 +269,7 @@ rsync.init = function(event)
'recursive startup rsync: ', 'recursive startup rsync: ',
config.source, config.source,
' -> ', ' -> ',
config.target, target,
' excluding\n', ' excluding\n',
exS exS
) )
@ -216,7 +283,7 @@ rsync.init = function(event)
config.rsync._computed, config.rsync._computed,
'-r', '-r',
config.source, config.source,
config.target target
) )
end end
end end
@ -225,19 +292,30 @@ end
-- --
-- Prepares and checks a syncs configuration on startup. -- Prepares and checks a syncs configuration on startup.
-- --
rsync.prepare = function( config ) rsync.prepare = function(
config, -- the configuration
level, -- additional error level for inherited use ( by rsyncssh )
skipTarget -- used by rsyncssh, do not check for target
)
if not config.target then level = level or 4
--
-- First let default.prepare test the checkgauge
--
default.prepare( config, level + 6 )
if not skipTarget and not config.target then
error( error(
'default.rsync needs "target" configured', 'default.rsync needs "target" configured',
4 level
) )
end end
if config.rsyncOps then if config.rsyncOps then
error( error(
'"rsyncOps" is outdated please use the new rsync = { ... } syntax.', '"rsyncOps" is outdated please use the new rsync = { ... } syntax.',
4 level
) )
end end
@ -246,7 +324,7 @@ rsync.prepare = function( config )
'"rsyncOpts" is outdated in favor of the new rsync = { ... } syntax\n"' + '"rsyncOpts" is outdated in favor of the new rsync = { ... } syntax\n"' +
'for which you provided the _extra attribute as well.\n"' + 'for which you provided the _extra attribute as well.\n"' +
'Please remove rsyncOpts from your config.', 'Please remove rsyncOpts from your config.',
4 level
) )
end end
@ -265,7 +343,7 @@ rsync.prepare = function( config )
'"rsyncBinary is outdated in favor of the new rsync = { ... } syntax\n"'+ '"rsyncBinary is outdated in favor of the new rsync = { ... } syntax\n"'+
'for which you provided the binary attribute as well.\n"' + 'for which you provided the binary attribute as well.\n"' +
"Please remove rsyncBinary from your config.'", "Please remove rsyncBinary from your config.'",
4 level
) )
end end
@ -283,75 +361,108 @@ rsync.prepare = function( config )
if config.rsync._computed then if config.rsync._computed then
error( error(
'please do not use the internal rsync._computed parameter', 'please do not use the internal rsync._computed parameter',
4 level
) )
end end
-- computes the rsync arguments into one list -- computes the rsync arguments into one list
local rsync = config.rsync; local rsync = config.rsync;
rsync._computed = { true } rsync._computed = { true }
local computed = rsync._computed local computed = rsync._computed
local computedN = 1
local shortFlags = {
verbose = 'v',
quiet = 'q',
checksum = 'c',
update = 'u',
links = 'l',
copy_links = 'L',
hard_links = 'H',
perms = 'p',
executability = 'E',
acls = 'A',
xattrs = 'X',
owner = 'o',
group = 'g',
times = 't',
sparse = 'S',
dry_run = 'n',
whole_file = 'W',
one_file_system = 'x',
prune_empty_dirs = 'm',
ignore_times = 'I',
compress = 'z',
cvs_exclude = 'C',
protect_args = 's',
ipv4 = '4',
ipv6 = '6'
}
local shorts = { '-' } local shorts = { '-' }
local shortsN = 2
if config.rsync._extra then if config.rsync._extra then
for k, v in ipairs( config.rsync._extra ) do for k, v in ipairs( config.rsync._extra ) do
computed[ k + 1 ] = v computed[ computedN ] = v
computedN = computedN + 1
end end
end end
if rsync.links then for k, flag in pairs( shortFlags ) do
shorts[ #shorts + 1 ] = 'l' if config.rsync[k] then
shorts[ shortsN ] = flag
shortsN = shortsN + 1
end
end end
if rsync.times then if config.rsync.rsh then
shorts[ #shorts + 1 ] = 't' computed[ computedN ] = '--rsh=' + config.rsync.rsh
computedN = computedN + 1
end end
if rsync.protectArgs then if config.rsync.rsync_path then
shorts[ #shorts + 1 ] = 's' computed[ computedN ] = '--rsync-path=' + config.rsync.rsync_path
computedN = computedN + 1
end end
if #shorts ~= 1 then if shortsN ~= 2 then
computed[ 1 ] = table.concat( shorts, '' ) computed[ 1 ] = table.concat( shorts, '' )
else else
computed[ 1 ] = { } computed[ 1 ] = { }
end end
-- appends a / to target if not present -- appends a / to target if not present
if string.sub(config.target, -1) ~= '/' then if not skipTarget and string.sub(config.target, -1) ~= '/' then
config.target = config.target..'/' config.target = config.target..'/'
end end
end end
--
-- rsync uses default collect
--
-- --
-- By default do deletes. -- By default do deletes.
-- --
rsync.delete = true rsync.delete = true
--
-- Rsyncd exitcodes
--
rsync.exitcodes = default.rsyncExitCodes
-- --
-- Calls rsync with this default options -- Calls rsync with this default options
-- --
rsync.rsync = { rsync.rsync = {
-- The rsync binary to be called. -- The rsync binary to be called.
binary = '/usr/bin/rsync', binary = '/usr/bin/rsync',
links = true, links = true,
times = true, times = true,
protectArgs = true protect_args = true
} }
--
-- Exit codes for rsync.
--
rsync.exitcodes = default.rsyncExitCodes
-- --
-- Default delay -- Default delay
-- --

View File

@ -16,344 +16,340 @@
-- --
if not default then if not default then
error('default not loaded'); error( 'default not loaded' );
end
if not default.rsync then
error( 'default.rsync not loaded' );
end end
if default.rsyncssh then if default.rsyncssh then
error('default-rsyncssh already loaded'); error( 'default-rsyncssh already loaded' );
end end
default.rsyncssh = { --
-- rsyncssh extends default.rsync
--
local rsyncssh = { default.rsync }
default.rsyncssh = rsyncssh
-- --
-- Spawns rsync for a list of events -- used to ensure there aren't typos in the keys
-- --
action = function(inlet) rsyncssh.checkgauge = {
local event, event2 = inlet.getEvent() -- unsets the inherited value of from default.rsync
local config = inlet.getConfig() target = false,
onMove = true,
-- makes move local on host -- rsyncssh users host and targetdir
-- if fails deletes the source... host = true,
if event.etype == 'Move' then targetdir = true,
log('Normal', 'Moving ',event.path,' -> ',event2.path)
spawn(event, '/usr/bin/ssh', -- ssh settings
config.host, ssh = {
'mv', binary = true,
'\"' .. config.targetdir .. event.path .. '\"', port = true,
'\"' .. config.targetdir .. event2.path .. '\"', _extra = true
'||', 'rm', '-rf', },
'\"' .. config.targetdir .. event.path .. '\"')
-- xargs settings
xargs = {
binary = true,
delimiter = true,
_extra = true
}
}
--
-- Spawns rsync for a list of events
--
rsyncssh.action = function( inlet )
local event, event2 = inlet.getEvent()
local config = inlet.getConfig()
-- makes move local on target host
-- if the move fails, it deletes the source
if event.etype == 'Move' then
log('Normal', 'Moving ',event.path,' -> ',event2.path)
spawn(
event,
config.ssh.binary,
-- config.ssh._computed, TODO XXX
config.host,
'mv',
'\"' .. config.targetdir .. event.path .. '\"',
'\"' .. config.targetdir .. event2.path .. '\"',
'||', 'rm', '-rf',
'\"' .. config.targetdir .. event.path .. '\"')
return
end
-- uses ssh to delete files on remote host
-- instead of constructing rsync filters
if event.etype == 'Delete' then
if not config.delete then
inlet.discardEvent(event)
return return
end end
-- uses ssh to delete files on remote host -- gets all other deletes ready to be
-- instead of constructing rsync filters -- executed
if event.etype == 'Delete' then
if not config.delete then
inlet.discardEvent(event)
return
end
local elist = inlet.getEvents(
function(e)
return e.etype == 'Delete'
end
)
local paths = elist.getPaths(
function(etype, path1, path2)
if path2 then
return config.targetdir..path1, config.targetdir..path2
else
return config.targetdir..path1
end
end
)
for _, v in pairs(paths) do
if string.match(v, '^%s*/+%s*$') then
log('Error', 'refusing to `rm -rf /` the target!')
terminate(-1) -- ERRNO
end
end
log('Normal', 'Deleting list\n', table.concat(paths, '\n'))
local params = {}
if config.port then
params[#params + 1] = 'p'
params[#params + 1] = config.port
end
spawn(
elist,
config.ssh.binary,
'<', table.concat(paths, config.xargs.delimiter),
params,
config.ssh._extra,
config.host,
config.xargs.binary,
config.xargs._extra
)
return
end
-- for everything else spawn a rsync
local elist = inlet.getEvents( local elist = inlet.getEvents(
function(e) function( e )
-- TODO use a table return e.etype == 'Delete'
return e.etype ~= 'Move' and
e.etype ~= 'Delete' and
e.etype ~= 'Init' and
e.etype ~= 'Blanket'
end end
) )
local paths = elist.getPaths() -- returns the paths of the delete list
local paths = elist.getPaths(
function( etype, path1, path2 )
if path2 then
return config.targetdir..path1, config.targetdir..path2
else
return config.targetdir..path1
end
end
)
-- removes trailing slashes from dirs. -- ensures none of the paths is '/'
for k, v in ipairs(paths) do for _, v in pairs( paths ) do
if string.byte(v, -1) == 47 then if string.match(v, '^%s*/+%s*$') then
paths[k] = string.sub(v, 1, -2) log('Error', 'refusing to `rm -rf /` the target!')
terminate(-1) -- ERRNO
end end
end end
local sPaths = table.concat(paths, '\n') log(
local zPaths = table.concat(paths, '\000') 'Normal',
log('Normal', 'Rsyncing list\n', sPaths) 'Deleting list\n',
table.concat( paths, '\n' )
)
local params = { }
spawn( spawn(
elist, elist,
config.rsyncBinary, config.ssh.binary,
'<', zPaths, '<', table.concat(paths, config.xargs.delimiter),
config.rsyncOpts, params,
'--from0', -- config.ssh._computed, TODO XXX
'--files-from=-', config.host,
config.source, config.xargs.binary,
config.host .. ':' .. config.targetdir config.xargs._extra
) )
end,
----- return
-- Called when collecting a finished child process end
-- --
collect = function(agent, exitcode) -- for everything else a rsync is spawned
--
local elist = inlet.getEvents(
function(e)
-- TODO use a table
return e.etype ~= 'Move' and
e.etype ~= 'Delete' and
e.etype ~= 'Init' and
e.etype ~= 'Blanket'
end
)
local config = agent.config local paths = elist.getPaths( )
if not agent.isList and agent.etype == 'Init' then
local rc = config.rsyncExitCodes[exitcode]
if rc == 'ok' then
log('Normal', 'Startup of "',agent.source,'" finished: ', exitcode)
elseif rc == 'again' then
if settings.insist then
log('Normal', 'Retrying startup of "',agent.source,'": ', exitcode)
else
log('Error', 'Temporary or permanent failure on startup of "',
agent.source, '". Terminating since "insist" is not set.');
terminate(-1) -- ERRNO
end
elseif rc == 'die' then
log('Error', 'Failure on startup of "',agent.source,'": ', exitcode)
else
log('Error', 'Unknown exitcode on startup of "', agent.source,': "',exitcode)
rc = 'die'
end
return rc
--
-- removes trailing slashes from dirs.
--
for k, v in ipairs( paths ) do
if string.byte(v, -1) == 47 then
paths[k] = string.sub(v, 1, -2)
end end
if agent.isList then end
local rc = config.rsyncExitCodes[exitcode] local sPaths = table.concat(paths, '\n')
local zPaths = table.concat(paths, '\000')
if rc == 'ok' then log('Normal', 'Rsyncing list\n', sPaths)
log('Normal', 'Finished (list): ',exitcode)
elseif rc == 'again' then spawn(
log('Normal', 'Retrying (list): ',exitcode) elist,
elseif rc == 'die' then config.rsync.binary,
log('Error', 'Failure (list): ', exitcode) '<', zPaths,
config.rsync._computed,
'--from0',
'--files-from=-',
config.source,
config.host .. ':' .. config.targetdir
)
end
-----
-- Called when collecting a finished child process
--
rsyncssh.collect = function( agent, exitcode )
local config = agent.config
if not agent.isList and agent.etype == 'Init' then
local rc = config.rsyncExitCodes[exitcode]
if rc == 'ok' then
log('Normal', 'Startup of "',agent.source,'" finished: ', exitcode)
elseif rc == 'again' then
if settings.insist then
log('Normal', 'Retrying startup of "',agent.source,'": ', exitcode)
else else
log('Error', 'Unknown exitcode (list): ',exitcode) log('Error', 'Temporary or permanent failure on startup of "',
rc = 'die' agent.source, '". Terminating since "insist" is not set.');
terminate(-1) -- ERRNO
end end
return rc elseif rc == 'die' then
log('Error', 'Failure on startup of "',agent.source,'": ', exitcode)
else else
log('Error', 'Unknown exitcode on startup of "', agent.source,': "',exitcode)
local rc = config.sshExitCodes[exitcode] rc = 'die'
if rc == 'ok' then
log('Normal', 'Finished ',agent.etype,' ',agent.sourcePath,': ',exitcode)
elseif rc == 'again' then
log('Normal', 'Retrying ',agent.etype,' ',agent.sourcePath,': ',exitcode)
elseif rc == 'die' then
log('Normal', 'Failure ',agent.etype,' ',agent.sourcePath,': ',exitcode)
else
log('Error', 'Unknown exitcode ',agent.etype,' ',agent.sourcePath,': ',exitcode)
rc = 'die'
end
return rc
end end
end, return rc
-- end
-- spawns the recursive startup sync
--
init = function(event)
local config = event.config if agent.isList then
local inlet = event.inlet local rc = config.rsyncExitCodes[exitcode]
local excludes = inlet.getExcludes() if rc == 'ok' then
local target = config.host .. ':' .. config.targetdir log('Normal', 'Finished (list): ',exitcode)
local delete = nil elseif rc == 'again' then
log('Normal', 'Retrying (list): ',exitcode)
if config.delete then elseif rc == 'die' then
delete = { '--delete', '--ignore-errors' }; log('Error', 'Failure (list): ', exitcode)
end
if #excludes == 0 then
log('Normal', 'Recursive startup rsync: ',config.source,' -> ',target)
spawn(
event, config.rsyncBinary,
delete,
'-r',
config.rsyncOpts,
config.source,
target
)
else else
local exS = table.concat(excludes, '\n') log('Error', 'Unknown exitcode (list): ',exitcode)
log('Normal', 'Recursive startup rsync: ',config.source, rc = 'die'
' -> ',target,' with excludes.')
spawn(
event, config.rsyncBinary,
'<', exS,
'--exclude-from=-',
delete,
'-r',
config.rsyncOpts,
config.source,
target
)
end end
end, return rc
else
local rc = config.sshExitCodes[exitcode]
-- if rc == 'ok' then
-- checks the configuration. log('Normal', 'Finished ',agent.etype,' ',agent.sourcePath,': ',exitcode)
-- elseif rc == 'again' then
prepare = function(config) log('Normal', 'Retrying ',agent.etype,' ',agent.sourcePath,': ',exitcode)
elseif rc == 'die' then
if not config.host then log('Normal', 'Failure ',agent.etype,' ',agent.sourcePath,': ',exitcode)
error('default.rsyncssh needs "host" configured', 4) else
log('Error', 'Unknown exitcode ',agent.etype,' ',agent.sourcePath,': ',exitcode)
rc = 'die'
end end
if not config.targetdir then return rc
error('default.rsyncssh needs "targetdir" configured', 4) end
end
if config.rsyncOps then end
error('did you mean rsyncOpts with "t"?', 4)
end
-- appends a slash to the targetdir if missing --
if string.sub(config.targetdir, -1) ~= '/' then -- checks the configuration.
config.targetdir = config.targetdir .. '/' --
end rsyncssh.prepare = function( config )
end,
-- default.rsync.prepare( config, 5, true )
-- the rsync binary called
--
rsyncBinary = '/usr/bin/rsync',
-- if not config.host then
-- calls rsync with this default short opts error('default.rsyncssh needs "host" configured', 4)
-- end
rsyncOpts = '-lts',
-- if not config.targetdir then
-- allow processes error('default.rsyncssh needs "targetdir" configured', 4)
-- end
maxProcesses = 1,
-- if config.rsyncOps then
-- The core should not split move events error('did you mean rsyncOpts with "t"?', 4)
-- end
onMove = true,
-- -- appends a slash to the targetdir if missing
-- default delay if string.sub(config.targetdir, -1) ~= '/' then
-- config.targetdir = config.targetdir .. '/'
delay = 15, end
end
--
-- allow processes
--
rsyncssh.maxProcesses = 1
--
-- The core should not split move events
--
rsyncssh.onMove = true
--
-- default delay
--
rsyncssh.delay = 15
-- --
-- by default do deletes -- no default exit codes
-- --
delete = true, rsyncssh.exitcodes = false
--
-- rsync exit codes
--
rsyncssh.rsyncExitCodes = default.rsyncExitCodes
--
-- ssh exit codes
--
rsyncssh.sshExitCodes = default.sshExitCodes
--
-- xargs calls configuration
--
-- xargs is used to delete multiple remote files, when ssh access is
-- available this is simpler than to build filters for rsync for this.
--
rsyncssh.xargs = {
-- --
-- rsync exit codes -- the binary called (on target host)
-- binary = '/usr/bin/xargs',
rsyncExitCodes = default.rsyncExitCodes,
-- --
-- ssh exit codes -- delimiter, uses null by default, you might want to override this for older
-- -- by for example '\n'
sshExitCodes = default.sshExitCodes, delimiter = '\000',
-- --
-- xargs calls configuration -- extra parameters
-- _extra = { '-0', 'rm -rf' }
-- xargs is used to delete multiple remote files, when ssh access is
-- available this is simpler than to build filters for rsync for this.
--
xargs = {
--
-- the binary called (on target host)
binary = '/usr/bin/xargs',
--
-- delimiter, uses null by default, you might want to override this for older
-- by for example '\n'
delimiter = '\000',
--
-- extra parameters
_extra = { '-0', 'rm -rf' }
},
--
-- ssh calls configuration
--
-- ssh is used to move and delete files on the target host
--
ssh = {
--
-- the binary called
binary = '/usr/bin/ssh',
--
-- if set connect to this port
port = nil,
--
-- extra parameters
_extra = { }
}
} }
--
-- ssh calls configuration
--
-- ssh is used to move and delete files on the target host
--
rsyncssh.ssh = {
--
-- the binary called
--
binary = '/usr/bin/ssh',
--
-- if set connect to this port
--
port = nil,
--
-- extra parameters
--
_extra = { }
}

View File

@ -9,237 +9,332 @@
--============================================================================ --============================================================================
if default then if default then
error('default already loaded') error( 'default already loaded' )
end end
default = { default = { }
-----
-- Default action calls user scripts on**** functions.
--
action = function(inlet)
-- in case of moves getEvent returns the origin and dest of the move
local event, event2 = inlet.getEvent()
local config = inlet.getConfig()
local func = config['on'.. event.etype]
if func then
func(event, event2)
end
-- if function didnt change the wait status its not interested
-- in this event -> drop it.
if event.status == 'wait' then
inlet.discardEvent(event)
end
end,
----- --
-- Default collector. -- used to ensure there aren't typos in the keys
-- --
-- Called when collecting a finished child process default.checkgauge = {
-- action = true,
collect = function(agent, exitcode) checkgauge = true,
collect = true,
delay = true,
exitcodes = true,
init = true,
maxDelays = true,
maxProcesses = true,
onCreate = true,
onModify = true,
onDelete = true,
onStartup = true,
onMove = true,
prepare = true,
rsyncExitCodes = true, -- TODO
sshExitCodes = true -- TODO
}
local config = agent.config --
local rc -- On default action the user's on*** scripts are called.
--
default.action = function( inlet )
if config.exitcodes then -- in case of moves getEvent returns the origin and dest of the move
rc = config.exitcodes[exitcode] local event, event2 = inlet.getEvent( )
elseif exitcode == 0 then local config = inlet.getConfig( )
rc = 'ok'
else
rc = 'die'
end
-- TODO synchronize with similar code before local func = config[ 'on'.. event.etype ]
if not agent.isList and agent.etype == 'Init' then
if rc == 'ok' then
log('Normal', 'Startup of "',agent.source,'" finished.')
return 'ok'
elseif rc == 'again' then
if settings.insist then
log(
'Normal',
'Retrying startup of "',
agent.source,
'": ',
exitcode
)
return 'again' if func then
else func( event, event2 )
log( end
'Error',
'Temporary or permanent failure on startup of "',
agent.source,
'". Terminating since "insist" is not set.'
)
terminate( -1 ) -- if function didnt change the wait status its not interested
end -- in this event -> drop it.
elseif rc == 'die' then if event.status == 'wait' then
inlet.discardEvent( event )
end
end
--
-- Default collector.
--
-- Called when collecting a finished child process
--
default.collect = function( agent, exitcode )
local config = agent.config
local rc
if config.exitcodes then
rc = config.exitcodes[exitcode]
elseif exitcode == 0 then
rc = 'ok'
else
rc = 'die'
end
-- TODO synchronize with similar code before
if not agent.isList and agent.etype == 'Init' then
if rc == 'ok' then
log('Normal', 'Startup of "',agent.source,'" finished.')
return 'ok'
elseif rc == 'again' then
if settings.insist then
log(
'Normal',
'Retrying startup of "',
agent.source,
'": ',
exitcode
)
return 'again'
else
log( log(
'Error', 'Error',
'Failure on startup of "', 'Temporary or permanent failure on startup of "',
agent.source, agent.source,
'".' '". Terminating since "insist" is not set.'
) )
terminate( -1 ) terminate( -1 )
else
log(
'Error',
'Unknown exitcode "',
exitcode,
'" on startup of "',
agent.source,
'".'
)
return 'die'
end end
end elseif rc == 'die' then
log(
'Error',
'Failure on startup of "',
agent.source,
'".'
)
if agent.isList then terminate( -1 )
if rc == 'ok' then
log(
'Normal',
'Finished a list after exitcode: ',
exitcode
)
elseif rc == 'again' then
log(
'Normal',
'Retrying a list after exitcode = ',
exitcode
)
elseif rc == 'die' then
log(
'Error',
'Failure with a list width exitcode = ',
exitcode
)
else
log(
'Error',
'Unknown exitcode "',exitcode,'" with a list'
)
rc = 'die'
end
else else
if rc == 'ok' then log(
log('Normal', 'Retrying ',agent.etype,' on ',agent.sourcePath,' = ',exitcode) 'Error',
elseif rc == 'again' then 'Unknown exitcode "',
log('Normal', 'Finished ',agent.etype,' on ',agent.sourcePath,' = ',exitcode) exitcode,
elseif rc == 'die' then '" on startup of "',
log('Error', 'Failure with ',agent.etype,' on ',agent.sourcePath,' = ',exitcode) agent.source,
else '".'
log('Normal', 'Unknown exitcode "',exitcode,'" with ', agent.etype, )
' on ',agent.sourcePath,' = ',exitcode) return 'die'
rc = 'die'
end
end end
end
return rc if agent.isList then
end, if rc == 'ok' then
log(
'Normal',
'Finished a list after exitcode: ',
exitcode
)
elseif rc == 'again' then
log(
'Normal',
'Retrying a list after exitcode = ',
exitcode
)
elseif rc == 'die' then
log(
'Error',
'Failure with a list width exitcode = ',
exitcode
)
else
log(
'Error',
'Unknown exitcode "',exitcode,'" with a list'
)
----- rc = 'die'
-- called on (re)initialization of Lsyncd.
--
init = function(event)
local config = event.config
local inlet = event.inlet
-- user functions
-- calls a startup if given by user script.
if type(config.onStartup) == 'function' then
local startup = config.onStartup(event)
-- TODO honor some return codes of startup like "warmstart".
end end
else
if event.status == 'wait' then if rc == 'ok' then
-- user script did not spawn anything log('Normal', 'Retrying ',agent.etype,' on ',agent.sourcePath,' = ',exitcode)
-- thus the blanket event is deleted again. elseif rc == 'again' then
inlet.discardEvent(event) log('Normal', 'Finished ',agent.etype,' on ',agent.sourcePath,' = ',exitcode)
elseif rc == 'die' then
log('Error', 'Failure with ',agent.etype,' on ',agent.sourcePath,' = ',exitcode)
else
log('Normal', 'Unknown exitcode "',exitcode,'" with ', agent.etype,
' on ',agent.sourcePath,' = ',exitcode)
rc = 'die'
end end
end, end
return rc
end
--
-- Called on the Init event sent
-- on (re)initialization of Lsyncd for every sync
--
default.init = function(event)
local config = event.config
local inlet = event.inlet
-- user functions
-- calls a startup if given by user script.
if type(config.onStartup) == 'function' then
local startup = config.onStartup(event)
-- TODO honor some return codes of startup like "warmstart".
end
if event.status == 'wait' then
-- user script did not spawn anything
-- thus the blanket event is deleted again.
inlet.discardEvent(event)
end
end
--
-- The maximum number of processes Lsyncd will
-- simultanously spawn for this sync.
--
default.maxProcesses = 1
--
-- The collapsor tries not to have more than these delays.
-- So it dealy stack does not grow too large,
-- since calculation for stacking events is n*log(n) (or so)
--
default.maxDelays = 1000
---
-- a default configuration using /bin/cp|rm|mv.
-- TODO huh?
--
default.direct = default_direct
--
-- Exitcodes of rsync and what to do.
-- TODO move to rsync
--
default.rsyncExitCodes = {
-----
-- The maximum number of processes Lsyncd will spawn simultanously for
-- one sync.
-- --
maxProcesses = 1, -- if another config provides the same table
-- this will not be inherited (merged) into that one
-----
-- Try not to have more than these delays.
-- not too large, since total calculation for stacking
-- events is n*log(n) or so..
-- --
maxDelays = 1000, -- if it does not, integer keys are to be copied
-- verbatim
-----
-- a default configuration using /bin/cp|rm|mv.
-- --
direct = default_direct, _merge = false,
_verbatim = true,
------ [ 0 ] = 'ok',
-- Exitcodes of rsync and what to do. [ 1 ] = 'die',
-- [ 2 ] = 'die',
rsyncExitCodes = { [ 3 ] = 'again',
[ 4 ] = 'die',
[ 5 ] = 'again',
[ 6 ] = 'again',
[ 10 ] = 'again',
[ 11 ] = 'again',
[ 12 ] = 'again',
[ 14 ] = 'again',
[ 20 ] = 'again',
[ 21 ] = 'again',
[ 22 ] = 'again',
-- -- partial transfers are ok, since Lsyncd has registered the event that
-- if another config provides the same table -- caused the transfer to be partial and will recall rsync.
-- this will not be inherited (merged) into that one [ 23 ] = 'ok',
-- [ 24 ] = 'ok',
-- if it does not, integer keys are to be copied
-- verbatim
--
_merge = false,
_verbatim = true,
[ 0 ] = 'ok', [ 25 ] = 'die',
[ 1 ] = 'die', [ 30 ] = 'again',
[ 2 ] = 'die', [ 35 ] = 'again',
[ 3 ] = 'again',
[ 4 ] = 'die',
[ 5 ] = 'again',
[ 6 ] = 'again',
[ 10 ] = 'again',
[ 11 ] = 'again',
[ 12 ] = 'again',
[ 14 ] = 'again',
[ 20 ] = 'again',
[ 21 ] = 'again',
[ 22 ] = 'again',
-- partial transfers are ok, since Lsyncd has registered the event that
-- caused the transfer to be partial and will recall rsync.
[ 23 ] = 'ok',
[ 24 ] = 'ok',
[ 25 ] = 'die',
[ 30 ] = 'again',
[ 35 ] = 'again',
[ 255 ] = 'again',
},
----- [ 255 ] = 'again',
-- Exitcodes of ssh and what to do.
--
sshExitCodes = {
--
-- if another config provides the same table
-- this will not be inherited (merged) into that one
--
-- if it does not, integer keys are to be copied
-- verbatim
--
_merge = false,
_verbatim = true,
[ 0 ] = 'ok',
[ 255 ] = 'again',
},
-----
-- Minimum seconds between two writes of a status file.
--
statusInterval = 10,
} }
--
-- Exitcodes of ssh and what to do.
--
default.sshExitCodes = {
--
-- if another config provides the same table
-- this will not be inherited (merged) into that one
--
-- if it does not, integer keys are to be copied
-- verbatim
--
_merge = false,
_verbatim = true,
[ 0 ] = 'ok',
[ 255 ] = 'again',
}
--
-- Minimum seconds between two writes of a status file.
--
default.statusInterval = 10
--
-- checks all keys to be in the checkgauge
--
local function check(
config,
gauge,
level
)
for k, v in pairs( config ) do
if not gauge[k] then
error(
'Parameter "'
.. k
.. '" unknown.'
.. ' (if this is not a typo add it to checkgauge)',
level
);
end
if type( gauge [ k ] ) == 'table' then
if type( v ) ~= 'table' then
error(
'Parameter "'
.. k
.. '" must be a table.',
level
)
end
check( config[ k ], gauge[ k ], level + 1 )
end
end
end
default.prepare = function( config, level )
local gauge = config.checkgauge
if not gauge then
return
end
check( config, gauge, level or 2 )
end