luci-app-dockerman: controller/docker refactoring and update coding style
authorFlorian Eckert <fe@dev.tdt.de>
Wed, 22 Jul 2020 14:08:05 +0000 (16:08 +0200)
committerFlorian Eckert <fe@dev.tdt.de>
Tue, 28 Jul 2020 12:16:14 +0000 (14:16 +0200)
Signed-off-by: Florian Eckert <fe@dev.tdt.de>
applications/luci-app-dockerman/luasrc/controller/dockerman.lua

index 6f4e43df53c2c08a5bb14c6d188217c5efa9632a..a592f4b3aa0b98c0f6dc21e2536a60b82b32f525 100644 (file)
 LuCI - Lua Configuration Interface
 Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
 ]]--
-require "luci.util"
+
 local docker = require "luci.model.docker"
--- local uci = require "luci.model.uci"
 
 module("luci.controller.dockerman",package.seeall)
 
 function index()
+       local e = entry({"admin", "docker"}, firstchild(), "Docker", 40)
+       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
+
+       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", "images"}, form("dockerman/images"), _("Images"),2).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", "events"}, call("action_events"), _("Events"),5)
 
-  local e = entry({"admin", "docker"}, firstchild(), "Docker", 40)
-  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
-
-  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","images"},form("dockerman/images"),_("Images"),2).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","events"},call("action_events"),_("Events"),5)
-  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
+       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 dk = docker.new()
-  local query ={}
-  query["until"] = os.time()
-  local events = dk:events({query = query})
-  if events.code == 200 then
-    for _, v in ipairs(events.body) do
-      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 or "null") .. " Container ID:"..  (v.Actor.ID or "null") .. " Container Name:" .. (v.Actor.Attributes.name or "null")
-      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 .. " Container ID:"..( v.Actor.Attributes.container or "null" ) .. " Network Name:" .. (v.Actor.Attributes.name or "null") .. " Network type:".. v.Actor.Attributes.type or ""
-      elseif v.Type == "image" 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")
-      end
-    end
-  end
-  luci.template.render("dockerman/logs", {self={syslog = logs, title="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
+                       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 or "null") .. " Container ID:"..  (v.Actor.ID or "null") .. " Container Name:" .. (v.Actor.Attributes.name or "null")
+                       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 .. " Container ID:"..( v.Actor.Attributes.container or "null" ) .. " Network Name:" .. (v.Actor.Attributes.name or "null") .. " Network type:".. v.Actor.Attributes.type or ""
+                       elseif v.Type == "image" 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")
+                       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
-   cpu_count = tonumber(d["cpu_stats"]["online_cpus"])
-   cpu_percent = 0.0
-   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"])
-  if system_delta > 0.0 then
-    cpu_percent = string.format("%.2f", cpu_delta / system_delta * 100.0 * cpu_count)
-  end
-  -- return cpu_percent .. "%"
-  return cpu_percent
+       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 = string.format("%.2f", tonumber(d["memory_stats"]["limit"]) / 1024 / 1024)
-  -- local usage = string.format("%.2f", (tonumber(d["memory_stats"]["usage"]) - tonumber(d["memory_stats"]["stats"]["total_cache"])) / 1024 / 1024)
-  -- return usage .. "MB / " .. limit.. "MB" 
-  local limit =tonumber(d["memory_stats"]["limit"])
-  local usage = tonumber(d["memory_stats"]["usage"]) - tonumber(d["memory_stats"]["stats"]["total_cache"])
-  return usage, limit
+       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 = (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"
-  --   end
-  -- 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
+       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
+       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(" ","&nbsp;")
-    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})
+       local data = docker:read_status()
+       if data then
+               data = data:gsub("\n","<br>"):gsub(" ","&nbsp;")
+               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)
+       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})
+       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})
+       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})
-  -- 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
-  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})
+       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
-    -- res.body = {"status":"sha256:d5304b58e2d8cc0a2fd640c05cec1bd4d1229a604ac0dd2909f13b2b47a29285"}
-    msg = res.body.status or res.body.error
-  elseif not msg and #res.body >= 1 then
-    -- res.body = [...{"status":"sha256:d5304b58e2d8cc0a2fd640c05cec1bd4d1229a604ac0dd2909f13b2b47a29285"}]
-    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})
+       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
+       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
+       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
+       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