diff options
Diffstat (limited to 'applications/luci-app-dockerman/luasrc/model/cbi/dockerman/images.lua')
-rw-r--r-- | applications/luci-app-dockerman/luasrc/model/cbi/dockerman/images.lua | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/applications/luci-app-dockerman/luasrc/model/cbi/dockerman/images.lua b/applications/luci-app-dockerman/luasrc/model/cbi/dockerman/images.lua new file mode 100644 index 000000000..29d4a6357 --- /dev/null +++ b/applications/luci-app-dockerman/luasrc/model/cbi/dockerman/images.lua @@ -0,0 +1,223 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman> +]]-- + +require "luci.util" +local uci = luci.model.uci.cursor() +local docker = require "luci.model.docker" +local dk = docker.new() + +local containers, images +local res = dk.images:list() +if res.code <300 then images = res.body else return end +res = dk.containers:list({query = {all=true}}) +if res.code <300 then containers = res.body else return end + +function get_images() + local data = {} + for i, v in ipairs(images) do + local index = v.Created .. v.Id + data[index]={} + data[index]["_selected"] = 0 + data[index]["id"] = v.Id:sub(8) + data[index]["_id"] = '<a href="javascript:new_tag(\''..v.Id:sub(8,20)..'\')" class="dockerman-link" title="'..translate("New tag")..'">' .. v.Id:sub(8,20) .. '</a>' + if v.RepoTags and next(v.RepoTags)~=nil then + for i, v1 in ipairs(v.RepoTags) do + data[index]["_tags"] =(data[index]["_tags"] and ( data[index]["_tags"] .. "<br>" )or "") .. ((v1:match("<none>") or (#v.RepoTags == 1)) and v1 or ('<a href="javascript:un_tag(\''..v1..'\')" class="dockerman_link" title="'..translate("Remove tag")..'" >' .. v1 .. '</a>')) + if not data[index]["tag"] then + data[index]["tag"] = v1--:match("<none>") and nil or v1 + end + end + else + data[index]["_tags"] = v.RepoDigests[1] and v.RepoDigests[1]:match("^(.-)@.+") + data[index]["_tags"] = (data[index]["_tags"] and data[index]["_tags"] or "<none>" ).. ":<none>" + end + data[index]["_tags"] = data[index]["_tags"]:gsub("<none>","<none>") + -- data[index]["_tags"] = '<a href="javascript:handle_tag(\''..data[index]["_id"]..'\')">' .. data[index]["_tags"] .. '</a>' + for ci,cv in ipairs(containers) do + if v.Id == cv.ImageID then + data[index]["_containers"] = (data[index]["_containers"] and (data[index]["_containers"] .. " | ") or "").. + '<a href='..luci.dispatcher.build_url("admin/docker/container/"..cv.Id)..' class="dockerman_link" title="'..translate("Container detail")..'">'.. cv.Names[1]:sub(2).."</a>" + end + end + data[index]["_size"] = string.format("%.2f", tostring(v.Size/1024/1024)).."MB" + data[index]["_created"] = os.date("%Y/%m/%d %H:%M:%S",v.Created) + end + return data +end + +local image_list = get_images() + +-- m = Map("docker", translate("Docker")) +m = SimpleForm("docker", translate("Docker")) +m.submit=false +m.reset=false + +local pull_value={_image_tag_name="", _registry="index.docker.io"} +local pull_section = m:section(SimpleSection, translate("Pull Image")) +pull_section.template="cbi/nullsection" +local tag_name = pull_section:option(Value, "_image_tag_name") +tag_name.template = "dockerman/cbi/inlinevalue" +tag_name.placeholder="lisaac/luci:latest" +local action_pull = pull_section:option(Button, "_pull") +action_pull.inputtitle= translate("Pull") +action_pull.template = "dockerman/cbi/inlinebutton" +action_pull.inputstyle = "add" +tag_name.write = function(self, section, value) + local hastag = value:find(":") + if not hastag then + value = value .. ":latest" + end + pull_value["_image_tag_name"] = value +end +action_pull.write = function(self, section) + local tag = pull_value["_image_tag_name"] + local json_stringify = luci.jsonc and luci.jsonc.stringify + if tag and tag ~= "" then + docker:write_status("Images: " .. "pulling" .. " " .. tag .. "...\n") + -- local x_auth = nixio.bin.b64encode(json_stringify({serveraddress= server})) , header={["X-Registry-Auth"] = x_auth} + local res = dk.images:create({query = {fromImage=tag}}, docker.pull_image_show_status_cb) + -- {"errorDetail": {"message": "failed to register layer: ApplyLayer exit status 1 stdout: stderr: write \/docker: no space left on device" }, "error": "failed to register layer: ApplyLayer exit status 1 stdout: stderr: write \/docker: no space left on device" } + if res and res.code == 200 and (res.body[#res.body] and not res.body[#res.body].error and res.body[#res.body].status and (res.body[#res.body].status == "Status: Downloaded newer image for ".. tag)) then + docker:clear_status() + else + docker:append_status("code:" .. res.code.." ".. (res.body[#res.body] and res.body[#res.body].error or (res.body.message or res.message)).. "\n") + end + else + docker:append_status("code: 400 please input the name of image name!") + end + luci.http.redirect(luci.dispatcher.build_url("admin/docker/images")) +end + +local import_section = m:section(SimpleSection, translate("Import Images")) +local im = import_section:option(DummyValue, "_image_import") +im.template = "dockerman/images_import" + +local image_table = m:section(Table, image_list, translate("Images")) + +local image_selecter = image_table:option(Flag, "_selected","") +image_selecter.disabled = 0 +image_selecter.enabled = 1 +image_selecter.default = 0 + +local image_id = image_table:option(DummyValue, "_id", translate("ID")) +image_id.rawhtml = true +image_table:option(DummyValue, "_tags", translate("RepoTags")).rawhtml = true +image_table:option(DummyValue, "_containers", translate("Containers")).rawhtml = true +image_table:option(DummyValue, "_size", translate("Size")) +image_table:option(DummyValue, "_created", translate("Created")) +image_selecter.write = function(self, section, value) + image_list[section]._selected = value +end + +local remove_action = function(force) + local image_selected = {} + -- 遍历table中sectionid + local image_table_sids = image_table:cfgsections() + for _, image_table_sid in ipairs(image_table_sids) do + -- 得到选中项的名字 + if image_list[image_table_sid]._selected == 1 then + image_selected[#image_selected+1] = (image_list[image_table_sid]["_tags"]:match("<br>") or image_list[image_table_sid]["_tags"]:match("<none>")) and image_list[image_table_sid].id or image_list[image_table_sid].tag + end + end + if next(image_selected) ~= nil then + local success = true + docker:clear_status() + for _,img in ipairs(image_selected) do + docker:append_status("Images: " .. "remove" .. " " .. img .. "...") + local query + if force then query = {force = true} end + local msg = dk.images:remove({id = img, query = query}) + if msg.code ~= 200 then + docker:append_status("code:" .. msg.code.." ".. (msg.body.message and msg.body.message or msg.message).. "\n") + success = false + else + docker:append_status("done\n") + end + end + if success then docker:clear_status() end + luci.http.redirect(luci.dispatcher.build_url("admin/docker/images")) + end +end + +local 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","<br>"):gsub(" "," ") +if docker_status.err then docker:clear_status() end + +local action = m:section(Table,{{}}) +action.notitle=true +action.rowcolors=false +action.template="cbi/nullsection" + +local btnremove = action:option(Button, "remove") +btnremove.inputtitle= translate("Remove") +btnremove.template = "dockerman/cbi/inlinebutton" +btnremove.inputstyle = "remove" +btnremove.forcewrite = true +btnremove.write = function(self, section) + remove_action() +end + +local btnforceremove = action:option(Button, "forceremove") +btnforceremove.inputtitle= translate("Force Remove") +btnforceremove.template = "dockerman/cbi/inlinebutton" +btnforceremove.inputstyle = "remove" +btnforceremove.forcewrite = true +btnforceremove.write = function(self, section) + remove_action(true) +end + +local btnsave = action:option(Button, "save") +btnsave.inputtitle= translate("Save") +btnsave.template = "dockerman/cbi/inlinebutton" +btnsave.inputstyle = "edit" +btnsave.forcewrite = true +btnsave.write = function (self, section) + local image_selected = {} + local image_table_sids = image_table:cfgsections() + for _, image_table_sid in ipairs(image_table_sids) do + if image_list[image_table_sid]._selected == 1 then + image_selected[#image_selected+1] = image_list[image_table_sid].id --image_id:cfgvalue(image_table_sid) + end + end + if next(image_selected) ~= nil then + local names + for _,img in ipairs(image_selected) do + names = names and (names .. "&names=".. img) or img + end + 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="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: " .. "save" .. " " .. table.concat(image_selected, "\n") .. "...") + local msg = dk.images:get({query = {names = names}}, cb) + if msg.code ~= 200 then + docker:append_status("code:" .. msg.code.." ".. (msg.body.message and msg.body.message or msg.message).. "\n") + success = false + else + docker:clear_status() + end + end +end + +local btnload = action:option(Button, "load") +btnload.inputtitle= translate("Load") +btnload.template = "dockerman/images_load" +btnload.inputstyle = "add" +return m |