Skip to content

Commit abed5af

Browse files
committed
Freshen up dry run mode for the installer/controller
The installer/controller dry run mode has not been kept up to date with recent changes. This commit updates the dry run mode to skip actions that would modify the system, such as writing to disk or starting services when in dry run mode. This will avoid damaging the host system when testing the installer in dry run mode (used by https://github.com/openshift-assisted/assisted-swarm)
1 parent 753d15c commit abed5af

File tree

5 files changed

+50
-14
lines changed

5 files changed

+50
-14
lines changed

src/assisted_installer_controller/assisted_installer_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,10 @@ type ControllerConfig struct {
9494
ControlPlaneCount int `envconfig:"CONTROL_PLANE_COUNT" required:"false" default:"3"`
9595
WaitForClusterVersion bool `envconfig:"CHECK_CLUSTER_VERSION" required:"false" default:"false"`
9696
MustGatherImage string `envconfig:"MUST_GATHER_IMAGE" required:"false" default:""`
97+
NotifyNumReboots bool `envconfig:"NOTIFY_NUM_REBOOTS" default:"false"`
9798
DryRunEnabled bool `envconfig:"DRY_ENABLE" required:"false" default:"false"`
9899
DryFakeRebootMarkerPath string `envconfig:"DRY_FAKE_REBOOT_MARKER_PATH" required:"false" default:""`
99100
DryRunClusterHostsPath string `envconfig:"DRY_CLUSTER_HOSTS_PATH"`
100-
NotifyNumReboots bool `envconfig:"NOTIFY_NUM_REBOOTS" default:"false"`
101101
// DryRunClusterHostsPath gets read parsed into ParsedClusterHosts by DryParseClusterHosts
102102
ParsedClusterHosts config.DryClusterHosts
103103
}

src/installer/installer.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,12 @@ func (i *installer) waitForWorkers(ctx context.Context) error {
220220
i.log.Error(err)
221221
return err
222222
}
223+
224+
if i.DryRunEnabled {
225+
// In dry run mode we assume we're not ABI
226+
return nil
227+
}
228+
223229
if invoker := common.GetInvoker(kc, i.log); invoker != common.InvokerAgent {
224230
return nil
225231
}
@@ -399,6 +405,10 @@ func (i *installer) writeImageToDisk(ignitionPath string) error {
399405
}
400406

401407
func (i *installer) skipMcoReboot(ignitionPath string) {
408+
if i.DryRunEnabled {
409+
return
410+
}
411+
402412
var mc *mcfgv1.MachineConfig
403413
mc, err := i.getEncapsulatedMC(ignitionPath)
404414
if err != nil {
@@ -447,9 +457,11 @@ func (i *installer) startBootstrap() error {
447457
}
448458

449459
// reload systemd configurations from filesystem and regenerate dependency trees
450-
err = i.ops.SystemctlAction("daemon-reload")
451-
if err != nil {
452-
return err
460+
if !i.DryRunEnabled {
461+
err = i.ops.SystemctlAction("daemon-reload")
462+
if err != nil {
463+
return err
464+
}
453465
}
454466

455467
/* in case hostname is illegal (localhost, contains capital letters, etc.), we need to set hostname to
@@ -466,7 +478,7 @@ func (i *installer) startBootstrap() error {
466478
// restart NetworkManager to trigger NetworkManager/dispatcher.d/30-local-dns-prepender
467479
// we don't do it on SNO because the "local-dns-prepender" is not even
468480
// available on none-platform
469-
if i.ControlPlaneCount != 1 {
481+
if i.ControlPlaneCount != 1 && !i.DryRunEnabled {
470482
err = i.ops.SystemctlAction("restart", "NetworkManager.service")
471483
if err != nil {
472484
i.log.Error(err)
@@ -482,7 +494,7 @@ func (i *installer) startBootstrap() error {
482494
// If we're in a pure RHEL/CentOS environment, we need to overlay the node image
483495
// first to have access to e.g. oc, kubelet, cri-o, etc...
484496
// https://github.com/openshift/enhancements/pull/1637
485-
if !i.ops.FileExists(openshiftClientBin) {
497+
if !i.ops.FileExists(openshiftClientBin) && !i.DryRunEnabled {
486498
err = i.ops.SystemctlAction("start", "--no-block", nodeImagePullService, nodeImageOverlayService)
487499
if err != nil {
488500
return err
@@ -504,6 +516,9 @@ func (i *installer) startBootstrap() error {
504516
}
505517

506518
servicesToStart := []string{"bootkube.service", "approve-csr.service", "progress.service"}
519+
if i.DryRunEnabled {
520+
servicesToStart = []string{}
521+
}
507522
for _, service := range servicesToStart {
508523
err = i.ops.SystemctlAction("start", service)
509524
if err != nil {
@@ -614,9 +629,12 @@ func (i *installer) waitForControlPlane(ctx context.Context) error {
614629
}
615630

616631
i.waitForBootkube(ctx)
617-
if err = i.waitForETCDBootstrap(ctx); err != nil {
618-
i.log.Error(err)
619-
return err
632+
633+
if !i.DryRunEnabled {
634+
if err = i.waitForETCDBootstrap(ctx); err != nil {
635+
i.log.Error(err)
636+
return err
637+
}
620638
}
621639

622640
// waiting for controller pod to be running

src/main/assisted-installer-controller/assisted_installer_main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ func main() {
9898
mockController := gomock.NewController(logger)
9999
kc = k8s_client.NewMockK8SClient(mockController)
100100
mock, _ := kc.(*k8s_client.MockK8SClient)
101-
drymock.PrepareControllerDryMock(mock, logger, o, Options.ControllerConfig.ParsedClusterHosts)
101+
drymock.PrepareControllerDryMock(mock, logger, o, Options.ControllerConfig.ParsedClusterHosts,
102+
Options.ControllerConfig.ControlPlaneCount)
102103
}
103104

104105
err = kc.SetProxyEnvVars()

src/main/drymock/dry_mode_k8s_mock.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,11 @@ Dry`)
7373
// PrepareControllerDryMock utilizes k8s_client.MockK8SClient to fake the k8s API to make the
7474
// controller think it's running on an actual cluster, just enough to make it pass an installation.
7575
// Used in dry mode.
76-
func PrepareControllerDryMock(mockk8sclient *k8s_client.MockK8SClient, logger *logrus.Logger, o ops.Ops, clusterHosts config.DryClusterHosts) {
76+
func PrepareControllerDryMock(mockk8sclient *k8s_client.MockK8SClient, logger *logrus.Logger, o ops.Ops, clusterHosts config.DryClusterHosts, controlPlaneCount int) {
77+
mockk8sclient.EXPECT().GetControlPlaneReplicas().Return(controlPlaneCount, nil).AnyTimes()
78+
// Dry run doesn't support arbiter for now
79+
mockk8sclient.EXPECT().GetArbiterReplicas().Return(0, nil).AnyTimes()
80+
7781
// Called by main
7882
mockk8sclient.EXPECT().SetProxyEnvVars().Return(nil).AnyTimes()
7983

@@ -107,7 +111,7 @@ func PrepareControllerDryMock(mockk8sclient *k8s_client.MockK8SClient, logger *l
107111
// Host didn't even reboot yet, don't pretend it fetched the ignition
108112
continue
109113
}
110-
mcsLogs += fmt.Sprintf("%s.(Ignition)\n", clusterHost.Ip)
114+
mcsLogs += fmt.Sprintf("%s:12345 User-Agent:\"Ignition\"\n", clusterHost.Ip)
111115
}
112116
return mcsLogs, nil
113117
}).AnyTimes()
@@ -280,7 +284,11 @@ dEFgad6P3hMZTOg7yVkMOd3QtgVQ9I8dXqS2nG9EMEh97WIhi6f5ztvcQvQ5tXjh
280284
// PrepareInstallerDryK8sMock utilizes k8s_client.MockK8SClient to fake the k8s API to make the
281285
// installer think it's talking with an actual cluster, just enough to make it pass an installation.
282286
// Used in dry mode.
283-
func PrepareInstallerDryK8sMock(mockk8sclient *k8s_client.MockK8SClient, logger logrus.FieldLogger, o ops.Ops, clusterHosts config.DryClusterHosts) {
287+
func PrepareInstallerDryK8sMock(mockk8sclient *k8s_client.MockK8SClient, logger logrus.FieldLogger, o ops.Ops, clusterHosts config.DryClusterHosts,
288+
controlPlaneCount int) {
289+
mockk8sclient.EXPECT().GetControlPlaneReplicas().Return(controlPlaneCount, nil).AnyTimes()
290+
// Dry run doesn't support arbiter for now
291+
mockk8sclient.EXPECT().GetArbiterReplicas().Return(0, nil).AnyTimes()
284292
// The installer compares AI host objects to cluster Node objects (either by name or by IP) to check which AI hosts are already
285293
// joined as nodes. This fakes the node list so that check will pass
286294
mockk8sclient.EXPECT().ListNodesByRole(gomock.Any()).DoAndReturn(func() (*v1.NodeList, error) {
@@ -307,7 +315,8 @@ func NewDryRunK8SClientBuilder(installerConfig *config.Config, ops ops.Ops) func
307315
mockController := gomock.NewController(ginkgo.GinkgoT())
308316
kc = k8s_client.NewMockK8SClient(mockController)
309317
mock, _ := kc.(*k8s_client.MockK8SClient)
310-
PrepareInstallerDryK8sMock(mock, logger, ops, installerConfig.ParsedClusterHosts)
318+
PrepareInstallerDryK8sMock(mock, logger, ops, installerConfig.ParsedClusterHosts,
319+
installerConfig.ControlPlaneCount)
311320
return kc, nil
312321
}
313322
}

src/ops/ops.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,14 @@ func (o *ops) configureFirstBootIgnition(liveLogger io.Writer, ignitionPath stri
268268
}
269269

270270
func (o *ops) WriteImageToExistingRoot(liveLogger io.Writer, ignitionPath string, installerArgs []string) error {
271+
if o.installerConfig.DryRunEnabled {
272+
// In dry run, we use an executable called dry-installer rather than ostree.
273+
// This executable is expected to pretend to be doing coreos-installer stuff and print fake
274+
// progress. It's up to the dry-mode user to make sure such executable is available in PATH
275+
_, err := o.ExecPrivilegeCommand(liveLogger, dryRunCoreosInstallerExecutable)
276+
return err
277+
}
278+
271279
if err := o.remountFilesystems(liveLogger); err != nil {
272280
return err
273281
}

0 commit comments

Comments
 (0)