diff --git a/README.md b/README.md index 24e325e88b7c7cee3c1600dcd1e65f46d7cbaeb8..7e4ec2c5570b5a9e053db982004a75ee28fabd6b 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,10 @@ It is written in C programming language and depends on a number of libraries of Currently, `swmodd` can not create new execution environment and it depends on pre-created execution environments/containers. `swmodd` treats host as one execution environment and further it usages the pre-created lxc-containers as available execution environments for managing services. -`SWMODD` in du_list only shows information about the packages from `opkg list` which has services registered in init.d -`SWMODD` in eu_list only shows information about the packages present in `ubus call service list` +NOTE: +- `SWMODD` in du_list only shows information about the packages from `opkg list` which has services registered in init.d +- `SWMODD` in eu_list only shows information about the packages present in `ubus call service list` +- `SWMODD` maintains a list of mandatory packages such as procd, ubusd, ubus client, swmodd and opkg as of now. Information about these packages are not shown in both eu_list and du_list. ## Concepts and Workflow `SWMODD` usages lxc library to interact with the lxc containers and opkg system utilities to manage the services running inside that container. @@ -30,6 +32,7 @@ root@iopsys:~# ubus -v list swmodules "du_update":{"eid":"Integer","environment":"String","uuid":"String","url":"String","username":"String","password":"String"} "du_uninstall":{"eid":"Integer","environment":"String","name":"String"} "eu_activate":{"eid":"Integer","environment":"String","service_name":"String","state":"Boolean"} + "ee_set_state":{"eid":"Integer","environment":"String","state":"String"} root@iopsys:~# ``` @@ -119,8 +122,9 @@ root@iopsys:~# ubus call swmodules environment "environment": [ { "name": "OpenWRT_Linux", - "eid" : "1", + "eid" : "1", "status": "Up", + "pause": 0, "type": "Linux", "vendor": "iopsys", "version": "4.19.151", @@ -141,7 +145,7 @@ root@iopsys:~# ubus call swmodules du_list { "name": "6in4", "environment": "OpenWRT_Linux", - "eid": "1", + "eid": "1", "uuid": "5f085cf2-ca02-44c8-8697-212585505b35", "duid": "04n0000", "url": "", @@ -153,7 +157,7 @@ root@iopsys:~# ubus call swmodules du_list { "name": "6rd", "environment": "OpenWRT_Linux", - "eid": "1", + "eid": "1", "uuid": "f10d5aea-ee7f-4144-8232-39b6c5541958", "duid": "04n0001", "url": "", @@ -166,7 +170,7 @@ root@iopsys:~# ubus call swmodules du_list { "name": "zoneinfo-europe", "environment": "OpenWRT_Linux", - "eid": "1", + "eid": "1", "uuid": "cac5b136-0eed-4d2c-8567-a2ad368102aa", "duid": "04n0363", "url": "", @@ -188,12 +192,12 @@ root@iopsys:~# ubus call swmodules eu_list { "name": "dnsmasq", "command": "/usr/sbin/dnsmasq", - "state" : "Active", + "state" : "Active", "config": "dhcp", "version": "2.85-5", "description": "It is intended to provide coupled DNS and DHCP service to a LAN.", "environment": "OpenWRT_Linux", - "eid" : "2", + "eid" : "2", "euid": 6338, "disk_space": 130094, "memory_space": 1248, @@ -202,12 +206,12 @@ root@iopsys:~# ubus call swmodules eu_list { "name": "ethmngr", "command": "/usr/sbin/ethmngr", - "state" : "Active", + "state" : "Active", "config": "", "version": "2.0.1", "description": "This package can be used to configure and provide status about", "environment": "OpenWRT_Linux", - "eid" : "2", + "eid" : "2", "euid": 7525, "disk_space": 4942, "memory_space": 4460, @@ -217,12 +221,12 @@ root@iopsys:~# ubus call swmodules eu_list { "name": "wifimngr", "command": "/usr/sbin/wifimngr", - "state" : "Active", + "state" : "Active", "config": "", "version": "11.2.0", "description": "This package can be used to configure and provide status about", "environment": "OpenWRT_Linux", - "eid" : "2", + "eid" : "2", "euid": 7704, "disk_space": 31394, "memory_space": 4688, @@ -260,6 +264,43 @@ root@iopsys:~# ubus call swmodules eu_activate '{"eid":1, "service_name":"obuspa } root@iopsys:~# ``` +#### Change the state of execution environment +Possible states of execution environment could be `start`, `stop`, `pause` and `resume`. To stop, pause or resume an execution environment the environment must be started prior. + +```bash +root@iopsys:~# ubus call swmodules ee_set_state '{"eid":2, "environment":"test", "state":"start"}' +{ + "status": true, + "reason": "" +} +root@iopsys:~# +root@iopsys:~# ubus call swmodules ee_set_state '{"eid":2, "environment":"test", "state":"stop"}' +{ + "status": true, + "reason": "" +} +root@iopsys:~# +root@iopsys:~# ubus call swmodules ee_set_state '{"eid":2, "environment":"test", "state":"pause"}' +{ + "status": false, + "reason": "ExecEnv not running" +} +root@iopsys:~# +root@iopsys:~# ubus call swmodules ee_set_state '{"eid":3, "environment":"test", "state":"resume"}' +{ + "status": false, + "reason": "no environment exist at this index" +} +root@iopsys:~# +``` + +## Vendor extensions to manage containers +In `tr181` 2.14 datamodel software modules does not provide all the functionalities required for full fledged deployment. To overcome this as a short term solution we have introduced some vendor extensions in the datamodel which can be found in the below table. + +| Name | Parent Object | Type | Write | Description | +| ------------------ | ------------------------------------- | ------- | ----- | ------------------------------------------------------------- | +| X_IOPSYS_EU_Pause | Device.SoftwareModules.ExecEnv.\{i\}. | boolean | W | Indicates whether or not this ExecEnv is paused. Setting `false` to this option resumes a paused Execution Environment, while setting `true` an Execution Environment pauses. If set operation of this parameter is attempted on a disabled ExecEnv, that operation does not take any action and so the ExecEnv must be enabled prior this operation to take effect. Once an ExecEnv is successfully enabled and also it is paused by configuring this parameter as `true` then it's status would be shown as `Up`. Once a paused environment is disabled, the module itself first resumes it and then stops it | + ## Limitations - `swmodd` can only manage host and pre-created lxc containers diff --git a/docs/api/swmodules.md b/docs/api/swmodules.md index 21cf7d61e918b72f7555ea24e9a26699cce38ca3..5e0093627762024dbb5e8196799aeb576c9fdb61 100644 --- a/docs/api/swmodules.md +++ b/docs/api/swmodules.md @@ -16,6 +16,7 @@ https://dev.iopsys.eu/iopsys/swmodd/schemas/ubus/swmodules.json | [du_list](#du_list) | Method | swmodules (this schema) | | [du_uninstall](#du_uninstall) | Method | swmodules (this schema) | | [du_update](#du_update) | Method | swmodules (this schema) | +| [ee_set_state](#ee_set_state) | Method | swmodules (this schema) | | [environment](#environment) | Method | swmodules (this schema) | | [eu_activate](#eu_activate) | Method | swmodules (this schema) | | [eu_list](#eu_list) | Method | swmodules (this schema) | @@ -643,6 +644,150 @@ ubus call swmodules du_update {"url":"officia dolore eiusmod","uuid":"dolor sint { "status": false } ``` +## ee_set_state + +### Change the current state of the Execution Environment + +`ee_set_state` + +- type: `Method` + +### ee_set_state Type + +`object` with following properties: + +| Property | Type | Required | +| -------- | ------ | ------------ | +| `input` | object | **Required** | +| `output` | object | Optional | + +#### input + +`input` + +- is **required** +- type: `object` + +##### input Type + +`object` with following properties: + +| Property | Type | Required | +| ------------- | ------- | ------------ | +| `eid` | integer | Optional | +| `environment` | string | Optional | +| `state` | string | **Required** | + +#### eid + +`eid` + +- is optional +- type: `integer` + +##### eid Type + +`integer` + +#### environment + +`environment` + +- is optional +- type: `string` + +##### environment Type + +`string` + +#### state + +`state` + +- is **required** +- type: reference + +##### state Type + +`string` + +The value of this property **must** be equal to one of the [known values below](#ee_set_state-known-values). + +##### state Known Values + +| Value | +| ------ | +| start | +| stop | +| pause | +| resume | + +### Ubus CLI Example + +``` +ubus call swmodules ee_set_state {"state":"stop","eid":3,"environment":"ea anim veniam minim ut"} +``` + +### JSONRPC Example + +```json +{ + "jsonrpc": "2.0", + "id": 0, + "method": "call", + "params": [ + "<SID>", + "swmodules", + "ee_set_state", + { "state": "stop", "eid": 3, "environment": "ea anim veniam minim ut" } + ] +} +``` + +#### output + +`output` + +- is optional +- type: `object` + +##### output Type + +`object` with following properties: + +| Property | Type | Required | +| -------- | ------- | ------------ | +| `reason` | string | **Required** | +| `status` | boolean | **Required** | + +#### reason + +`reason` + +- is **required** +- type: `string` + +##### reason Type + +`string` + +#### status + +`status` + +- is **required** +- type: `boolean` + +##### status Type + +`boolean` + +### Output Example + +```json +{ "status": true, "reason": "ipsum irure id" } +``` + ## environment ### Get list of available environments for software modules @@ -728,6 +873,11 @@ All items must be of the type: Unknown type ``. "status": { "type": "string" }, + "pause": { + "type": "integer", + "minimum": 0, + "maximum": 1 + }, "type": { "type": "string" }, @@ -757,6 +907,7 @@ All items must be of the type: Unknown type ``. "required": [ "name", "status", + "pause", "type", "vendor", "version", @@ -779,6 +930,7 @@ All items must be of the type: Unknown type ``. { "name": "sunt velit eiusmod", "status": "ut dolor ut", + "pause": 1, "type": "deserunt fugiat ea", "vendor": "ipsum irure", "version": "veniam laboris", diff --git a/gitlab-ci/shared.sh b/gitlab-ci/shared.sh index 3a1e13ef224c4da02e9dee34ebb416cdd8e3e644..4d1eec7cbeb099e1ff1b3ff274947305b7799ee3 100644 --- a/gitlab-ci/shared.sh +++ b/gitlab-ci/shared.sh @@ -61,7 +61,7 @@ function check_memory_leak() function build_swmodd() { - SWMOD_LXC=yes CFLAGS="-g -O0 -fprofile-arcs -ftest-coverage" LDFLAGS="--coverage" make + SWMOD_LXC=yes CFLAGS="-g -O0 -fprofile-arcs -ftest-coverage -DBBF_VENDOR_PREFIX=\\\"X_IOPSYS_EU_\\\"" LDFLAGS="--coverage" make check_ret $? mkdir -p /usr/lib/bbfdm/ exec_cmd cp -f libswmodd.so /usr/lib/bbfdm/libswmodd.so diff --git a/schemas/ubus/swmodules.json b/schemas/ubus/swmodules.json index 3b2fdf27c95601258949e3a08b0618005e8966df..7b8a061f1f6bf6bef9ad6c69ea6172bdbdd6b984 100644 --- a/schemas/ubus/swmodules.json +++ b/schemas/ubus/swmodules.json @@ -1,4 +1,15 @@ { + "definitions": { + "ee_state_type_t": { + "type": "string", + "enum": [ + "start", + "stop", + "pause", + "resume" + ] + } + }, "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://dev.iopsys.eu/iopsys/swmodd/schemas/ubus/swmodules.json", "type": "object", @@ -29,6 +40,11 @@ "status": { "type": "string" }, + "pause": { + "type": "integer", + "minimum": 0, + "maximum": 1 + }, "type": { "type": "string" }, @@ -58,6 +74,7 @@ "required": [ "name", "status", + "pause", "type", "vendor", "version", @@ -424,6 +441,47 @@ } } } + }, + "ee_set_state": { + "title": "Change the current state of the Execution Environment", + "type": "object", + "required": [ + "input" + ], + "properties": { + "input": { + "type": "object", + "properties": { + "eid": { + "type": "integer" + }, + "environment": { + "type": "string" + }, + "state": { + "$ref": "#/definitions/ee_state_type_t" + } + }, + "required": [ + "state" + ] + }, + "output": { + "type": "object", + "properties": { + "status": { + "type": "boolean" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "status", + "reason" + ] + } + } } } } diff --git a/src/datamodel.c b/src/datamodel.c index 9742f62e9905ecf076167415ab5117a994d67a90..4caa35a21bd5c6ac682029fa28bb293ffa246016 100644 --- a/src/datamodel.c +++ b/src/datamodel.c @@ -150,6 +150,35 @@ static int get_SoftwareModules_ExecutionUnitNumberOfEntries(char *refparam, stru return 0; } +/*#Device.SoftwareModules.ExecEnv.{i}.X_IOPSYS_EU_Pause!UBUS:swmodules/environment//environment[i-1].pause*/ +static int get_SoftwareModulesExecEnv_X_IOPSYS_EU_Pause(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmjson_get_value((json_object *)data, 1, "pause"); + return 0; +} + +static int set_SoftwareModulesExecEnv_X_IOPSYS_EU_Pause(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *env_name = NULL; + bool b; + + switch (action) { + case VALUECHECK: + if (dm_validate_boolean(value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + env_name = dmjson_get_value((json_object *)data, 1, "name"); + dmubus_call_set("swmodules", "ee_set_state", UBUS_ARGS{ + {"environment", env_name, String}, + {"state", b ? "pause" : "resume", String}}, + 2); + break; + } + return 0; +} + /*#Device.SoftwareModules.ExecEnv.{i}.Enable!UBUS:swmodules/environment//environment[i-1].status*/ static int get_SoftwareModulesExecEnv_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { @@ -171,8 +200,10 @@ static int set_SoftwareModulesExecEnv_Enable(char *refparam, struct dmctx *ctx, case VALUESET: string_to_bool(value, &b); env_name = dmjson_get_value((json_object *)data, 1, "name"); - if (env_name && strcmp(env_name, "OpenWRT_Linux") != 0) - dmcmd_no_wait(b ? "/usr/bin/lxc-start" : "/usr/bin/lxc-stop", 2, "-n", env_name); + dmubus_call_set("swmodules", "ee_set_state", UBUS_ARGS{ + {"environment", env_name, String}, + {"state", b ? "start" : "stop", String}}, + 2); break; } return 0; @@ -876,6 +907,7 @@ DMLEAF tSoftwareModulesParams[] = { DMLEAF tSoftwareModulesExecEnvParams[] = { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ {"Enable", &DMWRITE, DMT_BOOL, get_SoftwareModulesExecEnv_Enable, set_SoftwareModulesExecEnv_Enable, BBFDM_BOTH}, +{BBF_VENDOR_PREFIX"Pause", &DMWRITE, DMT_BOOL, get_SoftwareModulesExecEnv_X_IOPSYS_EU_Pause, set_SoftwareModulesExecEnv_X_IOPSYS_EU_Pause, BBFDM_BOTH}, {"Status", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_Status, NULL, BBFDM_BOTH}, {"Reset", &DMWRITE, DMT_BOOL, get_SoftwareModulesExecEnv_Reset, set_SoftwareModulesExecEnv_Reset, BBFDM_CWMP}, //{"Alias", &DMWRITE, DMT_STRING, get_SoftwareModulesExecEnv_Alias, set_SoftwareModulesExecEnv_Alias, BBFDM_BOTH}, diff --git a/src/swmod.c b/src/swmod.c index 008b974530c4564abc6871a224130774b3492c16..d1938af5ac157e08f17c9b364eb277ad3b11c957 100644 --- a/src/swmod.c +++ b/src/swmod.c @@ -82,6 +82,19 @@ enum { __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 }, @@ -191,6 +204,7 @@ swmod_environment(struct ubus_context *ctx, struct ubus_object *obj, 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); @@ -703,6 +717,72 @@ swmod_eu_activate(struct ubus_context *ctx, struct ubus_object *obj, 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), @@ -711,6 +791,7 @@ static const struct ubus_method swmod_object_methods[] = { 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); diff --git a/src/swmod.h b/src/swmod.h index 50c275632059bc6ecad44fabd1f9e9a7a5abd18f..4d494f0f3fbb7d33c558e620786d08025a15786c 100644 --- a/src/swmod.h +++ b/src/swmod.h @@ -36,6 +36,7 @@ typedef struct { bool exists; char status[32]; //Status + int pause; char name[32]; //Name char type[64]; //Type char vendor[128]; //Vendor diff --git a/src/swmod_host.c b/src/swmod_host.c index 2fffee59265ed546510b812b8c0eb7017030f97d..2e650eb728e6d6b1764e9815b3da5a815271b189 100644 --- a/src/swmod_host.c +++ b/src/swmod_host.c @@ -34,6 +34,7 @@ void populate_host_system_environment(void) { environments[0].exists = true; + environments[0].pause = 0; swmod_strncpy(environments[0].name, HOST_SYSTEM, 14); swmod_strncpy(environments[0].status, "Up", 3); diff --git a/src/swmod_lxc.c b/src/swmod_lxc.c index e975294effe0f83362dfb2dc9f11f652a525dbc4..4edc69f53256f6503916bc1f1931e25b1678e721 100644 --- a/src/swmod_lxc.c +++ b/src/swmod_lxc.c @@ -43,6 +43,50 @@ static char *g_lxc_buff; +enum { + LXC_START, + LXC_STOP, + LXC_PAUSE, + LXC_RESUME, + __LXC_STATE_MAX +}; + +enum { + LXC_SUCCESS, + LXC_FAILURE, + LXC_NOT_SUPPORTED, + LXC_ID_NOT_FOUND, + LXC_ALREADY_RUNNING, + LXC_NOT_RUNNING, + INVALID_REQUEST, + __LXC_ERROR_MAX +}; + +static int get_requested_lxc_state(char *state) +{ + if (strcmp(state, "start") == 0) { + return LXC_START; + } else if (strcmp(state, "stop") == 0) { + return LXC_STOP; + } else if (strcmp(state, "pause") == 0) { + return LXC_PAUSE; + } else if (strcmp(state, "resume") == 0) { + return LXC_RESUME; + } else { + return __LXC_STATE_MAX; + } +} + +char ee_set_state_error_msg[__LXC_ERROR_MAX][60] = { + "", + "internal failure", + "LXC not supported", + "container not found", + "ExecEnv already running", + "ExecEnv not running", + "invalid request" +}; + typedef struct lxc_attach_args { const char *lxcpath; const char *value; @@ -54,6 +98,14 @@ struct service_state { bool state; }; +const char *ee_state_failure_reason(int err) +{ + if (err >= __LXC_ERROR_MAX || err < 0) + return "unknown"; + + return ee_set_state_error_msg[err]; +} + const char *get_lxc_path_from_config(void) { return lxc_get_global_config_item(LXC_PATH); @@ -179,15 +231,22 @@ void populate_lxc_environment(void) for (i = 0; i < lxc_nbr; i++) { struct lxc_container *ct = clist[i]; + bool ct_running = ct->is_running(ct); environments[i+1].exists = true; swmod_strncpy(environments[i+1].name, ct->name, 32); - swmod_strncpy(environments[i+1].status, (ct->is_running(ct)) ? "Up" : "Disabled", 9); + swmod_strncpy(environments[i+1].status, ct_running ? "Up" : "Disabled", 9); + if (ct_running && ((strcmp(ct->state(ct), "FROZEN") == 0) || strcmp(ct->state(ct), "FREEZING") == 0)) { + environments[i+1].pause = 1; + } else { + environments[i+1].pause = 0; + } + swmod_strncpy(environments[i+1].type, "Linux Container", 16); snprintf(cmd, 1024, "/etc/swmod/map_du_%s", ct->name); create_file(cmd); - if (!ct->is_running(ct)) { - PRINT_INFO("lxc container not running"); + if (!ct_running || environments[i+1].pause) { + PRINT_INFO("lxc container not running or frozen"); lxc_container_put(ct); continue; } @@ -637,6 +696,84 @@ static int lxc_attach_service_state_func(void *args) return ubus_call_service_state(st->name, st->state); } +int swmod_set_ee_state(int index, char *state) +{ + int ret = LXC_SUCCESS; + const char *lxcpath = NULL; + int cid = index - 1; + + if (!lxc_is_supported(&lxcpath)) { + return LXC_NOT_SUPPORTED; + } + + struct lxc_container **clist = NULL; + int lxc_nbr; + + lxc_nbr = list_all_containers(lxcpath, NULL, &clist); + + if (cid >= lxc_nbr) { + ret = LXC_ID_NOT_FOUND; + goto end; + } + + struct lxc_container *ct = clist[cid]; + + int req_state = get_requested_lxc_state(state); + + switch (req_state) { + case LXC_START: + if (ct->is_running(ct)) { + ret = LXC_ALREADY_RUNNING; + break; + } + + ret = ct->start(ct, 0, NULL) ? LXC_SUCCESS: LXC_FAILURE; + break; + case LXC_STOP: + if (!ct->is_running(ct)) { + ret = LXC_NOT_RUNNING; + break; + } + + if (strcmp(ct->state(ct), "FROZEN") == 0 || strcmp(ct->state(ct), "FREEZING") == 0) { + /* to stop a frozen container first need to unfreeze it */ + if (!ct->unfreeze(ct)) { + ret = LXC_FAILURE; + break; + } + } + + ret = ct->stop(ct) ? LXC_SUCCESS : LXC_FAILURE; + break; + case LXC_PAUSE: + if (!ct->is_running(ct)) { + ret = LXC_NOT_RUNNING; + break; + } + + ret = ct->freeze(ct) ? LXC_SUCCESS : LXC_FAILURE; + break; + case LXC_RESUME: + if (!ct->is_running(ct)) { + ret = LXC_NOT_RUNNING; + break; + } + + ret = ct->unfreeze(ct) ? LXC_SUCCESS : LXC_FAILURE; + break; + default: + ret = INVALID_REQUEST; + } + + lxc_container_put(ct); + +end: + if (lxc_nbr > 0) + FREE(clist); + + return ret; +} + int swmod_set_lxc_service_state(int index, char *name, bool state) { int ret = -1; diff --git a/src/swmod_lxc.h b/src/swmod_lxc.h index 6379e942799db17636b93bb4195cda5da60a755b..b5d8f19b86ade456a85c2ef1100bf7647a803b58 100644 --- a/src/swmod_lxc.h +++ b/src/swmod_lxc.h @@ -37,5 +37,7 @@ void populate_lxc_eu(void); void get_pid_details_lxc(struct lxc_container *ct, int pid, char *cmdline, int *vsize); int swmod_lxc_copy_file_from_host(int cid, const char *package_path, char *lxc_pkg_path, int size); int swmod_set_lxc_service_state(int index, char *name, bool state); +const char *ee_state_failure_reason(int err); +int swmod_set_ee_state(int index, char *state); #endif //LXC_H diff --git a/src/tools.c b/src/tools.c index 6cf08db25950b3c8c582684aa5f7a1431879c4e4..ae79ac7ecbfd805bf93395d78379bd81bb330606 100644 --- a/src/tools.c +++ b/src/tools.c @@ -51,7 +51,7 @@ static unsigned char gLogLevel = DEFAULT_LOG_LEVEL; // Logging utilities void configure_debug_level(unsigned char level) { - if (level >= LOG_DEBUG) { + if (level > LOG_DEBUG) { fprintf(stderr, "Configured log level %d invalid, setting default level", level); gLogLevel = DEFAULT_LOG_LEVEL; } else { diff --git a/test/api/json/swmodules.validation.json b/test/api/json/swmodules.validation.json index a9f1e70f589164d235a055790bfb485e90ef79a7..7d9a4ada8c8b571f5a53ad3fc5e6dea0340b124f 100644 --- a/test/api/json/swmodules.validation.json +++ b/test/api/json/swmodules.validation.json @@ -379,6 +379,54 @@ "state": false }, "rc": 0 + }, + { + "method": "ee_set_state", + "args": { + "eid": 1, + "environment": "test", + "state": "start" + }, + "rc": 0 + }, + { + "method": "ee_set_state", + "args": { + "environment": "test", + "state": "stop" + }, + "rc": 0 + }, + { + "method": "ee_set_state", + "args": { + "eid": 2, + "state": "pause" + }, + "rc": 0 + }, + { + "method": "ee_set_state", + "args": { + "eid": 2, + "state": "resume" + }, + "rc": 0 + }, + { + "method": "ee_set_state", + "args": { + "eid": 2 + }, + "rc": 2 + }, + { + "method": "ee_set_state", + "args": { + "eid": 2, + "environment": "test" + }, + "rc": 2 } ] }