Skip to content

Commit 3499650

Browse files
check migration target before testing for architecture version
The x86_64 architecture version check only applies to migrations to SLE16. Do not check for it if we are migrating to SLE15.
1 parent 1dfc66c commit 3499650

File tree

7 files changed

+173
-64
lines changed

7 files changed

+173
-64
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: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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+
24+
from suse_migration_services.defaults import Defaults
25+
from suse_migration_services.command import Command
26+
27+
log = logging.getLogger(Defaults.get_migration_log_name())
28+
29+
30+
class MigrationTarget:
31+
"""Implements the detection of migration target"""
32+
@staticmethod
33+
def _parse_custom_config():
34+
migration_config = '/etc/sle-migration-service.yml'
35+
if os.path.isfile(migration_config):
36+
try:
37+
with open(migration_config, 'r') as config:
38+
return yaml.safe_load(config) or {}
39+
except Exception as issue:
40+
message = 'Loading {0} failed: {1}: {2}'.format(
41+
migration_config, type(issue).__name__, issue
42+
)
43+
log.error(message)
44+
45+
return {}
46+
47+
@staticmethod
48+
def get_migration_target():
49+
config_data = MigrationTarget._parse_custom_config()
50+
migration_product = config_data.get('migration_product')
51+
if migration_product:
52+
product = migration_product.split('/')
53+
return {
54+
'identifier': product[0],
55+
'version': product[1],
56+
'arch': product[2]
57+
}
58+
sles15_migration = Command.run(
59+
['rpm', '-q', 'SLES15-Migration'], raise_on_error=False
60+
)
61+
if sles15_migration.returncode == 0:
62+
# return default migration target
63+
return {
64+
'identifier': 'SLES',
65+
'version': '15.3',
66+
'arch': platform.machine()
67+
}
68+
sles16_migration = Command.run(
69+
['rpm', '-q', 'SLES16-Migration'], raise_on_error=False
70+
)
71+
if sles16_migration.returncode == 0:
72+
# return default migration target
73+
return {
74+
'identifier': 'SLES',
75+
'version': '16.0',
76+
'arch': platform.machine()
77+
}
78+
return {}

suse_migration_services/prechecks/cpu_arch.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,25 @@
2222

2323
from suse_migration_services.defaults import Defaults
2424
from suse_migration_services.command import Command
25+
from suse_migration_services.migration_target import MigrationTarget
2526

2627

