lxc.lua 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. --[[
  2. LuCI LXC module
  3. Copyright (C) 2014, Cisco Systems, Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Author: Petar Koretic <petar.koretic@sartura.hr>
  9. ]]--
  10. module("luci.controller.lxc", package.seeall)
  11. local uci = require "luci.model.uci".cursor()
  12. local util = require "luci.util"
  13. local nx = require "nixio"
  14. local url = util.shellquote(uci:get("lxc", "lxc", "url"))
  15. function index()
  16. if not nixio.fs.access("/etc/config/lxc") then
  17. return
  18. end
  19. page = node("admin", "services", "lxc")
  20. page.target = cbi("lxc")
  21. page.title = _("LXC Containers")
  22. page.order = 70
  23. page.acl_depends = { "luci-app-lxc" }
  24. page = entry({"admin", "services", "lxc_create"}, call("lxc_create"), nil)
  25. page.acl_depends = { "luci-app-lxc" }
  26. page.leaf = true
  27. page = entry({"admin", "services", "lxc_action"}, call("lxc_action"), nil)
  28. page.acl_depends = { "luci-app-lxc" }
  29. page.leaf = true
  30. page = entry({"admin", "services", "lxc_get_downloadable"}, call("lxc_get_downloadable"), nil)
  31. page.acl_depends = { "luci-app-lxc" }
  32. page.leaf = true
  33. page = entry({"admin", "services", "lxc_configuration_get"}, call("lxc_configuration_get"), nil)
  34. page.acl_depends = { "luci-app-lxc" }
  35. page.leaf = true
  36. page = entry({"admin", "services", "lxc_configuration_set"}, call("lxc_configuration_set"), nil)
  37. page.acl_depends = { "luci-app-lxc" }
  38. page.leaf = true
  39. end
  40. function lxc_get_downloadable()
  41. local target = lxc_get_arch_target(url)
  42. local templates = {}
  43. local f = io.popen('sh /usr/share/lxc/templates/lxc-download --list --server %s 2>/dev/null'
  44. %{ url }, 'r')
  45. local line
  46. for line in f:lines() do
  47. local dist, version, dist_target = line:match("^(%S+)%s+(%S+)%s+(%S+)%s+default%s+%S+$")
  48. if dist and version and dist_target and dist_target == target then
  49. templates[#templates+1] = "%s:%s" %{ dist, version }
  50. end
  51. end
  52. f:close()
  53. luci.http.prepare_content("application/json")
  54. luci.http.write_json(templates)
  55. end
  56. function lxc_create(lxc_name, lxc_template)
  57. luci.http.prepare_content("text/plain")
  58. local path = lxc_get_config_path()
  59. if not path then
  60. return
  61. end
  62. local lxc_dist, lxc_release = lxc_template:match("^(.+):(.+)$")
  63. luci.sys.call('/usr/bin/lxc-create --quiet --name %s --bdev best --template download -- --dist %s --release %s --arch %s --server %s'
  64. %{ lxc_name, lxc_dist, lxc_release, lxc_get_arch_target(url), url })
  65. while (nx.fs.access(path .. lxc_name .. "/partial")) do
  66. nx.nanosleep(1)
  67. end
  68. luci.http.write("0")
  69. end
  70. function lxc_action(lxc_action, lxc_name)
  71. local data, ec = util.ubus("lxc", lxc_action, lxc_name and { name = lxc_name } or {})
  72. luci.http.prepare_content("application/json")
  73. luci.http.write_json(ec and {} or data)
  74. end
  75. function lxc_get_config_path()
  76. local f = io.open("/etc/lxc/lxc.conf", "r")
  77. local content = f:read("*all")
  78. f:close()
  79. local ret = content:match('^%s*lxc.lxcpath%s*=%s*([^%s]*)')
  80. if ret then
  81. if nx.fs.access(ret) then
  82. local min_space = tonumber(uci:get("lxc", "lxc", "min_space")) or 100000
  83. local free_space = tonumber(util.exec("df " ..ret.. " | awk '{if(NR==2)print $4}'"))
  84. if free_space and free_space >= min_space then
  85. local min_temp = tonumber(uci:get("lxc", "lxc", "min_temp")) or 100000
  86. local free_temp = tonumber(util.exec("df /tmp | awk '{if(NR==2)print $4}'"))
  87. if free_temp and free_temp >= min_temp then
  88. return ret .. "/"
  89. else
  90. util.perror("lxc error: not enough temporary space (< " ..min_temp.. " KB)")
  91. end
  92. else
  93. util.perror("lxc error: not enough space (< " ..min_space.. " KB)")
  94. end
  95. else
  96. util.perror("lxc error: directory not found")
  97. end
  98. else
  99. util.perror("lxc error: config path is empty")
  100. end
  101. end
  102. function lxc_configuration_get(lxc_name)
  103. luci.http.prepare_content("text/plain")
  104. local f = io.open(lxc_get_config_path() .. lxc_name .. "/config", "r")
  105. local content = f:read("*all")
  106. f:close()
  107. luci.http.write(content)
  108. end
  109. function lxc_configuration_set(lxc_name)
  110. luci.http.prepare_content("text/plain")
  111. local lxc_configuration = luci.http.formvalue("lxc_conf")
  112. if lxc_configuration == nil then
  113. util.perror("lxc error: config formvalue is empty")
  114. return
  115. end
  116. local f, err = io.open(lxc_get_config_path() .. lxc_name .. "/config","w+")
  117. if not f then
  118. util.perror("lxc error: config file not found")
  119. return
  120. end
  121. f:write(lxc_configuration)
  122. f:close()
  123. luci.http.write("0")
  124. end
  125. function lxc_get_arch_target(url)
  126. local target = nx.uname().machine
  127. if url and url:match("images.linuxcontainers.org") then
  128. local target_map = {
  129. armv5 = "armel",
  130. armv6 = "armel",
  131. armv7 = "armhf",
  132. armv8 = "arm64",
  133. aarch64 = "arm64",
  134. i686 = "i386",
  135. x86_64 = "amd64"
  136. }
  137. local k, v
  138. for k, v in pairs(target_map) do
  139. if target:find(k) then
  140. return v
  141. end
  142. end
  143. end
  144. return target
  145. end