Skip to content

Commit e63daa0

Browse files
committed
[KT] Add vm --content_release flag to automate LTS content release workflow
Adds a new --content_release flag to the kt vm command that automates the entire LTS content release process. The workflow includes: - Running mkdistgitdiff to generate dist-git updates from source changes - Fetching sources via getsrc.sh - Building kernel RPMs using mock with per-kernel configs - Installing the built kernel in the VM - Rebooting and running kselftests Changes: - Add content_release() method to VmInstance that orchestrates the workflow - Add mock_config field to kernels.yaml for each kernel variant - Add user/email/depot_user/depot_token config fields needed for builds - Add mock and python3-GitPython dependencies to kernel_install_dep.sh - Update KernelInfo to include mock_config
1 parent d52f29d commit e63daa0

File tree

7 files changed

+169
-9
lines changed

7 files changed

+169
-9
lines changed

kernel_install_dep.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ install_kselftest_deps_8() {
3737
libreswan \
3838
libubsan \
3939
llvm \
40+
mock \
4041
ncurses-devel \
4142
net-tools \
4243
netsniff-ng \
@@ -46,6 +47,7 @@ install_kselftest_deps_8() {
4647
openssl-devel \
4748
perf \
4849
popt-devel \
50+
python3-GitPython \
4951
python3-pip \
5052
rsync \
5153
socat \
@@ -110,6 +112,7 @@ install_kselftest_deps_9() {
110112
libreswan \
111113
libubsan \
112114
llvm \
115+
mock \
113116
ncurses-devel \
114117
net-tools \
115118
netsniff-ng \
@@ -120,6 +123,7 @@ install_kselftest_deps_9() {
120123
packetdrill \
121124
perf \
122125
popt-devel \
126+
python3-GitPython \
123127
python3-pip \
124128
rsync \
125129
socat \
@@ -177,6 +181,7 @@ install_kselftest_deps_10() {
177181
libreswan \
178182
libubsan \
179183
llvm \
184+
mock \
180185
ncurses-devel \
181186
net-tools \
182187
nftables \
@@ -186,6 +191,7 @@ install_kselftest_deps_10() {
186191
packetdrill \
187192
perf \
188193
popt-devel \
194+
python3-GitPython \
189195
python3-pip \
190196
rsync \
191197
socat \
@@ -219,3 +225,5 @@ case "$ROCKY_SUPPORT_PRODUCT" in
219225
install_kselftest_deps_8
220226
;;
221227
esac
228+
229+
sudo usermod -a -G mock $USER

kt/commands/vm/command.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@
5757
help="Lists existings vms",
5858
)
5959
@click.option("--test", is_flag=True, help="Build the kernel and run kselftests")
60+
@click.option("--content_release", is_flag=True, help="Perform an lts content release")
6061
@click.argument("kernel_workspace", required=False, shell_complete=ShellCompletion.show_kernel_workspaces)
61-
def vm(kernel_workspace, console, destroy, override, list_all, test):
62-
main(name=kernel_workspace, console=console, destroy=destroy, override=override, list_all=list_all, test=test)
62+
def vm(kernel_workspace, console, destroy, override, list_all, test, content_release):
63+
main(
64+
name=kernel_workspace,
65+
console=console,
66+
destroy=destroy,
67+
override=override,
68+
list_all=list_all,
69+
test=test,
70+
content_release=content_release,
71+
)

kt/commands/vm/impl.py

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
from kt.ktlib.config import Config
1414
from kt.ktlib.kernel_workspace import KernelWorkspace
15+
from kt.ktlib.kernels import KernelsInfo
1516
from kt.ktlib.ssh import SshCommand
1617
from kt.ktlib.util import Constants
1718
from kt.ktlib.virt import VirtHelper, VmCommand
@@ -259,11 +260,106 @@ def test(self, config):
259260

260261
self.kselftests(config=config)
261262

263+
def content_release(self, config):
264+
logging.debug("Running mkdistgitdiff")
265+
mkdistgitdiff = str(config.base_path / Path("kernel-tools") / Path("mkdistgitdiff.py"))
266+
output_file = self.kernel_workspace.folder.absolute() / Path("mkdistgitdiff.log")
267+
268+
# mkdistgitdiff needs these to be set
269+
ssh_cmd = f'git config --global user.name "{config.user}"'
270+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
271+
ssh_cmd = f"git config --global user.email {config.email}"
272+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
273+
274+
ssh_cmd = (
275+
f"cd {self.kernel_workspace.dist_worktree.folder.absolute()} && {mkdistgitdiff} "
276+
f"--srcgit {self.kernel_workspace.src_worktree.folder.absolute()} "
277+
f"--srcgit-branch {self.kernel_workspace.src_worktree.local_branch} "
278+
f"--distgit . "
279+
f"--distgit-branch {self.kernel_workspace.dist_worktree.local_branch} "
280+
f"--last-tag "
281+
f"--bump"
282+
)
283+
SshCommand.run_with_output(output_file=output_file, domain=self.domain, command=[ssh_cmd])
284+
285+
ssh_cmd = (
286+
f"git -C {self.kernel_workspace.dist_worktree.folder.absolute()} "
287+
f"checkout {{${{USER}}}}_{self.kernel_workspace.src_worktree.local_branch}"
288+
)
289+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
290+
291+
ssh_cmd = (
292+
f"cd {self.kernel_workspace.dist_worktree.folder.absolute()} && "
293+
f"curl -O https://raw.githubusercontent.com/rocky-linux/rocky-tools/main/getsrc/getsrc.sh"
294+
)
295+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
296+
297+
ssh_cmd = f"cd {self.kernel_workspace.dist_worktree.folder.absolute()} && chmod +x ./getsrc.sh && ./getsrc.sh"
298+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
299+
300+
ssh_cmd = f"cd {self.kernel_workspace.folder} && mkdir -p build_files"
301+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
302+
303+
mock_configs_path = str(config.base_path / Path("mock-configs"))
304+
305+
# Get the mock_config from kernels.yaml
306+
kernels_info = KernelsInfo.from_yaml(config=config)
307+
kernel_name = Vm._extract_kernel_name(self.kernel_workspace.folder.name)
308+
mock_config = kernels_info.kernels[kernel_name].mock_config
309+
310+
ssh_cmd = (
311+
f"cd {self.kernel_workspace.folder} && "
312+
f"cp {mock_configs_path}/{mock_config} ${{USER}}_{mock_config} && "
313+
f"sed -i 's/DEPOT_USER/{config.depot_user}/g' ${{USER}}_{mock_config} && "
314+
f"sed -i 's/DEPOT_TOKEN/{config.depot_token}/g' ${{USER}}_{mock_config} "
315+
)
316+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
317+
318+
ssh_cmd = "sudo usermod -a -G mock ${USER}"
319+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
320+
321+
ssh_cmd = (
322+
f"cd {self.kernel_workspace.dist_worktree.folder.absolute()} && "
323+
f"mock -v -r ../${{USER}}_{mock_config} --resultdir={self.kernel_workspace.folder.absolute()}/build_files --buildsrpm "
324+
f"--spec=SPECS/kernel.spec --sources=SOURCES"
325+
)
326+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
327+
328+
ssh_cmd = (
329+
f"cd {self.kernel_workspace.dist_worktree.folder.absolute()} && "
330+
f"mock -v -r ../${{USER}}_{mock_config} --resultdir={self.kernel_workspace.folder.absolute()}/build_files "
331+
f"{self.kernel_workspace.folder.absolute()}/build_files/*.src.rpm"
332+
)
333+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
334+
335+
ssh_cmd = f"cd {self.kernel_workspace.folder} && rm ${{USER}}_{mock_config}"
336+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
337+
338+
ssh_cmd = (
339+
f"cd {self.kernel_workspace.folder} && "
340+
f"sudo dnf install $(find build_files -maxdepth 1 -name '*.rpm' -not -name '*.src.rpm' -not -name 'kernel-rt*.rpm' -not -name 'kernel-debug-*.rpm') -y"
341+
)
342+
output_file = self.kernel_workspace.folder.absolute() / Path("install.log")
343+
SshCommand.run_with_output(output_file=output_file, domain=self.domain, command=[ssh_cmd])
344+
345+
self.reboot()
346+
347+
ssh_cmd = f"sudo /usr/libexec/kselftests/run_kselftest.sh | tee {self.kernel_workspace.folder.absolute()}/selftest-$(uname -r).log"
348+
SshCommand.run(domain=self.domain, command=[ssh_cmd])
349+
262350
def console(self):
263351
VmCommand.console(vm_name=self.name)
264352

265353

266-
def main(name: str, console: bool, destroy: bool, override: bool, list_all: bool, test: bool = False):
354+
def main(
355+
name: str,
356+
console: bool,
357+
destroy: bool,
358+
override: bool,
359+
list_all: bool,
360+
test: bool = False,
361+
content_release: bool = False,
362+
):
267363
if list_all:
268364
VmCommand.list_all()
269365
return
@@ -289,5 +385,11 @@ def main(name: str, console: bool, destroy: bool, override: bool, list_all: bool
289385
time.sleep(Constants.VM_DEPS_INSTALL_WAIT_SECONDS)
290386
vm_instance.test(config=config)
291387

388+
if content_release:
389+
# Wait for the dependencies to be installed
390+
logging.info("Waiting for the deps to be installed")
391+
# time.sleep(Constants.VM_DEPS_INSTALL_WAIT_SECONDS)
392+
vm_instance.content_release(config=config)
393+
292394
if console:
293395
vm_instance.console()

kt/data/kernels.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,46 @@ kernels:
88
src_tree_branch: ciqcbr7_9
99
dist_git_root: dist-git-tree-cbr
1010
dist_git_branch: cbr79-7
11+
mock_config: centos-cbr79-x86_64.cfg
1112

1213
lts-8.6:
1314
src_tree_root: kernel-src-tree
1415
src_tree_branch: ciqlts8_6
1516
dist_git_root: dist-git-tree-lts
1617
dist_git_branch: lts86-8
18+
mock_config: rocky-lts86-depot-x86_64.cfg
1719

1820
lts-9.2:
1921
src_tree_root: kernel-src-tree
2022
src_tree_branch: ciqlts9_2
2123
dist_git_root: dist-git-tree-lts
2224
dist_git_branch: lts92-9
25+
mock_config: rocky-lts92-depot-x86_64.cfg
2326

2427
lts-9.4:
2528
src_tree_root: kernel-src-tree
2629
src_tree_branch: ciqlts9_4
2730
dist_git_root: dist-git-tree-lts
2831
dist_git_branch: lts94-9
32+
mock_config: rocky-lts94-depot-x86_64.cfg
2933

3034
fipslegacy-8.6:
3135
src_tree_root: kernel-src-tree
3236
src_tree_branch: fips-legacy-8-compliant/4.18.0-425.13.1
3337
dist_git_root: dist-git-tree-fips
3438
dist_git_branch: fips-compliant8
39+
mock_config: rocky-fips-legacy-8-x86_64.cfg
3540

3641
fips-9.2:
3742
src_tree_root: kernel-src-tree
3843
src_tree_branch: fips-9-compliant/5.14.0-284.30.1
3944
dist_git_root: dist-git-tree-fips
4045
dist_git_branch: el92-fips-compliant-9
46+
mock_config: rocky-fips92-depot-x86_64.cfg
4147

4248
lts-9.6:
4349
src_tree_root: kernel-src-tree
4450
src_tree_branch: ciqlts9_6
4551
dist_git_root: dist-git-tree-lts
4652
dist_git_branch: lts96-9
53+
mock_config: rocky-lts96-depot-x86_64.cfg

kt/ktlib/config.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ class Config:
2323
stored
2424
ssh_key: Path to the ssh key (public) shared between host and each vms
2525
26+
user: User's full name (for git config)
27+
email: User's email (for git config)
28+
29+
depot_user: Depot username
30+
depot_token: Depot token
31+
2632
All paths should be absolute, to avoid issues later.
2733
"""
2834

@@ -33,20 +39,44 @@ class Config:
3339

3440
ssh_key: Path
3541

42+
user: str
43+
email: str
44+
45+
depot_user: str
46+
depot_token: str
47+
3648
DEFAULT: ClassVar = {
3749
"base_path": "~/ciq",
3850
"kernels_dir": "~/ciq/kernels",
3951
"images_source_dir": "~/ciq/default_test_images",
4052
"images_dir": "~/ciq/tmp/virt-images",
4153
"ssh_key": "~/.ssh/id_ed25519_generic.pub",
54+
"user": "CIQ Developer",
55+
"email": "[email protected]",
56+
"depot_user": "user",
57+
"depot_token": "token",
4258
}
4359

4460
@classmethod
4561
def from_str_dict(cls, data: dict[str, str]):
46-
# Transform the str values to Path
47-
new_data = {k: Path(v).expanduser() for k, v in data.items()}
48-
49-
if not all(v.is_absolute() for v in new_data.values()):
62+
# Path fields that need to be converted
63+
path_fields = {"base_path", "kernels_dir", "images_source_dir", "images_dir", "ssh_key"}
64+
65+
# Merge user data with defaults to support partial configs
66+
merged_data = dict(cls.DEFAULT)
67+
merged_data.update(data)
68+
69+
# Transform only the path values to Path, keep strings as is
70+
new_data = {}
71+
for k, v in merged_data.items():
72+
if k in path_fields:
73+
new_data[k] = Path(v).expanduser()
74+
else:
75+
new_data[k] = v
76+
77+
# Check that all path fields are absolute
78+
path_values = {k: v for k, v in new_data.items() if k in path_fields}
79+
if not all(v.is_absolute() for v in path_values.values()):
5080
raise ValueError("all paths should be absolute; check your config")
5181

5282
return cls(**new_data)

kt/ktlib/kernels.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class KernelInfo:
2121
src_tree_branch: the corresponding branch in the source tree
2222
dist_git_root: rocky staging rpm repo
2323
dist_git_branch: corresponding branch in the rocky staging rpm repo
24+
mock_config: mock config used to build this kernel
2425
2526
The src_tree_root and dist_git_root contain absolute paths to the local
2627
clone of these repos and their corresponding remote url.
@@ -34,6 +35,8 @@ class KernelInfo:
3435
dist_git_root: RepoInfo
3536
dist_git_branch: str
3637

38+
mock_config: str = ""
39+
3740

3841
@dataclass
3942
class KernelsInfo:

tests/kt/ktlib/test_config.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ def test_config_load_from_json_data_None():
4747
def test_config_load_from_json_data_empty():
4848
json_data = "{}"
4949

50-
with pytest.raises(TypeError, match="missing 5 required positional arguments:"):
51-
config = Config.from_json(json_data) # noqa F841
50+
# Empty config should use defaults
51+
config = Config.from_json(json_data)
52+
assert config.base_path == DEFAULT_CONFIG["base_path"]
5253

5354

5455
def test_config_load_from_json_proper_base_path():

0 commit comments

Comments
 (0)