Skip to content

Commit e17e31c

Browse files
Add Kernel config diff script between different kernel versions (#375)
Signed-off-by: Vivek Reddy <[email protected]> Co-authored-by: Saikrishna Arcot <[email protected]>
1 parent ee073d9 commit e17e31c

File tree

5 files changed

+198
-1
lines changed

5 files changed

+198
-1
lines changed

.artifactignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
**/*
22
!*.deb
3+
!kconfig-diff-*.rst

.azure-pipelines/build-template.yml

+27-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ parameters:
3232
- name: artifact_name
3333
type: string
3434

35+
- name: linux_deb_pattern
36+
type: string
37+
3538
jobs:
3639
- job:
3740
pool: ${{ parameters.pool }}
@@ -44,14 +47,37 @@ jobs:
4447
steps:
4548
- checkout: self
4649
clean: true
47-
displayName: 'Checkout code'
50+
displayName: 'Checkout code'
51+
- task: DownloadPipelineArtifact@2
52+
inputs:
53+
source: specific
54+
project: build
55+
pipelineId: 426041
56+
artifact: ${{ parameters.artifact_name }}
57+
runVersion: 'specific'
58+
itemPattern: ${{ parameters.linux_deb_pattern }}
59+
targetPath: $(Agent.TempDirectory)/
60+
displayName: "Download the linux-image artifact from the last build with a different kernel version"
4861
- script: |
4962
git config --global user.email "[email protected]"
5063
git config --global user.name "Guohan Lu"
5164
export kernel_procure_method=build
5265
cat /proc/cpuinfo
5366
CONFIGURED_ARCH=${{ parameters.arch }} CONFIGURED_PLATFORM=${{ parameters.platform }} make
5467
displayName: "Compile sonic kernel"
68+
- script: |
69+
dpkg-deb -x $(Agent.TempDirectory)/${{ parameters.linux_deb_pattern }} $(Agent.TempDirectory)/old
70+
dpkg-deb -x $(System.DefaultWorkingDirectory)/${{ parameters.linux_deb_pattern }} $(Agent.TempDirectory)/new
71+
pip3 install tabulate
72+
python3 $(System.DefaultWorkingDirectory)/.azure-pipelines/kcfg-diff.py \
73+
--buildid $(Build.BuildId) \
74+
--ref_buildid 426041 \
75+
--arch ${{ parameters.arch }} \
76+
--old_kcfg $(Agent.TempDirectory)/old/boot/ \
77+
--new_kcfg $(Agent.TempDirectory)/new/boot/ \
78+
--output $(System.DefaultWorkingDirectory)/kconfig-diff-${{ parameters.platform }}-${{ parameters.arch }}.rst
79+
cat $(System.DefaultWorkingDirectory)/kconfig-diff-${{ parameters.platform }}-${{ parameters.arch }}.rst
80+
displayName: "Compute the kconfig diff"
5581
- publish: $(System.DefaultWorkingDirectory)/
5682
artifact: ${{ parameters.artifact_name }}
5783
displayName: "Archive sonic kernel debian packages"

.azure-pipelines/kcfg-diff.py

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import argparse
2+
import os
3+
import glob
4+
import sys
5+
import re
6+
from tabulate import tabulate
7+
8+
COLUMN_WIDTH_MAX = 40
9+
MODIF_COLUMN_WIDTH_MAX = 80
10+
11+
RST_TEMPLATE = '''\
12+
SONiC-linux-kernel KConfig Difference:
13+
==========
14+
15+
Reference Kernel
16+
------------
17+
- Version: {}
18+
- BuildID: https://dev.azure.com/mssonic/build/_build/results?buildId={}&view=results
19+
20+
Latest Kernel
21+
------------
22+
- Version: {}
23+
- BuildID: https://dev.azure.com/mssonic/build/_build/results?buildId={}&view=results
24+
25+
26+
Additions & Deletions
27+
------------
28+
{}
29+
30+
Modifications
31+
------------
32+
{}
33+
'''
34+
35+
def read_data(file1):
36+
data = []
37+
try:
38+
with open(file1, 'r') as f1:
39+
data = f1.readlines()
40+
except Exception as e:
41+
print("ABORT: Reading failed from {}, {}".format(file1, str(e)))
42+
sys.exit(1)
43+
44+
data = filter(lambda line: not(line.startswith('#')), data)
45+
ret = dict()
46+
for line in data:
47+
tokens = line.split('=')
48+
if len(tokens) == 2:
49+
key, val = tokens[0].strip(), tokens[-1].strip()
50+
ret[key] = val
51+
return ret
52+
53+
def write_data(fname, data):
54+
try:
55+
with open(fname, 'w') as f:
56+
f.write(data)
57+
except Exception as e:
58+
print("ABORT: Writing to the file {} failed {}".format(fname, str(e)))
59+
sys.exit(1)
60+
61+
def generate_diff(file1, file2):
62+
data_f1 = read_data(file1)
63+
data_f2 = read_data(file2)
64+
65+
additions = []
66+
modifications = []
67+
deletions = []
68+
69+
for key_old, val_old in data_f1.items():
70+
val_new = data_f2.get(key_old, None)
71+
if not val_new:
72+
deletions.append("{}={}".format(key_old, val_old))
73+
elif val_old != val_new:
74+
modifications.append("{}={}->{}".format(key_old, val_old, val_new))
75+
if val_new:
76+
del data_f2[key_old]
77+
78+
for key, val in data_f2.items():
79+
additions.append("{}={}".format(key, val))
80+
return additions, modifications, deletions
81+
82+
def restrict_column_width(lis, width):
83+
for i in range(0, len(lis)):
84+
curr_width = len(lis[i])
85+
new_val = ''
86+
num_newlines = int(curr_width/width)
87+
for j in range(0, num_newlines+1):
88+
if (j+1)*width < curr_width:
89+
new_val += lis[i][j*width:(j+1)*width]
90+
new_val += "\n"
91+
else:
92+
new_val += lis[i][j*width:]
93+
lis[i] = new_val
94+
95+
def format_diff_table(additions, modifications, deletions):
96+
max_len = max(len(additions), len(deletions))
97+
additions += [''] * (max_len - len(additions))
98+
deletions += [''] * (max_len - len(deletions))
99+
100+
restrict_column_width(additions, COLUMN_WIDTH_MAX)
101+
restrict_column_width(deletions, COLUMN_WIDTH_MAX)
102+
restrict_column_width(modifications, MODIF_COLUMN_WIDTH_MAX)
103+
104+
table_data = list(zip(additions, deletions))
105+
headers = ["ADDITIONS", "DELETIONS"]
106+
107+
add_del = tabulate(table_data, headers=headers, tablefmt="grid")
108+
mod = tabulate(list(zip(modifications)), headers=["MODIFICATIONS"], tablefmt="grid")
109+
return add_del, mod
110+
111+
def parse_kver(loc):
112+
files = glob.glob(os.path.join(loc, "config-*"))
113+
if len(files) > 1:
114+
print("WARNING: Multiple config- files present under {}, {}".format(loc, files))
115+
result = re.search(r"config-(.*)", os.path.basename(files[-1]))
116+
return result.group(1)
117+
118+
def create_parser():
119+
# Create argument parser
120+
parser = argparse.ArgumentParser()
121+
122+
# Optional arguments
123+
parser.add_argument("--arch", type=str, required=True)
124+
parser.add_argument("--old_kcfg", type=str, required=True)
125+
parser.add_argument("--new_kcfg", type=str, required=True)
126+
parser.add_argument("--output", type=str, required=True)
127+
parser.add_argument("--ref_buildid", type=str, required=True)
128+
parser.add_argument("--buildid", type=str, required=True)
129+
return parser
130+
131+
def verify_args(args):
132+
if not glob.glob(os.path.join(args.old_kcfg, "config-*")):
133+
print("ABORT: config file missing under {}".format(args.old_kcfg))
134+
return False
135+
136+
if not glob.glob(os.path.join(args.new_kcfg, "config-*")):
137+
print("ABORT: config file missing under {}".format(args.new_kcfg))
138+
return False
139+
140+
if not os.path.exists(os.path.dirname(args.output)):
141+
print("ABORT: Output Folder {} doesn't exist".format(args.output))
142+
return False
143+
return True
144+
145+
if __name__ == "__main__":
146+
parser = create_parser()
147+
args = parser.parse_args()
148+
if not verify_args(args):
149+
sys.exit(1)
150+
151+
ver_old = parse_kver(args.old_kcfg)
152+
ver_new = parse_kver(args.new_kcfg)
153+
f_old = os.path.join(args.old_kcfg, 'config-{}'.format(ver_old))
154+
f_new = os.path.join(args.new_kcfg, 'config-{}'.format(ver_new))
155+
156+
additions, modifications, deletions = generate_diff(f_old, f_new)
157+
add_del, mod = format_diff_table(additions, modifications, deletions)
158+
159+
diff = RST_TEMPLATE.format(ver_old, args.ref_buildid, ver_new, args.buildid, add_del, mod)
160+
write_data(args.output, diff)

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,9 @@ If the files patch/kconfig-exclusions and patch/kconfig-inclusions exist, they w
5050
Also, the final kernel configuration will be checked to verify that:
5151
- all options asked to be excluded are effectively not present in the kernel,
5252
- and all options asked to be included are effectively present in the kernel, using the exact type (module or built-in) or string or number.
53+
54+
## Kernel Configuration Difference during Upgrades
55+
56+
During Kernel Upgrades, the maintainer must update the configuration diff in the wiki of this repo. This acts as a guide for keeping track of configuration changes between Kernel upgrades. Applies for minor version upgrades as well
57+
58+
The diff is saved as kconfig-diff-{platform}-{arch}.rst under the artifacts of Azure.sonic-linux-kernel job runs.

azure-pipelines.yml

+4
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@ stages:
1717
arch: amd64
1818
sonic_slave: sonic-slave-bookworm
1919
artifact_name: sonic-linux-kernel
20+
linux_deb_pattern: linux-image-*-unsigned_*deb
2021

2122
- template: .azure-pipelines/build-template.yml
2223
parameters:
2324
arch: arm64
2425
pool: sonicbld-arm64
2526
sonic_slave: sonic-slave-bookworm-arm64
2627
artifact_name: sonic-linux-kernel.arm64
28+
linux_deb_pattern: linux-image-*-unsigned_*deb
2729

2830
- template: .azure-pipelines/build-template.yml
2931
parameters:
3032
arch: armhf
3133
pool: sonicbld-armhf
3234
sonic_slave: sonic-slave-bookworm-armhf
3335
artifact_name: sonic-linux-kernel.armhf
36+
linux_deb_pattern: linux-image-*-armmp_*deb
3437

3538
- template: .azure-pipelines/build-template.yml
3639
parameters:
@@ -39,4 +42,5 @@ stages:
3942
pool: sonicbld-arm64
4043
sonic_slave: sonic-slave-bookworm-arm64
4144
artifact_name: sonic-linux-kernel.pensando.arm64
45+
linux_deb_pattern: linux-image-*-unsigned_*deb
4246

0 commit comments

Comments
 (0)