Skip to content

Commit 5512072

Browse files
committed
Schedule product per livepatch kernel_version
Automate the livepatch isos posts. Due to the logic of the script generation this commit inserts a for loop for all the livepatches which will be scrapped from test repository. - the loop always run even if no livepatches found. However it will only append to the isos posts the variables only in the case that actually livepatch versions are available. To get the delta of the increment repo, it checks the datetime. - Use the same uri which is used for rsync. For that, some manipulation is needed to convert the rsync to a regular http URI. The approach is just a bit dirty, as any other approach would require further refactoring and bigger changes. depends-on: https://gitlab.suse.de/openqa/openqa-trigger-from-ibs-plugin/-/merge_requests/263 issue: https://progress.opensuse.org/issues/190134 Signed-off-by: Ioannis Bonatakis <[email protected]>
1 parent 5ea66e4 commit 5512072

File tree

3 files changed

+116
-4
lines changed

3 files changed

+116
-4
lines changed

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
- checkout
99
- run:
1010
command: |
11-
zypper -n in --no-recommends diffutils make python3 tar git-core
11+
zypper -n in --no-recommends diffutils make python3 tar git-core python3-requests
1212
- checkout
1313
- run: git clean -df
1414
- run: make test_regen_all
@@ -21,7 +21,7 @@ jobs:
2121
- checkout
2222
- run:
2323
command: |
24-
zypper -n in --no-recommends make python3-black python3-importlib-metadata
24+
zypper -n in --no-recommends make python3-black python3-importlib-metadata python3-requests
2525
- checkout
2626
- run: make test_python_style
2727

script/cfg.py

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import os
2+
import re
3+
import requests
4+
from bs4 import BeautifulSoup
5+
from datetime import datetime
26

