containers.lua 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. --[[
  2. LuCI - Lua Configuration Interface
  3. Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
  4. ]]--
  5. require "luci.util"
  6. local http = require "luci.http"
  7. local uci = luci.model.uci.cursor()
  8. local docker = require "luci.model.docker"
  9. local dk = docker.new()
  10. local images, networks, containers
  11. local res = dk.images:list()
  12. if res.code <300 then images = res.body else return end
  13. res = dk.networks:list()
  14. if res.code <300 then networks = res.body else return end
  15. res = dk.containers:list({query = {all=true}})
  16. if res.code <300 then containers = res.body else return end
  17. local urlencode = luci.http.protocol and luci.http.protocol.urlencode or luci.util.urlencode
  18. function get_containers()
  19. local data = {}
  20. if type(containers) ~= "table" then return nil end
  21. for i, v in ipairs(containers) do
  22. local index = v.Created .. v.Id
  23. data[index]={}
  24. data[index]["_selected"] = 0
  25. data[index]["_id"] = v.Id:sub(1,12)
  26. data[index]["name"] = v.Names[1]:sub(2)
  27. data[index]["_name"] = '<a href='..luci.dispatcher.build_url("admin/docker/container/"..v.Id)..' class="dockerman_link" title="'..translate("Container detail")..'">'.. v.Names[1]:sub(2).."</a>"
  28. data[index]["_status"] = v.Status
  29. if v.Status:find("^Up") then
  30. data[index]["_status"] = '<font color="green">'.. data[index]["_status"] .. "</font>"
  31. else
  32. data[index]["_status"] = '<font color="red">'.. data[index]["_status"] .. "</font>"
  33. end
  34. if (type(v.NetworkSettings) == "table" and type(v.NetworkSettings.Networks) == "table") then
  35. for networkname, netconfig in pairs(v.NetworkSettings.Networks) do
  36. data[index]["_network"] = (data[index]["_network"] ~= nil and (data[index]["_network"] .." | ") or "").. networkname .. (netconfig.IPAddress ~= "" and (": " .. netconfig.IPAddress) or "")
  37. end
  38. end
  39. -- networkmode = v.HostConfig.NetworkMode ~= "default" and v.HostConfig.NetworkMode or "bridge"
  40. -- data[index]["_network"] = v.NetworkSettings.Networks[networkmode].IPAddress or nil
  41. -- local _, _, image = v.Image:find("^sha256:(.+)")
  42. -- if image ~= nil then
  43. -- image=image:sub(1,12)
  44. -- end
  45. if v.Ports and next(v.Ports) ~= nil then
  46. data[index]["_ports"] = nil
  47. for _,v2 in ipairs(v.Ports) do
  48. data[index]["_ports"] = (data[index]["_ports"] and (data[index]["_ports"] .. ", ") or "")
  49. .. ((v2.PublicPort and v2.Type and v2.Type == "tcp") and ('<a href="javascript:void(0);" onclick="window.open((window.location.origin.match(/^(.+):\\d+$/) && window.location.origin.match(/^(.+):\\d+$/)[1] || window.location.origin) + \':\' + '.. v2.PublicPort ..', \'_blank\');">') or "")
  50. .. (v2.PublicPort and (v2.PublicPort .. ":") or "") .. (v2.PrivatePort and (v2.PrivatePort .."/") or "") .. (v2.Type and v2.Type or "")
  51. .. ((v2.PublicPort and v2.Type and v2.Type == "tcp")and "</a>" or "")
  52. end
  53. end
  54. for ii,iv in ipairs(images) do
  55. if iv.Id == v.ImageID then
  56. data[index]["_image"] = iv.RepoTags and iv.RepoTags[1] or (iv.RepoDigests[1]:gsub("(.-)@.+", "%1") .. ":<none>")
  57. end
  58. end
  59. data[index]["_image_id"] = v.ImageID:sub(8,20)
  60. data[index]["_command"] = v.Command
  61. end
  62. return data
  63. end
  64. local c_lists = get_containers()
  65. -- list Containers
  66. -- m = Map("docker", translate("Docker"))
  67. m = SimpleForm("docker", translate("Docker"))
  68. m.submit=false
  69. m.reset=false
  70. docker_status = m:section(SimpleSection)
  71. docker_status.template = "dockerman/apply_widget"
  72. docker_status.err=docker:read_status()
  73. docker_status.err=docker_status.err and docker_status.err:gsub("\n","<br>"):gsub(" ","&nbsp;")
  74. if docker_status.err then docker:clear_status() end
  75. c_table = m:section(Table, c_lists, translate("Containers"))
  76. c_table.nodescr=true
  77. -- v.template = "cbi/tblsection"
  78. -- v.sortable = true
  79. container_selecter = c_table:option(Flag, "_selected","")
  80. container_selecter.disabled = 0
  81. container_selecter.enabled = 1
  82. container_selecter.default = 0
  83. container_id = c_table:option(DummyValue, "_id", translate("ID"))
  84. container_id.width="10%"
  85. container_name = c_table:option(DummyValue, "_name", translate("Container Name"))
  86. container_name.rawhtml = true
  87. container_status = c_table:option(DummyValue, "_status", translate("Status"))
  88. container_status.width="15%"
  89. container_status.rawhtml=true
  90. container_ip = c_table:option(DummyValue, "_network", translate("Network"))
  91. container_ip.width="15%"
  92. container_ports = c_table:option(DummyValue, "_ports", translate("Ports"))
  93. container_ports.width="10%"
  94. container_ports.rawhtml = true
  95. container_image = c_table:option(DummyValue, "_image", translate("Image"))
  96. container_image.width="10%"
  97. container_command = c_table:option(DummyValue, "_command", translate("Command"))
  98. container_command.width="20%"
  99. container_selecter.write=function(self, section, value)
  100. c_lists[section]._selected = value
  101. end
  102. local start_stop_remove = function(m,cmd)
  103. local c_selected = {}
  104. -- 遍历table中sectionid
  105. local c_table_sids = c_table:cfgsections()
  106. for _, c_table_sid in ipairs(c_table_sids) do
  107. -- 得到选中项的名字
  108. if c_lists[c_table_sid]._selected == 1 then
  109. c_selected[#c_selected+1] = c_lists[c_table_sid].name --container_name:cfgvalue(c_table_sid)
  110. end
  111. end
  112. if #c_selected >0 then
  113. docker:clear_status()
  114. local success = true
  115. for _,cont in ipairs(c_selected) do
  116. docker:append_status("Containers: " .. cmd .. " " .. cont .. "...")
  117. local res = dk.containers[cmd](dk, {id = cont})
  118. if res and res.code >= 300 then
  119. success = false
  120. docker:append_status("code:" .. res.code.." ".. (res.body.message and res.body.message or res.message).. "\n")
  121. else
  122. docker:append_status("done\n")
  123. end
  124. end
  125. if success then docker:clear_status() end
  126. luci.http.redirect(luci.dispatcher.build_url("admin/docker/containers"))
  127. end
  128. end
  129. action_section = m:section(Table,{{}})
  130. action_section.notitle=true
  131. action_section.rowcolors=false
  132. action_section.template="cbi/nullsection"
  133. btnnew=action_section:option(Button, "_new")
  134. btnnew.inputtitle= translate("New")
  135. btnnew.template = "dockerman/cbi/inlinebutton"
  136. btnnew.inputstyle = "add"
  137. btnnew.forcewrite = true
  138. btnstart=action_section:option(Button, "_start")
  139. btnstart.template = "dockerman/cbi/inlinebutton"
  140. btnstart.inputtitle=translate("Start")
  141. btnstart.inputstyle = "apply"
  142. btnstart.forcewrite = true
  143. btnrestart=action_section:option(Button, "_restart")
  144. btnrestart.template = "dockerman/cbi/inlinebutton"
  145. btnrestart.inputtitle=translate("Restart")
  146. btnrestart.inputstyle = "reload"
  147. btnrestart.forcewrite = true
  148. btnstop=action_section:option(Button, "_stop")
  149. btnstop.template = "dockerman/cbi/inlinebutton"
  150. btnstop.inputtitle=translate("Stop")
  151. btnstop.inputstyle = "reset"
  152. btnstop.forcewrite = true
  153. btnkill=action_section:option(Button, "_kill")
  154. btnkill.template = "dockerman/cbi/inlinebutton"
  155. btnkill.inputtitle=translate("Kill")
  156. btnkill.inputstyle = "reset"
  157. btnkill.forcewrite = true
  158. btnremove=action_section:option(Button, "_remove")
  159. btnremove.template = "dockerman/cbi/inlinebutton"
  160. btnremove.inputtitle=translate("Remove")
  161. btnremove.inputstyle = "remove"
  162. btnremove.forcewrite = true
  163. btnnew.write = function(self, section)
  164. luci.http.redirect(luci.dispatcher.build_url("admin/docker/newcontainer"))
  165. end
  166. btnstart.write = function(self, section)
  167. start_stop_remove(m,"start")
  168. end
  169. btnrestart.write = function(self, section)
  170. start_stop_remove(m,"restart")
  171. end
  172. btnremove.write = function(self, section)
  173. start_stop_remove(m,"remove")
  174. end
  175. btnstop.write = function(self, section)
  176. start_stop_remove(m,"stop")
  177. end
  178. btnkill.write = function(self, section)
  179. start_stop_remove(m,"kill")
  180. end
  181. return m