Skip to content

Commit a4110aa

Browse files
authored
azl4: Create Distro-Aware FindBootPartitionUuidFromEsp for output.artifacts API support (#724)
The grub.cfg stubs on the EFI partitions are in a different location and require a different regular expression to grep for the boot partition UUID on AZL4, so this PR introduces DistroHandler.FindBootPartitionUuidFromEsp to handle that. Example azl4 grub.cfg stub (from Alpha 2 release): ``` search --fs-uuid --set=root 3190eea2-a4b1-4399-9679-e0840cf8eb75 set prefix=($root)/boot/grub2 configfile ($root)/boot/grub2/grub.cfg ```
1 parent 5195ba5 commit a4110aa

8 files changed

Lines changed: 64 additions & 17 deletions

File tree

toolkit/tools/pkg/imagecustomizerlib/artifactsinputoutput.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ var ukiRegex = regexp.MustCompile(`^vmlinuz-.*\.efi$`)
5757

5858
func outputArtifacts(ctx context.Context, items []imagecustomizerapi.OutputArtifactsItemType,
5959
outputDir string, buildDir string, buildImage string, verityMetadata []verityDeviceMetadata,
60-
previewFeatures []imagecustomizerapi.PreviewFeature,
60+
previewFeatures []imagecustomizerapi.PreviewFeature, distroHandler DistroHandler,
6161
) error {
6262
logger.Log.Infof("Outputting artifacts")
6363

@@ -82,7 +82,7 @@ func outputArtifacts(ctx context.Context, items []imagecustomizerapi.OutputArtif
8282
return err
8383
}
8484

85-
bootPartition, err := findBootPartitionFromEsp(systemBootPartition, diskPartitions, buildDir)
85+
bootPartition, err := findBootPartitionFromEsp(systemBootPartition, diskPartitions, buildDir, distroHandler)
8686
if err != nil {
8787
return err
8888
}

toolkit/tools/pkg/imagecustomizerlib/distrohandler.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ type DistroHandler interface {
5555
// For example: "boot/efi" for most distros, "boot" for ACL.
5656
GetEspDir() string
5757

58+
// FindBootPartitionUuidFromEsp reads the distro's grub.cfg stub from the already-mounted ESP at espMountDir and
59+
// returns the UUID of the partition that contains the grub.cfg.
60+
FindBootPartitionUuidFromEsp(espMountDir string) (string, error)
61+
5862
// Reports whether SELinux configuration is supported by the tool for this distro.
5963
SELinuxSupported() bool
6064

toolkit/tools/pkg/imagecustomizerlib/distrohandler_acl.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"fmt"
99
"io/fs"
10+
"path/filepath"
1011

1112
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/imagecustomizerapi"
1213
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/imageconnection"
@@ -78,6 +79,10 @@ func (d *aclDistroHandler) GetEspDir() string {
7879
return "boot"
7980
}
8081

82+
func (d *aclDistroHandler) FindBootPartitionUuidFromEsp(espMountDir string) (string, error) {
83+
return readBootPartitionUuidFromGrubCfg(filepath.Join(espMountDir, espGrubCfgPathAzl3), bootPartitionRegexAzl3)
84+
}
85+
8186
func (d *aclDistroHandler) SELinuxSupported() bool {
8287
return true
8388
}

toolkit/tools/pkg/imagecustomizerlib/distrohandler_azurelinux.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package imagecustomizerlib
66
import (
77
"context"
88
"fmt"
9+
"path/filepath"
910

1011
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/imagecustomizerapi"
1112
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/imagegen/installutils"
@@ -106,6 +107,17 @@ func (d *azureLinuxDistroHandler) GetEspDir() string {
106107
return "boot/efi"
107108
}
108109

110+
func (d *azureLinuxDistroHandler) FindBootPartitionUuidFromEsp(espMountDir string) (string, error) {
111+
espGrubCfgPath := espGrubCfgPathAzl3
112+
bootPartitionRegex := bootPartitionRegexAzl3
113+
if d.version == "4.0" {
114+
espGrubCfgPath = espGrubCfgPathAzl4
115+
bootPartitionRegex = bootPartitionRegexAzl4
116+
}
117+
118+
return readBootPartitionUuidFromGrubCfg(filepath.Join(espMountDir, espGrubCfgPath), bootPartitionRegex)
119+
}
120+
109121
func (d *azureLinuxDistroHandler) SELinuxSupported() bool {
110122
return true
111123
}

toolkit/tools/pkg/imagecustomizerlib/distrohandler_fedora.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package imagecustomizerlib
66
import (
77
"context"
88
"fmt"
9+
"path/filepath"
910
"slices"
1011

1112
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/imagecustomizerapi"
@@ -91,6 +92,11 @@ func (d *fedoraDistroHandler) GetEspDir() string {
9192
return "boot/efi"
9293
}
9394

95+
func (d *fedoraDistroHandler) FindBootPartitionUuidFromEsp(espMountDir string) (string, error) {
96+
// Reading Fedora's grub.cfg stub is not supported, so for now just use Azure Linux 3.0's values.
97+
return readBootPartitionUuidFromGrubCfg(filepath.Join(espMountDir, espGrubCfgPathAzl3), bootPartitionRegexAzl3)
98+
}
99+
94100
func (d *fedoraDistroHandler) SELinuxSupported() bool {
95101
return true
96102
}

toolkit/tools/pkg/imagecustomizerlib/distrohandler_ubuntu.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package imagecustomizerlib
66
import (
77
"context"
88
"fmt"
9+
"path/filepath"
910
"slices"
1011

1112
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/imagecustomizerapi"
@@ -112,6 +113,11 @@ func (d *ubuntuDistroHandler) GetEspDir() string {
112113
return "boot/efi"
113114
}
114115

116+
func (d *ubuntuDistroHandler) FindBootPartitionUuidFromEsp(espMountDir string) (string, error) {
117+
// Reading Ubuntu's grub.cfg stub is not supported, so for now just use Azure Linux 3.0's values.
118+
return readBootPartitionUuidFromGrubCfg(filepath.Join(espMountDir, espGrubCfgPathAzl3), bootPartitionRegexAzl3)
119+
}
120+
115121
func (d *ubuntuDistroHandler) SELinuxSupported() bool {
116122
return false
117123
}

toolkit/tools/pkg/imagecustomizerlib/imagecustomizer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ func customizeImageOptionsHelper(ctx context.Context, baseConfigPath string, con
271271
outputDir := file.GetAbsPathWithBase(baseConfigPath, rc.OutputArtifacts.Path)
272272

273273
err = outputArtifacts(ctx, rc.OutputArtifacts.Items, outputDir, rc.BuildDirAbs,
274-
rc.RawImageFile, im.verityMetadata, rc.PreviewFeatures)
274+
rc.RawImageFile, im.verityMetadata, rc.PreviewFeatures, im.distroHandler)
275275
if err != nil {
276276
return fmt.Errorf("%w:\n%w", ErrCustomizeOutputArtifacts, err)
277277
}

toolkit/tools/pkg/imagecustomizerlib/partitionutils.go

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717

1818
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/imagecustomizerapi"
1919
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/imagegen/diskutils"
20-
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/imagegen/installutils"
2120
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/file"
2221
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/grub"
2322
"github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/imageconnection"
@@ -32,12 +31,18 @@ import (
3231
)
3332

3433
var (
35-
bootPartitionRegex = regexp.MustCompile(`(?m)^search -n -u ([a-zA-Z0-9\-]+) -s$`)
34+
bootPartitionRegexAzl3 = regexp.MustCompile(`(?m)^[\t ]*search\s+-n\s+-u\s+([a-zA-Z0-9\-]+)\s+-s\s*$`)
35+
bootPartitionRegexAzl4 = regexp.MustCompile(`(?m)^[\t ]*search\s+--fs-uuid\s+--set=root\s+([a-zA-Z0-9\-]+)\s*$`)
3636

3737
// Extract the partition number from the loopback partition path.
3838
partitionNumberRegex = regexp.MustCompile(`^/dev/loop\d+p(\d+)$`)
3939
)
4040

41+
const (
42+
espGrubCfgPathAzl3 = "boot/grub2/grub.cfg"
43+
espGrubCfgPathAzl4 = "EFI/fedora/grub.cfg"
44+
)
45+
4146
const (
4247
// BtrfsTopLevelSubvolumeId is the ID of the top-level subvolume in a BTRFS filesystem.
4348
// This is BTRFS_FS_TREE_OBJECTID, the objectid that refers to the global FS_TREE root.
@@ -76,7 +81,9 @@ func findSystemBootPartition(diskPartitions []diskutils.PartitionInfo) (*diskuti
7681
return bootPartition, nil
7782
}
7883

79-
func findBootPartitionFromEsp(efiSystemPartition *diskutils.PartitionInfo, diskPartitions []diskutils.PartitionInfo, buildDir string) (*diskutils.PartitionInfo, error) {
84+
func findBootPartitionFromEsp(efiSystemPartition *diskutils.PartitionInfo, diskPartitions []diskutils.PartitionInfo,
85+
buildDir string, distroHandler DistroHandler,
86+
) (*diskutils.PartitionInfo, error) {
8087
tmpDir := filepath.Join(buildDir, tmpEspPartitionDirName)
8188

8289
// Mount the EFI System Partition.
@@ -86,9 +93,7 @@ func findBootPartitionFromEsp(efiSystemPartition *diskutils.PartitionInfo, diskP
8693
}
8794
defer efiSystemPartitionMount.Close()
8895

89-
// Read the grub.cfg file.
90-
grubConfigFilePath := filepath.Join(tmpDir, installutils.FedoraGrubCfgFile)
91-
grubConfigFile, err := os.ReadFile(grubConfigFilePath)
96+
bootPartitionUuid, err := distroHandler.FindBootPartitionUuidFromEsp(tmpDir)
9297
if err != nil {
9398
return nil, fmt.Errorf("failed to read EFI system partition's grub.cfg file:\n%w", err)
9499
}
@@ -99,14 +104,6 @@ func findBootPartitionFromEsp(efiSystemPartition *diskutils.PartitionInfo, diskP
99104
return nil, fmt.Errorf("failed to close EFI system partition mount:\n%w", err)
100105
}
101106

102-
// Look for the bootloader partition declaration line in the grub.cfg file.
103-
match := bootPartitionRegex.FindStringSubmatch(string(grubConfigFile))
104-
if match == nil {
105-
return nil, fmt.Errorf("failed to find boot partition in grub.cfg file")
106-
}
107-
108-
bootPartitionUuid := match[1]
109-
110107
var bootPartition *diskutils.PartitionInfo
111108
for i := range diskPartitions {
112109
diskPartition := diskPartitions[i]
@@ -124,6 +121,23 @@ func findBootPartitionFromEsp(efiSystemPartition *diskutils.PartitionInfo, diskP
124121
return bootPartition, nil
125122
}
126123

124+
// readBootPartitionUuidFromGrubCfg reads the grub.cfg file at grubConfigFilePath and
125+
// returns the UUID captured by bootPartitionRegex's first capture group.
126+
func readBootPartitionUuidFromGrubCfg(grubConfigFilePath string, bootPartitionRegex *regexp.Regexp,
127+
) (string, error) {
128+
grubConfigFile, err := os.ReadFile(grubConfigFilePath)
129+
if err != nil {
130+
return "", fmt.Errorf("failed to read EFI system partition's grub.cfg file (%s):\n%w", grubConfigFilePath, err)
131+
}
132+
133+
match := bootPartitionRegex.FindStringSubmatch(string(grubConfigFile))
134+
if match == nil {
135+
return "", fmt.Errorf("failed to find boot partition in grub.cfg file (%s)", grubConfigFilePath)
136+
}
137+
138+
return match[1], nil
139+
}
140+
127141
// Searches for the partition that contains the /etc/fstab file.
128142
// While technically it is possible to place /etc on a different partition, doing so is fairly difficult and requires
129143
// a custom initramfs module.

0 commit comments

Comments
 (0)