Skip to content

Commit 412dd22

Browse files
author
Shreyansh Sancheti
committed
parity: add LCOW document permutation tests
Restructure parity test framework and add permutation-based tests for LCOW HCS document creation comparing legacy and v2 builder outputs. Signed-off-by: Shreyansh Sancheti <shreyanshjain7174@gmail.com> Signed-off-by: Shreyansh Sancheti <shsancheti@microsoft.com>
1 parent 372f3f6 commit 412dd22

5 files changed

Lines changed: 439 additions & 32 deletions

File tree

internal/uvm/create_lcow.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ func makeLCOWVMGSDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_
458458
// This is done prior to json seriaisation and sending to the HCS layer to actually do the work of creating the VM.
459459
// Many details are quite different (see the typical JSON examples), in particular it boots from a VMGS file
460460
// which contains both the kernel and initrd as well as kernel boot options.
461-
func makeLCOWSecurityDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcsschema.ComputeSystem, err error) {
461+
func MakeLCOWSecurityDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcsschema.ComputeSystem, err error) {
462462
doc, vmgsErr := makeLCOWVMGSDoc(ctx, opts, uvm)
463463
if vmgsErr != nil {
464464
return nil, vmgsErr
@@ -938,7 +938,7 @@ func CreateLCOW(ctx context.Context, opts *OptionsLCOW) (_ *UtilityVM, err error
938938
// HCS config for SNP isolated vm is quite different to the usual case
939939
var doc *hcsschema.ComputeSystem
940940
if opts.SecurityPolicyEnabled {
941-
doc, err = makeLCOWSecurityDoc(ctx, opts, uvm)
941+
doc, err = MakeLCOWSecurityDoc(ctx, opts, uvm)
942942
if logrus.IsLevelEnabled(logrus.TraceLevel) {
943943
log.G(ctx).WithFields(logrus.Fields{
944944
"doc": log.Format(ctx, doc),

internal/uvm/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ func (uvm *UtilityVM) ScratchEncryptionEnabled() bool {
154154
}
155155

156156
// NewUtilityVMForDoc creates a minimal UtilityVM with the fields needed by
157-
// MakeLCOWDoc for HCS document generation in parity tests.
158-
// UtilityVM fields are unexported, so this constructor must live in the uvm package.
157+
// MakeLCOWDoc and MakeLCOWSecurityDoc for HCS document generation. This is
158+
// not a runnable VM — it exists only for parity testing.
159159
func NewUtilityVMForDoc(id, owner string, scsiControllerCount, vpmemMaxCount uint32, vpmemMaxSizeBytes uint64, vpmemMultiMapping bool) *UtilityVM {
160160
return &UtilityVM{
161161
id: id,

test/parity/vm/doc.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
//go:build windows
22

3-
// Package vmparity validates that the v2 modular VM document builders produce
4-
// HCS ComputeSystem documents equivalent to the legacy shim pipelines.
3+
// Package vm validates that the v2 VM document builders produce HCS
4+
// ComputeSystem documents equivalent to the legacy shim pipelines.
55
//
6-
// Currently covers LCOW; WCOW parity will be added in a future PR.
6+
// Currently covers LCOW parity between:
7+
// - Legacy: OCI spec → oci.UpdateSpecFromOptions → oci.ProcessAnnotations →
8+
// oci.SpecToUVMCreateOpts → uvm.MakeLCOWDoc → *hcsschema.ComputeSystem
9+
// - V2: vm.Spec + runhcsopts.Options → lcow.BuildSandboxConfig →
10+
// *hcsschema.ComputeSystem + *SandboxOptions
11+
//
12+
// WCOW parity will be added in a future PR.
713
package vmparity

test/parity/vm/hcs_lcow_document_creator_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import (
88
"fmt"
99
"os"
1010
"path/filepath"
11+
"strings"
1112
"testing"
1213

14+
"github.com/google/go-cmp/cmp"
1315
"github.com/opencontainers/runtime-spec/specs-go"
1416

1517
runhcsopts "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
@@ -111,3 +113,70 @@ func jsonToString(v interface{}) string {
111113
}
112114
return string(b)
113115
}
116+
117+
// normalizeKernelCmdLine trims leading/trailing whitespace from the kernel
118+
// command line in the document. The legacy builder has a minor quirk that
119+
// produces a leading space for initrd+KernelDirect boot. The v2 builder
120+
// does not. Since HCS trims whitespace from kernel args, this difference
121+
// is harmless and we normalize it away.
122+
func normalizeKernelCmdLine(doc *hcsschema.ComputeSystem) {
123+
if doc == nil || doc.VirtualMachine == nil || doc.VirtualMachine.Chipset == nil {
124+
return
125+
}
126+
if kd := doc.VirtualMachine.Chipset.LinuxKernelDirect; kd != nil {
127+
kd.KernelCmdLine = strings.TrimSpace(kd.KernelCmdLine)
128+
}
129+
if uefi := doc.VirtualMachine.Chipset.Uefi; uefi != nil && uefi.BootThis != nil {
130+
uefi.BootThis.OptionalData = strings.TrimSpace(uefi.BootThis.OptionalData)
131+
}
132+
}
133+
134+
// isOnlyKernelCmdLineWhitespaceDiff returns true if the only difference between
135+
// two documents is leading/trailing whitespace in the kernel command line.
136+
func isOnlyKernelCmdLineWhitespaceDiff(legacy, v2 *hcsschema.ComputeSystem) bool {
137+
legacyCopy := *legacy
138+
v2Copy := *v2
139+
if legacyCopy.VirtualMachine != nil {
140+
vmCopy := *legacyCopy.VirtualMachine
141+
legacyCopy.VirtualMachine = &vmCopy
142+
if vmCopy.Chipset != nil {
143+
chipCopy := *vmCopy.Chipset
144+
legacyCopy.VirtualMachine.Chipset = &chipCopy
145+
if chipCopy.LinuxKernelDirect != nil {
146+
lkdCopy := *chipCopy.LinuxKernelDirect
147+
legacyCopy.VirtualMachine.Chipset.LinuxKernelDirect = &lkdCopy
148+
}
149+
if chipCopy.Uefi != nil {
150+
uefiCopy := *chipCopy.Uefi
151+
legacyCopy.VirtualMachine.Chipset.Uefi = &uefiCopy
152+
if uefiCopy.BootThis != nil {
153+
btCopy := *uefiCopy.BootThis
154+
legacyCopy.VirtualMachine.Chipset.Uefi.BootThis = &btCopy
155+
}
156+
}
157+
}
158+
}
159+
if v2Copy.VirtualMachine != nil {
160+
vmCopy := *v2Copy.VirtualMachine
161+
v2Copy.VirtualMachine = &vmCopy
162+
if vmCopy.Chipset != nil {
163+
chipCopy := *vmCopy.Chipset
164+
v2Copy.VirtualMachine.Chipset = &chipCopy
165+
if chipCopy.LinuxKernelDirect != nil {
166+
lkdCopy := *chipCopy.LinuxKernelDirect
167+
v2Copy.VirtualMachine.Chipset.LinuxKernelDirect = &lkdCopy
168+
}
169+
if chipCopy.Uefi != nil {
170+
uefiCopy := *chipCopy.Uefi
171+
v2Copy.VirtualMachine.Chipset.Uefi = &uefiCopy
172+
if uefiCopy.BootThis != nil {
173+
btCopy := *uefiCopy.BootThis
174+
v2Copy.VirtualMachine.Chipset.Uefi.BootThis = &btCopy
175+
}
176+
}
177+
}
178+
}
179+
normalizeKernelCmdLine(&legacyCopy)
180+
normalizeKernelCmdLine(&v2Copy)
181+
return cmp.Diff(&legacyCopy, &v2Copy) == ""
182+
}

0 commit comments

Comments
 (0)