summaryrefslogtreecommitdiffstats
path: root/app/service-model.lua
blob: d6fb192596c744a67b8e7bb3d02d84f83cd6671e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
module (..., package.seeall)

require "fs"


--TODO this should be somehow figureoutable from acf info, help!
local cfgdir = "/usr/share/acf/app/service"

--TODO, in fs actually, find should use coroutines instead of reading
--all in table

local spec = nil

--TODO might on demand load only part of config that is needed for this app
--but then TODO need to make persistent item ids
local function loadCfg()
    if spec ~= nil then return end
    spec = {}
    for fname in fs.find(".*%.srv", cfgdir) do
        f = io.open(fname, 'r')
        if f then
	    s = f:read("*a")
	    f:close()
	    if s then
                c = loadstring("return ({\n" .. s .. "\n})")
	        if c then
		    for i,v in ipairs(c()) do
                        spec[#spec + 1] = v
		    end
		end
	    end
	end
    end
end



local function getAnyPid(pname)
    for e in lfs.dir("/proc") do
        if e == string.match(e, "^%d*$") then
            for line in io.lines("/proc/" .. e .. "/status") do
                tag, val = string.match(line, "^([^:]*):%s*(%S*)$");
                if tag == "Name" then
                    if val == pname then return e end
                    break
                end
            end
        end
    end
end

local mech = {}

function mech.initd(service, action)
    if not service.initd then return false, "no initd" end
    local f = io.popen("/etc/init.d/" .. service.initd .. ' ' .. action, "r")
    if not f then return false, "cannot run initd" end
    local ret = f:read("*a")
    f:close()
    return true, ret
end

function mech.pidfile(svc, action)
    if not service.pidfile then return false end
    if action ~= "status" then return false end
    f = io.open(svc.pidfile)
    if not f then return true, false end
    pid = tonumber(f:read("*a"))
    f:close()
    if not pid then return true, false end
    f = io.open("/proc/" .. tostring(pid) .. "/status")
    if not f then return true, false end
    if svc.pidcmdname then
        for line in f:lines() do
            k, v = string.match(line, '^([^:]*):%s*(.*)$')
            if k == "Name" then
                return true, (v == svc.pidcmdname)
            end
        end
    end
    f:close()
    return true, true
end

local function serviceAction(service, action)
    if not service[action] then return false, "no such action " .. action end
    return mech[service[action]](service, action)
end

local function getServiceActions(service)
    local ret = {}
    if service.start then ret[#ret + 1] = "start" end
    if service.stop then ret[#ret + 1] = "stop" end
    if service.restart then ret[#ret + 1] = "restart" end
    if service.reload then ret[#ret + 1] = "reload" end
    return ret
end

function list(self, app)
    loadCfg()
    ret = {}
    for k,v in pairs(spec) do
        if v.app == app then
            ret[#ret+1] = {
                id=k,
                name=v.name,
                descr=v.descr or "",
                status=serviceAction(v, "status"),
                actions=getServiceActions(v)
            }
        end
    end
    return ret
end

function update(self, id, action)
    loadCfg()
    svc = spec[id]
    if not svc then return false, "no service" end
    return serviceAction(svc, action)
end