8266490: Extend the OSContainer API to support the pids controller of cgroups
Reviewed-by: sgehwolf, lucy
This commit is contained in:
parent
2384e12888
commit
089e83bf1b
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,11 +34,15 @@
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
// controller names have to match the *_IDX indices
|
||||
static const char* cg_controller_name[] = { "cpu", "cpuset", "cpuacct", "memory", "pids" };
|
||||
|
||||
CgroupSubsystem* CgroupSubsystemFactory::create() {
|
||||
CgroupV1MemoryController* memory = NULL;
|
||||
CgroupV1Controller* cpuset = NULL;
|
||||
CgroupV1Controller* cpu = NULL;
|
||||
CgroupV1Controller* cpuacct = NULL;
|
||||
CgroupV1Controller* pids = NULL;
|
||||
CgroupInfo cg_infos[CG_INFO_LENGTH];
|
||||
u1 cg_type_flags = INVALID_CGROUPS_GENERIC;
|
||||
const char* proc_cgroups = "/proc/cgroups";
|
||||
@ -93,22 +97,29 @@ CgroupSubsystem* CgroupSubsystemFactory::create() {
|
||||
assert(is_cgroup_v1(&cg_type_flags), "Cgroup v1 expected");
|
||||
for (int i = 0; i < CG_INFO_LENGTH; i++) {
|
||||
CgroupInfo info = cg_infos[i];
|
||||
if (strcmp(info._name, "memory") == 0) {
|
||||
memory = new CgroupV1MemoryController(info._root_mount_path, info._mount_path);
|
||||
memory->set_subsystem_path(info._cgroup_path);
|
||||
} else if (strcmp(info._name, "cpuset") == 0) {
|
||||
cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path);
|
||||
cpuset->set_subsystem_path(info._cgroup_path);
|
||||
} else if (strcmp(info._name, "cpu") == 0) {
|
||||
cpu = new CgroupV1Controller(info._root_mount_path, info._mount_path);
|
||||
cpu->set_subsystem_path(info._cgroup_path);
|
||||
} else if (strcmp(info._name, "cpuacct") == 0) {
|
||||
cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path);
|
||||
cpuacct->set_subsystem_path(info._cgroup_path);
|
||||
if (info._data_complete) { // pids controller might have incomplete data
|
||||
if (strcmp(info._name, "memory") == 0) {
|
||||
memory = new CgroupV1MemoryController(info._root_mount_path, info._mount_path);
|
||||
memory->set_subsystem_path(info._cgroup_path);
|
||||
} else if (strcmp(info._name, "cpuset") == 0) {
|
||||
cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path);
|
||||
cpuset->set_subsystem_path(info._cgroup_path);
|
||||
} else if (strcmp(info._name, "cpu") == 0) {
|
||||
cpu = new CgroupV1Controller(info._root_mount_path, info._mount_path);
|
||||
cpu->set_subsystem_path(info._cgroup_path);
|
||||
} else if (strcmp(info._name, "cpuacct") == 0) {
|
||||
cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path);
|
||||
cpuacct->set_subsystem_path(info._cgroup_path);
|
||||
} else if (strcmp(info._name, "pids") == 0) {
|
||||
pids = new CgroupV1Controller(info._root_mount_path, info._mount_path);
|
||||
pids->set_subsystem_path(info._cgroup_path);
|
||||
}
|
||||
} else {
|
||||
log_debug(os, container)("CgroupInfo for %s not complete", cg_controller_name[i]);
|
||||
}
|
||||
}
|
||||
cleanup(cg_infos);
|
||||
return new CgroupV1Subsystem(cpuset, cpu, cpuacct, memory);
|
||||
return new CgroupV1Subsystem(cpuset, cpu, cpuacct, pids, memory);
|
||||
}
|
||||
|
||||
bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
|
||||
@ -122,9 +133,10 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
|
||||
char buf[MAXPATHLEN+1];
|
||||
char *p;
|
||||
bool is_cgroupsV2;
|
||||
// true iff all controllers, memory, cpu, cpuset, cpuacct are enabled
|
||||
// true iff all required controllers, memory, cpu, cpuset, cpuacct are enabled
|
||||
// at the kernel level.
|
||||
bool all_controllers_enabled;
|
||||
// pids might not be enabled on older Linux distros (SLES 12.1, RHEL 7.1)
|
||||
bool all_required_controllers_enabled;
|
||||
|
||||
/*
|
||||
* Read /proc/cgroups so as to be able to distinguish cgroups v2 vs cgroups v1.
|
||||
@ -136,10 +148,9 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
|
||||
*/
|
||||
cgroups = fopen(proc_cgroups, "r");
|
||||
if (cgroups == NULL) {
|
||||
log_debug(os, container)("Can't open %s, %s",
|
||||
proc_cgroups, os::strerror(errno));
|
||||
*flags = INVALID_CGROUPS_GENERIC;
|
||||
return false;
|
||||
log_debug(os, container)("Can't open %s, %s", proc_cgroups, os::strerror(errno));
|
||||
*flags = INVALID_CGROUPS_GENERIC;
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((p = fgets(buf, MAXPATHLEN, cgroups)) != NULL) {
|
||||
@ -167,19 +178,30 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
|
||||
cg_infos[CPUACCT_IDX]._name = os::strdup(name);
|
||||
cg_infos[CPUACCT_IDX]._hierarchy_id = hierarchy_id;
|
||||
cg_infos[CPUACCT_IDX]._enabled = (enabled == 1);
|
||||
} else if (strcmp(name, "pids") == 0) {
|
||||
log_debug(os, container)("Detected optional pids controller entry in %s", proc_cgroups);
|
||||
cg_infos[PIDS_IDX]._name = os::strdup(name);
|
||||
cg_infos[PIDS_IDX]._hierarchy_id = hierarchy_id;
|
||||
cg_infos[PIDS_IDX]._enabled = (enabled == 1);
|
||||
}
|
||||
}
|
||||
fclose(cgroups);
|
||||
|
||||
is_cgroupsV2 = true;
|
||||
all_controllers_enabled = true;
|
||||
all_required_controllers_enabled = true;
|
||||
for (int i = 0; i < CG_INFO_LENGTH; i++) {
|
||||
is_cgroupsV2 = is_cgroupsV2 && cg_infos[i]._hierarchy_id == 0;
|
||||
all_controllers_enabled = all_controllers_enabled && cg_infos[i]._enabled;
|
||||
// pids controller is optional. All other controllers are required
|
||||
if (i != PIDS_IDX) {
|
||||
is_cgroupsV2 = is_cgroupsV2 && cg_infos[i]._hierarchy_id == 0;
|
||||
all_required_controllers_enabled = all_required_controllers_enabled && cg_infos[i]._enabled;
|
||||
}
|
||||
if (log_is_enabled(Debug, os, container) && !cg_infos[i]._enabled) {
|
||||
log_debug(os, container)("controller %s is not enabled\n", cg_controller_name[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!all_controllers_enabled) {
|
||||
// one or more controllers disabled, disable container support
|
||||
if (!all_required_controllers_enabled) {
|
||||
// one or more required controllers disabled, disable container support
|
||||
log_debug(os, container)("One or more required controllers disabled at kernel level.");
|
||||
cleanup(cg_infos);
|
||||
*flags = INVALID_CGROUPS_GENERIC;
|
||||
@ -220,17 +242,21 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
|
||||
|
||||
while (!is_cgroupsV2 && (token = strsep(&controllers, ",")) != NULL) {
|
||||
if (strcmp(token, "memory") == 0) {
|
||||
assert(hierarchy_id == cg_infos[MEMORY_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch");
|
||||
assert(hierarchy_id == cg_infos[MEMORY_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for memory");
|
||||
cg_infos[MEMORY_IDX]._cgroup_path = os::strdup(cgroup_path);
|
||||
} else if (strcmp(token, "cpuset") == 0) {
|
||||
assert(hierarchy_id == cg_infos[CPUSET_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch");
|
||||
assert(hierarchy_id == cg_infos[CPUSET_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpuset");
|
||||
cg_infos[CPUSET_IDX]._cgroup_path = os::strdup(cgroup_path);
|
||||
} else if (strcmp(token, "cpu") == 0) {
|
||||
assert(hierarchy_id == cg_infos[CPU_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch");
|
||||
assert(hierarchy_id == cg_infos[CPU_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpu");
|
||||
cg_infos[CPU_IDX]._cgroup_path = os::strdup(cgroup_path);
|
||||
} else if (strcmp(token, "cpuacct") == 0) {
|
||||
assert(hierarchy_id == cg_infos[CPUACCT_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch");
|
||||
assert(hierarchy_id == cg_infos[CPUACCT_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpuacc");
|
||||
cg_infos[CPUACCT_IDX]._cgroup_path = os::strdup(cgroup_path);
|
||||
} else if (strcmp(token, "pids") == 0) {
|
||||
assert(hierarchy_id == cg_infos[PIDS_IDX]._hierarchy_id, "/proc/cgroups (%d) and /proc/self/cgroup (%d) hierarchy mismatch for pids",
|
||||
cg_infos[PIDS_IDX]._hierarchy_id, hierarchy_id);
|
||||
cg_infos[PIDS_IDX]._cgroup_path = os::strdup(cgroup_path);
|
||||
}
|
||||
}
|
||||
if (is_cgroupsV2) {
|
||||
@ -281,13 +307,15 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
|
||||
|
||||
/* Cgroup v1 relevant info
|
||||
*
|
||||
* Find the cgroup mount point for memory, cpuset, cpu, cpuacct
|
||||
* Find the cgroup mount point for memory, cpuset, cpu, cpuacct, pids
|
||||
*
|
||||
* Example for docker:
|
||||
* 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory
|
||||
*
|
||||
* Example for host:
|
||||
* 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory
|
||||
*
|
||||
* 44 31 0:39 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:23 - cgroup cgroup rw,pids
|
||||
*/
|
||||
if (sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- %s %*s %s", tmproot, tmpmount, tmp_fs_type, tmpcgroups) == 4) {
|
||||
if (strcmp("cgroup", tmp_fs_type) != 0) {
|
||||
@ -333,6 +361,12 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
|
||||
cg_infos[CPUACCT_IDX]._mount_path = os::strdup(tmpmount);
|
||||
cg_infos[CPUACCT_IDX]._root_mount_path = os::strdup(tmproot);
|
||||
cg_infos[CPUACCT_IDX]._data_complete = true;
|
||||
} else if (strcmp(token, "pids") == 0) {
|
||||
any_cgroup_mounts_found = true;
|
||||
assert(cg_infos[PIDS_IDX]._mount_path == NULL, "stomping of _mount_path");
|
||||
cg_infos[PIDS_IDX]._mount_path = os::strdup(tmpmount);
|
||||
cg_infos[PIDS_IDX]._root_mount_path = os::strdup(tmproot);
|
||||
cg_infos[PIDS_IDX]._data_complete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -387,10 +421,13 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,
|
||||
*flags = INVALID_CGROUPS_V1;
|
||||
return false;
|
||||
}
|
||||
if (log_is_enabled(Debug, os, container) && !cg_infos[PIDS_IDX]._data_complete) {
|
||||
log_debug(os, container)("Optional cgroup v1 pids subsystem not found");
|
||||
// keep the other controller info, pids is optional
|
||||
}
|
||||
// Cgroups v1 case, we have all the info we need.
|
||||
*flags = CGROUPS_V1;
|
||||
return true;
|
||||
|
||||
};
|
||||
|
||||
void CgroupSubsystemFactory::cleanup(CgroupInfo* cg_infos) {
|
||||
@ -514,3 +551,22 @@ jlong CgroupSubsystem::memory_limit_in_bytes() {
|
||||
memory_limit->set_value(mem_limit, OSCONTAINER_CACHE_TIMEOUT);
|
||||
return mem_limit;
|
||||
}
|
||||
|
||||
jlong CgroupSubsystem::limit_from_str(char* limit_str) {
|
||||
if (limit_str == NULL) {
|
||||
return OSCONTAINER_ERROR;
|
||||
}
|
||||
// Unlimited memory in cgroups is the literal string 'max' for
|
||||
// some controllers, for example the pids controller.
|
||||
if (strcmp("max", limit_str) == 0) {
|
||||
os::free(limit_str);
|
||||
return (jlong)-1;
|
||||
}
|
||||
julong limit;
|
||||
if (sscanf(limit_str, JULONG_FORMAT, &limit) != 1) {
|
||||
os::free(limit_str);
|
||||
return OSCONTAINER_ERROR;
|
||||
}
|
||||
os::free(limit_str);
|
||||
return (jlong)limit;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -61,12 +61,13 @@
|
||||
#define INVALID_CGROUPS_NO_MOUNT 5
|
||||
#define INVALID_CGROUPS_GENERIC 6
|
||||
|
||||
// Four controllers: cpu, cpuset, cpuacct, memory
|
||||
#define CG_INFO_LENGTH 4
|
||||
// Five controllers: cpu, cpuset, cpuacct, memory, pids
|
||||
#define CG_INFO_LENGTH 5
|
||||
#define CPUSET_IDX 0
|
||||
#define CPU_IDX 1
|
||||
#define CPUACCT_IDX 2
|
||||
#define MEMORY_IDX 3
|
||||
#define PIDS_IDX 4
|
||||
|
||||
typedef char * cptr;
|
||||
|
||||
@ -238,10 +239,12 @@ class CgroupSubsystem: public CHeapObj<mtInternal> {
|
||||
public:
|
||||
jlong memory_limit_in_bytes();
|
||||
int active_processor_count();
|
||||
jlong limit_from_str(char* limit_str);
|
||||
|
||||
virtual int cpu_quota() = 0;
|
||||
virtual int cpu_period() = 0;
|
||||
virtual int cpu_shares() = 0;
|
||||
virtual jlong pids_max() = 0;
|
||||
virtual jlong memory_usage_in_bytes() = 0;
|
||||
virtual jlong memory_and_swap_limit_in_bytes() = 0;
|
||||
virtual jlong memory_soft_limit_in_bytes() = 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -241,3 +241,28 @@ int CgroupV1Subsystem::cpu_shares() {
|
||||
|
||||
return shares;
|
||||
}
|
||||
|
||||
|
||||
char* CgroupV1Subsystem::pids_max_val() {
|
||||
GET_CONTAINER_INFO_CPTR(cptr, _pids, "/pids.max",
|
||||
"Maximum number of tasks is: %s", "%s %*d", pidsmax, 1024);
|
||||
if (pidsmax == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return os::strdup(pidsmax);
|
||||
}
|
||||
|
||||
/* pids_max
|
||||
*
|
||||
* Return the maximum number of tasks available to the process
|
||||
*
|
||||
* return:
|
||||
* maximum number of tasks
|
||||
* -1 for unlimited
|
||||
* OSCONTAINER_ERROR for not supported
|
||||
*/
|
||||
jlong CgroupV1Subsystem::pids_max() {
|
||||
if (_pids == NULL) return OSCONTAINER_ERROR;
|
||||
char * pidsmax_str = pids_max_val();
|
||||
return limit_from_str(pidsmax_str);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -87,6 +87,8 @@ class CgroupV1Subsystem: public CgroupSubsystem {
|
||||
|
||||
int cpu_shares();
|
||||
|
||||
jlong pids_max();
|
||||
|
||||
const char * container_type() {
|
||||
return "cgroupv1";
|
||||
}
|
||||
@ -101,15 +103,20 @@ class CgroupV1Subsystem: public CgroupSubsystem {
|
||||
CgroupV1Controller* _cpuset = NULL;
|
||||
CachingCgroupController* _cpu = NULL;
|
||||
CgroupV1Controller* _cpuacct = NULL;
|
||||
CgroupV1Controller* _pids = NULL;
|
||||
|
||||
char * pids_max_val();
|
||||
|
||||
public:
|
||||
CgroupV1Subsystem(CgroupV1Controller* cpuset,
|
||||
CgroupV1Controller* cpu,
|
||||
CgroupV1Controller* cpuacct,
|
||||
CgroupV1Controller* pids,
|
||||
CgroupV1MemoryController* memory) {
|
||||
_cpuset = cpuset;
|
||||
_cpu = new CachingCgroupController(cpu);
|
||||
_cpuacct = cpuacct;
|
||||
_pids = pids;
|
||||
_memory = new CachingCgroupController(memory);
|
||||
_unlimited_memory = (LONG_MAX / os::vm_page_size()) * os::vm_page_size();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Red Hat Inc.
|
||||
* Copyright (c) 2020, 2021, Red Hat Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -203,24 +203,6 @@ jlong CgroupV2Subsystem::read_memory_limit_in_bytes() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
jlong CgroupV2Subsystem::limit_from_str(char* limit_str) {
|
||||
if (limit_str == NULL) {
|
||||
return OSCONTAINER_ERROR;
|
||||
}
|
||||
// Unlimited memory in Cgroups V2 is the literal string 'max'
|
||||
if (strcmp("max", limit_str) == 0) {
|
||||
os::free(limit_str);
|
||||
return (jlong)-1;
|
||||
}
|
||||
julong limit;
|
||||
if (sscanf(limit_str, JULONG_FORMAT, &limit) != 1) {
|
||||
os::free(limit_str);
|
||||
return OSCONTAINER_ERROR;
|
||||
}
|
||||
os::free(limit_str);
|
||||
return (jlong)limit;
|
||||
}
|
||||
|
||||
char* CgroupV2Subsystem::mem_limit_val() {
|
||||
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.max",
|
||||
"Raw value for memory limit is: %s", "%s", mem_limit_str, 1024);
|
||||
@ -244,3 +226,26 @@ char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) {
|
||||
return os::strdup(buf);
|
||||
}
|
||||
|
||||
char* CgroupV2Subsystem::pids_max_val() {
|
||||
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/pids.max",
|
||||
"Maximum number of tasks is: %s", "%s %*d", pidsmax, 1024);
|
||||
if (pidsmax == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return os::strdup(pidsmax);
|
||||
}
|
||||
|
||||
/* pids_max
|
||||
*
|
||||
* Return the maximum number of tasks available to the process
|
||||
*
|
||||
* return:
|
||||
* maximum number of tasks
|
||||
* -1 for unlimited
|
||||
* OSCONTAINER_ERROR for not supported
|
||||
*/
|
||||
jlong CgroupV2Subsystem::pids_max() {
|
||||
char * pidsmax_str = pids_max_val();
|
||||
return limit_from_str(pidsmax_str);
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ class CgroupV2Subsystem: public CgroupSubsystem {
|
||||
char *mem_swp_limit_val();
|
||||
char *mem_soft_limit_val();
|
||||
char *cpu_quota_val();
|
||||
jlong limit_from_str(char* limit_str);
|
||||
char *pids_max_val();
|
||||
|
||||
public:
|
||||
CgroupV2Subsystem(CgroupController * unified) {
|
||||
@ -79,6 +79,8 @@ class CgroupV2Subsystem: public CgroupSubsystem {
|
||||
jlong memory_max_usage_in_bytes();
|
||||
char * cpu_cpuset_cpus();
|
||||
char * cpu_cpuset_memory_nodes();
|
||||
jlong pids_max();
|
||||
|
||||
const char * container_type() {
|
||||
return "cgroupv2";
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -129,3 +129,8 @@ int OSContainer::cpu_shares() {
|
||||
assert(cgroup_subsystem != NULL, "cgroup subsystem not available");
|
||||
return cgroup_subsystem->cpu_shares();
|
||||
}
|
||||
|
||||
jlong OSContainer::pids_max() {
|
||||
assert(cgroup_subsystem != NULL, "cgroup subsystem not available");
|
||||
return cgroup_subsystem->pids_max();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -62,6 +62,7 @@ class OSContainer: AllStatic {
|
||||
|
||||
static int cpu_shares();
|
||||
|
||||
static jlong pids_max();
|
||||
};
|
||||
|
||||
inline bool OSContainer::is_containerized() {
|
||||
|
@ -2238,6 +2238,7 @@ void os::Linux::print_uptime_info(outputStream* st) {
|
||||
|
||||
bool os::Linux::print_container_info(outputStream* st) {
|
||||
if (!OSContainer::is_containerized()) {
|
||||
st->print_cr("container information not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2326,6 +2327,14 @@ bool os::Linux::print_container_info(outputStream* st) {
|
||||
st->print_cr("%s", j == OSCONTAINER_ERROR ? "not supported" : "unlimited");
|
||||
}
|
||||
|
||||
j = OSContainer::OSContainer::pids_max();
|
||||
st->print("maximum number of tasks: ");
|
||||
if (j > 0) {
|
||||
st->print_cr(JLONG_FORMAT, j);
|
||||
} else {
|
||||
st->print_cr("%s", j == OSCONTAINER_ERROR ? "not supported" : "unlimited");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -995,7 +995,7 @@ bool WhiteBox::validate_cgroup(const char* proc_cgroups,
|
||||
const char* proc_self_cgroup,
|
||||
const char* proc_self_mountinfo,
|
||||
u1* cg_flags) {
|
||||
CgroupInfo cg_infos[4];
|
||||
CgroupInfo cg_infos[CG_INFO_LENGTH];
|
||||
return CgroupSubsystemFactory::determine_type(cg_infos, proc_cgroups,
|
||||
proc_self_cgroup,
|
||||
proc_self_mountinfo, cg_flags);
|
||||
|
@ -149,6 +149,11 @@ public class CgroupMetrics implements Metrics {
|
||||
return subsystem.getMemorySoftLimit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPidsMax() {
|
||||
return subsystem.getPidsMax();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBlkIOServiceCount() {
|
||||
return subsystem.getBlkIOServiceCount();
|
||||
|
@ -36,5 +36,13 @@ public interface CgroupSubsystem extends Metrics {
|
||||
* has determined that no limit is being imposed.
|
||||
*/
|
||||
public static final long LONG_RETVAL_UNLIMITED = -1;
|
||||
public static final String MAX_VAL = "max";
|
||||
|
||||
public static long limitFromString(String strVal) {
|
||||
if (strVal == null || MAX_VAL.equals(strVal)) {
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
}
|
||||
return Long.parseLong(strVal);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ public class CgroupSubsystemFactory {
|
||||
private static final String CPUSET_CTRL = "cpuset";
|
||||
private static final String BLKIO_CTRL = "blkio";
|
||||
private static final String MEMORY_CTRL = "memory";
|
||||
private static final String PIDS_CTRL = "pids";
|
||||
|
||||
/*
|
||||
* From https://www.kernel.org/doc/Documentation/filesystems/proc.txt
|
||||
@ -149,6 +150,7 @@ public class CgroupSubsystemFactory {
|
||||
case CPUSET_CTRL: infos.put(CPUSET_CTRL, info); break;
|
||||
case MEMORY_CTRL: infos.put(MEMORY_CTRL, info); break;
|
||||
case BLKIO_CTRL: infos.put(BLKIO_CTRL, info); break;
|
||||
case PIDS_CTRL: infos.put(PIDS_CTRL, info); break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,6 +253,7 @@ public class CgroupSubsystemFactory {
|
||||
case CPUACCT_CTRL:
|
||||
case CPU_CTRL:
|
||||
case BLKIO_CTRL:
|
||||
case PIDS_CTRL:
|
||||
CgroupInfo info = infos.get(cName);
|
||||
info.setCgroupPath(cgroupPath);
|
||||
break;
|
||||
@ -302,6 +305,7 @@ public class CgroupSubsystemFactory {
|
||||
case MEMORY_CTRL: // fall-through
|
||||
case CPU_CTRL:
|
||||
case CPUACCT_CTRL:
|
||||
case PIDS_CTRL:
|
||||
case BLKIO_CTRL: {
|
||||
CgroupInfo info = infos.get(controllerName);
|
||||
assert info.getMountPoint() == null;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -38,6 +38,7 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
|
||||
private CgroupV1SubsystemController cpuacct;
|
||||
private CgroupV1SubsystemController cpuset;
|
||||
private CgroupV1SubsystemController blkio;
|
||||
private CgroupV1SubsystemController pids;
|
||||
|
||||
private static volatile CgroupV1Subsystem INSTANCE;
|
||||
|
||||
@ -126,6 +127,15 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "pids": {
|
||||
if (info.getMountRoot() != null && info.getMountPoint() != null) {
|
||||
CgroupV1SubsystemController controller = new CgroupV1SubsystemController(info.getMountRoot(), info.getMountPoint());
|
||||
controller.setPath(info.getCgroupPath());
|
||||
subsystem.setPidsController(controller);
|
||||
anyActiveControllers = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new AssertionError("Unrecognized controller in infos: " + info.getName());
|
||||
}
|
||||
@ -170,6 +180,10 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
|
||||
this.blkio = blkio;
|
||||
}
|
||||
|
||||
private void setPidsController(CgroupV1SubsystemController pids) {
|
||||
this.pids = pids;
|
||||
}
|
||||
|
||||
private static long getLongValue(CgroupSubsystemController controller,
|
||||
String parm) {
|
||||
return CgroupSubsystemController.getLongValue(controller,
|
||||
@ -394,6 +408,13 @@ public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
|
||||
return CgroupV1SubsystemController.longValOrUnlimited(getLongValue(memory, "memory.soft_limit_in_bytes"));
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* pids subsystem
|
||||
****************************************************************/
|
||||
public long getPidsMax() {
|
||||
String pidsMaxStr = CgroupSubsystemController.getStringValue(pids, "pids.max");
|
||||
return CgroupSubsystem.limitFromString(pidsMaxStr);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* BlKIO Subsystem
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Red Hat Inc.
|
||||
* Copyright (c) 2020, 2021, Red Hat Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -45,7 +45,6 @@ public class CgroupV2Subsystem implements CgroupSubsystem {
|
||||
private final CgroupSubsystemController unified;
|
||||
private static final String PROVIDER_NAME = "cgroupv2";
|
||||
private static final int PER_CPU_SHARES = 1024;
|
||||
private static final String MAX_VAL = "max";
|
||||
private static final Object EMPTY_STR = "";
|
||||
private static final long NO_SWAP = 0;
|
||||
|
||||
@ -149,14 +148,7 @@ public class CgroupV2Subsystem implements CgroupSubsystem {
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
}
|
||||
String quota = tokens[tokenIdx];
|
||||
return limitFromString(quota);
|
||||
}
|
||||
|
||||
private long limitFromString(String strVal) {
|
||||
if (strVal == null || MAX_VAL.equals(strVal)) {
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
}
|
||||
return Long.parseLong(strVal);
|
||||
return CgroupSubsystem.limitFromString(quota);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -251,7 +243,7 @@ public class CgroupV2Subsystem implements CgroupSubsystem {
|
||||
@Override
|
||||
public long getMemoryLimit() {
|
||||
String strVal = CgroupSubsystemController.getStringValue(unified, "memory.max");
|
||||
return limitFromString(strVal);
|
||||
return CgroupSubsystem.limitFromString(strVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -279,7 +271,7 @@ public class CgroupV2Subsystem implements CgroupSubsystem {
|
||||
if (strVal == null) {
|
||||
return getMemoryLimit();
|
||||
}
|
||||
long swapLimit = limitFromString(strVal);
|
||||
long swapLimit = CgroupSubsystem.limitFromString(strVal);
|
||||
if (swapLimit >= 0) {
|
||||
long memoryLimit = getMemoryLimit();
|
||||
assert memoryLimit >= 0;
|
||||
@ -310,7 +302,13 @@ public class CgroupV2Subsystem implements CgroupSubsystem {
|
||||
@Override
|
||||
public long getMemorySoftLimit() {
|
||||
String softLimitStr = CgroupSubsystemController.getStringValue(unified, "memory.low");
|
||||
return limitFromString(softLimitStr);
|
||||
return CgroupSubsystem.limitFromString(softLimitStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPidsMax() {
|
||||
String pidsMaxStr = CgroupSubsystemController.getStringValue(unified, "pids.max");
|
||||
return CgroupSubsystem.limitFromString(pidsMaxStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -352,6 +352,19 @@ public interface Metrics {
|
||||
*/
|
||||
public long getMemorySoftLimit();
|
||||
|
||||
/*****************************************************************
|
||||
* pids subsystem
|
||||
****************************************************************/
|
||||
|
||||
/**
|
||||
* Returns the maximum number of tasks that may be created in the Isolation Group.
|
||||
*
|
||||
* @return The maximum number of tasks, -1 if the quota is unlimited or
|
||||
* -2 if not supported.
|
||||
*
|
||||
*/
|
||||
public long getPidsMax();
|
||||
|
||||
/*****************************************************************
|
||||
* BlKIO Subsystem
|
||||
****************************************************************/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -405,12 +405,23 @@ public final class LauncherHelper {
|
||||
limit = c.getMemoryAndSwapLimit();
|
||||
ostream.println(formatLimitString(limit, INDENT + "Memory & Swap Limit: ", longRetvalNotSupported));
|
||||
|
||||
limit = c.getPidsMax();
|
||||
ostream.println(formatLimitString(limit, INDENT + "Maximum Processes Limit: ",
|
||||
longRetvalNotSupported, false));
|
||||
ostream.println("");
|
||||
}
|
||||
|
||||
private static String formatLimitString(long limit, String prefix, long unavailable) {
|
||||
return formatLimitString(limit, prefix, unavailable, true);
|
||||
}
|
||||
|
||||
private static String formatLimitString(long limit, String prefix, long unavailable, boolean scale) {
|
||||
if (limit >= 0) {
|
||||
return prefix + SizePrefix.scaleValue(limit);
|
||||
if (scale) {
|
||||
return prefix + SizePrefix.scaleValue(limit);
|
||||
} else {
|
||||
return prefix + limit;
|
||||
}
|
||||
} else if (limit == unavailable) {
|
||||
return prefix + "N/A";
|
||||
} else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Red Hat Inc.
|
||||
* Copyright (c) 2020, 2021, Red Hat Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -105,6 +105,7 @@ public class CgroupSubsystemFactory {
|
||||
"devices 0 1 1\n" +
|
||||
"freezer 0 1 1\n" +
|
||||
"net_cls 0 1 1\n" +
|
||||
"pids 0 1 1\n" +
|
||||
"blkio 0 1 1\n" +
|
||||
"perf_event 0 1 1 ";
|
||||
private String cgroupsNonZeroJoinControllers =
|
||||
@ -168,7 +169,7 @@ public class CgroupSubsystemFactory {
|
||||
"perf_event 4 1 1\n" +
|
||||
"net_prio 5 1 1\n" +
|
||||
"hugetlb 6 1 1\n" +
|
||||
"pids 3 80 1";
|
||||
"pids 9 80 1"; // hierarchy has to match procSelfCgroupHybridContent
|
||||
private String mntInfoCgroupsV2Only =
|
||||
"28 21 0:25 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime shared:4 - cgroup2 none rw,seclabel,nsdelegate";
|
||||
private String mntInfoCgroupsV1SystemdOnly =
|
||||
|
@ -105,7 +105,8 @@ public class TestMisc {
|
||||
"Memory Soft Limit",
|
||||
"Memory Usage",
|
||||
"Maximum Memory Usage",
|
||||
"memory_max_usage_in_bytes"
|
||||
"memory_max_usage_in_bytes",
|
||||
"maximum number of tasks"
|
||||
};
|
||||
|
||||
for (String s : expectedToContain) {
|
||||
|
142
test/hotspot/jtreg/containers/docker/TestPids.java
Normal file
142
test/hotspot/jtreg/containers/docker/TestPids.java
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @key cgroups
|
||||
* @summary Test JVM's awareness of pids controller
|
||||
* @requires docker.support
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @build sun.hotspot.WhiteBox PrintContainerInfo
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox
|
||||
* @run driver TestPids
|
||||
*/
|
||||
import java.util.List;
|
||||
import jdk.test.lib.containers.docker.Common;
|
||||
import jdk.test.lib.containers.docker.DockerRunOptions;
|
||||
import jdk.test.lib.containers.docker.DockerTestUtils;
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.Platform;
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
public class TestPids {
|
||||
private static final String imageName = Common.imageName("pids");
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (!DockerTestUtils.canTestDocker()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Common.prepareWhiteBox();
|
||||
DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
|
||||
|
||||
try {
|
||||
testPids();
|
||||
} finally {
|
||||
if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) {
|
||||
DockerTestUtils.removeDockerImage(imageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testPids() throws Exception {
|
||||
System.out.println("Testing pids controller ...");
|
||||
testPids("400");
|
||||
testPids("800");
|
||||
testPids("2000");
|
||||
testPids("Unlimited");
|
||||
}
|
||||
|
||||
private static DockerRunOptions commonOpts() {
|
||||
DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "PrintContainerInfo");
|
||||
opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
|
||||
opts.addJavaOpts("-Xlog:os+container=trace", "-cp", "/test-classes/");
|
||||
Common.addWhiteBoxOpts(opts);
|
||||
return opts;
|
||||
}
|
||||
|
||||
private static void checkResult(List<String> lines, String lineMarker, String expectedValue) {
|
||||
boolean lineMarkerFound = false;
|
||||
|
||||
for (String line : lines) {
|
||||
if (line.contains("WARNING: Your kernel does not support pids limit capabilities")) {
|
||||
System.out.println("Docker pids limitation seems not to work, avoiding check");
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.contains(lineMarker)) {
|
||||
lineMarkerFound = true;
|
||||
String[] parts = line.split(":");
|
||||
System.out.println("DEBUG: line = " + line);
|
||||
System.out.println("DEBUG: parts.length = " + parts.length);
|
||||
|
||||
Asserts.assertEquals(parts.length, 2);
|
||||
String actual = parts[1].replaceAll("\\s","");
|
||||
// Unlimited pids leads on some setups not to "max" in the output, but to a high number
|
||||
if (expectedValue.equals("max")) {
|
||||
if (actual.equals("max")) {
|
||||
System.out.println("Found expected max for unlimited pids value.");
|
||||
} else {
|
||||
try {
|
||||
int ai = Integer.parseInt(actual);
|
||||
if (ai > 20000) {
|
||||
System.out.println("Limit value " + ai + " got accepted as unlimited, log line was " + line);
|
||||
} else {
|
||||
throw new RuntimeException("Limit value " + ai + " is not accepted as unlimited, log line was " + line);
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new RuntimeException("Could not convert " + actual + " to an integer, log line was " + line);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Asserts.assertEquals(actual, expectedValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Asserts.assertTrue(lineMarkerFound);
|
||||
}
|
||||
|
||||
private static void testPids(String value) throws Exception {
|
||||
Common.logNewTestCase("pids controller test, limiting value = " + value);
|
||||
|
||||
DockerRunOptions opts = commonOpts();
|
||||
if (value.equals("Unlimited")) {
|
||||
opts.addDockerOpts("--pids-limit=-1");
|
||||
} else {
|
||||
opts.addDockerOpts("--pids-limit="+value);
|
||||
}
|
||||
|
||||
List<String> lines = Common.run(opts).asLines();
|
||||
if (value.equals("Unlimited")) {
|
||||
checkResult(lines, "Maximum number of tasks is: ", "max");
|
||||
} else {
|
||||
checkResult(lines, "Maximum number of tasks is: ", value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
127
test/jdk/jdk/internal/platform/docker/TestPidsLimit.java
Normal file
127
test/jdk/jdk/internal/platform/docker/TestPidsLimit.java
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @key cgroups
|
||||
* @summary Test JDK Metrics class when running inside a docker container with limited pids
|
||||
* @bug 8266490
|
||||
* @requires docker.support
|
||||
* @library /test/lib
|
||||
* @build TestPidsLimit
|
||||
* @run driver TestPidsLimit
|
||||
*/
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jdk.test.lib.containers.docker.Common;
|
||||
import jdk.test.lib.containers.docker.DockerRunOptions;
|
||||
import jdk.test.lib.containers.docker.DockerTestUtils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
public class TestPidsLimit {
|
||||
private static final String imageName = Common.imageName("pids");
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (!DockerTestUtils.canTestDocker()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
|
||||
|
||||
try {
|
||||
testPidsLimit("1000");
|
||||
testPidsLimit("2000");
|
||||
testPidsLimit("Unlimited");
|
||||
} finally {
|
||||
if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) {
|
||||
DockerTestUtils.removeDockerImage(imageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkResult(List<String> lines, String lineMarker, String expectedValue) {
|
||||
boolean lineMarkerFound = false;
|
||||
|
||||
for (String line : lines) {
|
||||
if (line.contains("WARNING: Your kernel does not support pids limit capabilities")) {
|
||||
System.out.println("Docker pids limitation seems not to work, avoiding check");
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.contains(lineMarker)) {
|
||||
lineMarkerFound = true;
|
||||
String[] parts = line.split(":");
|
||||
System.out.println("DEBUG: line = " + line);
|
||||
System.out.println("DEBUG: parts.length = " + parts.length);
|
||||
|
||||
Asserts.assertEquals(parts.length, 2);
|
||||
String actual = parts[1].replaceAll("\\s","");
|
||||
// Unlimited pids leads on some setups not to "max" in the output, but to a high number
|
||||
if (expectedValue.equals("Unlimited")) {
|
||||
if (actual.equals("Unlimited")) {
|
||||
System.out.println("Found expected value for unlimited pids.");
|
||||
} else {
|
||||
try {
|
||||
int ai = Integer.parseInt(actual);
|
||||
if (ai > 20000) {
|
||||
System.out.println("Limit value " + ai + " got accepted as unlimited, log line was " + line);
|
||||
} else {
|
||||
throw new RuntimeException("Limit value " + ai + " is not accepted as unlimited, log line was " + line);
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new RuntimeException("Could not convert " + actual + " to an integer, log line was " + line);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Asserts.assertEquals(actual, expectedValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Asserts.assertTrue(lineMarkerFound);
|
||||
}
|
||||
|
||||
private static void testPidsLimit(String pidsLimit) throws Exception {
|
||||
Common.logNewTestCase("testPidsLimit (limit: " + pidsLimit + ")");
|
||||
DockerRunOptions opts = Common.newOptsShowSettings(imageName);
|
||||
if (pidsLimit.equals("Unlimited")) {
|
||||
opts.addDockerOpts("--pids-limit=-1");
|
||||
} else {
|
||||
opts.addDockerOpts("--pids-limit="+pidsLimit);
|
||||
}
|
||||
|
||||
OutputAnalyzer out = DockerTestUtils.dockerRunJava(opts);
|
||||
out.shouldHaveExitValue(0);
|
||||
// some docker enviroments do not have the pids limit capabilities
|
||||
String sdr = out.getOutput();
|
||||
if (sdr.contains("WARNING: Your kernel does not support pids limit capabilities")) {
|
||||
System.out.println("Docker pids limitation seems not to work, avoiding check");
|
||||
} else {
|
||||
List<String> lines = new ArrayList<>();
|
||||
sdr.lines().forEach(s -> lines.add(s));
|
||||
checkResult(lines, "Maximum Processes Limit: ", pidsLimit);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -57,6 +57,10 @@ public class Common {
|
||||
.addJavaOpts("-Xlog:os+container=trace");
|
||||
}
|
||||
|
||||
public static DockerRunOptions newOptsShowSettings(String imageNameAndTag) {
|
||||
return new DockerRunOptions(imageNameAndTag, "/jdk/bin/java", "-version", "-XshowSettings:system");
|
||||
}
|
||||
|
||||
|
||||
// create commonly used options with class to be launched inside container
|
||||
public static DockerRunOptions newOpts(String imageNameAndTag, String testClass) {
|
||||
|
Loading…
Reference in New Issue
Block a user