Skip to content

Commit 7063a14

Browse files
committed
Add configurable swapfile for memory-constrained test VMs
1 parent 0e4bc4a commit 7063a14

7 files changed

Lines changed: 57 additions & 3 deletions

File tree

alts/shared/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ class OpennebulaConfig(BaseModel):
154154
vm_group: Optional[str] = None
155155
default_vm_disk_size: Optional[int] = 15360
156156
default_vm_ram_size: Optional[int] = 1536
157+
# Swapfile size in MB created during provisioning; 0 disables it
158+
default_vm_swap_size: Optional[int] = 0
157159
network: Optional[str] = None
158160
# Quota checking configuration
159161
quota_check_enabled: bool = False

alts/worker/runners/base.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,13 @@ def vm_ram_size(self) -> int:
356356
CONFIG.opennebula_config.default_vm_ram_size,
357357
)
358358

359+
@property
360+
def vm_swap_size(self) -> int:
361+
return self._test_env.get(
362+
'vm_swap_size',
363+
getattr(CONFIG.opennebula_config, 'default_vm_swap_size', 0),
364+
)
365+
359366
@property
360367
def dist_arch(self):
361368
return self._dist_arch
@@ -745,6 +752,7 @@ def initial_provision(self, verbose=False):
745752
'integrity_tests_dir': self._integrity_tests_dir,
746753
'connection_type': self.ansible_connection_type,
747754
'pytest_is_needed': self.pytest_is_needed,
755+
'vm_swap_size': self.vm_swap_size,
748756
'development_mode': CONFIG.development_mode,
749757
'package_proxy': CONFIG.package_proxy,
750758
'third_party_repo_ssh_hosts': [

alts/worker/runners/opennebula.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ def _render_tf_main_file(self):
203203
template_id=template_id,
204204
vm_disk_size=self.vm_disk_size,
205205
vm_ram_size=self.vm_ram_size,
206+
vm_swap_size=self.vm_swap_size,
206207
opennebula_network=CONFIG.opennebula_config.network,
207208
)
208209

configs/example_config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ opennebula_config:
4242
# in MB
4343
default_vm_disk_size:
4444
default_vm_ram_size:
45+
default_vm_swap_size:
4546
network:
4647

4748
bs_host:

resources/opennebula/opennebula.tf.tmpl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ locals {
3636
# Disk configuration
3737
disk_0 = data.opennebula_template.selected_template.disk[0]
3838
disk_size = max(
39-
local.disk_0.size, # Original disk size from template
40-
15360, # Minimum required size
41-
local.disk_0.size + 5120 # Original size + 5GB
39+
local.disk_0.size, # Original disk size from template
40+
15360, # Minimum required size
41+
local.disk_0.size + 5120 + ${vm_swap_size} # Original size + 5GB + swapfile (MB)
4242
)
4343
# Determine network_id: use template network if available, otherwise use test_system_network
4444
network_id = local.template_has_network ? data.opennebula_virtual_network.template_network[0].id : data.opennebula_virtual_network.test_system_network.id

resources/roles/preparation/defaults/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ third_party_repo_ssh_hosts: []
1010
# and is passed in as an extra-var by the runner. Empty list here is a
1111
# no-op fallback so the role still works if invoked standalone.
1212
cached_test_repos: []
13+
# Swapfile size in MB, passed in as an extra-var by the runner from the
14+
# platform's `vm_swap_size`. 0 (the default) disables swapfile creation.
15+
vm_swap_size: 0

resources/roles/preparation/tasks/main.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,45 @@
2121
tags:
2222
- initial_provision
2323

24+
# Some platforms (e.g. CL7h) carry many available kernels across repos, and
25+
# dnf/yum can exhaust memory while resolving kernel-module dependencies.
26+
# A swapfile sized from the platform's `vm_swap_size` gives them headroom.
27+
# VM-only (Docker envs share the host kernel and can't swapon) and a no-op
28+
# when vm_swap_size is 0.
29+
- name: Provide swap space for memory-constrained platforms
30+
when:
31+
- connection_type != 'docker'
32+
- (vm_swap_size | int) > 0
33+
tags:
34+
- initial_provision
35+
block:
36+
- name: Allocate swapfile
37+
ansible.builtin.command:
38+
cmd: "fallocate -l {{ vm_swap_size }}M /swapfile"
39+
creates: /swapfile
40+
41+
- name: Restrict swapfile permissions
42+
ansible.builtin.file:
43+
path: /swapfile
44+
owner: root
45+
group: root
46+
mode: '0600'
47+
48+
- name: Format swapfile
49+
ansible.builtin.command:
50+
cmd: mkswap /swapfile
51+
register: _mkswap
52+
changed_when: _mkswap.rc == 0
53+
54+
- name: Enable swapfile
55+
ansible.builtin.command:
56+
cmd: swapon /swapfile
57+
register: _swapon
58+
changed_when: _swapon.rc == 0
59+
failed_when:
60+
- _swapon.rc != 0
61+
- "'already active' not in _swapon.stderr"
62+
2463
# SSH client config is only needed where the third-party repo is cloned
2564
# *inside* the environment (VMs cloned over SSH). Docker envs receive the
2665
# repo via `docker cp` from the worker, so they never clone and need no

0 commit comments

Comments
 (0)