Commit 337584d2 authored by Ted Trask's avatar Ted Trask
Browse files

Rewrite of DNScache.

git-svn-id: svn://svn.alpinelinux.org/acf/dnscache/trunk@1262 ab2d0c66-481e-0410-8bed-d214d4d58bed
parent 30aaf3f8
<? local form, viewlibrary = ...
require("viewfunctions")
?>
<?
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
io.write(html.cfe_unpack(form))
io.write("</span>")
--]]
?>
<? if viewlibrary and viewlibrary.dispatch_component then
viewlibrary.dispatch_component("status")
end ?>
<H1>Config</H1>
<?
displayform(form)
?>
<? if viewlibrary and viewlibrary.dispatch_component then
viewlibrary.dispatch_component("startstop")
end ?>
......@@ -3,115 +3,108 @@ module(..., package.seeall)
-- Load libraries
require("format")
-- Set variables
local newrecordtxt = "[New]"
-- ################################################################################
-- LOCAL FUNCTIONS
local function displaycmdmanagement(pidofstatus)
-- Add a management buttons
local management = {}
management.start = cfe({ name="cmdmanagement",
label="Program control-panel",
value="Start",
type="submit",
})
management.stop = cfe({ name="cmdmanagement",
label="Program control-panel",
value="Stop",
type="submit",
})
management.restart = cfe({ name="cmdmanagement",
label="Program control-panel",
value="Restart",
type="submit",
})
-- next CFE can be used to present the result of the previous action
management.actionresult = cfe({ name="actionresult",
label="Previous action result",
})
-- Disable management buttons based on if the process is running or not
if (pidofstatus) then
management.start.disabled = "yes"
else
management.stop.disabled = "yes"
management.restart.disabled = "yes"
local function handle_form(getFunction, setFunction, clientdata, option, label, descr)
local form = getFunction()
if clientdata[option] then
form.errtxt = nil
for name,value in pairs(form.value) do
value.errtxt = nil
if value.type == "boolean" then
value.value = (clientdata[name] ~= nil)
elseif value.type == "list" then
value.value = {}
if clientdata[name] and clientdata[name] ~= "" then
for ip in string.gmatch(clientdata[name].."\n", "%s*(%S[^\n]*%S)%s*\n") do
table.insert(value.value, ip)
end
end
else
value.value = clientdata[name] or value.value
end
end
form = setFunction(form)
if not form.errtxt then
form.descr = descr
end
end
return management
end
form.type = "form"
form.option = option
form.label = label
-- ################################################################################
-- PUBLIC FUNCTIONS
return form
end
default_action = "status"
function status(self)
return { status=self.model.getstatus() }
return self.model.getstatus()
end
function expert(self)
local modifications = self.clientdata.filecontent or ""
if ( self.clientdata.cmdsave ) then
modifications = self.model:update_filecontent(modifications)
function startstop(self)
local result
if self.clientdata.action then
result = self.model.startstop_service(self.clientdata.action)
self.sessiondata.dnscachestartstopresult = result
self.redirect_to_referrer(self)
end
local url = self.conf.script .. self.conf.prefix .. self.conf.controller
-- Start/Stop/Restart process
local cmdmanagement, actionresult
if ( self.clientdata.cmdmanagement) then
cmdmanagement = cfe({
name="cmdmanagement",
label="Previous action result",
action=cfe({
name="cmdmanagement",
value=string.lower(self.clientdata.cmdmanagement), -- This row contains start/stop/restart (one of these commands)
}),
})
actionresult, cmdmanagement = self.model:startstop_service( cmdmanagement.action )
local status = self.model.getstatus()
status = status.value.status
if self.sessiondata.dnscachestartstopresult then
result = self.sessiondata.dnscachestartstopresult
self.sessiondata.dnscachestartstopresult = nil
end
local status=self.model.getstatus()
local file = self.model:get_filedetails()
-- Add buttons
file.cmdsave = cfe ({
name="cmdsave",
label="Apply settings",
value="Apply",
type="submit",
})
if (self.clientdata.cmdsave) then
file.cmdsave.descr="* Changes has been saved!"
end
-- Management buttons (Hide/show buttons
local pidofstatus
if (string.lower(status.status.value) == "enabled" ) then pidofstatus = true end
management = displaycmdmanagement(pidofstatus)
if (actionresult) then
management.actionresult.descr=cmdmanagement.descr
management.actionresult.errtxt=cmdmanagement.errtxt
return cfe({ type="group", value={status=status, result=result} })
end
function config(self)
return handle_form(self.model.getconfig, self.model.setconfig, self.clientdata, "Save", "Edit Config", "Configuration Set")
end
function expert(self)
local filedetails
if self.clientdata.Save then
filedetails = self.model.setconfigfile(self.clientdata.filecontent)
if not filedetails.errtxt then
filedetails.descr = "Config file set"
end
else
filedetails = self.model.getconfigfile()
end
return ( {
status = status,
file = file,
modifications = modifications,
management = management,
url = url, } )
filedetails.type = "form"
filedetails.option = "Save"
filedetails.label = "Set config file"
return filedetails
end
function editips(self)
return handle_form(self.model.getIPs, self.model.setIPs, self.clientdata, "Save", "Edit IP List", "IP List Set")
end
function logfile(self)
function listdomains(self)
return self.model.getDomains()
end
local status=self.model.getstatus()
local logfile = self.model:get_logfile()
function createdomain(self)
local cmdresult = handle_form(self.model.getNewDomain, self.model.setNewDomain, self.clientdata, "Create", "Create new domain", "New domain created")
if cmdresult.descr then
redirect_to_referrer(self)
end
return cmdresult
end
function editdomain(self)
return handle_form(function(form) return self.model.getDomain(self.clientdata.domain) end,
self.model.setDomain, self.clientdata, "Save", "Edit domain entry", "Domain saved")
end
return ({
status = status,
logfile = logfile,
url = url,
})
function deletedomain(self)
local cmdresult = self.model.deleteDomain(self.clientdata.domain)
redirect_to_referrer(self)
return cmdresult
end
<? local form, viewlibrary = ...
require("viewfunctions")
?>
<?
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
io.write(html.cfe_unpack(form))
io.write("</span>")
--]]
?>
<H1><?= form.label ?></H1>
<?
form.action = "createdomain"
local order = { }
displayform(form, order)
?>
<? local form, viewlibrary = ...
require("viewfunctions")
?>
<?
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
io.write(html.cfe_unpack(form))
io.write("</span>")
--]]
?>
<H1><?= form.label ?></H1>
<?
form.value.domain.contenteditable = false
local order = { "domain", "iplist" }
displayform(form, order)
?>
<? local form, viewlibrary = ...
require("viewfunctions")
?>
<?
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
io.write(html.cfe_unpack(form))
io.write("</span>")
--]]
?>
<H1><?= form.label ?></H1>
<?
displayform(form)
?>
<? local form = ...
require("viewfunctions")
?>
<? local form, viewlibrary = ... ?>
<? require("viewfunctions") ?>
<?
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
......@@ -9,50 +8,43 @@ io.write("</span>")
--]]
?>
<H1>SYSTEM INFO</H1>
<DL>
<?
local myform = form.status
local tags = { "status", "version", "autostart", }
displayinfo(myform,tags,"viewonly")
?>
</DL>
<? ---[[ ?>
<? if viewlibrary and viewlibrary.dispatch_component then
viewlibrary.dispatch_component("status")
end ?>
<? --]] ?>
<form name="myform" action="" method="POST">
<h1>CONFIGURATION</h1>
<H2>Expert config</H2>
<h3>File details</h3>
<H1>Configuration</H1>
<H2>Expert Configuration</H2>
<H3>File Details</H3>
<DL>
<?
local myform = form.file
local tags = { "filename", "filesize", "mtime", "sumerrors", }
displayinfo(myform,tags,"viewonly")
displayitem(form.value.filename)
displayitem(form.value.filesize)
displayitem(form.value.mtime)
?>
</DL>
<H3>FILE CONTENT</H3>
<?
local myform = form.file
io.write(html.form[myform.filecontent.type](myform.filecontent))
?>
<H3>File Content</H3>
<? if form.descr then ?><P CLASS='descr'><?= string.gsub(form.descr, "\n", "<BR>") ?></P><? end ?>
<? if form.errtxt then ?><P CLASS='error'><?= string.gsub(form.errtxt, "\n", "<BR>") ?></P><? end ?>
<form action="" method="POST">
<textarea name="filecontent">
<?= form.value.filecontent.value ?>
</textarea>
<? if form.value.filecontent.errtxt then ?><P CLASS='error'><?= string.gsub(form.value.filecontent.errtxt, "\n", "<BR>") ?></P><? end ?>
<H2>SAVE AND APPLY ABOVE SETTINGS</H2>
<DL>
<?
local tags = { "cmdsave", }
displayinfo(myform,tags)
?>
</DL>
<DL><DT></DT><DD><input class="submit" type="submit" name="<?= form.option ?>" value="Save"></DD></DL>
</form>
<? if viewlibrary and viewlibrary.dispatch_component then
viewlibrary.dispatch_component("startstop")
end ?>
<?
-- Management buttons
local myform = form.management
local tags = { "start", "stop", "restart" }
if (myform) then
io.write("<H1>MANAGEMENT</H1>\n<DL>")
displaymanagement(myform,tags)
io.write("</DL>")
end
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
io.write(html.cfe_unpack(form))
io.write("</span>")
--]]
?>
</form>
<? local data, viewlibrary = ...
require("viewfunctions")
?>
<?
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
io.write(html.cfe_unpack(data))
io.write("</span>")
--]]
?>
<h1>Configuration</h1>
<h2>Edit/View DNS server entries</h2>
<TABLE>
<TR style="background:#eee;font-weight:bold;">
<TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Action</TD>
<TD style="white-space:nowrap;text-align:left;" class="header">Domain</TD>
</TR>
<? for i,domain in ipairs(data.value) do ?>
<TR>
<TD style="padding-right:20px;white-space:nowrap;">
<? io.write(html.link{value = "editdomain?domain=" .. domain, label="Edit " }) ?>
<? if domain ~= "@" then
io.write(html.link{value = "deletedomain?domain=" .. domain, label="Delete " })
end ?>
</TD>
<TD style="white-space:nowrap;" width="90%"><?= domain ?></TD>
</TR>
<? end ?>
</TABLE>
<? if viewlibrary and viewlibrary.dispatch_component then
viewlibrary.dispatch_component("createdomain")
end ?>
<? local form = ... ?>
<?
require("viewfunctions")
?>
<H1>SYSTEM INFO</H1>
<DL>
<?
local myform = form.status
local tags = { "status", "version", "autostart", }
displayinfo(myform,tags,"viewonly")
?>
</DL>
<form name="myform" action="" method="POST">
<h1>LOGFILE</h1>
<h2>Details</h2>
<DL>
<?
local myform = form.logfile
local tags = { "filename", "filesize", "mtime", "sumerrors", }
displayinfo(myform,tags,"viewonly")
?>
</DL>
<H3>FILE CONTENT</H3>
<?
io.write(html.form[myform.filecontent.type](myform.filecontent))
?>
</form>
......@@ -30,180 +30,271 @@ local function process_status_text(procname)
end
end
local function humanreadable(value)
local myvalue = tonumber(value)
if not (myvalue) then
return false
end
if ( myvalue > 1073741824 ) then
myvalue=((myvalue/1073741824) - (myvalue/1073741824%0.1)) .. "G"
elseif ( myvalue > 1048576 ) then
myvalue=((myvalue/1048576) - (myvalue/1048576%0.1)) .. "M"
elseif ( myvalue > 1024 ) then
myvalue=((myvalue/1024) - (myvalue/1024%0.1)) .. "k"
end
return myvalue
end
local function list_servers()
local serverlist = {}
local serverdetails = {}
for k,v in pairs(posix.dir(baseurl .. "servers")) do
if not string.match(v, "^%.") then
if (fs.is_file(baseurl .. "servers/" .. v)) then
table.insert(serverlist, v)
serverdetails[v] = fs.read_file_as_array(baseurl .. "servers/" .. v)
end
local function validateconfig(config)
local success = true
if config.value.IPSEND and not validator.is_ipv4(config.value.IPSEND.value) then
config.value.IPSEND.errtxt = "Invalid IP address"
success = false
end
if config.value.CACHESIZE and not validator.is_integer(config.value.CACHESIZE.value) then
config.value.CACHESIZE.errtxt = "Must be an integer"
success = false
end
if config.value.IP and not validator.is_ipv4(config.value.IP.value) then
config.value.IP.errtxt = "Invalid IP address"
success = false
end
return success, config
end
local function getfiledetails(file)
local filename = cfe({ value=file, label="File name" })
local filecontent = cfe({ type="longtext", label="File content" })
local filesize = cfe({ value="0", label="File size" })
local mtime = cfe({ value="---", label="File date" })
if fs.is_file(file) then
local filedetails = fs.stat(file)
filecontent.value = fs.read_file(file)
filesize.value = filedetails.size
mtime.value = filedetails.mtime
else
filename.errtxt = "File not found"
end
return cfe({ type="group", value={filename=filename, filecontent=filecontent, filesize=filesize, mtime=mtime}, label="Config file details" })
end
local function validatedomain(domain)
local success = false
local domains = getDomains()
domain.value.domain.errtxt = "Invalid domain"
for i,name in ipairs(domains.value) do
if name == domain.value.domain.value then
domain.value.domain.errtxt = nil
success = true
break
end
end
for i,name in ipairs(domain.value.iplist.value) do
if not validator.is_ipv4(name) then
domain.value.iplist.errtxt = "Invalid IP address"
success = false
break
end
end
return serverlist, serverdetails
return success, domain
end
-- ################################################################################
-- PUBLIC FUNCTIONS
function startstop_service ( self, action )
local cmd = action.value
local cmdresult,cmdmessage,cmderror,cmdaction = daemoncontrol.daemoncontrol(processname, cmd)
action.descr=cmdmessage
action.errtxt=cmderror
return cmdresult,action
function startstop_service(action)
-- action is validated in daemoncontrol
local cmdresult,cmdmessage,cmderror,cmdaction = daemoncontrol.daemoncontrol(processname, action)
return cfe({ type="boolean", value=cmdresult, descr=cmdmessage, errtxt=cmderror, label="Start/Stop result" })
end
function getstatus()
local status = {}
local config = getconfig()
local value, errtxt = processinfo.package_version(packagename)
status.version = cfe({ name = "version",
status.version = cfe({
label="Program version",
value=value,
errtxt=errtxt,
})
status.status = cfe({ name="status",
status.status = cfe({
label="Program status",
value=process_status_text(processname),
})
local autostart_sequense, autostart_errtxt = processinfo.process_botsequence(processname)
status.autostart = cfe({ name="autostart",
status.autostart = cfe({
label="Autostart sequence",
value=autostart_sequense,
errtxt=autostart_errtxt,
})
return cfe({ type="group", value=status, label="DNS Cache Status" })
end
status.ip = cfe({ name="ip",
label="Listening on",
value=config.IP or "",
})
function getconfig()
local conf = getopts.getoptsfromfile(configfile, "") or {}
local output = {}
output.IPSEND = cfe({ value = conf.IPSEND or "", label="IP address for requests",
descr="Use 0.0.0.0 for default address" })
output.CACHESIZE = cfe({ value=conf.CACHESIZE or "0", label="Cache size" })
output.IP = cfe({ value=conf.IP or "", label="IP address to listen on" })
output.FORWARDONLY = cfe({ type="boolean", value=(conf.FORWARDONLY and conf.FORWARDONLY ~= ""),
label="Forward only", descr="Servers are parent caches, not root servers" })
return cfe({ type="group", value=output, label="DNS Cache Config" })
end
status.cachesize = cfe({ name="cachesize",
label="Cache size",
value=humanreadable(config.CACHESIZE or ""),
})
function setconfig(config)
local success, config = validateconfig(config)
local serverlist, serverdetails = list_servers()
status.servers = cfe({ name="servers",
label="Configured DNS-servers",
value=serverlist,
option=serverdetails,
})
if success then
local file = fs.read_file(configfile)
getopts.setoptsinfile(file,"","IPSEND",config.value.IPSEND.value)
getopts.setoptsinfile(file,"","CACHESIZE",config.value.CACHESIZE.value)
getopts.setoptsinfile(file,"","IP",config.value.IP.value)
if config.value.IPSEND.value then
getopts.setoptsinfile(file,"","FORWARDONLY",config.value.IPSEND.value)
else
getopts.setoptsinfile(file,"","FORWARDONLY","")
end
fs.write_file(configfile, file)
else
config.errtxt = "Failed to set config"
end
return status
return config
end
function get_logfile ()
local file = {}
local cmdtxt = "grep ".. processname .. " /var/log/messages"
local cmd, error = io.popen(cmdtxt ,r)
local cmdoutput = cmd:read("*a")
cmd:close()
function getconfigfile()
local config = getfiledetails(configfile)
return config