Skip to content

Commit 32bea93

Browse files
committed
add logic to kernel version
1 parent ea6ee1f commit 32bea93

14 files changed

Lines changed: 481 additions & 14 deletions

File tree

image-templates/azl3-x86_64-edge-raw.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ systemConfig:
8686

8787
# Kernel Configuration
8888
kernel:
89-
version: "6.12"
89+
version: "6.6"
9090
cmdline: "console=ttyS0,115200 console=tty0 loglevel=7"
9191
#packages:
9292
# - kernel-azure

image-templates/ubuntu24-x86_64-minimal-raw.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ systemConfig:
8282
- systemd-timesyncd
8383

8484
kernel:
85-
version: "6.17"
85+
version: "6.14"
8686
cmdline: "console=ttyS0,115200 console=tty0 loglevel=7"
8787
packages:
88-
- linux-image-generic-hwe-24.04
88+
- linux-image-generic*

internal/ospackage/debutils/download.go

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,31 @@ type pkgChecksum struct {
5656
}
5757

5858
var (
59-
RepoCfg RepoConfig
60-
RepoCfgs []RepoConfig // Support for multiple repositories
61-
PkgChecksum []pkgChecksum
62-
GzHref string
63-
Architecture string
64-
UserRepo []config.PackageRepository
65-
ReportPath = "builds"
59+
RepoCfg RepoConfig
60+
RepoCfgs []RepoConfig // Support for multiple repositories
61+
PkgChecksum []pkgChecksum
62+
GzHref string
63+
Architecture string
64+
UserRepo []config.PackageRepository
65+
KernelVersion string
66+
KernelPackages = make(map[string]struct{})
67+
ReportPath = "builds"
6668
)
6769

