diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go index cd92108778..75cfa61da4 100644 --- a/cmd/podman/machine/init.go +++ b/cmd/podman/machine/init.go @@ -83,6 +83,14 @@ func init() { ) _ = initCmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone) + swapFlagName := "swap" + flags.Uint64VarP( + &initOpts.Swap, + swapFlagName, "s", 0, + "Swap in MiB", + ) + _ = initCmd.RegisterFlagCompletionFunc(swapFlagName, completion.AutocompleteNone) + flags.BoolVar( &now, "now", false, diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go index bddcf49c2a..f6f7144ce2 100644 --- a/cmd/podman/machine/list.go +++ b/cmd/podman/machine/list.go @@ -119,6 +119,7 @@ func outputTemplate(cmd *cobra.Command, responses []*entities.ListReporter) erro "CPUs": "CPUS", "Memory": "MEMORY", "DiskSize": "DISK SIZE", + "Swap": "SWAP", }) rpt := report.New(os.Stdout, cmd.Name()) @@ -182,6 +183,7 @@ func toMachineFormat(vms []*machine.ListResponse, defaultCon *config.Connection) response.VMType = vm.VMType response.CPUs = vm.CPUs response.Memory = strUint(uint64(vm.Memory.ToBytes())) + response.Swap = strUint(uint64(vm.Swap.ToBytes())) response.DiskSize = strUint(uint64(vm.DiskSize.ToBytes())) response.Port = vm.Port response.RemoteUsername = vm.RemoteUsername @@ -225,6 +227,7 @@ func toHumanFormat(vms []*machine.ListResponse, defaultCon *config.Connection) [ response.VMType = vm.VMType response.CPUs = vm.CPUs response.Memory = units.BytesSize(float64(vm.Memory.ToBytes())) + response.Swap = units.BytesSize(float64(vm.Swap.ToBytes())) response.DiskSize = units.BytesSize(float64(vm.DiskSize.ToBytes())) humanResponses = append(humanResponses, response) diff --git a/docs/source/markdown/podman-machine-init.1.md.in b/docs/source/markdown/podman-machine-init.1.md.in index 7edb7eabfc..a6f8ba0654 100644 --- a/docs/source/markdown/podman-machine-init.1.md.in +++ b/docs/source/markdown/podman-machine-init.1.md.in @@ -104,6 +104,12 @@ if there is no existing remote connection configurations. API forwarding, if available, follows this setting. +#### **--swap**, **-s**=*number* + +Swap (in MiB). Note: 1024MiB = 1GiB. + +Renders a `zram-generator.conf` file with zram-size set to the value passed to --swap + #### **--timezone** Set the timezone for the machine and containers. Valid values are `local` or diff --git a/docs/source/markdown/podman-machine-list.1.md.in b/docs/source/markdown/podman-machine-list.1.md.in index 60ebb12294..a850666cd7 100644 --- a/docs/source/markdown/podman-machine-list.1.md.in +++ b/docs/source/markdown/podman-machine-list.1.md.in @@ -50,6 +50,7 @@ Valid placeholders for the Go template are listed below: | .RemoteUsername | VM Username for rootless Podman | | .Running | Is machine running | | .Stream | Stream name | +| .Swap | Allocated swap for machine | | .UserModeNetworking | Whether machine uses user-mode networking | | .VMType | VM type | diff --git a/pkg/domain/entities/machine.go b/pkg/domain/entities/machine.go index c6db89d3c1..1d2e45f321 100644 --- a/pkg/domain/entities/machine.go +++ b/pkg/domain/entities/machine.go @@ -13,6 +13,7 @@ type ListReporter struct { VMType string CPUs uint64 Memory string + Swap string DiskSize string Port int RemoteUsername string diff --git a/pkg/machine/config.go b/pkg/machine/config.go index 046b94b0f1..92bc2ef5da 100644 --- a/pkg/machine/config.go +++ b/pkg/machine/config.go @@ -22,9 +22,7 @@ import ( const apiUpTimeout = 20 * time.Second -var ( - ForwarderBinaryName = "gvproxy" -) +var ForwarderBinaryName = "gvproxy" type Download struct { Arch string @@ -55,6 +53,7 @@ type ListResponse struct { VMType string CPUs uint64 Memory strongunits.MiB + Swap strongunits.MiB DiskSize strongunits.GiB Port int RemoteUsername string diff --git a/pkg/machine/define/initopts.go b/pkg/machine/define/initopts.go index b1ccaaa6b7..edafddb986 100644 --- a/pkg/machine/define/initopts.go +++ b/pkg/machine/define/initopts.go @@ -11,6 +11,7 @@ type InitOptions struct { Volumes []string IsDefault bool Memory uint64 + Swap uint64 Name string TimeZone string URI url.URL diff --git a/pkg/machine/e2e/config_init_test.go b/pkg/machine/e2e/config_init_test.go index 39911a5db4..875e4a4872 100644 --- a/pkg/machine/e2e/config_init_test.go +++ b/pkg/machine/e2e/config_init_test.go @@ -28,6 +28,7 @@ type initMachine struct { playbook string cpus *uint diskSize *uint + swap *uint ignitionPath string username string image string @@ -81,6 +82,9 @@ func (i *initMachine) buildCmd(m *machineTestBuilder) []string { if i.userModeNetworking { cmd = append(cmd, "--user-mode-networking") } + if i.swap != nil { + cmd = append(cmd, "--swap", strconv.Itoa(int(*i.swap))) + } name := m.name cmd = append(cmd, name) @@ -112,11 +116,17 @@ func (i *initMachine) withCPUs(num uint) *initMachine { i.cpus = &num return i } + func (i *initMachine) withDiskSize(size uint) *initMachine { i.diskSize = &size return i } +func (i *initMachine) withSwap(size uint) *initMachine { + i.swap = &size + return i +} + func (i *initMachine) withIgnitionPath(path string) *initMachine { i.ignitionPath = path return i diff --git a/pkg/machine/e2e/init_test.go b/pkg/machine/e2e/init_test.go index 12b9f4a2c0..c197ac9351 100644 --- a/pkg/machine/e2e/init_test.go +++ b/pkg/machine/e2e/init_test.go @@ -238,7 +238,6 @@ var _ = Describe("podman machine init", func() { Expect(testMachine.Resources.Memory).To(BeEquivalentTo(uint64(2048))) } Expect(testMachine.SSHConfig.RemoteUsername).To(Equal(remoteUsername)) - }) It("machine init with cpus, disk size, memory, timezone", func() { @@ -282,6 +281,23 @@ var _ = Describe("podman machine init", func() { Expect(timezoneSession.outputToString()).To(ContainSubstring("HST")) }) + It("machine init with swap", func() { + skipIfWSL("Configuring swap is not supported on WSL") + name := randomString() + i := new(initMachine) + session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath).withSwap(2048).withNow()).run() + Expect(err).ToNot(HaveOccurred()) + Expect(session).To(Exit(0)) + + ssh := &sshMachine{} + sshSession, err := mb.setName(name).setCmd(ssh.withSSHCommand([]string{"zramctl -bo DISKSIZE"})).run() + Expect(err).ToNot(HaveOccurred()) + Expect(sshSession).To(Exit(0)) + + // 2147483648 bytes = 2048MiB + Expect(sshSession.outputToString()).To(ContainSubstring("2147483648")) + }) + It("machine init with volume", func() { if testProvider.VMType() == define.HyperVVirt { Skip("volumes are not supported on hyperv yet") @@ -373,7 +389,6 @@ var _ = Describe("podman machine init", func() { output := strings.TrimSpace(sshSession2.outputToString()) Expect(output).To(HavePrefix("/run/user")) Expect(output).To(HaveSuffix("/podman/podman.sock")) - }) It("machine init rootful with docker.sock check", func() { diff --git a/pkg/machine/ignition/ignition.go b/pkg/machine/ignition/ignition.go index d6206ff658..4c73297e81 100644 --- a/pkg/machine/ignition/ignition.go +++ b/pkg/machine/ignition/ignition.go @@ -67,6 +67,7 @@ type DynamicIgnition struct { Rootful bool NetRecover bool Rosetta bool + Swap uint64 } func (ign *DynamicIgnition) Write() error { @@ -136,7 +137,7 @@ func (ign *DynamicIgnition) GenerateIgnitionConfig() error { ignStorage := Storage{ Directories: getDirs(ign.Name), - Files: getFiles(ign.Name, ign.UID, ign.Rootful, ign.VMType, ign.NetRecover), + Files: getFiles(ign.Name, ign.UID, ign.Rootful, ign.VMType, ign.NetRecover, ign.Swap), Links: getLinks(ign.Name), } @@ -293,7 +294,7 @@ func getDirs(usrName string) []Directory { return dirs } -func getFiles(usrName string, uid int, rootful bool, vmtype define.VMType, _ bool) []File { +func getFiles(usrName string, uid int, rootful bool, vmtype define.VMType, _ bool, swap uint64) []File { files := make([]File, 0) lingerExample := parser.NewUnitFile() @@ -407,6 +408,21 @@ pids_limit=0 }, }) + if swap > 0 { + files = append(files, File{ + Node: Node{ + Path: "/etc/systemd/zram-generator.conf", + }, + FileEmbedded1: FileEmbedded1{ + Append: nil, + Contents: Resource{ + Source: EncodeDataURLPtr(fmt.Sprintf("[zram0]\nzram-size=%d\n", swap)), + }, + Mode: IntToPtr(0644), + }, + }) + } + // get certs for current user userHome, err := os.UserHomeDir() if err != nil { diff --git a/pkg/machine/shim/host.go b/pkg/machine/shim/host.go index 3b368b4a87..56c75b6bf7 100644 --- a/pkg/machine/shim/host.go +++ b/pkg/machine/shim/host.go @@ -32,9 +32,7 @@ import ( // List is done at the host level to allow for a *possible* future where // more than one provider is used func List(vmstubbers []vmconfigs.VMProvider, _ machine.ListOptions) ([]*machine.ListResponse, error) { - var ( - lrs []*machine.ListResponse - ) + var lrs []*machine.ListResponse for _, s := range vmstubbers { dirs, err := env.GetMachineDirs(s.VMType()) @@ -51,15 +49,15 @@ func List(vmstubbers []vmconfigs.VMProvider, _ machine.ListOptions) ([]*machine. return nil, err } lr := machine.ListResponse{ - Name: name, - CreatedAt: mc.Created, - LastUp: mc.LastUp, - Running: state == machineDefine.Running, - Starting: mc.Starting, - //Stream: "", // No longer applicable + Name: name, + CreatedAt: mc.Created, + LastUp: mc.LastUp, + Running: state == machineDefine.Running, + Starting: mc.Starting, VMType: s.VMType().String(), CPUs: mc.Resources.CPUs, Memory: mc.Resources.Memory, + Swap: mc.Swap, DiskSize: mc.Resources.DiskSize, Port: mc.SSH.Port, RemoteUsername: mc.SSH.RemoteUsername, @@ -206,13 +204,13 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) error { VMType: mp.VMType(), WritePath: ignitionFile.GetPath(), Rootful: opts.Rootful, + Swap: opts.Swap, }) // If the user provides an ignition file, we need to // copy it into the conf dir if len(opts.IgnitionPath) > 0 { err = ignBuilder.BuildWithIgnitionFile(opts.IgnitionPath) - if err != nil { return err } diff --git a/pkg/machine/vmconfigs/config.go b/pkg/machine/vmconfigs/config.go index 67cd6fbcc1..7fd28ae577 100644 --- a/pkg/machine/vmconfigs/config.go +++ b/pkg/machine/vmconfigs/config.go @@ -27,6 +27,8 @@ type MachineConfig struct { SSH SSHConfig Version uint + Swap strongunits.MiB + // Image stuff imageDescription machineImage //nolint:unused diff --git a/pkg/machine/vmconfigs/machine.go b/pkg/machine/vmconfigs/machine.go index 42a7bfea89..bf20f47eba 100644 --- a/pkg/machine/vmconfigs/machine.go +++ b/pkg/machine/vmconfigs/machine.go @@ -81,6 +81,10 @@ func NewMachineConfig(opts define.InitOptions, dirs *define.MachineDirs, sshIden } mc.Resources = mrc + if opts.Swap > 0 { + mc.Swap = strongunits.MiB(opts.Swap) + } + sshPort, err := ports.AllocateMachinePort() if err != nil { return nil, err