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.

504 lines
12 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. enum {
  48. RPC_LXC_CREATE_NAME,
  49. RPC_LXC_CREATE_CONFIG,
  50. RPC_LXC_CREATE_TEMPLATE,
  51. RPC_LXC_CREATE_FLAGS,
  52. RPC_LXC_CREATE_ARGS,
  53. __RPC_LXC_CREATE_MAX,
  54. };
  55. static const struct blobmsg_policy rpc_lxc_min_policy[__RPC_LXC_MAX] = {
  56. [RPC_LXC_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  57. [RPC_LXC_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
  58. };
  59. static const struct blobmsg_policy rpc_lxc_shutdown_policy[__RPC_LXC_SHUTDOWN_MAX] = {
  60. [RPC_LXC_SHUTDOWN_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  61. [RPC_LXC_SHUTDOWN_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
  62. [RPC_LXC_SHUTDOWN_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
  63. };
  64. static const struct blobmsg_policy rpc_lxc_rename_policy[__RPC_LXC_RENAME_MAX] = {
  65. [RPC_LXC_RENAME_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  66. [RPC_LXC_RENAME_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
  67. [RPC_LXC_RENAME_NEWNAME] = { .name = "newname", .type = BLOBMSG_TYPE_STRING },
  68. };
  69. static const struct blobmsg_policy rpc_lxc_create_policy[__RPC_LXC_CREATE_MAX] = {
  70. [RPC_LXC_CREATE_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  71. [RPC_LXC_CREATE_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
  72. [RPC_LXC_CREATE_TEMPLATE] = { .name = "template", .type = BLOBMSG_TYPE_STRING },
  73. [RPC_LXC_CREATE_FLAGS] = { .name = "flags", .type = BLOBMSG_TYPE_INT32 },
  74. [RPC_LXC_CREATE_ARGS] = { .name = "args", .type = BLOBMSG_TYPE_ARRAY },
  75. };
  76. static struct rpc_lxc *
  77. rpc_lxc_init(struct blob_attr *tb[__RPC_LXC_MAX])
  78. {
  79. struct rpc_lxc *l = NULL;
  80. l = calloc(1, sizeof(struct rpc_lxc));
  81. if (!l) return NULL;
  82. if (tb[RPC_LXC_NAME]) {
  83. l->name = blobmsg_data(tb[RPC_LXC_NAME]);
  84. } else {
  85. goto error;
  86. }
  87. if (tb[RPC_LXC_CONFIG]) {
  88. l->config = blobmsg_data(tb[RPC_LXC_CONFIG]);
  89. } else {
  90. l->config = NULL;
  91. }
  92. l->container = lxc_container_new(l->name, l->config);
  93. if (!l->container) {
  94. goto error;
  95. }
  96. return l;
  97. error:
  98. free(l);
  99. return NULL;
  100. }
  101. static void
  102. rpc_lxc_done(struct rpc_lxc *l)
  103. {
  104. if (l) {
  105. lxc_container_put(l->container);
  106. free(l);
  107. }
  108. return;
  109. }
  110. static int
  111. rpc_lxc_start(struct ubus_context *ctx, struct ubus_object *obj,
  112. struct ubus_request_data *req, const char *method,
  113. struct blob_attr *msg)
  114. {
  115. struct blob_attr *tb[__RPC_LXC_MAX];
  116. struct rpc_lxc *l = NULL;
  117. int rc;
  118. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  119. l = rpc_lxc_init(tb);
  120. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  121. if (l->container->is_running(l->container)) {
  122. rc = UBUS_STATUS_UNKNOWN_ERROR;
  123. goto out;
  124. }
  125. if (!l->container->start(l->container, 0, NULL)) {
  126. rc = UBUS_STATUS_INVALID_ARGUMENT;
  127. goto out;
  128. }
  129. rc = UBUS_STATUS_OK;
  130. out:
  131. rpc_lxc_done(l);
  132. return rc;
  133. }
  134. static int
  135. rpc_lxc_reboot(struct ubus_context *ctx, struct ubus_object *obj,
  136. struct ubus_request_data *req, const char *method,
  137. struct blob_attr *msg)
  138. {
  139. struct blob_attr *tb[__RPC_LXC_MAX];
  140. struct rpc_lxc *l = NULL;
  141. int rc;
  142. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  143. l = rpc_lxc_init(tb);
  144. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  145. if (!l->container->is_running(l->container)) {
  146. rc = UBUS_STATUS_UNKNOWN_ERROR;
  147. goto out;
  148. }
  149. if (!l->container->reboot(l->container)) {
  150. rc = UBUS_STATUS_INVALID_ARGUMENT;
  151. goto out;
  152. }
  153. rc = UBUS_STATUS_OK;
  154. out:
  155. rpc_lxc_done(l);
  156. return rc;
  157. }
  158. static int
  159. rpc_lxc_shutdown(struct ubus_context *ctx, struct ubus_object *obj,
  160. struct ubus_request_data *req, const char *method,
  161. struct blob_attr *msg)
  162. {
  163. struct blob_attr *tb[__RPC_LXC_SHUTDOWN_MAX];
  164. struct rpc_lxc *l = NULL;
  165. int rc;
  166. blobmsg_parse(rpc_lxc_shutdown_policy, __RPC_LXC_SHUTDOWN_MAX, tb, blob_data(msg), blob_len(msg));
  167. l = rpc_lxc_init(tb);
  168. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  169. if (!l->container->is_running(l->container)) {
  170. rc = UBUS_STATUS_UNKNOWN_ERROR;
  171. goto out;
  172. }
  173. /* define default timeout */
  174. int timeout = 30;
  175. if (tb[RPC_LXC_SHUTDOWN_TIMEOUT]) {
  176. timeout = blobmsg_get_u32(tb[RPC_LXC_SHUTDOWN_TIMEOUT]);
  177. }
  178. if (!l->container->shutdown(l->container, timeout)) {
  179. rc = UBUS_STATUS_UNKNOWN_ERROR;
  180. goto out;
  181. }
  182. rc = UBUS_STATUS_OK;
  183. out:
  184. rpc_lxc_done(l);
  185. return rc;
  186. }
  187. static int
  188. rpc_lxc_stop(struct ubus_context *ctx, struct ubus_object *obj,
  189. struct ubus_request_data *req, const char *method,
  190. struct blob_attr *msg)
  191. {
  192. struct blob_attr *tb[__RPC_LXC_MAX];
  193. struct rpc_lxc *l = NULL;
  194. int rc;
  195. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  196. l = rpc_lxc_init(tb);
  197. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  198. if (!l->container->is_running(l->container)) {
  199. rc = UBUS_STATUS_UNKNOWN_ERROR;
  200. goto out;
  201. }
  202. if (!l->container->stop(l->container)) {
  203. rc = UBUS_STATUS_INVALID_ARGUMENT;
  204. goto out;
  205. }
  206. rc = UBUS_STATUS_OK;
  207. out:
  208. rpc_lxc_done(l);
  209. return rc;
  210. }
  211. static int
  212. rpc_lxc_freeze(struct ubus_context *ctx, struct ubus_object *obj,
  213. struct ubus_request_data *req, const char *method,
  214. struct blob_attr *msg)
  215. {
  216. struct blob_attr *tb[__RPC_LXC_MAX];
  217. struct rpc_lxc *l = NULL;
  218. int rc;
  219. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  220. l = rpc_lxc_init(tb);
  221. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  222. if (!l->container->is_running(l->container)) {
  223. rc = UBUS_STATUS_UNKNOWN_ERROR;
  224. goto out;
  225. }
  226. if (!l->container->freeze(l->container)) {
  227. rc = UBUS_STATUS_INVALID_ARGUMENT;
  228. goto out;
  229. }
  230. rc = UBUS_STATUS_OK;
  231. out:
  232. rpc_lxc_done(l);
  233. return rc;
  234. }
  235. static int
  236. rpc_lxc_unfreeze(struct ubus_context *ctx, struct ubus_object *obj,
  237. struct ubus_request_data *req, const char *method,
  238. struct blob_attr *msg)
  239. {
  240. struct blob_attr *tb[__RPC_LXC_MAX];
  241. struct rpc_lxc *l = NULL;
  242. int rc;
  243. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  244. l = rpc_lxc_init(tb);
  245. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  246. if (!l->container->is_running(l->container)) {
  247. rc = UBUS_STATUS_UNKNOWN_ERROR;
  248. goto out;
  249. }
  250. if (!l->container->unfreeze(l->container)) {
  251. rc = UBUS_STATUS_INVALID_ARGUMENT;
  252. goto out;
  253. }
  254. rc = UBUS_STATUS_OK;
  255. out:
  256. rpc_lxc_done(l);
  257. return rc;
  258. }
  259. static int
  260. rpc_lxc_rename(struct ubus_context *ctx, struct ubus_object *obj,
  261. struct ubus_request_data *req, const char *method,
  262. struct blob_attr *msg)
  263. {
  264. struct blob_attr *tb[__RPC_LXC_RENAME_MAX];
  265. struct rpc_lxc *l = NULL;
  266. int rc;
  267. blobmsg_parse(rpc_lxc_rename_policy, __RPC_LXC_RENAME_MAX, tb, blob_data(msg), blob_len(msg));
  268. l = rpc_lxc_init(tb);
  269. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  270. if (!tb[RPC_LXC_RENAME_NEWNAME]) {
  271. rc = UBUS_STATUS_INVALID_ARGUMENT;
  272. goto out;
  273. }
  274. if (l->container->is_running(l->container)) {
  275. rc = UBUS_STATUS_UNKNOWN_ERROR;
  276. goto out;
  277. }
  278. char *newname = blobmsg_data(tb[RPC_LXC_RENAME_NEWNAME]);
  279. if (!newname || !l->container->rename(l->container, newname)) {
  280. rc = UBUS_STATUS_INVALID_ARGUMENT;
  281. goto out;
  282. }
  283. rc = UBUS_STATUS_OK;
  284. out:
  285. rpc_lxc_done(l);
  286. return rc;
  287. }
  288. static int
  289. rpc_lxc_create(struct ubus_context *ctx, struct ubus_object *obj,
  290. struct ubus_request_data *req, const char *method,
  291. struct blob_attr *msg)
  292. {
  293. struct blob_attr *tb[__RPC_LXC_CREATE_MAX];
  294. struct rpc_lxc *l = NULL;
  295. int rc;
  296. char *template = "none";
  297. int flags = 0;
  298. char **args = NULL;
  299. blobmsg_parse(rpc_lxc_create_policy, __RPC_LXC_CREATE_MAX, tb, blob_data(msg), blob_len(msg));
  300. l = rpc_lxc_init(tb);
  301. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  302. if (tb[RPC_LXC_CREATE_TEMPLATE])
  303. template = blobmsg_data(tb[RPC_LXC_CREATE_TEMPLATE]);
  304. if (tb[RPC_LXC_CREATE_FLAGS])
  305. flags = blobmsg_get_u32(tb[RPC_LXC_CREATE_FLAGS]);
  306. if (tb[RPC_LXC_CREATE_ARGS]) {
  307. struct blob_attr *cur;
  308. int num, rem;
  309. num = blobmsg_check_array(tb[RPC_LXC_CREATE_ARGS], BLOBMSG_TYPE_STRING);
  310. // trailing NULL is needed
  311. args = calloc(num + 1, sizeof(char *));
  312. if (!args) {
  313. rc = UBUS_STATUS_UNKNOWN_ERROR;
  314. goto out;
  315. }
  316. num = 0;
  317. blobmsg_for_each_attr(cur, tb[RPC_LXC_CREATE_ARGS], rem)
  318. {
  319. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
  320. continue;
  321. args[num++] = (char *) blobmsg_data(cur);
  322. }
  323. }
  324. if (!l->container->create(l->container, template, NULL, NULL, flags, args)) {
  325. rc = UBUS_STATUS_INVALID_ARGUMENT;
  326. goto out;
  327. }
  328. rc = UBUS_STATUS_OK;
  329. out:
  330. rpc_lxc_done(l);
  331. free(args);
  332. return rc;
  333. }
  334. static int
  335. rpc_lxc_destroy(struct ubus_context *ctx, struct ubus_object *obj,
  336. struct ubus_request_data *req, const char *method,
  337. struct blob_attr *msg)
  338. {
  339. struct blob_attr *tb[__RPC_LXC_MAX];
  340. struct rpc_lxc *l = NULL;
  341. int rc;
  342. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  343. l = rpc_lxc_init(tb);
  344. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  345. if (l->container->is_running(l->container)) {
  346. rc = UBUS_STATUS_UNKNOWN_ERROR;
  347. goto out;
  348. }
  349. if (!l->container->destroy(l->container)) {
  350. rc = UBUS_STATUS_INVALID_ARGUMENT;
  351. goto out;
  352. }
  353. rc = UBUS_STATUS_OK;
  354. out:
  355. rpc_lxc_done(l);
  356. return rc;
  357. }
  358. static int
  359. rpc_lxc_list(struct ubus_context *ctx, struct ubus_object *obj,
  360. struct ubus_request_data *req, const char *method,
  361. struct blob_attr *msg)
  362. {
  363. blob_buf_init(&buf, 0);
  364. int rc;
  365. char **names;
  366. struct lxc_container **cret;
  367. rc = list_all_containers(NULL, &names, &cret);
  368. if (rc == -1)
  369. return UBUS_STATUS_UNKNOWN_ERROR;
  370. for (int i = 0; i < rc; i++) {
  371. struct lxc_container *c = cret[i];
  372. blobmsg_add_string(&buf, names[i], c->state(c));
  373. free(names[i]);
  374. lxc_container_put(c);
  375. }
  376. ubus_send_reply(ctx, req, buf.head);
  377. return UBUS_STATUS_OK;
  378. }
  379. static int
  380. rpc_lxc_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
  381. {
  382. static const struct ubus_method lxc_methods[] = {
  383. UBUS_METHOD("start", rpc_lxc_start, rpc_lxc_min_policy),
  384. UBUS_METHOD("reboot", rpc_lxc_reboot, rpc_lxc_min_policy),
  385. UBUS_METHOD("shutdown", rpc_lxc_shutdown, rpc_lxc_shutdown_policy),
  386. UBUS_METHOD("stop", rpc_lxc_stop, rpc_lxc_min_policy),
  387. UBUS_METHOD("freeze", rpc_lxc_freeze, rpc_lxc_min_policy),
  388. UBUS_METHOD("unfreeze", rpc_lxc_unfreeze, rpc_lxc_min_policy),
  389. UBUS_METHOD("rename", rpc_lxc_rename, rpc_lxc_rename_policy),
  390. UBUS_METHOD("create", rpc_lxc_create, rpc_lxc_create_policy),
  391. UBUS_METHOD("destroy", rpc_lxc_destroy, rpc_lxc_min_policy),
  392. UBUS_METHOD_NOARG("list", rpc_lxc_list),
  393. };
  394. static struct ubus_object_type lxc_type =
  395. UBUS_OBJECT_TYPE("luci-rpc-lxc", lxc_methods);
  396. static struct ubus_object obj = {
  397. .name = "lxc",
  398. .type = &lxc_type,
  399. .methods = lxc_methods,
  400. .n_methods = ARRAY_SIZE(lxc_methods),
  401. };
  402. return ubus_add_object(ctx, &obj);
  403. }
  404. struct rpc_plugin rpc_plugin = {
  405. .init = rpc_lxc_api_init
  406. };