From 153e482090bcdf22facb9a868991057d2a61d775 Mon Sep 17 00:00:00 2001 From: Luka Perkov Date: Fri, 10 Oct 2014 15:44:49 +0200 Subject: [PATCH] rpcd-mod-lxc: add package for rpcd lxc module Signed-off-by: Luka Perkov --- utils/rpcd-mod-lxc/Makefile | 35 ++ utils/rpcd-mod-lxc/files/CMakeLists.txt | 19 ++ utils/rpcd-mod-lxc/files/lxc.c | 427 ++++++++++++++++++++++++ 3 files changed, 481 insertions(+) create mode 100644 utils/rpcd-mod-lxc/Makefile create mode 100644 utils/rpcd-mod-lxc/files/CMakeLists.txt create mode 100644 utils/rpcd-mod-lxc/files/lxc.c diff --git a/utils/rpcd-mod-lxc/Makefile b/utils/rpcd-mod-lxc/Makefile new file mode 100644 index 000000000..ccabc39d7 --- /dev/null +++ b/utils/rpcd-mod-lxc/Makefile @@ -0,0 +1,35 @@ +# +# Copyright (C) 2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=rpcd-mod-lxc +PKG_RELEASE=20141012 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +define Package/rpcd-mod-lxc + SECTION:=libs + CATEGORY:=Libraries + TITLE:=LXC rpcd module + DEPENDS:=+rpcd +liblxc + MAINTAINER:=Luka Perkov +endef + +define Build/Prepare + $(CP) ./files/* $(PKG_BUILD_DIR)/ +endef + +define Package/rpcd-mod-lxc/install + $(INSTALL_DIR) $(1)/usr/lib/rpcd + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/lxc.so $(1)/usr/lib/rpcd/ +endef + +$(eval $(call BuildPackage,rpcd-mod-lxc)) diff --git a/utils/rpcd-mod-lxc/files/CMakeLists.txt b/utils/rpcd-mod-lxc/files/CMakeLists.txt new file mode 100644 index 000000000..4a728a0bc --- /dev/null +++ b/utils/rpcd-mod-lxc/files/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 2.6) +PROJECT(rpcd-mod-lxc) +ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -Wmissing-declarations) + +INCLUDE_DIRECTORIES(include) +FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) + +SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) + +SET(SOURCES lxc.c) + +ADD_LIBRARY(rpcd-mod-lxc SHARED ${SOURCES}) + +FIND_LIBRARY(lxc NAMES lxc liblxc) +TARGET_LINK_LIBRARIES(rpcd-mod-lxc ${lxc}) + +SET_TARGET_PROPERTIES(rpcd-mod-lxc PROPERTIES OUTPUT_NAME lxc PREFIX "") +INSTALL(TARGETS rpcd-mod-lxc LIBRARY DESTINATION lib) diff --git a/utils/rpcd-mod-lxc/files/lxc.c b/utils/rpcd-mod-lxc/files/lxc.c new file mode 100644 index 000000000..ae412da30 --- /dev/null +++ b/utils/rpcd-mod-lxc/files/lxc.c @@ -0,0 +1,427 @@ +/* + * rpcd-lxc-plugin + * + * Copyright (C) 2014 Cisco Systems, Inc. + * Author: Luka Perkov + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include + +static struct blob_buf buf; + +struct rpc_lxc { + /* ubus options */ + char *name; + char *config; + /* lxc container */ + struct lxc_container *container; +}; + +enum { + RPC_LXC_NAME, + RPC_LXC_CONFIG, + __RPC_LXC_MAX, +}; + +enum { + RPC_LXC_SHUTDOWN_NAME, + RPC_LXC_SHUTDOWN_CONFIG, + RPC_LXC_SHUTDOWN_TIMEOUT, + __RPC_LXC_SHUTDOWN_MAX, +}; + +enum { + RPC_LXC_RENAME_NAME, + RPC_LXC_RENAME_CONFIG, + RPC_LXC_RENAME_NEWNAME, + __RPC_LXC_RENAME_MAX, +}; + +static const struct blobmsg_policy rpc_lxc_min_policy[__RPC_LXC_MAX] = { + [RPC_LXC_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, + [RPC_LXC_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING }, +}; + +static const struct blobmsg_policy rpc_lxc_shutdown_policy[__RPC_LXC_SHUTDOWN_MAX] = { + [RPC_LXC_SHUTDOWN_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, + [RPC_LXC_SHUTDOWN_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING }, + [RPC_LXC_SHUTDOWN_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 }, +}; + +static const struct blobmsg_policy rpc_lxc_rename_policy[__RPC_LXC_RENAME_MAX] = { + [RPC_LXC_RENAME_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, + [RPC_LXC_RENAME_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING }, + [RPC_LXC_RENAME_NEWNAME] = { .name = "newname", .type = BLOBMSG_TYPE_STRING }, +}; + +static struct rpc_lxc * +rpc_lxc_init(struct blob_attr *tb[__RPC_LXC_MAX]) +{ + struct rpc_lxc *l = NULL; + + l = calloc(1, sizeof(struct rpc_lxc)); + if (!l) return NULL; + + if (tb[RPC_LXC_NAME]) { + l->name = blobmsg_data(tb[RPC_LXC_NAME]); + } else { + goto error; + } + + if (tb[RPC_LXC_CONFIG]) { + l->config = blobmsg_data(tb[RPC_LXC_CONFIG]); + } else { + l->config = NULL; + } + + l->container = lxc_container_new(l->name, l->config); + if (!l->container) { + goto error; + } + + return l; +error: + free(l); + return NULL; +} + +static void +rpc_lxc_done(struct rpc_lxc *l) +{ + if (l) { + lxc_container_put(l->container); + free(l); + } + + return; +} + +static int +rpc_lxc_start(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__RPC_LXC_MAX]; + struct rpc_lxc *l = NULL; + int rc; + + blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg)); + + l = rpc_lxc_init(tb); + if (!l) return UBUS_STATUS_INVALID_ARGUMENT; + + if (l->container->is_running(l->container)) { + rc = UBUS_STATUS_UNKNOWN_ERROR; + goto out; + } + + if (!l->container->start(l->container, 0, NULL)) { + rc = UBUS_STATUS_INVALID_ARGUMENT; + goto out; + } + + rc = UBUS_STATUS_OK; +out: + rpc_lxc_done(l); + return rc; +} + + +static int +rpc_lxc_reboot(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__RPC_LXC_MAX]; + struct rpc_lxc *l = NULL; + int rc; + + blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg)); + + l = rpc_lxc_init(tb); + if (!l) return UBUS_STATUS_INVALID_ARGUMENT; + + if (!l->container->is_running(l->container)) { + rc = UBUS_STATUS_UNKNOWN_ERROR; + goto out; + } + + if (!l->container->reboot(l->container)) { + rc = UBUS_STATUS_INVALID_ARGUMENT; + goto out; + } + + rc = UBUS_STATUS_OK; +out: + rpc_lxc_done(l); + return rc; +} + +static int +rpc_lxc_shutdown(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__RPC_LXC_SHUTDOWN_MAX]; + struct rpc_lxc *l = NULL; + int rc; + + blobmsg_parse(rpc_lxc_shutdown_policy, __RPC_LXC_SHUTDOWN_MAX, tb, blob_data(msg), blob_len(msg)); + + l = rpc_lxc_init(tb); + if (!l) return UBUS_STATUS_INVALID_ARGUMENT; + + if (!l->container->is_running(l->container)) { + rc = UBUS_STATUS_UNKNOWN_ERROR; + goto out; + } + + /* define default timeout */ + int timeout = 30; + if (tb[RPC_LXC_SHUTDOWN_TIMEOUT]) { + timeout = blobmsg_get_u32(tb[RPC_LXC_SHUTDOWN_TIMEOUT]); + } + + if (!l->container->shutdown(l->container, timeout)) { + rc = UBUS_STATUS_UNKNOWN_ERROR; + goto out; + } + + rc = UBUS_STATUS_OK; +out: + rpc_lxc_done(l); + return rc; +} + +static int +rpc_lxc_stop(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__RPC_LXC_MAX]; + struct rpc_lxc *l = NULL; + int rc; + + blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg)); + + l = rpc_lxc_init(tb); + if (!l) return UBUS_STATUS_INVALID_ARGUMENT; + + if (!l->container->is_running(l->container)) { + rc = UBUS_STATUS_UNKNOWN_ERROR; + goto out; + } + + if (!l->container->stop(l->container)) { + rc = UBUS_STATUS_INVALID_ARGUMENT; + goto out; + } + + rc = UBUS_STATUS_OK; +out: + rpc_lxc_done(l); + return rc; +} + +static int +rpc_lxc_freeze(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__RPC_LXC_MAX]; + struct rpc_lxc *l = NULL; + int rc; + + blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg)); + + l = rpc_lxc_init(tb); + if (!l) return UBUS_STATUS_INVALID_ARGUMENT; + + if (!l->container->is_running(l->container)) { + rc = UBUS_STATUS_UNKNOWN_ERROR; + goto out; + } + + if (!l->container->freeze(l->container)) { + rc = UBUS_STATUS_INVALID_ARGUMENT; + goto out; + } + + rc = UBUS_STATUS_OK; +out: + rpc_lxc_done(l); + return rc; +} + +static int +rpc_lxc_unfreeze(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__RPC_LXC_MAX]; + struct rpc_lxc *l = NULL; + int rc; + + blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg)); + + l = rpc_lxc_init(tb); + if (!l) return UBUS_STATUS_INVALID_ARGUMENT; + + if (!l->container->is_running(l->container)) { + rc = UBUS_STATUS_UNKNOWN_ERROR; + goto out; + } + + if (!l->container->unfreeze(l->container)) { + rc = UBUS_STATUS_INVALID_ARGUMENT; + goto out; + } + + rc = UBUS_STATUS_OK; +out: + rpc_lxc_done(l); + return rc; +} + +static int +rpc_lxc_rename(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__RPC_LXC_RENAME_MAX]; + struct rpc_lxc *l = NULL; + int rc; + + blobmsg_parse(rpc_lxc_rename_policy, __RPC_LXC_RENAME_MAX, tb, blob_data(msg), blob_len(msg)); + + l = rpc_lxc_init(tb); + if (!l) return UBUS_STATUS_INVALID_ARGUMENT; + + if (!tb[RPC_LXC_RENAME_NEWNAME]) { + rc = UBUS_STATUS_INVALID_ARGUMENT; + goto out; + } + + if (l->container->is_running(l->container)) { + rc = UBUS_STATUS_UNKNOWN_ERROR; + goto out; + } + + char *newname = blobmsg_data(tb[RPC_LXC_RENAME_NEWNAME]); + if (!newname || !l->container->rename(l->container, newname)) { + rc = UBUS_STATUS_INVALID_ARGUMENT; + goto out; + } + + rc = UBUS_STATUS_OK; +out: + rpc_lxc_done(l); + return rc; +} + +static int +rpc_lxc_destroy(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__RPC_LXC_MAX]; + struct rpc_lxc *l = NULL; + int rc; + + blobmsg_parse(rpc_lxc_min_policy, __RPC_LXC_MAX, tb, blob_data(msg), blob_len(msg)); + + l = rpc_lxc_init(tb); + if (!l) return UBUS_STATUS_INVALID_ARGUMENT; + + if (l->container->is_running(l->container)) { + rc = UBUS_STATUS_UNKNOWN_ERROR; + goto out; + } + + if (!l->container->destroy(l->container)) { + rc = UBUS_STATUS_INVALID_ARGUMENT; + goto out; + } + + rc = UBUS_STATUS_OK; +out: + rpc_lxc_done(l); + return rc; +} + +static int +rpc_lxc_list(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + + blob_buf_init(&buf, 0); + + int rc; + char **names; + struct lxc_container **cret; + + rc = list_all_containers(NULL, &names, &cret); + if (rc == -1) + return UBUS_STATUS_UNKNOWN_ERROR; + + for (int i = 0; i < rc; i++) { + struct lxc_container *c = cret[i]; + blobmsg_add_string(&buf, names[i], c->state(c)); + + free(names[i]); + lxc_container_put(c); + } + + ubus_send_reply(ctx, req, buf.head); + + return UBUS_STATUS_OK; +} + +static int +rpc_lxc_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx) +{ + static const struct ubus_method lxc_methods[] = { + UBUS_METHOD("start", rpc_lxc_start, rpc_lxc_min_policy), + UBUS_METHOD("reboot", rpc_lxc_reboot, rpc_lxc_min_policy), + UBUS_METHOD("shutdown", rpc_lxc_shutdown, rpc_lxc_shutdown_policy), + UBUS_METHOD("stop", rpc_lxc_stop, rpc_lxc_min_policy), + UBUS_METHOD("freeze", rpc_lxc_freeze, rpc_lxc_min_policy), + UBUS_METHOD("unfreeze", rpc_lxc_unfreeze, rpc_lxc_min_policy), + UBUS_METHOD("rename", rpc_lxc_rename, rpc_lxc_rename_policy), + UBUS_METHOD("destroy", rpc_lxc_destroy, rpc_lxc_min_policy), + UBUS_METHOD_NOARG("list", rpc_lxc_list), + }; + + static struct ubus_object_type lxc_type = + UBUS_OBJECT_TYPE("luci-rpc-lxc", lxc_methods); + + static struct ubus_object obj = { + .name = "lxc", + .type = &lxc_type, + .methods = lxc_methods, + .n_methods = ARRAY_SIZE(lxc_methods), + }; + + return ubus_add_object(ctx, &obj); +} + +struct rpc_plugin rpc_plugin = { + .init = rpc_lxc_api_init +};