lede-packages-rs

git clone git://archive.git.mtrnord.blog/MTRNord/lede-packages-rs.git
Log | Files | Refs | README | LICENSE

lxc.c (11985B)


      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 
     20 #include <libubus.h>
     21 
     22 #include <lxc/lxccontainer.h>
     23 
     24 #include <rpcd/plugin.h>
     25 
     26 static struct blob_buf buf;
     27 
     28 struct rpc_lxc {
     29 	/* ubus options */
     30 	char *name;
     31 	char *config;
     32 	/* lxc container */
     33 	struct lxc_container *container;
     34 };
     35 
     36 enum {
     37 	RPC_LXC_NAME,
     38 	RPC_LXC_CONFIG,
     39 	__RPC_LXC_MAX,
     40 };
     41 
     42 enum {
     43 	RPC_LXC_SHUTDOWN_NAME,
     44 	RPC_LXC_SHUTDOWN_CONFIG,
     45 	RPC_LXC_SHUTDOWN_TIMEOUT,
     46 	__RPC_LXC_SHUTDOWN_MAX,
     47 };
     48 
     49 enum {
     50 	RPC_LXC_RENAME_NAME,
     51 	RPC_LXC_RENAME_CONFIG,
     52 	RPC_LXC_RENAME_NEWNAME,
     53 	__RPC_LXC_RENAME_MAX,
     54 };
     55 
     56 enum {
     57 	RPC_LXC_CREATE_NAME,
     58 	RPC_LXC_CREATE_CONFIG,
     59 	RPC_LXC_CREATE_TEMPLATE,
     60 	RPC_LXC_CREATE_FLAGS,
     61 	RPC_LXC_CREATE_ARGS,
     62 	__RPC_LXC_CREATE_MAX,
     63 };
     64 
     65 static const struct blobmsg_policy rpc_lxc_min_policy[__RPC_LXC_MAX] = {
     66 	[RPC_LXC_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
     67 	[RPC_LXC_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
     68 };
     69 
     70 static const struct blobmsg_policy rpc_lxc_shutdown_policy[__RPC_LXC_SHUTDOWN_MAX] = {
     71 	[RPC_LXC_SHUTDOWN_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
     72 	[RPC_LXC_SHUTDOWN_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
     73 	[RPC_LXC_SHUTDOWN_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
     74 };
     75 
     76 static const struct blobmsg_policy rpc_lxc_rename_policy[__RPC_LXC_RENAME_MAX] = {
     77 	[RPC_LXC_RENAME_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
     78 	[RPC_LXC_RENAME_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
     79 	[RPC_LXC_RENAME_NEWNAME] = { .name = "newname", .type = BLOBMSG_TYPE_STRING },
     80 };
     81 
     82 static const struct blobmsg_policy rpc_lxc_create_policy[__RPC_LXC_CREATE_MAX] = {
     83 	[RPC_LXC_CREATE_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
     84 	[RPC_LXC_CREATE_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING },
     85 	[RPC_LXC_CREATE_TEMPLATE] = { .name = "template", .type = BLOBMSG_TYPE_STRING },
     86 	[RPC_LXC_CREATE_FLAGS] = { .name = "flags", .type = BLOBMSG_TYPE_INT32 },
     87 	[RPC_LXC_CREATE_ARGS] = { .name = "args", .type = BLOBMSG_TYPE_ARRAY },
     88 };
     89 
     90 static struct rpc_lxc *
     91 rpc_lxc_init(struct blob_attr *tb[__RPC_LXC_MAX])
     92 {
     93 	struct rpc_lxc *l = NULL;
     94 
     95 	l = calloc(1, sizeof(struct rpc_lxc));
     96 	if (!l) return NULL;
     97 
     98 	if (tb[RPC_LXC_NAME]) {
     99 		l->name = blobmsg_data(tb[RPC_LXC_NAME]);
    100 	} else {
    101 		goto error;
    102 	}
    103 
    104 	if (tb[RPC_LXC_CONFIG]) {
    105 		l->config = blobmsg_data(tb[RPC_LXC_CONFIG]);
    106 	} else {
    107 		l->config = NULL;
    108 	}
    109 
    110 	l->container = lxc_container_new(l->name, l->config);
    111 	if (!l->container) {
    112 		goto error;
    113 	}
    114 
    115 	return l;
    116 error:
    117 	free(l);
    118 	return NULL;
    119 }
    120 
    121 static void
    122 rpc_lxc_done(struct rpc_lxc *l)
    123 {
    124 	if (l) {
    125 		lxc_container_put(l->container);
    126 		free(l);
    127 	}
    128 
    129 	return;
    130 }
    131 
    132 static int
    133 rpc_lxc_start(struct ubus_context *ctx, struct ubus_object *obj,
    134 		struct ubus_request_data *req, const char *method,
    135 		struct blob_attr *msg)
    136 {
    137 	struct blob_attr *tb[__RPC_LXC_MAX];
    138 	struct rpc_lxc *l = NULL;
    139 	int rc;
    140 
    141 	blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
    142 
    143 	l = rpc_lxc_init(tb);
    144 	if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
    145 
    146 	if (l->container->is_running(l->container)) {
    147 		rc = UBUS_STATUS_UNKNOWN_ERROR;
    148 		goto out;
    149 	}
    150 
    151 	if (!l->container->start(l->container, 0, NULL)) {
    152 		rc = UBUS_STATUS_INVALID_ARGUMENT;
    153 		goto out;
    154 	}
    155 
    156 	rc = UBUS_STATUS_OK;
    157 out:
    158 	rpc_lxc_done(l);
    159 	return rc;
    160 }
    161 
    162 
    163 static int
    164 rpc_lxc_reboot(struct ubus_context *ctx, struct ubus_object *obj,
    165 		struct ubus_request_data *req, const char *method,
    166 		struct blob_attr *msg)
    167 {
    168 	struct blob_attr *tb[__RPC_LXC_MAX];
    169 	struct rpc_lxc *l = NULL;
    170 	int rc;
    171 
    172 	blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
    173 
    174 	l = rpc_lxc_init(tb);
    175 	if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
    176 
    177 	if (!l->container->is_running(l->container)) {
    178 		rc = UBUS_STATUS_UNKNOWN_ERROR;
    179 		goto out;
    180 	}
    181 
    182 	if (!l->container->reboot(l->container)) {
    183 		rc = UBUS_STATUS_INVALID_ARGUMENT;
    184 		goto out;
    185 	}
    186 
    187 	rc = UBUS_STATUS_OK;
    188 out:
    189 	rpc_lxc_done(l);
    190 	return rc;
    191 }
    192 
    193 static int
    194 rpc_lxc_shutdown(struct ubus_context *ctx, struct ubus_object *obj,
    195 		struct ubus_request_data *req, const char *method,
    196 		struct blob_attr *msg)
    197 {
    198 	struct blob_attr *tb[__RPC_LXC_SHUTDOWN_MAX];
    199 	struct rpc_lxc *l = NULL;
    200 	int rc;
    201 
    202 	blobmsg_parse(rpc_lxc_shutdown_policy, __RPC_LXC_SHUTDOWN_MAX, tb, blob_data(msg), blob_len(msg));
    203 
    204 	l = rpc_lxc_init(tb);
    205 	if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
    206 
    207 	if (!l->container->is_running(l->container)) {
    208 		rc = UBUS_STATUS_UNKNOWN_ERROR;
    209 		goto out;
    210 	}
    211 
    212 	/* define default timeout */
    213 	int timeout = 30;
    214 	if (tb[RPC_LXC_SHUTDOWN_TIMEOUT]) {
    215 		timeout = blobmsg_get_u32(tb[RPC_LXC_SHUTDOWN_TIMEOUT]);
    216 	}
    217 
    218 	if (!l->container->shutdown(l->container, timeout)) {
    219 		rc = UBUS_STATUS_UNKNOWN_ERROR;
    220 		goto out;
    221 	}
    222 
    223 	rc = UBUS_STATUS_OK;
    224 out:
    225 	rpc_lxc_done(l);
    226 	return rc;
    227 }
    228 
    229 static int
    230 rpc_lxc_stop(struct ubus_context *ctx, struct ubus_object *obj,
    231 		struct ubus_request_data *req, const char *method,
    232 		struct blob_attr *msg)
    233 {
    234 	struct blob_attr *tb[__RPC_LXC_MAX];
    235 	struct rpc_lxc *l = NULL;
    236 	int rc;
    237 
    238 	blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
    239 
    240 	l = rpc_lxc_init(tb);
    241 	if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
    242 
    243 	if (!l->container->is_running(l->container)) {
    244 		rc = UBUS_STATUS_UNKNOWN_ERROR;
    245 		goto out;
    246 	}
    247 
    248 	if (!l->container->stop(l->container)) {
    249 		rc = UBUS_STATUS_INVALID_ARGUMENT;
    250 		goto out;
    251 	}
    252 
    253 	rc = UBUS_STATUS_OK;
    254 out:
    255 	rpc_lxc_done(l);
    256 	return rc;
    257 }
    258 
    259 static int
    260 rpc_lxc_freeze(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_MAX];
    265 	struct rpc_lxc *l = NULL;
    266 	int rc;
    267 
    268 	blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
    269 
    270 	l = rpc_lxc_init(tb);
    271 	if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
    272 
    273 	if (!l->container->is_running(l->container)) {
    274 		rc = UBUS_STATUS_UNKNOWN_ERROR;
    275 		goto out;
    276 	}
    277 
    278 	if (!l->container->freeze(l->container)) {
    279 		rc = UBUS_STATUS_INVALID_ARGUMENT;
    280 		goto out;
    281 	}
    282 
    283 	rc = UBUS_STATUS_OK;
    284 out:
    285 	rpc_lxc_done(l);
    286 	return rc;
    287 }
    288 
    289 static int
    290 rpc_lxc_unfreeze(struct ubus_context *ctx, struct ubus_object *obj,
    291 		struct ubus_request_data *req, const char *method,
    292 		struct blob_attr *msg)
    293 {
    294 	struct blob_attr *tb[__RPC_LXC_MAX];
    295 	struct rpc_lxc *l = NULL;
    296 	int rc;
    297 
    298 	blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
    299 
    300 	l = rpc_lxc_init(tb);
    301 	if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
    302 
    303 	if (!l->container->is_running(l->container)) {
    304 		rc = UBUS_STATUS_UNKNOWN_ERROR;
    305 		goto out;
    306 	}
    307 
    308 	if (!l->container->unfreeze(l->container)) {
    309 		rc = UBUS_STATUS_INVALID_ARGUMENT;
    310 		goto out;
    311 	}
    312 
    313 	rc = UBUS_STATUS_OK;
    314 out:
    315 	rpc_lxc_done(l);
    316 	return rc;
    317 }
    318 
    319 static int
    320 rpc_lxc_rename(struct ubus_context *ctx, struct ubus_object *obj,
    321 		struct ubus_request_data *req, const char *method,
    322 		struct blob_attr *msg)
    323 {
    324 	struct blob_attr *tb[__RPC_LXC_RENAME_MAX];
    325 	struct rpc_lxc *l = NULL;
    326 	int rc;
    327 
    328 	blobmsg_parse(rpc_lxc_rename_policy, __RPC_LXC_RENAME_MAX, tb, blob_data(msg), blob_len(msg));
    329 
    330 	l = rpc_lxc_init(tb);
    331 	if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
    332 
    333 	if (!tb[RPC_LXC_RENAME_NEWNAME]) {
    334 		rc = UBUS_STATUS_INVALID_ARGUMENT;
    335 		goto out;
    336 	}
    337 
    338 	if (l->container->is_running(l->container)) {
    339 		rc = UBUS_STATUS_UNKNOWN_ERROR;
    340 		goto out;
    341 	}
    342 
    343 	char *newname = blobmsg_data(tb[RPC_LXC_RENAME_NEWNAME]);
    344 	if (!newname || !l->container->rename(l->container, newname)) {
    345 		rc = UBUS_STATUS_INVALID_ARGUMENT;
    346 		goto out;
    347 	}
    348 
    349 	rc = UBUS_STATUS_OK;
    350 out:
    351 	rpc_lxc_done(l);
    352 	return rc;
    353 }
    354 
    355 static int
    356 rpc_lxc_create(struct ubus_context *ctx, struct ubus_object *obj,
    357 		struct ubus_request_data *req, const char *method,
    358 		struct blob_attr *msg)
    359 {
    360 	struct blob_attr *tb[__RPC_LXC_CREATE_MAX];
    361 	struct rpc_lxc *l = NULL;
    362 	int rc;
    363 
    364 	char *template = "none";
    365 	int flags = 0;
    366 	char **args = NULL;
    367 
    368 	blobmsg_parse(rpc_lxc_create_policy, __RPC_LXC_CREATE_MAX, tb, blob_data(msg), blob_len(msg));
    369 
    370 	l = rpc_lxc_init(tb);
    371 	if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
    372 
    373 	if (tb[RPC_LXC_CREATE_TEMPLATE])
    374 		template = blobmsg_data(tb[RPC_LXC_CREATE_TEMPLATE]);
    375 
    376 	if (tb[RPC_LXC_CREATE_FLAGS])
    377 		flags = blobmsg_get_u32(tb[RPC_LXC_CREATE_FLAGS]);
    378 
    379 	if (tb[RPC_LXC_CREATE_ARGS]) {
    380 		struct blob_attr *cur;
    381 		int num, rem;
    382 
    383 		num = blobmsg_check_array(tb[RPC_LXC_CREATE_ARGS], BLOBMSG_TYPE_STRING);
    384 
    385 		// trailing NULL is needed
    386 		args = calloc(num + 1, sizeof(char *));
    387 		if (!args) {
    388 			rc = UBUS_STATUS_UNKNOWN_ERROR;
    389 			goto out;
    390 		}
    391 
    392 		num = 0;
    393 		blobmsg_for_each_attr(cur, tb[RPC_LXC_CREATE_ARGS], rem)
    394 		{
    395 			if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
    396 				continue;
    397 
    398 			args[num++] = (char *) blobmsg_data(cur);
    399 		}
    400 	}
    401 
    402 	if (!l->container->create(l->container, template, NULL, NULL, flags, args)) {
    403 		rc = UBUS_STATUS_INVALID_ARGUMENT;
    404 		goto out;
    405 	}
    406 
    407 	rc = UBUS_STATUS_OK;
    408 out:
    409 	rpc_lxc_done(l);
    410 	free(args);
    411 	return rc;
    412 }
    413 
    414 static int
    415 rpc_lxc_destroy(struct ubus_context *ctx, struct ubus_object *obj,
    416 		struct ubus_request_data *req, const char *method,
    417 		struct blob_attr *msg)
    418 {
    419 	struct blob_attr *tb[__RPC_LXC_MAX];
    420 	struct rpc_lxc *l = NULL;
    421 	int rc;
    422 
    423 	blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg));
    424 
    425 	l = rpc_lxc_init(tb);
    426 	if (!l) return UBUS_STATUS_INVALID_ARGUMENT;
    427 
    428 	if (l->container->is_running(l->container)) {
    429 		rc = UBUS_STATUS_UNKNOWN_ERROR;
    430 		goto out;
    431 	}
    432 
    433 	if (!l->container->destroy(l->container)) {
    434 		rc = UBUS_STATUS_INVALID_ARGUMENT;
    435 		goto out;
    436 	}
    437 
    438 	rc = UBUS_STATUS_OK;
    439 out:
    440 	rpc_lxc_done(l);
    441 	return rc;
    442 }
    443 
    444 static int
    445 rpc_lxc_list(struct ubus_context *ctx, struct ubus_object *obj,
    446 		struct ubus_request_data *req, const char *method,
    447 		struct blob_attr *msg)
    448 {
    449 
    450 	blob_buf_init(&buf, 0);
    451 
    452 	int rc;
    453 	char **names;
    454 	struct lxc_container **cret;
    455 
    456 	rc = list_all_containers(NULL, &names, &cret);
    457 	if (rc == -1)
    458 		return UBUS_STATUS_UNKNOWN_ERROR;
    459 
    460 	for (int i = 0; i < rc; i++) {
    461 		struct lxc_container *c = cret[i];
    462 		blobmsg_add_string(&buf, names[i], c->state(c));
    463 
    464 		free(names[i]);
    465 		lxc_container_put(c);
    466 	}
    467 
    468 	ubus_send_reply(ctx, req, buf.head);
    469 
    470 	return UBUS_STATUS_OK;
    471 }
    472 
    473 static int
    474 rpc_lxc_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
    475 {
    476 	static const struct ubus_method lxc_methods[] = {
    477 		UBUS_METHOD("start", rpc_lxc_start, rpc_lxc_min_policy),
    478 		UBUS_METHOD("reboot", rpc_lxc_reboot, rpc_lxc_min_policy),
    479 		UBUS_METHOD("shutdown", rpc_lxc_shutdown, rpc_lxc_shutdown_policy),
    480 		UBUS_METHOD("stop", rpc_lxc_stop, rpc_lxc_min_policy),
    481 		UBUS_METHOD("freeze", rpc_lxc_freeze, rpc_lxc_min_policy),
    482 		UBUS_METHOD("unfreeze", rpc_lxc_unfreeze, rpc_lxc_min_policy),
    483 		UBUS_METHOD("rename", rpc_lxc_rename, rpc_lxc_rename_policy),
    484 		UBUS_METHOD("create", rpc_lxc_create, rpc_lxc_create_policy),
    485 		UBUS_METHOD("destroy", rpc_lxc_destroy, rpc_lxc_min_policy),
    486 		UBUS_METHOD_NOARG("list", rpc_lxc_list),
    487 	};
    488 
    489 	static struct ubus_object_type lxc_type =
    490 		UBUS_OBJECT_TYPE("luci-rpc-lxc", lxc_methods);
    491 
    492 	static struct ubus_object obj = {
    493 		.name = "lxc",
    494 		.type = &lxc_type,
    495 		.methods = lxc_methods,
    496 		.n_methods = ARRAY_SIZE(lxc_methods),
    497 	};
    498 
    499 	return ubus_add_object(ctx, &obj);
    500 }
    501 
    502 struct rpc_plugin rpc_plugin = {
    503 	.init = rpc_lxc_api_init
    504 };