luci-app-dockerman: controller/docker refactoring and update coding style

Signed-off-by: Florian Eckert <fe@dev.tdt.de>
This commit is contained in:
Florian Eckert 2020-07-22 16:08:05 +02:00
parent 94bcd70e97
commit 10e6f62904

View file

@ -2,386 +2,444 @@
LuCI - Lua Configuration Interface LuCI - Lua Configuration Interface
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman> Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]-- ]]--
require "luci.util"
local docker = require "luci.model.docker" local docker = require "luci.model.docker"
-- local uci = require "luci.model.uci"
module("luci.controller.dockerman",package.seeall) module("luci.controller.dockerman",package.seeall)
function index() function index()
local e = entry({"admin", "docker"}, firstchild(), "Docker", 40)
e.dependent = false
e.acl_depends = { "luci-app-dockerman" }
local e = entry({"admin", "docker"}, firstchild(), "Docker", 40) entry({"admin", "docker", "overview"},cbi("dockerman/overview"),_("Overview"),0).leaf=true
e.dependent = false
e.acl_depends = { "luci-app-dockerman" }
entry({"admin","docker","overview"},cbi("dockerman/overview"),_("Overview"),0).leaf=true local remote = luci.model.uci.cursor():get("dockerd", "globals", "remote_endpoint")
if remote == nil then
local socket = luci.model.uci.cursor():get("dockerd", "globals", "socket_path")
if socket and not nixio.fs.access(socket) then
return
end
elseif remote == "true" then
local host = luci.model.uci.cursor():get("dockerd", "globals", "remote_host")
local port = luci.model.uci.cursor():get("dockerd", "globals", "remote_port")
if not host or not port then
return
end
end
local remote = luci.model.uci.cursor():get("dockerd", "globals", "remote_endpoint") if (require "luci.model.docker").new():_ping().code ~= 200 then
if remote == nil then return
local socket = luci.model.uci.cursor():get("dockerd", "globals", "socket_path") end
if socket and not nixio.fs.access(socket) then return end
elseif remote == "true" then
local host = luci.model.uci.cursor():get("dockerd", "globals", "remote_host")
local port = luci.model.uci.cursor():get("dockerd", "globals", "remote_port")
if not host or not port then return end
end
if (require "luci.model.docker").new():_ping().code ~= 200 then return end entry({"admin", "docker", "containers"}, form("dockerman/containers"), _("Containers"),1).leaf=true
entry({"admin","docker","containers"},form("dockerman/containers"),_("Containers"),1).leaf=true entry({"admin", "docker", "images"}, form("dockerman/images"), _("Images"),2).leaf=true
entry({"admin","docker","images"},form("dockerman/images"),_("Images"),2).leaf=true entry({"admin", "docker", "networks"}, form("dockerman/networks"), _("Networks"),3).leaf=true
entry({"admin","docker","networks"},form("dockerman/networks"),_("Networks"),3).leaf=true entry({"admin", "docker", "volumes"}, form("dockerman/volumes"), _("Volumes"),4).leaf=true
entry({"admin","docker","volumes"},form("dockerman/volumes"),_("Volumes"),4).leaf=true entry({"admin", "docker", "events"}, call("action_events"), _("Events"),5)
entry({"admin","docker","events"},call("action_events"),_("Events"),5)
entry({"admin","docker","newcontainer"},form("dockerman/newcontainer")).leaf=true entry({"admin", "docker", "newcontainer"}, form("dockerman/newcontainer")).leaf=true
entry({"admin","docker","newnetwork"},form("dockerman/newnetwork")).leaf=true entry({"admin", "docker", "newnetwork"}, form("dockerman/newnetwork")).leaf=true
entry({"admin","docker","container"},form("dockerman/container")).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_stats"}, call("action_get_container_stats")).leaf=true
entry({"admin","docker","container_put_archive"},call("upload_archive")).leaf=true entry({"admin", "docker", "container_get_archive"}, call("download_archive")).leaf=true
entry({"admin","docker","images_save"},call("save_images")).leaf=true entry({"admin", "docker", "container_put_archive"}, call("upload_archive")).leaf=true
entry({"admin","docker","images_load"},call("load_images")).leaf=true entry({"admin", "docker", "images_save"}, call("save_images")).leaf=true
entry({"admin","docker","images_import"},call("import_images")).leaf=true entry({"admin", "docker", "images_load"}, call("load_images")).leaf=true
entry({"admin","docker","images_get_tags"},call("get_image_tags")).leaf=true entry({"admin", "docker", "images_import"}, call("import_images")).leaf=true
entry({"admin","docker","images_tag"},call("tag_image")).leaf=true entry({"admin", "docker", "images_get_tags"}, call("get_image_tags")).leaf=true
entry({"admin","docker","images_untag"},call("untag_image")).leaf=true entry({"admin", "docker", "images_tag"}, call("tag_image")).leaf=true
entry({"admin","docker","confirm"},call("action_confirm")).leaf=true entry({"admin", "docker", "images_untag"}, call("untag_image")).leaf=true
entry({"admin", "docker", "confirm"}, call("action_confirm")).leaf=true
end end
function action_events() function action_events()
local logs = "" local logs = ""
local dk = docker.new() local query ={}
local query ={}
query["until"] = os.time() local dk = docker.new()
local events = dk:events({query = query}) query["until"] = os.time()
if events.code == 200 then local events = dk:events({query = query})
for _, v in ipairs(events.body) do
if v and v.Type == "container" then if events.code == 200 then
logs = (logs ~= "" and (logs .. "\n") or logs) .. "[" .. os.date("%Y-%m-%d %H:%M:%S", v.time) .."] "..v.Type.. " " .. (v.Action or "null") .. " Container ID:".. (v.Actor.ID or "null") .. " Container Name:" .. (v.Actor.Attributes.name or "null") for _, v in ipairs(events.body) do
elseif v.Type == "network" then if v and v.Type == "container" then
logs = (logs ~= "" and (logs .. "\n") or logs) .. "[" .. os.date("%Y-%m-%d %H:%M:%S", v.time) .."] "..v.Type.. " " .. v.Action .. " Container ID:"..( v.Actor.Attributes.container or "null" ) .. " Network Name:" .. (v.Actor.Attributes.name or "null") .. " Network type:".. v.Actor.Attributes.type or "" logs = (logs ~= "" and (logs .. "\n") or logs) .. "[" .. os.date("%Y-%m-%d %H:%M:%S", v.time) .."] "..v.Type.. " " .. (v.Action or "null") .. " Container ID:".. (v.Actor.ID or "null") .. " Container Name:" .. (v.Actor.Attributes.name or "null")
elseif v.Type == "image" then elseif v.Type == "network" then
logs = (logs ~= "" and (logs .. "\n") or logs) .. "[" .. os.date("%Y-%m-%d %H:%M:%S", v.time) .."] "..v.Type.. " " .. v.Action .. " Image:".. (v.Actor.ID or "null").. " Image Name:" .. (v.Actor.Attributes.name or "null") logs = (logs ~= "" and (logs .. "\n") or logs) .. "[" .. os.date("%Y-%m-%d %H:%M:%S", v.time) .."] "..v.Type.. " " .. v.Action .. " Container ID:"..( v.Actor.Attributes.container or "null" ) .. " Network Name:" .. (v.Actor.Attributes.name or "null") .. " Network type:".. v.Actor.Attributes.type or ""
end elseif v.Type == "image" then
end logs = (logs ~= "" and (logs .. "\n") or logs) .. "[" .. os.date("%Y-%m-%d %H:%M:%S", v.time) .."] "..v.Type.. " " .. v.Action .. " Image:".. (v.Actor.ID or "null").. " Image Name:" .. (v.Actor.Attributes.name or "null")
end end
luci.template.render("dockerman/logs", {self={syslog = logs, title="Events"}}) end
end
luci.template.render("dockerman/logs", {self={syslog = logs, title="Events"}})
end end
local calculate_cpu_percent = function(d) local calculate_cpu_percent = function(d)
if type(d) ~= "table" then return end if type(d) ~= "table" then
cpu_count = tonumber(d["cpu_stats"]["online_cpus"]) return
cpu_percent = 0.0 end
cpu_delta = tonumber(d["cpu_stats"]["cpu_usage"]["total_usage"]) - tonumber(d["precpu_stats"]["cpu_usage"]["total_usage"])
system_delta = tonumber(d["cpu_stats"]["system_cpu_usage"]) - tonumber(d["precpu_stats"]["system_cpu_usage"]) local cpu_count = tonumber(d["cpu_stats"]["online_cpus"])
if system_delta > 0.0 then local cpu_percent = 0.0
cpu_percent = string.format("%.2f", cpu_delta / system_delta * 100.0 * cpu_count) local cpu_delta = tonumber(d["cpu_stats"]["cpu_usage"]["total_usage"]) - tonumber(d["precpu_stats"]["cpu_usage"]["total_usage"])
end local system_delta = tonumber(d["cpu_stats"]["system_cpu_usage"]) - tonumber(d["precpu_stats"]["system_cpu_usage"])
-- return cpu_percent .. "%" if system_delta > 0.0 then
return cpu_percent cpu_percent = string.format("%.2f", cpu_delta / system_delta * 100.0 * cpu_count)
end
return cpu_percent
end end
local get_memory = function(d) local get_memory = function(d)
if type(d) ~= "table" then return end if type(d) ~= "table" then
-- local limit = string.format("%.2f", tonumber(d["memory_stats"]["limit"]) / 1024 / 1024) return
-- local usage = string.format("%.2f", (tonumber(d["memory_stats"]["usage"]) - tonumber(d["memory_stats"]["stats"]["total_cache"])) / 1024 / 1024) end
-- return usage .. "MB / " .. limit.. "MB"
local limit =tonumber(d["memory_stats"]["limit"]) local limit =tonumber(d["memory_stats"]["limit"])
local usage = tonumber(d["memory_stats"]["usage"]) - tonumber(d["memory_stats"]["stats"]["total_cache"]) local usage = tonumber(d["memory_stats"]["usage"]) - tonumber(d["memory_stats"]["stats"]["total_cache"])
return usage, limit
return usage, limit
end end
local get_rx_tx = function(d) local get_rx_tx = function(d)
if type(d) ~="table" then return end if type(d) ~="table" then
-- local data return
-- if type(d["networks"]) == "table" then end
-- for e, v in pairs(d["networks"]) do
-- data = (data and (data .. "<br>") or "") .. e .. " Total Tx:" .. string.format("%.2f",(tonumber(v.tx_bytes)/1024/1024)) .. "MB Total Rx: ".. string.format("%.2f",(tonumber(v.rx_bytes)/1024/1024)) .. "MB" local data = {}
-- end if type(d["networks"]) == "table" then
-- end for e, v in pairs(d["networks"]) do
local data = {} data[e] = {
if type(d["networks"]) == "table" then bw_tx = tonumber(v.tx_bytes),
for e, v in pairs(d["networks"]) do bw_rx = tonumber(v.rx_bytes)
data[e] = { }
bw_tx = tonumber(v.tx_bytes), end
bw_rx = tonumber(v.rx_bytes) end
}
end return data
end
return data
end end
function action_get_container_stats(container_id) function action_get_container_stats(container_id)
if container_id then if container_id then
local dk = docker.new() local dk = docker.new()
local response = dk.containers:inspect({id = container_id}) local response = dk.containers:inspect({id = container_id})
if response.code == 200 and response.body.State.Running then if response.code == 200 and response.body.State.Running then
response = dk.containers:stats({id = container_id, query = {stream = false}}) response = dk.containers:stats({id = container_id, query = {stream = false}})
if response.code == 200 then if response.code == 200 then
local container_stats = response.body local container_stats = response.body
local cpu_percent = calculate_cpu_percent(container_stats) local cpu_percent = calculate_cpu_percent(container_stats)
local mem_useage, mem_limit = get_memory(container_stats) local mem_useage, mem_limit = get_memory(container_stats)
local bw_rxtx = get_rx_tx(container_stats) local bw_rxtx = get_rx_tx(container_stats)
luci.http.status(response.code, response.body.message) luci.http.status(response.code, response.body.message)
luci.http.prepare_content("application/json") luci.http.prepare_content("application/json")
luci.http.write_json({ luci.http.write_json({
cpu_percent = cpu_percent, cpu_percent = cpu_percent,
memory = { memory = {
mem_useage = mem_useage, mem_useage = mem_useage,
mem_limit = mem_limit mem_limit = mem_limit
}, },
bw_rxtx = bw_rxtx bw_rxtx = bw_rxtx
}) })
else else
luci.http.status(response.code, response.body.message) luci.http.status(response.code, response.body.message)
luci.http.prepare_content("text/plain") luci.http.prepare_content("text/plain")
luci.http.write(response.body.message) luci.http.write(response.body.message)
end end
else else
if response.code == 200 then if response.code == 200 then
luci.http.status(500, "container "..container_id.." not running") luci.http.status(500, "container "..container_id.." not running")
luci.http.prepare_content("text/plain") luci.http.prepare_content("text/plain")
luci.http.write("Container "..container_id.." not running") luci.http.write("Container "..container_id.." not running")
else else
luci.http.status(response.code, response.body.message) luci.http.status(response.code, response.body.message)
luci.http.prepare_content("text/plain") luci.http.prepare_content("text/plain")
luci.http.write(response.body.message) luci.http.write(response.body.message)
end end
end end
else else
luci.http.status(404, "No container name or id") luci.http.status(404, "No container name or id")
luci.http.prepare_content("text/plain") luci.http.prepare_content("text/plain")
luci.http.write("No container name or id") luci.http.write("No container name or id")
end end
end end
function action_confirm() function action_confirm()
local data = docker:read_status() local data = docker:read_status()
if data then if data then
data = data:gsub("\n","<br>"):gsub(" ","&nbsp;") data = data:gsub("\n","<br>"):gsub(" ","&nbsp;")
code = 202 code = 202
msg = data msg = data
else else
code = 200 code = 200
msg = "finish" msg = "finish"
data = "finish" data = "finish"
end end
luci.http.status(code, msg)
luci.http.prepare_content("application/json") luci.http.status(code, msg)
luci.http.write_json({info = data}) luci.http.prepare_content("application/json")
luci.http.write_json({info = data})
end end
function download_archive() function download_archive()
local id = luci.http.formvalue("id") local id = luci.http.formvalue("id")
local path = luci.http.formvalue("path") local path = luci.http.formvalue("path")
local dk = docker.new() local dk = docker.new()
local first local first
local cb = function(res, chunk) local cb = function(res, chunk)
if res.code == 200 then if res.code == 200 then
if not first then if not first then
first = true first = true
luci.http.header('Content-Disposition', 'inline; filename="archive.tar"') luci.http.header('Content-Disposition', 'inline; filename="archive.tar"')
luci.http.header('Content-Type', 'application\/x-tar') luci.http.header('Content-Type', 'application\/x-tar')
end end
luci.ltn12.pump.all(chunk, luci.http.write) luci.ltn12.pump.all(chunk, luci.http.write)
else else
if not first then if not first then
first = true first = true
luci.http.prepare_content("text/plain") luci.http.prepare_content("text/plain")
end end
luci.ltn12.pump.all(chunk, luci.http.write) luci.ltn12.pump.all(chunk, luci.http.write)
end end
end end
local res = dk.containers:get_archive({id = id, query = {path = path}}, cb) local res = dk.containers:get_archive({
id = id,
query = {
path = path
}
}, cb)
end end
function upload_archive(container_id) function upload_archive(container_id)
local path = luci.http.formvalue("upload-path") local path = luci.http.formvalue("upload-path")
local dk = docker.new() local dk = docker.new()
local ltn12 = require "luci.ltn12" local ltn12 = require "luci.ltn12"
local rec_send = function(sinkout) local rec_send = function(sinkout)
luci.http.setfilehandler(function (meta, chunk, eof) luci.http.setfilehandler(function (meta, chunk, eof)
if chunk then if chunk then
ltn12.pump.step(ltn12.source.string(chunk), sinkout) ltn12.pump.step(ltn12.source.string(chunk), sinkout)
end end
end) end)
end end
local res = dk.containers:put_archive({id = container_id, query = {path = path}, body = rec_send}) local res = dk.containers:put_archive({
local msg = res and res.body and res.body.message or nil id = container_id,
luci.http.status(res.code, msg) query = {
luci.http.prepare_content("application/json") path = path
luci.http.write_json({message = msg}) },
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 end
function save_images(container_id) function save_images(container_id)
local names = luci.http.formvalue("names") local names = luci.http.formvalue("names")
local dk = docker.new() local dk = docker.new()
local first local first
local cb = function(res, chunk) local cb = function(res, chunk)
if res.code == 200 then if res.code == 200 then
if not first then if not first then
first = true first = true
luci.http.status(res.code, res.message) luci.http.status(res.code, res.message)
luci.http.header('Content-Disposition', 'inline; filename="images.tar"') luci.http.header('Content-Disposition', 'inline; filename="images.tar"')
luci.http.header('Content-Type', 'application\/x-tar') luci.http.header('Content-Type', 'application\/x-tar')
end end
luci.ltn12.pump.all(chunk, luci.http.write) luci.ltn12.pump.all(chunk, luci.http.write)
else else
if not first then if not first then
first = true first = true
luci.http.prepare_content("text/plain") luci.http.prepare_content("text/plain")
end end
luci.ltn12.pump.all(chunk, luci.http.write) luci.ltn12.pump.all(chunk, luci.http.write)
end end
end end
docker:write_status("Images: saving" .. " " .. container_id .. "...")
local res = dk.images:get({id = container_id, query = {names = names}}, cb) docker:write_status("Images: saving" .. " " .. container_id .. "...")
docker:clear_status() local res = dk.images:get({
local msg = res and res.body and res.body.message or nil id = container_id,
luci.http.status(res.code, msg) query = {
luci.http.prepare_content("application/json") names = names
luci.http.write_json({message = msg}) }
}, 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 end
function load_images() function load_images()
local path = luci.http.formvalue("upload-path") local path = luci.http.formvalue("upload-path")
local dk = docker.new() local dk = docker.new()
local ltn12 = require "luci.ltn12" local ltn12 = require "luci.ltn12"
local rec_send = function(sinkout) local rec_send = function(sinkout)
luci.http.setfilehandler(function (meta, chunk, eof) luci.http.setfilehandler(function (meta, chunk, eof)
if chunk then if chunk then
ltn12.pump.step(ltn12.source.string(chunk), sinkout) ltn12.pump.step(ltn12.source.string(chunk), sinkout)
end end
end) end)
end end
docker:write_status("Images: loading...") docker:write_status("Images: loading...")
local res = dk.images:load({body = rec_send}) local res = dk.images:load({body = rec_send})
-- res.body = {"stream":"Loaded image ID: sha256:1399d3d81f80d68832e85ed6ba5f94436ca17966539ba715f661bd36f3caf08f\n"} local msg = res and res.body and ( res.body.message or res.body.stream or res.body.error ) or nil
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
if res.code == 200 and msg and msg:match("Loaded image ID") then docker:clear_status()
docker:clear_status() luci.http.status(res.code, msg)
luci.http.status(res.code, msg) else
else docker:append_status("code:" .. res.code.." ".. msg)
docker:append_status("code:" .. res.code.." ".. msg) luci.http.status(300, msg)
luci.http.status(300, msg) end
end
luci.http.prepare_content("application/json") luci.http.prepare_content("application/json")
luci.http.write_json({message = msg}) luci.http.write_json({message = msg})
end end
function import_images() function import_images()
local src = luci.http.formvalue("src") local src = luci.http.formvalue("src")
local itag = luci.http.formvalue("tag") local itag = luci.http.formvalue("tag")
local dk = docker.new() local dk = docker.new()
local ltn12 = require "luci.ltn12" local ltn12 = require "luci.ltn12"
local rec_send = function(sinkout)
luci.http.setfilehandler(function (meta, chunk, eof) local rec_send = function(sinkout)
if chunk then luci.http.setfilehandler(function (meta, chunk, eof)
ltn12.pump.step(ltn12.source.string(chunk), sinkout) if chunk then
end ltn12.pump.step(ltn12.source.string(chunk), sinkout)
end) end
end end)
docker:write_status("Images: importing".. " ".. itag .."...\n") end
local repo = itag and itag:match("^([^:]+)")
local tag = itag and itag:match("^[^:]-:([^:]+)") docker:write_status("Images: importing".. " ".. itag .."...\n")
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 repo = itag and itag:match("^([^:]+)")
local msg = res and res.body and ( res.body.message )or nil local tag = itag and itag:match("^[^:]-:([^:]+)")
if not msg and #res.body == 0 then local res = dk.images:create({
-- res.body = {"status":"sha256:d5304b58e2d8cc0a2fd640c05cec1bd4d1229a604ac0dd2909f13b2b47a29285"} query = {
msg = res.body.status or res.body.error fromSrc = src or "-",
elseif not msg and #res.body >= 1 then repo = repo or nil,
-- res.body = [...{"status":"sha256:d5304b58e2d8cc0a2fd640c05cec1bd4d1229a604ac0dd2909f13b2b47a29285"}] tag = tag or nil
msg = res.body[#res.body].status or res.body[#res.body].error },
end body = not src and rec_send or nil
if res.code == 200 and msg and msg:match("sha256:") then }, docker.import_image_show_status_cb)
docker:clear_status()
else local msg = res and res.body and ( res.body.message )or nil
docker:append_status("code:" .. res.code.." ".. msg) if not msg and #res.body == 0 then
end msg = res.body.status or res.body.error
luci.http.status(res.code, msg) elseif not msg and #res.body >= 1 then
luci.http.prepare_content("application/json") msg = res.body[#res.body].status or res.body[#res.body].error
luci.http.write_json({message = msg}) 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 end
function get_image_tags(image_id) function get_image_tags(image_id)
if not image_id then if not image_id then
luci.http.status(400, "no image id") luci.http.status(400, "no image id")
luci.http.prepare_content("application/json") luci.http.prepare_content("application/json")
luci.http.write_json({message = "no image id"}) luci.http.write_json({message = "no image id"})
return return
end end
local dk = docker.new()
local res = dk.images:inspect({id = image_id}) local dk = docker.new()
local msg = res and res.body and res.body.message or nil local res = dk.images:inspect({
luci.http.status(res.code, msg) id = image_id
luci.http.prepare_content("application/json") })
if res.code == 200 then local msg = res and res.body and res.body.message or nil
local tags = res.body.RepoTags luci.http.status(res.code, msg)
luci.http.write_json({tags = tags}) luci.http.prepare_content("application/json")
else
local msg = res and res.body and res.body.message or nil if res.code == 200 then
luci.http.write_json({message = msg}) local tags = res.body.RepoTags
end 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 end
function tag_image(image_id) function tag_image(image_id)
local src = luci.http.formvalue("tag") local src = luci.http.formvalue("tag")
local image_id = image_id or luci.http.formvalue("id") 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") if type(src) ~= "string" or not image_id then
luci.http.prepare_content("application/json") luci.http.status(400, "no image id or tag")
luci.http.write_json({message = "no image id or tag"}) luci.http.prepare_content("application/json")
return luci.http.write_json({message = "no image id or tag"})
end return
local repo = src:match("^([^:]+)") end
local tag = src:match("^[^:]-:([^:]+)")
local dk = docker.new() local repo = src:match("^([^:]+)")
local res = dk.images:tag({id = image_id, query={repo=repo, tag=tag}}) local tag = src:match("^[^:]-:([^:]+)")
local msg = res and res.body and res.body.message or nil local dk = docker.new()
luci.http.status(res.code, msg) local res = dk.images:tag({
luci.http.prepare_content("application/json") id = image_id,
if res.code == 201 then query={
local tags = res.body.RepoTags repo=repo,
luci.http.write_json({tags = tags}) tag=tag
else }
local msg = res and res.body and res.body.message or nil })
luci.http.write_json({message = msg}) local msg = res and res.body and res.body.message or nil
end 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 end
function untag_image(tag) function untag_image(tag)
local tag = tag or luci.http.formvalue("tag") local tag = tag or luci.http.formvalue("tag")
if not tag then
luci.http.status(400, "no tag name") if not tag then
luci.http.prepare_content("application/json") luci.http.status(400, "no tag name")
luci.http.write_json({message = "no tag name"}) luci.http.prepare_content("application/json")
return luci.http.write_json({message = "no tag name"})
end return
local dk = docker.new() end
local res = dk.images:inspect({name = tag})
if res.code == 200 then local dk = docker.new()
local tags = res.body.RepoTags local res = dk.images:inspect({name = tag})
if #tags > 1 then
local r = dk.images:remove({name = tag}) if res.code == 200 then
local msg = r and r.body and r.body.message or nil local tags = res.body.RepoTags
luci.http.status(r.code, msg) if #tags > 1 then
luci.http.prepare_content("application/json") local r = dk.images:remove({name = tag})
luci.http.write_json({message = msg}) local msg = r and r.body and r.body.message or nil
else luci.http.status(r.code, msg)
luci.http.status(500, "Cannot remove the last tag") luci.http.prepare_content("application/json")
luci.http.prepare_content("application/json") luci.http.write_json({message = msg})
luci.http.write_json({message = "Cannot remove the last tag"}) else
end luci.http.status(500, "Cannot remove the last tag")
else luci.http.prepare_content("application/json")
local msg = res and res.body and res.body.message or nil luci.http.write_json({message = "Cannot remove the last tag"})
luci.http.status(res.code, msg) end
luci.http.prepare_content("application/json") else
luci.http.write_json({message = msg}) local msg = res and res.body and res.body.message or nil
end luci.http.status(res.code, msg)
luci.http.prepare_content("application/json")
luci.http.write_json({message = msg})
end
end end