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.

547 lines
13 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_info(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. char **addresses;
  267. void *k;
  268. pid_t initpid;
  269. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  270. l = rpc_lxc_init(tb);
  271. if (!l)
  272. return UBUS_STATUS_INVALID_ARGUMENT;
  273. blob_buf_init(&buf, 0);
  274. blobmsg_add_string(&buf, "name", l->container->name);
  275. blobmsg_add_string(&buf, "state", l->container->state(l->container));
  276. initpid = l->container->init_pid(l->container);
  277. if (initpid >= 0)
  278. blobmsg_add_u32(&buf, "pid", initpid);
  279. k = blobmsg_open_array(&buf, "ips");
  280. addresses = l->container->get_ips(l->container, NULL, NULL, 0);
  281. if (addresses) {
  282. int i;
  283. for (i = 0; addresses[i]; i++)
  284. blobmsg_add_string(&buf, "ip", addresses[i]);
  285. }
  286. blobmsg_close_array(&buf, k);
  287. ubus_send_reply(ctx, req, buf.head);
  288. rpc_lxc_done(l);
  289. return UBUS_STATUS_OK;
  290. }
  291. static int
  292. rpc_lxc_rename(struct ubus_context *ctx, struct ubus_object *obj,
  293. struct ubus_request_data *req, const char *method,
  294. struct blob_attr *msg)
  295. {
  296. struct blob_attr *tb[__RPC_LXC_RENAME_MAX];
  297. struct rpc_lxc *l = NULL;
  298. int rc;
  299. blobmsg_parse(rpc_lxc_rename_policy, __RPC_LXC_RENAME_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_RENAME_NEWNAME]) {
  303. rc = UBUS_STATUS_INVALID_ARGUMENT;
  304. goto out;
  305. }
  306. if (l->container->is_running(l->container)) {
  307. rc = UBUS_STATUS_UNKNOWN_ERROR;
  308. goto out;
  309. }
  310. char *newname = blobmsg_data(tb[RPC_LXC_RENAME_NEWNAME]);
  311. if (!newname || !l->container->rename(l->container, newname)) {
  312. rc = UBUS_STATUS_INVALID_ARGUMENT;
  313. goto out;
  314. }
  315. rc = UBUS_STATUS_OK;
  316. out:
  317. rpc_lxc_done(l);
  318. return rc;
  319. }
  320. static int
  321. rpc_lxc_create(struct ubus_context *ctx, struct ubus_object *obj,
  322. struct ubus_request_data *req, const char *method,
  323. struct blob_attr *msg)
  324. {
  325. struct blob_attr *tb[__RPC_LXC_CREATE_MAX];
  326. struct rpc_lxc *l = NULL;
  327. int rc;
  328. char *template = "none";
  329. int flags = 0;
  330. char **args = NULL;
  331. blobmsg_parse(rpc_lxc_create_policy, __RPC_LXC_CREATE_MAX, tb, blob_data(msg), blob_len(msg));
  332. l = rpc_lxc_init(tb);
  333. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  334. if (tb[RPC_LXC_CREATE_TEMPLATE])
  335. template = blobmsg_data(tb[RPC_LXC_CREATE_TEMPLATE]);
  336. if (tb[RPC_LXC_CREATE_FLAGS])
  337. flags = blobmsg_get_u32(tb[RPC_LXC_CREATE_FLAGS]);
  338. if (tb[RPC_LXC_CREATE_ARGS]) {
  339. struct blob_attr *cur;
  340. int num, rem;
  341. num = blobmsg_check_array(tb[RPC_LXC_CREATE_ARGS], BLOBMSG_TYPE_STRING);
  342. // trailing NULL is needed
  343. args = calloc(num + 1, sizeof(char *));
  344. if (!args) {
  345. rc = UBUS_STATUS_UNKNOWN_ERROR;
  346. goto out;
  347. }
  348. num = 0;
  349. blobmsg_for_each_attr(cur, tb[RPC_LXC_CREATE_ARGS], rem)
  350. {
  351. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
  352. continue;
  353. args[num++] = (char *) blobmsg_data(cur);
  354. }
  355. }
  356. if (!l->container->create(l->container, template, NULL, NULL, flags, args)) {
  357. rc = UBUS_STATUS_INVALID_ARGUMENT;
  358. goto out;
  359. }
  360. rc = UBUS_STATUS_OK;
  361. out:
  362. rpc_lxc_done(l);
  363. free(args);
  364. return rc;
  365. }
  366. static int
  367. rpc_lxc_destroy(struct ubus_context *ctx, struct ubus_object *obj,
  368. struct ubus_request_data *req, const char *method,
  369. struct blob_attr *msg)
  370. {
  371. struct blob_attr *tb[__RPC_LXC_MAX];
  372. struct rpc_lxc *l = NULL;
  373. int rc;
  374. blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
  375. l = rpc_lxc_init(tb);
  376. if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
  377. if (l->container->is_running(l->container)) {
  378. rc = UBUS_STATUS_UNKNOWN_ERROR;
  379. goto out;
  380. }
  381. if (!l->container->destroy(l->container)) {
  382. rc = UBUS_STATUS_INVALID_ARGUMENT;
  383. goto out;
  384. }
  385. rc = UBUS_STATUS_OK;
  386. out:
  387. rpc_lxc_done(l);
  388. return rc;
  389. }
  390. static int
  391. rpc_lxc_list(struct ubus_context *ctx, struct ubus_object *obj,
  392. struct ubus_request_data *req, const char *method,
  393. struct blob_attr *msg)
  394. {
  395. blob_buf_init(&buf, 0);
  396. int rc;
  397. char **names;
  398. struct lxc_container **cret;
  399. rc = list_all_containers(NULL, &names, &cret);
  400. if (rc == -1)
  401. return UBUS_STATUS_UNKNOWN_ERROR;
  402. for (int i = 0; i < rc; i++) {
  403. struct lxc_container *c = cret[i];
  404. blobmsg_add_string(&buf, names[i], c->state(c));
  405. free(names[i]);
  406. lxc_container_put(c);
  407. }
  408. ubus_send_reply(ctx, req, buf.head);
  409. return UBUS_STATUS_OK;
  410. }
  411. static int
  412. rpc_lxc_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
  413. {
  414. static const struct ubus_method lxc_methods[] = {
  415. UBUS_METHOD("start", rpc_lxc_start, rpc_lxc_min_policy),
  416. UBUS_METHOD("reboot", rpc_lxc_reboot, rpc_lxc_min_policy),
  417. UBUS_METHOD("shutdown", rpc_lxc_shutdown, rpc_lxc_shutdown_policy),
  418. UBUS_METHOD("stop", rpc_lxc_stop, rpc_lxc_min_policy),
  419. UBUS_METHOD("freeze", rpc_lxc_freeze, rpc_lxc_min_policy),
  420. UBUS_METHOD("unfreeze", rpc_lxc_unfreeze, rpc_lxc_min_policy),
  421. UBUS_METHOD("info", rpc_lxc_info, rpc_lxc_min_policy),
  422. UBUS_METHOD("rename", rpc_lxc_rename, rpc_lxc_rename_policy),
  423. UBUS_METHOD("create", rpc_lxc_create, rpc_lxc_create_policy),
  424. UBUS_METHOD("destroy", rpc_lxc_destroy, rpc_lxc_min_policy),
  425. UBUS_METHOD_NOARG("list", rpc_lxc_list),
  426. };
  427. static struct ubus_object_type lxc_type =
  428. UBUS_OBJECT_TYPE("luci-rpc-lxc", lxc_methods);
  429. static struct ubus_object obj = {
  430. .name = "lxc",
  431. .type = &lxc_type,
  432. .methods = lxc_methods,
  433. .n_methods = ARRAY_SIZE(lxc_methods),
  434. };
  435. return ubus_add_object(ctx, &obj);
  436. }
  437. struct rpc_plugin rpc_plugin = {
  438. .init = rpc_lxc_api_init
  439. };