From a3605aa89f818f60e813ff18cf6b7c918f22b35b Mon Sep 17 00:00:00 2001 From: CrystalChun Date: Thu, 22 Feb 2024 08:40:29 -0800 Subject: [PATCH] MGMT-16843: Extract host ignition before bootstrap https://issues.redhat.com/browse/MGMT-16843 Reordered the flow for bootstrap nodes to extract the host ignition before starting bootstrap. This is so we can get the requested hostname from the host ignition ahead of running bootkube which will allow the requested hostname to be set. --- src/installer/installer.go | 39 +++++++++++++++++++++--------- src/installer/installer_test.go | 43 +++++++++++++++++---------------- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/src/installer/installer.go b/src/installer/installer.go index 754965098..2eed4f1bb 100644 --- a/src/installer/installer.go +++ b/src/installer/installer.go @@ -108,11 +108,23 @@ func (i *installer) InstallNode() error { } ctx, cancel := context.WithCancel(context.Background()) bootstrapErrGroup, _ := errgroup.WithContext(ctx) + var ignitionPath string //cancel the context in case this method ends defer cancel() isBootstrap := false if i.Config.Role == string(models.HostRoleBootstrap) && i.HighAvailabilityMode != models.ClusterHighAvailabilityModeNone { isBootstrap = true + i.Config.Role = string(models.HostRoleMaster) + ignitionPath, err = i.downloadHostIgnition() + if err != nil { + return err + } + + if err = i.ops.ExtractFromIgnition(ignitionPath, "/etc/hostname"); err != nil { + i.log.Errorf("extract /etc/hostname from igntion failed %s", err) + return err + } + bootstrapErrGroup.Go(func() error { return i.startBootstrap() }) @@ -121,7 +133,6 @@ func (i *installer) InstallNode() error { } i.UpdateHostInstallProgress(models.HostStageInstalling, i.Config.Role) - var ignitionPath string // i.HighAvailabilityMode is set as an empty string for workers // regardless of the availability mode of the cluster they are joining @@ -132,7 +143,7 @@ func (i *installer) InstallNode() error { if err != nil { return err } - } else { + } else if !isBootstrap { ignitionPath, err = i.downloadHostIgnition() if err != nil { return err @@ -917,22 +928,28 @@ func (i *installer) updateConfiguringStatus(ctx context.Context) { // createSingleNodeMasterIgnition will start the bootstrap flow and wait for bootkube // when bootkube complete the single node master ignition will be under singleNodeMasterIgnitionPath func (i *installer) createSingleNodeMasterIgnition() (string, error) { - if err := i.startBootstrap(); err != nil { - i.log.Errorf("Bootstrap failed %s", err) - return "", err - } - i.waitForBootkube(context.Background()) - _, err := i.ops.ExecPrivilegeCommand(utils.NewLogWriter(i.log), "stat", singleNodeMasterIgnitionPath) - if err != nil { + if _, err := i.ops.ExecPrivilegeCommand(utils.NewLogWriter(i.log), "stat", singleNodeMasterIgnitionPath); err != nil { i.log.Errorf("Failed to find single node master ignition: %s", err) return "", err } + i.Config.Role = string(models.HostRoleMaster) - err = i.updateSingleNodeIgnition(singleNodeMasterIgnitionPath) - if err != nil { + if err := i.updateSingleNodeIgnition(singleNodeMasterIgnitionPath); err != nil { + i.log.Errorf("get single node ignition failed failed %s", err) + return "", err + } + + if err := i.ops.ExtractFromIgnition(singleNodeMasterIgnitionPath, "/etc/hostname"); err != nil { + i.log.Errorf("extract /etc/hostname from igntion failed %s", err) return "", err } + if err := i.startBootstrap(); err != nil { + i.log.Errorf("Bootstrap failed %s", err) + return "", err + } + + i.waitForBootkube(context.Background()) return singleNodeMasterIgnitionPath, nil } diff --git a/src/installer/installer_test.go b/src/installer/installer_test.go index 048aba1c0..4afa4f8e4 100644 --- a/src/installer/installer_test.go +++ b/src/installer/installer_test.go @@ -336,6 +336,9 @@ var _ = Describe("installer HostRoleMaster role", func() { extractSecretFromIgnitionSuccess := func() { mockops.EXPECT().ExtractFromIgnition(filepath.Join(InstallDir, bootstrapIgn), dockerConfigFile).Return(nil).Times(1) } + extractHostnameFromIgnitionSuccess := func() { + mockops.EXPECT().ExtractFromIgnition(filepath.Join(InstallDir, "master-host-id.ign"), "/etc/hostname").Return(nil).Times(1) + } generateSshKeyPairSuccess := func() { mockops.EXPECT().ExecPrivilegeCommand(gomock.Any(), "ssh-keygen", "-q", "-f", sshKeyPath, "-N", "").Return("OK", nil).Times(1) } @@ -348,6 +351,8 @@ var _ = Describe("installer HostRoleMaster role", func() { mkdirSuccess(sshDir) mkdirSuccess(InstallDir) downloadFileSuccess(bootstrapIgn) + downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") + extractHostnameFromIgnitionSuccess() extractSecretFromIgnitionSuccess() extractIgnitionToFS("Success", nil) generateSshKeyPairSuccess() @@ -383,7 +388,6 @@ var _ = Describe("installer HostRoleMaster role", func() { resolvConfSuccess() waitForControllerSuccessfully(conf.ClusterID) //HostRoleMaster flow: - downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) reportLogProgressSuccess() setBootOrderSuccess(gomock.Any()) @@ -416,7 +420,6 @@ var _ = Describe("installer HostRoleMaster role", func() { resolvConfSuccess() waitForControllerSuccessfully(conf.ClusterID) //HostRoleMaster flow: - downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) reportLogProgressSuccess() setBootOrderSuccess(gomock.Any()) @@ -449,7 +452,6 @@ var _ = Describe("installer HostRoleMaster role", func() { resolvConfSuccess() waitForControllerSuccessfully(conf.ClusterID) //HostRoleMaster flow: - downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) setBootOrderSuccess(gomock.Any()) uploadLogsSuccess(true) @@ -474,13 +476,14 @@ var _ = Describe("installer HostRoleMaster role", func() { mkdirSuccess(InstallDir) mkdirSuccess(sshDir) downloadFileSuccess(bootstrapIgn) + downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") + extractHostnameFromIgnitionSuccess() extractSecretFromIgnitionSuccess() extractIgnitionToFS("Success", nil) generateSshKeyPairSuccess() err := fmt.Errorf("generate SSH keys failed") mockops.EXPECT().CreateOpenshiftSshManifest(assistedInstallerSshManifest, sshManifestTmpl, sshPubKeyPath).Return(err).Times(1) //HostRoleMaster flow: - downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) setBootOrderSuccess(gomock.Any()) getEncapsulatedMcSuccess(nil) @@ -510,7 +513,6 @@ var _ = Describe("installer HostRoleMaster role", func() { resolvConfSuccess() waitForControllerSuccessfully(conf.ClusterID) //HostRoleMaster flow: - downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) setBootOrderSuccess(gomock.Any()) uploadLogsSuccess(true) @@ -533,6 +535,7 @@ var _ = Describe("installer HostRoleMaster role", func() { mkdirSuccess(sshDir) downloadFileSuccess(bootstrapIgn) downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") + extractHostnameFromIgnitionSuccess() writeToDiskSuccess(gomock.Any()) setBootOrderSuccess(gomock.Any()) extractSecretFromIgnitionSuccess() @@ -556,7 +559,6 @@ var _ = Describe("installer HostRoleMaster role", func() { err := fmt.Errorf("Failed to restart NetworkManager") restartNetworkManager(err) //HostRoleMaster flow: - downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) setBootOrderSuccess(gomock.Any()) getEncapsulatedMcSuccess(nil) @@ -644,7 +646,6 @@ var _ = Describe("installer HostRoleMaster role", func() { resolvConfSuccess() waitForControllerSuccessfully(conf.ClusterID) //HostRoleMaster flow: - downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") writeToDiskSuccess(gomock.Any()) setBootOrderSuccess(gomock.Any()) uploadLogsSuccess(true) @@ -1072,18 +1073,25 @@ var _ = Describe("installer HostRoleMaster role", func() { extractSecretFromIgnitionSuccess := func() { mockops.EXPECT().ExtractFromIgnition(filepath.Join(InstallDir, bootstrapIgn), dockerConfigFile).Return(nil).Times(1) } + extractHostnameFromIgnitionSuccess := func() { + mockops.EXPECT().ExtractFromIgnition(singleNodeMasterIgnitionPath, "/etc/hostname").Return(nil).Times(1) + } + verifySingleNodeMasterIgnitionSuccess := func() { + mockops.EXPECT().ExecPrivilegeCommand(gomock.Any(), "stat", singleNodeMasterIgnitionPath).Return("", nil).Times(1) + } singleNodeBootstrapSetup := func() { cleanInstallDevice() mkdirSuccess(InstallDir) mkdirSuccess(sshDir) downloadFileSuccess(bootstrapIgn) + verifySingleNodeMasterIgnitionSuccess() + downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") + singleNodeMergeIgnitionSuccess() + extractHostnameFromIgnitionSuccess() extractSecretFromIgnitionSuccess() extractIgnitionToFS("Success", nil) daemonReload(nil) } - verifySingleNodeMasterIgnitionSuccess := func() { - mockops.EXPECT().ExecPrivilegeCommand(gomock.Any(), "stat", singleNodeMasterIgnitionPath).Return("", nil).Times(1) - } It("single node happy flow", func() { updateProgressSuccess([][]string{{string(models.HostStageStartingInstallation), conf.Role}, @@ -1099,9 +1107,6 @@ var _ = Describe("installer HostRoleMaster role", func() { waitForBootkubeSuccess() bootkubeStatusSuccess() //HostRoleMaster flow: - verifySingleNodeMasterIgnitionSuccess() - singleNodeMergeIgnitionSuccess() - downloadHostIgnitionSuccess(infraEnvId, hostId, "master-host-id.ign") mockops.EXPECT().WriteImageToDisk(singleNodeMasterIgnitionPath, device, mockbmclient, nil).Return(nil).Times(1) setBootOrderSuccess(gomock.Any()) uploadLogsSuccess(true) @@ -1126,15 +1131,11 @@ var _ = Describe("installer HostRoleMaster role", func() { }) It("Failed to find master ignition", func() { updateProgressSuccess([][]string{{string(models.HostStageStartingInstallation), conf.Role}, - {string(models.HostStageInstalling), string(models.HostRoleMaster)}, - }) + {string(models.HostStageInstalling), string(models.HostRoleMaster)}, + }) // single node bootstrap flow - singleNodeBootstrapSetup() - checkLocalHostname("localhost", nil) - prepareControllerSuccess() - startServicesSuccess() - waitForBootkubeSuccess() - bootkubeStatusSuccess() + cleanInstallDevice() + mkdirSuccess(InstallDir) //HostRoleMaster flow: err := fmt.Errorf("Failed to find master ignition") mockops.EXPECT().ExecPrivilegeCommand(gomock.Any(), "stat", singleNodeMasterIgnitionPath).Return("", err).Times(1)