summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2024-05-28 21:51:17 +0200
committerGitHub <noreply@github.com>2024-05-28 21:51:17 +0200
commit9d0a453c923fe8efd5dafe6230dafe7d267aa9d6 (patch)
tree605277202acb37767fde9cced01c371d3bc8fd42
parent6954288ea6b1ec7a64cec1d370f8b11884166c18 (diff)
parentd180595aff41d8c23c35937656fbc8fe4d93ad7a (diff)
downloadvyos-1x-9d0a453c923fe8efd5dafe6230dafe7d267aa9d6.tar.gz
vyos-1x-9d0a453c923fe8efd5dafe6230dafe7d267aa9d6.zip
Merge pull request #3535 from vyos/mergify/bp/sagitta/pr-3530
T6406: Container CPU limits (backport #3530)
-rw-r--r--interface-definitions/container.xml.in18
-rwxr-xr-xsmoketest/scripts/cli/test_container.py16
-rwxr-xr-xsmoketest/scripts/system/test_kernel_options.py8
-rwxr-xr-xsrc/conf_mode/container.py9
4 files changed, 50 insertions, 1 deletions
diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in
index 2296a3e9e..1ad7215e5 100644
--- a/interface-definitions/container.xml.in
+++ b/interface-definitions/container.xml.in
@@ -192,6 +192,24 @@
</leafNode>
</children>
</tagNode>
+ <leafNode name="cpu-quota">
+ <properties>
+ <help>This limits the number of CPU resources the container can use</help>
+ <valueHelp>
+ <format>u32:0</format>
+ <description>Unlimited</description>
+ </valueHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Amount of CPU time the container can use in amount of cores (up to three decimals)</description>
+ </valueHelp>
+ <constraint>
+ <regex>(0|[1-9]\d*)(\.\d{1,3})?</regex>
+ </constraint>
+ <constraintErrorMessage>Container CPU limit must be a (decimal) number in range 0 to number of threads</constraintErrorMessage>
+ </properties>
+ <defaultValue>0</defaultValue>
+ </leafNode>
<leafNode name="memory">
<properties>
<help>Memory (RAM) available to this container</help>
diff --git a/smoketest/scripts/cli/test_container.py b/smoketest/scripts/cli/test_container.py
index 3201883b8..90f821c60 100755
--- a/smoketest/scripts/cli/test_container.py
+++ b/smoketest/scripts/cli/test_container.py
@@ -91,6 +91,22 @@ class TestContainer(VyOSUnitTestSHIM.TestCase):
# Check for running process
self.assertEqual(process_named_running(PROCESS_NAME), pid)
+ def test_cpu_limit(self):
+ cont_name = 'c2'
+
+ self.cli_set(base_path + ['name', cont_name, 'allow-host-networks'])
+ self.cli_set(base_path + ['name', cont_name, 'image', cont_image])
+ self.cli_set(base_path + ['name', cont_name, 'cpu-quota', '1.25'])
+
+ self.cli_commit()
+
+ pid = 0
+ with open(PROCESS_PIDFILE.format(cont_name), 'r') as f:
+ pid = int(f.read())
+
+ # Check for running process
+ self.assertEqual(process_named_running(PROCESS_NAME), pid)
+
def test_ipv4_network(self):
prefix = '192.0.2.0/24'
base_name = 'ipv4'
diff --git a/smoketest/scripts/system/test_kernel_options.py b/smoketest/scripts/system/test_kernel_options.py
index bc7f658b0..4666e98e7 100755
--- a/smoketest/scripts/system/test_kernel_options.py
+++ b/smoketest/scripts/system/test_kernel_options.py
@@ -120,5 +120,13 @@ class TestKernelModules(unittest.TestCase):
tmp = re.findall(f'{option}=(y|m)', self._config_data)
self.assertTrue(tmp)
+ def test_container_cpu(self):
+ options_to_check = [
+ 'CONFIG_CGROUP_SCHED', 'CONFIG_CPUSETS', 'CONFIG_CGROUP_CPUACCT', 'CONFIG_CFS_BANDWIDTH'
+ ]
+ for option in options_to_check:
+ tmp = re.findall(f'{option}=(y|m)', self._config_data)
+ self.assertTrue(tmp)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py
index 91a10e891..ca09dff9f 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -16,6 +16,7 @@
import os
+from decimal import Decimal
from hashlib import sha256
from ipaddress import ip_address
from ipaddress import ip_network
@@ -127,6 +128,11 @@ def verify(container):
f'locally. Please use "add container image {image}" to add it '\
f'to the system! Container "{name}" will not be started!')
+ if 'cpu_quota' in container_config:
+ cores = vyos.cpu.get_core_count()
+ if Decimal(container_config['cpu_quota']) > cores:
+ raise ConfigError(f'Cannot set limit to more cores than available "{name}"!')
+
if 'network' in container_config:
if len(container_config['network']) > 1:
raise ConfigError(f'Only one network can be specified for container "{name}"!')
@@ -257,6 +263,7 @@ def verify(container):
def generate_run_arguments(name, container_config):
image = container_config['image']
+ cpu_quota = container_config['cpu_quota']
memory = container_config['memory']
shared_memory = container_config['shared_memory']
restart = container_config['restart']
@@ -333,7 +340,7 @@ def generate_run_arguments(name, container_config):
if 'allow_host_pid' in container_config:
host_pid = '--pid host'
- container_base_cmd = f'--detach --interactive --tty --replace {capabilities} ' \
+ container_base_cmd = f'--detach --interactive --tty --replace {capabilities} --cpus {cpu_quota} ' \
f'--memory {memory}m --shm-size {shared_memory}m --memory-swap 0 --restart {restart} ' \
f'--name {name} {hostname} {device} {port} {volume} {env_opt} {label} {uid} {host_pid}'