mirror of
https://github.com/lima-vm/lima.git
synced 2026-10-28 11:44:35 +08:00
Merge pull request #5528 from trodemaster/feat/vz-guest-os-version-log
feat(vz): record the guest macOS version from the restore image
This commit is contained in:
9 files changed
+131
-4
No files matched your search
@@ -66,6 +66,8 @@ LIMA_CIDATA_SKIP_DEFAULT_DEPENDENCY_RESOLUTION=
|
||||
LIMA_CIDATA_VMTYPE={{ .VMType }}
|
||||
LIMA_CIDATA_VSOCK_PORT={{ .VSockPort }}
|
||||
LIMA_CIDATA_VIRTIO_PORT={{ .VirtioPort}}
|
||||
LIMA_CIDATA_GUEST_OS_VERSION={{ .GuestOSVersion }}
|
||||
LIMA_CIDATA_GUEST_OS_BUILD_VERSION={{ .GuestOSBuildVersion }}
|
||||
{{- if .Plain}}
|
||||
LIMA_CIDATA_PLAIN=1
|
||||
{{- else}}
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/lima-vm/lima/v2/pkg/networks/usernet"
|
||||
"github.com/lima-vm/lima/v2/pkg/osutil"
|
||||
"github.com/lima-vm/lima/v2/pkg/sshutil"
|
||||
"github.com/lima-vm/lima/v2/pkg/store"
|
||||
"github.com/lima-vm/lima/v2/pkg/strutil"
|
||||
)
|
||||
|
||||
@@ -125,10 +126,12 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
|
||||
}
|
||||
archive := "nerdctl-full.tgz"
|
||||
var darwinOpts limatype.DarwinOpts
|
||||
var guestOSVersion, guestOSBuildVersion string
|
||||
if *instConfig.OS == limatype.DARWIN {
|
||||
if err := limayaml.Convert(instConfig.OsOpts[limatype.DARWIN], &darwinOpts, "osOpts.Darwin"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
guestOSVersion, guestOSBuildVersion = store.ReadGuestOSVersion(instDir)
|
||||
}
|
||||
var suppressFirstLoginSetupPlist string
|
||||
if darwinOpts.SuppressFirstLoginSetupPlist != nil {
|
||||
@@ -166,6 +169,8 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
|
||||
|
||||
SuppressFirstLoginSetup: darwinOpts.SuppressFirstLoginSetup != nil && *darwinOpts.SuppressFirstLoginSetup,
|
||||
SuppressFirstLoginSetupPlist: suppressFirstLoginSetupPlist,
|
||||
GuestOSVersion: guestOSVersion,
|
||||
GuestOSBuildVersion: guestOSBuildVersion,
|
||||
}
|
||||
|
||||
firstUsernetIndex := limayaml.FirstUsernetIndex(instConfig)
|
||||
|
||||
@@ -139,6 +139,8 @@ type TemplateArgs struct {
|
||||
TPM bool
|
||||
SuppressFirstLoginSetup bool
|
||||
SuppressFirstLoginSetupPlist string // empty = use built-in plist
|
||||
GuestOSVersion string // macOS guests only: restore-image OS version, e.g. "27.0.0"; empty otherwise
|
||||
GuestOSBuildVersion string // macOS guests only: restore-image build, e.g. "26A428"; empty otherwise
|
||||
}
|
||||
|
||||
func (t *TemplateArgs) generateWindowsInitialPassword() error {
|
||||
|
||||
@@ -6,11 +6,13 @@ package cidata
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"github.com/lima-vm/lima/v2/pkg/iso9660util"
|
||||
"github.com/lima-vm/lima/v2/pkg/limatype"
|
||||
)
|
||||
|
||||
@@ -172,6 +174,42 @@ func TestTemplate9p(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateGuestOSVersion(t *testing.T) {
|
||||
args := &TemplateArgs{
|
||||
Name: "default",
|
||||
User: "foo",
|
||||
UID: 501,
|
||||
Home: "/home/foo.guest",
|
||||
Shell: "/bin/bash",
|
||||
SSHPubKeys: []string{"ssh-rsa dummy foo@example.com"},
|
||||
MountType: "reverse-sshfs",
|
||||
OS: "Darwin",
|
||||
GuestOSVersion: "27.0.0",
|
||||
GuestOSBuildVersion: "26A428",
|
||||
}
|
||||
limaEnv := renderLimaEnv(t, args)
|
||||
assert.Assert(t, strings.Contains(limaEnv, "LIMA_CIDATA_GUEST_OS_VERSION=27.0.0\n"))
|
||||
assert.Assert(t, strings.Contains(limaEnv, "LIMA_CIDATA_GUEST_OS_BUILD_VERSION=26A428\n"))
|
||||
|
||||
// Emitted empty when unknown, like the other optional LIMA_CIDATA_* vars.
|
||||
args.GuestOSVersion = ""
|
||||
args.GuestOSBuildVersion = ""
|
||||
limaEnv = renderLimaEnv(t, args)
|
||||
assert.Assert(t, strings.Contains(limaEnv, "LIMA_CIDATA_GUEST_OS_VERSION=\n"))
|
||||
assert.Assert(t, strings.Contains(limaEnv, "LIMA_CIDATA_GUEST_OS_BUILD_VERSION=\n"))
|
||||
}
|
||||
|
||||
func renderLimaEnv(t *testing.T, args *TemplateArgs) string {
|
||||
t.Helper()
|
||||
layout, err := ExecuteTemplateCIDataISO(args)
|
||||
assert.NilError(t, err)
|
||||
idx := slices.IndexFunc(layout, func(f iso9660util.Entry) bool { return f.Path == "lima.env" })
|
||||
assert.Assert(t, idx >= 0, "lima.env not found in cidata layout")
|
||||
b, err := io.ReadAll(layout[idx].Reader)
|
||||
assert.NilError(t, err)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// TestTemplateNICRename is a regression test for
|
||||
// https://github.com/lima-vm/lima/issues/4792 (Ubuntu 26.04 first-boot NIC
|
||||
// rename race, LP: #2136392): user-data must contain the rename/wait bootcmd,
|
||||
|
||||
@@ -65,6 +65,17 @@ func newMacPlatformConfiguration(inst *limatype.Instance) (vz.PlatformConfigurat
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Record the guest macOS version too: the IPSW is removed after
|
||||
// installation, so this is the only point where it can be read.
|
||||
osVersion := ipswImage.OperatingSystemVersion().String()
|
||||
buildVersion := ipswImage.BuildVersion()
|
||||
logrus.Infof("Guest macOS version: %s (build %s)", osVersion, buildVersion)
|
||||
if err = os.WriteFile(filepath.Join(inst.Dir, filenames.VzGuestOSVersion), []byte(osVersion+"\n"), 0o644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = os.WriteFile(filepath.Join(inst.Dir, filenames.VzGuestOSBuildVersion), []byte(buildVersion+"\n"), 0o644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipswMostFeatureFul := ipswImage.MostFeaturefulSupportedConfiguration()
|
||||
hwModelData = ipswMostFeatureFul.HardwareModel().DataRepresentation()
|
||||
if err = os.WriteFile(hwModelFile, hwModelData, 0o666); err != nil {
|
||||
|
||||
@@ -69,10 +69,12 @@ const (
|
||||
ExternalDriverStderrLog = "driver.stderr.log"
|
||||
BootSession = "boot-session.tmp" // boot of the host during which the PID files in the same directory were written
|
||||
VzIdentifier = "vz-identifier"
|
||||
VzHwModel = "vz-hwmodel" // macOS guests only
|
||||
VzAux = "vz-aux" // macOS guests only
|
||||
VzEfi = "vz-efi" // efi variable store
|
||||
QemuEfiCodeFD = "qemu-efi-code.fd" // efi code; not always created
|
||||
VzHwModel = "vz-hwmodel" // macOS guests only
|
||||
VzGuestOSVersion = "vz-guest-os-version" // macOS guests only; restore-image OS version, e.g. "27.0.0"
|
||||
VzGuestOSBuildVersion = "vz-guest-os-build-version" // macOS guests only; restore-image build, e.g. "26A428"
|
||||
VzAux = "vz-aux" // macOS guests only
|
||||
VzEfi = "vz-efi" // efi variable store
|
||||
QemuEfiCodeFD = "qemu-efi-code.fd" // efi code; not always created
|
||||
AnsibleInventoryYAML = "ansible-inventory.yaml"
|
||||
|
||||
// SocketDir is the default location for forwarded sockets with a relative paths in HostSocket.
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: Copyright The Lima Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
|
||||
)
|
||||
|
||||
// ReadGuestOSVersion returns the macOS version (e.g. "27.0.0") and build
|
||||
// version (e.g. "26A428") of the restore image that a macOS guest on the vz
|
||||
// driver was installed from. Both are empty when unknown: for non-macOS guests,
|
||||
// and for instances installed before the version was recorded.
|
||||
func ReadGuestOSVersion(instDir string) (version, buildVersion string) {
|
||||
return readOptionalFile(filepath.Join(instDir, filenames.VzGuestOSVersion)),
|
||||
readOptionalFile(filepath.Join(instDir, filenames.VzGuestOSBuildVersion))
|
||||
}
|
||||
|
||||
func readOptionalFile(path string) string {
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
logrus.WithError(err).Warnf("Failed to read %#q", path)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(string(b))
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// SPDX-FileCopyrightText: Copyright The Lima Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
|
||||
)
|
||||
|
||||
func TestReadGuestOSVersion(t *testing.T) {
|
||||
instDir := t.TempDir()
|
||||
|
||||
version, buildVersion := ReadGuestOSVersion(instDir)
|
||||
assert.Equal(t, version, "")
|
||||
assert.Equal(t, buildVersion, "")
|
||||
|
||||
assert.NilError(t, os.WriteFile(filepath.Join(instDir, filenames.VzGuestOSVersion), []byte("27.0.0\n"), 0o644))
|
||||
assert.NilError(t, os.WriteFile(filepath.Join(instDir, filenames.VzGuestOSBuildVersion), []byte("26A428\n"), 0o644))
|
||||
version, buildVersion = ReadGuestOSVersion(instDir)
|
||||
assert.Equal(t, version, "27.0.0")
|
||||
assert.Equal(t, buildVersion, "26A428")
|
||||
}
|
||||
@@ -73,6 +73,8 @@ VZ:
|
||||
- `vz.pid`: VZ PID
|
||||
- `vz-identifier`: Unique machine identifier file for a VM
|
||||
- `vz-hwmodel`: Hardware model information for a Mac VM
|
||||
- `vz-guest-os-version`: macOS version of the restore image a Mac VM was created from, e.g. `27.0.0` (written once, at create time)
|
||||
- `vz-guest-os-build-version`: build number of that restore image, e.g. `26A428`
|
||||
- `vz-aux`: Auxiliary storage for a Mac VM
|
||||
- `vz-efi`: EFIVariable store file for a VM
|
||||
|
||||
@@ -233,6 +235,8 @@ The volume label is "cidata", as defined by [cloud-init NoCloud](https://docs.cl
|
||||
- `LIMA_CIDATA_VMTYPE`: the VM driver type ("qemu", "vz", "wsl2", ...), used to conditionally enable VM-specific behavior (e.g. virtiofs mounts on `vz`).
|
||||
- `LIMA_CIDATA_VSOCK_PORT`: the vsock port used by the guest agent (0 when vsock is not used).
|
||||
- `LIMA_CIDATA_VIRTIO_PORT`: the virtio-serial port name used by the guest agent (empty when virtio-serial is not used).
|
||||
- `LIMA_CIDATA_GUEST_OS_VERSION`: for macOS guests on the `vz` driver, the macOS version of the restore image the instance was created from, e.g. `27.0.0`. Empty for other guests and for instances created before this was recorded.
|
||||
- `LIMA_CIDATA_GUEST_OS_BUILD_VERSION`: the corresponding build number, e.g. `26A428`. Empty in the same cases.
|
||||
- `LIMA_CIDATA_PLAIN`: set to "1" when the instance is in [plain mode](../config/plain.md) (no mounts, port forwarding, or containerd), empty otherwise.
|
||||
- `LIMA_CIDATA_NO_CLOUD_INIT`: set to "1" if cloud-init should be skipped on this boot, empty otherwise.
|
||||
|
||||
|
||||
Reference in new issue
Block a user