添加 luasrc/controller/dockerman.lua
This commit is contained in:
commit
9ae6414173
472
luasrc/controller/dockerman.lua
Normal file
472
luasrc/controller/dockerman.lua
Normal file
@ -0,0 +1,472 @@
|
||||
徽标
|
||||
探索
|
||||
简体中文
|
||||
登录
|
||||
sbwml
|
||||
/
|
||||
luci-app-dockerman
|
||||
关注
|
||||
1
|
||||
点赞
|
||||
0
|
||||
派生
|
||||
0
|
||||
代码
|
||||
工单
|
||||
合并请求
|
||||
项目
|
||||
版本发布
|
||||
百科
|
||||
动态
|
||||
|
||||
openwrt-23.05
|
||||
luci-app-dockerman/luasrc/controller/dockerman.lua
|
||||
437 行
|
||||
13 KiB
|
||||
Lua
|
||||
原始文件
|
||||
永久链接
|
||||
Blame
|
||||
文件历史
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
|
||||
]]--
|
||||
|
||||
local docker = require "luci.model.docker"
|
||||
|
||||
module("luci.controller.dockerman",package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "docker"}, firstchild(), _("Docker"), 41).acl_depends = { "luci-app-dockerman" }
|
||||
entry({"admin", "docker", "overview"},cbi("dockerman/overview"),_("Overview"), 1).leaf=true
|
||||
entry({"admin", "docker", "containers"}, form("dockerman/containers"), _("Containers"), 2).leaf=true
|
||||
entry({"admin", "docker", "images"}, form("dockerman/images"), _("Images"), 3).leaf=true
|
||||
entry({"admin", "docker", "networks"}, form("dockerman/networks"), _("Networks"), 4).leaf=true
|
||||
entry({"admin", "docker", "volumes"}, form("dockerman/volumes"), _("Volumes"), 5).leaf=true
|
||||
entry({"admin", "docker", "events"}, call("action_events"), _("Events"), 6)
|
||||
entry({"admin", "docker", "config"},cbi("dockerman/configuration"),_("Configuration"), 7).leaf=true
|
||||
|
||||
entry({"admin", "docker", "newcontainer"}, form("dockerman/newcontainer")).leaf=true
|
||||
entry({"admin", "docker", "newnetwork"}, form("dockerman/newnetwork")).leaf=true
|
||||
entry({"admin", "docker", "container"}, form("dockerman/container")).leaf=true
|
||||
|
||||
entry({"admin", "docker", "container_stats"}, call("action_get_container_stats")).leaf=true
|
||||
entry({"admin", "docker", "container_get_archive"}, call("download_archive")).leaf=true
|
||||
entry({"admin", "docker", "container_put_archive"}, call("upload_archive")).leaf=true
|
||||
entry({"admin", "docker", "images_save"}, call("save_images")).leaf=true
|
||||
entry({"admin", "docker", "images_load"}, call("load_images")).leaf=true
|
||||
entry({"admin", "docker", "images_import"}, call("import_images")).leaf=true
|
||||
entry({"admin", "docker", "images_get_tags"}, call("get_image_tags")).leaf=true
|
||||
entry({"admin", "docker", "images_tag"}, call("tag_image")).leaf=true
|
||||
entry({"admin", "docker", "images_untag"}, call("untag_image")).leaf=true
|
||||
entry({"admin", "docker", "confirm"}, call("action_confirm")).leaf=true
|
||||
end
|
||||
|
||||
function action_events()
|
||||
local logs = ""
|
||||
local query ={}
|
||||
|
||||
local dk = docker.new()
|
||||
query["until"] = os.time()
|
||||
local events = dk:events({query = query})
|
||||
|
||||
if events.code == 200 then
|
||||
for _, v in ipairs(events.body) do
|
||||
local date = "unknown"
|
||||
if v and v.time then
|
||||
date = os.date("%Y-%m-%d %H:%M:%S", v.time)
|
||||
end
|
||||
|
||||
local name = v.Actor.Attributes.name or "unknown"
|
||||
local action = v.Action or "unknown"
|
||||
|
||||
if v and v.Type == "container" then
|
||||
local id = v.Actor.ID or "unknown"
|
||||
logs = logs .. string.format("[%s] %s %s Container ID: %s Container Name: %s\n", date, v.Type, action, id, name)
|
||||
elseif v.Type == "network" then
|
||||
local container = v.Actor.Attributes.container or "unknown"
|
||||
local network = v.Actor.Attributes.type or "unknown"
|
||||
logs = logs .. string.format("[%s] %s %s Container ID: %s Network Name: %s Network type: %s\n", date, v.Type, action, container, name, network)
|
||||
elseif v.Type == "image" then
|
||||
local id = v.Actor.ID or "unknown"
|
||||
logs = logs .. string.format("[%s] %s %s Image: %s Image name: %s\n", date, v.Type, action, id, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
luci.template.render("dockerman/logs", {self={syslog = logs, title="Events"}})
|
||||
end
|
||||
|
||||
local calculate_cpu_percent = function(d)
|
||||
if type(d) ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
local cpu_count = tonumber(d["cpu_stats"]["online_cpus"])
|
||||
local cpu_percent = 0.0
|
||||
local cpu_delta = tonumber(d["cpu_stats"]["cpu_usage"]["total_usage"]) - tonumber(d["precpu_stats"]["cpu_usage"]["total_usage"])
|
||||
local system_delta = tonumber(d["cpu_stats"]["system_cpu_usage"]) - tonumber(d["precpu_stats"]["system_cpu_usage"])
|
||||
if system_delta > 0.0 then
|
||||
cpu_percent = string.format("%.2f", cpu_delta / system_delta * 100.0 * cpu_count)
|
||||
end
|
||||
|
||||
return cpu_percent
|
||||
end
|
||||
|
||||
local get_memory = function(d)
|
||||
if type(d) ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
local limit =tonumber(d["memory_stats"]["limit"])
|
||||
local usage = tonumber(d["memory_stats"]["usage"]) - tonumber(d["memory_stats"]["stats"]["total_cache"])
|
||||
|
||||
return usage, limit
|
||||
end
|
||||
|
||||
local get_rx_tx = function(d)
|
||||
if type(d) ~="table" then
|
||||
return
|
||||
end
|
||||
|
||||
local data = {}
|
||||
if type(d["networks"]) == "table" then
|
||||
for e, v in pairs(d["networks"]) do
|
||||
data[e] = {
|
||||
bw_tx = tonumber(v.tx_bytes),
|
||||
bw_rx = tonumber(v.rx_bytes)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
function action_get_container_stats(container_id)
|
||||
if container_id then
|
||||
local dk = docker.new()
|
||||
local response = dk.containers:inspect({id = container_id})
|
||||
if response.code == 200 and response.body.State.Running then
|
||||
response = dk.containers:stats({id = container_id, query = {stream = false}})
|
||||
if response.code == 200 then
|
||||
local container_stats = response.body
|
||||
local cpu_percent = calculate_cpu_percent(container_stats)
|
||||
local mem_useage, mem_limit = get_memory(container_stats)
|
||||
local bw_rxtx = get_rx_tx(container_stats)
|
||||
luci.http.status(response.code, response.body.message)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({
|
||||
cpu_percent = cpu_percent,
|
||||
memory = {
|
||||
mem_useage = mem_useage,
|
||||
mem_limit = mem_limit
|
||||
},
|
||||
bw_rxtx = bw_rxtx
|
||||
})
|
||||
else
|
||||
luci.http.status(response.code, response.body.message)
|
||||
luci.http.prepare_content("text/plain")
|
||||
luci.http.write(response.body.message)
|
||||
end
|
||||
else
|
||||
if response.code == 200 then
|
||||
luci.http.status(500, "container "..container_id.." not running")
|
||||
luci.http.prepare_content("text/plain")
|
||||
luci.http.write("Container "..container_id.." not running")
|
||||
else
|
||||
luci.http.status(response.code, response.body.message)
|
||||
luci.http.prepare_content("text/plain")
|
||||
luci.http.write(response.body.message)
|
||||
end
|
||||
end
|
||||
else
|
||||
luci.http.status(404, "No container name or id")
|
||||
luci.http.prepare_content("text/plain")
|
||||
luci.http.write("No container name or id")
|
||||
end
|
||||
end
|
||||
|
||||
function action_confirm()
|
||||
local data = docker:read_status()
|
||||
if data then
|
||||
data = data:gsub("\n","<br />"):gsub(" "," ")
|
||||
code = 202
|
||||
msg = data
|
||||
else
|
||||
code = 200
|
||||
msg = "finish"
|
||||
data = "finish"
|
||||
end
|
||||
|
||||
luci.http.status(code, msg)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({info = data})
|
||||
end
|
||||
|
||||
function download_archive()
|
||||
local id = luci.http.formvalue("id")
|
||||
local path = luci.http.formvalue("path")
|
||||
local dk = docker.new()
|
||||
local first
|
||||
|
||||
local cb = function(res, chunk)
|
||||
if res.code == 200 then
|
||||
if not first then
|
||||
first = true
|
||||
luci.http.header('Content-Disposition', 'inline; filename="archive.tar"')
|
||||
luci.http.header('Content-Type', 'application\/x-tar')
|
||||
end
|
||||
luci.ltn12.pump.all(chunk, luci.http.write)
|
||||
else
|
||||
if not first then
|
||||
first = true
|
||||
luci.http.prepare_content("text/plain")
|
||||
end
|
||||
luci.ltn12.pump.all(chunk, luci.http.write)
|
||||
end
|
||||
end
|
||||
|
||||
local res = dk.containers:get_archive({
|
||||
id = id,
|
||||
query = {
|
||||
path = path
|
||||
}
|
||||
}, cb)
|
||||
end
|
||||
|
||||
function upload_archive(container_id)
|
||||
local path = luci.http.formvalue("upload-path")
|
||||
local dk = docker.new()
|
||||
local ltn12 = require "luci.ltn12"
|
||||
|
||||
local rec_send = function(sinkout)
|
||||
luci.http.setfilehandler(function (meta, chunk, eof)
|
||||
if chunk then
|
||||
ltn12.pump.step(ltn12.source.string(chunk), sinkout)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local res = dk.containers:put_archive({
|
||||
id = container_id,
|
||||
query = {
|
||||
path = path
|
||||
},
|
||||
body = rec_send
|
||||
})
|
||||
|
||||
local msg = res and res.body and res.body.message or nil
|
||||
luci.http.status(res.code, msg)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({message = msg})
|
||||
end
|
||||
|
||||
function save_images(container_id)
|
||||
local names = luci.http.formvalue("names")
|
||||
local dk = docker.new()
|
||||
local first
|
||||
|
||||
local cb = function(res, chunk)
|
||||
if res.code == 200 then
|
||||
if not first then
|
||||
first = true
|
||||
luci.http.status(res.code, res.message)
|
||||
luci.http.header('Content-Disposition', 'inline; filename="images.tar"')
|
||||
luci.http.header('Content-Type', 'application\/x-tar')
|
||||
end
|
||||
luci.ltn12.pump.all(chunk, luci.http.write)
|
||||
else
|
||||
if not first then
|
||||
first = true
|
||||
luci.http.prepare_content("text/plain")
|
||||
end
|
||||
luci.ltn12.pump.all(chunk, luci.http.write)
|
||||
end
|
||||
end
|
||||
|
||||
docker:write_status("Images: saving" .. " " .. container_id .. "...")
|
||||
local res = dk.images:get({
|
||||
id = container_id,
|
||||
query = {
|
||||
names = names
|
||||
}
|
||||
}, cb)
|
||||
docker:clear_status()
|
||||
|
||||
local msg = res and res.body and res.body.message or nil
|
||||
luci.http.status(res.code, msg)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({message = msg})
|
||||
end
|
||||
|
||||
function load_images()
|
||||
local path = luci.http.formvalue("upload-path")
|
||||
local dk = docker.new()
|
||||
local ltn12 = require "luci.ltn12"
|
||||
|
||||
local rec_send = function(sinkout)
|
||||
luci.http.setfilehandler(function (meta, chunk, eof)
|
||||
if chunk then
|
||||
ltn12.pump.step(ltn12.source.string(chunk), sinkout)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
docker:write_status("Images: loading...")
|
||||
local res = dk.images:load({body = rec_send})
|
||||
local msg = res and res.body and ( res.body.message or res.body.stream or res.body.error ) or nil
|
||||
if res.code == 200 and msg and msg:match("Loaded image ID") then
|
||||
docker:clear_status()
|
||||
luci.http.status(res.code, msg)
|
||||
else
|
||||
docker:append_status("code:" .. res.code.." ".. msg)
|
||||
luci.http.status(300, msg)
|
||||
end
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({message = msg})
|
||||
end
|
||||
|
||||
function import_images()
|
||||
local src = luci.http.formvalue("src")
|
||||
local itag = luci.http.formvalue("tag")
|
||||
local dk = docker.new()
|
||||
local ltn12 = require "luci.ltn12"
|
||||
|
||||
local rec_send = function(sinkout)
|
||||
luci.http.setfilehandler(function (meta, chunk, eof)
|
||||
if chunk then
|
||||
ltn12.pump.step(ltn12.source.string(chunk), sinkout)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
docker:write_status("Images: importing".. " ".. itag .."...\n")
|
||||
local repo = itag and itag:match("^([^:]+)")
|
||||
local tag = itag and itag:match("^[^:]-:([^:]+)")
|
||||
local res = dk.images:create({
|
||||
query = {
|
||||
fromSrc = src or "-",
|
||||
repo = repo or nil,
|
||||
tag = tag or nil
|
||||
},
|
||||
body = not src and rec_send or nil
|
||||
}, docker.import_image_show_status_cb)
|
||||
|
||||
local msg = res and res.body and ( res.body.message )or nil
|
||||
if not msg and #res.body == 0 then
|
||||
msg = res.body.status or res.body.error
|
||||
elseif not msg and #res.body >= 1 then
|
||||
msg = res.body[#res.body].status or res.body[#res.body].error
|
||||
end
|
||||
|
||||
if res.code == 200 and msg and msg:match("sha256:") then
|
||||
docker:clear_status()
|
||||
else
|
||||
docker:append_status("code:" .. res.code.." ".. msg)
|
||||
end
|
||||
|
||||
luci.http.status(res.code, msg)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({message = msg})
|
||||
end
|
||||
|
||||
function get_image_tags(image_id)
|
||||
if not image_id then
|
||||
luci.http.status(400, "no image id")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({message = "no image id"})
|
||||
return
|
||||
end
|
||||
|
||||
local dk = docker.new()
|
||||
local res = dk.images:inspect({
|
||||
id = image_id
|
||||
})
|
||||
local msg = res and res.body and res.body.message or nil
|
||||
luci.http.status(res.code, msg)
|
||||
luci.http.prepare_content("application/json")
|
||||
|
||||
if res.code == 200 then
|
||||
local tags = res.body.RepoTags
|
||||
luci.http.write_json({tags = tags})
|
||||
else
|
||||
local msg = res and res.body and res.body.message or nil
|
||||
luci.http.write_json({message = msg})
|
||||
end
|
||||
end
|
||||
|
||||
function tag_image(image_id)
|
||||
local src = luci.http.formvalue("tag")
|
||||
local image_id = image_id or luci.http.formvalue("id")
|
||||
|
||||
if type(src) ~= "string" or not image_id then
|
||||
luci.http.status(400, "no image id or tag")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({message = "no image id or tag"})
|
||||
return
|
||||
end
|
||||
|
||||
local repo = src:match("^([^:]+)")
|
||||
local tag = src:match("^[^:]-:([^:]+)")
|
||||
local dk = docker.new()
|
||||
local res = dk.images:tag({
|
||||
id = image_id,
|
||||
query={
|
||||
repo=repo,
|
||||
tag=tag
|
||||
}
|
||||
})
|
||||
local msg = res and res.body and res.body.message or nil
|
||||
luci.http.status(res.code, msg)
|
||||
luci.http.prepare_content("application/json")
|
||||
|
||||
if res.code == 201 then
|
||||
local tags = res.body.RepoTags
|
||||
luci.http.write_json({tags = tags})
|
||||
else
|
||||
local msg = res and res.body and res.body.message or nil
|
||||
luci.http.write_json({message = msg})
|
||||
end
|
||||
end
|
||||
|
||||
function untag_image(tag)
|
||||
local tag = tag or luci.http.formvalue("tag")
|
||||
|
||||
if not tag then
|
||||
luci.http.status(400, "no tag name")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({message = "no tag name"})
|
||||
return
|
||||
end
|
||||
|
||||
local dk = docker.new()
|
||||
local res = dk.images:inspect({name = tag})
|
||||
|
||||
if res.code == 200 then
|
||||
local tags = res.body.RepoTags
|
||||
if #tags > 1 then
|
||||
local r = dk.images:remove({name = tag})
|
||||
local msg = r and r.body and r.body.message or nil
|
||||
luci.http.status(r.code, msg)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({message = msg})
|
||||
else
|
||||
luci.http.status(500, "Cannot remove the last tag")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({message = "Cannot remove the last tag"})
|
||||
end
|
||||
else
|
||||
local msg = res and res.body and res.body.message or nil
|
||||
luci.http.status(res.code, msg)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({message = msg})
|
||||
end
|
||||
end
|
||||
页面:
|
||||
98ms
|
||||
模板:
|
||||
12ms
|
||||
粤ICP备15088933号-3
|
||||
公网安备粤公网安备 44090202000478号
|
Loading…
Reference in New Issue
Block a user