From 4e80c1bc822e8cbafefc1a6933b65803cafd8291 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Thu, 26 Aug 2021 16:20:47 +0200 Subject: [PATCH] distro/rhel85: add simplified edge installer This adds a new installer called the "Simplified Installer" for Edge. In contrast to the existing insaller, which is based on Anaconda, this new installer based on the CoreOS installer project[1], a small rust based binary that is executed in the initramfs and will flash a raw image to a specified installation device. For this a new blueprint option is introduced. The raw image is created from an existing OSTree commit and embedded into the resulting bootable iso. When booting the iso the installation will automatically start witout any interaction from the user. NB: As with the existing edge installer, support is currently limited to x86. The new installer also does not support non-uefi boot. [1] https://github.com/coreos/coreos-installer Co-Developed-by: Achilleas Koutsou Co-Developed-by: Antonio Murdaca --- .../rhel8.5-edge-simplified-installer.md | 12 + internal/blueprint/customizations.go | 29 +- internal/distro/rhel85/distro.go | 35 ++- internal/distro/rhel85/distro_test.go | 15 +- internal/distro/rhel85/package_sets.go | 76 +++++ internal/distro/rhel85/partition_tables.go | 54 ++++ internal/distro/rhel85/pipelines.go | 264 ++++++++++++++++++ internal/distro/rhel85/stage_options.go | 23 ++ internal/store/json.go | 44 +-- 9 files changed, 512 insertions(+), 40 deletions(-) create mode 100644 docs/news/unreleased/rhel8.5-edge-simplified-installer.md diff --git a/docs/news/unreleased/rhel8.5-edge-simplified-installer.md b/docs/news/unreleased/rhel8.5-edge-simplified-installer.md new file mode 100644 index 000000000..560c77a0e --- /dev/null +++ b/docs/news/unreleased/rhel8.5-edge-simplified-installer.md @@ -0,0 +1,12 @@ +# Add a new Simplified Installer for RHEL for Edge 8.5 + +OSBuild Composer can now build the RHEL 8.5 for Edge Simplified Installer. +This installer is optimized for unattended installation to a device, which +can be specified via a new blueprint option, `installation_device`. As for +the existing RHEL for Edge installer, an existing OSTree commit needs to +be provided. A raw image will be created with that commit deployed in it +and the installer will flash this raw image to the specified installation +device. +The following image new types are supported: edge-simplified-installer. + +Relevant PR: https://github.com/osbuild/osbuild-composer/pull/1654 \ No newline at end of file diff --git a/internal/blueprint/customizations.go b/internal/blueprint/customizations.go index 371aba8f2..27828edb1 100644 --- a/internal/blueprint/customizations.go +++ b/internal/blueprint/customizations.go @@ -6,16 +6,17 @@ import ( ) type Customizations struct { - Hostname *string `json:"hostname,omitempty" toml:"hostname,omitempty"` - Kernel *KernelCustomization `json:"kernel,omitempty" toml:"kernel,omitempty"` - SSHKey []SSHKeyCustomization `json:"sshkey,omitempty" toml:"sshkey,omitempty"` - User []UserCustomization `json:"user,omitempty" toml:"user,omitempty"` - Group []GroupCustomization `json:"group,omitempty" toml:"group,omitempty"` - Timezone *TimezoneCustomization `json:"timezone,omitempty" toml:"timezone,omitempty"` - Locale *LocaleCustomization `json:"locale,omitempty" toml:"locale,omitempty"` - Firewall *FirewallCustomization `json:"firewall,omitempty" toml:"firewall,omitempty"` - Services *ServicesCustomization `json:"services,omitempty" toml:"services,omitempty"` - Filesystem []FilesystemCustomization `json:"filesystem,omitempty" toml:"filesystem,omitempty"` + Hostname *string `json:"hostname,omitempty" toml:"hostname,omitempty"` + Kernel *KernelCustomization `json:"kernel,omitempty" toml:"kernel,omitempty"` + SSHKey []SSHKeyCustomization `json:"sshkey,omitempty" toml:"sshkey,omitempty"` + User []UserCustomization `json:"user,omitempty" toml:"user,omitempty"` + Group []GroupCustomization `json:"group,omitempty" toml:"group,omitempty"` + Timezone *TimezoneCustomization `json:"timezone,omitempty" toml:"timezone,omitempty"` + Locale *LocaleCustomization `json:"locale,omitempty" toml:"locale,omitempty"` + Firewall *FirewallCustomization `json:"firewall,omitempty" toml:"firewall,omitempty"` + Services *ServicesCustomization `json:"services,omitempty" toml:"services,omitempty"` + Filesystem []FilesystemCustomization `json:"filesystem,omitempty" toml:"filesystem,omitempty"` + InstallationDevice string `json:"installation_device,omitempty" toml:"installation_device,omitempty"` } type KernelCustomization struct { @@ -268,3 +269,11 @@ func (c *Customizations) GetFilesystemsMinSize() uint64 { } return uint64(agg) } + +func (c *Customizations) GetInstallationDevice() string { + defaultDevice := "/dev/sda" + if c == nil || c.InstallationDevice == "" { + return defaultDevice + } + return c.InstallationDevice +} diff --git a/internal/distro/rhel85/distro.go b/internal/distro/rhel85/distro.go index a0d6468ab..257cfecf7 100644 --- a/internal/distro/rhel85/distro.go +++ b/internal/distro/rhel85/distro.go @@ -445,7 +445,12 @@ func (t *imageType) checkOptions(customizations *blueprint.Customizations, optio if options.OSTree.Parent == "" { return fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.name) } - if customizations != nil { + + if t.name == "edge-simplified-installer" { + if err := customizations.CheckAllowed("InstallationDevice"); err != nil { + return fmt.Errorf("boot ISO image type %q contains unsupported blueprint customizations: %v", t.name, err) + } + } else if customizations != nil { return fmt.Errorf("boot ISO image type %q does not support blueprint customizations", t.name) } } @@ -606,6 +611,32 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { exports: []string{"bootiso"}, } + edgeSimplifiedInstallerImgType := imageType{ + name: "edge-simplified-installer", + nameAliases: []string{"rhel-edge-simplified-installer"}, + filename: "simplified-installer.iso", + mimeType: "application/x-iso9660-image", + packageSets: map[string]rpmmd.PackageSet{ + // TODO: non-arch-specific package set handling for installers + // This image type requires build packages for installers and + // ostree/edge. For now we only have x86-64 installer build + // package sets defined. When we add installer build package sets + // for other architectures, this will need to be moved to the + // architecture and the merging will happen in the PackageSets() + // method like the other sets. + buildPkgsKey: x8664InstallerBuildPackageSet().Append(edgeBuildPackageSet()), + installerPkgsKey: edgeSimplifiedInstallerPackageSet(), + }, + enabledServices: edgeServices, + defaultSize: 10 * GigaByte, + rpmOstree: true, + bootable: true, + bootISO: true, + pipelines: edgeSimplifiedInstallerPipelines, + exports: []string{"bootiso"}, + basePartitionTables: edgeBasePartitionTables, + } + qcow2ImgType := imageType{ name: "qcow2", filename: "disk.qcow2", @@ -807,7 +838,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { exports: []string{"bootiso"}, } - x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, ec2ImgTypeX86_64, ec2HaImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType) + x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, ec2ImgTypeX86_64, ec2HaImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeSimplifiedInstallerImgType) aarch64.addImageTypes(qcow2ImgType, openstackImgType, amiImgTypeAarch64, ec2ImgTypeAarch64, tarImgType, edgeCommitImgType, edgeOCIImgType) ppc64le.addImageTypes(qcow2ImgType, tarImgType) s390x.addImageTypes(qcow2ImgType, tarImgType) diff --git a/internal/distro/rhel85/distro_test.go b/internal/distro/rhel85/distro_test.go index eaa00b3df..0350eb7d3 100644 --- a/internal/distro/rhel85/distro_test.go +++ b/internal/distro/rhel85/distro_test.go @@ -417,8 +417,8 @@ func TestDistro_ManifestError(t *testing.T) { _, err := imgType.Manifest(bp.Customizations, imgOpts, nil, nil, 0) if imgTypeName == "edge-commit" || imgTypeName == "edge-container" { assert.EqualError(t, err, "kernel boot parameter customizations are not supported for ostree types") - } else if imgTypeName == "edge-installer" { - assert.EqualError(t, err, "boot ISO image type \"edge-installer\" requires specifying a URL from which to retrieve the OSTree commit") + } else if imgTypeName == "edge-installer" || imgTypeName == "edge-simplified-installer" { + assert.EqualError(t, err, fmt.Sprintf("boot ISO image type \"%s\" requires specifying a URL from which to retrieve the OSTree commit", imgTypeName)) } else { assert.NoError(t, err) } @@ -445,6 +445,7 @@ func TestArchitecture_ListImageTypes(t *testing.T) { "edge-commit", "edge-container", "edge-installer", + "edge-simplified-installer", "tar", "image-installer", }, @@ -574,7 +575,7 @@ func TestDistro_CustomFileSystemManifestError(t *testing.T) { _, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, 0) if imgTypeName == "edge-commit" || imgTypeName == "edge-container" { assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types") - } else if imgTypeName == "edge-installer" { + } else if imgTypeName == "edge-installer" || imgTypeName == "edge-simplified-installer" { continue } else { assert.EqualError(t, err, "The following custom mountpoints are not supported [\"/boot\"]") @@ -602,7 +603,7 @@ func TestDistro_TestRootMountPoint(t *testing.T) { _, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, 0) if imgTypeName == "edge-commit" || imgTypeName == "edge-container" { assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types") - } else if imgTypeName == "edge-installer" { + } else if imgTypeName == "edge-installer" || imgTypeName == "edge-simplified-installer" { continue } else { assert.NoError(t, err) @@ -630,7 +631,7 @@ func TestDistro_CustomFileSystemSubDirectories(t *testing.T) { _, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, 0) if imgTypeName == "edge-commit" || imgTypeName == "edge-container" { assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types") - } else if imgTypeName == "edge-installer" { + } else if imgTypeName == "edge-installer" || imgTypeName == "edge-simplified-installer" { continue } else { assert.NoError(t, err) @@ -658,7 +659,7 @@ func TestDistro_CustomFileSystemPatternMatching(t *testing.T) { _, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, 0) if imgTypeName == "edge-commit" || imgTypeName == "edge-container" { assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types") - } else if imgTypeName == "edge-installer" { + } else if imgTypeName == "edge-installer" || imgTypeName == "edge-simplified-installer" { continue } else { assert.EqualError(t, err, "The following custom mountpoints are not supported [\"/variable\"]") @@ -686,7 +687,7 @@ func TestDistro_CustomUsrPartitionNotLargeEnough(t *testing.T) { _, err := imgType.Manifest(bp.Customizations, distro.ImageOptions{}, nil, nil, 0) if imgTypeName == "edge-commit" || imgTypeName == "edge-container" { assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types") - } else if imgTypeName == "edge-installer" { + } else if imgTypeName == "edge-installer" || imgTypeName == "edge-simplified-installer" { continue } else { assert.NoError(t, err) diff --git a/internal/distro/rhel85/package_sets.go b/internal/distro/rhel85/package_sets.go index 5b5564ab2..566a02f89 100644 --- a/internal/distro/rhel85/package_sets.go +++ b/internal/distro/rhel85/package_sets.go @@ -357,6 +357,82 @@ func installerPackageSet() rpmmd.PackageSet { } } +func edgeSimplifiedInstallerPackageSet() rpmmd.PackageSet { + return rpmmd.PackageSet{ + Include: []string{ + "cloud-utils-growpart", + "dracut-live", + "xfsprogs", + "bsdtar", + "coreos-installer", + "coreos-installer-bootinfra", + "dracut-config-generic", + "dracut-network", + "kernel", + "binutils", + "basesystem", + "sudo", + "systemd", + "coreutils", + "util-linux", + "curl", + "e2fsprogs", + "dosfstools", + "attr", + "xz", + "gzip", + "iptables", + "dnsmasq", + "traceroute", + "hostname", + "iproute", + "iputils", + "openssh-clients", + "procps-ng", + "rootfiles", + "passwd", + "policycoreutils", + "policycoreutils-python-utils", + "selinux-policy-targeted", + "setools-console", + "less", + "tar", + "ima-evm-utils", + "shim-x64", + "ostree", + "microcode_ctl", + "iwl1000-firmware", + "iwl100-firmware", + "iwl105-firmware", + "iwl135-firmware", + "iwl2000-firmware", + "iwl2030-firmware", + "iwl3160-firmware", + "iwl5000-firmware", + "iwl5150-firmware", + "iwl6000-firmware", + "iwl6050-firmware", + "iwl7260-firmware", + + // for the dracut modules + "keyutils", + "rng-tools", + "lvm2", + "device-mapper-multipath", + "lldpad", + "fcoe-utils", + "iscsi-initiator-utils", + "rpcbind", + "biosdevname", + "nfs-utils", + "plymouth", + "prefixdevname", + "anaconda-dracut", + }, + Exclude: nil, + } +} + func edgeInstallerPackageSet() rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{ diff --git a/internal/distro/rhel85/partition_tables.go b/internal/distro/rhel85/partition_tables.go index 9b2f3d4e4..14bfe9cf9 100644 --- a/internal/distro/rhel85/partition_tables.go +++ b/internal/distro/rhel85/partition_tables.go @@ -181,3 +181,57 @@ var ec2BasePartitionTables = distro.BasePartitionTableMap{ }, }, } + +var edgeBasePartitionTables = distro.BasePartitionTableMap{ + distro.X86_64ArchName: disk.PartitionTable{ + UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0", + Type: "gpt", + Partitions: []disk.Partition{ + { + Size: 2048, // 2MB + Bootable: true, + Type: disk.BIOSBootPartitionGUID, + UUID: disk.BIOSBootPartitionUUID, + }, + { + Size: 260096, // 127 MB + Type: disk.EFISystemPartitionGUID, + UUID: disk.EFISystemPartitionUUID, + Filesystem: &disk.Filesystem{ + Type: "vfat", + UUID: disk.EFIFilesystemUUID, + Mountpoint: "/boot/efi", + Label: "EFI-SYSTEM", + FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt", + FSTabFreq: 0, + FSTabPassNo: 2, + }, + }, + { + Size: 786432, // 384 MB + Type: disk.FilesystemDataGUID, + UUID: disk.FilesystemDataUUID, + Filesystem: &disk.Filesystem{ + Type: "xfs", + Mountpoint: "/boot", + Label: "boot", + FSTabOptions: "defaults", + FSTabFreq: 1, + FSTabPassNo: 1, + }, + }, + { + Type: disk.FilesystemDataGUID, + UUID: disk.RootPartitionUUID, + Filesystem: &disk.Filesystem{ + Type: "xfs", + Label: "root", + Mountpoint: "/", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + }, + }, +} diff --git a/internal/distro/rhel85/pipelines.go b/internal/distro/rhel85/pipelines.go index 70bfee566..30f19d27c 100644 --- a/internal/distro/rhel85/pipelines.go +++ b/internal/distro/rhel85/pipelines.go @@ -844,6 +844,270 @@ func ostreePayloadStages(options distro.ImageOptions, ostreeRepoPath string) []* return stages } +func edgeSimplifiedInstallerPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { + pipelines := make([]osbuild.Pipeline, 0) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + installerPackages := packageSetSpecs[installerPkgsKey] + kernelVer := kernelVerStr(installerPackages, "kernel", t.Arch().Name()) + imgName := "disk.img" + imgNameXz := imgName + ".xz" + ostreeRepoPath := "/ostree/repo" + installDevice := customizations.GetInstallationDevice() + + partitionTable, err := t.getPartitionTable(nil, options, rng) + if err != nil { + return nil, err + } + + // prepare ostree deployment tree + treePipeline := ostreeDeployPipeline(t, &partitionTable, ostreeRepoPath, customizations.GetKernel(), kernelVer, rng, options) + pipelines = append(pipelines, *treePipeline) + + // make raw image from tree + imagePipeline := liveImagePipeline(treePipeline.Name, imgName, &partitionTable, t.arch, kernelVer) + pipelines = append(pipelines, *imagePipeline) + + // compress image + xzPipeline := xzArchivePipeline(imagePipeline.Name, imgName, imgNameXz) + pipelines = append(pipelines, *xzPipeline) + + // create boot ISO with raw image + installerTreePipeline := simplifiedInstallerTreePipeline(repos, installerPackages, kernelVer, t.Arch().Name()) + efibootTreePipeline := simplifiedInstallerEFIBootTreePipeline(installDevice, kernelVer, t.Arch().Name()) + bootISOTreePipeline := simplifiedInstallerBootISOTreePipeline(xzPipeline.Name, kernelVer) + + pipelines = append(pipelines, *installerTreePipeline, *efibootTreePipeline, *bootISOTreePipeline) + pipelines = append(pipelines, *bootISOPipeline(t.Filename(), t.Arch().Name(), false)) + + return pipelines, nil +} + +func simplifiedInstallerBootISOTreePipeline(archivePipelineName, kver string) *osbuild.Pipeline { + p := new(osbuild.Pipeline) + p.Name = "bootiso-tree" + p.Build = "name:build" + + p.AddStage(osbuild.NewCopyStageSimple( + &osbuild.CopyStageOptions{ + Paths: []osbuild.CopyStagePath{ + { + From: "input://file/disk.img.xz", + To: "tree:///disk.img.xz", + }, + }, + }, + osbuild.NewFilesInputs(osbuild.NewFilesInputReferencesPipeline(archivePipelineName, "disk.img.xz")), + )) + + p.AddStage(osbuild.NewMkdirStage( + &osbuild.MkdirStageOptions{ + Paths: []osbuild.Path{ + { + Path: "images", + }, + { + Path: "images/pxeboot", + }, + }, + }, + )) + + var sectorSize uint64 = 512 + pt := disk.PartitionTable{ + Size: 20971520, + Partitions: []disk.Partition{ + { + Start: 0, + Size: 20971520 / sectorSize, + Filesystem: &disk.Filesystem{ + Type: "vfat", + Mountpoint: "/", + }, + }, + }, + } + + filename := "images/efiboot.img" + loopback := osbuild.NewLoopbackDevice(&osbuild.LoopbackDeviceOptions{Filename: filename}) + p.AddStage(osbuild.NewTruncateStage(&osbuild.TruncateStageOptions{Filename: filename, Size: fmt.Sprintf("%d", pt.Size)})) + + for _, stage := range mkfsStages(&pt, loopback) { + p.AddStage(stage) + } + + inputName := "root-tree" + copyInputs := copyPipelineTreeInputs(inputName, "efiboot-tree") + copyOptions, copyDevices, copyMounts := copyFSTreeOptions(inputName, "efiboot-tree", &pt, loopback) + p.AddStage(osbuild.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts)) + + inputName = "coi" + copyInputs = copyPipelineTreeInputs(inputName, "coi-tree") + p.AddStage(osbuild.NewCopyStageSimple( + &osbuild.CopyStageOptions{ + Paths: []osbuild.CopyStagePath{ + { + From: fmt.Sprintf("input://%s/boot/vmlinuz-%s", inputName, kver), + To: "tree:///images/pxeboot/vmlinuz", + }, + { + From: fmt.Sprintf("input://%s/boot/initramfs-%s.img", inputName, kver), + To: "tree:///images/pxeboot/initrd.img", + }, + }, + }, + copyInputs, + )) + + inputName = "efi-tree" + copyInputs = copyPipelineTreeInputs(inputName, "efiboot-tree") + p.AddStage(osbuild.NewCopyStageSimple( + &osbuild.CopyStageOptions{ + Paths: []osbuild.CopyStagePath{ + { + From: fmt.Sprintf("input://%s/EFI", inputName), + To: "tree:///", + }, + }, + }, + copyInputs, + )) + + return p +} + +func simplifiedInstallerEFIBootTreePipeline(installDevice, kernelVer, arch string) *osbuild.Pipeline { + p := new(osbuild.Pipeline) + p.Name = "efiboot-tree" + p.Build = "name:build" + + isolabel := fmt.Sprintf("RHEL-8-5-0-BaseOS-%s", arch) + + var architectures []string + + if arch == "x86_64" { + architectures = []string{"IA32", "X64"} + } else if arch == "aarch64" { + architectures = []string{"AA64"} + } else { + panic("unsupported architecture") + } + + p.AddStage(osbuild.NewGrubISOStage( + &osbuild.GrubISOStageOptions{ + Product: osbuild.Product{ + Name: "Red Hat Enterprise Linux", + Version: osVersion, + }, + ISOLabel: isolabel, + Kernel: osbuild.ISOKernel{ + Dir: "/images/pxeboot", + Opts: []string{"rd.neednet=1", + "console=tty0", + "console=ttyS0", + "edge.liveiso=" + isolabel, + "coreos.inst.install_dev=" + installDevice, + "coreos.inst.image_file=/run/media/iso/disk.img.xz", + "coreos.inst.insecure"}, + }, + Architectures: architectures, + Vendor: "redhat", + }, + )) + + return p +} + +func simplifiedInstallerTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, kernelVer string, arch string) *osbuild.Pipeline { + p := new(osbuild.Pipeline) + p.Name = "coi-tree" + p.Build = "name:build" + p.AddStage(osbuild.NewRPMStage(rpmStageOptions(repos), rpmStageInputs(packages))) + p.AddStage(osbuild.NewBuildstampStage(buildStampStageOptions(arch))) + p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: "en_US.UTF-8"})) + p.AddStage(osbuild.NewSystemdStage(systemdStageOptions([]string{"coreos-installer"}, nil, nil, ""))) + p.AddStage(osbuild.NewDracutStage(dracutStageOptions(kernelVer, []string{ + "rdcore", + }))) + + return p +} + +func ostreeDeployPipeline( + t *imageType, + pt *disk.PartitionTable, + repoPath string, + kernel *blueprint.KernelCustomization, + kernelVer string, + rng *rand.Rand, + options distro.ImageOptions, +) *osbuild.Pipeline { + + p := new(osbuild.Pipeline) + p.Name = "image-tree" + p.Build = "name:build" + osname := "redhat" + + p.AddStage(osbuild.OSTreeInitFsStage()) + p.AddStage(osbuild.NewOSTreePullStage( + &osbuild.OSTreePullStageOptions{Repo: repoPath}, + ostreePullStageInputs("org.osbuild.source", options.OSTree.Parent, options.OSTree.Ref), + )) + p.AddStage(osbuild.NewOSTreeOsInitStage( + &osbuild.OSTreeOsInitStageOptions{ + OSName: osname, + }, + )) + p.AddStage(osbuild.NewOSTreeConfigStage(ostreeConfigStageOptions(repoPath, true))) + p.AddStage(osbuild.NewMkdirStage(efiMkdirStageOptions())) + p.AddStage(osbuild.NewOSTreeDeployStage( + &osbuild.OSTreeDeployStageOptions{ + OsName: osname, + Ref: options.OSTree.Ref, + Mounts: []string{"/boot", "/boot/efi"}, + Rootfs: osbuild.Rootfs{ + Label: "root", + }, + KernelOpts: []string{ + "console=tty0", + "console=ttyS0", + "systemd.log_target=console", + "systemd.journald.forward_to_console=1", + }, + }, + )) + p.AddStage(osbuild.NewOSTreeFillvarStage( + &osbuild.OSTreeFillvarStageOptions{ + Deployment: osbuild.OSTreeDeployment{ + OSName: osname, + Ref: options.OSTree.Ref, + }, + }, + )) + + fstabOptions := pt.FSTabStageOptionsV2() + fstabOptions.OSTree = &osbuild.OSTreeFstab{ + Deployment: osbuild.OSTreeDeployment{ + OSName: osname, + Ref: options.OSTree.Ref, + }, + } + p.AddStage(osbuild2.NewFSTabStage(fstabOptions)) + + // TODO: Add users? + + p.AddStage(bootloaderConfigStage(t, *pt, kernel, kernelVer, true, true)) + + p.AddStage(osbuild.NewOSTreeSelinuxStage( + &osbuild.OSTreeSelinuxStageOptions{ + Deployment: osbuild.OSTreeDeployment{ + OSName: osname, + Ref: options.OSTree.Ref, + }, + }, + )) + return p +} + func anacondaTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, kernelVer string, arch string, payloadStages []*osbuild.Stage) *osbuild.Pipeline { p := new(osbuild.Pipeline) p.Name = "anaconda-tree" diff --git a/internal/distro/rhel85/stage_options.go b/internal/distro/rhel85/stage_options.go index 4a678120c..6f00222ad 100644 --- a/internal/distro/rhel85/stage_options.go +++ b/internal/distro/rhel85/stage_options.go @@ -2,6 +2,7 @@ package rhel85 import ( "fmt" + "os" "path/filepath" "sort" @@ -550,3 +551,25 @@ func chmodStageOptions(path, mode string, recursive bool) *osbuild.ChmodStageOpt }, } } + +func ostreeConfigStageOptions(repo string, readOnly bool) *osbuild.OSTreeConfigStageOptions { + return &osbuild.OSTreeConfigStageOptions{ + Repo: repo, + Config: &osbuild.OSTreeConfig{ + Sysroot: &osbuild.SysrootOptions{ + ReadOnly: common.BoolToPtr(readOnly), + }, + }, + } +} + +func efiMkdirStageOptions() *osbuild.MkdirStageOptions { + return &osbuild.MkdirStageOptions{ + Paths: []osbuild.Path{ + { + Path: "/boot/efi", + Mode: os.FileMode(0700), + }, + }, + } +} diff --git a/internal/store/json.go b/internal/store/json.go index fb97bf213..c36d7a44e 100644 --- a/internal/store/json.go +++ b/internal/store/json.go @@ -340,27 +340,29 @@ func (store *Store) toStoreV0() *storeV0 { } var imageTypeCompatMapping = map[string]string{ - "vhd": "Azure", - "ami": "AWS", - "liveiso": "LiveISO", - "openstack": "OpenStack", - "qcow2": "qcow2", - "vmdk": "VMWare", - "ext4-filesystem": "Raw-filesystem", - "partitioned-disk": "Partitioned-disk", - "tar": "Tar", - "fedora-iot-commit": "fedora-iot-commit", - "rhel-edge-commit": "rhel-edge-commit", - "rhel-edge-container": "rhel-edge-container", - "rhel-edge-installer": "rhel-edge-installer", - "edge-commit": "edge-commit", - "edge-container": "edge-container", - "edge-installer": "edge-installer", - "image-installer": "image-installer", - "test_type": "test_type", // used only in json_test.go - "test_type_invalid": "test_type_invalid", // used only in json_test.go - "ec2": "ec2", - "ec2-ha": "ec2-ha", + "vhd": "Azure", + "ami": "AWS", + "liveiso": "LiveISO", + "openstack": "OpenStack", + "qcow2": "qcow2", + "vmdk": "VMWare", + "ext4-filesystem": "Raw-filesystem", + "partitioned-disk": "Partitioned-disk", + "tar": "Tar", + "fedora-iot-commit": "fedora-iot-commit", + "rhel-edge-commit": "rhel-edge-commit", + "rhel-edge-container": "rhel-edge-container", + "rhel-edge-installer": "rhel-edge-installer", + "rhel-edge-simplified-installer": "rhel-edge-simplified-installer", + "edge-commit": "edge-commit", + "edge-container": "edge-container", + "edge-installer": "edge-installer", + "edge-simplified-installer": "edge-simplified-installer", + "image-installer": "image-installer", + "test_type": "test_type", // used only in json_test.go + "test_type_invalid": "test_type_invalid", // used only in json_test.go + "ec2": "ec2", + "ec2-ha": "ec2-ha", } func imageTypeToCompatString(imgType distro.ImageType) string {