Skip to content

Commit d743021

Browse files
authored
Merge pull request #387 from SUSE/bsc1249593
Implement x86_64 architecture version check as a pre-check
2 parents 1318c45 + 1efc6c1 commit d743021

File tree

8 files changed

+251
-98
lines changed

8 files changed

+251
-98
lines changed

package/suse-migration-sle16-activation-spec-template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ install -D -m 755 grub.d/99_migration \
4646

4747
%pre
4848
# Prevent installation for CPUs that are too old
49-
# SLE16 image panics on CPUs older than x86_64_v1 (i.e. x86_64) (bsc#1249593), so we need to block migration before getting into the image.
49+
# SLE16 image panics on CPUs older than x86_64_v2 (i.e. x86_64) (bsc#1249593), so we need to block migration before getting into the image.
5050
# We need the ZYPP_READONLY_HACK here since we are running inside a zypper transaction; without this the invocation of zypper will fail due to locking issues.
5151
if [ "$(ZYPP_READONLY_HACK=1 zypper system-architecture)" == "x86_64" ]; then
5252
echo "CPU Architecture too old. Aborting installation."
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
# Copyright (c) 2025 SUSE Linux LLC. All rights reserved.
3+
#
4+
# This file is part of suse-migration-services.
5+
#
6+
# suse-migration-services is free software: you can redistribute it and/or
7+
# modify it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# suse-migration-services is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with suse-migration-services. If not, see <http://www.gnu.org/licenses/>
18+
#
19+
import logging
20+
import yaml
21+
import os
22+
import platform
23+
from glob import glob
24+
from fnmatch import fnmatch
25+
26+
from suse_migration_services.defaults import Defaults
27+
28+
log = logging.getLogger(Defaults.get_migration_log_name())
29+
30+
31+
class MigrationTarget:
32+
"""Implements the detection of migration target"""
33+
@staticmethod
34+
def _parse_custom_config():
35+
migration_config = '/etc/sle-migration-service.yml'
36+
if os.path.isfile(migration_config):
37+
try:
38+
with open(migration_config, 'r') as config:
39+
return yaml.safe_load(config) or {}
40+
except Exception as issue:
41+
message = 'Loading {0} failed: {1}: {2}'.format(
42+
migration_config, type(issue).__name__, issue
43+
)
44+
log.error(message)
45+
46+
return {}
47+
48+
@staticmethod
49+
def get_migration_target():
50+
config_data = MigrationTarget._parse_custom_config()
51+
migration_product = config_data.get('migration_product')
52+
if migration_product:
53+
product = migration_product.split('/')
54+
return {
55+
'identifier': product[0],
56+
'version': product[1],
57+
'arch': product[2]
58+
}
59+
migration_iso = glob('/migration-image/*-*Migration.*.iso')
60+
if not migration_iso:
61+
return {}
62+
migration_iso = migration_iso[0]
63+
64+
if fnmatch(migration_iso, '*SLES16*-*Migration*.iso'):
65+
# return default migration target
66+
return {
67+
'identifier': 'SLES',
68+
'version': '16.0',
69+
'arch': platform.machine()
70+
}
71+
else:
72+
# return default migration target
73+
return {
74+
'identifier': 'SLES',
75+
'version': '15.4',
76+
'arch': platform.machine()
77+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Copyright (c) 2025
2+
#
3+
# SUSE Linux LLC. All rights reserved.
4+
#
5+
# This file is part of suse-migration-services.
6+
#
7+
# suse-migration-services is free software: you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation, either version 3 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# suse-migration-services is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with suse-migration-services. If not, see <http://www.gnu.org/licenses/>
19+
"""Module for checking for CPU architecture support"""
20+
import logging
21+
import os
22+
23+
from suse_migration_services.defaults import Defaults
24+
from suse_migration_services.command import Command
25+
from suse_migration_services.migration_target import MigrationTarget
26+
27+
28+
def x86_64_version():
29+
"""Function to check whether current CPU architecture is new enough to support SLE16"""
30+
target = MigrationTarget.get_migration_target()
31+
32+
if target.get('version') != '16.0':
33+
# This check is only necessary for migration to SLE16
34+
return
35+
36+
log = logging.getLogger(Defaults.get_migration_log_name())
37+
os.environ['ZYPP_READONLY_HACK'] = '1'
38+
zypper_call = Command.run(['zypper', 'system-architecture'])
39+
arch = zypper_call.output
40+
41+
if arch.strip().lower() == "x86_64":
42+
log.error(
43+
'SLE16 requires x86_64_v2 at minimum. The architecture version '
44+
'of this system is too old.'
45+
)
46+
47+
48+
def cpu_arch():
49+
"""Function for CPU architecture related checks"""
50+
x86_64_version()

suse_migration_services/prechecks/pre_checks.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import suse_migration_services.prechecks.kernels as check_multi_kernels
3131
import suse_migration_services.prechecks.scc as check_scc
3232
import suse_migration_services.prechecks.wicked2nm as check_wicked2nm
33+
import suse_migration_services.prechecks.cpu_arch as check_cpu_arch
3334

3435

3536
def main():
@@ -92,6 +93,9 @@ def main():
9293

9394
log.info('Checking harmful migration conditions')
9495

96+
log.info('--> Checking system architecture version...')
97+
check_cpu_arch.cpu_arch()
98+
9599
log.info('--> Checking for local private repos...')
96100
check_repos.remote_repos(
97101
migration_system=migration_system_mode

suse_migration_services/prechecks/scc.py

Lines changed: 2 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@
1515
# You should have received a copy of the GNU General Public License
1616
# along with suse-migration-services. If not, see <http://www.gnu.org/licenses/>#
1717
from lxml import etree
18-
import platform
1918
import requests
2019
import yaml
2120
import logging
2221
import os
2322
import glob
2423

25-
from suse_migration_services.command import Command
2624
from suse_migration_services.defaults import Defaults
25+
from suse_migration_services.migration_target import MigrationTarget
2726

2827
log = logging.getLogger(Defaults.get_migration_log_name())
2928

@@ -43,7 +42,7 @@ def migration(migration_system=False):
4342
return
4443

4544
installed_products = get_installed_products()
46-
installed_products['target_base_product'] = get_migration_target()
45+
installed_products['target_base_product'] = MigrationTarget.get_migration_target()
4746

4847
if installed_products.get('installed_products') and \
4948
installed_products.get('target_base_product'):
@@ -129,51 +128,6 @@ def get_registration_server_url():
129128
log.error(message)
130129

131130

132-
def get_migration_target():
133-
migration_config = '/etc/sle-migration-service.yml'
134-
config_data = {}
135-
if os.path.isfile(migration_config):
136-
try:
137-
with open(migration_config, 'r') as config:
138-
config_data = yaml.safe_load(config) or {}
139-
except Exception as issue:
140-
message = 'Loading {0} failed: {1}: {2}'.format(
141-
migration_config, type(issue).__name__, issue
142-
)
143-
log.error(message)
144-
return {}
145-
146-
migration_product = config_data.get('migration_product')
147-
if migration_product:
148-
product = migration_product.split('/')
149-
return {
150-
'identifier': product[0],
151-
'version': product[1],
152-
'arch': product[2]
153-
}
154-
sles15_migration = Command.run(
155-
['rpm', '-q', 'SLES15-Migration'], raise_on_error=False
156-
)
157-
if sles15_migration.returncode == 0:
158-
# return default migration target
159-
return {
160-
'identifier': 'SLES',
161-
'version': '15.3',
162-
'arch': platform.machine()
163-
}
164-
sles16_migration = Command.run(
165-
['rpm', '-q', 'SLES16-Migration'], raise_on_error=False
166-
)
167-
if sles16_migration.returncode == 0:
168-
# return default migration target
169-
return {
170-
'identifier': 'SLES',
171-
'version': '16.0',
172-
'arch': platform.machine()
173-
}
174-
return {}
175-
176-
177131
def get_installed_products():
178132
installed_products = {
179133
'installed_products': []

test/unit/migration_target_test.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from unittest.mock import (
2+
patch
3+
)
4+
5+
from suse_migration_services.migration_target import MigrationTarget
6+
7+
8+
class TestMigrationTarget(object):
9+
@patch('platform.machine')
10+
@patch('os.path.isfile')
11+
@patch('suse_migration_services.migration_target.glob')
12+
def test_get_migration_target_empty(
13+
self, mock_glob, mock_os_path_isfile,
14+
mock_platform_machine
15+
):
16+
mock_platform_machine.return_value = 'x86_64'
17+
mock_glob.return_value = []
18+
mock_os_path_isfile.return_value = False
19+
assert MigrationTarget.get_migration_target() == {}
20+
21+
@patch('platform.machine')
22+
@patch('os.path.isfile')
23+
@patch('suse_migration_services.migration_target.glob')
24+
def test_get_migration_target_sles15(
25+
self, mock_glob, mock_os_path_isfile,
26+
mock_platform_machine
27+
):
28+
mock_platform_machine.return_value = 'x86_64'
29+
mock_glob.return_value = [
30+
'/migration-image/SLES15-Migration.x86_64-2.1.9-Build6.64.99.iso'
31+
]
32+
mock_os_path_isfile.return_value = False
33+
assert MigrationTarget.get_migration_target() == {
34+
'identifier': 'SLES',
35+
'version': '15.4',
36+
'arch': 'x86_64'
37+
}
38+
39+
@patch('platform.machine')
40+
@patch('os.path.isfile')
41+
@patch('suse_migration_services.migration_target.glob')
42+
def test_get_migration_target_sles16(
43+
self, mock_glob, mock_os_path_isfile,
44+
mock_platform_machine
45+
):
46+
mock_glob.return_value = [
47+
'/migration-image/SLES16-Migration.x86_64-2.1.23-Build2.1.iso'
48+
]
49+
mock_platform_machine.return_value = 'x86_64'
50+
mock_os_path_isfile.return_value = False # No /etc/sle-migration-service.yml
51+
assert MigrationTarget.get_migration_target() == {
52+
'identifier': 'SLES',
53+
'version': '16.0',
54+
'arch': 'x86_64'
55+
}

0 commit comments

Comments
 (0)