2728
def x86_64_version():
2829
"""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+
2936
log = logging.getLogger(Defaults.get_migration_log_name())
30-
os.environ['ZYPPER_READONLY_HACK'] = '1'
37+
os.environ['ZYPP_READONLY_HACK'] = '1'
3138
zypper_call = Command.run(['zypper', 'system-architecture'])
3239
arch = zypper_call.output
3340

3441
if arch.strip().lower() == "x86_64":
3542
log.error(
36-
'SLE16 requires x86_64_v1 at minimum. The architecture version '
43+
'SLE16 requires x86_64_v2 at minimum. The architecture version '
3744
'of this system is too old.'
3845
)
3946

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: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from unittest.mock import (
2+
patch, Mock
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.command.Command.run')
12+
def test_get_migration_target(
13+
self, mock_Command_run, mock_os_path_isfile,
14+
mock_platform_machine
15+
):
16+
mock_platform_machine.return_value = 'x86_64'
17+
sles15_migration = Mock()
18+
sles15_migration.returncode = 0
19+
mock_Command_run.return_value = sles15_migration
20+
mock_os_path_isfile.return_value = False
21+
assert MigrationTarget.get_migration_target() == {
22+
'identifier': 'SLES',
23+
'version': '15.3',
24+
'arch': 'x86_64'
25+
}
26+
27+
@patch('platform.machine')
28+
@patch('os.path.isfile')
29+
@patch('suse_migration_services.command.Command.run')
30+
def test_get_migration_target_sles16(
31+
self, mock_Command_run, mock_os_path_isfile,
32+
mock_platform_machine
33+
):
34+
mock_platform_machine.return_value = 'x86_64'
35+
sles15_migration_not_found = Mock()
36+
sles15_migration_not_found.returncode = 1 # SLES15-Migration not found
37+
sles16_migration_found = Mock()
38+
sles16_migration_found.returncode = 0 # SLES16-Migration found
39+
mock_Command_run.side_effect = [sles15_migration_not_found, sles16_migration_found]
40+
mock_os_path_isfile.return_value = False # No /etc/sle-migration-service.yml
41+
assert MigrationTarget.get_migration_target() == {
42+
'identifier': 'SLES',
43+
'version': '16.0',
44+
'arch': 'x86_64'
45+
}

test/unit/pre_checks_test.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -882,23 +882,48 @@ def test_check_wicked2nm_in_host_system_failure(
882882
)
883883

884884
@patch('suse_migration_services.command.Command.run')
885-
def test_check_x86_64_version_v2(
886-
self, mock_Command_run,
885+
@patch('suse_migration_services.migration_target.MigrationTarget.get_migration_target')
886+
def test_check_x86_64_v2(
887+
self, mock_get_migration_target, mock_Command_run,
887888
mock_os_getuid, mock_log
888889
):
890+
mock_get_migration_target.return_value = {
891+
'version': '16.0'
892+
}
889893
mock_Command_run.return_value.output = 'x86_64_v2'
890894

891895
check_cpu_arch.cpu_arch()
896+
assert 'SLE16 requires x86_64_v2 at minimum' not in self._caplog.text
892897
mock_Command_run.assert_called_once_with(['zypper', 'system-architecture'])
893898

894899
@patch('suse_migration_services.command.Command.run')
895-
def test_check_x86_64_old(
896-
self, mock_Command_run,
900+
@patch('suse_migration_services.migration_target.MigrationTarget.get_migration_target')
901+
def test_check_x86_64_v1(
902+
self, mock_get_migration_target, mock_Command_run,
897903
mock_os_getuid, mock_log
898904
):
905+
mock_get_migration_target.return_value = {
906+
'version': '16.0'
907+
}
899908
mock_Command_run.return_value.output = 'x86_64'
900909

901910
with self._caplog.at_level(logging.ERROR):
902911
check_cpu_arch.cpu_arch()
903-
assert 'SLE16 requires x86_64_v1 at minimum' in self._caplog.text
912+
assert 'SLE16 requires x86_64_v2 at minimum' in self._caplog.text
904913
mock_Command_run.assert_called_once_with(['zypper', 'system-architecture'])
914+
915+
@patch('suse_migration_services.command.Command.run')
916+
@patch('suse_migration_services.migration_target.MigrationTarget.get_migration_target')
917+
def test_check_x86_64_v1_sle15(
918+
self, mock_get_migration_target, mock_Command_run,
919+
mock_os_getuid, mock_log
920+
):
921+
mock_get_migration_target.return_value = {
922+
'version': '15.0'
923+
}
924+
mock_Command_run.return_value.output = 'x86_64'
925+
926+
with self._caplog.at_level(logging.ERROR):
927+
check_cpu_arch.cpu_arch()
928+
assert 'SLE16 requires x86_64_v2 at minimum' not in self._caplog.text
929+
mock_Command_run.assert_not_called()

tools/run_migration

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,6 @@ if (( EUID != 0 )); then
139139
exit 1
140140
fi
141141

142-
# Do not start migration for CPUs that are too old
143-
# SLE16 image panics on CPUs older than x86_64_v1 (i.e. x86_64) (bsc#1249593), so we need to block
144-
# migration before getting into the image.
145-
if [ "$(zypper system-architecture)" == "x86_64" ]; then
146-
echo "CPU Architecture too old. Aborting migration."
147-
exit 1
148-
fi
149-
150142
# Set signal handler on EXIT
151143
trap cleanup EXIT
152144

@@ -167,6 +159,14 @@ if [[ "${migration_iso}" == *SLES16*-*Migration*.iso ]]; then
167159
fi
168160

169161
if ${is_sles16_migration}; then
162+
# Do not start migration for CPUs that are too old
163+
# SLE16 image panics on CPUs older than x86_64_v2 (i.e. x86_64) (bsc#1249593), so we need to
164+
# block migration before getting into the image.
165+
if [ "$(zypper system-architecture)" == "x86_64" ]; then
166+
echo "CPU Architecture too old. Aborting migration."
167+
exit 1
168+
fi
169+
170170
# store snapper pre snapshot if available
171171
store_snapper_pre_snapshot
172172

0 commit comments

Comments
 (0)