Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Un-hardcode list of Windows versions #166

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions ue4docker/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,8 @@ def build():
logger.error('https://unrealcontainers.com/docs/concepts/windows-containers', False)
sys.exit(1)

# Verify that the user is not attempting to build images with a newer kernel version than the host OS
if WindowsUtils.isNewerBaseTag(config.hostBasetag, config.basetag):
logger.error('Error: cannot build container images with a newer kernel version than that of the host OS!')
sys.exit(1)

# Check if the user is building a different kernel version to the host OS but is still copying DLLs from System32
differentKernels = WindowsUtils.isInsiderPreview() or config.basetag != config.hostBasetag
differentKernels = config.basetag != config.hostBasetag
if config.pullPrerequisites == False and differentKernels == True and config.dlldir == config.defaultDllDir:
logger.error('Error: building images with a different kernel version than the host,', False)
logger.error('but a custom DLL directory has not specified via the `-dlldir=DIR` arg.', False)
Expand Down
3 changes: 1 addition & 2 deletions ue4docker/diagnostics/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ def _generateWindowsBuildArgs(self, logger, basetagOverride=None, isolationOverr
'''

# Determine the appropriate container image base tag for the host system release unless the user specified a base tag
buildArgs = []
defaultBaseTag = WindowsUtils.getReleaseBaseTag(WindowsUtils.getWindowsRelease())
defaultBaseTag = WindowsUtils.getWindowsRelease()
baseTag = basetagOverride if basetagOverride is not None else defaultBaseTag
buildArgs = ['--build-arg', 'BASETAG={}'.format(baseTag)]

Expand Down
15 changes: 8 additions & 7 deletions ue4docker/infrastructure/BuildConfiguration.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,29 +228,30 @@ def _generateWindowsConfig(self):
self.dlldir = self.args.dlldir if self.args.dlldir is not None else self.defaultDllDir

# Determine base tag for the Windows release of the host system
self.hostRelease = WindowsUtils.getWindowsRelease()
self.hostBasetag = WindowsUtils.getReleaseBaseTag(self.hostRelease)
self.hostBasetag = WindowsUtils.getWindowsRelease()

# Store the tag for the base Windows Server Core image
self.basetag = self.args.basetag if self.args.basetag is not None else self.hostBasetag
self.baseImage = 'mcr.microsoft.com/windows/servercore:' + self.basetag
self.prereqsTag = self.basetag

validBaseTags = WindowsUtils.getValidBaseTags()

# Verify that any user-specified base tag is valid
if WindowsUtils.isValidBaseTag(self.basetag) == False:
raise RuntimeError('unrecognised Windows Server Core base image tag "{}", supported tags are {}'.format(self.basetag, WindowsUtils.getValidBaseTags()))
if self.basetag not in validBaseTags:
raise RuntimeError('unrecognised Windows Server Core base image tag "{}", supported tags are {}'.format(self.basetag, validBaseTags))

# Verify that any user-specified tag suffix does not collide with our base tags
if WindowsUtils.isValidBaseTag(self.suffix) == True:
raise RuntimeError('tag suffix cannot be any of the Windows Server Core base image tags: {}'.format(WindowsUtils.getValidBaseTags()))
if self.suffix in validBaseTags:
raise RuntimeError('tag suffix cannot be any of the Windows Server Core base image tags: {}'.format(validBaseTags))

# If the user has explicitly specified an isolation mode then use it, otherwise auto-detect
if self.args.isolation is not None:
self.isolation = self.args.isolation
else:

# If we are able to use process isolation mode then use it, otherwise fallback to the Docker daemon's default isolation mode
differentKernels = WindowsUtils.isInsiderPreview() or self.basetag != self.hostBasetag
differentKernels = self.basetag != self.hostBasetag
hostSupportsProcess = WindowsUtils.supportsProcessIsolation()
dockerSupportsProcess = parse_version(DockerUtils.version()['Version']) >= parse_version('18.09.0')
if not differentKernels and hostSupportsProcess and dockerSupportsProcess:
Expand Down
61 changes: 9 additions & 52 deletions ue4docker/infrastructure/WindowsUtils.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
from .DockerUtils import DockerUtils
from pkg_resources import parse_version
import platform, sys
import platform, requests, sys

if platform.system() == 'Windows':
import winreg

class WindowsUtils(object):

# The latest Windows build version we recognise as a non-Insider build
_latestReleaseBuild = 19042

# The list of Windows Server Core base image tags that we recognise, in ascending version number order
_validTags = ['ltsc2016', '1709', '1803', 'ltsc2019', '1903', '1909', '2004', '20H2']

# The list of Windows Server and Windows 10 host OS releases that are blacklisted due to critical bugs
# (See: <https://unrealcontainers.com/docs/concepts/windows-containers>)
_blacklistedReleases = ['1903', '1909']
Expand Down Expand Up @@ -76,7 +70,13 @@ def getWindowsRelease() -> str:
'''
Determines the Windows 10 / Windows Server release (1607, 1709, 1803, etc.) of the Windows host system
'''
return WindowsUtils._getVersionRegKey('ReleaseId')
try:
# Starting with Windows 20H2 (also known as 2009), Microsoft stopped updating ReleaseId
# and instead updates DisplayVersion
return WindowsUtils._getVersionRegKey('DisplayVersion')
except FileNotFoundError:
# Fallback to ReleaseId for pre-20H2 releases that didn't have DisplayVersion
return WindowsUtils._getVersionRegKey('ReleaseId')

@staticmethod
def getWindowsBuild() -> int:
Expand Down Expand Up @@ -112,55 +112,12 @@ def isWindowsServer() -> bool:
# TODO: Replace this with something more reliable
return 'Windows Server' in WindowsUtils._getVersionRegKey('ProductName')

@staticmethod
def isInsiderPreview() -> bool:
'''
Determines if the Windows host system is a Windows Insider preview build
'''
return WindowsUtils.getWindowsBuild() > WindowsUtils._latestReleaseBuild

@staticmethod
def getReleaseBaseTag(release: str) -> str:
'''
Retrieves the tag for the Windows Server Core base image matching the specified Windows 10 / Windows Server release
'''

# For Windows Insider preview builds, build the latest release tag
if WindowsUtils.isInsiderPreview():
return WindowsUtils._validTags[-1]

# This lookup table is based on the list of valid tags from <https://hub.docker.com/r/microsoft/windowsservercore/>
return {
'1709': '1709',
'1803': '1803',
'1809': 'ltsc2019',
'1903': '1903',
'1909': '1909',
'2004': '2004',
'2009': '20H2',
'20H2': '20H2'
}.get(release, 'ltsc2016')

@staticmethod
def getValidBaseTags() -> [str]:
'''
Returns the list of valid tags for the Windows Server Core base image, in ascending chronological release order
'''
return WindowsUtils._validTags

@staticmethod
def isValidBaseTag(tag: str) -> bool:
'''
Determines if the specified tag is a valid Windows Server Core base image tag
'''
return tag in WindowsUtils._validTags

@staticmethod
def isNewerBaseTag(older: str, newer: str) -> bool:
'''
Determines if the base tag `newer` is chronologically newer than the base tag `older`
'''
return WindowsUtils._validTags.index(newer) > WindowsUtils._validTags.index(older)
return requests.get('https://mcr.microsoft.com/v2/windows/servercore/tags/list').json()['tags']

@staticmethod
def supportsProcessIsolation() -> bool:
Expand Down