1975 lines
54 KiB
C
Raw Normal View History

2019-09-30 10:53:41 -04:00
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-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: tanyifeng
* Create: 2017-11-22
* Description: provide container verify functions
******************************************************************************/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <sys/utsname.h>
#include <libgen.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysinfo.h>
#include <linux/oom.h>
#include "constants.h"
#include "error.h"
#include "liblcrd.h"
#include "log.h"
#include "sysinfo.h"
#include "specs.h"
#include "verify.h"
#include "lcrd_config.h"
/* verify hook timeout */
static int verify_hook_timeout(int t)
{
if (t < 0) {
ERROR("Hook spec timeout invalid");
lcrd_set_error_message("Invalid timeout: %d", t);
return -1;
}
return 0;
}
/* verify hook path */
static int verify_hook_root_and_no_other(const struct stat *st, const char *path)
{
/* validate file owner */
if (st->st_uid != 0) {
ERROR("Hook file %s isn't right,file owner should be root", path);
lcrd_set_error_message("Hook file %s isn't right,file owner should be root", path);
return -1;
}
/* validate file if can be written by other user */
if (st->st_mode & S_IWOTH) {
ERROR("Hook path %s isn't right,file should not be written by non-root", path);
lcrd_set_error_message("%s should not be written by non-root", path);
return -1;
}
return 0;
}
static int verify_hook_path(const char *path)
{
int ret = 0;
struct stat st;
/* validate absolute path */
ret = util_validate_absolute_path(path);
if (ret != 0) {
ERROR("Hook path %s must be an absolute path", path);
lcrd_set_error_message("%s is not an absolute path", path);
goto out;
}
ret = stat(path, &st);
/* validate file exits */
if (ret < 0) {
ERROR("Hook path %s isn't exist", path);
lcrd_set_error_message("Cann't find path: %s", path);
ret = -1;
goto out;
}
if (verify_hook_root_and_no_other(&st, path) != 0) {
ret = -1;
goto out;
}
out:
return ret;
}
static int verify_hook_conf(const defs_hook *p)
{
int ret = 0;
/* validate hookpath */
ret = verify_hook_path(p->path);
if (ret != 0) {
goto out;
}
/* validate timeout */
ret = verify_hook_timeout(p->timeout);
out:
return ret;
}
static inline bool is_mem_limit_minimum(int64_t limit)
{
/* It's not kernel limit, we want this 4M limit to supply a reasonable functional container */
#define LINUX_MIN_MEMORY 4194304
return limit != 0 && limit < LINUX_MIN_MEMORY;
}
/* check memroy limit and memory swap */
static int verify_mem_limit_swap(const sysinfo_t *sysinfo, int64_t limit, int64_t swap, bool update)
{
int ret = 0;
/* check the minimum memory limit */
if (is_mem_limit_minimum(limit)) {
ERROR("Minimum memory limit allowed is 4MB");
lcrd_set_error_message("Minimum memory limit allowed is 4MB");
ret = -1;
goto out;
}
if (limit > 0 && !(sysinfo->cgmeminfo.limit)) {
ERROR("Your kernel does not support memory limit capabilities. Limitation discarded.");
lcrd_set_error_message(
"Your kernel does not support memory limit capabilities. Limitation discarded.");
ret = -1;
goto out;
}
if (limit > 0 && swap != 0 && !(sysinfo->cgmeminfo.swap)) {
ERROR("Your kernel does not support swap limit capabilities, memory limited without swap.");
lcrd_set_error_message(
"Your kernel does not support swap limit capabilities, memory limited without swap.");
ret = -1;
goto out;
}
if (limit > 0 && swap > 0 && swap < limit) {
ERROR("Minimum memoryswap limit should be larger than memory limit, see usage.");
lcrd_set_error_message("Minimum memoryswap limit should be larger than memory limit");
ret = -1;
goto out;
}
if (limit == 0 && swap > 0 && !update) {
ERROR("You should always set the Memory limit when using Memoryswap limit, see usage.");
lcrd_set_error_message("You should set the memory limit when using memoryswap limit");
ret = -1;
goto out;
}
out:
return ret;
}
static inline bool is_swappiness_invalid(uint64_t swapiness)
{
return (int64_t)swapiness < -1 || swapiness > 100;
}
/* verify memory swappiness */
static int verify_memory_swappiness(const sysinfo_t *sysinfo, uint64_t swapiness)
{
int ret = 0;
if ((int64_t)swapiness != -1 && !(sysinfo->cgmeminfo.swappiness)) {
ERROR("Your kernel does not support memory swappiness capabilities, memory swappiness discarded.");
lcrd_set_error_message(
"Your kernel does not support memory swappiness capabilities, memory swappiness discarded.");
ret = -1;
goto out;
}
if (is_swappiness_invalid(swapiness)) {
ERROR("Invalid value: %lld, valid memory swappiness range is 0-100", (long long)swapiness);
lcrd_set_error_message("Invalid value: %lld, valid memory swappiness range is 0-100", (long long)swapiness);
ret = -1;
goto out;
}
out:
return ret;
}
/* verify memory reservation */
static int verify_memory_reservation(const sysinfo_t *sysinfo, int64_t limit, int64_t reservation)
{
int ret = 0;
if (reservation > 0 && !(sysinfo->cgmeminfo.reservation)) {
ERROR("Your kernel does not support memory soft limit capabilities. Limitation discarded");
lcrd_set_error_message("Your kernel does not support memory soft limit capabilities. Limitation discarded");
ret = -1;
goto out;
}
/* check the minimum memory limit */
if (is_mem_limit_minimum(reservation)) {
ERROR("Minimum memory reservation allowed is 4MB");
lcrd_set_error_message("Minimum memory reservation allowed is 4MB");
ret = -1;
goto out;
}
if (limit > 0 && reservation > 0 && limit < reservation) {
ERROR("Minimum memory limit should be larger than memory reservation limit, see usage.");
lcrd_set_error_message("Minimum memory limit should be larger than memory reservation limit, see usage.");
ret = -1;
goto out;
}
out:
return ret;
}
/* check kernel version */
static bool check_kernel_version(const char *version)
{
struct utsname uts;
int ret;
ret = uname(&uts);
if (ret < 0) {
WARN("Can not get kernel version: %s", strerror(errno));
} else {
if (strverscmp(uts.release, version) < 0) {
return false;
}
}
return true;
}
/* verify memory kernel */
static int verify_memory_kernel(const sysinfo_t *sysinfo, int64_t kernel)
{
int ret = 0;
if (kernel > 0 && !(sysinfo->cgmeminfo.kernel)) {
ERROR("Your kernel does not support kernel memory limit capabilities. Limitation discarded.");
lcrd_set_error_message("Your kernel does not support kernel memory limit capabilities. Limitation discarded.");
ret = -1;
goto out;
}
if (is_mem_limit_minimum(kernel)) {
ERROR("Minimum kernel memory limit allowed is 4MB");
lcrd_set_error_message("Minimum kernel memory limit allowed is 4MB");
ret = -1;
goto out;
}
if (kernel > 0 && !check_kernel_version("4.0.0")) {
WARN("You specified a kernel memory limit on a kernel older than 4.0. "
"Kernel memory limits are experimental on older kernels, "
"it won't work as expected and can cause your system to be unstable.");
}
out:
return ret;
}
/* verify pids limit */
static int verify_pids_limit(const sysinfo_t *sysinfo, int64_t pids_limit)
{
int ret = 0;
if (pids_limit != 0 && !(sysinfo->pidsinfo.pidslimit)) {
ERROR("Your kernel does not support pids limit capabilities, pids limit discarded.");
lcrd_set_error_message("Your kernel does not support pids limit capabilities, pids limit discarded.");
ret = -1;
}
return ret;
}
/* verify files limit */
static int verify_files_limit(const sysinfo_t *sysinfo, int64_t files_limit)
{
int ret = 0;
if (files_limit != 0 && !(sysinfo->filesinfo.fileslimit)) {
ERROR("Your kernel does not support files limit capabilities, files limit discarded.");
lcrd_set_error_message("Your kernel does not support files limit capabilities, files limit discarded.");
ret = -1;
}
return ret;
}
/* verify oom control */
static int verify_oom_control(const sysinfo_t *sysinfo, bool oomdisable)
{
int ret = 0;
if (oomdisable && !(sysinfo->cgmeminfo.oomkilldisable)) {
ERROR("Your kernel does not support OomKillDisable, OomKillDisable discarded");
lcrd_set_error_message("Your kernel does not support OomKillDisable, OomKillDisable discarded");
ret = -1;
}
return ret;
}
/* verify resources memory */
static int verify_resources_memory(const sysinfo_t *sysinfo, const oci_runtime_config_linux_resources_memory *memory)
{
int ret = 0;
ret = verify_mem_limit_swap(sysinfo, memory->limit, memory->swap, false);
if (ret != 0) {
goto out;
}
ret = verify_memory_swappiness(sysinfo, memory->swappiness);
if (ret != 0) {
goto out;
}
ret = verify_memory_reservation(sysinfo, memory->limit, memory->reservation);
if (ret != 0) {
goto out;
}
ret = verify_memory_kernel(sysinfo, memory->kernel);
if (ret != 0) {
goto out;
}
ret = verify_oom_control(sysinfo, memory->disable_oom_killer);
if (ret != 0) {
goto out;
}
out:
return ret;
}
/* verify resources pids */
static int verify_resources_pids(const sysinfo_t *sysinfo, const oci_runtime_config_linux_resources_pids *pids)
{
int ret = 0;
ret = verify_pids_limit(sysinfo, pids->limit);
if (ret != 0) {
goto out;
}
out:
return ret;
}
// ValidateResources performs platform specific validation of the resource settings
// cpu-rt-runtime and cpu-rt-period can not be greater than their parent, cpu-rt-runtime requires sys_nice
static int verify_cpu_realtime(const sysinfo_t *sysinfo, int64_t realtime_period, int64_t realtime_runtime)
{
int ret = 0;
if (realtime_period > 0 && !(sysinfo->cgcpuinfo.cpu_rt_period)) {
ERROR("Invalid --cpu-rt-period: Your kernel does not support cgroup rt period");
lcrd_set_error_message("Invalid --cpu-rt-period: Your kernel does not support cgroup rt period");
ret = -1;
goto out;
}
if (realtime_runtime > 0 && !(sysinfo->cgcpuinfo.cpu_rt_runtime)) {
ERROR("Invalid --cpu-rt-runtime: Your kernel does not support cgroup rt runtime");
lcrd_set_error_message("Invalid --cpu-rt-period: Your kernel does not support cgroup rt runtime");
ret = -1;
goto out;
}
if (realtime_period != 0 && realtime_runtime != 0 && realtime_runtime > realtime_period) {
ERROR("Invalid --cpu-rt-runtime: rt runtime cannot be higher than rt period");
lcrd_set_error_message("Invalid --cpu-rt-runtime: rt runtime cannot be higher than rt period");
ret = -1;
goto out;
}
out:
return ret;
}
/* verify cpu shares */
static int verify_cpu_shares(const sysinfo_t *sysinfo, int64_t cpu_shares)
{
int ret = 0;
if (cpu_shares > 0 && !(sysinfo->cgcpuinfo.cpu_shares)) {
ERROR("Your kernel does not support cgroup cpu shares. Shares discarded.");
lcrd_set_error_message(
"Your kernel does not support cgroup cpu shares. Shares discarded.");
ret = -1;
}
return ret;
}
static int verify_cpu_cfs_period(const sysinfo_t *sysinfo, int64_t cpu_cfs_period)
{
int ret = 0;
if (cpu_cfs_period > 0 && !(sysinfo->cgcpuinfo.cpu_cfs_period)) {
ERROR("Your kernel does not support CPU cfs period. Period discarded.");
lcrd_set_error_message("Your kernel does not support CPU cfs period. Period discarded.");
ret = -1;
goto out;
}
out:
return ret;
}
static inline bool is_cpu_cfs_quota_invalid(int64_t cpu_cfs_quota)
{
return cpu_cfs_quota > 0 && cpu_cfs_quota < 1000;
}
static int verify_cpu_cfs_quota(const sysinfo_t *sysinfo, int64_t cpu_cfs_quota)
{
int ret = 0;
if (cpu_cfs_quota > 0 && !(sysinfo->cgcpuinfo.cpu_cfs_quota)) {
ERROR("Your kernel does not support CPU cfs quato. Quota discarded.");
lcrd_set_error_message("Your kernel does not support CPU cfs quato. Quota discarded.");
ret = -1;
goto out;
}
if (is_cpu_cfs_quota_invalid(cpu_cfs_quota)) {
ERROR("CPU cfs quota can not be less than 1ms (i.e. 1000)");
lcrd_set_error_message("CPU cfs quota can not be less than 1ms (i.e. 1000)");
ret = -1;
goto out;
}
out:
return ret;
}
/* verify cpu cfs scheduler */
static int verify_cpu_cfs_scheduler(const sysinfo_t *sysinfo, int64_t cpu_cfs_period, int64_t cpu_cfs_quota)
{
int ret = 0;
ret = verify_cpu_cfs_period(sysinfo, cpu_cfs_period);
if (ret != 0) {
goto out;
}
ret = verify_cpu_cfs_quota(sysinfo, cpu_cfs_quota);
if (ret != 0) {
goto out;
}
out:
return ret;
}
/* max cpu */
int max_cpu(const char *cores)
{
int max = -1;
char *str = NULL;
char *tmp = NULL;
char *chr = NULL;
str = util_strdup_s(cores);
if (str == NULL) {
goto out;
}
tmp = str;
chr = strchr(tmp, ',');
for (; chr != NULL || *tmp != '\0'; chr = strchr(tmp, ',')) {
char *subchr = NULL;
int value = 0;
if (chr != NULL) {
*chr++ = '\0';
}
subchr = strchr(tmp, '-');
if (subchr != NULL) {
*subchr++ = '\0';
} else {
subchr = tmp;
}
if (util_safe_int(subchr, &value) || value < 0) {
max = -1;
goto out;
}
if (value > max) {
max = value;
}
if (chr != NULL) {
tmp = chr;
} else {
break;
}
}
out:
free(str);
return max;
}
/* check cpu */
static bool check_cpu(const char *provided, const char *available)
{
int max_available = 0;
int max_request = 0;
if (provided == NULL) {
return true;
}
max_available = max_cpu(available);
max_request = max_cpu(provided);
if (max_available == -1 || max_request == -1) {
ERROR("failed to get the number of cpus");
return false;
}
if (max_request > max_available) {
ERROR("invalid maxRequest is %d, max available: %d", max_request, max_available);
lcrd_set_error_message("invalid maxRequest is %d, max available: %d", max_request, max_available);
return false;
}
return true;
}
/* parse unit list */
int parse_unit_list(const char *val, bool *available_list)
{
int ret = -1;
char *str = NULL;
char *tmp = NULL;
char *chr = NULL;
if (val == NULL) {
return 0;
}
str = util_strdup_s(val);
tmp = str;
chr = strchr(tmp, ',');
for (; chr != NULL || *tmp != '\0'; chr = strchr(tmp, ',')) {
char *subchr = NULL;
if (chr != NULL) {
*chr++ = '\0';
}
subchr = strchr(tmp, '-');
if (subchr == NULL) {
int value = 0;
if (util_safe_int(tmp, &value) || value < 0) {
goto out;
}
available_list[value] = true;
} else {
int min = 0;
int max = 0;
int i = 0;
*subchr++ = '\0';
if (util_safe_int(tmp, &min) || min < 0) {
goto out;
}
if (util_safe_int(subchr, &max) || max < 0) {
goto out;
}
for (i = min; i <= max; i++) {
available_list[i] = true;
}
}
if (chr != NULL) {
tmp = chr;
} else {
break;
}
}
ret = 0;
out:
free(str);
return ret;
}
/* is cpuset list available */
static bool is_cpuset_list_available(const char *provided, const char *available)
{
int cpu_num = 0;
int i = 0;
bool ret = false;
bool *parsed_provided = NULL;
bool *parsed_available = NULL;
cpu_num = get_nprocs();
if (cpu_num <= 0) {
ERROR("failed to get the number of processors configured by the operating system!");
goto out;
}
if ((size_t)cpu_num > SIZE_MAX / sizeof(bool)) {
ERROR("invalid cpu num");
goto out;
}
parsed_provided = util_common_calloc_s(sizeof(bool) * (unsigned int)cpu_num);
if (parsed_provided == NULL) {
ERROR("memory alloc failed!");
goto out;
}
parsed_available = util_common_calloc_s(sizeof(bool) * (unsigned int)cpu_num);
if (parsed_available == NULL) {
ERROR("memory alloc failed!");
goto out;
}
if (!check_cpu(provided, available)) {
goto out;
}
if (parse_unit_list(provided, parsed_provided) < 0 ||
parse_unit_list(available, parsed_available) < 0) {
goto out;
}
for (i = 0; i < cpu_num; i++) {
if (!parsed_provided[i] || parsed_available[i]) {
continue;
}
goto out;
}
ret = true;
out:
free(parsed_provided);
free(parsed_available);
return ret;
}
/* is cpuset cpus available */
bool is_cpuset_cpus_available(const sysinfo_t *sysinfo, const char *cpus)
{
bool ret = false;
ret = is_cpuset_list_available(cpus, sysinfo->cpusetinfo.cpus);
if (!ret) {
ERROR("Checking cpuset.cpus got invalid format: %s.", cpus);
lcrd_set_error_message("Checking cpuset.cpus got invalid format: %s.", cpus);
}
return ret;
}
/* is cpuset mems available */
bool is_cpuset_mems_available(const sysinfo_t *sysinfo, const char *mems)
{
bool ret = false;
ret = is_cpuset_list_available(mems, sysinfo->cpusetinfo.mems);
if (!ret) {
ERROR("Checking cpuset.mems got invalid format: %s.", mems);
lcrd_set_error_message("Checking cpuset.mems got invalid format: %s.", mems);
}
return ret;
}
// cpuset subsystem checks and adjustments
static int verify_resources_cpuset(const sysinfo_t *sysinfo, const char *cpus, const char *mems)
{
int ret = 0;
bool cpus_available = false;
bool mems_available = false;
if (cpus != NULL && !(sysinfo->cpusetinfo.cpuset)) {
ERROR("Your kernel does not support cpuset. Cpuset discarded.");
lcrd_set_error_message("Your kernel does not support cpuset. Cpuset discarded.");
ret = -1;
goto out;
}
if (mems != NULL && !(sysinfo->cpusetinfo.cpuset)) {
ERROR("Your kernel does not support cpuset. Cpuset discarded.");
lcrd_set_error_message("Your kernel does not support cpuset. Cpuset discarded.");
ret = -1;
goto out;
}
cpus_available = is_cpuset_cpus_available(sysinfo, cpus);
if (!cpus_available) {
ERROR("Requested CPUs are not available - requested %s, available: %s.", cpus, sysinfo->cpusetinfo.cpus);
lcrd_set_error_message("Requested CPUs are not available - requested %s, available: %s.", cpus,
sysinfo->cpusetinfo.cpus);
ret = -1;
goto out;
}
mems_available = is_cpuset_mems_available(sysinfo, mems);
if (!mems_available) {
ERROR("Requested memory nodes are not available - requested %s, available: %s.",
mems, sysinfo->cpusetinfo.mems);
lcrd_set_error_message("Requested memory nodes are not available - requested %s, available: %s.",
mems, sysinfo->cpusetinfo.mems);
ret = -1;
goto out;
}
out:
return ret;
}
/* verify resources cpu */
static int verify_resources_cpu(const sysinfo_t *sysinfo, const oci_runtime_config_linux_resources_cpu *cpu)
{
int ret = 0;
ret = verify_cpu_realtime(sysinfo, (int64_t)(cpu->realtime_period), cpu->realtime_runtime);
if (ret != 0) {
goto out;
}
ret = verify_cpu_shares(sysinfo, (int64_t)(cpu->shares));
if (ret != 0) {
goto out;
}
ret = verify_cpu_cfs_scheduler(sysinfo, (int64_t)(cpu->period), cpu->quota);
if (ret != 0) {
goto out;
}
ret = verify_resources_cpuset(sysinfo, cpu->cpus, cpu->mems);
if (ret != 0) {
goto out;
}
out:
return ret;
}
static inline bool is_blkio_weight_invalid(int weight)
{
return weight > 0 && (weight < 10 || weight > 1000);
}
/* verify blkio weight */
static int verify_blkio_weight(const sysinfo_t *sysinfo, int weight)
{
int ret = 0;
if (weight > 0 && !(sysinfo->blkioinfo.blkio_weight)) {
ERROR("Your kernel does not support Block I/O weight. Weight discarded.");
lcrd_set_error_message("Your kernel does not support Block I/O weight. Weight discarded.");
ret = -1;
goto out;
}
if (is_blkio_weight_invalid(weight)) {
ERROR("Range of blkio weight is from 10 to 1000.");
lcrd_set_error_message("Range of blkio weight is from 10 to 1000.");
ret = -1;
goto out;
}
out:
return ret;
}
static inline bool is_hostconfig_blkio_weight_invalid(uint16_t weight)
{
return weight > 0 && (weight < 10 || weight > 1000);
}
/* verify hostconfig blkio weight */
static int verify_hostconfig_blkio_weight(const sysinfo_t *sysinfo, uint16_t weight)
{
int ret = 0;
if (weight > 0 && !(sysinfo->blkioinfo.blkio_weight)) {
ERROR("Your kernel does not support Block I/O weight. Weight in host config discarded.");
lcrd_set_error_message("Your kernel does not support Block I/O weight. Weight in host config discarded.");
ret = -1;
goto out;
}
if (is_hostconfig_blkio_weight_invalid(weight)) {
ERROR("Range of blkio weight is from 10 to 1000.");
lcrd_set_error_message("Range of blkio weight is from 10 to 1000.");
ret = -1;
goto out;
}
out:
return ret;
}
/* verify blkio device */
static int verify_blkio_device(const sysinfo_t *sysinfo, size_t weight_device_len)
{
int ret = 0;
if (weight_device_len > 0 && !(sysinfo->blkioinfo.blkio_weight_device)) {
ERROR("Your kernel does not support Block I/O weight_device.");
lcrd_set_error_message("Your kernel does not support Block I/O weight_device.");
ret = -1;
}
return ret;
}
/* verify oom score adj */
static int verify_oom_score_adj(int oom_score_adj)
{
int ret = 0;
if (oom_score_adj < OOM_SCORE_ADJ_MIN || oom_score_adj > OOM_SCORE_ADJ_MAX) {
ERROR("Invalid value %d, range for oom score adj is [-1000, 1000].", oom_score_adj);
lcrd_set_error_message("Invalid value %d, range for oom score adj is [-1000, 1000].", oom_score_adj);
ret = -1;
}
return ret;
}
#ifdef ENABLE_OCI_IMAGE
static bool is_storage_opts_valid(const json_map_string_string *storage_opts)
{
size_t i;
for (i = 0; i < storage_opts->len; i++) {
if (strcmp(storage_opts->keys[i], "size") != 0) {
// Only check key here, check value by image driver
ERROR("Unknown storage option: %s", storage_opts->keys[i]);
lcrd_set_error_message("Unknown storage option: %s", storage_opts->keys[i]);
return false;
}
}
return true;
}
/* verify storage options */
static int verify_storage_opts(const host_config *hc)
{
int ret = 0;
char *driver = NULL;
json_map_string_string *storage_opts = NULL;
if (hc != NULL) {
storage_opts = hc->storage_opt;
}
driver = conf_get_lcrd_storage_driver();
if (driver == NULL) {
ERROR("Failed to get storage driver");
return -1;
}
if (storage_opts == NULL || storage_opts->len == 0 || strcmp(driver, "overlay2") != 0) {
goto cleanup;
}
if (storage_opts->len > 0) {
char *backing_fs = NULL;
backing_fs = conf_get_lcrd_storage_driver_backing_fs();
if (backing_fs == NULL) {
ERROR("No backing fs detected");
ret = -1;
goto cleanup;
}
if (strcmp(backing_fs, "xfs") == 0) {
WARN("Filesystem quota for overlay2 over xfs is not totally support");
}
free(backing_fs);
}
if (!is_storage_opts_valid(storage_opts)) {
ret = -1;
goto cleanup;
}
cleanup:
free(driver);
return ret;
}
#endif
/* verify blkio rw bps device */
static int verify_blkio_rw_bps_device(const sysinfo_t *sysinfo, size_t throttle_read_bps_device_len,
size_t throttle_write_bps_device_len)
{
int ret = 0;
if (throttle_read_bps_device_len > 0 && !(sysinfo->blkioinfo.blkio_read_bps_device)) {
ERROR("Your kernel does not support Block read limit in bytes per second");
lcrd_set_error_message("Your kernel does not support Block read limit in bytes per second");
ret = -1;
goto out;
}
if (throttle_write_bps_device_len > 0 && !(sysinfo->blkioinfo.blkio_write_bps_device)) {
ERROR("Your kernel does not support Block write limit in bytes per second");
lcrd_set_error_message("Your kernel does not support Block write limit in bytes per second");
ret = -1;
goto out;
}
out:
return ret;
}
/* verify blkio rw iops device */
static int verify_blkio_rw_iops_device(const sysinfo_t *sysinfo, size_t throttle_read_iops_device_len,
size_t throttle_write_iops_device_len)
{
int ret = 0;
if (throttle_read_iops_device_len > 0 && !(sysinfo->blkioinfo.blkio_read_iops_device)) {
ERROR("Your kernel does not support Block read limit in IO per second");
lcrd_set_error_message("Your kernel does not support Block read limit in IO per second");
ret = -1;
goto out;
}
if (throttle_write_iops_device_len > 0 && !(sysinfo->blkioinfo.blkio_write_iops_device)) {
ERROR("Your kernel does not support Block write limit in IO per second");
lcrd_set_error_message("Your kernel does not support Block write limit in IO per second");
ret = -1;
goto out;
}
out:
return ret;
}
/* verify resources blkio */
static int verify_resources_blkio(const sysinfo_t *sysinfo, const oci_runtime_config_linux_resources_block_io *blkio)
{
int ret = 0;
ret = verify_blkio_weight(sysinfo, blkio->weight);
if (ret != 0) {
goto out;
}
ret = verify_blkio_device(sysinfo, blkio->weight_device_len);
if (ret != 0) {
goto out;
}
ret = verify_blkio_rw_bps_device(sysinfo, blkio->throttle_read_bps_device_len,
blkio->throttle_write_bps_device_len);
if (ret != 0) {
goto out;
}
ret = verify_blkio_rw_iops_device(sysinfo, blkio->throttle_read_iops_device_len,
blkio->throttle_write_iops_device_len);
if (ret != 0) {
goto out;
}
out:
return ret;
}
static bool check_hugetlbs_repeated(size_t newlen, const char *pagesize,
const oci_runtime_config_linux_resources_hugepage_limits_element *hugetlb,
oci_runtime_config_linux_resources_hugepage_limits_element **newtlb)
{
bool repeated = false;
size_t j;
for (j = 0; j < newlen; j++) {
if (newtlb[j] != NULL && newtlb[j]->page_size != NULL && !strcmp(newtlb[j]->page_size, pagesize)) {
WARN("hugetlb-limit setting of %s is repeated, former setting %llu will be replaced with %llu",
pagesize, newtlb[j]->limit, hugetlb->limit);
newtlb[j]->limit = hugetlb->limit;
repeated = true;
goto out;
}
}
out:
return repeated;
}
static void free_hugetlbs_array(oci_runtime_config_linux_resources_hugepage_limits_element **hugetlb,
size_t hugetlb_len)
{
size_t i;
if (hugetlb == NULL) {
return;
}
for (i = 0; i < hugetlb_len; i++) {
if (hugetlb[i] != NULL) {
free_oci_runtime_config_linux_resources_hugepage_limits_element(hugetlb[i]);
hugetlb[i] = NULL;
}
}
free(hugetlb);
}
/* verify resources hugetlbs */
static int verify_resources_hugetlbs(const sysinfo_t *sysinfo,
oci_runtime_config_linux_resources_hugepage_limits_element ***hugetlb,
size_t *hugetlb_len)
{
int ret = 0;
oci_runtime_config_linux_resources_hugepage_limits_element **newhugetlb = NULL;
size_t newlen = 0;
size_t i;
if (!sysinfo->hugetlbinfo.hugetlblimit) {
ERROR("Your kernel does not support hugetlb limit. --hugetlb-limit discarded.");
lcrd_set_error_message(
"Your kernel does not support hugetlb limit. --hugetlb-limit discarded.");
ret = -1;
goto out;
}
for (i = 0; i < *hugetlb_len; i++) {
char *pagesize = NULL;
size_t newsize, oldsize;
oci_runtime_config_linux_resources_hugepage_limits_element **tmphugetlb;
pagesize = validate_hugetlb((*hugetlb)[i]->page_size, (*hugetlb)[i]->limit);
if (pagesize == NULL) {
ret = -1;
goto out;
}
if (check_hugetlbs_repeated(newlen, pagesize, (*hugetlb)[i], newhugetlb)) {
free(pagesize);
continue;
}
// append new hugetlb
if (newlen > SIZE_MAX / sizeof(oci_runtime_config_linux_resources_hugepage_limits_element *) - 1) {
free(pagesize);
ERROR("Too many new hugetlb to append!");
ret = -1;
goto out;
}
newsize = sizeof(oci_runtime_config_linux_resources_hugepage_limits_element *) * (newlen + 1);
oldsize = newsize - sizeof(oci_runtime_config_linux_resources_hugepage_limits_element *);
ret = mem_realloc((void **)&tmphugetlb, newsize, newhugetlb, oldsize);
if (ret < 0) {
free(pagesize);
ERROR("Out of memory");
ret = -1;
goto out;
}
newhugetlb = tmphugetlb;
newhugetlb[newlen] = util_common_calloc_s(sizeof(oci_runtime_config_linux_resources_hugepage_limits_element));
if (newhugetlb[newlen] == NULL) {
free(pagesize);
ERROR("Out of memory");
ret = -1;
goto out;
}
newhugetlb[newlen]->limit = (*hugetlb)[i]->limit;
newhugetlb[newlen]->page_size = pagesize;
newlen++;
}
out:
if (ret != 0 && newhugetlb != NULL) {
free_hugetlbs_array(newhugetlb, newlen);
} else if (ret == 0) {
free_hugetlbs_array(*hugetlb, *hugetlb_len);
*hugetlb = newhugetlb;
*hugetlb_len = newlen;
}
return ret;
}
/* adapt memory swap */
static int adapt_memory_swap(const sysinfo_t *sysinfo, const int64_t *limit, int64_t *swap)
{
if (*limit > 0 && *swap == 0 && sysinfo->cgmeminfo.swap) {
if (*limit > (INT64_MAX / 2)) {
ERROR("Memory swap out of range!");
lcrd_set_error_message("Memory swap out of range!");
return -1;
}
*swap = (*limit) * 2;
}
return 0;
}
/* adapt resources memory */
static int adapt_resources_memory(const sysinfo_t *sysinfo, oci_runtime_config_linux_resources_memory *memory)
{
return adapt_memory_swap(sysinfo, &(memory->limit), &(memory->swap));
}
/* verify linux resources */
static int verify_linux_resources(const sysinfo_t *sysinfo, oci_runtime_config_linux_resources *resources)
{
int ret = 0;
// memory
if (resources->memory != NULL) {
ret = verify_resources_memory(sysinfo, resources->memory);
if (ret != 0) {
goto out;
}
}
// pids
if (resources->pids != NULL) {
ret = verify_resources_pids(sysinfo, resources->pids);
if (ret != 0) {
goto out;
}
}
// cpu
if (resources->cpu != NULL) {
ret = verify_resources_cpu(sysinfo, resources->cpu);
if (ret != 0) {
goto out;
}
}
// hugetlb
if (resources->hugepage_limits_len && resources->hugepage_limits != NULL) {
ret = verify_resources_hugetlbs(sysinfo, &(resources->hugepage_limits), &(resources->hugepage_limits_len));
if (ret != 0) {
goto out;
}
}
// blkio
if (resources->block_io != NULL) {
ret = verify_resources_blkio(sysinfo, resources->block_io);
if (ret != 0) {
goto out;
}
}
out:
return ret;
}
/* adapt linux resources */
static int adapt_linux_resources(const sysinfo_t *sysinfo, oci_runtime_config_linux_resources *resources)
{
int ret = 0;
// memory
if (resources->memory != NULL) {
ret = adapt_resources_memory(sysinfo, resources->memory);
if (ret != 0) {
goto out;
}
}
out:
return ret;
}
static bool verify_oci_linux_sysctl(const oci_runtime_config_linux *l)
{
size_t i = 0;
if (l->sysctl == NULL) {
return true;
}
for (i = 0; i < l->sysctl->len; i++) {
if (strcmp("kernel.pid_max", l->sysctl->keys[i]) == 0) {
if (!pid_max_kernel_namespaced()) {
lcrd_set_error_message("Sysctl '%s' is not kernel namespaced, it cannot be changed",
l->sysctl->keys[i]);
return false;
} else {
return true;
}
}
if (!check_sysctl_valid(l->sysctl->keys[i])) {
lcrd_set_error_message("Sysctl %s=%s is not whitelist",
l->sysctl->keys[i],
l->sysctl->values[i]);
return false;
}
}
return true;
}
/* verify oci linux */
static int verify_oci_linux(const sysinfo_t *sysinfo, const oci_runtime_config_linux *l)
{
int ret = 0;
// Resources
if (l->resources != NULL) {
ret = verify_linux_resources(sysinfo, l->resources);
if (ret != 0) {
goto out;
}
}
if (!verify_oci_linux_sysctl(l)) {
ret = -1;
goto out;
}
out:
return ret;
}
static int verify_oci_hook_prestart(const oci_runtime_spec_hooks *h)
{
size_t i;
for (i = 0; i < h->prestart_len; i++) {
int ret = 0;
ret = verify_hook_conf(h->prestart[i]);
if (ret != 0) {
return ret;
}
}
return 0;
}
static int verify_oci_hook_poststart(const oci_runtime_spec_hooks *h)
{
size_t i;
for (i = 0; i < h->poststart_len; i++) {
int ret = 0;
ret = verify_hook_conf(h->poststart[i]);
if (ret != 0) {
return ret;
}
}
return 0;
}
static int verify_oci_hook_poststop(const oci_runtime_spec_hooks *h)
{
size_t i;
for (i = 0; i < h->poststop_len; i++) {
int ret = 0;
ret = verify_hook_conf(h->poststop[i]);
if (ret != 0) {
return ret;
}
}
return 0;
}
/* verify oci hook */
int verify_oci_hook(const oci_runtime_spec_hooks *h)
{
int ret = 0;
// Prestart
ret = verify_oci_hook_prestart(h);
if (ret != 0) {
goto out;
}
// Poststart
ret = verify_oci_hook_poststart(h);
if (ret != 0) {
goto out;
}
// Poststop
ret = verify_oci_hook_poststop(h);
if (ret != 0) {
goto out;
}
out:
return ret;
}
/* adapt oci linux */
static int adapt_oci_linux(const sysinfo_t *sysinfo, oci_runtime_config_linux *l)
{
int ret = 0;
// Resources
if (l->resources != NULL) {
ret = adapt_linux_resources(sysinfo, l->resources);
if (ret != 0) {
goto out;
}
}
out:
return ret;
}
/* get source mount */
static int get_source_mount(const char *src, char **srcpath, char **optional)
{
mountinfo_t **minfos = NULL;
mountinfo_t *info = NULL;
int ret = 0;
char real_path[PATH_MAX + 1] = {0};
char *dirc = NULL;
char *dname = NULL;
if (realpath(src, real_path) == NULL) {
ERROR("Failed to get real path for %s : %s", src, strerror(errno));
return -1;
}
minfos = getmountsinfo();
if (minfos == NULL) {
ERROR("Failed to get mounts info");
ret = -1;
goto out;
}
info = find_mount_info(minfos, real_path);
if (info != NULL) {
*srcpath = util_strdup_s(real_path);
*optional = info->optional ? util_strdup_s(info->optional) : NULL;
goto out;
}
dirc = util_strdup_s(real_path);
dname = dirc;
while (strcmp(dirc, "/")) {
dname = dirname(dname);
info = find_mount_info(minfos, dname);
if (info != NULL) {
*srcpath = util_strdup_s(dname);
*optional = info->optional ? util_strdup_s(info->optional) : NULL;
goto out;
}
}
ERROR("Could not find source mount of %s", src);
ret = -1;
out:
free(dirc);
free_mounts_info(minfos);
return ret;
}
static inline bool is_optional_shared(const char *optional)
{
return optional != NULL && strncmp(optional, "shared:", strlen("shared:")) == 0;
}
/* ensure shared */
static int ensure_shared(const char *src)
{
int ret = 0;
char *srcpath = NULL;
char *optional = NULL;
ret = get_source_mount(src, &srcpath, &optional);
if (ret != 0) {
goto out;
}
if (is_optional_shared(optional)) {
goto out;
}
ERROR("Path %s is mounted on %s but it is not a shared mount", src, srcpath);
ret = -1;
out:
free(srcpath);
free(optional);
return ret;
}
static inline bool is_optional_slave(const char *optional)
{
return optional != NULL && strncmp(optional, "master:", strlen("master:")) == 0;
}
/* ensure shared or slave */
static int ensure_shared_or_slave(const char *src)
{
int ret = 0;
char *srcpath = NULL;
char *optional = NULL;
ret = get_source_mount(src, &srcpath, &optional);
if (ret != 0) {
goto out;
}
if (is_optional_shared(optional) || is_optional_slave(optional)) {
goto out;
}
ERROR("Path %s is mounted on %s but it is not a shared or slave mount", src, srcpath);
ret = -1;
out:
free(srcpath);
free(optional);
return ret;
}
static inline bool is_propagation_shared(const char *propagation)
{
return strcmp(propagation, "shared") == 0 || strcmp(propagation, "rshared") == 0;
}
static void set_mount_propagation_shared(const oci_runtime_spec *container)
{
if (container->linux->rootfs_propagation == NULL) {
container->linux->rootfs_propagation = util_strdup_s("shared");
return;
}
if (!is_propagation_shared(container->linux->rootfs_propagation)) {
free(container->linux->rootfs_propagation);
container->linux->rootfs_propagation = util_strdup_s("shared");
}
}
static inline bool is_propagation_slave(const char *propagation)
{
return strcmp(propagation, "slave") == 0 || strcmp(propagation, "rslave") == 0;
}
static void set_mount_propagation_slave(const oci_runtime_spec *container)
{
if (container->linux->rootfs_propagation == NULL) {
container->linux->rootfs_propagation = util_strdup_s("rslave");
return;
}
if (!is_propagation_shared(container->linux->rootfs_propagation) &&
!is_propagation_slave(container->linux->rootfs_propagation)) {
free(container->linux->rootfs_propagation);
container->linux->rootfs_propagation = util_strdup_s("rslave");
}
}
static int make_mount_propagation(const oci_runtime_spec *container, const char *source, const char *option)
{
int ret;
if (is_propagation_shared(option)) {
ret = ensure_shared(source);
if (ret != 0) {
return ret;
}
set_mount_propagation_shared(container);
} else if (is_propagation_slave(option)) {
ret = ensure_shared_or_slave(source);
if (ret != 0) {
return ret;
}
set_mount_propagation_slave(container);
}
return 0;
}
/* set mounts */
static int set_mounts(const oci_runtime_spec *container)
{
int ret = 0;
size_t i, k;
defs_mount **m = NULL;
if (container == NULL) {
return -1;
}
m = container->mounts;
for (i = 0; i < container->mounts_len; i++) {
for (k = 0; k < m[i]->options_len; k++) {
ret = make_mount_propagation(container, m[i]->source, m[i]->options[k]);
if (ret != 0) {
goto out;
}
}
}
out:
return ret;
}
/* verify custom mount */
static int verify_custom_mount(defs_mount **mounts, size_t len)
{
int ret = 0;
size_t i = 0;
defs_mount *iter = NULL;
for (; i < len; ++i) {
iter = *(mounts + i);
if (iter == NULL || strcmp(iter->type, "bind")) {
continue;
}
if (!util_file_exists(iter->source) &&
util_mkdir_p(iter->source, CONFIG_DIRECTORY_MODE)) {
ERROR("Failed to create directory '%s': %s", iter->source, strerror(errno));
lcrd_try_set_error_message("Failed to create directory '%s': %s", iter->source, strerror(errno));
ret = -1;
goto out;
}
}
out:
return ret;
}
static int verify_container_linux(const oci_runtime_spec *container, const sysinfo_t *sysinfo)
{
int ret = 0;
/* verify and adapt container settings */
if (container->linux != NULL) {
ret = verify_oci_linux(sysinfo, container->linux);
if (ret != 0) {
goto out;
}
ret = adapt_oci_linux(sysinfo, container->linux);
if (ret != 0) {
goto out;
}
}
out:
return ret;
}
static int verify_container_mounts(const oci_runtime_spec *container)
{
int ret = 0;
/* verify custom mount info, ensure source path exist */
if (container->mounts != NULL && container->mounts_len > 0) {
ret = verify_custom_mount(container->mounts, container->mounts_len);
if (ret != 0) {
goto out;
}
ret = set_mounts(container);
if (ret != 0) {
goto out;
}
}
out:
return ret;
}
/* verify container settings */
int verify_container_settings(const oci_runtime_spec *container)
{
int ret = 0;
sysinfo_t *sysinfo = NULL;
sysinfo = get_sys_info(true);
if (sysinfo == NULL) {
ERROR("Can not get system info");
ret = -1;
goto out;
}
if (!util_valid_host_name(container->hostname)) {
ERROR("Invalid container hostname %s", container->hostname);
lcrd_set_error_message("Invalid container hostname (%s), only %s and less than 64 bytes are allowed.",
container->hostname, HOST_NAME_REGEXP);
ret = -1;
goto out;
}
/* verify and adapt container settings */
ret = verify_container_linux(container, sysinfo);
if (ret != 0) {
goto out;
}
ret = verify_container_mounts(container);
if (ret != 0) {
goto out;
}
/* verify hook settings */
if (container->hooks != NULL && verify_oci_hook(container->hooks)) {
ERROR("Verify hook file failed");
ret = -1;
goto out;
}
out:
free_sysinfo(sysinfo);
return ret;
}
static void free_hugetlb_array(host_config_hugetlbs_element **hugetlb, size_t len)
{
size_t i;
if (hugetlb == NULL) {
return;
}
for (i = 0; i < len; i++) {
free_host_config_hugetlbs_element(hugetlb[i]);
hugetlb[i] = NULL;
}
free(hugetlb);
}
static int append_hugetlb_array(host_config_hugetlbs_element ***hugetlb, size_t len)
{
size_t newsize;
size_t oldsize;
host_config_hugetlbs_element **tmphugetlb;
int ret;
if (len > SIZE_MAX / sizeof(host_config_hugetlbs_element *) - 1) {
return -1;
}
newsize = sizeof(host_config_hugetlbs_element *) * (len + 1);
oldsize = newsize - sizeof(host_config_hugetlbs_element *);
ret = mem_realloc((void **)&tmphugetlb, newsize, *hugetlb, oldsize);
if (ret < 0) {
return -1;
}
*hugetlb = tmphugetlb;
(*hugetlb)[len] = util_common_calloc_s(sizeof(host_config_hugetlbs_element));
if ((*hugetlb)[len] == NULL) {
return -1;
}
return 0;
}
static int add_hugetbl_element(host_config_hugetlbs_element ***hugetlb, size_t *len,
const host_config_hugetlbs_element *element)
{
char *pagesize = NULL;
size_t j;
int ret = 0;
pagesize = validate_hugetlb(element->page_size, element->limit);
if (pagesize == NULL) {
return -1;
}
for (j = 0; j < *len; j++) {
if (strcmp((*hugetlb)[j]->page_size, pagesize) == 0) {
WARN("Hostconfig: hugetlb-limit setting of %s is repeated, "
"former setting % llu will be replaced with % llu",
pagesize, (*hugetlb)[j]->limit, element->limit);
(*hugetlb)[j]->limit = element->limit;
goto out;
}
}
// append new hugetlb
ret = append_hugetlb_array(hugetlb, *len);
if (ret < 0) {
ERROR("Out of memory");
goto out;
}
(*hugetlb)[*len]->page_size = pagesize;
(*hugetlb)[*len]->limit = element->limit;
(*len)++;
return 0;
out:
free(pagesize);
return ret;
}
/* verify host config hugetlbs */
static int verify_host_config_hugetlbs(const sysinfo_t *sysinfo, host_config_hugetlbs_element ***hugetlb,
size_t *hugetlb_len)
{
int ret;
host_config_hugetlbs_element **newhugetlb = NULL;
size_t newlen = 0;
size_t i = 0;
if (*hugetlb == NULL || *hugetlb_len == 0) {
return 0;
}
if (!sysinfo->hugetlbinfo.hugetlblimit) {
ERROR("Your kernel does not support hugetlb limit. --hugetlb-limit discarded.");
lcrd_set_error_message("Your kernel does not support hugetlb limit. --hugetlb-limit discarded.");
ret = -1;
goto out;
}
for (i = 0; i < *hugetlb_len; i++) {
ret = add_hugetbl_element(&newhugetlb, &newlen, (*hugetlb)[i]);
if (ret != 0) {
goto out;
}
}
free_hugetlb_array(*hugetlb, *hugetlb_len);
*hugetlb = newhugetlb;
*hugetlb_len = newlen;
return 0;
out:
free_hugetlb_array(newhugetlb, newlen);
return ret;
}
static int host_config_settings_memory(const sysinfo_t *sysinfo, const host_config *hostconfig, bool update)
{
int ret = 0;
ret = verify_mem_limit_swap(sysinfo, hostconfig->memory, hostconfig->memory_swap, update);
if (ret != 0) {
goto out;
}
ret = verify_memory_reservation(sysinfo, hostconfig->memory, hostconfig->memory_reservation);
if (ret != 0) {
goto out;
}
ret = verify_memory_kernel(sysinfo, hostconfig->kernel_memory);
if (ret != 0) {
goto out;
}
out:
return ret;
}
static int host_config_settings_cpu(const sysinfo_t *sysinfo, const host_config *hostconfig)
{
int ret = 0;
ret = verify_cpu_realtime(sysinfo, hostconfig->cpu_realtime_period, hostconfig->cpu_realtime_runtime);
if (ret != 0) {
goto out;
}
ret = verify_cpu_shares(sysinfo, hostconfig->cpu_shares);
if (ret != 0) {
goto out;
}
ret = verify_cpu_cfs_scheduler(sysinfo, hostconfig->cpu_period, hostconfig->cpu_quota);
if (ret != 0) {
goto out;
}
// cpuset
ret = verify_resources_cpuset(sysinfo, hostconfig->cpuset_cpus, hostconfig->cpuset_mems);
if (ret != 0) {
goto out;
}
out:
return ret;
}
static int host_config_settings_blkio(const sysinfo_t *sysinfo, const host_config *hostconfig)
{
int ret = 0;
ret = verify_hostconfig_blkio_weight(sysinfo, hostconfig->blkio_weight);
if (ret != 0) {
goto out;
}
ret = verify_blkio_device(sysinfo, hostconfig->blkio_weight_device_len);
if (ret != 0) {
goto out;
}
out:
return ret;
}
static inline bool is_restart_policy_always(const char *policy)
{
return strcmp(policy, "always") == 0;
}
static inline bool is_restart_policy_on_reboot(const char *policy)
{
return strcmp(policy, "on-reboot") == 0;
}
static inline bool is_restart_policy_no(const char *policy)
{
return strcmp(policy, "no") == 0;
}
static inline bool is_restart_policy_on_failure(const char *policy)
{
return strcmp(policy, "on-failure") == 0;
}
static int verify_restart_policy_name(const host_config_restart_policy *rp, const host_config *hostconfig)
{
if (is_restart_policy_always(rp->name) || is_restart_policy_no(rp->name) || is_restart_policy_on_reboot(rp->name)) {
if (rp->maximum_retry_count != 0) {
ERROR("Maximum retry count cannot be used with restart policy '%s'", rp->name);
lcrd_set_error_message("Maximum retry count cannot be used with restart policy '%s'", rp->name);
return -1;
}
} else if (is_restart_policy_on_failure(rp->name)) {
if (rp->maximum_retry_count < 0) {
ERROR("Maximum retry count cannot be negative");
lcrd_set_error_message("Maximum retry count cannot be negative");
return -1;
}
} else {
ERROR("Invalid restart policy '%s'", rp->name);
lcrd_set_error_message("Invalid restart policy '%s'", rp->name);
return -1;
}
if (hostconfig->auto_remove && !is_restart_policy_no(rp->name)) {
ERROR("Can't create 'AutoRemove' container with restart policy");
lcrd_set_error_message("Can't create 'AutoRemove' container with restart policy");
return -1;
}
return 0;
}
static int host_config_settings_restart_policy(const host_config *hostconfig)
{
host_config_restart_policy *rp = NULL;
if (hostconfig == NULL || hostconfig->restart_policy == NULL) {
return 0;
}
rp = hostconfig->restart_policy;
if (rp->name == NULL || rp->name[0] == '\0') {
if (rp->maximum_retry_count != 0) {
ERROR("Maximum retry count cannot be used with empty restart policy");
lcrd_set_error_message("Maximum retry count cannot be used with empty restart policy");
return -1;
}
return 0;
}
return verify_restart_policy_name(rp, hostconfig);
}
static int host_config_settings_with_sysinfo(host_config *hostconfig, bool update)
{
int ret = 0;
sysinfo_t *sysinfo = NULL;
sysinfo = get_sys_info(true);
if (sysinfo == NULL) {
ERROR("Can not get system info");
return -1;
}
ret = verify_host_config_hugetlbs(sysinfo, &(hostconfig->hugetlbs), &(hostconfig->hugetlbs_len));
if (ret != 0) {
goto out;
}
// memory
ret = host_config_settings_memory(sysinfo, hostconfig, update);
if (ret != 0) {
goto out;
}
ret = verify_pids_limit(sysinfo, hostconfig->pids_limit);
if (ret != 0) {
goto out;
}
ret = verify_files_limit(sysinfo, hostconfig->files_limit);
if (ret != 0) {
goto out;
}
// cpu & cpuset
ret = host_config_settings_cpu(sysinfo, hostconfig);
if (ret != 0) {
goto out;
}
// blkio
ret = host_config_settings_blkio(sysinfo, hostconfig);
if (ret != 0) {
goto out;
}
out:
free_sysinfo(sysinfo);
return ret;
}
/* verify host config settings */
int verify_host_config_settings(host_config *hostconfig, bool update)
{
int ret = 0;
if (hostconfig == NULL) {
return 0;
}
// restart policy
ret = host_config_settings_restart_policy(hostconfig);
if (ret != 0) {
goto out;
}
ret = host_config_settings_with_sysinfo(hostconfig, update);
if (ret != 0) {
goto out;
}
// oom score adj
ret = verify_oom_score_adj(hostconfig->oom_score_adj);
if (ret != 0) {
goto out;
}
#ifdef ENABLE_OCI_IMAGE
// storage options
ret = verify_storage_opts(hostconfig);
if (ret != 0) {
goto out;
}
#endif
out:
return ret;
}
/* verify container settings start */
int verify_container_settings_start(const char *rootpath, const char *id)
{
int ret = 0;
oci_runtime_spec *container = read_oci_config(rootpath, id);
if (container == NULL) {
ERROR("Failed to read oci config");
ret = -1;
goto out;
}
/* verify custom mount info, ensure source path exist */
if (container->mounts != NULL && container->mounts_len > 0) {
ret = verify_custom_mount(container->mounts, container->mounts_len);
}
out:
free_oci_runtime_spec(container);
return ret;
}
static inline bool is_less_than_one_second(int64_t timeout)
{
return timeout != 0 && timeout < Time_Second;
}
int verify_health_check_parameter(const container_custom_config *custom_spec)
{
int ret = 0;
if (custom_spec == NULL || custom_spec->health_check == NULL) {
return ret;
}
if (is_less_than_one_second(custom_spec->health_check->interval)) {
ERROR("Interval in Healthcheck cannot be less than one second");
lcrd_set_error_message("Interval in Healthcheck cannot be less than one second");
ret = -1;
goto out;
}
if (is_less_than_one_second(custom_spec->health_check->timeout)) {
ERROR("Timeout in Healthcheck cannot be less than one second");
lcrd_set_error_message("Timeout in Healthcheck cannot be less than one second");
ret = -1;
goto out;
}
if (is_less_than_one_second(custom_spec->health_check->start_period)) {
ERROR("StartPeriod in Healthcheck cannot be less than one second");
lcrd_set_error_message("StartPeriod in Healthcheck cannot be less than one second");
ret = -1;
goto out;
}
if (custom_spec->health_check->retries < 0) {
ERROR("--health-retries cannot be negative");
lcrd_set_error_message("--health-retries cannot be negative");
ret = -1;
goto out;
}
out:
return ret;
}
2019-12-25 15:50:34 +08:00