OSModifier: Add support for updating grub (#9874)

Co-authored-by: Ubuntu <azureuser@elaine-dev2.ympr0pkouz1evfbws3zckpfswc.bx.internal.cloudapp.net>
This commit is contained in:
elainezhao96 2024-09-05 11:31:31 -07:00 коммит произвёл GitHub
Родитель a83715e18b
Коммит 449f279ffc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
13 изменённых файлов: 418 добавлений и 42 удалений

Просмотреть файл

@ -1474,7 +1474,7 @@ func installGrubTemplateFile(assetFile, targetFile, installRoot, rootDevice, boo
return
}
func CallGrubMkconfig(installChroot *safechroot.Chroot) (err error) {
func CallGrubMkconfig(installChroot safechroot.ChrootInterface) (err error) {
squashErrors := false
ReportActionf("Running grub2-mkconfig...")
@ -1965,7 +1965,7 @@ func SELinuxConfigure(selinuxMode configuration.SELinux, installChroot *safechro
return
}
func SELinuxUpdateConfig(selinuxMode configuration.SELinux, installChroot *safechroot.Chroot) (err error) {
func SELinuxUpdateConfig(selinuxMode configuration.SELinux, installChroot safechroot.ChrootInterface) (err error) {
const (
selinuxPattern = "^SELINUX=.*"
)
@ -1986,7 +1986,7 @@ func SELinuxUpdateConfig(selinuxMode configuration.SELinux, installChroot *safec
return
}
func SELinuxRelabelFiles(installChroot *safechroot.Chroot, mountPointToFsTypeMap map[string]string, isRootFS bool,
func SELinuxRelabelFiles(installChroot safechroot.ChrootInterface, mountPointToFsTypeMap map[string]string, isRootFS bool,
) (err error) {
const (
fileContextBasePath = "etc/selinux/%s/contexts/files/file_contexts"

Просмотреть файл

@ -18,10 +18,11 @@ import (
var (
app = kingpin.New("osmodifier", "Used to modify os")
configFile = app.Flag("config-file", "Path of the os modification config file.").Required().String()
configFile = app.Flag("config-file", "Path of the os modification config file.").String()
logFlags = exe.SetupLogFlags(app)
profFlags = exe.SetupProfileFlags(app)
timestampFile = app.Flag("timestamp-file", "File that stores timestamps for this program.").String()
updateGrub = app.Flag("update-grub", "Update default GRUB.").Bool()
)
func main() {
@ -40,9 +41,19 @@ func main() {
timestamp.BeginTiming("osmodifier", *timestampFile)
defer timestamp.CompleteTiming()
err = modifyImage()
if err != nil {
log.Fatalf("os modification failed: %v", err)
// Check if the updateGrub flag is set
if *updateGrub {
err := osmodifierlib.ModifyDefaultGrub()
if err != nil {
log.Fatalf("update grub failed: %v", err)
}
}
if len(*configFile) > 0 {
err = modifyImage()
if err != nil {
log.Fatalf("OS modification failed: %v", err)
}
}
}

Просмотреть файл

@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package osmodifierapi
import (
"fmt"
)
type IdentifiedPartition struct {
Id string `yaml:"id"`
}
func (i *IdentifiedPartition) IsValid() error {
// Check if Id is not empty
if i.Id == "" {
return fmt.Errorf("invalid id: empty string")
}
return nil
}

Просмотреть файл

@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package osmodifierapi
import (
"fmt"
"strings"
"github.com/asaskevich/govalidator"
"github.com/microsoft/azurelinux/toolkit/tools/imagecustomizerapi"
)
// OS defines how each system present on the image is supposed to be configured.
type OS struct {
Hostname string `yaml:"hostname"`
SELinux imagecustomizerapi.SELinux `yaml:"selinux"`
Users []imagecustomizerapi.User `yaml:"users"`
Overlays *[]Overlay `yaml:"overlays"`
}
func (s *OS) IsValid() error {
var err error
if s.Hostname != "" {
if !govalidator.IsDNSName(s.Hostname) || strings.Contains(s.Hostname, "_") {
return fmt.Errorf("invalid hostname (%s)", s.Hostname)
}
}
err = s.SELinux.IsValid()
if err != nil {
return fmt.Errorf("invalid selinux:\n%w", err)
}
for i, user := range s.Users {
err = user.IsValid()
if err != nil {
return fmt.Errorf("invalid users item at index %d:\n%w", i, err)
}
}
if s.Overlays != nil {
upperDirs := make(map[string]bool)
workDirs := make(map[string]bool)
for i, overlay := range *s.Overlays {
// Validate the overlay itself
err := overlay.IsValid()
if err != nil {
return fmt.Errorf("invalid overlay at index %d:\n%w", i, err)
}
// Check for unique UpperDir
if _, exists := upperDirs[overlay.UpperDir]; exists {
return fmt.Errorf("duplicate upperDir (%s) found in overlay at index %d", overlay.UpperDir, i)
}
upperDirs[overlay.UpperDir] = true
// Check for unique WorkDir
if _, exists := workDirs[overlay.WorkDir]; exists {
return fmt.Errorf("duplicate workDir (%s) found in overlay at index %d", overlay.WorkDir, i)
}
workDirs[overlay.WorkDir] = true
}
}
return nil
}

Просмотреть файл

@ -0,0 +1,73 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package osmodifierapi
import (
"fmt"
"strings"
)
type Overlay struct {
LowerDir string `yaml:"lowerDir"`
UpperDir string `yaml:"upperDir"`
WorkDir string `yaml:"workDir"`
Partition *IdentifiedPartition `yaml:"partition"`
}
func (o *Overlay) IsValid() error {
// Validate paths for UpperDir, WorkDir, and LowerDir
if err := validatePath(o.UpperDir); err != nil {
return fmt.Errorf("invalid upperDir (%s):\n%w", o.UpperDir, err)
}
if err := validatePath(o.WorkDir); err != nil {
return fmt.Errorf("invalid workDir (%s):\n%w", o.WorkDir, err)
}
if err := validatePath(o.LowerDir); err != nil {
return fmt.Errorf("invalid lowerDir (%s):\n%w", o.LowerDir, err)
}
// Check if UpperDir and WorkDir are identical
if o.UpperDir == o.WorkDir {
return fmt.Errorf("upperDir and workDir must be distinct, but both are '%s'", o.UpperDir)
}
// Check if UpperDir is a subdirectory of WorkDir or vice versa
if isSubDirString(o.UpperDir, o.WorkDir) {
return fmt.Errorf("upperDir (%s) should not be a subdirectory of workDir (%s)", o.UpperDir, o.WorkDir)
}
if isSubDirString(o.WorkDir, o.UpperDir) {
return fmt.Errorf("workDir (%s) should not be a subdirectory of upperDir (%s)", o.WorkDir, o.UpperDir)
}
if o.Partition != nil {
if err := o.Partition.IsValid(); err != nil {
return fmt.Errorf("invalid partition:\n%w", err)
}
}
return nil
}
func validatePath(path string) error {
// Check if the path is empty
if path == "" {
return fmt.Errorf("path cannot be empty")
}
// Check if the path contains spaces
if strings.Contains(path, " ") {
return fmt.Errorf("path (%s) contains spaces and is invalid", path)
}
return nil
}
func isSubDirString(dir1, dir2 string) bool {
// Ensure paths are cleaned and have consistent trailing slashes
cleanDir1 := strings.TrimSuffix(dir1, "/") + "/"
cleanDir2 := strings.TrimSuffix(dir2, "/") + "/"
// Check if dir2 starts with dir1 (indicating a subdirectory)
return cleanDir1 != cleanDir2 && strings.HasPrefix(cleanDir2, cleanDir1)
}

Просмотреть файл

@ -23,8 +23,8 @@ type BootCustomizer struct {
isGrubMkconfig bool
}
func NewBootCustomizer(imageChroot *safechroot.Chroot) (*BootCustomizer, error) {
grubCfgContent, err := readGrub2ConfigFile(imageChroot)
func NewBootCustomizer(imageChroot safechroot.ChrootInterface) (*BootCustomizer, error) {
grubCfgContent, err := ReadGrub2ConfigFile(imageChroot)
if err != nil {
return nil, err
}
@ -83,7 +83,7 @@ func (b *BootCustomizer) getSELinuxModeFromGrub() (imagecustomizerapi.SELinuxMod
// Get the SELinux kernel command-line args.
if b.isGrubMkconfig {
_, args, _, err = getDefaultGrubFileLinuxArgs(b.defaultGrubFileContent, defaultGrubFileVarNameCmdlineForSELinux)
_, args, _, err = GetDefaultGrubFileLinuxArgs(b.defaultGrubFileContent, defaultGrubFileVarNameCmdlineForSELinux)
if err != nil {
return "", err
}
@ -103,7 +103,7 @@ func (b *BootCustomizer) getSELinuxModeFromGrub() (imagecustomizerapi.SELinuxMod
return selinuxMode, nil
}
func (b *BootCustomizer) GetSELinuxMode(imageChroot *safechroot.Chroot) (imagecustomizerapi.SELinuxMode, error) {
func (b *BootCustomizer) GetSELinuxMode(imageChroot safechroot.ChrootInterface) (imagecustomizerapi.SELinuxMode, error) {
// Get the SELinux mode from the kernel command-line args.
selinuxMode, err := b.getSELinuxModeFromGrub()
if err != nil {
@ -163,7 +163,7 @@ func (b *BootCustomizer) UpdateKernelCommandLineArgs(defaultGrubFileVarName defa
func (b *BootCustomizer) PrepareForVerity() error {
if b.isGrubMkconfig {
// Force root command-line arg to be referenced by /dev path instead of by UUID.
defaultGrubFileContent, err := updateDefaultGrubFileVariable(b.defaultGrubFileContent, "GRUB_DISABLE_UUID",
defaultGrubFileContent, err := UpdateDefaultGrubFileVariable(b.defaultGrubFileContent, "GRUB_DISABLE_UUID",
"true")
if err != nil {
return err
@ -171,26 +171,31 @@ func (b *BootCustomizer) PrepareForVerity() error {
// Disable recovery menu entry, to avoid having more than 1 linux command in the grub.cfg file.
// This will make it easier to modify the grub.cfg file to add the verity args.
defaultGrubFileContent, err = updateDefaultGrubFileVariable(defaultGrubFileContent, "GRUB_DISABLE_RECOVERY",
defaultGrubFileContent, err = UpdateDefaultGrubFileVariable(defaultGrubFileContent, "GRUB_DISABLE_RECOVERY",
"true")
if err != nil {
return err
}
// For verity, the root device will always be "/dev/mapper/root"
defaultGrubFileContent, err = UpdateDefaultGrubFileVariable(defaultGrubFileContent, "GRUB_DEVICE", "/dev/mapper/root")
if err != nil {
return err
}
b.defaultGrubFileContent = defaultGrubFileContent
}
return nil
}
func (b *BootCustomizer) WriteToFile(imageChroot *safechroot.Chroot) error {
func (b *BootCustomizer) WriteToFile(imageChroot safechroot.ChrootInterface) error {
if b.isGrubMkconfig {
// Update /etc/defaukt/grub file.
err := writeDefaultGrubFile(b.defaultGrubFileContent, imageChroot)
err := WriteDefaultGrubFile(b.defaultGrubFileContent, imageChroot)
if err != nil {
return err
}
// Update /boot/grub2/grub.cfg file.
err = installutils.CallGrubMkconfig(imageChroot)
if err != nil {

Просмотреть файл

@ -161,9 +161,10 @@ func TestBootCustomizerVerity30(t *testing.T) {
err := b.PrepareForVerity()
assert.NoError(t, err)
expectedDefaultGrubFileDiff := `6a7,8
expectedDefaultGrubFileDiff := `6a7,9
> GRUB_DISABLE_UUID="true"
> GRUB_DISABLE_RECOVERY="true"
> GRUB_DEVICE="/dev/mapper/root"
`
checkDiffs30(t, b, "", expectedDefaultGrubFileDiff)

Просмотреть файл

@ -56,7 +56,7 @@ func handleSELinux(selinuxMode imagecustomizerapi.SELinuxMode, resetBootLoaderTy
}
}
err = updateSELinuxModeInConfigFile(selinuxMode, imageChroot)
err = UpdateSELinuxModeInConfigFile(selinuxMode, imageChroot)
if err != nil {
return imagecustomizerapi.SELinuxModeDefault, err
}
@ -64,7 +64,7 @@ func handleSELinux(selinuxMode imagecustomizerapi.SELinuxMode, resetBootLoaderTy
return selinuxMode, nil
}
func updateSELinuxModeInConfigFile(selinuxMode imagecustomizerapi.SELinuxMode, imageChroot *safechroot.Chroot) error {
func UpdateSELinuxModeInConfigFile(selinuxMode imagecustomizerapi.SELinuxMode, imageChroot safechroot.ChrootInterface) error {
imagerSELinuxMode, err := selinuxModeToImager(selinuxMode)
if err != nil {
return err

Просмотреть файл

@ -137,7 +137,7 @@ func findDefaultGrubFileVarAssign(varAssigns []defaultGrubFileVarAssign, name de
// - cmdLineVarAssign: The variable assignment that matches 'varName'.
// - args: The list of kernel command-line args.
// - insertAt: An index that new kernel command-line args can be inserted at.
func getDefaultGrubFileLinuxArgs(defaultGrubFileContent string, varName defaultGrubFileVarName,
func GetDefaultGrubFileLinuxArgs(defaultGrubFileContent string, varName defaultGrubFileVarName,
) (defaultGrubFileVarAssign, []grubConfigLinuxArg, int, error) {
varAssigns, err := findDefaultGrubFileVarAssigns(defaultGrubFileContent)
if err != nil {
@ -174,7 +174,7 @@ func getDefaultGrubFileLinuxArgs(defaultGrubFileContent string, varName defaultG
insertAt = len(argsString)
}
args, err := parseCommandLineArgs(grubTokens)
args, err := ParseCommandLineArgs(grubTokens)
if err != nil {
err = fmt.Errorf("failed to parse %s's value args:\n%w", varName, err)
return defaultGrubFileVarAssign{}, nil, 0, err
@ -185,7 +185,7 @@ func getDefaultGrubFileLinuxArgs(defaultGrubFileContent string, varName defaultG
// Takes the string contents of /etc/default/grub file and inserts the provided command-line args.
func addExtraCommandLineToDefaultGrubFile(defaultGrubFileContent string, extraCommandLine string) (string, error) {
cmdLineVarAssign, _, insertAt, err := getDefaultGrubFileLinuxArgs(defaultGrubFileContent,
cmdLineVarAssign, _, insertAt, err := GetDefaultGrubFileLinuxArgs(defaultGrubFileContent,
defaultGrubFileVarNameCmdlineLinuxDefault)
if err != nil {
return "", err
@ -215,7 +215,7 @@ func addExtraCommandLineToDefaultGrubFile(defaultGrubFileContent string, extraCo
func updateDefaultGrubFileKernelCommandLineArgs(defaultGrubFileContent string, varName defaultGrubFileVarName,
argsToRemove []string, newArgs []string,
) (string, error) {
cmdLineVarAssign, args, insertAt, err := getDefaultGrubFileLinuxArgs(defaultGrubFileContent, varName)
cmdLineVarAssign, args, insertAt, err := GetDefaultGrubFileLinuxArgs(defaultGrubFileContent, varName)
if err != nil {
return "", err
}
@ -286,7 +286,7 @@ func insertDefaultGrubFileVarAssign(defaultGrubFileContent string, insertAfterLi
// Sets the value of a variable in the /etc/default/grub file, either replacing the existing variable value (if one
// exists) or adding a new one.
func updateDefaultGrubFileVariable(defaultGrubFileContent string, varName string, newValue string) (string, error) {
func UpdateDefaultGrubFileVariable(defaultGrubFileContent string, varName string, newValue string) (string, error) {
varAssigns, err := findDefaultGrubFileVarAssigns(defaultGrubFileContent)
if err != nil {
err = fmt.Errorf("failed to parse %s file:\n%w", installutils.GrubDefFile, err)
@ -320,7 +320,7 @@ func updateDefaultGrubFileVariable(defaultGrubFileContent string, varName string
// Checks if the image uses grub-mkconfig.
func isGrubMkconfigEnabled(imageChroot *safechroot.Chroot) (bool, error) {
grub2ConfigFile, err := readGrub2ConfigFile(imageChroot)
grub2ConfigFile, err := ReadGrub2ConfigFile(imageChroot)
if err != nil {
return false, err
}
@ -336,7 +336,7 @@ func isGrubMkconfigConfig(grub2Config string) bool {
}
// Reads the string contents of the /etc/default/grub file.
func readDefaultGrubFile(imageChroot *safechroot.Chroot) (string, error) {
func readDefaultGrubFile(imageChroot safechroot.ChrootInterface) (string, error) {
logger.Log.Debugf("Reading %s file", installutils.GrubDefFile)
grub2ConfigFilePath := getDefaultGrubFilePath(imageChroot)
@ -351,7 +351,7 @@ func readDefaultGrubFile(imageChroot *safechroot.Chroot) (string, error) {
}
// Writes the string contents of the /etc/default/grub file.
func writeDefaultGrubFile(grub2Config string, imageChroot *safechroot.Chroot) error {
func WriteDefaultGrubFile(grub2Config string, imageChroot safechroot.ChrootInterface) error {
logger.Log.Debugf("Writing %s file", installutils.GrubDefFile)
grub2ConfigFilePath := getDefaultGrubFilePath(imageChroot)
@ -365,6 +365,6 @@ func writeDefaultGrubFile(grub2Config string, imageChroot *safechroot.Chroot) er
return nil
}
func getDefaultGrubFilePath(imageChroot *safechroot.Chroot) string {
func getDefaultGrubFilePath(imageChroot safechroot.ChrootInterface) string {
return filepath.Join(imageChroot.RootDir(), installutils.GrubDefFile)
}

Просмотреть файл

@ -120,7 +120,7 @@ func findLinuxOrInitrdLineAll(inputGrubCfgContent string, commandName string, al
}
// Find the linux command within the grub config file.
func findLinuxLine(inputGrubCfgContent string) (grub.Line, error) {
func FindLinuxLine(inputGrubCfgContent string) (grub.Line, error) {
lines, err := findLinuxOrInitrdLineAll(inputGrubCfgContent, linuxCommand, false /*allowMultiple*/)
if err != nil {
return grub.Line{}, err
@ -245,7 +245,7 @@ func getLinuxCommandLineArgs(grub2Config string, requireKernelOpts bool) ([]grub
return nil, 0, err
}
args, err := parseCommandLineArgs(argTokens)
args, err := ParseCommandLineArgs(argTokens)
if err != nil {
return nil, 0, err
}
@ -295,7 +295,7 @@ func findCommandLineInsertAt(argTokens []grub.Token, requireKernelOpts bool) (in
}
// Takes a tokenized grub.cfg file and makes a best effort to extract the kernel command-line args.
func parseCommandLineArgs(argTokens []grub.Token) ([]grubConfigLinuxArg, error) {
func ParseCommandLineArgs(argTokens []grub.Token) ([]grubConfigLinuxArg, error) {
args := []grubConfigLinuxArg(nil)
for i := range argTokens {
@ -400,7 +400,7 @@ func replaceKernelCommandLineArgValueAll(inputGrubCfgContent string, name string
// Skip the "linux" command and the kernel binary path arg.
argTokens := line.Tokens[2:]
args, err := parseCommandLineArgs(argTokens)
args, err := ParseCommandLineArgs(argTokens)
if err != nil {
return "", nil, err
}
@ -445,7 +445,7 @@ func updateKernelCommandLineArgsAll(grub2Config string, argsToRemove []string, n
return "", err
}
args, err := parseCommandLineArgs(argTokens)
args, err := ParseCommandLineArgs(argTokens)
if err != nil {
return "", err
}
@ -474,7 +474,7 @@ func updateKernelCommandLineArgs(grub2Config string, argsToRemove []string, newA
func updateKernelCommandLineArgsHelper(value string, args []grubConfigLinuxArg, insertAt int,
argsToRemove []string, newArgs []string,
) (string, error) {
newArgsQuoted := grubArgsToString(newArgs)
newArgsQuoted := GrubArgsToString(newArgs)
foundArgs := findMatchingCommandLineArgs(args, argsToRemove)
builder := strings.Builder{}
@ -511,7 +511,7 @@ func updateKernelCommandLineArgsHelper(value string, args []grubConfigLinuxArg,
// Takes a list of unescaped and unquoted kernel command-line args and combines them into a single string with
// appropriate quoting for a grub.cfg file.
func grubArgsToString(args []string) string {
func GrubArgsToString(args []string) string {
builder := strings.Builder{}
for i, arg := range args {
if i != 0 {
@ -666,7 +666,7 @@ func getSELinuxModeFromLinuxArgs(args []grubConfigLinuxArg) (imagecustomizerapi.
}
// Gets the SELinux mode set by the /etc/selinux/config file.
func getSELinuxModeFromConfigFile(imageChroot *safechroot.Chroot) (imagecustomizerapi.SELinuxMode, error) {
func getSELinuxModeFromConfigFile(imageChroot safechroot.ChrootInterface) (imagecustomizerapi.SELinuxMode, error) {
selinuxConfigFilePath := filepath.Join(imageChroot.RootDir(), installutils.SELinuxConfigFile)
// Read the SELinux config file.
@ -701,7 +701,7 @@ func getSELinuxModeFromConfigFile(imageChroot *safechroot.Chroot) (imagecustomiz
}
// Reads the /boot/grub2/grub.cfg file.
func readGrub2ConfigFile(imageChroot *safechroot.Chroot) (string, error) {
func ReadGrub2ConfigFile(imageChroot safechroot.ChrootInterface) (string, error) {
logger.Log.Debugf("Reading grub.cfg file")
grub2ConfigFilePath := getGrub2ConfigFilePath(imageChroot)
@ -716,7 +716,7 @@ func readGrub2ConfigFile(imageChroot *safechroot.Chroot) (string, error) {
}
// Writes the /boot/grub2/grub.cfg file.
func writeGrub2ConfigFile(grub2Config string, imageChroot *safechroot.Chroot) error {
func writeGrub2ConfigFile(grub2Config string, imageChroot safechroot.ChrootInterface) error {
logger.Log.Debugf("Writing grub.cfg file")
grub2ConfigFilePath := getGrub2ConfigFilePath(imageChroot)
@ -730,7 +730,7 @@ func writeGrub2ConfigFile(grub2Config string, imageChroot *safechroot.Chroot) er
return nil
}
func getGrub2ConfigFilePath(imageChroot *safechroot.Chroot) string {
func getGrub2ConfigFilePath(imageChroot safechroot.ChrootInterface) string {
return filepath.Join(imageChroot.RootDir(), installutils.GrubCfgFile)
}

Просмотреть файл

@ -4,13 +4,19 @@
package osmodifierlib
import (
"fmt"
"strings"
"github.com/microsoft/azurelinux/toolkit/tools/imagecustomizerapi"
"github.com/microsoft/azurelinux/toolkit/tools/internal/logger"
"github.com/microsoft/azurelinux/toolkit/tools/internal/safechroot"
"github.com/microsoft/azurelinux/toolkit/tools/osmodifierapi"
"github.com/microsoft/azurelinux/toolkit/tools/pkg/imagecustomizerlib"
)
func doModifications(baseConfigPath string, osConfig *imagecustomizerapi.OS) error {
func doModifications(baseConfigPath string, osConfig *osmodifierapi.OS) error {
var dummyChroot safechroot.ChrootInterface = &safechroot.DummyChroot{}
err := imagecustomizerlib.AddOrUpdateUsers(osConfig.Users, baseConfigPath, dummyChroot)
if err != nil {
return err
@ -21,5 +27,98 @@ func doModifications(baseConfigPath string, osConfig *imagecustomizerapi.OS) err
return err
}
if osConfig.Overlays != nil {
bootCustomizer, err := imagecustomizerlib.NewBootCustomizer(dummyChroot)
if err != nil {
return err
}
err = updateGrubConfigForOverlay(*osConfig.Overlays, bootCustomizer)
if err != nil {
return err
}
err = bootCustomizer.WriteToFile(dummyChroot)
if err != nil {
return err
}
}
if osConfig.SELinux.Mode != "" {
bootCustomizer, err := imagecustomizerlib.NewBootCustomizer(dummyChroot)
if err != nil {
return err
}
err = handleSELinux(osConfig.SELinux.Mode, bootCustomizer, dummyChroot)
if err != nil {
return err
}
err = bootCustomizer.WriteToFile(dummyChroot)
if err != nil {
return err
}
}
return nil
}
func updateGrubConfigForOverlay(overlays []osmodifierapi.Overlay, bootCustomizer *imagecustomizerlib.BootCustomizer) error {
var err error
var overlayConfigs []string
// Iterate over each Overlay configuration
for _, overlay := range overlays {
// Construct the argument for each Overlay
overlayConfig := fmt.Sprintf(
"%s,%s,%s,%s",
overlay.LowerDir, overlay.UpperDir, overlay.WorkDir, overlay.Partition.Id,
)
overlayConfigs = append(overlayConfigs, overlayConfig)
}
// Concatenate all overlay configurations with spaces
concatenatedOverlays := strings.Join(overlayConfigs, " ")
// Construct the final cmdline argument
newArgs := []string{
fmt.Sprintf("rd.overlayfs=%s", concatenatedOverlays),
}
err = bootCustomizer.UpdateKernelCommandLineArgs("GRUB_CMDLINE_LINUX", []string{"rd.overlayfs"},
newArgs)
if err != nil {
return err
}
return nil
}
func handleSELinux(selinuxMode imagecustomizerapi.SELinuxMode, bootCustomizer *imagecustomizerlib.BootCustomizer, dummyChroot safechroot.ChrootInterface) error {
var err error
currentSELinuxMode, err := bootCustomizer.GetSELinuxMode(dummyChroot)
if err != nil {
return fmt.Errorf("failed to get current SELinux mode:\n%w", err)
}
if selinuxMode == imagecustomizerapi.SELinuxModeDefault || selinuxMode == currentSELinuxMode {
// Don't need to change the configured SELinux mode.
return nil
}
logger.Log.Infof("Configuring SELinux mode")
err = bootCustomizer.UpdateSELinuxCommandLine(selinuxMode)
if err != nil {
return err
}
err = imagecustomizerlib.UpdateSELinuxModeInConfigFile(selinuxMode, dummyChroot)
if err != nil {
return err
}
// No need to set SELinux labels here as in trident there is reset labels at the end
return nil
}

Просмотреть файл

@ -0,0 +1,87 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package osmodifierlib
import (
"fmt"
"github.com/microsoft/azurelinux/toolkit/tools/internal/logger"
"github.com/microsoft/azurelinux/toolkit/tools/internal/safechroot"
"github.com/microsoft/azurelinux/toolkit/tools/internal/sliceutils"
"github.com/microsoft/azurelinux/toolkit/tools/pkg/imagecustomizerlib"
)
var grubArgs = []string{
"rd.overlayfs",
"roothash",
"rd.systemd.verity",
"systemd.verity_root_data",
"systemd.verity_root_hash",
"systemd.verity_root_options",
"selinux",
"enforcing",
}
func modifyDefaultGrub() error {
var dummyChroot safechroot.ChrootInterface = &safechroot.DummyChroot{}
// Get verity, selinux, overlayfs, and root device values from /boot/grub2/grub.cfg
values, err := extractValuesFromGrubConfig(dummyChroot)
if err != nil {
return fmt.Errorf("error getting verity, selinux and overlayfs values from grub.cfg:\n%w", err)
}
bootCustomizer, err := imagecustomizerlib.NewBootCustomizer(dummyChroot)
if err != nil {
return err
}
// Stamp root device value to /etc/default/grub
err = bootCustomizer.PrepareForVerity()
if err != nil {
return fmt.Errorf("failed to prepare grub config files for verity:\n%w", err)
}
// Stamp verity, selinux and overlayfs values to /etc/default/grub
err = bootCustomizer.UpdateKernelCommandLineArgs("GRUB_CMDLINE_LINUX", grubArgs, values)
if err != nil {
return err
}
err = bootCustomizer.WriteToFile(dummyChroot)
if err != nil {
return fmt.Errorf("error writing to default grub:\n%w", err)
} else {
logger.Log.Info("Successfully updated default grub")
}
return nil
}
func extractValuesFromGrubConfig(imageChroot safechroot.ChrootInterface) ([]string, error) {
grubCfgContent, err := imagecustomizerlib.ReadGrub2ConfigFile(imageChroot)
if err != nil {
return nil, err
}
line, err := imagecustomizerlib.FindLinuxLine(grubCfgContent)
if err != nil {
return nil, err
}
argTokens, err := imagecustomizerlib.ParseCommandLineArgs(line.Tokens)
if err != nil {
return nil, err
}
var values []string
for _, arg := range argTokens {
if sliceutils.ContainsValue(grubArgs, arg.Name) {
if arg.Value != "" {
values = append(values, arg.Name+"="+arg.Value)
}
}
}
return values, nil
}

Просмотреть файл

@ -8,12 +8,13 @@ import (
"path/filepath"
"github.com/microsoft/azurelinux/toolkit/tools/imagecustomizerapi"
"github.com/microsoft/azurelinux/toolkit/tools/osmodifierapi"
)
func ModifyOSWithConfigFile(configFile string) error {
var err error
var osConfig imagecustomizerapi.OS
var osConfig osmodifierapi.OS
err = imagecustomizerapi.UnmarshalYamlFile(configFile, &osConfig)
if err != nil {
return err
@ -34,7 +35,7 @@ func ModifyOSWithConfigFile(configFile string) error {
return nil
}
func ModifyOS(baseConfigPath string, osConfig *imagecustomizerapi.OS) error {
func ModifyOS(baseConfigPath string, osConfig *osmodifierapi.OS) error {
err := doModifications(baseConfigPath, osConfig)
if err != nil {
return err
@ -42,3 +43,12 @@ func ModifyOS(baseConfigPath string, osConfig *imagecustomizerapi.OS) error {
return nil
}
func ModifyDefaultGrub() error {
err := modifyDefaultGrub()
if err != nil {
return err
}
return nil
}