Files
podman/pkg/machine/os/machine_os.go
Brent Baude aba2df7517 Add podman machine os upgrade command
Implements automatic OS upgrade functionality for Podman machines that requires no user input beyond running the command. The upgrade logic automatically determines the appropriate upgrade path using a three-way comparison between client version, machine version, and OCI registry:

* When the client version is older than the machine version, no action is taken and an error is returned.
* When the client version matches the machine version, the OCI registry is queried to check for in-band updates by comparing image digests.  This handles minor, patch level, and updates oci image use cases.
* When the client version is newer than the machine version, the machine is upgraded to match the client's major.minor version.
* No manual image selection or version specification required.

The command supports dry-run mode and JSON (only) output format for automation.

Signed-off-by: Brent Baude <bbaude@redhat.com>
2026-01-16 14:14:06 -06:00

71 lines
1.9 KiB
Go

//go:build amd64 || arm64
package os
import (
"context"
"fmt"
"github.com/containers/podman/v6/pkg/machine"
"github.com/containers/podman/v6/pkg/machine/shim"
"github.com/containers/podman/v6/pkg/machine/vmconfigs"
)
// MachineOS manages machine OS's from outside the machine.
type MachineOS struct {
Args []string
VM *vmconfigs.MachineConfig
Provider vmconfigs.VMProvider
VMName string
Restart bool
}
// Apply applies the image by sshing into the machine and running apply from inside the VM.
func (m *MachineOS) Apply(image string, _ ApplyOptions) error {
var off bool
args := []string{"podman", "machine", "os", "apply", image}
if err := machine.LocalhostSSHShellForceTerm(m.VM.SSH.RemoteUsername, m.VM.SSH.IdentityPath, m.VMName, m.VM.SSH.Port, args); err != nil {
return err
}
if m.Restart {
if err := shim.Stop(m.VM, m.Provider, off); err != nil {
return err
}
if err := shim.Start(m.VM, m.Provider, machine.StartOptions{NoInfo: true}, &off); err != nil {
return err
}
fmt.Printf("Machine %q restarted successfully\n", m.VMName)
}
return nil
}
func (m *MachineOS) Upgrade(_ context.Context, opts UpgradeOptions) error {
isDryRun := opts.DryRun
if len(opts.Format) > 0 {
isDryRun = true
}
args := []string{"podman", "machine", "os", "upgrade", "--host-version=" + opts.ClientVersion.String()}
if opts.DryRun {
args = append(args, "-n")
}
if opts.Format != "" {
args = append(args, "-f", opts.Format)
}
if err := machine.LocalhostSSHShellForceTerm(m.VM.SSH.RemoteUsername, m.VM.SSH.IdentityPath, m.VMName, m.VM.SSH.Port, args); err != nil {
return err
}
if m.Restart && !isDryRun {
var off bool
if err := shim.Stop(m.VM, m.Provider, off); err != nil {
return err
}
if err := shim.Start(m.VM, m.Provider, machine.StartOptions{NoInfo: true}, &off); err != nil {
return err
}
fmt.Printf("Machine %q restarted successfully\n", m.VMName)
}
return nil
}