Skip to content

Commit cab6959

Browse files
authored
Add Azure Linux 4.0 target OS and filesystem options (#714)
This PR adds the minimal foundation needed to recognize AzL4 as a target distro and configure its filesystems correctly. Locally verified. Build (dev) run against PR branch to ensure no regressions.
1 parent c0b2280 commit cab6959

5 files changed

Lines changed: 120 additions & 31 deletions

File tree

docs/imagecustomizer/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ other Linux distributions as well.
5959
Image Customizer supports the following input image distributions:
6060

6161
- Azure Linux 3.0
62+
- Azure Linux 4.0
6263
- Ubuntu 22.04
6364
- Ubuntu 24.04
6465

toolkit/tools/imagegen/diskutils/filesystem.go

Lines changed: 86 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ type fileSystemsOptions struct {
4242
Btrfs btrfsOptions
4343
// The ext4 options to use.
4444
Ext4 ext4Options
45+
// The ext4 options to use for the partition that contains the /boot directory.
46+
BootExt4 ext4Options
4547
// The xfs options to use.
4648
Xfs xfsOptions
4749
// The xfs options to use for the partition that contains the /boot directory.
@@ -68,6 +70,13 @@ var (
6870
Checksum: "crc32c",
6971
}
7072

73+
// The default btrfs options used by an Azure Linux 4.0 image (kernel v6.18).
74+
// Same as AZL3 since nothing has changed since v5.15.
75+
azl4BtrfsOptions = btrfsOptions{
76+
Features: []string{"extref", "skinny-metadata", "no-holes", "free-space-tree"},
77+
Checksum: "crc32c",
78+
}
79+
7180
// The default btrfs options used by Fedora 42 (kernel v6.11+)
7281
fedora42BtrfsOptions = btrfsOptions{
7382
Features: []string{"extref", "skinny-metadata", "no-holes", "free-space-tree"},
@@ -119,6 +128,29 @@ var (
119128
},
120129
}
121130

131+
// The default ext4 options used by an Azure Linux 4.0 image.
132+
// See, the /etc/mke2fs.conf file in an Azure Linux 4.0 image.
133+
azl4Ext4Options = ext4Options{
134+
BlockSize: 4096,
135+
Features: []string{
136+
"sparse_super", "large_file", "filetype", "resize_inode", "dir_index", "ext_attr", "has_journal", "extent",
137+
"huge_file", "flex_bg", "metadata_csum", "metadata_csum_seed", "64bit", "dir_nlink", "extra_isize",
138+
"orphan_file",
139+
},
140+
}
141+
142+
// GRUB 2.06 doesn't support 'metadata_csum_seed', we need a new set of ext4 options for the /boot partition.
143+
// This is azl4Ext4Options without 'metadata_csum_seed'.
144+
// This is needed because AZL4 images are built on AZL3 hosts.
145+
azl4BootExt4Options = ext4Options{
146+
BlockSize: 4096,
147+
Features: []string{
148+
"sparse_super", "large_file", "filetype", "resize_inode", "dir_index", "ext_attr", "has_journal", "extent",
149+
"huge_file", "flex_bg", "metadata_csum", "64bit", "dir_nlink", "extra_isize",
150+
"orphan_file",
151+
},
152+
}
153+
122154
// The default ext4 options used by Fedora 42 (kernel v6.11+)
123155
// Based on typical Fedora defaults with modern ext4 features
124156
fedora42Ext4Options = ext4Options{
@@ -170,6 +202,17 @@ var (
170202
Features: []string{"bigtime", "crc", "finobt", "inobtcount", "reflink", "rmapbt", "sparse"},
171203
}
172204

205+
// The default xfs options used by an Azure Linux 4.0 image (kernel v6.18).
206+
// See, the /usr/share/xfsprogs/mkfs/lts_6.12.conf file.
207+
azl4XfsOptions = xfsOptions{
208+
Features: []string{"bigtime", "crc", "finobt", "inobtcount", "reflink", "rmapbt", "sparse", "nrext64"},
209+
}
210+
211+
// GRUB 2.12 supports 'nrext64'.
212+
azl4BootXfsOptions = xfsOptions{
213+
Features: []string{"bigtime", "crc", "finobt", "inobtcount", "reflink", "rmapbt", "sparse", "nrext64"},
214+
}
215+
173216
// The default xfs options used by Fedora 42 (kernel v6.11+)
174217
// Based on modern XFS features supported in recent kernels
175218
fedora42XfsOptions = xfsOptions{
@@ -196,34 +239,46 @@ var (
196239

197240
targetOsFileSystemsOptions = map[targetos.TargetOs]fileSystemsOptions{
198241
targetos.TargetOsAzureLinux2: {
199-
Btrfs: azl2BtrfsOptions,
200-
Ext4: azl2Ext4Options,
201-
Xfs: azl2XfsOptions,
202-
BootXfs: azl2XfsOptions,
242+
Btrfs: azl2BtrfsOptions,
243+
Ext4: azl2Ext4Options,
244+
BootExt4: azl2Ext4Options,
245+
Xfs: azl2XfsOptions,
246+
BootXfs: azl2XfsOptions,
203247
},
204248
targetos.TargetOsAzureLinux3: {
205-
Btrfs: azl3BtrfsOptions,
206-
Ext4: azl3Ext4Options,
207-
Xfs: azl3XfsOptions,
208-
BootXfs: azl3BootXfsOptions,
249+
Btrfs: azl3BtrfsOptions,
250+
Ext4: azl3Ext4Options,
251+
BootExt4: azl3Ext4Options,
252+
Xfs: azl3XfsOptions,
253+
BootXfs: azl3BootXfsOptions,
254+
},
255+
targetos.TargetOsAzureLinux4: {
256+
Btrfs: azl4BtrfsOptions,
257+
Ext4: azl4Ext4Options,
258+
BootExt4: azl4BootExt4Options,
259+
Xfs: azl4XfsOptions,
260+
BootXfs: azl4BootXfsOptions,
209261
},
210262
targetos.TargetOsFedora42: {
211-
Btrfs: fedora42BtrfsOptions,
212-
Ext4: fedora42Ext4Options,
213-
Xfs: fedora42XfsOptions,
214-
BootXfs: fedora42XfsOptions,
263+
Btrfs: fedora42BtrfsOptions,
264+
Ext4: fedora42Ext4Options,
265+
BootExt4: fedora42Ext4Options,
266+
Xfs: fedora42XfsOptions,
267+
BootXfs: fedora42XfsOptions,
215268
},
216269
targetos.TargetOsUbuntu2204: {
217-
Btrfs: ubuntu2204BtrfsOptions,
218-
Ext4: ubuntu2204Ext4Options,
219-
Xfs: ubuntu2204XfsOptions,
220-
BootXfs: ubuntu2204XfsOptions,
270+
Btrfs: ubuntu2204BtrfsOptions,
271+
Ext4: ubuntu2204Ext4Options,
272+
BootExt4: ubuntu2204Ext4Options,
273+
Xfs: ubuntu2204XfsOptions,
274+
BootXfs: ubuntu2204XfsOptions,
221275
},
222276
targetos.TargetOsUbuntu2404: {
223-
Btrfs: ubuntu2404BtrfsOptions,
224-
Ext4: ubuntu2404Ext4Options,
225-
Xfs: ubuntu2404XfsOptions,
226-
BootXfs: ubuntu2404XfsOptions,
277+
Btrfs: ubuntu2404BtrfsOptions,
278+
Ext4: ubuntu2404Ext4Options,
279+
BootExt4: ubuntu2404Ext4Options,
280+
Xfs: ubuntu2404XfsOptions,
281+
BootXfs: ubuntu2404XfsOptions,
227282
},
228283
}
229284

@@ -274,7 +329,8 @@ var (
274329
//
275330
// Ref: https://e2fsprogs.sourceforge.net/e2fsprogs-release.html
276331
ext4FeaturesE2fsprogsSupport = map[string]version.Version{
277-
"orphan_file": {1, 47, 0},
332+
"orphan_file": {1, 47, 0},
333+
"metadata_csum_seed": {1, 47, 0},
278334
}
279335

280336
// A list of XFS features and their minimum supported xfsprogs / kernel versions.
@@ -372,7 +428,7 @@ func getFileSystemOptions(targetOs targetos.TargetOs, filesystemType string, isB
372428
return options, nil
373429

374430
case "ext4":
375-
options, err := getExt4FileSystemOptions(hostKernelVersion, options, partDevPath, fsSizeMiB)
431+
options, err := getExt4FileSystemOptions(hostKernelVersion, options, partDevPath, fsSizeMiB, isBootPartition)
376432
if err != nil {
377433
return nil, err
378434
}
@@ -465,17 +521,22 @@ func getBtrfsFileSystemOptions(hostKernelVersion version.Version, options fileSy
465521
}
466522

467523
func getExt4FileSystemOptions(hostKernelVersion version.Version, options fileSystemsOptions, partDevPath string,
468-
fsSizeMiB uint64,
524+
fsSizeMiB uint64, isBootPartition bool,
469525
) ([]string, error) {
470526
mke2fsVersion, err := getMke2fsVersion()
471527
if err != nil {
472528
return nil, err
473529
}
474530

531+
ext4Options := options.Ext4
532+
if isBootPartition {
533+
ext4Options = options.BootExt4
534+
}
535+
475536
// "none" requests no default options.
476537
features := []string{"none"}
477538

478-
for _, feature := range options.Ext4.Features {
539+
for _, feature := range ext4Options.Features {
479540
requiredKernelVersion, hasRequiredKernelVersion := ext4FeaturesKernelSupport[feature]
480541
if hasRequiredKernelVersion && requiredKernelVersion.Gt(hostKernelVersion) {
481542
// Feature is not supported on build host kernel.
@@ -495,7 +556,7 @@ func getExt4FileSystemOptions(hostKernelVersion version.Version, options fileSys
495556

496557
featuresArg := strings.Join(features, ",")
497558

498-
args := []string{"mkfs.ext4", "-b", strconv.Itoa(options.Ext4.BlockSize), "-O", featuresArg, partDevPath}
559+
args := []string{"mkfs.ext4", "-b", strconv.Itoa(ext4Options.BlockSize), "-O", featuresArg, partDevPath}
499560

500561
if fsSizeMiB != 0 {
501562
args = append(args, fmt.Sprintf("%dm", fsSizeMiB))

toolkit/tools/internal/targetos/targetos.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type TargetOs string
1818
const (
1919
TargetOsAzureLinux2 TargetOs = "azl2"
2020
TargetOsAzureLinux3 TargetOs = "azl3"
21+
TargetOsAzureLinux4 TargetOs = "azl4"
2122
TargetOsAzureContainerLinux3 TargetOs = "acl3"
2223
TargetOsFedora42 TargetOs = "fedora42"
2324
TargetOsUbuntu2204 TargetOs = "ubuntu2204"
@@ -68,6 +69,9 @@ func GetInstalledTargetOs(rootfs string) (TargetOs, error) {
6869
case "3.0":
6970
return TargetOsAzureLinux3, nil
7071

72+
case "4.0":
73+
return TargetOsAzureLinux4, nil
74+
7175
default:
7276
return "", fmt.Errorf("unknown VERSION_ID (%s) for Azure Linux in os-release", versionId)
7377
}

toolkit/tools/pkg/imagecustomizerlib/distrohandler.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ func NewDistroHandlerFromTargetOs(targetOs targetos.TargetOs) DistroHandler {
8383
return newAzureLinuxDistroHandler("2.0")
8484
case targetos.TargetOsAzureLinux3:
8585
return newAzureLinuxDistroHandler("3.0")
86+
case targetos.TargetOsAzureLinux4:
87+
return newAzureLinuxDistroHandler("4.0")
8688
case targetos.TargetOsAzureContainerLinux3:
8789
return newAclDistroHandler()
8890
case targetos.TargetOsUbuntu2204:

toolkit/tools/pkg/imagecustomizerlib/distrohandler_azurelinux.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,16 @@ type azureLinuxDistroHandler struct {
2424
}
2525

2626
func newAzureLinuxDistroHandler(version string) *azureLinuxDistroHandler {
27+
var packageManager rpmPackageManagerHandler
28+
if version == "4.0" {
29+
packageManager = newDnfPackageManager(version)
30+
} else {
31+
packageManager = newTdnfPackageManager(version)
32+
}
33+
2734
return &azureLinuxDistroHandler{
2835
version: version,
29-
packageManager: newTdnfPackageManager(version),
36+
packageManager: packageManager,
3037
}
3138
}
3239

@@ -36,6 +43,8 @@ func (d *azureLinuxDistroHandler) GetTargetOs() targetos.TargetOs {
3643
return targetos.TargetOsAzureLinux2
3744
case "3.0":
3845
return targetos.TargetOsAzureLinux3
46+
case "4.0":
47+
return targetos.TargetOsAzureLinux4
3948
default:
4049
panic("unsupported Azure Linux version: " + d.version)
4150
}
@@ -65,13 +74,25 @@ func (d *azureLinuxDistroHandler) GetAllPackagesFromChroot(imageChroot safechroo
6574
}
6675

6776
func (d *azureLinuxDistroHandler) DetectBootloaderType(imageChroot safechroot.ChrootInterface) (BootloaderType, error) {
68-
if d.IsPackageInstalled(imageChroot, "grub2-efi-binary") || d.IsPackageInstalled(imageChroot, "grub2-efi-binary-noprefix") {
69-
return BootloaderTypeGrub, nil
77+
grubPackages := []string{"grub2-efi-binary", "grub2-efi-binary-noprefix"}
78+
if d.version == "4.0" {
79+
grubPackages = []string{"grub2-efi-x64", "grub2-efi-aa64"}
80+
}
81+
for _, pkg := range grubPackages {
82+
if d.IsPackageInstalled(imageChroot, pkg) {
83+
return BootloaderTypeGrub, nil
84+
}
85+
}
86+
systemdBootPackages := []string{"systemd-boot"}
87+
if d.version == "4.0" {
88+
systemdBootPackages = []string{"systemd-boot", "systemd-boot-unsigned"}
7089
}
71-
if d.IsPackageInstalled(imageChroot, "systemd-boot") {
72-
return BootloaderTypeSystemdBoot, nil
90+
for _, pkg := range systemdBootPackages {
91+
if d.IsPackageInstalled(imageChroot, pkg) {
92+
return BootloaderTypeSystemdBoot, nil
93+
}
7394
}
74-
return "", fmt.Errorf("unknown bootloader: neither grub2-efi-binary, grub2-efi-binary-noprefix, nor systemd-boot found")
95+
return "", fmt.Errorf("unknown bootloader: none of %v or %v found", grubPackages, systemdBootPackages)
7596
}
7697

7798
func (d *azureLinuxDistroHandler) GetEspDir() string {

0 commit comments

Comments
 (0)