You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

427 lines
9.7 KiB

  1. /*
  2. * rpcd-lxc-plugin
  3. *
  4. * Copyright (C) 2014 Cisco Systems, Inc.
  5. * Author: Luka Perkov <luka@openwrt.org>
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for any
  8. * purpose with or without fee is hereby granted, provided that the above
  9. * copyright notice and this permission notice appear in all copies.
  10. *
  11. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  12. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  13. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  14. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  16. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  17. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18. */
  19. #include <libubus.h>
  20. #include <lxc/lxccontainer.h>
  21. #include <rpcd/plugin.h>
  22. static struct blob_buf buf;
  23. struct rpc_lxc {
  24. /* ubus options */
  25. char *name;
  26. char *config;
  27. /* lxc container */
  28. struct lxc_container *container;
  29. };
  30. enum {
  31. RPC_LXC_NAME,
  32. RPC_LXC_CONFIG,
  33. __RPC_LXC_MAX,
  34. };
  35. enum {
  36. RPC_LXC_SHUTDOWN_NAME,
  37. RPC_LXC_SHUTDOWN_CONFIG,
  38. RPC_LXC_SHUTDOWN_TIMEOUT,
  39. __RPC_LXC_SHUTDOWN_MAX,
  40. };
  41. enum {
  42. RPC_LXC_RENAME_NAME,
  43. RPC_LXC_RENAME_CONFIG,
  44. RPC_LXC_RENAME_NEWNAME,
  45. __RPC_LXC_RENAME_MAX,
  46. };
  47. static const struct blobmsg_policy rpc_lxc_min_policy[__RPC_LXC_MAX] = {
  48. [RPC_LXC_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  49. [RPC_LXC_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
  50. };
  51. static const struct blobmsg_policy rpc_lxc_shutdown_policy[__RPC_LXC_SHUTDOWN_MAX] = {
  52. [RPC_LXC_SHUTDOWN_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  53. [RPC_LXC_SHUTDOWN_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
  54. [RPC_LXC_SHUTDOWN_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
  55. };
  56. static const struct blobmsg_policy rpc_lxc_rename_policy[__RPC_LXC_RENAME_MAX] = {
  57. [RPC_LXC_RENAME_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  58. [RPC_LXC_RENAME_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
  59. [RPC_LXC_RENAME_NEWNAME] = { .name = "newname", .type = BLOBMSG_TYPE_STRING },
  60. };
  61. static struct rpc_lxc *
  62. rpc_lxc_init(struct blob_attr *tb[__RPC_LXC_MAX])
  63. {
  64. struct rpc_lxc *l = NULL;
  65. l = calloc(1, sizeof(struct rpc_lxc));
  66. if (!l) return NULL;
  67. if (tb[RPC_LXC_NAME]) {
  68. l->name = blobmsg_data(tb[RPC_LXC_NAME]);
  69. } else {
  70. goto error;
  71. }
  72. if (tb[RPC_LXC_CONFIG]) {
  73. l->config = blobmsg_data(tb[RPC_LXC_CONFIG]);
  74. } else {
  75. l->config = NULL;
  76. }
  77. l->container = lxc_container_new(l->name, l->config);
  78. if (!l->container) {
  79. goto error;
  80. }
  81. return l;
  82. error:
  83. free(l);
  84. return NULL;
  85. }
  86. static void
  87. rpc_lxc_done(struct rpc_lxc *l)
  88. {
  89. if (l) {
  90. lxc_container_put(l->container);
  91. free(l);
  92. }
  93. return;
  94. }
  95. static int
  96. rpc_lxc_start(struct ubus_context *ctx, struct ubus_object *obj,
  97. struct ubus_request_data *req, const char *method,
  98. struct blob_attr *msg)
  99. {
  100. struct blob_attr *tb[__RPC_LXC_MAX];
  101. struct rpc_lxc *l = NULL;
  102. int rc;
  103. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  104. l = rpc_lxc_init(tb);
  105. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  106. if (l->container->is_running(l->container)) {
  107. rc = UBUS_STATUS_UNKNOWN_ERROR;
  108. goto out;
  109. }
  110. if (!l->container->start(l->container, 0, NULL)) {
  111. rc = UBUS_STATUS_INVALID_ARGUMENT;
  112. goto out;
  113. }
  114. rc = UBUS_STATUS_OK;
  115. out:
  116. rpc_lxc_done(l);
  117. return rc;
  118. }
  119. static int
  120. rpc_lxc_reboot(struct ubus_context *ctx, struct ubus_object *obj,
  121. struct ubus_request_data *req, const char *method,
  122. struct blob_attr *msg)
  123. {
  124. struct blob_attr *tb[__RPC_LXC_MAX];
  125. struct rpc_lxc *l = NULL;
  126. int rc;
  127. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  128. l = rpc_lxc_init(tb);
  129. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  130. if (!l->container->is_running(l->container)) {
  131. rc = UBUS_STATUS_UNKNOWN_ERROR;
  132. goto out;
  133. }
  134. if (!l->container->reboot(l->container)) {
  135. rc = UBUS_STATUS_INVALID_ARGUMENT;
  136. goto out;
  137. }
  138. rc = UBUS_STATUS_OK;
  139. out:
  140. rpc_lxc_done(l);
  141. return rc;
  142. }
  143. static int
  144. rpc_lxc_shutdown(struct ubus_context *ctx, struct ubus_object *obj,
  145. struct ubus_request_data *req, const char *method,
  146. struct blob_attr *msg)
  147. {
  148. struct blob_attr *tb[__RPC_LXC_SHUTDOWN_MAX];
  149. struct rpc_lxc *l = NULL;
  150. int rc;
  151. blobmsg_parse(rpc_lxc_shutdown_policy, __RPC_LXC_SHUTDOWN_MAX, tb, blob_data(msg), blob_len(msg));
  152. l = rpc_lxc_init(tb);
  153. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  154. if (!l->container->is_running(l->container)) {
  155. rc = UBUS_STATUS_UNKNOWN_ERROR;
  156. goto out;
  157. }
  158. /* define default timeout */
  159. int timeout = 30;
  160. if (tb[RPC_LXC_SHUTDOWN_TIMEOUT]) {
  161. timeout = blobmsg_get_u32(tb[RPC_LXC_SHUTDOWN_TIMEOUT]);
  162. }
  163. if (!l->container->shutdown(l->container, timeout)) {
  164. rc = UBUS_STATUS_UNKNOWN_ERROR;
  165. goto out;
  166. }
  167. rc = UBUS_STATUS_OK;
  168. out:
  169. rpc_lxc_done(l);
  170. return rc;
  171. }
  172. static int
  173. rpc_lxc_stop(struct ubus_context *ctx, struct ubus_object *obj,
  174. struct ubus_request_data *req, const char *method,
  175. struct blob_attr *msg)
  176. {
  177. struct blob_attr *tb[__RPC_LXC_MAX];
  178. struct rpc_lxc *l = NULL;
  179. int rc;
  180. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  181. l = rpc_lxc_init(tb);
  182. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  183. if (!l->container->is_running(l->container)) {
  184. rc = UBUS_STATUS_UNKNOWN_ERROR;
  185. goto out;
  186. }
  187. if (!l->container->stop(l->container)) {
  188. rc = UBUS_STATUS_INVALID_ARGUMENT;
  189. goto out;
  190. }
  191. rc = UBUS_STATUS_OK;
  192. out:
  193. rpc_lxc_done(l);
  194. return rc;
  195. }
  196. static int
  197. rpc_lxc_freeze(struct ubus_context *ctx, struct ubus_object *obj,
  198. struct ubus_request_data *req, const char *method,
  199. struct blob_attr *msg)
  200. {
  201. struct blob_attr *tb[__RPC_LXC_MAX];
  202. struct rpc_lxc *l = NULL;
  203. int rc;
  204. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  205. l = rpc_lxc_init(tb);
  206. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  207. if (!l->container->is_running(l->container)) {
  208. rc = UBUS_STATUS_UNKNOWN_ERROR;
  209. goto out;
  210. }
  211. if (!l->container->freeze(l->container)) {
  212. rc = UBUS_STATUS_INVALID_ARGUMENT;
  213. goto out;
  214. }
  215. rc = UBUS_STATUS_OK;
  216. out:
  217. rpc_lxc_done(l);
  218. return rc;
  219. }
  220. static int
  221. rpc_lxc_unfreeze(struct ubus_context *ctx, struct ubus_object *obj,
  222. struct ubus_request_data *req, const char *method,
  223. struct blob_attr *msg)
  224. {
  225. struct blob_attr *tb[__RPC_LXC_MAX];
  226. struct rpc_lxc *l = NULL;
  227. int rc;
  228. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  229. l = rpc_lxc_init(tb);
  230. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  231. if (!l->container->is_running(l->container)) {
  232. rc = UBUS_STATUS_UNKNOWN_ERROR;
  233. goto out;
  234. }
  235. if (!l->container->unfreeze(l->container)) {
  236. rc = UBUS_STATUS_INVALID_ARGUMENT;
  237. goto out;
  238. }
  239. rc = UBUS_STATUS_OK;
  240. out:
  241. rpc_lxc_done(l);
  242. return rc;
  243. }
  244. static int
  245. rpc_lxc_rename(struct ubus_context *ctx, struct ubus_object *obj,
  246. struct ubus_request_data *req, const char *method,
  247. struct blob_attr *msg)
  248. {
  249. struct blob_attr *tb[__RPC_LXC_RENAME_MAX];
  250. struct rpc_lxc *l = NULL;
  251. int rc;
  252. blobmsg_parse(rpc_lxc_rename_policy, __RPC_LXC_RENAME_MAX, tb, blob_data(msg), blob_len(msg));
  253. l = rpc_lxc_init(tb);
  254. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  255. if (!tb[RPC_LXC_RENAME_NEWNAME]) {
  256. rc = UBUS_STATUS_INVALID_ARGUMENT;
  257. goto out;
  258. }
  259. if (l->container->is_running(l->container)) {
  260. rc = UBUS_STATUS_UNKNOWN_ERROR;
  261. goto out;
  262. }
  263. char *newname = blobmsg_data(tb[RPC_LXC_RENAME_NEWNAME]);
  264. if (!newname || !l->container->rename(l->container, newname)) {
  265. rc = UBUS_STATUS_INVALID_ARGUMENT;
  266. goto out;
  267. }
  268. rc = UBUS_STATUS_OK;
  269. out:
  270. rpc_lxc_done(l);
  271. return rc;
  272. }
  273. static int
  274. rpc_lxc_destroy(struct ubus_context *ctx, struct ubus_object *obj,
  275. struct ubus_request_data *req, const char *method,
  276. struct blob_attr *msg)
  277. {
  278. struct blob_attr *tb[__RPC_LXC_MAX];
  279. struct rpc_lxc *l = NULL;
  280. int rc;
  281. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  282. l = rpc_lxc_init(tb);
  283. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  284. if (l->container->is_running(l->container)) {
  285. rc = UBUS_STATUS_UNKNOWN_ERROR;
  286. goto out;
  287. }
  288. if (!l->container->destroy(l->container)) {
  289. rc = UBUS_STATUS_INVALID_ARGUMENT;
  290. goto out;
  291. }
  292. rc = UBUS_STATUS_OK;
  293. out:
  294. rpc_lxc_done(l);
  295. return rc;
  296. }
  297. static int
  298. rpc_lxc_list(struct ubus_context *ctx, struct ubus_object *obj,
  299. struct ubus_request_data *req, const char *method,
  300. struct blob_attr *msg)
  301. {
  302. blob_buf_init(&buf, 0);
  303. int rc;
  304. char **names;
  305. struct lxc_container **cret;
  306. rc = list_all_containers(NULL, &names, &cret);
  307. if (rc == -1)
  308. return UBUS_STATUS_UNKNOWN_ERROR;
  309. for (int i = 0; i < rc; i++) {
  310. struct lxc_container *c = cret[i];
  311. blobmsg_add_string(&buf, names[i], c->state(c));
  312. free(names[i]);
  313. lxc_container_put(c);
  314. }
  315. ubus_send_reply(ctx, req, buf.head);
  316. return UBUS_STATUS_OK;
  317. }
  318. static int
  319. rpc_lxc_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
  320. {
  321. static const struct ubus_method lxc_methods[] = {
  322. UBUS_METHOD("start", rpc_lxc_start, rpc_lxc_min_policy),
  323. UBUS_METHOD("reboot", rpc_lxc_reboot, rpc_lxc_min_policy),
  324. UBUS_METHOD("shutdown", rpc_lxc_shutdown, rpc_lxc_shutdown_policy),
  325. UBUS_METHOD("stop", rpc_lxc_stop, rpc_lxc_min_policy),
  326. UBUS_METHOD("freeze", rpc_lxc_freeze, rpc_lxc_min_policy),
  327. UBUS_METHOD("unfreeze", rpc_lxc_unfreeze, rpc_lxc_min_policy),
  328. UBUS_METHOD("rename", rpc_lxc_rename, rpc_lxc_rename_policy),
  329. UBUS_METHOD("destroy", rpc_lxc_destroy, rpc_lxc_min_policy),
  330. UBUS_METHOD_NOARG("list", rpc_lxc_list),
  331. };
  332. static struct ubus_object_type lxc_type =
  333. UBUS_OBJECT_TYPE("luci-rpc-lxc", lxc_methods);
  334. static struct ubus_object obj = {
  335. .name = "lxc",
  336. .type = &lxc_type,
  337. .methods = lxc_methods,
  338. .n_methods = ARRAY_SIZE(lxc_methods),
  339. };
  340. return ubus_add_object(ctx, &obj);
  341. }
  342. struct rpc_plugin rpc_plugin = {
  343. .init = rpc_lxc_api_init
  344. };