70+
// ConfigureKernelSelection sets the kernel package requests and version used
71+
// during top-level package matching.
72+
func ConfigureKernelSelection(kernelPackages []string, kernelVersion string) {
73+
KernelVersion = kernelVersion
74+
KernelPackages = make(map[string]struct{}, len(kernelPackages))
75+
for _, pkg := range kernelPackages {
76+
pkg = strings.TrimSpace(pkg)
77+
if pkg == "" {
78+
continue
79+
}
80+
KernelPackages[pkg] = struct{}{}
81+
}
82+
}
83+
6884
// Packages returns the list of base packages
6985
func Packages() ([]ospackage.PackageInfo, error) {
7086
log := logger.Logger()
@@ -365,11 +381,37 @@ func MatchRequested(requests []string, all []ospackage.PackageInfo) ([]ospackage
365381
log := logger.Logger()
366382

367383
var out []ospackage.PackageInfo
384+
seen := make(map[string]struct{})
368385
var requestedPkgs []string
369386
gotMissingPkg := false
370387

371388
for _, want := range requests {
389+
if isGlobPattern(want) {
390+
pkgs, found := ResolveWildcardPackageConflicts(want, all)
391+
if !found {
392+
requestedPkgs = append(requestedPkgs, want)
393+
log.Warnf("requested package '%q' not found in repo", want)
394+
gotMissingPkg = true
395+
continue
396+
}
397+
398+
for _, pkg := range pkgs {
399+
key := fmt.Sprintf("%s=%s", pkg.Name, pkg.Version)
400+
if _, ok := seen[key]; ok {
401+
continue
402+
}
403+
seen[key] = struct{}{}
404+
out = append(out, pkg)
405+
}
406+
continue
407+
}
408+
372409
if pkg, found := ResolveTopPackageConflicts(want, all); found {
410+
key := fmt.Sprintf("%s=%s", pkg.Name, pkg.Version)
411+
if _, ok := seen[key]; ok {
412+
continue
413+
}
414+
seen[key] = struct{}{}
373415
out = append(out, pkg)
374416
} else {
375417
requestedPkgs = append(requestedPkgs, want)

internal/ospackage/debutils/download_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,37 @@ func TestMatchRequested(t *testing.T) {
672672
}
673673
}
674674

675+
func TestMatchRequestedKernelWildcardVersion(t *testing.T) {
676+
ConfigureKernelSelection([]string{"linux-image-generic*"}, "6.14")
677+
defer ConfigureKernelSelection(nil, "")
678+
679+
all := []ospackage.PackageInfo{
680+
{
681+
Name: "linux-image-generic-hwe-24.04",
682+
Version: "6.13.0-10.10~24.04.1",
683+
URL: "pool/main/l/linux-meta-hwe-6.13/linux-image-generic-hwe-24.04_6.13.0-10.10~24.04.1_amd64.deb",
684+
},
685+
{
686+
Name: "linux-image-generic-hwe-24.04",
687+
Version: "6.14.2.1.0",
688+
URL: "pool/main/l/linux-meta-hwe-6.14/linux-image-generic-hwe-24.04_6.14.2.1.0_amd64.deb",
689+
},
690+
}
691+
692+
matched, err := MatchRequested([]string{"linux-image-generic*"}, all)
693+
if err != nil {
694+
t.Fatalf("expected wildcard kernel request to resolve, got error: %v", err)
695+
}
696+
697+
if len(matched) != 1 {
698+
t.Fatalf("expected one resolved package, got %d", len(matched))
699+
}
700+
701+
if matched[0].Version != "6.14.2.1.0" {
702+
t.Fatalf("expected kernel version-compatible package, got %q", matched[0].Version)
703+
}
704+
}
705+
675706
// TestWriteArrayToFile tests the WriteArrayToFile function
676707
func TestWriteArrayToFile(t *testing.T) {
677708
// Save original ReportPath

internal/ospackage/debutils/resolver.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,9 +1045,69 @@ func compareVersions(v1, v2 string) int {
10451045
return cmp
10461046
}
10471047

1048+
func isKernelPackageRequest(want string) bool {
1049+
for pattern := range KernelPackages {
1050+
if pattern == want {
1051+
return true
1052+
}
1053+
1054+
if !isGlobPattern(pattern) {
1055+
continue
1056+
}
1057+
1058+
matched, err := path.Match(pattern, want)
1059+
if err == nil && matched {
1060+
return true
1061+
}
1062+
}
1063+
1064+
return false
1065+
}
1066+
1067+
func stripEpoch(version string) string {
1068+
if colonIdx := strings.Index(version, ":"); colonIdx != -1 {
1069+
return version[colonIdx+1:]
1070+
}
1071+
return version
1072+
}
1073+
1074+
func matchesKernelVersion(candidateVersion string) bool {
1075+
if KernelVersion == "" {
1076+
return false
1077+
}
1078+
1079+
versionNoEpoch := stripEpoch(candidateVersion)
1080+
if versionNoEpoch == KernelVersion {
1081+
return true
1082+
}
1083+
1084+
if !strings.HasPrefix(versionNoEpoch, KernelVersion) {
1085+
return false
1086+
}
1087+
1088+
if len(versionNoEpoch) == len(KernelVersion) {
1089+
return true
1090+
}
1091+
1092+
nextChar := versionNoEpoch[len(KernelVersion)]
1093+
return nextChar == '.' || nextChar == '-' || nextChar == '_' || nextChar == '+' || nextChar == '~'
1094+
}
1095+
1096+
func filterKernelCandidates(candidates []ospackage.PackageInfo) []ospackage.PackageInfo {
1097+
var matched []ospackage.PackageInfo
1098+
for _, candidate := range candidates {
1099+
if matchesKernelVersion(candidate.Version) {
1100+
matched = append(matched, candidate)
1101+
}
1102+
}
1103+
return matched
1104+
}
1105+
10481106
// ResolvePackage finds the best matching package for a given package name
10491107
func ResolveTopPackageConflicts(want string, all []ospackage.PackageInfo) (ospackage.PackageInfo, bool) {
1108+
log := logger.Logger()
10501109
var candidates []ospackage.PackageInfo
1110+
isKernelPackage := isKernelPackageRequest(want)
10511111
for _, pi := range all {
10521112
// 1) exact name and version matched with .deb filenamae, e.g. acct_7.6.4-5+b1_amd64
10531113
if filepath.Base(pi.URL) == want+".deb" {
@@ -1137,6 +1197,21 @@ func ResolveTopPackageConflicts(want string, all []ospackage.PackageInfo) (ospac
11371197
return ospackage.PackageInfo{}, false
11381198
}
11391199

1200+
if isKernelPackage && KernelVersion != "" {
1201+
var beforeFilter []ospackage.PackageInfo
1202+
beforeFilter = append(beforeFilter, candidates...)
1203+
candidates = filterKernelCandidates(candidates)
1204+
if len(candidates) == 0 {
1205+
var availableVersions []string
1206+
for _, pkg := range beforeFilter {
1207+
availableVersions = append(availableVersions, pkg.Version)
1208+
}
1209+
log.Errorf("kernel version mismatch: package %q requires kernel version %q, but available versions are: %v",
1210+
want, KernelVersion, availableVersions)
1211+
return ospackage.PackageInfo{}, false
1212+
}
1213+
}
1214+
11401215
// If we got an exact match in step (1), it's the only candidate
11411216
if len(candidates) == 1 && (candidates[0].Name == want || candidates[0].Name == want+".deb") {
11421217
return candidates[0], true
@@ -1146,6 +1221,52 @@ func ResolveTopPackageConflicts(want string, all []ospackage.PackageInfo) (ospac
11461221
return candidates[0], true
11471222
}
11481223

1224+
// ResolveWildcardPackageConflicts expands a wildcard request to the best package
1225+
// for each matched base package name.
1226+
func ResolveWildcardPackageConflicts(want string, all []ospackage.PackageInfo) ([]ospackage.PackageInfo, bool) {
1227+
if !isGlobPattern(want) {
1228+
pkg, found := ResolveTopPackageConflicts(want, all)
1229+
if !found {
1230+
return nil, false
1231+
}
1232+
return []ospackage.PackageInfo{pkg}, true
1233+
}
1234+
1235+
baseNames := make(map[string]struct{})
1236+
for _, pi := range all {
1237+
matched, err := path.Match(want, pi.Name)
1238+
if err != nil || !matched {
1239+
continue
1240+
}
1241+
baseNames[pi.Name] = struct{}{}
1242+
}
1243+
1244+
if len(baseNames) == 0 {
1245+
return nil, false
1246+
}
1247+
1248+
var results []ospackage.PackageInfo
1249+
for baseName := range baseNames {
1250+
pkg, found := ResolveTopPackageConflicts(baseName, all)
1251+
if found {
1252+
results = append(results, pkg)
1253+
}
1254+
}
1255+
1256+
if len(results) == 0 {
1257+
return nil, false
1258+
}
1259+
1260+
sort.Slice(results, func(i, j int) bool {
1261+
if results[i].Name == results[j].Name {
1262+
return compareVersions(results[i].Version, results[j].Version) > 0
1263+
}
1264+
return results[i].Name < results[j].Name
1265+
})
1266+
1267+
return results, true
1268+
}
1269+
11491270
// Helper function to find all candidates for a dependency
11501271
func findAllCandidates(depName string, all []ospackage.PackageInfo) []ospackage.PackageInfo {
11511272
var candidates []ospackage.PackageInfo

internal/ospackage/debutils/resolver_test.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,3 +451,105 @@ func TestResolveTopPackageConflicts(t *testing.T) {
451451
})
452452
}
453453
}
454+
455+
func TestResolveTopPackageConflictsKernelVersionSelection(t *testing.T) {
456+
debutils.ConfigureKernelSelection([]string{"linux-image-generic-hwe-24.04"}, "6.17")
457+
defer debutils.ConfigureKernelSelection(nil, "")
458+
459+
all := []ospackage.PackageInfo{
460+
{
461+
Name: "linux-image-generic-hwe-24.04",
462+
Version: "6.18.0-10.10~24.04.1",
463+
URL: "pool/main/l/linux-meta-hwe-6.18/linux-image-generic-hwe-24.04_6.18.0-10.10~24.04.1_amd64.deb",
464+
},
465+
{
466+
Name: "linux-image-generic-hwe-24.04",
467+
Version: "6.17.0-5.5~24.04.1",
468+
URL: "pool/main/l/linux-meta-hwe-6.17/linux-image-generic-hwe-24.04_6.17.0-5.5~24.04.1_amd64.deb",
469+
},
470+
{
471+
Name: "linux-image-generic-hwe-24.04",
472+
Version: "1:6.17.0-6.6~24.04.1",
473+
URL: "pool/main/l/linux-meta-hwe-6.17/linux-image-generic-hwe-24.04_6.17.0-6.6~24.04.1_amd64.deb",
474+
},
475+
}
476+
477+
result, found := debutils.ResolveTopPackageConflicts("linux-image-generic-hwe-24.04", all)
478+
if !found {
479+
t.Fatal("expected kernel package to be found")
480+
}
481+
if result.Version != "1:6.17.0-6.6~24.04.1" {
482+
t.Errorf("expected kernel-version-matching package, got %q", result.Version)
483+
}
484+
}
485+
486+
func TestResolveTopPackageConflictsKernelVersionMissing(t *testing.T) {
487+
debutils.ConfigureKernelSelection([]string{"linux-image-generic-hwe-24.04"}, "6.17")
488+
defer debutils.ConfigureKernelSelection(nil, "")
489+
490+
all := []ospackage.PackageInfo{
491+
{
492+
Name: "linux-image-generic-hwe-24.04",
493+
Version: "6.18.0-10.10~24.04.1",
494+
URL: "pool/main/l/linux-meta-hwe-6.18/linux-image-generic-hwe-24.04_6.18.0-10.10~24.04.1_amd64.deb",
495+
},
496+
}
497+
498+
_, found := debutils.ResolveTopPackageConflicts("linux-image-generic-hwe-24.04", all)
499+
if found {
500+
t.Fatal("expected kernel package resolution to fail when no candidate matches kernel version")
501+
}
502+
}
503+
504+
func TestResolveTopPackageConflictsKernelVersionPrefixMatch(t *testing.T) {
505+
debutils.ConfigureKernelSelection([]string{"linux-image-generic-hwe-24.04"}, "6.17")
506+
defer debutils.ConfigureKernelSelection(nil, "")
507+
508+
all := []ospackage.PackageInfo{
509+
{
510+
Name: "linux-image-generic-hwe-24.04",
511+
Version: "6.170.1.1.0",
512+
URL: "pool/main/l/linux-meta-hwe-6.170/linux-image-generic-hwe-24.04_6.170.1.1.0_amd64.deb",
513+
},
514+
{
515+
Name: "linux-image-generic-hwe-24.04",
516+
Version: "6.17.1.1.0",
517+
URL: "pool/main/l/linux-meta-hwe-6.17/linux-image-generic-hwe-24.04_6.17.1.1.0_amd64.deb",
518+
},
519+
}
520+
521+
result, found := debutils.ResolveTopPackageConflicts("linux-image-generic-hwe-24.04", all)
522+
if !found {
523+
t.Fatal("expected kernel package to be found")
524+
}
525+
if result.Version != "6.17.1.1.0" {
526+
t.Errorf("expected dotted patch version to match kernel version prefix, got %q", result.Version)
527+
}
528+
}
529+
530+
func TestResolveTopPackageConflictsKernelVersionWildcardPattern(t *testing.T) {
531+
debutils.ConfigureKernelSelection([]string{"linux-image-generic*"}, "6.14")
532+
defer debutils.ConfigureKernelSelection(nil, "")
533+
534+
all := []ospackage.PackageInfo{
535+
{
536+
Name: "linux-image-generic-hwe-24.04",
537+
Version: "6.15.0-1.1~24.04.1",
538+
URL: "pool/main/l/linux-meta-hwe-6.15/linux-image-generic-hwe-24.04_6.15.0-1.1~24.04.1_amd64.deb",
539+
},
540+
{
541+
Name: "linux-image-generic-hwe-24.04",
542+
Version: "6.14.3.2.0",
543+
URL: "pool/main/l/linux-meta-hwe-6.14/linux-image-generic-hwe-24.04_6.14.3.2.0_amd64.deb",
544+
},
545+
}
546+
547+
result, found := debutils.ResolveTopPackageConflicts("linux-image-generic-hwe-24.04", all)
548+
if !found {
549+
t.Fatal("expected kernel wildcard pattern to match package request")
550+
}
551+
552+
if result.Version != "6.14.3.2.0" {
553+
t.Errorf("expected wildcard kernel pattern to enforce kernel version filter, got %q", result.Version)
554+
}
555+
}

0 commit comments

Comments
 (0)