From b866489bb5b3706614f6748d39477f9c36f0fb9e Mon Sep 17 00:00:00 2001 From: Nick Carboni Date: Wed, 9 Oct 2024 17:00:59 -0400 Subject: [PATCH 1/2] Install to the existing root when CoreosImage is set This indicates the container image that should be installed and booted for the installed host. It also indicates that we should install to the existing root filesystem, in a new stateroot, rather than expecting a device path. https://issues.redhat.com/browse/MGMT-19100 --- src/config/config.go | 2 + src/config/config_test.go | 6 +++ src/installer/installer.go | 31 ++++++++---- src/installer/installer_test.go | 85 ++++++++++++++++++++++----------- src/ops/mock_ops.go | 14 ++++++ src/ops/ops.go | 66 +++++++++++++++++++++++++ src/ops/ops_test.go | 81 +++++++++++++++++++++++++++++++ 7 files changed, 246 insertions(+), 39 deletions(-) diff --git a/src/config/config.go b/src/config/config.go index 6c40d73b37..5984d45ee5 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -40,6 +40,7 @@ type Config struct { SkipInstallationDiskCleanup bool EnableSkipMcoReboot bool NotifyNumReboots bool + CoreosImage string } func printHelpAndExit(err error) { @@ -79,6 +80,7 @@ func (c *Config) ProcessArgs(args []string) { flagSet.BoolVar(&c.SkipInstallationDiskCleanup, "skip-installation-disk-cleanup", false, "Skip installation disk cleanup gives disk management to coreos-installer in case needed") flagSet.BoolVar(&c.EnableSkipMcoReboot, "enable-skip-mco-reboot", false, "indicate assisted installer to generate settings to match MCO requirements for skipping reboot after firstboot") flagSet.BoolVar(&c.NotifyNumReboots, "notify-num-reboots", false, "indicate number of reboots should be notified as event") + flagSet.StringVar(&c.CoreosImage, "coreos-image", "", "CoreOS image to install to the existing root") var installerArgs string flagSet.StringVar(&installerArgs, "installer-args", "", "JSON array of additional coreos-installer arguments") diff --git a/src/config/config_test.go b/src/config/config_test.go index f479a7e2e1..e5b4587149 100644 --- a/src/config/config_test.go +++ b/src/config/config_test.go @@ -66,6 +66,12 @@ var _ = Describe("ProcessArgs", func() { Expect(config.InfraEnvID).To(Equal("9f2a26d7-10a6-4be0-b1c2-e895ad3b04b8")) }) + It("should set coreos image when provided", func() { + config := &Config{} + arguments := []string{"--role", string(models.HostRoleBootstrap), "--infra-env-id", "9f2a26d7-10a6-4be0-b1c2-e895ad3b04b8", "--cluster-id", "0ae63135-5f7c-431e-9c72-0efaf2cb83b8", "--coreos-image", "example.com/coreos/os:latest"} + config.ProcessArgs(arguments) + Expect(config.CoreosImage).To(Equal("example.com/coreos/os:latest")) + }) }) var _ = Describe("SetInstallerArgs", func() { diff --git a/src/installer/installer.go b/src/installer/installer.go index c582085220..9a66049364 100644 --- a/src/installer/installer.go +++ b/src/installer/installer.go @@ -155,14 +155,17 @@ func (i *installer) InstallNode() error { } } - if i.EnableSkipMcoReboot { - i.skipMcoReboot(ignitionPath) - } + // we can't do any of this if we're installing to the existing root + if i.Config.CoreosImage == "" { + if i.EnableSkipMcoReboot { + i.skipMcoReboot(ignitionPath) + } - if err = i.ops.SetBootOrder(i.Device); err != nil { - i.log.WithError(err).Warnf("Failed to set boot order") - // Ignore the error for now so it doesn't fail the installation in case it fails - //return err + if err = i.ops.SetBootOrder(i.Device); err != nil { + i.log.WithError(err).Warnf("Failed to set boot order") + // Ignore the error for now so it doesn't fail the installation in case it fails + //return err + } } if isBootstrap { @@ -321,7 +324,7 @@ func convertToOverwriteKargs(args []string) []string { } func (i *installer) cleanupInstallDevice() { - if i.DryRunEnabled || i.Config.SkipInstallationDiskCleanup { + if i.DryRunEnabled || i.Config.SkipInstallationDiskCleanup || i.Config.CoreosImage != "" { i.log.Infof("skipping installation disk cleanup") } else { err := i.cleanupDevice.CleanupInstallDevice(i.Config.Device) @@ -365,7 +368,11 @@ func (i *installer) writeImageToDisk(ignitionPath string) error { interval := time.Second liveLogger := coreos_logger.NewCoreosInstallerLogWriter(i.log, i.inventoryClient, i.Config.InfraEnvID, i.Config.HostID) err := utils.Retry(3, interval, i.log, func() error { - return i.ops.WriteImageToDisk(liveLogger, ignitionPath, i.Device, i.Config.InstallerArgs) + if i.Config.CoreosImage == "" { + return i.ops.WriteImageToDisk(liveLogger, ignitionPath, i.Device, i.Config.InstallerArgs) + } else { + return i.ops.WriteImageToExistingRoot(liveLogger, ignitionPath) + } }) if err != nil { i.log.WithError(err).Error("Failed to write image to disk") @@ -1044,7 +1051,11 @@ func RunInstaller(installerConfig *config.Config, logger *logrus.Logger) error { ) // Try to format requested disks. May fail formatting some disks, this is not an error. - ai.FormatDisks() + if installerConfig.CoreosImage == "" { + ai.FormatDisks() + } else { + logger.Info("not attempting disk format when installing to boot device") + } if err = ai.InstallNode(); err != nil { ai.UpdateHostInstallProgress(models.HostStageFailed, err.Error()) diff --git a/src/installer/installer_test.go b/src/installer/installer_test.go index 2fac4a11f1..0f4361a9b4 100644 --- a/src/installer/installer_test.go +++ b/src/installer/installer_test.go @@ -114,7 +114,7 @@ var _ = Describe("installer HostRoleMaster role", func() { mockops.EXPECT().WriteImageToDisk(gomock.Any(), filepath.Join(InstallDir, "master-host-id.ign"), device, extra).Return(nil).Times(1) } - setBootOrderSuccess := func(extra interface{}) { + setBootOrderSuccess := func() { mockops.EXPECT().SetBootOrder(device).Return(nil).Times(1) } @@ -389,7 +389,7 @@ var _ = Describe("installer HostRoleMaster role", func() { downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) reportLogProgressSuccess() - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(true) ironicAgentDoesntExist() rebootSuccess() @@ -425,7 +425,7 @@ var _ = Describe("installer HostRoleMaster role", func() { downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) reportLogProgressSuccess() - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(true) ironicAgentDoesntExist() rebootSuccess() @@ -449,7 +449,7 @@ var _ = Describe("installer HostRoleMaster role", func() { //HostRoleMaster flow: downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() getEncapsulatedMcSuccess(nil) overwriteImageSuccess() ret := installerObj.InstallNode() @@ -480,7 +480,7 @@ var _ = Describe("installer HostRoleMaster role", func() { downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) reportLogProgressSuccess() - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(true) ironicAgentDoesntExist() rebootSuccess() @@ -513,7 +513,7 @@ var _ = Describe("installer HostRoleMaster role", func() { //HostRoleMaster flow: downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(true) reportLogProgressSuccess() ironicAgentDoesntExist() @@ -554,7 +554,7 @@ var _ = Describe("installer HostRoleMaster role", func() { downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) reportLogProgressSuccess() - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(true) ironicAgentDoesntExist() rebootSuccess() @@ -584,7 +584,7 @@ var _ = Describe("installer HostRoleMaster role", func() { //HostRoleMaster flow: downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() getEncapsulatedMcSuccess(nil) overwriteImageSuccess() ret := installerObj.InstallNode() @@ -615,7 +615,7 @@ var _ = Describe("installer HostRoleMaster role", func() { //HostRoleMaster flow: downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(true) reportLogProgressSuccess() ironicAgentDoesntExist() @@ -637,7 +637,7 @@ var _ = Describe("installer HostRoleMaster role", func() { downloadFileSuccess(bootstrapIgn) downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() extractSecretFromIgnitionSuccess() getEncapsulatedMcSuccess(nil) overwriteImageSuccess() @@ -661,7 +661,7 @@ var _ = Describe("installer HostRoleMaster role", func() { //HostRoleMaster flow: downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() getEncapsulatedMcSuccess(nil) overwriteImageSuccess() ret := installerObj.InstallNode() @@ -748,7 +748,7 @@ var _ = Describe("installer HostRoleMaster role", func() { //HostRoleMaster flow: downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(true) reportLogProgressSuccess() ironicAgentDoesntExist() @@ -847,18 +847,23 @@ var _ = Describe("installer HostRoleMaster role", func() { }) }) Context("Master role", func() { - installerArgs := []string{"-n", "--append-karg", "nameserver=8.8.8.8"} - conf := config.Config{Role: string(models.HostRoleMaster), - ClusterID: "cluster-id", - InfraEnvID: "infra-env-id", - HostID: "host-id", - Device: "/dev/vda", - URL: "https://assisted-service.com:80", - OpenshiftVersion: openShiftVersion, - InstallerArgs: installerArgs, - EnableSkipMcoReboot: withEnableSkipMcoReboot, - } + var ( + conf config.Config + installerArgs []string + ) + BeforeEach(func() { + installerArgs = []string{"-n", "--append-karg", "nameserver=8.8.8.8"} + conf = config.Config{Role: string(models.HostRoleMaster), + ClusterID: "cluster-id", + InfraEnvID: "infra-env-id", + HostID: "host-id", + Device: "/dev/vda", + URL: "https://assisted-service.com:80", + OpenshiftVersion: openShiftVersion, + InstallerArgs: installerArgs, + EnableSkipMcoReboot: withEnableSkipMcoReboot, + } installerObj = NewAssistedInstaller(l, conf, mockops, mockbmclient, k8sBuilder, mockIgnition, cleanupDevice) evaluateDiskSymlinkSuccess() @@ -873,7 +878,7 @@ var _ = Describe("installer HostRoleMaster role", func() { mkdirSuccess(InstallDir) downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(installerArgs) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(false) reportLogProgressSuccess() ironicAgentDoesntExist() @@ -884,6 +889,28 @@ var _ = Describe("installer HostRoleMaster role", func() { Expect(ret).Should(BeNil()) }) + It("installs to the existing root and does not skip reboot, clean install device, or set boot order when coreosImage is set", func() { + installerObj.Config.CoreosImage = "example.com/coreos/os:latest" + updateProgressSuccess([][]string{{string(models.HostStageStartingInstallation), conf.Role}, + {string(models.HostStageInstalling), conf.Role}, + {string(models.HostStageWritingImageToDisk)}, + {string(models.HostStageRebooting)}, + }) + cleanupDevice.EXPECT().CleanupInstallDevice(device).Times(0) + mkdirSuccess(InstallDir) + downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") + mockops.EXPECT().WriteImageToExistingRoot(gomock.Any(), filepath.Join(InstallDir, "master-host-id.ign")).Return(nil).Times(1) + mockops.EXPECT().SetBootOrder(device).Times(0) + uploadLogsSuccess(false) + reportLogProgressSuccess() + ironicAgentDoesntExist() + rebootSuccess() + mockops.EXPECT().GetEncapsulatedMC(gomock.Any()).Times(0) + mockops.EXPECT().OverwriteOsImage(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + ret := installerObj.InstallNode() + Expect(ret).Should(BeNil()) + }) + It("HostRoleMaster role happy flow with skipping disk cleanup", func() { installerObj.Config.SkipInstallationDiskCleanup = true cleanupDevice.EXPECT().CleanupInstallDevice(gomock.Any()).Return(nil).Times(0) @@ -896,7 +923,7 @@ var _ = Describe("installer HostRoleMaster role", func() { mkdirSuccess(InstallDir) downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(installerArgs) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(false) reportLogProgressSuccess() ironicAgentDoesntExist() @@ -963,7 +990,7 @@ var _ = Describe("installer HostRoleMaster role", func() { mkdirSuccess(InstallDir) downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(installerArgs) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(false) reportLogProgressSuccess() getEncapsulatedMcSuccess(nil) @@ -1018,7 +1045,7 @@ var _ = Describe("installer HostRoleMaster role", func() { uploadLogsSuccess(false) reportLogProgressSuccess() writeToDiskSuccess(installerArgs) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() getEncapsulatedMcSuccess(nil) overwriteImageSuccess() ironicAgentDoesntExist() @@ -1070,7 +1097,7 @@ var _ = Describe("installer HostRoleMaster role", func() { mkdirSuccess(InstallDir) downloadHostIgnitionSuccess(infraEnvId, hostId, "worker-host-id.ign") mockops.EXPECT().WriteImageToDisk(gomock.Any(), filepath.Join(InstallDir, "worker-host-id.ign"), device, nil).Return(nil).Times(1) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() // failure must do nothing reportLogProgressSuccess() mockops.EXPECT().UploadInstallationLogs(false).Return("", errors.Errorf("Dummy")).Times(1) @@ -1176,7 +1203,7 @@ var _ = Describe("installer HostRoleMaster role", func() { singleNodeMergeIgnitionSuccess() downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") mockops.EXPECT().WriteImageToDisk(gomock.Any(), singleNodeMasterIgnitionPath, device, nil).Return(nil).Times(1) - setBootOrderSuccess(gomock.Any()) + setBootOrderSuccess() uploadLogsSuccess(true) reportLogProgressSuccess() ironicAgentDoesntExist() diff --git a/src/ops/mock_ops.go b/src/ops/mock_ops.go index 9b497b813a..8aff008345 100644 --- a/src/ops/mock_ops.go +++ b/src/ops/mock_ops.go @@ -399,3 +399,17 @@ func (mr *MockOpsMockRecorder) WriteImageToDisk(liveLogger, ignitionPath, device mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteImageToDisk", reflect.TypeOf((*MockOps)(nil).WriteImageToDisk), liveLogger, ignitionPath, device, extraArgs) } + +// WriteImageToExistingRoot mocks base method. +func (m *MockOps) WriteImageToExistingRoot(liveLogger io.Writer, ignitionPath string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WriteImageToExistingRoot", liveLogger, ignitionPath) + ret0, _ := ret[0].(error) + return ret0 +} + +// WriteImageToExistingRoot indicates an expected call of WriteImageToExistingRoot. +func (mr *MockOpsMockRecorder) WriteImageToExistingRoot(liveLogger, ignitionPath any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteImageToExistingRoot", reflect.TypeOf((*MockOps)(nil).WriteImageToExistingRoot), liveLogger, ignitionPath) +} diff --git a/src/ops/ops.go b/src/ops/ops.go index 058fffe733..6cdb2181f5 100644 --- a/src/ops/ops.go +++ b/src/ops/ops.go @@ -49,6 +49,7 @@ const ( type Ops interface { Mkdir(dirName string) error WriteImageToDisk(liveLogger io.Writer, ignitionPath string, device string, extraArgs []string) error + WriteImageToExistingRoot(liveLogger io.Writer, ignitionPath string) error Reboot(delay string) error SetBootOrder(device string) error ExtractFromIgnition(ignitionPath string, fileToExtract string) error @@ -125,6 +126,71 @@ func (o *ops) SystemctlAction(action string, args ...string) error { return errors.Wrapf(err, "Failed executing systemctl %s %s", action, args) } +var ostreeOutputRegex = regexp.MustCompile(`Imported: (\w+)`) + +func (o *ops) importOSTreeCommit(liveLogger io.Writer) (string, error) { + ostreeReleasePullSpec := fmt.Sprintf("ostree-unverified-registry:%s", o.installerConfig.CoreosImage) + out, err := o.ExecPrivilegeCommand(liveLogger, "ostree", "container", "unencapsulate", "--authfile", "/root/.docker/config.json", "--quiet", "--repo", "/ostree/repo", ostreeReleasePullSpec) + if err != nil { + return "", errors.Wrapf(err, "failed to unencapsulate rhcos payload image: %s", out) + } + + matches := ostreeOutputRegex.FindStringSubmatch(out) + if matches == nil { + return "", fmt.Errorf("got unexpected output from unencapsulate: \"%s\"", out) + } + + return matches[1], nil +} + +func (o *ops) WriteImageToExistingRoot(liveLogger io.Writer, ignitionPath string) error { + out, err := o.ExecPrivilegeCommand(liveLogger, "mount", "/sysroot", "-o", "remount,rw") + if err != nil { + return errors.Wrapf(err, "failed to remount sysroot: %s", out) + } + out, err = o.ExecPrivilegeCommand(liveLogger, "mount", "/boot", "-o", "remount,rw") + if err != nil { + return errors.Wrapf(err, "failed to remount boot: %s", out) + } + + out, err = o.ExecPrivilegeCommand(liveLogger, "ostree", "admin", "stateroot-init", "install") + if err != nil { + return errors.Wrapf(err, "failed creating new stateroot: %s", out) + } + + commit, err := o.importOSTreeCommit(liveLogger) + if err != nil { + return err + } + o.log.Infof("imported commit %s", commit) + + out, err = o.ExecPrivilegeCommand(liveLogger, "ostree", "admin", "deploy", + "--stateroot", "install", + "--karg", "$ignition_firstboot", + "--karg", defaultIgnitionPlatformId, + commit) + if err != nil { + return errors.Wrapf(err, "failed to deploy commit to stateroot: %s", out) + } + + out, err = o.ExecPrivilegeCommand(liveLogger, "mkdir", "/boot/ignition") + if err != nil { + return errors.Wrapf(err, "failed to create ignition directory: %s", out) + } + + out, err = o.ExecPrivilegeCommand(liveLogger, "cp", ignitionPath, "/boot/ignition/config.ign") + if err != nil { + return errors.Wrapf(err, "failed to copy ignition file: %s", out) + } + + out, err = o.ExecPrivilegeCommand(liveLogger, "touch", "/boot/ignition.firstboot") + if err != nil { + return errors.Wrapf(err, "failed to write ignition marker file: %s", out) + } + + return nil +} + func (o *ops) WriteImageToDisk(liveLogger io.Writer, ignitionPath string, device string, extraArgs []string) error { allArgs := installerArgs(ignitionPath, device, extraArgs) o.log.Infof("Writing image and ignition to disk with arguments: %v", allArgs) diff --git a/src/ops/ops_test.go b/src/ops/ops_test.go index 82d4b066d6..3cc2e89a43 100644 --- a/src/ops/ops_test.go +++ b/src/ops/ops_test.go @@ -13,6 +13,7 @@ import ( "reflect" "github.com/openshift/assisted-installer/src/ops/execute" + "github.com/openshift/assisted-installer/src/utils" "github.com/coreos/ignition/v2/config/v3_2/types" "github.com/go-openapi/swag" @@ -525,3 +526,83 @@ var _ = Describe("get number of reboots", func() { Expect(err).To(HaveOccurred()) }) }) + +var _ = Describe("importOSTreeCommit", func() { + const osImage = "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:d21f2ed754a66d18b0a13a59434fa4dc36abd4320e78f3be83a3e29e21e3c2f9" + var ( + l = logrus.New() + ctrl *gomock.Controller + execMock *execute.MockExecute + o *ops + ) + + BeforeEach(func() { + ctrl = gomock.NewController(GinkgoT()) + execMock = execute.NewMockExecute(ctrl) + o = &ops{ + log: l, + logWriter: utils.NewLogWriter(l), + installerConfig: &config.Config{ + CoreosImage: osImage, + }, + executor: execMock, + } + }) + + It("returns the commit when successful", func() { + pullSpec := "ostree-unverified-registry:" + osImage + execMock.EXPECT().ExecCommand(gomock.Any(), + "nsenter", "--target", "1", "--cgroup", "--mount", "--ipc", "--pid", "--", + "ostree", "container", "unencapsulate", + "--authfile", "/root/.docker/config.json", + "--quiet", + "--repo", "/ostree/repo", + pullSpec, + ).Return("Imported: bd58af6b04f8ed7e3e72d1af34439fb03a5640a516edd200fb26775df346ae25\n", nil) + commit, err := o.importOSTreeCommit(io.Discard) + Expect(err).NotTo(HaveOccurred()) + Expect(commit).To(Equal("bd58af6b04f8ed7e3e72d1af34439fb03a5640a516edd200fb26775df346ae25")) + }) + + It("fails when the command fails", func() { + pullSpec := "ostree-unverified-registry:" + osImage + execMock.EXPECT().ExecCommand(gomock.Any(), + "nsenter", "--target", "1", "--cgroup", "--mount", "--ipc", "--pid", "--", + "ostree", "container", "unencapsulate", + "--authfile", "/root/.docker/config.json", + "--quiet", + "--repo", "/ostree/repo", + pullSpec, + ).Return("", fmt.Errorf("failed")) + _, err := o.importOSTreeCommit(io.Discard) + Expect(err).To(HaveOccurred()) + }) + + It("fails when the output is not as expected", func() { + pullSpec := "ostree-unverified-registry:" + osImage + execMock.EXPECT().ExecCommand(gomock.Any(), + "nsenter", "--target", "1", "--cgroup", "--mount", "--ipc", "--pid", "--", + "ostree", "container", "unencapsulate", + "--authfile", "/root/.docker/config.json", + "--quiet", + "--repo", "/ostree/repo", + pullSpec, + ).Return("commit bd58af6b04f8ed7e3e72d1af34439fb03a5640a516edd200fb26775df346ae25\n", nil) + _, err := o.importOSTreeCommit(io.Discard) + Expect(err).To(HaveOccurred()) + }) + + It("fails when the output cannot be parsed", func() { + pullSpec := "ostree-unverified-registry:" + osImage + execMock.EXPECT().ExecCommand(gomock.Any(), + "nsenter", "--target", "1", "--cgroup", "--mount", "--ipc", "--pid", "--", + "ostree", "container", "unencapsulate", + "--authfile", "/root/.docker/config.json", + "--quiet", + "--repo", "/ostree/repo", + pullSpec, + ).Return("some nonsense here", nil) + _, err := o.importOSTreeCommit(io.Discard) + Expect(err).To(HaveOccurred()) + }) +}) From 2bde2745341a3279db1608fd7967bba8ec9f5834 Mon Sep 17 00:00:00 2001 From: Nick Carboni Date: Mon, 20 Jan 2025 14:42:53 -0500 Subject: [PATCH 2/2] Add a constant for docker auth file --- src/ops/ops.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ops/ops.go b/src/ops/ops.go index 6cdb2181f5..a1b99545f3 100644 --- a/src/ops/ops.go +++ b/src/ops/ops.go @@ -38,6 +38,7 @@ import ( ) const ( + dockerConfigFile = "/root/.docker/config.json" coreosInstallerExecutable = "coreos-installer" dryRunCoreosInstallerExecutable = "dry-installer" encapsulatedMachineConfigFile = "/etc/ignition-machine-config-encapsulated.json" @@ -130,7 +131,7 @@ var ostreeOutputRegex = regexp.MustCompile(`Imported: (\w+)`) func (o *ops) importOSTreeCommit(liveLogger io.Writer) (string, error) { ostreeReleasePullSpec := fmt.Sprintf("ostree-unverified-registry:%s", o.installerConfig.CoreosImage) - out, err := o.ExecPrivilegeCommand(liveLogger, "ostree", "container", "unencapsulate", "--authfile", "/root/.docker/config.json", "--quiet", "--repo", "/ostree/repo", ostreeReleasePullSpec) + out, err := o.ExecPrivilegeCommand(liveLogger, "ostree", "container", "unencapsulate", "--authfile", dockerConfigFile, "--quiet", "--repo", "/ostree/repo", ostreeReleasePullSpec) if err != nil { return "", errors.Wrapf(err, "failed to unencapsulate rhcos payload image: %s", out) } @@ -1018,7 +1019,7 @@ func (o *ops) OverwriteOsImage(osImage, device string, extraArgs []string) error "--sysroot", "/mnt", "--authfile", - "/root/.docker/config.json", + dockerConfigFile, "--imgref", "ostree-unverified-registry:"+osImage, "--karg",