iSulad/src/config/lcrd_config.c
openeuler-iSula ee41558c0c iSUlad: remove seucrec new
Signed-off-by: openeuler-iSula <isula@huawei.com>
2019-12-29 15:59:28 +08:00

1816 lines
49 KiB
C

/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
* iSulad licensed under the Mulan PSL v1.
* You can use this software according to the terms and conditions of the Mulan PSL v1.
* You may obtain a copy of Mulan PSL v1 at:
* http://license.coscl.org.cn/MulanPSL
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v1 for more details.
* Author: lifeng
* Create: 2018-11-08
* Description: provide container configure definition
******************************************************************************/
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <limits.h>
#include <fcntl.h>
#include <libgen.h>
#include "constants.h"
#include "log.h"
#include "utils.h"
#include "lcrd_config.h"
#include "sysinfo.h"
#include "liblcrd.h"
#define ENGINE_ROOTPATH_NAME "engines"
#define GRAPH_ROOTPATH_NAME "storage"
#define GRAPH_ROOTPATH_CHECKED_FLAG "NEED_CHECK"
#define INCREMENT_INTREVAL 2
#define BUFFER_ITEM_NUMS 10
static struct lcrd_conf g_lcrd_conf;
static double g_jiffy = 0.0;
/* tick to ns */
static inline unsigned long long tick_to_ns(uint64_t tick)
{
#define EPSINON 0.0001
if (g_jiffy < EPSINON && g_jiffy > -EPSINON) {
g_jiffy = (double)sysconf(_SC_CLK_TCK);
}
if ((uint64_t)(tick / g_jiffy) > (UINT64_MAX / Time_Second)) {
return UINT64_MAX;
}
return (uint64_t)((tick / g_jiffy) * Time_Second);
}
/*
* returns the host system's cpu usage in nanoseconds.
* Uses /proc/stat defined by POSIX. Looks for the cpu statistics line
* and then sums up the first seven fields provided.
* See `man 5 proc` for details on specific field information.
*/
int get_system_cpu_usage(uint64_t *val)
{
int ret = 0;
int nret;
unsigned long long total, usertime, nicetime, systemtime, idletime;
unsigned long long ioWait, irq, softIrq, steal, guest, guestnice;
char buffer[BUFSIZ + 1] = { 0 };
char *tmp = NULL;
FILE *file = NULL;
if (val == NULL) {
return -1;
}
file = util_fopen("/proc/stat", "r");
if (file == NULL) {
ERROR("Failed to open '/proc/stat'");
return -1;
}
ioWait = irq = softIrq = steal = guest = guestnice = 0;
/*
* Depending on your kernel version,
* 5, 7, 8 or 9 of these fields will be set.
* The rest will remain at zero.
*/
tmp = fgets(buffer, BUFSIZ, file);
if (tmp == NULL) {
ret = -1;
goto out;
}
nret = sscanf(buffer, "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &usertime,
&nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
if (nret != BUFFER_ITEM_NUMS) {
ERROR("sscanf buffer failed");
ret = -1;
goto out;
}
total = usertime + nicetime + systemtime + idletime + ioWait + irq + softIrq;
*val = tick_to_ns(total);
out:
fclose(file);
return ret;
}
/* lcrd server conf wrlock */
int lcrd_server_conf_wrlock()
{
int ret = 0;
if (pthread_rwlock_wrlock(&g_lcrd_conf.lcrd_conf_rwlock)) {
ERROR("Failed to acquire lcrd conf write lock");
ret = -1;
}
return ret;
}
/* lcrd server conf rdlock */
int lcrd_server_conf_rdlock()
{
int ret = 0;
if (pthread_rwlock_rdlock(&g_lcrd_conf.lcrd_conf_rwlock)) {
ERROR("Failed to acquire lcrd conf read lock");
ret = -1;
}
return ret;
}
/* lcrd server conf unlock */
int lcrd_server_conf_unlock()
{
int ret = 0;
if (pthread_rwlock_unlock(&g_lcrd_conf.lcrd_conf_rwlock)) {
ERROR("Failed to release lcrd conf lock");
ret = -1;
}
return ret;
}
struct service_arguments *conf_get_server_conf()
{
return g_lcrd_conf.server_conf;
}
/* conf get lcrd pidfile */
char *conf_get_lcrd_pidfile()
{
char *filename = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs == NULL || conf->json_confs->pidfile == NULL) {
goto out;
}
filename = util_strdup_s(conf->json_confs->pidfile);
out:
(void)lcrd_server_conf_unlock();
return filename;
}
/* conf get engine rootpath */
char *conf_get_engine_rootpath()
{
char *epath = NULL;
char *rootpath = NULL;
size_t len;
rootpath = conf_get_lcrd_rootdir();
if (rootpath == NULL) {
ERROR("Get rootpath failed");
return epath;
}
if (strlen(rootpath) > (SIZE_MAX - strlen(ENGINE_ROOTPATH_NAME)) - 2) {
ERROR("Root path is too long");
goto free_out;
}
len = strlen(rootpath) + 1 + strlen(ENGINE_ROOTPATH_NAME) + 1;
if (len > PATH_MAX) {
ERROR("The size of path exceeds the limit");
goto free_out;
}
epath = util_common_calloc_s(len);
if (epath == NULL) {
ERROR("Out of memory");
goto free_out;
}
int nret = snprintf(epath, len, "%s/%s", rootpath, ENGINE_ROOTPATH_NAME);
if (nret < 0 || (size_t)nret >= len) {
ERROR("Sprintf engine path failed");
free(epath);
epath = NULL;
}
free_out:
free(rootpath);
return epath;
}
/* conf get graph rootpath */
char *conf_get_graph_rootpath()
{
char *epath = NULL;
char *rootpath = NULL;
size_t len;
rootpath = conf_get_lcrd_rootdir();
if (rootpath == NULL) {
ERROR("Get rootpath failed");
return epath;
}
if (strlen(rootpath) > (SIZE_MAX - strlen(GRAPH_ROOTPATH_NAME)) - 2) {
ERROR("Root path is too long");
goto free_out;
}
len = strlen(rootpath) + 1 + strlen(GRAPH_ROOTPATH_NAME) + 1;
if (len > PATH_MAX) {
ERROR("The size of path exceeds the limit");
goto free_out;
}
epath = util_common_calloc_s(len);
if (epath == NULL) {
ERROR("Out of memory");
goto free_out;
}
int nret = snprintf(epath, len, "%s/%s", rootpath, GRAPH_ROOTPATH_NAME);
if (nret < 0 || (size_t)nret >= len) {
ERROR("Sprintf graph path failed");
free(epath);
epath = NULL;
}
free_out:
free(rootpath);
return epath;
}
/* conf get graph checked flag file path */
char *conf_get_graph_check_flag_file()
{
char *epath = NULL;
char *rootpath = NULL;
size_t len;
rootpath = conf_get_lcrd_rootdir();
if (rootpath == NULL) {
ERROR("Get rootpath failed");
return epath;
}
if (strlen(rootpath) > ((SIZE_MAX - strlen(GRAPH_ROOTPATH_NAME)) - strlen(GRAPH_ROOTPATH_CHECKED_FLAG)) - 3) {
ERROR("Root path is too long");
goto free_out;
}
len = strlen(rootpath) + 1 + strlen(GRAPH_ROOTPATH_NAME) + 1 + strlen(GRAPH_ROOTPATH_CHECKED_FLAG) + 1;
if (len > PATH_MAX) {
ERROR("The size of path exceeds the limit");
goto free_out;
}
epath = util_common_calloc_s(len);
if (epath == NULL) {
ERROR("Out of memory");
goto free_out;
}
int nret = snprintf(epath, len, "%s/%s/%s", rootpath, GRAPH_ROOTPATH_NAME, GRAPH_ROOTPATH_CHECKED_FLAG);
if (nret < 0 || (size_t)nret >= len) {
ERROR("Sprintf graph checked flag failed");
free(epath);
epath = NULL;
}
free_out:
free(rootpath);
return epath;
}
/* conf get graph run path */
char *conf_get_graph_run_path()
{
char *epath = NULL;
char *rootpath = NULL;
size_t len;
rootpath = conf_get_lcrd_statedir();
if (rootpath == NULL) {
ERROR("Get rootpath failed");
return epath;
}
if (strlen(rootpath) > (SIZE_MAX - strlen(GRAPH_ROOTPATH_NAME)) - 2) {
ERROR("Root path is too long");
goto free_out;
}
len = strlen(rootpath) + 1 + strlen(GRAPH_ROOTPATH_NAME) + 1;
if (len > PATH_MAX) {
ERROR("The size of path exceeds the limit");
goto free_out;
}
epath = util_common_calloc_s(len);
if (epath == NULL) {
ERROR("Out of memory");
goto free_out;
}
int nret = snprintf(epath, len, "%s/%s", rootpath, GRAPH_ROOTPATH_NAME);
if (nret < 0 || (size_t)nret >= len) {
ERROR("Sprintf graph run path failed");
free(epath);
epath = NULL;
}
free_out:
free(rootpath);
return epath;
}
/* conf get routine rootdir */
char *conf_get_routine_rootdir(const char *runtime)
{
char *path = NULL;
struct service_arguments *conf = NULL;
size_t len = 0;
if (runtime == NULL) {
ERROR("Runtime is NULL");
return NULL;
}
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->graph == NULL) {
ERROR("Server conf is NULL or rootpath is NULL");
goto out;
}
/* path = conf->rootpath + / + engines + / + runtime + /0 */
if (strlen(conf->json_confs->graph) > (SIZE_MAX - strlen(ENGINE_ROOTPATH_NAME)) - 3) {
ERROR("Graph path is too long");
goto out;
}
len = strlen(conf->json_confs->graph) + 1 + strlen(ENGINE_ROOTPATH_NAME) + 1 + strlen(runtime) + 1;
if (len > PATH_MAX / sizeof(char)) {
ERROR("The size of path exceeds the limit");
goto out;
}
path = util_common_calloc_s(sizeof(char) * len);
if (path == NULL) {
ERROR("Out of memory");
goto out;
}
int nret = snprintf(path, len, "%s/%s/%s", conf->json_confs->graph, ENGINE_ROOTPATH_NAME, runtime);
if (nret < 0 || (size_t)nret >= len) {
ERROR("Failed to sprintf path");
free(path);
path = NULL;
}
out:
(void)lcrd_server_conf_unlock();
return path;
}
/* conf get routine statedir */
char *conf_get_routine_statedir(const char *runtime)
{
char *path = NULL;
struct service_arguments *conf = NULL;
size_t len = 0;
if (runtime == NULL) {
return NULL;
}
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->state == NULL) {
goto out;
}
/* path = conf->statepath + / + runtime + /0 */
if (strlen(conf->json_confs->state) > (SIZE_MAX - strlen(runtime)) - 2) {
ERROR("State path is too long");
goto out;
}
len = strlen(conf->json_confs->state) + 1 + strlen(runtime) + 1;
if (len > PATH_MAX) {
goto out;
}
path = util_common_calloc_s(sizeof(char) * len);
if (path == NULL) {
goto out;
}
int nret = snprintf(path, len, "%s/%s", conf->json_confs->state, runtime);
if (nret < 0 || (size_t)nret >= len) {
ERROR("sprintf path failed");
free(path);
path = NULL;
}
out:
(void)lcrd_server_conf_unlock();
return path;
}
/* conf get lcrd rootdir */
char *conf_get_lcrd_rootdir()
{
char *path = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->graph == NULL) {
goto out;
}
path = util_strdup_s(conf->json_confs->graph);
out:
(void)lcrd_server_conf_unlock();
return path;
}
#ifdef ENABLE_OCI_IMAGE
/* conf get graph driver */
char *conf_get_lcrd_storage_driver()
{
char *driver = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->driver->name == NULL) {
goto out;
}
driver = util_strdup_s(conf->driver->name);
out:
(void)lcrd_server_conf_unlock();
return driver;
}
/* conf get graph driver */
char *conf_get_lcrd_storage_driver_backing_fs()
{
char *fs = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->driver->backing_fs == NULL) {
goto out;
}
fs = util_strdup_s(conf->driver->backing_fs);
out:
(void)lcrd_server_conf_unlock();
return fs;
}
/* conf get graph driver opts */
char **conf_get_storage_opts()
{
int nret = 0;
size_t i;
char **opts = NULL;
char *p = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->storage_opts == NULL) {
goto out;
}
for (i = 0; i < conf->json_confs->storage_opts_len; i++) {
p = conf->json_confs->storage_opts[i];
if (p == NULL) {
goto out;
}
nret = util_array_append(&opts, p);
if (nret != 0) {
ERROR("Out of memory");
goto out_free;
}
}
out_free:
if (nret != 0) {
util_free_array(opts);
opts = NULL;
}
out:
(void)lcrd_server_conf_unlock();
return opts;
}
#endif
/* conf get registry */
char **conf_get_registry_list()
{
int nret = 0;
size_t i;
char **opts = NULL;
char *p = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->registry_mirrors_len == 0) {
goto out;
}
for (i = 0; i < conf->json_confs->registry_mirrors_len; i++) {
p = conf->json_confs->registry_mirrors[i];
if (p == NULL) {
break;
}
nret = util_array_append(&opts, p);
if (nret != 0) {
ERROR("Out of memory");
util_free_array(opts);
opts = NULL;
goto out;
}
}
out:
(void)lcrd_server_conf_unlock();
return opts;
}
/* conf get insecure registry */
char **conf_get_insecure_registry_list()
{
int nret = 0;
size_t i;
char **opts = NULL;
char *p = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->insecure_registries_len == 0) {
goto out;
}
for (i = 0; i < conf->json_confs->insecure_registries_len; i++) {
p = conf->json_confs->insecure_registries[i];
if (p == NULL) {
break;
}
nret = util_array_append(&opts, p);
if (nret != 0) {
util_free_array(opts);
opts = NULL;
ERROR("Out of memory");
break;
}
}
out:
(void)lcrd_server_conf_unlock();
return opts;
}
/* conf get lcrd statedir */
char *conf_get_lcrd_statedir()
{
char *path = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->state == NULL) {
goto out;
}
path = util_strdup_s(conf->json_confs->state);
out:
(void)lcrd_server_conf_unlock();
return path;
}
/* conf get lcrd mount rootfs */
char *conf_get_lcrd_mount_rootfs()
{
char *path = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->rootfsmntdir == NULL) {
goto out;
}
path = util_strdup_s(conf->json_confs->rootfsmntdir);
out:
(void)lcrd_server_conf_unlock();
return path;
}
/* conf get lcrd umask for containers */
char *conf_get_lcrd_native_umask()
{
char *umask = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->native_umask == NULL) {
goto out;
}
umask = util_strdup_s(conf->json_confs->native_umask);
out:
(void)lcrd_server_conf_unlock();
return umask;
}
/* conf get lcrd cgroup parent for containers */
char *conf_get_lcrd_cgroup_parent()
{
char *cgroup_parent = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->cgroup_parent == NULL) {
goto out;
}
cgroup_parent = util_strdup_s(conf->json_confs->cgroup_parent);
out:
(void)lcrd_server_conf_unlock();
return cgroup_parent;
}
/* conf get lcrd engine */
char *conf_get_lcrd_engine()
{
char *engine = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->engine == NULL) {
goto out;
}
engine = util_strdup_s(conf->json_confs->engine);
out:
(void)lcrd_server_conf_unlock();
return engine;
}
/* conf get lcrd loglevel */
char *conf_get_lcrd_loglevel()
{
char *loglevel = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->log_level == NULL) {
goto out;
}
loglevel = util_strdup_s(conf->json_confs->log_level);
out:
(void)lcrd_server_conf_unlock();
return loglevel;
}
/* get log file helper */
char *get_log_file_helper(const struct service_arguments *conf, const char *suffix)
{
char *logfile = NULL;
size_t len = 0;
int nret = 0;
if (suffix == NULL) {
return NULL;
}
// log_file path = parent path + "/" + suffix
if (strlen(conf->logpath) > (SIZE_MAX - strlen(suffix)) - 2) {
ERROR("Log path is too long");
return NULL;
}
len = strlen(conf->logpath) + 1 + strlen(suffix) + 1;
if (len > PATH_MAX) {
ERROR("The size of path exceeds the limit");
return NULL;
}
logfile = util_common_calloc_s(len * sizeof(char));
if (logfile == NULL) {
ERROR("Out of memory");
goto out;
}
nret = snprintf(logfile, len, "%s/%s", conf->logpath, suffix);
if (nret < 0 || (size_t)nret >= len) {
free(logfile);
logfile = NULL;
ERROR("Failed to sprintf log path");
}
out:
return logfile;
}
/* conf get lcrd log gather fifo path */
char *conf_get_lcrd_log_gather_fifo_path()
{
char *logfile = NULL;
char *statedir = NULL;
size_t len = 0;
int nret;
statedir = conf_get_lcrd_statedir();
if (statedir == NULL) {
ERROR("Get lcrd statedir failed");
goto err_out;
}
if (strlen(statedir) > (SIZE_MAX - strlen("/lcrd_log_gather_fifo")) - 1) {
ERROR("State path is too long");
goto err_out;
}
len = strlen(statedir) + strlen("/lcrd_log_gather_fifo") + 1;
if (len > PATH_MAX) {
ERROR("Too long path: %s", statedir);
goto err_out;
}
logfile = util_common_calloc_s(len);
if (logfile == NULL) {
ERROR("Out of memory");
goto err_out;
}
nret = snprintf(logfile, len, "%s%s", statedir, "/lcrd_log_gather_fifo");
if (nret < 0 || (size_t)nret >= len) {
ERROR("Sprintf log file failed");
goto err_out;
}
goto out;
err_out:
free(logfile);
logfile = NULL;
out:
free(statedir);
return logfile;
}
/* conf get lcrd log file */
char *conf_get_lcrd_log_file()
{
char *logfile = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->logpath == NULL) {
goto out;
}
logfile = get_log_file_helper(conf, "lcrd.log");
out:
(void)lcrd_server_conf_unlock();
return logfile;
}
/* conf get engine log file */
char *conf_get_engine_log_file()
{
char *logfile = NULL;
char *full_path = NULL;
char *prefix = "fifo:";
size_t len = 0;
logfile = conf_get_lcrd_log_gather_fifo_path();
if (logfile == NULL) {
ERROR("conf_get_lcrd_log_gather_fifo_path failed");
goto out;
}
len = strlen(prefix) + strlen(logfile) + 1;
if (len > PATH_MAX) {
ERROR("The size of path exceeds the limit");
goto out;
}
full_path = util_common_calloc_s(len * sizeof(char));
if (full_path == NULL) {
FATAL("Out of Memory");
goto out;
}
int nret = snprintf(full_path, len, "%s%s", prefix, logfile);
if (nret < 0 || (size_t)nret >= len) {
ERROR("Failed to sprintf engine log path");
free(full_path);
full_path = NULL;
goto out;
}
out:
free(logfile);
return full_path;
}
int conf_get_daemon_log_config(char **loglevel, char **logdriver, char **engine_log_path)
{
*loglevel = conf_get_lcrd_loglevel();
if (*loglevel == NULL) {
ERROR("DoStart: Failed to get log level");
return -1;
}
*logdriver = conf_get_lcrd_logdriver();
if (*logdriver == NULL) {
ERROR("DoStart: Failed to get log driver");
return -1;
}
*engine_log_path = conf_get_engine_log_file();
if (strcmp(*logdriver, "file") == 0 && *engine_log_path == NULL) {
ERROR("DoStart: Log driver is file, but engine log path is NULL");
return -1;
}
return 0;
}
/* conf get lcrd logdriver */
char *conf_get_lcrd_logdriver()
{
char *logdriver = NULL;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->log_driver == NULL) {
goto out;
}
logdriver = util_strdup_s(conf->json_confs->log_driver);
out:
(void)lcrd_server_conf_unlock();
return logdriver;
}
/* conf get image layer check flag */
bool conf_get_image_layer_check_flag()
{
bool check_flag = false;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return false;
}
conf = conf_get_server_conf();
if (conf == NULL) {
goto out;
}
check_flag = conf->json_confs->image_layer_check;
out:
(void)lcrd_server_conf_unlock();
return check_flag;
}
/* conf get flag of use decrypted key to pull image */
bool conf_get_use_decrypted_key_flag()
{
bool check_flag = true;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return false;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs->use_decrypted_key == NULL) {
goto out;
}
check_flag = *(conf->json_confs->use_decrypted_key);
out:
(void)lcrd_server_conf_unlock();
return check_flag;
}
bool conf_get_skip_insecure_verify_flag()
{
bool check_flag = false;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return false;
}
conf = conf_get_server_conf();
if (conf == NULL) {
goto out;
}
check_flag = conf->json_confs->insecure_skip_verify_enforce;
out:
(void)lcrd_server_conf_unlock();
return check_flag;
}
#define OCI_STR_ARRAY_DUP(src, dest, srclen, destlen, ret) \
do { \
if ((src) != NULL) { \
(dest) = str_array_dup((const char **)(src), (srclen)); \
if ((dest) == NULL) { \
(ret) = -1; \
goto out; \
} \
(destlen) = (srclen); \
} \
} while (0)
#define HOOKS_ELEM_DUP_DEF(item) \
defs_hook *hooks_##item##_elem_dup(const defs_hook *src) \
{ \
int ret = 0; \
defs_hook *dest = NULL; \
if (src == NULL) \
return NULL; \
dest = util_common_calloc_s(sizeof(defs_hook)); \
if (dest == NULL) \
return NULL; \
dest->path = util_strdup_s(src->path); \
OCI_STR_ARRAY_DUP(src->args, dest->args, src->args_len, dest->args_len, ret); \
OCI_STR_ARRAY_DUP(src->env, dest->env, src->env_len, dest->env_len, ret); \
dest->timeout = src->timeout; \
out: \
if (ret != 0 && dest != NULL) { \
free_defs_hook(dest); \
dest = NULL; \
} \
return dest; \
}
/* HOOKS ELEM DUP DEF */
HOOKS_ELEM_DUP_DEF(prestart)
/* HOOKS ELEM DUP DEF */
HOOKS_ELEM_DUP_DEF(poststart)
/* HOOKS ELEM DUP DEF */
HOOKS_ELEM_DUP_DEF(poststop)
#define HOOKS_ITEM_DUP_DEF(item) \
int hooks_##item##_dup(oci_runtime_spec_hooks *dest, const oci_runtime_spec_hooks *src) \
{ \
int i = 0; \
if (src->item##_len > SIZE_MAX / sizeof(defs_hook *) - 1) { \
return -1; \
} \
dest->item = util_common_calloc_s(sizeof(defs_hook *) * (src->item##_len + 1)); \
if (dest->item == NULL) \
return -1; \
dest->item##_len = src->item##_len; \
for (; (size_t)i < src->item##_len; ++i) { \
dest->item[i] = hooks_##item##_elem_dup(src->item[i]); \
if (dest->item[i] == NULL) \
return -1; \
} \
return 0; \
}
/* HOOKS ITEM DUP DEF */
HOOKS_ITEM_DUP_DEF(prestart)
/* HOOKS ITEM DUP DEF */
HOOKS_ITEM_DUP_DEF(poststart)
/* HOOKS ITEM DUP DEF */
HOOKS_ITEM_DUP_DEF(poststop)
/* hooks_dup */
oci_runtime_spec_hooks *hooks_dup(const oci_runtime_spec_hooks *src)
{
int ret = 0;
oci_runtime_spec_hooks *dest = NULL;
if (src == NULL) {
return NULL;
}
dest = util_common_calloc_s(sizeof(oci_runtime_spec_hooks));
if (dest == NULL) {
return NULL;
}
ret = hooks_prestart_dup(dest, src);
if (ret != 0) {
goto out;
}
ret = hooks_poststart_dup(dest, src);
if (ret != 0) {
goto out;
}
ret = hooks_poststop_dup(dest, src);
out:
if (ret != 0) {
free_oci_runtime_spec_hooks(dest);
dest = NULL;
}
return dest;
}
/* conf get lcrd hooks */
int conf_get_lcrd_hooks(oci_runtime_spec_hooks **phooks)
{
int ret = 0;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return -1;
}
conf = conf_get_server_conf();
if (conf != NULL && conf->hooks != NULL) {
*phooks = hooks_dup(conf->hooks);
if ((*phooks) == NULL) {
ret = -1;
goto out;
}
} else {
*phooks = NULL;
}
out:
(void)lcrd_server_conf_unlock();
return ret;
}
/* conf get lcrd default ulimit */
int conf_get_lcrd_default_ulimit(host_config_ulimits_element ***ulimit)
{
int ret = 0;
size_t i, ulimit_len;
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return -1;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->default_ulimit_len == 0) {
*ulimit = NULL;
goto out;
}
for (i = 0; i < conf->default_ulimit_len; i++) {
ulimit_len = ulimit_array_len(*ulimit);
if (ulimit_array_append(ulimit, conf->default_ulimit[i], ulimit_len) != 0) {
ERROR("ulimit append failed");
ret = -1;
goto out;
}
}
out:
(void)lcrd_server_conf_unlock();
return ret;
}
/* conf get start timeout */
unsigned int conf_get_start_timeout()
{
struct service_arguments *conf = NULL;
unsigned int ret = 0;
if (lcrd_server_conf_rdlock() != 0) {
return 0;
}
conf = conf_get_server_conf();
if (conf == NULL) {
goto out;
}
ret = conf->start_timeout;
out:
(void)lcrd_server_conf_unlock();
return ret;
}
/* conf get image opt timeout */
unsigned int conf_get_im_opt_timeout()
{
struct service_arguments *conf = NULL;
unsigned int ret = 0;
if (lcrd_server_conf_rdlock() != 0) {
return 0;
}
conf = conf_get_server_conf();
if (conf == NULL) {
goto out;
}
ret = conf->image_opt_timeout;
out:
(void)lcrd_server_conf_unlock();
return ret;
}
char *conf_get_im_server_sock_addr()
{
struct service_arguments *conf = NULL;
char *result = NULL;
if (lcrd_server_conf_rdlock() != 0) {
ERROR("BUG conf_rdlock failed");
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs == NULL) {
goto out;
}
result = util_strdup_s(conf->json_confs->image_server_sock_addr);
out:
(void)lcrd_server_conf_unlock();
return result;
}
bool conf_update_im_server_sock_addr(const char *new_sock_addr)
{
struct service_arguments *conf = NULL;
bool result = true;
if (new_sock_addr == NULL) {
return false;
}
if (lcrd_server_conf_rdlock() != 0) {
ERROR("BUG conf_rdlock failed");
return false;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs == NULL) {
result = false;
goto out;
}
free(conf->json_confs->image_server_sock_addr);
conf->json_confs->image_server_sock_addr = util_strdup_s(new_sock_addr);
out:
(void)lcrd_server_conf_unlock();
return result;
}
char *conf_get_enable_plugins()
{
struct service_arguments *conf = NULL;
char *plugins = NULL;
if (lcrd_server_conf_rdlock() != 0) {
ERROR("BUG conf_rdlock failed");
return NULL;
}
conf = conf_get_server_conf();
if (conf == NULL || conf->json_confs == NULL || conf->json_confs->enable_plugins == NULL) {
goto out;
}
plugins = util_strdup_s(conf->json_confs->enable_plugins);
out:
(void)lcrd_server_conf_unlock();
return plugins;
}
/* save args to conf */
int save_args_to_conf(struct service_arguments *args)
{
int ret = 0;
ret = pthread_rwlock_init(&g_lcrd_conf.lcrd_conf_rwlock, NULL);
if (ret != 0) {
ERROR("Failed to init lcrd conf rwlock");
ret = -1;
goto out;
}
if (pthread_rwlock_wrlock(&g_lcrd_conf.lcrd_conf_rwlock) != 0) {
ERROR("Failed to acquire lcrd conf write lock");
ret = -1;
goto out;
}
if (g_lcrd_conf.server_conf != NULL) {
service_arguments_free(g_lcrd_conf.server_conf);
free(g_lcrd_conf.server_conf);
}
g_lcrd_conf.server_conf = args;
if (pthread_rwlock_unlock(&g_lcrd_conf.lcrd_conf_rwlock) != 0) {
ERROR("Failed to release lcrd conf write lock");
ret = -1;
goto out;
}
out:
return ret;
}
/* set path group */
static int set_path_group(const char *rpath, const char *group)
{
struct group *grp = NULL;
gid_t gid;
grp = getgrnam(group);
if (grp != NULL) {
gid = grp->gr_gid;
DEBUG("Group %s found, gid: %d", group, gid);
if (chown(rpath, -1, gid) != 0) {
DEBUG("Failed to chown %s to gid: %d", rpath, gid);
return -1;
}
} else {
if (strcmp(group, "docker") == 0 || strcmp(group, "lcrd") == 0) {
DEBUG("Warning: could not change group %s to %s", rpath, group);
} else {
lcrd_set_error_message("Group %s not found", group);
return -1;
}
}
return 0;
}
/* set socket group */
int set_unix_socket_group(const char *socket, const char *group)
{
const char *path = NULL;
char rpath[PATH_MAX + 1] = { 0x00 };
int ret = 0;
int nret = 0;
if (socket == NULL || group == NULL) {
return -1;
}
path = socket + strlen(UNIX_SOCKET_PREFIX);
if (strlen(path) > PATH_MAX || realpath(path, rpath) == NULL) {
ERROR("ensure socket path %s failed", path);
ret = -1;
goto out;
}
nret = set_path_group(rpath, group);
if (nret < 0) {
ERROR("set group of the path: %s failed", rpath);
ret = -1;
goto out;
}
if (chmod(rpath, SOCKET_GROUP_DIRECTORY_MODE) != 0) {
DEBUG("Failed to chmod for socket: %s", rpath);
ret = -1;
goto out;
}
out:
if (ret == 0) {
DEBUG("Listener created for HTTP on unix (%s)", rpath);
}
return ret;
}
/* maybe create cpu realtime file */
static int maybe_create_cpu_realtime_file(bool present, int64_t value, const char *file, const char *path)
{
int ret;
int fd = 0;
ssize_t nwrite;
char fpath[PATH_MAX] = { 0 };
char buf[LCRD_NUMSTRLEN64] = { 0 };
if (!present || value == 0) {
return 0;
}
ret = util_mkdir_p(path, CONFIG_DIRECTORY_MODE);
if (ret != 0) {
ERROR("Failed to mkdir: %s", path);
return -1;
}
int nret = snprintf(fpath, sizeof(fpath), "%s/%s", path, file);
if (nret < 0 || nret >= sizeof(fpath)) {
ERROR("Failed to print string");
return -1;
}
nret = snprintf(buf, sizeof(buf), "%lld", (long long int)value);
if (nret < 0 || (size_t)nret >= sizeof(buf)) {
ERROR("Failed to print string");
return -1;
}
fd = util_open(fpath, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0700);
if (fd < 0) {
ERROR("Failed to open file: %s: %s", fpath, strerror(errno));
lcrd_set_error_message("Failed to open file: %s: %s", fpath, strerror(errno));
return -1;
}
nwrite = util_write_nointr(fd, buf, strlen(buf));
if (nwrite < 0) {
ERROR("Failed to write %s to %s: %s", buf, fpath, strerror(errno));
lcrd_set_error_message("Failed to write '%s' to '%s': %s", buf, fpath, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
static int get_cgroup_cpu_rt(int64_t *cpu_rt_period, int64_t *cpu_rt_runtime)
{
struct service_arguments *conf = NULL;
if (lcrd_server_conf_rdlock() != 0) {
return -1;
}
conf = conf_get_server_conf();
if (conf == NULL) {
(void)lcrd_server_conf_unlock();
return -1;
}
*cpu_rt_period = conf->json_confs->cpu_rt_period;
*cpu_rt_runtime = conf->json_confs->cpu_rt_runtime;
if (lcrd_server_conf_unlock() != 0) {
return -1;
}
return 0;
}
static int recursively_create_cgroup(const char *path, int recursive_depth, int64_t cpu_rt_period,
int64_t cpu_rt_runtime)
{
int ret = 0;
sysinfo_t *sysinfo = NULL;
char *dup = NULL;
char *dirpath = NULL;
char *mnt = NULL;
char *root = NULL;
char fpath[PATH_MAX] = { 0 };
dup = util_strdup_s(path);
dirpath = dirname(dup);
ret = init_cgroups_path(dirpath, (recursive_depth + 1));
free(dup);
if (ret != 0) {
return ret;
}
ret = find_cgroup_mountpoint_and_root("cpu", &mnt, &root);
if (ret != 0 || mnt == NULL || root == NULL) {
ERROR("Can not find cgroup mnt and root path for subsystem 'cpu'");
lcrd_set_error_message("Can not find cgroup mnt and root path for subsystem 'cpu'");
ret = -1;
goto out;
}
// When iSulad is run inside iSulad/docker, the root is based of the host cgroup.
// Replace root to "/"
if (strncmp(root, "/lxc/", strlen("/lxc/")) != 0) {
root[1] = '\0';
}
int nret = snprintf(fpath, sizeof(fpath), "%s/%s/%s", mnt, root, path);
if (nret < 0 || (size_t)nret >= sizeof(fpath)) {
ERROR("Failed to print string");
ret = -1;
goto out;
}
sysinfo = get_sys_info(true);
if (sysinfo == NULL) {
ERROR("Can not get system info");
ret = -1;
goto out;
}
ret = maybe_create_cpu_realtime_file(sysinfo->cgcpuinfo.cpu_rt_period, cpu_rt_period, "cpu.rt_period_us", fpath);
if (ret != 0) {
goto out;
}
ret = maybe_create_cpu_realtime_file(sysinfo->cgcpuinfo.cpu_rt_runtime, cpu_rt_runtime, "cpu.rt_runtime_us", fpath);
if (ret != 0) {
goto out;
}
out:
free(mnt);
free(root);
free_sysinfo(sysinfo);
return ret;
}
/* init cgroups path */
int init_cgroups_path(const char *path, int recursive_depth)
{
int64_t cpu_rt_period = 0;
int64_t cpu_rt_runtime = 0;
if ((recursive_depth + 1) > MAX_PATH_DEPTH) {
ERROR("Reach the max cgroup depth:%s", path);
return -1;
}
if (path == NULL || strcmp(path, "/") == 0 || strcmp(path, ".") == 0) {
return 0;
}
if (get_cgroup_cpu_rt(&cpu_rt_period, &cpu_rt_runtime)) {
return -1;
}
if (cpu_rt_period == 0 && cpu_rt_runtime == 0) {
return 0;
}
// Recursively create cgroup to ensure that the system and all parent cgroups have values set
// for the period and runtime as this limits what the children can be set to.
if (recursively_create_cgroup(path, recursive_depth, cpu_rt_period, cpu_rt_runtime)) {
return -1;
}
return 0;
}
#define OVERRIDE_STRING_VALUE(dst, src) \
do { \
if ((src) != NULL && strlen((src)) != 0) { \
free((dst)); \
(dst) = (src); \
(src) = NULL; \
} \
} while (0)
static int string_array_append(char **suffix, size_t suffix_len, size_t *curr_len, char ***result)
{
if (suffix_len > 0) {
size_t new_len = *curr_len + suffix_len;
size_t work_len = *curr_len;
size_t i, j;
if (util_grow_array(result, &work_len, new_len, INCREMENT_INTREVAL) != 0) {
return -1;
}
for (i = *curr_len, j = 0; i < new_len; i++) {
(*result)[i] = suffix[j];
suffix[j++] = NULL;
}
*curr_len = new_len;
}
return 0;
}
int parse_log_opts(struct service_arguments *args, const char *key, const char *value)
{
int ret = -1;
if (key == NULL || value == NULL) {
return 0;
}
// support new driver options, add here
if (strcmp(key, "log-path") == 0) {
free(args->logpath);
args->logpath = util_strdup_s(value);
ret = 0;
} else if (strcmp(key, "log-file-mode") == 0) {
unsigned int file_mode = 0;
if (util_safe_uint(value, &file_mode) == 0) {
args->log_file_mode = file_mode;
ret = 0;
}
} else if (strcmp(key, "max-file") == 0) {
int tmaxfile = 0;
if (util_safe_int(value, &tmaxfile) == 0 && tmaxfile > 0) {
args->max_file = tmaxfile;
ret = 0;
}
} else if (strcmp(key, "max-size") == 0) {
int64_t tmaxsize = 0;
if (util_parse_byte_size_string(value, &tmaxsize) == 0 && tmaxsize > 0) {
args->max_size = tmaxsize;
ret = 0;
}
} else {
ERROR("Invalid config: %s = %s", key, value);
}
return ret;
}
static inline void override_string_value(char **dst, char **src)
{
if (*src == NULL || (*src)[0] == '\0') {
return;
}
free(*dst);
*dst = *src;
*src = NULL;
}
static inline void override_bool_pointer_value(bool **dst, bool **src)
{
if (*src == NULL) {
return;
}
free(*dst);
*dst = *src;
*src = NULL;
}
static int merge_hosts_conf_into_global(struct service_arguments *args,
const isulad_daemon_configs *tmp_json_confs)
{
size_t i, j;
for (i = 0; i < tmp_json_confs->hosts_len; i++) {
for (j = 0; j < args->json_confs->hosts_len; j++) {
if (strcmp(args->json_confs->hosts[j], tmp_json_confs->hosts[i]) == 0) {
break;
}
}
if (j != args->json_confs->hosts_len) {
continue;
}
if (util_array_append(&(args->json_confs->hosts), tmp_json_confs->hosts[i]) != 0) {
ERROR("merge hosts config failed");
return -1;
}
args->json_confs->hosts_len++;
if (args->json_confs->hosts_len > MAX_HOSTS) {
lcrd_set_error_message("Too many hosts, the max number is %d", MAX_HOSTS);
return -1;
}
}
return 0;
}
static int merge_logs_conf_into_global(struct service_arguments *args, isulad_daemon_configs *tmp_json_confs)
{
size_t i;
override_string_value(&args->json_confs->log_level, &tmp_json_confs->log_level);
override_string_value(&args->json_confs->log_driver, &tmp_json_confs->log_driver);
for (i = 0; tmp_json_confs->log_opts != NULL && i < tmp_json_confs->log_opts->len; i++) {
if (parse_log_opts(args, tmp_json_confs->log_opts->keys[i], tmp_json_confs->log_opts->values[i]) != 0) {
COMMAND_ERROR("Failed to parse log options %s:%s", tmp_json_confs->log_opts->keys[i],
tmp_json_confs->log_opts->values[i]);
return -1;
}
if (append_json_map_string_string(args->json_confs->log_opts, tmp_json_confs->log_opts->keys[i],
tmp_json_confs->log_opts->values[i]) != 0) {
ERROR("Out of memory");
return -1;
}
}
return 0;
}
static int merge_authorization_conf_into_global(struct service_arguments *args, isulad_daemon_configs *tmp_json_confs)
{
args->json_confs->tls = tmp_json_confs->tls;
args->json_confs->tls_verify = tmp_json_confs->tls_verify;
if (tmp_json_confs->tls_config != NULL) {
override_string_value(&args->json_confs->tls_config->ca_file, &tmp_json_confs->tls_config->ca_file);
override_string_value(&args->json_confs->tls_config->cert_file, &tmp_json_confs->tls_config->cert_file);
override_string_value(&args->json_confs->tls_config->key_file, &tmp_json_confs->tls_config->key_file);
}
if (tmp_json_confs->authorization_plugin != NULL) {
override_string_value(&args->json_confs->authorization_plugin, &tmp_json_confs->authorization_plugin);
}
return 0;
}
static int merge_storage_conf_into_global(struct service_arguments *args, isulad_daemon_configs *tmp_json_confs)
{
override_string_value(&args->json_confs->storage_driver, &tmp_json_confs->storage_driver);
if (string_array_append(tmp_json_confs->storage_opts, tmp_json_confs->storage_opts_len,
&(args->json_confs->storage_opts_len), &(args->json_confs->storage_opts)) != 0) {
ERROR("merge graph config failed");
return -1;
}
return 0;
}
static int merge_registry_conf_into_global(struct service_arguments *args, isulad_daemon_configs *tmp_json_confs)
{
if (string_array_append(tmp_json_confs->registry_mirrors, tmp_json_confs->registry_mirrors_len,
&(args->json_confs->registry_mirrors_len), &(args->json_confs->registry_mirrors)) != 0) {
ERROR("merge registry mirrors config failed");
return -1;
}
if (string_array_append(tmp_json_confs->insecure_registries, tmp_json_confs->insecure_registries_len,
&(args->json_confs->insecure_registries_len),
&(args->json_confs->insecure_registries)) != 0) {
ERROR("merge insecure registries config failed");
return -1;
}
return 0;
}
static int merge_default_ulimits_conf_into_global(struct service_arguments *args,
isulad_daemon_configs *tmp_json_confs)
{
if (tmp_json_confs == NULL) {
return -1;
}
if (tmp_json_confs->default_ulimits == NULL) {
return 0;
}
args->json_confs->default_ulimits = tmp_json_confs->default_ulimits;
tmp_json_confs->default_ulimits = NULL;
return 0;
}
int merge_json_confs_into_global(struct service_arguments *args)
{
isulad_daemon_configs *tmp_json_confs;
parser_error err = NULL;
int ret = 0;
tmp_json_confs = isulad_daemon_configs_parse_file(ISULAD_DAEMON_JSON_CONF_FILE, NULL, &err);
if (tmp_json_confs == NULL) {
COMMAND_ERROR("Load isulad json config failed: %s", err != NULL ? err : "");
ret = -1;
goto out;
}
// Daemon socket option
if (merge_hosts_conf_into_global(args, tmp_json_confs)) {
ret = -1;
goto out;
}
override_string_value(&args->json_confs->group, &tmp_json_confs->group);
override_string_value(&args->json_confs->graph, &tmp_json_confs->graph);
override_string_value(&args->json_confs->state, &tmp_json_confs->state);
if (merge_logs_conf_into_global(args, tmp_json_confs)) {
ret = -1;
goto out;
}
override_string_value(&args->json_confs->pidfile, &tmp_json_confs->pidfile);
// iSulad runtime execution options
override_string_value(&args->json_confs->engine, &tmp_json_confs->engine);
override_string_value(&args->json_confs->hook_spec, &tmp_json_confs->hook_spec);
override_string_value(&args->json_confs->enable_plugins, &tmp_json_confs->enable_plugins);
override_string_value(&args->json_confs->native_umask, &tmp_json_confs->native_umask);
override_string_value(&args->json_confs->cgroup_parent, &tmp_json_confs->cgroup_parent);
override_string_value(&args->json_confs->rootfsmntdir, &tmp_json_confs->rootfsmntdir);
override_string_value(&args->json_confs->start_timeout, &tmp_json_confs->start_timeout);
override_string_value(&args->json_confs->image_opt_timeout, &tmp_json_confs->image_opt_timeout);
override_string_value(&args->json_confs->image_server_sock_addr, &tmp_json_confs->image_server_sock_addr);
override_string_value(&args->json_confs->pod_sandbox_image, &tmp_json_confs->pod_sandbox_image);
override_string_value(&args->json_confs->network_plugin, &tmp_json_confs->network_plugin);
override_string_value(&args->json_confs->cni_bin_dir, &tmp_json_confs->cni_bin_dir);
override_string_value(&args->json_confs->cni_conf_dir, &tmp_json_confs->cni_conf_dir);
// Daemon storage-driver
if (merge_storage_conf_into_global(args, tmp_json_confs)) {
ret = -1;
goto out;
}
if (merge_registry_conf_into_global(args, tmp_json_confs)) {
ret = -1;
goto out;
}
if (tmp_json_confs->cpu_rt_period > 0) {
args->json_confs->cpu_rt_period = tmp_json_confs->cpu_rt_period;
}
if (tmp_json_confs->cpu_rt_runtime > 0) {
args->json_confs->cpu_rt_runtime = tmp_json_confs->cpu_rt_runtime;
}
if (tmp_json_confs->image_service) {
args->json_confs->image_service = tmp_json_confs->image_service;
}
if (tmp_json_confs->image_layer_check) {
args->json_confs->image_layer_check = tmp_json_confs->image_layer_check;
}
override_bool_pointer_value(&args->json_confs->use_decrypted_key, &tmp_json_confs->use_decrypted_key);
if (tmp_json_confs->insecure_skip_verify_enforce) {
args->json_confs->insecure_skip_verify_enforce = tmp_json_confs->insecure_skip_verify_enforce;
}
if (merge_authorization_conf_into_global(args, tmp_json_confs)) {
ret = -1;
goto out;
}
if (merge_default_ulimits_conf_into_global(args, tmp_json_confs)) {
ret = -1;
goto out;
}
out:
free(err);
free_isulad_daemon_configs(tmp_json_confs);
return ret;
}