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.

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