From 24c178f39b0bca2c558a803309a93c8bcaef5109 Mon Sep 17 00:00:00 2001 From: gaufde <108958455+gaufde@users.noreply.github.com> Date: Sat, 19 Oct 2024 19:04:37 -0700 Subject: [PATCH] Fix for podman machine init not creating necessary JSON file when is passed. This bug was first described in https://github.com/containers/podman/issues/23544. Signed-off-by: Graceson Aufderheide --- pkg/machine/shim/host.go | 52 ++++++++------- pkg/machine/shim/host_test.go | 117 ++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 24 deletions(-) create mode 100644 pkg/machine/shim/host_test.go diff --git a/pkg/machine/shim/host.go b/pkg/machine/shim/host.go index 948ebe11ab..f8c8921555 100644 --- a/pkg/machine/shim/host.go +++ b/pkg/machine/shim/host.go @@ -196,30 +196,39 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) error { // copy it into the conf dir if len(opts.IgnitionPath) > 0 { err = ignBuilder.BuildWithIgnitionFile(opts.IgnitionPath) - return err - } - err = ignBuilder.GenerateIgnitionConfig() - if err != nil { - return err - } + if err != nil { + return err + } + } else { - readyIgnOpts, err := mp.PrepareIgnition(mc, &ignBuilder) - if err != nil { - return err - } + err = ignBuilder.GenerateIgnitionConfig() + if err != nil { + return err + } - readyUnitFile, err := ignition.CreateReadyUnitFile(mp.VMType(), readyIgnOpts) - if err != nil { - return err - } + readyIgnOpts, err := mp.PrepareIgnition(mc, &ignBuilder) + if err != nil { + return err + } - readyUnit := ignition.Unit{ - Enabled: ignition.BoolToPtr(true), - Name: "ready.service", - Contents: ignition.StrToPtr(readyUnitFile), + readyUnitFile, err := ignition.CreateReadyUnitFile(mp.VMType(), readyIgnOpts) + if err != nil { + return err + } + + readyUnit := ignition.Unit{ + Enabled: ignition.BoolToPtr(true), + Name: "ready.service", + Contents: ignition.StrToPtr(readyUnitFile), + } + ignBuilder.WithUnit(readyUnit) + + err = ignBuilder.Build() + if err != nil { + return err + } } - ignBuilder.WithUnit(readyUnit) // Mounts if mp.VMType() != machineDefine.WSLVirt { @@ -245,11 +254,6 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) error { return err } - err = ignBuilder.Build() - if err != nil { - return err - } - return mc.Write() } diff --git a/pkg/machine/shim/host_test.go b/pkg/machine/shim/host_test.go new file mode 100644 index 0000000000..a8c9a4f10d --- /dev/null +++ b/pkg/machine/shim/host_test.go @@ -0,0 +1,117 @@ +package shim + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/containers/podman/v5/pkg/machine/define" + "github.com/containers/podman/v5/pkg/machine/env" + provider2 "github.com/containers/podman/v5/pkg/machine/provider" + "github.com/containers/podman/v5/pkg/machine/vmconfigs" +) + +func fileExists(filename string) bool { + _, err := os.Stat(filename) + return err == nil +} + +func createTempIgnitionFile(t *testing.T) string { + t.Helper() + + mockIgnitionContent := `{"ignition":{"version":"3.4.0"},"passwd":{"users":[{"name":"core"}]}}` + + tmpFile, err := os.CreateTemp("", "test-ignition-*.ign") + if err != nil { + t.Fatalf("Failed to create temporary ignition file: %v", err) + } + + if _, err := tmpFile.WriteString(mockIgnitionContent); err != nil { + t.Fatalf("Failed to write to temporary ignition file: %v", err) + } + + if err := tmpFile.Close(); err != nil { + t.Fatalf("Failed to close temporary ignition file: %v", err) + } + + return tmpFile.Name() +} + +func TestInit(t *testing.T) { + var ( + provider vmconfigs.VMProvider + ) + + provider, err := provider2.Get() + if err != nil { + t.Fatalf("Failed to get provider: %v", err) + } + + dirs, err := env.GetMachineDirs(provider.VMType()) + if err != nil { + t.Fatalf("Failed to get dirs: %v", err) + } + + tempIgnitionPath := createTempIgnitionFile(t) + defer func(name string) { + err := os.Remove(name) + if err != nil { + t.Fatalf("Failed to remove temp ignition file: %v", err) + } + }(tempIgnitionPath) + + type args struct { + opts define.InitOptions + mp vmconfigs.VMProvider + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Default machine", + args: args{ + opts: define.InitOptions{ + Name: "test-default-machine", + }, + mp: provider, + }, + wantErr: false, + }, + { + name: "With ignition", + args: args{ + opts: define.InitOptions{ + Name: "test-with-ignition", + IgnitionPath: tempIgnitionPath, + }, + mp: provider, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := Init(tt.args.opts, tt.args.mp); (err != nil) != tt.wantErr { + t.Errorf("Init() error = %v, wantErr %v", err, tt.wantErr) + } + + // Check for file existence only for valid initialization + if !tt.wantErr { + configDir := dirs.ConfigDir.GetPath() + fileExtensions := []string{".lock", ".json", ".ign"} + + for _, ext := range fileExtensions { + filename := filepath.Join(configDir, fmt.Sprintf("%s%s", tt.args.opts.Name, ext)) + if !fileExists(filename) { + t.Errorf("Expected file %s does not exist", filename) + } else { + t.Logf("File %s exists", filename) + } + } + } + }) + } +}