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 };