Skip to content

Commit c2189bc

Browse files
committed
Fix FIPS enabled cluster operations
Make sure host system is FIPS enabled and proper installer is downloaded
1 parent 5452052 commit c2189bc

File tree

4 files changed

+504
-478
lines changed

4 files changed

+504
-478
lines changed

Diff for: osia/cli.py

+38-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
openshift"""
1818
import argparse
1919
import logging
20-
from typing import List
20+
from typing import List, Tuple, Optional
21+
from subprocess import Popen
2122
import coloredlogs
23+
import distro
2224

2325
from .config.config import ARCH_AMD, ARCH_ARM, ARCH_X86_64, ARCH_AARCH64, ARCH_S390X, ARCH_PPC
2426
from .installer import install_cluster, delete_cluster, storage, download_installer
@@ -84,16 +86,40 @@ def _read_list(in_str: str) -> List[str]:
8486
a['proc'] = _identity
8587

8688

89+
def _check_fips_compatible() -> Tuple[bool, Optional[str]]:
90+
rhel_version = None
91+
if distro.id() == "rhel":
92+
rhel_version = distro.major_version()
93+
94+
if not rhel_version:
95+
return False, "FIPS installs are supported only from RHEL systems"
96+
try:
97+
with Popen(["fips-mode-setup", "--check"]) as proc:
98+
proc.wait()
99+
if proc.returncode != 0:
100+
return False, "FIPS is not enabled on the system"
101+
except FileNotFoundError:
102+
return False, "fips-mode-setup must be installed on the system"
103+
104+
return True, None
105+
106+
87107
def _resolve_installer(from_args):
88108
if from_args.installer is None and from_args.installer_version is None:
89109
raise Exception('Either installer or installer-version must be passed')
90110
if from_args.installer:
91111
return from_args.installer
92112

113+
rhel_version = None
114+
if distro.id() == "rhel":
115+
rhel_version = distro.major_version()
116+
93117
return download_installer(from_args.installer_version,
94118
from_args.installer_arch,
95119
from_args.installers_dir,
96-
from_args.installer_source)
120+
from_args.installer_source,
121+
rhel_version=rhel_version,
122+
fips=from_args.enable_fips)
97123

98124

99125
def _merge_dictionaries(from_args):
@@ -107,6 +133,11 @@ def _merge_dictionaries(from_args):
107133

108134
def _exec_install_cluster(args):
109135
conf = _merge_dictionaries(args)
136+
if args.enable_fips:
137+
supported, msg = _check_fips_compatible()
138+
if not supported:
139+
raise Exception(msg)
140+
110141
if not args.skip_git:
111142
storage.check_repository()
112143
logging.info('Starting the installer with cloud name %s', conf['cloud_name'])
@@ -123,6 +154,11 @@ def _exec_install_cluster(args):
123154

124155
def _exec_delete_cluster(args):
125156
conf = _merge_dictionaries(args)
157+
if args.enable_fips:
158+
supported, msg = _check_fips_compatible()
159+
if not supported:
160+
logging.info(msg)
161+
logging.info('Continuing as cleanup can be done from anywhere.')
126162

127163
if not args.skip_git:
128164
storage.check_repository()

Diff for: osia/installer/downloader/install.py

+50-21
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,20 @@
2828
import requests
2929

3030
from bs4 import BeautifulSoup
31+
from semantic_version import Version, SimpleSpec
3132
from .utils import get_data
3233

3334

3435
PROD_ROOT = "http://mirror.openshift.com/pub/openshift-v4/{}/clients/ocp/"
3536
BUILD_ROOT = "https://openshift-release-artifacts.svc.ci.openshift.org/"
3637
PREVIEW_ROOT = "http://mirror.openshift.com/pub/openshift-v4/{}/clients/ocp-dev-preview/"
3738

38-
VERSION_RE = re.compile(r"^openshift-install-(?P<platform>\w+)"
39-
r"(-(?P<architecture>\w+))?-(?P<version>\d+.*)\.tar\.gz")
39+
VERSION_RE = re.compile(r"^openshift-install(-rhel(?P<rhel>\d+))?(-(?P<platform>(linux|mac)))?"
40+
r"(-(?P<architecture>\w+))?(-(?P<version>\d+.*))?\.tar\.gz")
4041
EXTRACTION_RE = re.compile(r'.*Extracting tools for .*, may take up to a minute.*')
4142

4243

43-
def _current_platform():
44+
def _current_platform() -> Tuple[str, str]:
4445
if platform.system() == "Linux" and platform.machine() == "x86_64":
4546
return "linux", "amd64"
4647
if platform.system() == "Linux" and platform.machine() == "arm64":
@@ -53,10 +54,14 @@ def _current_platform():
5354
raise Exception(f"Unrecognized platform {platform.system()} {platform.machine()}")
5455

5556

56-
def get_url(directory: str, arch: str) -> Tuple[Optional[str], Optional[str]]:
57+
def get_url(directory: str, arch: str, fips: bool = False,
58+
rhel_version: str = None) -> Tuple[Optional[str], Optional[str]]:
5759
"""Searches the http directory and returns both url to installer
5860
and version.
5961
"""
62+
if fips and not rhel_version:
63+
raise Exception("Rhel version was not detected. Please download installer separatly.")
64+
6065
logging.debug('Url for installers look-up %s', directory)
6166
lst = requests.get(directory, allow_redirects=True)
6267
tree = BeautifulSoup(lst.content, 'html.parser')
@@ -66,16 +71,26 @@ def get_url(directory: str, arch: str) -> Tuple[Optional[str], Optional[str]]:
6671
for k in links:
6772
logging.debug('Parsing link: %s', k.get('href'))
6873
match = VERSION_RE.match(k.get('href'))
69-
if match and match.group('platform') == os_name:
70-
if (local_arch == match.group('architecture')) \
71-
or (local_arch == arch and not match.group('architecture')):
72-
installer = lst.url + k.get('href')
74+
75+
if match:
76+
if match.group("version"):
7377
version = match.group('version')
78+
79+
if fips and match.group("rhel") == rhel_version:
80+
installer = lst.url + k.get('href')
7481
break
82+
83+
if not fips and match.group('platform') == os_name:
84+
if (local_arch == match.group('architecture')) \
85+
or (local_arch == arch and not match.group('architecture')):
86+
installer = lst.url + k.get('href')
87+
version = match.group('version')
88+
break
7589
return installer, version
7690

7791

78-
def get_devel_url(version: str, arch: str) -> Tuple[Optional[str], Optional[str]]:
92+
def get_devel_url(version: str, arch: str, fips: bool = False,
93+
rhel_version: str = None) -> Tuple[Optional[str], Optional[str]]:
7994
"""
8095
Searches developement sources and returns url to installer
8196
"""
@@ -88,17 +103,19 @@ def get_devel_url(version: str, arch: str) -> Tuple[Optional[str], Optional[str]
88103
req = requests.get(BUILD_ROOT + version, allow_redirects=True)
89104
ast = BeautifulSoup(req.content, 'html.parser')
90105
logging.debug('Installer found on page, continuing')
91-
return get_url(req.url, arch)
106+
return get_url(req.url, arch, fips, rhel_version)
92107

93108

94-
def get_prev_url(version: str, arch: str) -> Tuple[Optional[str], Optional[str]]:
109+
def get_prev_url(version: str, arch: str, fips: bool = False,
110+
rhel_version: str = None) -> Tuple[Optional[str], Optional[str]]:
95111
"""Returns installer url from dev-preview sources"""
96-
return get_url(PREVIEW_ROOT.format(arch) + version + "/", arch)
112+
return get_url(PREVIEW_ROOT.format(arch) + version + "/", arch, fips, rhel_version)
97113

98114

99-
def get_prod_url(version: str, arch: str) -> Tuple[Optional[str], Optional[str]]:
115+
def get_prod_url(version: str, arch: str, fips: bool = False,
116+
rhel_version: str = None) -> Tuple[Optional[str], Optional[str]]:
100117
"""Returns installer url from production sources"""
101-
return get_url(PROD_ROOT.format(arch) + version + "/", arch)
118+
return get_url(PROD_ROOT.format(arch) + version + "/", arch, fips, rhel_version)
102119

103120

104121
def _get_storage_path(version: str, install_base: str) -> str:
@@ -114,12 +131,12 @@ def _extract_tar(buffer: NamedTemporaryFile, target: str) -> Path:
114131
with tarfile.open(buffer.name) as tar:
115132
inst_info = None
116133
for i in tar.getmembers():
117-
if i.name == 'openshift-install':
134+
if i.name in ['openshift-install', 'openshift-install-fips']:
118135
inst_info = i
119136
if inst_info is None:
120137
raise Exception("error")
121138
stream = tar.extractfile(inst_info)
122-
result = Path(target).joinpath('openshift-install')
139+
result = Path(target).joinpath(inst_info.name)
123140
with result.open('wb') as output:
124141
copyfileobj(stream, output)
125142
result.chmod(result.stat().st_mode | stat.S_IXUSR)
@@ -131,10 +148,13 @@ def get_installer(tar_url: str, target: str):
131148
return get_data(tar_url, target, _extract_tar)
132149

133150

151+
# pylint: disable=too-many-arguments
134152
def download_installer(installer_version: str,
135153
installer_arch: str,
136154
dest_directory: str,
137-
source: str) -> str:
155+
source: str,
156+
fips: bool = False,
157+
rhel_version: str = None) -> str:
138158
"""Starts search and extraction of installer"""
139159
logging.debug("Getting version %s of %s, storing to directory %s and devel is %r",
140160
installer_version, installer_arch, dest_directory, source)
@@ -149,12 +169,21 @@ def download_installer(installer_version: str,
149169
else:
150170
raise Exception("Error for source profile " + source)
151171

152-
url, version = downloader(installer_version, installer_arch)
172+
if fips and Version(installer_version.split("-")[-1]+".0") in SimpleSpec("<4.16"):
173+
# ocp <4.16 does not have dedicated openshift-install-fips,
174+
# it just need to be run on fips enabled RHEL
175+
fips = False
176+
rhel_version = None
177+
178+
url, version = downloader(installer_version, installer_arch, fips, rhel_version)
153179
logging.debug('Installer\'s URL is %s and full version is %s', url, version)
154180
root = Path(dest_directory).joinpath(version)
155181

156-
if root.exists() and root.joinpath('openshift-install').exists():
182+
installer_exe_name = 'openshift-install'
183+
if fips:
184+
installer_exe_name += '-fips'
185+
if root.exists() and root.joinpath(installer_exe_name).exists():
157186
logging.info('Found installer at %s', root.as_posix())
158-
return root.joinpath('openshift-install').as_posix()
159-
root.mkdir(parents=True)
187+
return root.joinpath(installer_exe_name).as_posix()
188+
root.mkdir(parents=True, exist_ok=True)
160189
return get_installer(url, root.as_posix())

0 commit comments

Comments
 (0)