37
header = '''# GENERATED FILE - DO NOT EDIT
48
set -e
@@ -306,10 +310,100 @@ def openqa_call_start_meta_variables(meta_variables):
306310
def pre_openqa_call_start(repos):
307311
return ''
308312

309-
openqa_call_start = lambda distri, version, archs, staging, news, news_archs, flavor_distri, meta_variables, assets_flavor, repo0folder, openqa_cli: '''
313+
def _find_latest_livepatches(url):
314+
"""
315+
Scrapes a URL to find all kernel-livepatch-* with the
316+
most recent date.
317+
"""
318+
try:
319+
response = requests.get(url)
320+
response.raise_for_status()
321+
except requests.exceptions.RequestException as e:
322+
print(f"Error fetching URL: {e}")
323+
return []
324+
325+
soup = BeautifulSoup(response.text, 'html.parser')
326+
327+
livepatches_unfiltered = []
328+
latest_date = None
329+
lp_regex = r'kernel-livepatch-((?:\d+_?)+-\d+)'
330+
#pdb.set_trace()
331+
for link in soup.find_all('a'):
332+
if (link and link.text.startswith('kernel-livepatch-')):
333+
#and '-rt' in link.text):
334+
#pdb.set_trace()
335+
if link.next_sibling and isinstance(link.next_sibling, str):
336+
date_str = link.next_sibling.strip().split()[0]
337+
338+
try:
339+
# NOTE: The date format on dist.suse.de is YYYY-MM-DD.
340+
current_date = datetime.strptime(date_str, '%Y-%m-%d')
341+
livepatches_unfiltered.append({'name': link.text, 'date': current_date})
342+
343+
if latest_date is None or current_date > latest_date:
344+
latest_date = current_date
345+
except (ValueError, IndexError):
346+
# Continue if the date format is unexpected or not present
347+
continue
348+
349+
if latest_date is None:
350+
return []
351+
# to list only the recent ones
352+
latest_patches_list = []
353+
for patch in livepatches_unfiltered:
354+
if patch['date'] == latest_date:
355+
kernel_version = re.search(lp_regex, patch['name'])
356+
latest_patches_list.append(kernel_version.group(1))
357+
358+
return latest_patches_list
359+
360+
def _find_product_folder(p):
361+
"""
362+
Tries to find the product name looking it up in the server's repo dirs
363+
:param p: The local path as defined in ActionGenerator.envdir
364+
:return: The matched product name
365+
"""
366+
uri, prod = os.path.split(p)
367+
target_filename = "files_iso.lst"
368+
iso_file_found = None
369+
370+
for root, dirs, files in os.walk(p):
371+
if target_filename in files:
372+
iso_file_found = os.path.join(root, target_filename)
373+
break # found
374+
375+
if iso_file_found:
376+
with open(iso_file_found, 'r') as f:
377+
iso_file = f.readline().strip()
378+
if iso_file.endswith("spdx.json"):
379+
prod_folder_pattern = r'(.*)-(?:aarch64|x86_64|s390x|ppc64le)'
380+
prod_folder = re.match(prod_folder_pattern, iso_file)
381+
if prod_folder:
382+
return prod_folder.group(1)
383+
return ""
384+
385+
def openqa_fetch_livepatch_list(ag_vars):
386+
kpatches = {}
387+
productpath_local = ag_vars.envdir
388+
prod_build_name = _find_product_folder(productpath_local)
389+
if not prod_build_name:
390+
return # no spdx.json, return and do what you do
391+
repo_path = ag_vars.productrepopath().replace('::', '/', 1)
392+
repo_path = repo_path.replace("repos", ag_vars.brand)
393+
repo_path = f"https://{repo_path}"
394+
for arch in ['x86_64','aarch64','s390x','ppc64le']:
395+
totest_url = f"{repo_path}/{prod_build_name}-{arch}/{arch}/"
396+
latest_kernel_livepatches = _find_latest_livepatches(totest_url)
397+
398+
if latest_kernel_livepatches:
399+
kpatches.update({arch: latest_kernel_livepatches})
400+
return kpatches
401+
402+
openqa_call_start = lambda distri, version, archs, staging, news, news_archs, flavor_distri, meta_variables, assets_flavor, repo0folder, openqa_cli, livepatches={},: '''
310403
archs=(ARCHITECTURS)
311404
[ ! -f __envsub/files_repo.lst ] || ! grep -q -- "-POOL-" __envsub/files_repo.lst || additional_repo_suffix=-POOL
312-
405+
declare -a livepatches
406+
livepatches=(NONE)
313407
for flavor in {FLAVORALIASLIST,}; do
314408
for arch in "${archs[@]}"; do
315409
filter=$flavor
@@ -326,6 +420,11 @@ def pre_openqa_call_start(repos):
326420
[ -n "$iso" ] || [ "$flavor" != "''' + assets_flavor + r'''" ] || buildex=$(grep -o -E '(Build|Snapshot)[^-]*' __envsub/files_asset.lst | head -n 1)
327421
[ -n "$iso$build" ] || build=$(grep -h -o -E '(Build|Snapshot)[^-]*' __envsub/Media1*.lst 2>/dev/null | head -n 1 | grep -o -E '[0-9]\.?[0-9]+(\.[0-9]+)*')|| :
328422
[ -n "$build" ] || continue
423+
livepatches_all="''' + str(livepatches) + r'''"
424+
livepatches=($(echo "$livepatches_all" | sed "s/[{}']//g" | sed 's/, /\n/g' | awk -F':' -v arch="$arch" '$1 == arch {print $2}'))
425+
if [ ${#livepatches[@]} -eq 0 ]; then
426+
livepatches=(NONE)
427+
fi
329428
buildex=${buildex/.install.iso/}
330429
buildex=${buildex/.iso/}
331430
buildex=${buildex/.raw.xz/}
@@ -342,7 +441,12 @@ def pre_openqa_call_start(repos):
342441
}
343442
fi
344443
# test "$destiso" != "" || continue
444+
for livepatch in "${livepatches[@]}"; do
345445
echo "''' + openqa_cli + ''' \\\\\"
446+
if [[ "${livepatch}" != "NONE" ]]; then
447+
echo \" KGRAFT=1 \\\\
448+
KERNEL_VERSION=${livepatch} \\\\\"
449+
fi
346450
(
347451
echo \" DISTRI=$distri \\\\
348452
ARCH=$arch \\\\
@@ -583,6 +687,7 @@ def openqa_call_end(version):
583687
echo " FLAVOR=${flavor//Tumbleweed-/} \\\\"
584688
) | LANG=C.UTF-8 sort
585689
echo ""
690+
done
586691
done
587692
done
588693
'''

script/scriptgen.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,12 @@ def gen_print_openqa(self, f):
10081008
"| grep {} | grep $arch | head -n 1".format(self.mask),
10091009
)
10101010
else:
1011+
livepatch_updates = cfg.openqa_fetch_livepatch_list(self.ag)
1012+
openqa_livepatches = {}
1013+
if livepatch_updates:
1014+
openqa_livepatches = {
1015+
f"{arch}:{' '.join(versions)}" for arch, versions in livepatch_updates.items() if versions
1016+
}
10111017
self.p(
10121018
cfg.openqa_call_start(
10131019
self.ag.distri,
@@ -1021,6 +1027,7 @@ def gen_print_openqa(self, f):
10211027
self.assets_flavor,
10221028
self.repo0folder,
10231029
self.ag.openqa_cli,
1030+
openqa_livepatches,
10241031
),
10251032
f,
10261033
)

0 commit comments

Comments
 (0)