-
Suvendhu Hansa authoredSuvendhu Hansa authored
swmod.c 23.75 KiB
/*
* swmod.c: SWMOD deamon
*
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
*
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <libubox/uloop.h>
#include <curl/curl.h>
#include "swmod_uci.h"
#include "swmod_opkg.h"
#include "tools.h"
#include "swmod_host.h"
#include "swmod.h"
#ifdef SWMOD_LXC
#include "swmod_lxc.h"
#endif
#define DW_PKG_PATH "/tmp/dw_package.ipk"
struct ubus_context *ubus_ctx;
ExecEnv environments[MAX_ENV] = {0};
ExecUnit exec_units[MAX_ENV] = {0};
enum {
DU_INSTALL_ENV_ID,
DU_INSTALL_ENV,
DU_INSTALL_UUID,
DU_INSTALL_URL,
DU_INSTALL_USERNAME,
DU_INSTALL_PASSWORD,
__DU_INSTALL_MAX
};
enum {
DU_UPDATE_ENV_ID,
DU_UPDATE_ENV,
DU_UPDATE_UUID,
DU_UPDATE_URL,
DU_UPDATE_USERNAME,
DU_UPDATE_PASSWORD,
__DU_UPDATE_MAX
};
enum {
DU_UNINSTALL_ENV_ID,
DU_UNINSTALL_ENV,
DU_UNINSTALL_NAME,
__DU_UNINSTALL_MAX
};
enum {
EU_DU_LIST_ENV_ID,
EU_DU_LIST_ENV,
__EU_DU_LIST_MAX
};
enum {
EU_ACTIVATE_SERVICE_ENV_ID,
EU_ACTIVATE_SERVICE_ENV,
EU_ACTIVATE_SERVICE_NAME,
EU_ACTIVATE_SERVICE_STATUS,
__EU_ACTIVATE_SERVICE_MAX
};
enum {
EE_SET_STATE_ENV_ID,
EE_SET_STATE_ENV,
EE_SET_STATE_STATUS,
__EE_SET_STATE_MAX
};
static const struct blobmsg_policy ee_set_state_policy[__EE_SET_STATE_MAX] = {
[EE_SET_STATE_ENV_ID] = { .name = "eid", .type = BLOBMSG_TYPE_INT32 },
[EE_SET_STATE_ENV] = { .name = "environment", .type = BLOBMSG_TYPE_STRING },
[EE_SET_STATE_STATUS] = { .name = "state", .type = BLOBMSG_TYPE_STRING },
};
static const struct blobmsg_policy eu_activate_policy[__EU_ACTIVATE_SERVICE_MAX] = {
[EU_ACTIVATE_SERVICE_ENV_ID] = { .name = "eid", .type = BLOBMSG_TYPE_INT32 },
[EU_ACTIVATE_SERVICE_ENV] = { .name = "environment", .type = BLOBMSG_TYPE_STRING },
[EU_ACTIVATE_SERVICE_NAME] = { .name = "service_name", .type = BLOBMSG_TYPE_STRING },
[EU_ACTIVATE_SERVICE_STATUS] = { .name = "state", .type = BLOBMSG_TYPE_INT8 },
};
static const struct blobmsg_policy du_install_policy[__DU_INSTALL_MAX] = {
[DU_INSTALL_ENV_ID] = { .name = "eid", .type = BLOBMSG_TYPE_INT32 },
[DU_INSTALL_ENV] = { .name = "environment", .type = BLOBMSG_TYPE_STRING },
[DU_INSTALL_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING },
[DU_INSTALL_URL] = { .name = "url", .type = BLOBMSG_TYPE_STRING },
[DU_INSTALL_USERNAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING },
[DU_INSTALL_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING },
};
static const struct blobmsg_policy du_update_policy[__DU_UPDATE_MAX] = {
[DU_UPDATE_ENV_ID] = { .name = "eid", .type = BLOBMSG_TYPE_INT32 },
[DU_UPDATE_ENV] = { .name = "environment", .type = BLOBMSG_TYPE_STRING },
[DU_UPDATE_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING },
[DU_UPDATE_URL] = { .name = "url", .type = BLOBMSG_TYPE_STRING },
[DU_UPDATE_USERNAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING },
[DU_UPDATE_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING },
};
static const struct blobmsg_policy du_uninstall_policy[__DU_UNINSTALL_MAX] = {
[DU_UNINSTALL_ENV_ID] = { .name = "eid", .type = BLOBMSG_TYPE_INT32 },
[DU_UNINSTALL_ENV] = { .name = "environment", .type = BLOBMSG_TYPE_STRING },
[DU_UNINSTALL_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
};
static const struct blobmsg_policy eu_du_list_policy[__EU_DU_LIST_MAX] = {
[EU_DU_LIST_ENV_ID] = { .name = "eid", .type = BLOBMSG_TYPE_INT32 },
[EU_DU_LIST_ENV] = { .name = "environment", .type = BLOBMSG_TYPE_STRING },
};
static void
populate_environments(void)
{
memset(environments, '\0', sizeof(environments));
/* Host system */
populate_host_system_environment();
/* Linux containers */
#ifdef SWMOD_LXC
populate_lxc_environment();
#endif
}
int get_eid_from_env_name(char *ename)
{
int i;
for (i = 0; i < MAX_ENV; i++) {
if (!environments[i].exists)
continue;
if (strcmp(environments[i].name, ename) == 0)
return i + 1;
}
return 0;
}
static int get_map_filename_from_eid(unsigned int eid, char *fname, int size)
{
if (!fname)
return -1;
memset(fname, 0, size);
if (eid == 1) {
strncpy(fname, SWMOD_MAP_DU, size - 1);
return 0;
} else {
if (!environments[eid - 1].exists)
return -1;
snprintf(fname, size, "%s_%s", SWMOD_MAP_DU, environments[eid - 1].name);
return 0;
}
}
static int
swmod_environment(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_buf bb;
void *a, *t;
int i;
populate_environments();
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
a = blobmsg_open_array(&bb, "environment");
for (i = 0; i < MAX_ENV; i++) {
if (!environments[i].exists)
continue;
t = blobmsg_open_table(&bb, "");
blobmsg_add_string(&bb, "name", environments[i].name);
blobmsg_add_u32(&bb, "eid", i + 1);
blobmsg_add_string(&bb, "status", environments[i].status);
blobmsg_add_u32(&bb, "pause", environments[i].pause);
blobmsg_add_string(&bb, "type", environments[i].type);
blobmsg_add_string(&bb, "vendor", environments[i].vendor);
blobmsg_add_string(&bb, "version", environments[i].version);
blobmsg_add_u64(&bb, "allocated_disk_space", environments[i].allocated_disk_space);
blobmsg_add_u64(&bb, "available_disk_space", environments[i].available_disk_space);
blobmsg_add_u64(&bb, "allocated_memory", environments[i].allocated_memory);
blobmsg_add_u64(&bb, "available_memory", environments[i].available_memory);
blobmsg_close_table(&bb, t);
}
blobmsg_close_array(&bb, a);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
int update_map_du_file(struct blob_buf *bb, char *pkg_name,
char *pkg_version, char *url, char *username,
char *password, char *env, char *uuid)
{
char uci_map_du_path[128] = {0};
#ifdef SWMOD_LXC
if (!env || strcmp(env, HOST_SYSTEM) == 0)
swmod_strncpy(uci_map_du_path, SWMOD_PATH, 12);
else {
const char *lxc_config_path = get_lxc_path_from_config();
snprintf(uci_map_du_path, sizeof(uci_map_du_path), "%s/%s/rootfs%s",
lxc_config_path ? lxc_config_path : "",
env,
SWMOD_PATH);
}
#else
swmod_strncpy(uci_map_du_path, SWMOD_PATH, 12);
#endif
swmod_uci_init(uci_map_du_path);
struct uci_section *new_s = swmod_uci_add_section(SWMOD_MAP_DU, "deployment");
swmod_uci_set_value_by_section(new_s, "name", pkg_name);
swmod_uci_set_value_by_section(new_s, "version", pkg_version);
swmod_uci_set_value_by_section(new_s, "url", url);
swmod_uci_set_value_by_section(new_s, "username", (username && *username) ? username : "");
swmod_uci_set_value_by_section(new_s, "password", (password && *password) ? password : "");
swmod_uci_set_value_by_section(new_s, "environment", (env) ? env : HOST_SYSTEM);
blobmsg_add_string(bb,"environment", (env) ? env : HOST_SYSTEM);
if (uuid && *uuid != '\0') {
//use the given UUID
swmod_uci_set_value_by_section(new_s, "uuid", uuid);
blobmsg_add_string(bb,"uuid", uuid);
} else {
//generate a UUID
char *new_uuid = generate_uuid();
swmod_uci_set_value_by_section(new_s, "uuid", new_uuid);
blobmsg_add_string(bb,"uuid", new_uuid);
FREE(new_uuid);
}
//generate a DUID
char *duid = generate_duid(false, 0);
swmod_uci_set_value_by_section(new_s, "duid", duid);
FREE(duid);
/* Get Description from package_name.control and Set it to map_du file */
//get_description_from_package(new_s, pkg_name);
/* Get Config from package_name.list and Set it to map_du file */
//get_config_from_package(new_s, pkg_name);
swmod_uci_fini(SWMOD_MAP_DU);
return 0;
}
static int download_remote_package(const char *url, char *username, char *password)
{
long res_code = 0;
CURL *curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
if (username)
curl_easy_setopt(curl, CURLOPT_USERNAME, username);
if (password)
curl_easy_setopt(curl, CURLOPT_PASSWORD, password);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 100);
FILE *fp = fopen(DW_PKG_PATH, "wb");
if (fp) {
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_perform(curl);
fclose(fp);
} else {
curl_easy_cleanup(curl);
return -1;
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_code);
curl_easy_cleanup(curl);
if ((strncmp(url, "http", 4) == 0 && res_code != 200) ||
(strncmp(url, "ftp", 3) == 0 && res_code != 226) ||
(strncmp(url, "http", 4) && strncmp(url, "ftp", 3))) {
return -1;
}
return 0;
}
return -1;
}
static int
swmod_du_install(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__DU_INSTALL_MAX] = {NULL};
struct blob_buf bb;
int eid = 0, err = -1;
char url[2048] = {0};
bool remote_file = false;
if (blobmsg_parse(du_install_policy, __DU_INSTALL_MAX, tb, blob_data(msg), blob_len(msg)))
return UBUS_STATUS_UNKNOWN_ERROR;
if (tb[DU_INSTALL_ENV])
eid = get_eid_from_env_name(blobmsg_get_string(tb[DU_INSTALL_ENV]));
/* Priority should be given on EID if both EID and ENV name are provided */
if (tb[DU_INSTALL_ENV_ID])
eid = blobmsg_get_u32(tb[DU_INSTALL_ENV_ID]);
if (!tb[DU_INSTALL_URL])
return UBUS_STATUS_INVALID_ARGUMENT;
snprintf(url, sizeof(url), "%s", blobmsg_get_string(tb[DU_INSTALL_URL]));
if (strchr(url, ':') != NULL) {
/* This is a remote package, need to download first */
if(0 != download_remote_package(url, blobmsg_get_string(tb[DU_INSTALL_USERNAME]),
blobmsg_get_string(tb[DU_INSTALL_PASSWORD]))) {
goto end;
}
snprintf(url, sizeof(url), "%s", DW_PKG_PATH);
remote_file = true;
}
err = swmod_install_package(url, eid, remote_file);
//synchronize_deployment_units_with_map_du_file();
end:
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
blobmsg_add_u8(&bb, "status", (err) ? false : true);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
int update_corresponding_section_in_map_du_file(char *pkg_version, char *url,
char *username, char *password, const char *env, char *uuid)
{
char uci_map_du_path[128] = {0};
#ifdef SWMOD_LXC
if (!env || strcmp(env, HOST_SYSTEM) == 0)
swmod_strncpy(uci_map_du_path, SWMOD_PATH, 12);
else {
const char *lxc_config_path = get_lxc_path_from_config();
snprintf(uci_map_du_path, sizeof(uci_map_du_path), "%s/%s/rootfs%s",
lxc_config_path ? lxc_config_path : "",
env,
SWMOD_PATH);
}
#else
swmod_strncpy(uci_map_du_path, SWMOD_PATH, 12);
#endif
swmod_uci_init(uci_map_du_path);
struct uci_section *s = NULL;
swmod_uci_foreach_section(SWMOD_MAP_DU, "deployment", s) {
const char *map_uuid = swmod_uci_get_value_by_section(s, "uuid");
if (strcmp(map_uuid, uuid) == 0) {
swmod_uci_set_value_by_section(s, "version", pkg_version);
swmod_uci_set_value_by_section(s, "url", url);
swmod_uci_set_value_by_section(s, "username", (username && *username) ? username : "");
swmod_uci_set_value_by_section(s, "password", (password && *password) ? password : "");
break;
}
}
swmod_uci_fini(SWMOD_MAP_DU);
return 0;
}
static int
swmod_du_update(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__DU_UPDATE_MAX] = {NULL};
struct blob_buf bb;
char url[2048] = {0};
int eid = 0, err = -1;
bool remote_file = false;
if (blobmsg_parse(du_update_policy, __DU_UPDATE_MAX, tb, blob_data(msg), blob_len(msg)))
return UBUS_STATUS_UNKNOWN_ERROR;
if (!tb[DU_UPDATE_URL] || !tb[DU_UPDATE_UUID])
return UBUS_STATUS_INVALID_ARGUMENT;
if (tb[DU_UPDATE_ENV])
eid = get_eid_from_env_name(blobmsg_get_string(tb[DU_UPDATE_ENV]));
/* Priority should be given on EID if both EID and ENV name are provided */
if (tb[DU_UPDATE_ENV_ID])
eid = blobmsg_get_u32(tb[DU_UPDATE_ENV_ID]);
snprintf(url, sizeof(url), "%s", blobmsg_get_string(tb[DU_UPDATE_URL]));
if (strchr(url, ':') != NULL) {
/* This is a remote package, need to download first */
if (0 != download_remote_package(url, blobmsg_get_string(tb[DU_UPDATE_USERNAME]),
blobmsg_get_string(tb[DU_UPDATE_PASSWORD]))) {
goto end;
}
snprintf(url, sizeof(url), "%s", DW_PKG_PATH);
remote_file = true;
}
err = swmod_update_package(url, eid, remote_file);
//synchronize_deployment_units_with_map_du_file();
end:
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
blobmsg_add_u8(&bb, "status", (!err) ? true : false);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static int
swmod_du_uninstall(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__DU_UNINSTALL_MAX] = {NULL};
struct blob_buf bb;
int eid = 0;
if (blobmsg_parse(du_uninstall_policy, __DU_UNINSTALL_MAX, tb, blob_data(msg), blob_len(msg)))
return UBUS_STATUS_UNKNOWN_ERROR;
if (!tb[DU_UNINSTALL_NAME])
return UBUS_STATUS_INVALID_ARGUMENT;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (tb[DU_UNINSTALL_ENV])
eid = get_eid_from_env_name(blobmsg_get_string(tb[DU_UNINSTALL_ENV]));
/* Priority should be given on EID if both EID and ENV name are provided */
if (tb[DU_UNINSTALL_ENV_ID])
eid = blobmsg_get_u32(tb[DU_UNINSTALL_ENV_ID]);
int err = swmod_remove_package(blobmsg_get_string(tb[DU_UNINSTALL_NAME]), eid);
blobmsg_add_u8(&bb, "status", (!err) ? true : false);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static int get_eid_from_blob(struct blob_attr *msg)
{
unsigned int eid = 0;
struct blob_attr *tb[__EU_DU_LIST_MAX] = {NULL};
if (blobmsg_parse(eu_du_list_policy, __EU_DU_LIST_MAX, tb, blob_data(msg), blob_len(msg)) == 0) {
if (tb[EU_DU_LIST_ENV]) {
eid = get_eid_from_env_name(blobmsg_get_string(tb[EU_DU_LIST_ENV]));
}
/* Priority given to EID if both EID and ENV name are provided */
if (tb[EU_DU_LIST_ENV_ID]) {
eid = blobmsg_get_u32(tb[EU_DU_LIST_ENV_ID]);
}
}
return eid;
}
static void prepare_du_list_result(unsigned int eid, struct blob_buf *bb)
{
struct uci_section *ss = NULL;
char map_du_fname[64] = {0};
if (0 != get_map_filename_from_eid(eid, map_du_fname, sizeof(map_du_fname)))
return;
swmod_uci_foreach_section(map_du_fname, "deployment", ss) {
void *t = blobmsg_open_table(bb, "");
blobmsg_add_string(bb, "name", swmod_uci_get_value_by_section(ss, "name"));
blobmsg_add_string(bb, "environment", swmod_uci_get_value_by_section(ss, "environment"));
blobmsg_add_string(bb, "eid", swmod_uci_get_value_by_section(ss, "eid"));
blobmsg_add_string(bb, "uuid", swmod_uci_get_value_by_section(ss, "uuid"));
blobmsg_add_string(bb, "duid", swmod_uci_get_value_by_section(ss, "duid"));
blobmsg_add_string(bb, "url", swmod_uci_get_value_by_section(ss, "url"));
blobmsg_add_string(bb, "version", swmod_uci_get_value_by_section(ss, "version"));
blobmsg_add_string(bb, "config", swmod_uci_get_value_by_section(ss, "config"));
blobmsg_add_string(bb, "description", swmod_uci_get_value_by_section(ss, "description"));
blobmsg_add_string(bb, "vendor", ""); //TODO
blobmsg_close_table(bb, t);
}
}
static int
swmod_du_list(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_buf bb;
void *a;
unsigned int eid = get_eid_from_blob(msg);
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
a = blobmsg_open_array(&bb, "deployment_unit");
swmod_uci_init(SWMOD_PATH);
if (eid) {
eid <= MAX_ENV ? prepare_du_list_result(eid, &bb) :
PRINT_ERR("Invalid eid '%d', valid range [1 - %d]", eid, MAX_ENV);
} else {
for (int i = 1; i <= MAX_ENV; i++) {
prepare_du_list_result(i, &bb);
}
}
swmod_uci_fini(SWMOD_MAP_DU);
blobmsg_close_array(&bb, a);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static void
populate_execution_unit()
{
memset(exec_units, '\0', sizeof(exec_units));
/* Host system */
populate_service_list(service_get_cb);
/* Linux containers */
#ifdef SWMOD_LXC
populate_lxc_eu();
#endif
}
static void prepare_eu_list_result(unsigned int idx, struct blob_buf *bb)
{
int j;
void *t;
if (!exec_units[idx].exists)
return;
for (j = 0; j < MAX_EU; j++) {
if (!exec_units[idx].eu_exists[j])
continue;
t = blobmsg_open_table(bb, "");
blobmsg_add_string(bb, "name", exec_units[idx].name[j]);
blobmsg_add_string(bb, "command", exec_units[idx].command[j]);
blobmsg_add_string(bb, "state", exec_units[idx].state[j]);
blobmsg_add_string(bb, "config", exec_units[idx].config[j]);
blobmsg_add_string(bb, "version", exec_units[idx].version[j]);
blobmsg_add_string(bb, "description", exec_units[idx].description[j]);
blobmsg_add_string(bb, "environment", exec_units[idx].environment[j]);
blobmsg_add_u32(bb, "eid", idx + 1);
blobmsg_add_u32(bb, "euid", exec_units[idx].euid[j]);
blobmsg_add_u32(bb, "disk_space", exec_units[idx].disk_space[j]);
blobmsg_add_u32(bb, "memory_space", exec_units[idx].memory_space[j]);
blobmsg_add_string(bb, "vendor", exec_units[idx].vendor[j]); //TODO
blobmsg_close_table(bb, t);
}
}
static int
swmod_eu_list(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_buf bb;
void *a;
unsigned int eid = get_eid_from_blob(msg);
populate_execution_unit();
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
a = blobmsg_open_array(&bb, "execution_unit");
if (eid) {
eid <= MAX_ENV ? prepare_eu_list_result(eid - 1, &bb) :
PRINT_ERR("Invalid eid '%d', valid range [1 - %d]", eid, MAX_ENV);
} else {
for (int i = 0; i < MAX_ENV; i++) {
prepare_eu_list_result(i, &bb);
}
}
blobmsg_close_array(&bb, a);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static int
swmod_eu_activate(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_buf bb;
struct blob_attr *tb[__EU_ACTIVATE_SERVICE_MAX] = {NULL};
char name[32] = {0};
bool state = false;
int eid = 0;
if (blobmsg_parse(eu_activate_policy, __EU_ACTIVATE_SERVICE_MAX, tb, blob_data(msg), blob_len(msg)) != 0) {
return UBUS_STATUS_INVALID_ARGUMENT;
}
if (!tb[EU_ACTIVATE_SERVICE_NAME] || !tb[EU_ACTIVATE_SERVICE_STATUS]) {
return UBUS_STATUS_INVALID_ARGUMENT;
}
if (tb[EU_ACTIVATE_SERVICE_ENV]) {
eid = get_eid_from_env_name(blobmsg_get_string(tb[EU_ACTIVATE_SERVICE_ENV]));
}
/* Priority should be given on EID if both EID and ENV name are provided */
if (tb[EU_ACTIVATE_SERVICE_ENV_ID]) {
eid = blobmsg_get_u32(tb[EU_ACTIVATE_SERVICE_ENV_ID]);
}
if (eid <= 0 || eid > MAX_ENV)
return UBUS_STATUS_INVALID_ARGUMENT;
snprintf(name, sizeof(name), "%s", blobmsg_get_string(tb[EU_ACTIVATE_SERVICE_NAME]));
state = blobmsg_get_bool(tb[EU_ACTIVATE_SERVICE_STATUS]);
int index = eid - 1;
if (!environments[index].exists) {
PRINT_INFO("No environment exists at index: %d", index);
return -1;
}
int err = -1;
if (strcmp(environments[index].name, HOST_SYSTEM) == 0) {
err = swmod_set_host_service_state(name, state);
} else {
#ifdef SWMOD_LXC
err = swmod_set_lxc_service_state(index, name, state);
#endif
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
blobmsg_add_u8(&bb, "status", (err >= 0) ? true : false);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static int
swmod_ee_set_state(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_buf bb;
struct blob_attr *tb[__EE_SET_STATE_MAX] = {NULL};
int eid = 0;
if (blobmsg_parse(ee_set_state_policy, __EE_SET_STATE_MAX, tb, blob_data(msg), blob_len(msg)) != 0) {
return UBUS_STATUS_INVALID_ARGUMENT;
}
if (!tb[EE_SET_STATE_STATUS]) {
return UBUS_STATUS_INVALID_ARGUMENT;
}
if (tb[EE_SET_STATE_ENV]) {
eid = get_eid_from_env_name(blobmsg_get_string(tb[EE_SET_STATE_ENV]));
}
/* Priority should be given on EID if both EID and ENV name are provided */
if (tb[EE_SET_STATE_ENV_ID]) {
eid = blobmsg_get_u32(tb[EE_SET_STATE_ENV_ID]);
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (eid <= 0 || eid > MAX_ENV) {
blobmsg_add_u8(&bb, "status", false);
blobmsg_add_string(&bb, "reason", "invalid eid/environment");
goto end;
}
int index = eid - 1;
if (!environments[index].exists) {
blobmsg_add_u8(&bb, "status", false);
blobmsg_add_string(&bb, "reason", "no environment exist at this index");
goto end;
}
if (strcmp(environments[index].name, HOST_SYSTEM) == 0) {
blobmsg_add_u8(&bb, "status", false);
blobmsg_add_string(&bb, "reason", "request can not be performed on host system");
goto end;
} else {
#ifdef SWMOD_LXC
char state[10] = {0};
snprintf(state, sizeof(state), "%s", blobmsg_get_string(tb[EE_SET_STATE_STATUS]));
int err = swmod_set_ee_state(index, state);
blobmsg_add_u8(&bb, "status", (err == 0) ? true : false);
blobmsg_add_string(&bb, "reason", ee_state_failure_reason(err));
#else
blobmsg_add_u8(&bb, "status", false);
blobmsg_add_string(&bb, "reason", "LXC service not present");
#endif
}
end:
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static const struct ubus_method swmod_object_methods[] = {
UBUS_METHOD_NOARG("environment", swmod_environment),
UBUS_METHOD("du_list", swmod_du_list, eu_du_list_policy),
UBUS_METHOD("eu_list", swmod_eu_list, eu_du_list_policy),
UBUS_METHOD("du_install", swmod_du_install, du_install_policy),
UBUS_METHOD("du_update", swmod_du_update, du_update_policy),
UBUS_METHOD("du_uninstall", swmod_du_uninstall, du_uninstall_policy),
UBUS_METHOD("eu_activate", swmod_eu_activate, eu_activate_policy),
UBUS_METHOD("ee_set_state", swmod_ee_set_state, ee_set_state_policy),
};
static struct ubus_object_type swmod_object_type = UBUS_OBJECT_TYPE("swmodules", swmod_object_methods);
static struct ubus_object swmod_object = {
.name = "swmodules",
.type = &swmod_object_type,
.methods = swmod_object_methods,
.n_methods = ARRAY_SIZE(swmod_object_methods),
};
static int swmod_pre_init(void)
{
populate_environments();
return synchronize_deployment_units_with_map_du_file();
}
static int swmod_init(struct ubus_context *ctx)
{
int ret;
ret = ubus_add_object(ctx, &swmod_object);
if (ret)
PRINT_ERR("Failed to publish '%s' object : %s", swmod_object.name, ubus_strerror(ret));
return ret;
}
static void usage(char *prog)
{
fprintf(stderr, "Usage: %s [options]\n", prog);
fprintf(stderr, "\n");
fprintf(stderr, "options:\n");
fprintf(stderr, " -s <socket path> ubus socket\n");
fprintf(stderr, " -l <log_level> Configures log level\n");
fprintf(stderr, "\n");
}
int main(int argc, char **argv)
{
const char *ubus_socket = NULL;
int ret, ch;
while ((ch = getopt(argc, argv, "hs:l:")) != -1) {
switch (ch) {
case 's':
ubus_socket = optarg;
break;
case 'l':
configure_debug_level(atoi(optarg));
break;
case 'h':
usage(argv[0]);
exit(0);
default:
break;
}
}
openlog("swmodd", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
uloop_init();
ubus_ctx = ubus_connect(ubus_socket);
if (!ubus_ctx) {
fprintf(stderr, "Failed to connect to ubus\n");
return -1;
}
swmod_pre_init();
ubus_add_uloop(ubus_ctx);
ret = swmod_init(ubus_ctx);
if (ret)
goto out;
uloop_run();
out:
ubus_free(ubus_ctx);
uloop_done();
closelog();
return 0;
}