diff --git a/cmd/containerd-shim-runhcs-v1/exec_hcs.go b/cmd/containerd-shim-runhcs-v1/exec_hcs.go index 0886ff19a5..d176986432 100644 --- a/cmd/containerd-shim-runhcs-v1/exec_hcs.go +++ b/cmd/containerd-shim-runhcs-v1/exec_hcs.go @@ -262,7 +262,7 @@ func (he *hcsExec) Kill(ctx context.Context, signal uint32) error { return nil case shimExecStateRunning: supported := false - if osversion.Get().Build >= osversion.RS5 { + if osversion.Build() >= osversion.RS5 { supported = he.host == nil || he.host.SignalProcessSupported() } var options interface{} diff --git a/cmd/containerd-shim-runhcs-v1/pod.go b/cmd/containerd-shim-runhcs-v1/pod.go index bdec1d4c75..73a3247998 100644 --- a/cmd/containerd-shim-runhcs-v1/pod.go +++ b/cmd/containerd-shim-runhcs-v1/pod.go @@ -55,7 +55,7 @@ type shimPod interface { func createPod(ctx context.Context, events publisher, req *task.CreateTaskRequest, s *specs.Spec) (shimPod, error) { log.G(ctx).WithField("tid", req.ID).Debug("createPod") - if osversion.Get().Build < osversion.RS5 { + if osversion.Build() < osversion.RS5 { return nil, errors.Wrapf(errdefs.ErrFailedPrecondition, "pod support is not available on Windows versions previous to RS5 (%d)", osversion.RS5) } diff --git a/cmd/containerd-shim-runhcs-v1/task_hcs.go b/cmd/containerd-shim-runhcs-v1/task_hcs.go index 438cb73985..ddbb2e7c5d 100644 --- a/cmd/containerd-shim-runhcs-v1/task_hcs.go +++ b/cmd/containerd-shim-runhcs-v1/task_hcs.go @@ -53,7 +53,7 @@ func newHcsStandaloneTask(ctx context.Context, events publisher, req *task.Creat owner := filepath.Base(os.Args[0]) var parent *uvm.UtilityVM - if osversion.Get().Build >= osversion.RS5 && oci.IsIsolated(s) { + if osversion.Build() >= osversion.RS5 && oci.IsIsolated(s) { // Create the UVM parent opts, err := oci.SpecToUVMCreateOpts(ctx, s, fmt.Sprintf("%s@vm", req.ID), owner) if err != nil { @@ -375,7 +375,7 @@ type hcsTask struct { // host is the hosting VM for this exec if hypervisor isolated. If // `host==nil` this is an Argon task so no UVM cleanup is required. // - // NOTE: if `osversion.Get().Build < osversion.RS5` this will always be + // NOTE: if `osversion.Build() < osversion.RS5` this will always be // `nil`. host *uvm.UtilityVM diff --git a/cmd/runhcs/container.go b/cmd/runhcs/container.go index ac5eb49bed..66b0bb9589 100644 --- a/cmd/runhcs/container.go +++ b/cmd/runhcs/container.go @@ -307,7 +307,7 @@ func createContainer(cfg *containerConfig) (_ *container, err error) { return nil, fmt.Errorf("host container %s is not a VM host", hostID) } hostUniqueID = host.UniqueID - } else if vmisolated && (isSandbox || cfg.Spec.Linux != nil || osversion.Get().Build >= osversion.RS5) { + } else if vmisolated && (isSandbox || cfg.Spec.Linux != nil || osversion.Build() >= osversion.RS5) { // This handles all LCOW, Pod Sandbox, and (Windows Xenon V2 for RS5+) hostID = cfg.ID newvm = true diff --git a/cmd/runhcs/create-scratch.go b/cmd/runhcs/create-scratch.go index 379ba646c6..78bb614171 100644 --- a/cmd/runhcs/create-scratch.go +++ b/cmd/runhcs/create-scratch.go @@ -43,7 +43,7 @@ var createScratchCommand = cli.Command{ return errors.New("'destpath' is required") } - if osversion.Get().Build < osversion.RS5 { + if osversion.Build() < osversion.RS5 { return errors.New("LCOW is not supported pre-RS5") } diff --git a/cmd/runhcs/kill.go b/cmd/runhcs/kill.go index d323d4edee..6edf9eaa4b 100644 --- a/cmd/runhcs/kill.go +++ b/cmd/runhcs/kill.go @@ -44,7 +44,7 @@ signal to the init process of the "ubuntu01" container: signalsSupported := false // The Signal feature was added in RS5 - if osversion.Get().Build >= osversion.RS5 { + if osversion.Build() >= osversion.RS5 { if c.IsHost || c.HostID != "" { var hostID string if c.IsHost { diff --git a/cmd/runhcs/prepare-disk.go b/cmd/runhcs/prepare-disk.go index 78dda8dbb9..6349e02911 100644 --- a/cmd/runhcs/prepare-disk.go +++ b/cmd/runhcs/prepare-disk.go @@ -39,7 +39,7 @@ var prepareDiskCommand = cli.Command{ return errors.New("'destpath' is required") } - if osversion.Get().Build < osversion.RS5 { + if osversion.Build() < osversion.RS5 { return errors.New("LCOW is not supported pre-RS5") } diff --git a/computestorage/setup.go b/computestorage/setup.go index ca7b40ef66..06aaf841e8 100644 --- a/computestorage/setup.go +++ b/computestorage/setup.go @@ -49,7 +49,7 @@ func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.H // // `options` are the options applied while processing the layer. func SetupBaseOSVolume(ctx context.Context, layerPath, volumePath string, options OsLayerOptions) (err error) { - if osversion.Get().Build < 19645 { + if osversion.Build() < 19645 { return errors.New("SetupBaseOSVolume is not present on builds older than 19645") } title := "hcsshim.SetupBaseOSVolume" diff --git a/internal/hcsoci/hcsdoc_wcow.go b/internal/hcsoci/hcsdoc_wcow.go index 439740fe9b..c183126c42 100644 --- a/internal/hcsoci/hcsdoc_wcow.go +++ b/internal/hcsoci/hcsdoc_wcow.go @@ -366,7 +366,7 @@ func createWindowsContainerDocument(ctx context.Context, coi *createOptionsInter } v1.MappedDirectories = mounts.mdsv1 v2Container.MappedDirectories = mounts.mdsv2 - if len(mounts.mpsv1) > 0 && osversion.Get().Build < osversion.RS3 { + if len(mounts.mpsv1) > 0 && osversion.Build() < osversion.RS3 { return nil, nil, fmt.Errorf("named pipe mounts are not supported on this version of Windows") } v1.MappedPipes = mounts.mpsv1 diff --git a/internal/schemaversion/schemaversion.go b/internal/schemaversion/schemaversion.go index fd2d40909b..aa9b6f774e 100644 --- a/internal/schemaversion/schemaversion.go +++ b/internal/schemaversion/schemaversion.go @@ -27,7 +27,7 @@ func IsSupported(sv *hcsschema.Version) error { return nil } if IsV21(sv) { - if osversion.Get().Build < osversion.RS5 { + if osversion.Build() < osversion.RS5 { return fmt.Errorf("unsupported on this Windows build") } return nil @@ -67,7 +67,7 @@ func String(sv *hcsschema.Version) string { // requested option. func DetermineSchemaVersion(requestedSV *hcsschema.Version) *hcsschema.Version { sv := SchemaV10() - if osversion.Get().Build >= osversion.RS5 { + if osversion.Build() >= osversion.RS5 { sv = SchemaV21() } if requestedSV != nil { diff --git a/internal/uvm/create.go b/internal/uvm/create.go index d688ef5733..cbcd4d84a1 100644 --- a/internal/uvm/create.go +++ b/internal/uvm/create.go @@ -145,11 +145,11 @@ func verifyOptions(ctx context.Context, options interface{}) error { return errors.New("PreferredRootFSTypeVHD requires at least one VPMem device") } } - if opts.KernelDirect && osversion.Get().Build < 18286 { + if opts.KernelDirect && osversion.Build() < 18286 { return errors.New("KernelDirectBoot is not supported on builds older than 18286") } - if opts.EnableColdDiscardHint && osversion.Get().Build < 18967 { + if opts.EnableColdDiscardHint && osversion.Build() < 18967 { return errors.New("EnableColdDiscardHint is not supported on builds older than 18967") } case *OptionsWCOW: diff --git a/internal/uvm/create_lcow.go b/internal/uvm/create_lcow.go index 0c4a301b2a..48f501d6db 100644 --- a/internal/uvm/create_lcow.go +++ b/internal/uvm/create_lcow.go @@ -97,7 +97,7 @@ func defaultLCOWOSBootFilesPath() string { // executable files name. func NewDefaultOptionsLCOW(id, owner string) *OptionsLCOW { // Use KernelDirect boot by default on all builds that support it. - kernelDirectSupported := osversion.Get().Build >= 18286 + kernelDirectSupported := osversion.Build() >= 18286 opts := &OptionsLCOW{ Options: newDefaultOptions(id, owner), BootFilesPath: defaultLCOWOSBootFilesPath(), diff --git a/internal/uvm/network.go b/internal/uvm/network.go index 04f4b9252a..65d7450b6b 100644 --- a/internal/uvm/network.go +++ b/internal/uvm/network.go @@ -512,7 +512,7 @@ func (uvm *UtilityVM) isNetworkNamespaceSupported() bool { } func getNetworkModifyRequest(adapterID string, requestType string, settings interface{}) interface{} { - if osversion.Get().Build >= osversion.RS5 { + if osversion.Build() >= osversion.RS5 { return guestrequest.NetworkModifyRequest{ AdapterId: adapterID, RequestType: requestType, diff --git a/internal/uvm/plan9.go b/internal/uvm/plan9.go index 684c173dc6..cd8408479a 100644 --- a/internal/uvm/plan9.go +++ b/internal/uvm/plan9.go @@ -34,7 +34,7 @@ func (uvm *UtilityVM) AddPlan9(ctx context.Context, hostPath string, uvmPath str if uvm.operatingSystem != "linux" { return nil, errNotSupported } - if restrict && osversion.Get().Build < osversion.V19H1 { + if restrict && osversion.Build() < osversion.V19H1 { return nil, errors.New("single-file mappings are not supported on this build of Windows") } if uvmPath == "" { diff --git a/internal/uvm/vsmb.go b/internal/uvm/vsmb.go index 85692d8824..1f29fbd0bf 100644 --- a/internal/uvm/vsmb.go +++ b/internal/uvm/vsmb.go @@ -134,7 +134,7 @@ func openHostPath(path string) (windows.Handle, error) { // To work around this, we attempt to query for FileIdInfo ourselves if on an affected build. If // the query fails, we override the specified options to force no direct map to be used. func forceNoDirectMap(path string) (bool, error) { - if ver := osversion.Get().Build; ver < osversion.V19H1 || ver > osversion.V20H2 { + if ver := osversion.Build(); ver < osversion.V19H1 || ver > osversion.V20H2 { return false, nil } h, err := openHostPath(path) diff --git a/internal/wclayer/expandscratchsize.go b/internal/wclayer/expandscratchsize.go index 93f27da8a0..22f7605bee 100644 --- a/internal/wclayer/expandscratchsize.go +++ b/internal/wclayer/expandscratchsize.go @@ -30,7 +30,7 @@ func ExpandScratchSize(ctx context.Context, path string, size uint64) (err error // Manually expand the volume now in order to work around bugs in 19H1 and // prerelease versions of Vb. Remove once this is fixed in Windows. - if build := osversion.Get().Build; build >= osversion.V19H1 && build < 19020 { + if build := osversion.Build(); build >= osversion.V19H1 && build < 19020 { err = expandSandboxVolume(ctx, path) if err != nil { return err diff --git a/osversion/osversion_windows.go b/osversion/osversion_windows.go index 42e58403de..3ab3bcd89a 100644 --- a/osversion/osversion_windows.go +++ b/osversion/osversion_windows.go @@ -2,6 +2,7 @@ package osversion import ( "fmt" + "sync" "golang.org/x/sys/windows" ) @@ -15,19 +16,26 @@ type OSVersion struct { Build uint16 } +var ( + osv OSVersion + once sync.Once +) + // Get gets the operating system version on Windows. // The calling application must be manifested to get the correct version information. func Get() OSVersion { - var err error - osv := OSVersion{} - osv.Version, err = windows.GetVersion() - if err != nil { - // GetVersion never fails. - panic(err) - } - osv.MajorVersion = uint8(osv.Version & 0xFF) - osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF) - osv.Build = uint16(osv.Version >> 16) + once.Do(func() { + var err error + osv = OSVersion{} + osv.Version, err = windows.GetVersion() + if err != nil { + // GetVersion never fails. + panic(err) + } + osv.MajorVersion = uint8(osv.Version & 0xFF) + osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF) + osv.Build = uint16(osv.Version >> 16) + }) return osv } diff --git a/test/cri-containerd/container_virtual_device_test.go b/test/cri-containerd/container_virtual_device_test.go index e5762642aa..cc51599175 100644 --- a/test/cri-containerd/container_virtual_device_test.go +++ b/test/cri-containerd/container_virtual_device_test.go @@ -200,7 +200,7 @@ func getGPUContainerRequestWCOW(t *testing.T, podID string, podConfig *runtime.P func Test_RunContainer_VirtualDevice_GPU_LCOW(t *testing.T) { requireFeatures(t, featureLCOW, featureGPU) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } @@ -240,7 +240,7 @@ func Test_RunContainer_VirtualDevice_GPU_LCOW(t *testing.T) { func Test_RunContainer_VirtualDevice_GPU_Multiple_LCOW(t *testing.T) { requireFeatures(t, featureLCOW, featureGPU) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } @@ -289,7 +289,7 @@ func Test_RunContainer_VirtualDevice_GPU_Multiple_LCOW(t *testing.T) { func Test_RunContainer_VirtualDevice_GPU_and_NoGPU_LCOW(t *testing.T) { requireFeatures(t, featureLCOW, featureGPU) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } @@ -358,7 +358,7 @@ func Test_RunContainer_VirtualDevice_GPU_and_NoGPU_LCOW(t *testing.T) { func Test_RunContainer_VirtualDevice_GPU_Multiple_Removal_LCOW(t *testing.T) { requireFeatures(t, featureLCOW, featureGPU) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } @@ -486,7 +486,7 @@ func Test_RunContainer_VirtualDevice_ClassGUID_WCOW_Process(t *testing.T) { func Test_RunContainer_VirtualDevice_GPU_WCOW_Hypervisor(t *testing.T) { requireFeatures(t, featureWCOWHypervisor, featureGPU) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } @@ -531,7 +531,7 @@ func Test_RunContainer_VirtualDevice_GPU_WCOW_Hypervisor(t *testing.T) { func Test_RunContainer_VirtualDevice_GPU_and_NoGPU_WCOW_Hypervisor(t *testing.T) { requireFeatures(t, featureWCOWHypervisor, featureGPU) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } @@ -592,7 +592,7 @@ func Test_RunContainer_VirtualDevice_GPU_and_NoGPU_WCOW_Hypervisor(t *testing.T) func Test_RunContainer_VirtualDevice_GPU_Multiple_WCOW_Hypervisor(t *testing.T) { requireFeatures(t, featureWCOWHypervisor, featureGPU) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } @@ -645,7 +645,7 @@ func Test_RunContainer_VirtualDevice_GPU_Multiple_WCOW_Hypervisor(t *testing.T) func Test_RunContainer_VirtualDevice_GPU_Multiple_Removal_WCOW_Hypervisor(t *testing.T) { requireFeatures(t, featureWCOWHypervisor, featureGPU) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } diff --git a/test/cri-containerd/main.go b/test/cri-containerd/main.go index 5cd219d220..ab281178a6 100644 --- a/test/cri-containerd/main.go +++ b/test/cri-containerd/main.go @@ -57,8 +57,8 @@ const ( // Image definitions var ( - imageWindowsNanoserver = getWindowsNanoserverImage(osversion.Get().Build) - imageWindowsServercore = getWindowsServerCoreImage(osversion.Get().Build) + imageWindowsNanoserver = getWindowsNanoserverImage(osversion.Build()) + imageWindowsServercore = getWindowsServerCoreImage(osversion.Build()) imageWindowsNanoserver17763 = getWindowsNanoserverImage(osversion.RS5) imageWindowsNanoserver18362 = getWindowsNanoserverImage(osversion.V19H1) imageWindowsNanoserver19041 = getWindowsNanoserverImage(osversion.V20H1) diff --git a/test/cri-containerd/runpodsandbox_test.go b/test/cri-containerd/runpodsandbox_test.go index 6ba364bead..8a50668537 100644 --- a/test/cri-containerd/runpodsandbox_test.go +++ b/test/cri-containerd/runpodsandbox_test.go @@ -260,7 +260,7 @@ func Test_RunPodSandbox_MemorySize_LCOW(t *testing.T) { func Test_RunPodSandbox_MMIO_WCOW_Process(t *testing.T) { requireFeatures(t, featureWCOWProcess) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } pullRequiredImages(t, []string{imageWindowsNanoserver}) @@ -277,7 +277,7 @@ func Test_RunPodSandbox_MMIO_WCOW_Process(t *testing.T) { func Test_RunPodSandbox_MMIO_WCOW_Hypervisor(t *testing.T) { requireFeatures(t, featureWCOWHypervisor) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } pullRequiredImages(t, []string{imageWindowsNanoserver}) @@ -294,7 +294,7 @@ func Test_RunPodSandbox_MMIO_WCOW_Hypervisor(t *testing.T) { func Test_RunPodSandbox_MMIO_LCOW(t *testing.T) { requireFeatures(t, featureLCOW) - if osversion.Get().Build < osversion.V20H1 { + if osversion.Build() < osversion.V20H1 { t.Skip("Requires build +20H1") } pullRequiredLcowImages(t, []string{imageLcowK8sPause}) @@ -917,7 +917,7 @@ func Test_RunPodSandbox_MultipleContainersSameVhd_WCOW(t *testing.T) { requireFeatures(t, featureWCOWHypervisor) // Prior to 19H1, we aren't able to easily create a formatted VHD, as // HcsFormatWritableLayerVhd requires the VHD to be mounted prior the call. - if osversion.Get().Build < osversion.V19H1 { + if osversion.Build() < osversion.V19H1 { t.Skip("Requires at least 19H1") } diff --git a/test/functional/utilities/requiresbuild.go b/test/functional/utilities/requiresbuild.go index fb0d79396d..47930994d0 100644 --- a/test/functional/utilities/requiresbuild.go +++ b/test/functional/utilities/requiresbuild.go @@ -7,13 +7,13 @@ import ( ) func RequiresBuild(t *testing.T, b uint16) { - if osversion.Get().Build < b { + if osversion.Build() < b { t.Skipf("Requires build %d+", b) } } func RequiresExactBuild(t *testing.T, b uint16) { - if osversion.Get().Build != b { + if osversion.Build() != b { t.Skipf("Requires exact build %d", b) } }