From: Florian Eckert Date: Thu, 23 Jul 2020 06:52:03 +0000 (+0200) Subject: luci-app-dockerman: cbi/container update coding style X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=30caab1e739599d11c394c862cd788a302ebf65d;p=project%2Fluci.git luci-app-dockerman: cbi/container update coding style Signed-off-by: Florian Eckert --- diff --git a/applications/luci-app-dockerman/luasrc/model/cbi/dockerman/container.lua b/applications/luci-app-dockerman/luasrc/model/cbi/dockerman/container.lua index 1c39ebf4f0..0a8cbdcd19 100644 --- a/applications/luci-app-dockerman/luasrc/model/cbi/dockerman/container.lua +++ b/applications/luci-app-dockerman/luasrc/model/cbi/dockerman/container.lua @@ -4,585 +4,747 @@ Copyright 2019 lisaac ]]-- require "luci.util" + local docker = require "luci.model.docker" local dk = docker.new() + container_id = arg[1] local action = arg[2] or "info" -local images, networks, container_info -if not container_id then return end -local res = dk.containers:inspect({id = container_id}) -if res.code < 300 then container_info = res.body else return end +local m, s, o +local images, networks, container_info, res + +if not container_id then + return +end + +res = dk.containers:inspect({id = container_id}) +if res.code < 300 then + container_info = res.body +else + return +end + res = dk.networks:list() -if res.code < 300 then networks = res.body else return end +if res.code < 300 then + networks = res.body +else + return +end local get_ports = function(d) - local data - if d.HostConfig and d.HostConfig.PortBindings then - for inter, out in pairs(d.HostConfig.PortBindings) do - data = (data and (data .. "
") or "") .. out[1]["HostPort"] .. ":" .. inter - end - end - return data + local data + + if d.HostConfig and d.HostConfig.PortBindings then + for inter, out in pairs(d.HostConfig.PortBindings) do + data = (data and (data .. "
") or "") .. out[1]["HostPort"] .. ":" .. inter + end + end + + return data end local get_env = function(d) - local data - if d.Config and d.Config.Env then - for _,v in ipairs(d.Config.Env) do - data = (data and (data .. "
") or "") .. v - end - end - return data + local data + + if d.Config and d.Config.Env then + for _,v in ipairs(d.Config.Env) do + data = (data and (data .. "
") or "") .. v + end + end + + return data end local get_command = function(d) - local data - if d.Config and d.Config.Cmd then - for _,v in ipairs(d.Config.Cmd) do - data = (data and (data .. " ") or "") .. v - end - end - return data + local data + + if d.Config and d.Config.Cmd then + for _,v in ipairs(d.Config.Cmd) do + data = (data and (data .. " ") or "") .. v + end + end + + return data end local get_mounts = function(d) - local data - if d.Mounts then - for _,v in ipairs(d.Mounts) do - local v_sorce_d, v_dest_d - local v_sorce = "" - local v_dest = "" - for v_sorce_d in v["Source"]:gmatch('[^/]+') do - if v_sorce_d and #v_sorce_d > 12 then - v_sorce = v_sorce .. "/" .. v_sorce_d:sub(1,12) .. "..." - else - v_sorce = v_sorce .."/".. v_sorce_d - end - end - for v_dest_d in v["Destination"]:gmatch('[^/]+') do - if v_dest_d and #v_dest_d > 12 then - v_dest = v_dest .. "/" .. v_dest_d:sub(1,12) .. "..." - else - v_dest = v_dest .."/".. v_dest_d - end - end - data = (data and (data .. "
") or "") .. v_sorce .. ":" .. v["Destination"] .. (v["Mode"] ~= "" and (":" .. v["Mode"]) or "") - end - end - return data + local data + + if d.Mounts then + for _,v in ipairs(d.Mounts) do + local v_sorce_d, v_dest_d + local v_sorce = "" + local v_dest = "" + for v_sorce_d in v["Source"]:gmatch('[^/]+') do + if v_sorce_d and #v_sorce_d > 12 then + v_sorce = v_sorce .. "/" .. v_sorce_d:sub(1,12) .. "..." + else + v_sorce = v_sorce .."/".. v_sorce_d + end + end + for v_dest_d in v["Destination"]:gmatch('[^/]+') do + if v_dest_d and #v_dest_d > 12 then + v_dest = v_dest .. "/" .. v_dest_d:sub(1,12) .. "..." + else + v_dest = v_dest .."/".. v_dest_d + end + end + data = (data and (data .. "
") or "") .. v_sorce .. ":" .. v["Destination"] .. (v["Mode"] ~= "" and (":" .. v["Mode"]) or "") + end + end + + return data end local get_device = function(d) - local data - if d.HostConfig and d.HostConfig.Devices then - for _,v in ipairs(d.HostConfig.Devices) do - data = (data and (data .. "
") or "") .. v["PathOnHost"] .. ":" .. v["PathInContainer"] .. (v["CgroupPermissions"] ~= "" and (":" .. v["CgroupPermissions"]) or "") - end - end - return data + local data + + if d.HostConfig and d.HostConfig.Devices then + for _,v in ipairs(d.HostConfig.Devices) do + data = (data and (data .. "
") or "") .. v["PathOnHost"] .. ":" .. v["PathInContainer"] .. (v["CgroupPermissions"] ~= "" and (":" .. v["CgroupPermissions"]) or "") + end + end + + return data end local get_links = function(d) - local data - if d.HostConfig and d.HostConfig.Links then - for _,v in ipairs(d.HostConfig.Links) do - data = (data and (data .. "
") or "") .. v - end - end - return data + local data + + if d.HostConfig and d.HostConfig.Links then + for _,v in ipairs(d.HostConfig.Links) do + data = (data and (data .. "
") or "") .. v + end + end + + return data end local get_tmpfs = function(d) - local data - if d.HostConfig and d.HostConfig.Tmpfs then - for k, v in pairs(d.HostConfig.Tmpfs) do - data = (data and (data .. "
") or "") .. k .. (v~="" and ":" or "")..v - end - end - return data + local data + + if d.HostConfig and d.HostConfig.Tmpfs then + for k, v in pairs(d.HostConfig.Tmpfs) do + data = (data and (data .. "
") or "") .. k .. (v~="" and ":" or "")..v + end + end + + return data end local get_dns = function(d) - local data - if d.HostConfig and d.HostConfig.Dns then - for _, v in ipairs(d.HostConfig.Dns) do - data = (data and (data .. "
") or "") .. v - end - end - return data + local data + + if d.HostConfig and d.HostConfig.Dns then + for _, v in ipairs(d.HostConfig.Dns) do + data = (data and (data .. "
") or "") .. v + end + end + + return data end local get_sysctl = function(d) - local data - if d.HostConfig and d.HostConfig.Sysctls then - for k, v in pairs(d.HostConfig.Sysctls) do - data = (data and (data .. "
") or "") .. k..":"..v - end - end - return data + local data + + if d.HostConfig and d.HostConfig.Sysctls then + for k, v in pairs(d.HostConfig.Sysctls) do + data = (data and (data .. "
") or "") .. k..":"..v + end + end + + return data end local get_networks = function(d) - local data={} - if d.NetworkSettings and d.NetworkSettings.Networks and type(d.NetworkSettings.Networks) == "table" then - for k,v in pairs(d.NetworkSettings.Networks) do - data[k] = v.IPAddress or "" - end - end - return data + local data={} + + if d.NetworkSettings and d.NetworkSettings.Networks and type(d.NetworkSettings.Networks) == "table" then + for k,v in pairs(d.NetworkSettings.Networks) do + data[k] = v.IPAddress or "" + end + end + + return data end local start_stop_remove = function(m, cmd) - docker:clear_status() - docker:append_status("Containers: " .. cmd .. " " .. container_id .. "...") - local res - if cmd ~= "upgrade" then - res = dk.containers[cmd](dk, {id = container_id}) - else - res = dk.containers_upgrade(dk, {id = container_id}) - end - if res and res.code >= 300 then - docker:append_status("code:" .. res.code.." ".. (res.body.message and res.body.message or res.message)) - luci.http.redirect(luci.dispatcher.build_url("admin/docker/container/"..container_id)) - else - docker:clear_status() - if cmd ~= "remove" and cmd ~= "upgrade" then - luci.http.redirect(luci.dispatcher.build_url("admin/docker/container/"..container_id)) - else - luci.http.redirect(luci.dispatcher.build_url("admin/docker/containers")) - end - end + local res + + docker:clear_status() + docker:append_status("Containers: " .. cmd .. " " .. container_id .. "...") + + if cmd ~= "upgrade" then + res = dk.containers[cmd](dk, {id = container_id}) + else + res = dk.containers_upgrade(dk, {id = container_id}) + end + + if res and res.code >= 300 then + docker:append_status("code:" .. res.code.." ".. (res.body.message and res.body.message or res.message)) + luci.http.redirect(luci.dispatcher.build_url("admin/docker/container/"..container_id)) + else + docker:clear_status() + if cmd ~= "remove" and cmd ~= "upgrade" then + luci.http.redirect(luci.dispatcher.build_url("admin/docker/container/"..container_id)) + else + luci.http.redirect(luci.dispatcher.build_url("admin/docker/containers")) + end + end end m=SimpleForm("docker", container_info.Name:sub(2), translate("Docker Container") ) m.redirect = luci.dispatcher.build_url("admin/docker/containers") --- m:append(Template("dockerman/container")) -docker_status = m:section(SimpleSection) -docker_status.template = "dockerman/apply_widget" -docker_status.err=docker:read_status() -docker_status.err=docker_status.err and docker_status.err:gsub("\n","
"):gsub(" "," ") -if docker_status.err then docker:clear_status() end - - -action_section = m:section(Table,{{}}) -action_section.notitle=true -action_section.rowcolors=false -action_section.template = "cbi/nullsection" - -btnstart=action_section:option(Button, "_start") -btnstart.template = "dockerman/cbi/inlinebutton" -btnstart.inputtitle=translate("Start") -btnstart.inputstyle = "apply" -btnstart.forcewrite = true -btnrestart=action_section:option(Button, "_restart") -btnrestart.template = "dockerman/cbi/inlinebutton" -btnrestart.inputtitle=translate("Restart") -btnrestart.inputstyle = "reload" -btnrestart.forcewrite = true -btnstop=action_section:option(Button, "_stop") -btnstop.template = "dockerman/cbi/inlinebutton" -btnstop.inputtitle=translate("Stop") -btnstop.inputstyle = "reset" -btnstop.forcewrite = true -btnkill=action_section:option(Button, "_kill") -btnkill.template = "dockerman/cbi/inlinebutton" -btnkill.inputtitle=translate("Kill") -btnkill.inputstyle = "reset" -btnkill.forcewrite = true -btnupgrade=action_section:option(Button, "_upgrade") -btnupgrade.template = "dockerman/cbi/inlinebutton" -btnupgrade.inputtitle=translate("Upgrade") -btnupgrade.inputstyle = "reload" -btnstop.forcewrite = true -btnduplicate=action_section:option(Button, "_duplicate") -btnduplicate.template = "dockerman/cbi/inlinebutton" -btnduplicate.inputtitle=translate("Duplicate/Edit") -btnduplicate.inputstyle = "add" -btnstop.forcewrite = true -btnremove=action_section:option(Button, "_remove") -btnremove.template = "dockerman/cbi/inlinebutton" -btnremove.inputtitle=translate("Remove") -btnremove.inputstyle = "remove" -btnremove.forcewrite = true - -btnstart.write = function(self, section) - start_stop_remove(m,"start") + +s = m:section(SimpleSection) +s.template = "dockerman/apply_widget" +s.err=docker:read_status() +s.err=s.err and s.err:gsub("\n","
"):gsub(" "," ") +if s.err then + docker:clear_status() +end + +s = m:section(Table,{{}}) +s.notitle=true +s.rowcolors=false +s.template = "cbi/nullsection" + +o = s:option(Button, "_start") +o.template = "dockerman/cbi/inlinebutton" +o.inputtitle=translate("Start") +o.inputstyle = "apply" +o.forcewrite = true +o.write = function(self, section) + start_stop_remove(m,"start") end -btnrestart.write = function(self, section) - start_stop_remove(m,"restart") + +o = s:option(Button, "_restart") +o.template = "dockerman/cbi/inlinebutton" +o.inputtitle=translate("Restart") +o.inputstyle = "reload" +o.forcewrite = true +o.write = function(self, section) + start_stop_remove(m,"restart") end -btnupgrade.write = function(self, section) - start_stop_remove(m,"upgrade") + +o = s:option(Button, "_stop") +o.template = "dockerman/cbi/inlinebutton" +o.inputtitle=translate("Stop") +o.inputstyle = "reset" +o.forcewrite = true +o.write = function(self, section) + start_stop_remove(m,"stop") end -btnremove.write = function(self, section) - start_stop_remove(m,"remove") + +o = s:option(Button, "_kill") +o.template = "dockerman/cbi/inlinebutton" +o.inputtitle=translate("Kill") +o.inputstyle = "reset" +o.forcewrite = true +o.write = function(self, section) + start_stop_remove(m,"kill") end -btnstop.write = function(self, section) - start_stop_remove(m,"stop") + +o = s:option(Button, "_upgrade") +o.template = "dockerman/cbi/inlinebutton" +o.inputtitle=translate("Upgrade") +o.inputstyle = "reload" +o.forcewrite = true +o.write = function(self, section) + start_stop_remove(m,"upgrade") end -btnkill.write = function(self, section) - start_stop_remove(m,"kill") + +o = s:option(Button, "_duplicate") +o.template = "dockerman/cbi/inlinebutton" +o.inputtitle=translate("Duplicate/Edit") +o.inputstyle = "add" +o.forcewrite = true +o.write = function(self, section) + luci.http.redirect(luci.dispatcher.build_url("admin/docker/newcontainer/duplicate/"..container_id)) end -btnduplicate.write = function(self, section) - luci.http.redirect(luci.dispatcher.build_url("admin/docker/newcontainer/duplicate/"..container_id)) + +o = s:option(Button, "_remove") +o.template = "dockerman/cbi/inlinebutton" +o.inputtitle=translate("Remove") +o.inputstyle = "remove" +o.forcewrite = true +o.write = function(self, section) + start_stop_remove(m,"remove") end -tab_section = m:section(SimpleSection) -tab_section.template = "dockerman/container" - -if action == "info" then - m.submit = false - m.reset = false - table_info = { - ["01name"] = {_key = translate("Name"), _value = container_info.Name:sub(2) or "-", _button=translate("Update")}, - ["02id"] = {_key = translate("ID"), _value = container_info.Id or "-"}, - ["03image"] = {_key = translate("Image"), _value = container_info.Config.Image .. "
" .. container_info.Image}, - ["04status"] = {_key = translate("Status"), _value = container_info.State and container_info.State.Status or "-"}, - ["05created"] = {_key = translate("Created"), _value = container_info.Created or "-"}, - } - table_info["06start"] = container_info.State.Status == "running" and {_key = translate("Start Time"), _value = container_info.State and container_info.State.StartedAt or "-"} or {_key = translate("Finish Time"), _value = container_info.State and container_info.State.FinishedAt or "-"} - table_info["07healthy"] = {_key = translate("Healthy"), _value = container_info.State and container_info.State.Health and container_info.State.Health.Status or "-"} - table_info["08restart"] = {_key = translate("Restart Policy"), _value = container_info.HostConfig and container_info.HostConfig.RestartPolicy and container_info.HostConfig.RestartPolicy.Name or "-", _button=translate("Update")} - table_info["081user"] = {_key = translate("User"), _value = container_info.Config and (container_info.Config.User ~="" and container_info.Config.User or "-") or "-"} - table_info["09mount"] = {_key = translate("Mount/Volume"), _value = get_mounts(container_info) or "-"} - table_info["10cmd"] = {_key = translate("Command"), _value = get_command(container_info) or "-"} - table_info["11env"] = {_key = translate("Env"), _value = get_env(container_info) or "-"} - table_info["12ports"] = {_key = translate("Ports"), _value = get_ports(container_info) or "-"} - table_info["13links"] = {_key = translate("Links"), _value = get_links(container_info) or "-"} - table_info["14device"] = {_key = translate("Device"), _value = get_device(container_info) or "-"} - table_info["15tmpfs"] = {_key = translate("Tmpfs"), _value = get_tmpfs(container_info) or "-"} - table_info["16dns"] = {_key = translate("DNS"), _value = get_dns(container_info) or "-"} - table_info["17sysctl"] = {_key = translate("Sysctl"), _value = get_sysctl(container_info) or "-"} - info_networks = get_networks(container_info) - list_networks = {} - for _, v in ipairs (networks) do - if v.Name then - local parent = v.Options and v.Options.parent or nil - local ip = v.IPAM and v.IPAM.Config and v.IPAM.Config[1] and v.IPAM.Config[1].Subnet or nil - ipv6 = v.IPAM and v.IPAM.Config and v.IPAM.Config[2] and v.IPAM.Config[2].Subnet or nil - local network_name = v.Name .. " | " .. v.Driver .. (parent and (" | " .. parent) or "") .. (ip and (" | " .. ip) or "").. (ipv6 and (" | " .. ipv6) or "") - list_networks[v.Name] = network_name - end - end - - if type(info_networks)== "table" then - for k,v in pairs(info_networks) do - table_info["14network"..k] = { - _key = translate("Network"), _value = k.. (v~="" and (" | ".. v) or ""), _button=translate("Disconnect") - } - list_networks[k]=nil - end - end - - table_info["15connect"] = {_key = translate("Connect Network"), _value = list_networks ,_opts = "", _button=translate("Connect")} - - - d_info = m:section(Table,table_info) - d_info.nodescr=true - d_info.formvalue=function(self, section) - return table_info - end - dv_key = d_info:option(DummyValue, "_key", translate("Info")) - dv_key.width = "20%" - dv_value = d_info:option(ListValue, "_value") - dv_value.render = function(self, section, scope) - if table_info[section]._key == translate("Name") then - self:reset_values() - self.template = "cbi/value" - self.size = 30 - self.keylist = {} - self.vallist = {} - self.default=table_info[section]._value - Value.render(self, section, scope) - elseif table_info[section]._key == translate("Restart Policy") then - self.template = "cbi/lvalue" - self:reset_values() - self.size = nil - self:value("no", "No") - self:value("unless-stopped", "Unless stopped") - self:value("always", "Always") - self:value("on-failure", "On failure") - self.default=table_info[section]._value - ListValue.render(self, section, scope) - elseif table_info[section]._key == translate("Connect Network") then - self.template = "cbi/lvalue" - self:reset_values() - self.size = nil - for k,v in pairs(list_networks) do - if k ~= "host" then - self:value(k,v) - end - end - self.default=table_info[section]._value - ListValue.render(self, section, scope) - else - self:reset_values() - self.rawhtml=true - self.template = "cbi/dvalue" - self.default=table_info[section]._value - DummyValue.render(self, section, scope) - end - end - dv_value.forcewrite = true -- for write function using simpleform - dv_value.write = function(self, section, value) - table_info[section]._value=value - end - dv_value.validate = function(self, value) - return value - end - dv_opts = d_info:option(Value, "_opts") - dv_opts.forcewrite = true -- for write function using simpleform - dv_opts.write = function(self, section, value) - - table_info[section]._opts=value - end - dv_opts.validate = function(self, value) - return value - end - dv_opts.render = function(self, section, scope) - if table_info[section]._key==translate("Connect Network") then - self.template = "cbi/value" - self.keylist = {} - self.vallist = {} - self.placeholder = "10.1.1.254" - self.datatype = "ip4addr" - self.default=table_info[section]._opts - Value.render(self, section, scope) - else - self.rawhtml=true - self.template = "cbi/dvalue" - self.default=table_info[section]._opts - DummyValue.render(self, section, scope) - end - end - btn_update = d_info:option(Button, "_button") - btn_update.forcewrite = true - btn_update.render = function(self, section, scope) - if table_info[section]._button and table_info[section]._value ~= nil then - btn_update.inputtitle=table_info[section]._button - self.template = "cbi/button" - self.inputstyle = "edit" - Button.render(self, section, scope) - else - self.template = "cbi/dvalue" - self.default="" - DummyValue.render(self, section, scope) - end - end - btn_update.write = function(self, section, value) - local res - docker:clear_status() - if section == "01name" then - docker:append_status("Containers: rename " .. container_id .. "...") - local new_name = table_info[section]._value - res = dk.containers:rename({id = container_id, query = {name=new_name}}) - elseif section == "08restart" then - docker:append_status("Containers: update " .. container_id .. "...") - local new_restart = table_info[section]._value - res = dk.containers:update({id = container_id, body = {RestartPolicy = {Name = new_restart}}}) - elseif table_info[section]._key == translate("Network") then - local _,_,leave_network = table_info[section]._value:find("(.-) | .+") - leave_network = leave_network or table_info[section]._value - docker:append_status("Network: disconnect " .. leave_network .. container_id .. "...") - res = dk.networks:disconnect({name = leave_network, body = {Container = container_id}}) - elseif section == "15connect" then - local connect_network = table_info[section]._value - local network_opiton - if connect_network ~= "none" and connect_network ~= "bridge" and connect_network ~= "host" then - network_opiton = table_info[section]._opts ~= "" and { - IPAMConfig={ - IPv4Address=table_info[section]._opts - } - } or nil - end - docker:append_status("Network: connect " .. connect_network .. container_id .. "...") - res = dk.networks:connect({name = connect_network, body = {Container = container_id, EndpointConfig= network_opiton}}) - end - if res and res.code > 300 then - docker:append_status("code:" .. res.code.." ".. (res.body.message and res.body.message or res.message)) - else - docker:clear_status() - end - luci.http.redirect(luci.dispatcher.build_url("admin/docker/container/"..container_id.."/info")) - end - --- info end +s = m:section(SimpleSection) +s.template = "dockerman/container" + +if action == "info" then + m.submit = false + m.reset = false + table_info = { + ["01name"] = { + _key = translate("Name"), + _value = container_info.Name:sub(2) or "-", + _button=translate("Update") + }, + ["02id"] = { + _key = translate("ID"), + _value = container_info.Id or "-" + }, + ["03image"] = { + _key = translate("Image"), + _value = container_info.Config.Image .. "
" .. container_info.Image + }, + ["04status"] = { + _key = translate("Status"), + _value = container_info.State and container_info.State.Status or "-" + }, + ["05created"] = { + _key = translate("Created"), + _value = container_info.Created or "-" + }, + } + + table_info["06start"] = container_info.State.Status == "running" and {_key = translate("Start Time"), _value = container_info.State and container_info.State.StartedAt or "-"} or {_key = translate("Finish Time"), _value = container_info.State and container_info.State.FinishedAt or "-"} + + table_info["07healthy"] = { + _key = translate("Healthy"), + _value = container_info.State and container_info.State.Health and container_info.State.Health.Status or "-" + } + table_info["08restart"] = { + _key = translate("Restart Policy"), + _value = container_info.HostConfig and container_info.HostConfig.RestartPolicy and container_info.HostConfig.RestartPolicy.Name or "-", + _button=translate("Update") + } + table_info["081user"] = { + _key = translate("User"), + _value = container_info.Config and (container_info.Config.User ~="" and container_info.Config.User or "-") or "-" + } + table_info["09mount"] = { + _key = translate("Mount/Volume"), + _value = get_mounts(container_info) or "-" + } + table_info["10cmd"] = { + _key = translate("Command"), + _value = get_command(container_info) or "-" + } + table_info["11env"] = { + _key = translate("Env"), + _value = get_env(container_info) or "-" + } + table_info["12ports"] = { + _key = translate("Ports"), + _value = get_ports(container_info) or "-" + } + table_info["13links"] = { + _key = translate("Links"), + _value = get_links(container_info) or "-" + } + table_info["14device"] = { + _key = translate("Device"), + _value = get_device(container_info) or "-" + } + table_info["15tmpfs"] = { + _key = translate("Tmpfs"), + _value = get_tmpfs(container_info) or "-" + } + table_info["16dns"] = { + _key = translate("DNS"), + _value = get_dns(container_info) or "-" + } + table_info["17sysctl"] = { + _key = translate("Sysctl"), + _value = get_sysctl(container_info) or "-" + } + + info_networks = get_networks(container_info) + list_networks = {} + for _, v in ipairs (networks) do + if v.Name then + local parent = v.Options and v.Options.parent or nil + local ip = v.IPAM and v.IPAM.Config and v.IPAM.Config[1] and v.IPAM.Config[1].Subnet or nil + ipv6 = v.IPAM and v.IPAM.Config and v.IPAM.Config[2] and v.IPAM.Config[2].Subnet or nil + local network_name = v.Name .. " | " .. v.Driver .. (parent and (" | " .. parent) or "") .. (ip and (" | " .. ip) or "").. (ipv6 and (" | " .. ipv6) or "") + list_networks[v.Name] = network_name + end + end + + if type(info_networks)== "table" then + for k,v in pairs(info_networks) do + table_info["14network"..k] = { + _key = translate("Network"), + value = k.. (v~="" and (" | ".. v) or ""), + _button=translate("Disconnect") + } + list_networks[k]=nil + end + end + + table_info["15connect"] = { + _key = translate("Connect Network"), + _value = list_networks ,_opts = "", + _button=translate("Connect") + } + + d_info = m:section(Table,table_info) + d_info.nodescr=true + d_info.formvalue=function(self, section) + return table_info + end + + dv_key = d_info:option(DummyValue, "_key", translate("Info")) + dv_key.width = "20%" + dv_value = d_info:option(ListValue, "_value") + dv_value.render = function(self, section, scope) + if table_info[section]._key == translate("Name") then + self:reset_values() + self.template = "cbi/value" + self.size = 30 + self.keylist = {} + self.vallist = {} + self.default=table_info[section]._value + Value.render(self, section, scope) + elseif table_info[section]._key == translate("Restart Policy") then + self.template = "cbi/lvalue" + self:reset_values() + self.size = nil + self:value("no", "No") + self:value("unless-stopped", "Unless stopped") + self:value("always", "Always") + self:value("on-failure", "On failure") + self.default=table_info[section]._value + ListValue.render(self, section, scope) + elseif table_info[section]._key == translate("Connect Network") then + self.template = "cbi/lvalue" + self:reset_values() + self.size = nil + for k,v in pairs(list_networks) do + if k ~= "host" then + self:value(k,v) + end + end + self.default=table_info[section]._value + ListValue.render(self, section, scope) + else + self:reset_values() + self.rawhtml=true + self.template = "cbi/dvalue" + self.default=table_info[section]._value + DummyValue.render(self, section, scope) + end + end + + dv_value.forcewrite = true -- for write function using simpleform + dv_value.write = function(self, section, value) + table_info[section]._value=value + end + dv_value.validate = function(self, value) + return value + end + dv_opts = d_info:option(Value, "_opts") + dv_opts.forcewrite = true -- for write function using simpleform + dv_opts.write = function(self, section, value) + table_info[section]._opts=value + end + dv_opts.validate = function(self, value) + return value + end + dv_opts.render = function(self, section, scope) + if table_info[section]._key==translate("Connect Network") then + self.template = "cbi/value" + self.keylist = {} + self.vallist = {} + self.placeholder = "10.1.1.254" + self.datatype = "ip4addr" + self.default=table_info[section]._opts + Value.render(self, section, scope) + else + self.rawhtml=true + self.template = "cbi/dvalue" + self.default=table_info[section]._opts + DummyValue.render(self, section, scope) + end + end + + btn_update = d_info:option(Button, "_button") + btn_update.forcewrite = true + btn_update.render = function(self, section, scope) + if table_info[section]._button and table_info[section]._value ~= nil then + btn_update.inputtitle=table_info[section]._button + self.template = "cbi/button" + self.inputstyle = "edit" + Button.render(self, section, scope) + else + self.template = "cbi/dvalue" + self.default="" + DummyValue.render(self, section, scope) + end + end + + btn_update.write = function(self, section, value) + + local res + docker:clear_status() + + if section == "01name" then + docker:append_status("Containers: rename " .. container_id .. "...") + local new_name = table_info[section]._value + res = dk.containers:rename({ + id = container_id, + query = { + name=new_name + } + }) + elseif section == "08restart" then + docker:append_status("Containers: update " .. container_id .. "...") + local new_restart = table_info[section]._value + res = dk.containers:update({ + id = container_id, + body = { + RestartPolicy = { + Name = new_restart + } + } + }) + elseif table_info[section]._key == translate("Network") then + local _,_,leave_network + + _, _, leave_network = table_info[section]._value:find("(.-) | .+") + leave_network = leave_network or table_info[section]._value + docker:append_status("Network: disconnect " .. leave_network .. container_id .. "...") + res = dk.networks:disconnect({ + name = leave_network, + body = { + Container = container_id + } + }) + elseif section == "15connect" then + local connect_network = table_info[section]._value + local network_opiton + if connect_network ~= "none" + and connect_network ~= "bridge" + and connect_network ~= "host" then + + network_opiton = table_info[section]._opts ~= "" and { + IPAMConfig={ + IPv4Address=table_info[section]._opts + } + } or nil + end + docker:append_status("Network: connect " .. connect_network .. container_id .. "...") + res = dk.networks:connect({ + name = connect_network, + body = { + Container = container_id, + EndpointConfig= network_opiton + } + }) + end + + if res and res.code > 300 then + docker:append_status("code:" .. res.code.." ".. (res.body.message and res.body.message or res.message)) + else + docker:clear_status() + end + luci.http.redirect(luci.dispatcher.build_url("admin/docker/container/"..container_id.."/info")) + end elseif action == "resources" then - local resources_section= m:section(SimpleSection) - d = resources_section:option( Value, "cpus", translate("CPUs"), translate("Number of CPUs. Number is a fractional number. 0.000 means no limit.")) - d.placeholder = "1.5" - d.rmempty = true - d.datatype="ufloat" - d.default = container_info.HostConfig.NanoCpus / (10^9) - - d = resources_section:option(Value, "cpushares", translate("CPU Shares Weight"), translate("CPU shares relative weight, if 0 is set, the system will ignore the value and use the default of 1024.")) - d.placeholder = "1024" - d.rmempty = true - d.datatype="uinteger" - d.default = container_info.HostConfig.CpuShares - - d = resources_section:option(Value, "memory", translate("Memory"), translate("Memory limit (format: []). Number is a positive integer. Unit can be one of b, k, m, or g. Minimum is 4M.")) - d.placeholder = "128m" - d.rmempty = true - d.default = container_info.HostConfig.Memory ~=0 and ((container_info.HostConfig.Memory / 1024 /1024) .. "M") or 0 - - d = resources_section:option(Value, "blkioweight", translate("Block IO Weight"), translate("Block IO weight (relative weight) accepts a weight value between 10 and 1000.")) - d.placeholder = "500" - d.rmempty = true - d.datatype="uinteger" - d.default = container_info.HostConfig.BlkioWeight - - m.handle = function(self, state, data) - if state == FORM_VALID then - local memory = data.memory - if memory and memory ~= 0 then - _,_,n,unit = memory:find("([%d%.]+)([%l%u]+)") - if n then - unit = unit and unit:sub(1,1):upper() or "B" - if unit == "M" then - memory = tonumber(n) * 1024 * 1024 - elseif unit == "G" then - memory = tonumber(n) * 1024 * 1024 * 1024 - elseif unit == "K" then - memory = tonumber(n) * 1024 - else - memory = tonumber(n) - end - end - end - request_body = { - BlkioWeight = tonumber(data.blkioweight), - NanoCPUs = tonumber(data.cpus)*10^9, - Memory = tonumber(memory), - CpuShares = tonumber(data.cpushares) - } - docker:write_status("Containers: update " .. container_id .. "...") - local res = dk.containers:update({id = container_id, body = request_body}) - if res and res.code >= 300 then - docker:append_status("code:" .. res.code.." ".. (res.body.message and res.body.message or res.message)) - else - docker:clear_status() - end - luci.http.redirect(luci.dispatcher.build_url("admin/docker/container/"..container_id.."/resources")) - end - end + local s = m:section(SimpleSection) + o = s:option( Value, "cpus", + translate("CPUs"), + translate("Number of CPUs. Number is a fractional number. 0.000 means no limit.")) + o.placeholder = "1.5" + o.rmempty = true + o.datatype="ufloat" + o.default = container_info.HostConfig.NanoCpus / (10^9) + + o = s:option(Value, "cpushares", + translate("CPU Shares Weight"), + translate("CPU shares relative weight, if 0 is set, the system will ignore the value and use the default of 1024.")) + o.placeholder = "1024" + o.rmempty = true + o.datatype="uinteger" + o.default = container_info.HostConfig.CpuShares + + o = s:option(Value, "memory", + translate("Memory"), + translate("Memory limit (format: []). Number is a positive integer. Unit can be one of b, k, m, or g. Minimum is 4M.")) + o.placeholder = "128m" + o.rmempty = true + o.default = container_info.HostConfig.Memory ~=0 and ((container_info.HostConfig.Memory / 1024 /1024) .. "M") or 0 + + o = s:option(Value, "blkioweight", + translate("Block IO Weight"), + translate("Block IO weight (relative weight) accepts a weight value between 10 and 1000.")) + o.placeholder = "500" + o.rmempty = true + o.datatype="uinteger" + o.default = container_info.HostConfig.BlkioWeight + + m.handle = function(self, state, data) + if state == FORM_VALID then + local memory = data.memory + if memory and memory ~= 0 then + _,_,n,unit = memory:find("([%d%.]+)([%l%u]+)") + if n then + unit = unit and unit:sub(1,1):upper() or "B" + if unit == "M" then + memory = tonumber(n) * 1024 * 1024 + elseif unit == "G" then + memory = tonumber(n) * 1024 * 1024 * 1024 + elseif unit == "K" then + memory = tonumber(n) * 1024 + else + memory = tonumber(n) + end + end + end + + request_body = { + BlkioWeight = tonumber(data.blkioweight), + NanoCPUs = tonumber(data.cpus)*10^9, + Memory = tonumber(memory), + CpuShares = tonumber(data.cpushares) + } + + docker:write_status("Containers: update " .. container_id .. "...") + local res = dk.containers:update({id = container_id, body = request_body}) + if res and res.code >= 300 then + docker:append_status("code:" .. res.code.." ".. (res.body.message and res.body.message or res.message)) + else + docker:clear_status() + end + luci.http.redirect(luci.dispatcher.build_url("admin/docker/container/"..container_id.."/resources")) + end + end + elseif action == "file" then - local filesection= m:section(SimpleSection) - m.submit = false - m.reset = false - filesection.template = "dockerman/container_file" - filesection.container = container_id + local filesection= m:section(SimpleSection) + m.submit = false + m.reset = false + filesection.template = "dockerman/container_file" + filesection.container = container_id elseif action == "inspect" then - local inspectsection= m:section(SimpleSection) - inspectsection.syslog = luci.jsonc.stringify(container_info, true) - inspectsection.title = translate("Container Inspect") - inspectsection.template = "dockerman/logs" - m.submit = false - m.reset = false + local inspectsection= m:section(SimpleSection) + inspectsection.syslog = luci.jsonc.stringify(container_info, true) + inspectsection.title = translate("Container Inspect") + inspectsection.template = "dockerman/logs" + m.submit = false + m.reset = false elseif action == "logs" then - local logsection= m:section(SimpleSection) - local logs = "" - local query ={ - stdout = 1, - stderr = 1, - tail = 1000 - } - local logs = dk.containers:logs({id = container_id, query = query}) - if logs.code == 200 then - logsection.syslog=logs.body - else - logsection.syslog="Get Logs ERROR\n"..logs.code..": "..logs.body - end - logsection.title=translate("Container Logs") - logsection.template = "dockerman/logs" - m.submit = false - m.reset = false + local logsection= m:section(SimpleSection) + local logs = "" + local query ={ + stdout = 1, + stderr = 1, + tail = 1000 + } + + local logs = dk.containers:logs({id = container_id, query = query}) + if logs.code == 200 then + logsection.syslog=logs.body + else + logsection.syslog="Get Logs ERROR\n"..logs.code..": "..logs.body + end + + logsection.title=translate("Container Logs") + logsection.template = "dockerman/logs" + m.submit = false + m.reset = false elseif action == "console" then - m.submit = false - m.reset = false - local cmd_docker = luci.util.exec("which docker"):match("^.+docker") or nil - local cmd_ttyd = luci.util.exec("which ttyd"):match("^.+ttyd") or nil - if cmd_docker and cmd_ttyd and container_info.State.Status == "running" then - local consolesection= m:section(SimpleSection) - local cmd = "/bin/sh" - local uid - local vcommand = consolesection:option(Value, "command", translate("Command")) - vcommand:value("/bin/sh", "/bin/sh") - vcommand:value("/bin/ash", "/bin/ash") - vcommand:value("/bin/bash", "/bin/bash") - vcommand.default = "/bin/sh" - vcommand.forcewrite = true - vcommand.write = function(self, section, value) - cmd = value - end - local vuid = consolesection:option(Value, "uid", translate("UID")) - vuid.forcewrite = true - vuid.write = function(self, section, value) - uid = value - end - local btn_connect = consolesection:option(Button, "connect") - btn_connect.render = function(self, section, scope) - self.inputstyle = "add" - self.title = " " - self.inputtitle = translate("Connect") - Button.render(self, section, scope) - end - btn_connect.write = function(self, section) - local cmd_docker = luci.util.exec("which docker"):match("^.+docker") or nil - local cmd_ttyd = luci.util.exec("which ttyd"):match("^.+ttyd") or nil - if not cmd_docker or not cmd_ttyd or cmd_docker:match("^%s+$") or cmd_ttyd:match("^%s+$") then return end - local kill_ttyd = 'netstat -lnpt | grep ":7682[ \t].*ttyd$" | awk \'{print $NF}\' | awk -F\'/\' \'{print "kill -9 " $1}\' | sh > /dev/null' - luci.util.exec(kill_ttyd) - local hosts - local uci = (require "luci.model.uci").cursor() - local remote = uci:get("dockerd", "globals", "remote_endpoint") - local socket_path = (remote == "false" or not remote) and uci:get("dockerd", "globals", "socket_path") or nil - local host = (remote == "true") and uci:get("dockerd", "globals", "remote_host") or nil - local port = (remote == "true") and uci:get("dockerd", "globals", "remote_port") or nil - if remote and host and port then - hosts = host .. ':'.. port - elseif socket_path then - hosts = "unix://" .. socket_path - else - return - end - local start_cmd = cmd_ttyd .. ' -d 2 --once -p 7682 '.. cmd_docker .. ' -H "'.. hosts ..'" exec -it ' .. (uid and uid ~= "" and (" -u ".. uid .. ' ') or "").. container_id .. ' ' .. cmd .. ' &' - os.execute(start_cmd) - local console = consolesection:option(DummyValue, "console") - console.container_id = container_id - console.template = "dockerman/container_console" - end - end + m.submit = false + m.reset = false + local cmd_docker = luci.util.exec("which docker"):match("^.+docker") or nil + local cmd_ttyd = luci.util.exec("which ttyd"):match("^.+ttyd") or nil + if cmd_docker and cmd_ttyd and container_info.State.Status == "running" then + local consolesection= m:section(SimpleSection) + local cmd = "/bin/sh" + local uid + local vcommand = consolesection:option(Value, "command", translate("Command")) + vcommand:value("/bin/sh", "/bin/sh") + vcommand:value("/bin/ash", "/bin/ash") + vcommand:value("/bin/bash", "/bin/bash") + vcommand.default = "/bin/sh" + vcommand.forcewrite = true + vcommand.write = function(self, section, value) + cmd = value + end + + local vuid = consolesection:option(Value, "uid", translate("UID")) + vuid.forcewrite = true + vuid.write = function(self, section, value) + uid = value + end + + local btn_connect = consolesection:option(Button, "connect") + btn_connect.render = function(self, section, scope) + self.inputstyle = "add" + self.title = " " + self.inputtitle = translate("Connect") + Button.render(self, section, scope) + end + btn_connect.write = function(self, section) + local cmd_docker = luci.util.exec("which docker"):match("^.+docker") or nil + local cmd_ttyd = luci.util.exec("which ttyd"):match("^.+ttyd") or nil + if not cmd_docker or not cmd_ttyd or cmd_docker:match("^%s+$") or cmd_ttyd:match("^%s+$") then return end + local kill_ttyd = 'netstat -lnpt | grep ":7682[ \t].*ttyd$" | awk \'{print $NF}\' | awk -F\'/\' \'{print "kill -9 " $1}\' | sh > /dev/null' + luci.util.exec(kill_ttyd) + local hosts + local uci = (require "luci.model.uci").cursor() + local remote = uci:get("dockerd", "globals", "remote_endpoint") + local socket_path = (remote == "false" or not remote) and uci:get("dockerd", "globals", "socket_path") or nil + local host = (remote == "true") and uci:get("dockerd", "globals", "remote_host") or nil + local port = (remote == "true") and uci:get("dockerd", "globals", "remote_port") or nil + if remote and host and port then + hosts = host .. ':'.. port + elseif socket_path then + hosts = "unix://" .. socket_path + else + return + end + local start_cmd = cmd_ttyd .. ' -d 2 --once -p 7682 '.. cmd_docker .. ' -H "'.. hosts ..'" exec -it ' .. (uid and uid ~= "" and (" -u ".. uid .. ' ') or "").. container_id .. ' ' .. cmd .. ' &' + os.execute(start_cmd) + local console = consolesection:option(DummyValue, "console") + console.container_id = container_id + console.template = "dockerman/container_console" + end + end elseif action == "stats" then - local response = dk.containers:top({id = container_id, query = {ps_args="-aux"}}) - local container_top - if response.code == 200 then - container_top=response.body - else - response = dk.containers:top({id = container_id}) - if response.code == 200 then - container_top=response.body - end - end - - if type(container_top) == "table" then - container_top=response.body - stat_section = m:section(SimpleSection) - stat_section.container_id = container_id - stat_section.template = "dockerman/container_stats" - table_stats = {cpu={key=translate("CPU Useage"),value='-'},memory={key=translate("Memory Useage"),value='-'}} - stat_section = m:section(Table, table_stats, translate("Stats")) - stat_section:option(DummyValue, "key", translate("Stats")).width="33%" - stat_section:option(DummyValue, "value") - top_section= m:section(Table, container_top.Processes, translate("TOP")) - for i, v in ipairs(container_top.Titles) do - top_section:option(DummyValue, i, translate(v)) - end -end -m.submit = false -m.reset = false + local response = dk.containers:top({id = container_id, query = {ps_args="-aux"}}) + local container_top + if response.code == 200 then + container_top=response.body + else + response = dk.containers:top({id = container_id}) + if response.code == 200 then + container_top=response.body + end + end + + if type(container_top) == "table" then + container_top=response.body + stat_section = m:section(SimpleSection) + stat_section.container_id = container_id + stat_section.template = "dockerman/container_stats" + table_stats = { + cpu={ + key=translate("CPU Useage"), + value='-' + }, + memory={ + key=translate("Memory Useage"), + value='-' + } + } + stat_section = m:section(Table, table_stats, translate("Stats")) + stat_section:option(DummyValue, "key", translate("Stats")).width="33%" + stat_section:option(DummyValue, "value") + top_section= m:section(Table, container_top.Processes, translate("TOP")) + for i, v in ipairs(container_top.Titles) do + top_section:option(DummyValue, i, translate(v)) + end + end + m.submit = false + m.reset = false end return m