Merge "processutils: add support for missing process limits"

This commit is contained in:
Jenkins 2016-05-04 13:24:04 +00:00 committed by Gerrit Code Review
commit 6bae2be9ba
3 changed files with 85 additions and 11 deletions

View File

@ -26,8 +26,15 @@ USAGE_PROGRAM = ('%s -m oslo_concurrency.prlimit'
RESOURCES = ( RESOURCES = (
# argparse argument => resource # argparse argument => resource
('as', resource.RLIMIT_AS), ('as', resource.RLIMIT_AS),
('core', resource.RLIMIT_CORE),
('cpu', resource.RLIMIT_CPU),
('data', resource.RLIMIT_DATA),
('fsize', resource.RLIMIT_FSIZE),
('memlock', resource.RLIMIT_MEMLOCK),
('nofile', resource.RLIMIT_NOFILE), ('nofile', resource.RLIMIT_NOFILE),
('nproc', resource.RLIMIT_NPROC),
('rss', resource.RLIMIT_RSS), ('rss', resource.RLIMIT_RSS),
('stack', resource.RLIMIT_STACK),
) )
@ -35,10 +42,24 @@ def parse_args():
parser = argparse.ArgumentParser(description='prlimit', prog=USAGE_PROGRAM) parser = argparse.ArgumentParser(description='prlimit', prog=USAGE_PROGRAM)
parser.add_argument('--as', type=int, parser.add_argument('--as', type=int,
help='Address space limit in bytes') help='Address space limit in bytes')
parser.add_argument('--core', type=int,
help='Core file size limit in bytes')
parser.add_argument('--cpu', type=int,
help='CPU time limit in seconds')
parser.add_argument('--data', type=int,
help='Data size limit in bytes')
parser.add_argument('--fsize', type=int,
help='File size limit in bytes')
parser.add_argument('--memlock', type=int,
help='Locked memory limit in bytes')
parser.add_argument('--nofile', type=int, parser.add_argument('--nofile', type=int,
help='Maximum number of open files') help='Maximum number of open files')
parser.add_argument('--nproc', type=int,
help='Maximum number of processes')
parser.add_argument('--rss', type=int, parser.add_argument('--rss', type=int,
help='Maximum Resident Set Size (RSS) in bytes') help='Maximum Resident Set Size (RSS) in bytes')
parser.add_argument('--stack', type=int,
help='Stack size limit in bytes')
parser.add_argument('program', parser.add_argument('program',
help='Program (absolute path)') help='Program (absolute path)')
parser.add_argument('program_args', metavar="arg", nargs='...', parser.add_argument('program_args', metavar="arg", nargs='...',

View File

@ -134,16 +134,36 @@ class ProcessLimits(object):
Attributes: Attributes:
* address_space: Address space limit in bytes * address_space: Address space limit in bytes
* number_files: Maximum number of open files. * core_file_size: Core file size limit in bytes
* cpu_time: CPU time limit in seconds
* data_size: Data size limit in bytes
* file_size: File size limit in bytes
* memory_locked: Locked memory limit in bytes
* number_files: Maximum number of open files
* number_processes: Maximum number of processes
* resident_set_size: Maximum Resident Set Size (RSS) in bytes * resident_set_size: Maximum Resident Set Size (RSS) in bytes
* stack_size: Stack size limit in bytes
This object can be used for the *prlimit* parameter of :func:`execute`. This object can be used for the *prlimit* parameter of :func:`execute`.
""" """
_LIMITS = {
"address_space": "--as",
"core_file_size": "--core",
"cpu_time": "--cpu",
"data_size": "--data",
"file_size": "--fsize",
"memory_locked": "--memlock",
"number_files": "--nofile",
"number_processes": "--nproc",
"resident_set_size": "--rss",
"stack_size": "--stack",
}
def __init__(self, **kw): def __init__(self, **kw):
self.address_space = kw.pop('address_space', None) for limit in self._LIMITS.keys():
self.number_files = kw.pop('number_files', None) setattr(self, limit, kw.pop(limit, None))
self.resident_set_size = kw.pop('resident_set_size', None)
if kw: if kw:
raise ValueError("invalid limits: %s" raise ValueError("invalid limits: %s"
% ', '.join(sorted(kw.keys()))) % ', '.join(sorted(kw.keys())))
@ -151,12 +171,10 @@ class ProcessLimits(object):
def prlimit_args(self): def prlimit_args(self):
"""Create a list of arguments for the prlimit command line.""" """Create a list of arguments for the prlimit command line."""
args = [] args = []
if self.address_space: for limit in self._LIMITS.keys():
args.append('--as=%s' % self.address_space) val = getattr(self, limit)
if self.number_files: if val is not None:
args.append('--nofile=%s' % self.number_files) args.append("%s=%s" % (self._LIMITS[limit], val))
if self.resident_set_size:
args.append('--rss=%s' % self.resident_set_size)
return args return args

View File

@ -752,7 +752,7 @@ class PrlimitTestCase(test_base.BaseTestCase):
# Create a new soft limit for a resource, lower than the current # Create a new soft limit for a resource, lower than the current
# soft limit. # soft limit.
soft_limit, hard_limit = resource.getrlimit(res) soft_limit, hard_limit = resource.getrlimit(res)
if soft_limit < 0: if soft_limit <= 0:
soft_limit = default_limit soft_limit = default_limit
else: else:
soft_limit -= substract soft_limit -= substract
@ -790,6 +790,31 @@ class PrlimitTestCase(test_base.BaseTestCase):
prlimit = self.limit_address_space() prlimit = self.limit_address_space()
self.check_limit(prlimit, 'RLIMIT_AS', prlimit.address_space) self.check_limit(prlimit, 'RLIMIT_AS', prlimit.address_space)
def test_core_size(self):
size = self.soft_limit(resource.RLIMIT_CORE, 1, 1024)
prlimit = processutils.ProcessLimits(core_file_size=size)
self.check_limit(prlimit, 'RLIMIT_CORE', prlimit.core_file_size)
def test_cpu_time(self):
time = self.soft_limit(resource.RLIMIT_CPU, 1, 1024)
prlimit = processutils.ProcessLimits(cpu_time=time)
self.check_limit(prlimit, 'RLIMIT_CPU', prlimit.cpu_time)
def test_data_size(self):
max_memory = self.memory_limit(resource.RLIMIT_DATA)
prlimit = processutils.ProcessLimits(data_size=max_memory)
self.check_limit(prlimit, 'RLIMIT_DATA', max_memory)
def test_file_size(self):
size = self.soft_limit(resource.RLIMIT_FSIZE, 1, 1024)
prlimit = processutils.ProcessLimits(file_size=size)
self.check_limit(prlimit, 'RLIMIT_FSIZE', prlimit.file_size)
def test_memory_locked(self):
max_memory = self.memory_limit(resource.RLIMIT_MEMLOCK)
prlimit = processutils.ProcessLimits(memory_locked=max_memory)
self.check_limit(prlimit, 'RLIMIT_MEMLOCK', max_memory)
def test_resident_set_size(self): def test_resident_set_size(self):
max_memory = self.memory_limit(resource.RLIMIT_RSS) max_memory = self.memory_limit(resource.RLIMIT_RSS)
prlimit = processutils.ProcessLimits(resident_set_size=max_memory) prlimit = processutils.ProcessLimits(resident_set_size=max_memory)
@ -800,6 +825,16 @@ class PrlimitTestCase(test_base.BaseTestCase):
prlimit = processutils.ProcessLimits(number_files=nfiles) prlimit = processutils.ProcessLimits(number_files=nfiles)
self.check_limit(prlimit, 'RLIMIT_NOFILE', nfiles) self.check_limit(prlimit, 'RLIMIT_NOFILE', nfiles)
def test_number_processes(self):
nprocs = self.soft_limit(resource.RLIMIT_NPROC, 1, 65535)
prlimit = processutils.ProcessLimits(number_processes=nprocs)
self.check_limit(prlimit, 'RLIMIT_NPROC', nprocs)
def test_stack_size(self):
max_memory = self.memory_limit(resource.RLIMIT_STACK)
prlimit = processutils.ProcessLimits(stack_size=max_memory)
self.check_limit(prlimit, 'RLIMIT_STACK', max_memory)
def test_unsupported_prlimit(self): def test_unsupported_prlimit(self):
self.assertRaises(ValueError, processutils.ProcessLimits, xxx=33) self.assertRaises(ValueError, processutils.ProcessLimits, xxx=33)