lxc.lua 4.8 KB

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