lxc.lua 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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 ssl_status = lxc_get_ssl_status()
  43. local templates = {}
  44. local f = io.popen('sh /usr/share/lxc/templates/lxc-download --list %s --server %s 2>/dev/null'
  45. %{ ssl_status, url }, 'r')
  46. local line
  47. for line in f:lines() do
  48. local dist, version, dist_target = line:match("^(%S+)%s+(%S+)%s+(%S+)%s+default%s+%S+$")
  49. if dist and version and dist_target and dist_target == target then
  50. templates[#templates+1] = "%s:%s" %{ dist, version }
  51. end
  52. end
  53. f:close()
  54. luci.http.prepare_content("application/json")
  55. luci.http.write_json(templates)
  56. end
  57. function lxc_create(lxc_name, lxc_template)
  58. luci.http.prepare_content("text/plain")
  59. local path = lxc_get_config_path()
  60. if not path then
  61. return
  62. end
  63. local ssl_status = lxc_get_ssl_status()
  64. local lxc_dist, lxc_release = lxc_template:match("^(.+):(.+)$")
  65. luci.sys.call('/usr/bin/lxc-create --quiet --name %s --bdev best --template download -- --dist %s --release %s --arch %s --server %s %s'
  66. %{ lxc_name, lxc_dist, lxc_release, lxc_get_arch_target(url), url, ssl_status })
  67. while (nx.fs.access(path .. lxc_name .. "/partial")) do
  68. nx.nanosleep(1)
  69. end
  70. luci.http.write("0")
  71. end
  72. function lxc_action(lxc_action, lxc_name)
  73. local data, ec = util.ubus("lxc", lxc_action, lxc_name and { name = lxc_name } or {})
  74. luci.http.prepare_content("application/json")
  75. luci.http.write_json(ec and {} or data)
  76. end
  77. function lxc_get_config_path()
  78. local f = io.open("/etc/lxc/lxc.conf", "r")
  79. local content = f:read("*all")
  80. f:close()
  81. local ret = content:match('^%s*lxc.lxcpath%s*=%s*([^%s]*)')
  82. if ret then
  83. if nx.fs.access(ret) then
  84. local min_space = tonumber(uci:get("lxc", "lxc", "min_space")) or 100000
  85. local free_space = tonumber(util.exec("df " ..ret.. " | awk '{if(NR==2)print $4}'"))
  86. if free_space and free_space >= min_space then
  87. local min_temp = tonumber(uci:get("lxc", "lxc", "min_temp")) or 100000
  88. local free_temp = tonumber(util.exec("df /tmp | awk '{if(NR==2)print $4}'"))
  89. if free_temp and free_temp >= min_temp then
  90. return ret .. "/"
  91. else
  92. util.perror("lxc error: not enough temporary space (< " ..min_temp.. " KB)")
  93. end
  94. else
  95. util.perror("lxc error: not enough space (< " ..min_space.. " KB)")
  96. end
  97. else
  98. util.perror("lxc error: directory not found")
  99. end
  100. else
  101. util.perror("lxc error: config path is empty")
  102. end
  103. end
  104. function lxc_configuration_get(lxc_name)
  105. luci.http.prepare_content("text/plain")
  106. local f = io.open(lxc_get_config_path() .. lxc_name .. "/config", "r")
  107. local content = f:read("*all")
  108. f:close()
  109. luci.http.write(content)
  110. end
  111. function lxc_configuration_set(lxc_name)
  112. luci.http.prepare_content("text/plain")
  113. local lxc_configuration = luci.http.formvalue("lxc_conf")
  114. if lxc_configuration == nil then
  115. util.perror("lxc error: config formvalue is empty")
  116. return
  117. end
  118. local f, err = io.open(lxc_get_config_path() .. lxc_name .. "/config","w+")
  119. if not f then
  120. util.perror("lxc error: config file not found")
  121. return
  122. end
  123. f:write(lxc_configuration)
  124. f:close()
  125. luci.http.write("0")
  126. end
  127. function lxc_get_arch_target(url)
  128. local target = nx.uname().machine
  129. if url and url:match("images.linuxcontainers.org") then
  130. local target_map = {
  131. armv5 = "armel",
  132. armv6 = "armel",
  133. armv7 = "armhf",
  134. armv8 = "arm64",
  135. aarch64 = "arm64",
  136. i686 = "i386",
  137. x86_64 = "amd64"
  138. }
  139. local k, v
  140. for k, v in pairs(target_map) do
  141. if target:find(k) then
  142. return v
  143. end
  144. end
  145. end
  146. return target
  147. end
  148. function lxc_get_ssl_status()
  149. local ssl_enabled = uci:get("lxc", "lxc", "ssl_enabled")
  150. local ssl_status = "--no-validate"
  151. if ssl_enabled and ssl_enabled == "1" then
  152. ssl_status = ""
  153. end
  154. return ssl_status
  155. end