Skip to content

Commit be06e4a

Browse files
authored
Merge branch 'master' into update/lpe_v1_6_58
2 parents 1fc5289 + 3b84a93 commit be06e4a

File tree

9 files changed

+209
-199
lines changed

9 files changed

+209
-199
lines changed

src/core/src/core_logic/VersionComparator.py

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
class VersionComparator(object):
2020

21-
def compare_version_nums(self, version_a, version_b):
21+
def compare_versions(self, version_a, version_b):
2222
# type (str, str) -> int
2323
""" Compare two versions with handling numeric and string parts, return -1 (less), +1 (greater), 0 (equal) """
2424

@@ -35,48 +35,46 @@ def compare_version_nums(self, version_a, version_b):
3535
# If equal 27.13.4 vs 27.13.4, return 0
3636
return (len(parse_version_a) > len(parse_version_b)) - (len(parse_version_a) < len(parse_version_b))
3737

38-
def extract_version_nums(self, path):
38+
@staticmethod
39+
def extract_version_from_os_version_nums(os_version):
3940
# type (str) -> str
4041
"""
41-
Extract the version part from a given path.
42-
Input: /var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5/config
43-
Return: "1.2.5"
42+
Extract the version part from a given os version.
43+
Input os version Extracted Version
44+
34 34
45+
34~18 34
46+
34.~18.04 34
47+
34.a+18.04.1 34
48+
34abc-18.04 34
49+
abc34~18.04 34
50+
abc34~18.04.123 34
51+
34~25.1.2-18.04.1 34
52+
34.1~18.04.1 34.1
53+
34.13.4 34.13.4
54+
34.13.4~18.04.1 34.13.4
55+
34.13.4-ab+18.04.1 34.13.4
56+
34.13.4abc-18.04.1 34.13.4
57+
abc.34.13.4!@abc 34.13.4
4458
"""
45-
match = re.search(r'([\d]+\.[\d]+\.[\d]+)', path)
46-
return match.group(1) if match else str()
59+
version_num = re.search(r'(\d+(?:\.\d+)*)', os_version) # extract numbers with optional dot-separated parts
60+
return version_num.group(1) if version_num else str()
4761

48-
def sort_versions_desc_order(self, paths):
49-
# type (list[str]) -> list[str]
50-
"""
51-
Sort paths based on version numbers extracted from paths.
52-
Input:
53-
["Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001",
54-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100",
55-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.21.100"]
56-
Return:
57-
["Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001",
58-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.21.100",
59-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100"]
60-
"""
61-
return sorted(paths, key=self.__version_key, reverse=True)
62-
63-
def __version_key(self, path):
62+
def __version_key(self, version_input):
6463
# type (str) -> (int)
6564
""" Extract version number from input and return int tuple.
66-
Input: "Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100"
67-
Return: (1.6.100)
65+
os version input: "34~18.04"
66+
Return: (34)
6867
"""
69-
version_numbers = self.extract_version_nums(path)
68+
version_numbers = self.extract_version_from_os_version_nums(os_version=version_input)
7069
return tuple(map(int, version_numbers.split('.'))) if version_numbers else (0, 0, 0)
7170

72-
def __split_version_components(self, version):
73-
# type (str) -> [any]
74-
""" Split a version into numeric and non-numeric into components list: 27.13.4~18.04.1 -> [27][14][4]"""
75-
return [int(x) if x.isdigit() else x for x in re.split(r'(\d+)', version) if x]
76-
7771
def __parse_version(self, version_components):
7872
# type (str) -> [[any]]
79-
""" Parse the split version list into list [27][14][4] -> [[27], [14], [4]]"""
73+
""" Parse the split version list into list [27][14][4] -> [[27], [14], [4]] """
8074
return [self.__split_version_components(x) for x in version_components.split(".")]
8175

82-
76+
@staticmethod
77+
def __split_version_components(version):
78+
# type (str) -> [any]
79+
""" Splits a version into numeric and non-numeric into components list: 27.13.4~18.04.1 -> [27][14][4] """
80+
return [int(x) if x.isdigit() else x for x in re.split(r'(\d+)', version) if x]

src/core/src/package_managers/UbuntuProClient.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ def is_pro_working(self):
5757
ubuntu_pro_client_version = version_result.installed_version
5858

5959
# extract version from pro_client_verison 27.13.4~18.04.1 -> 27.13.4
60-
extracted_ubuntu_pro_client_version = self.version_comparator.extract_version_nums(ubuntu_pro_client_version)
60+
extracted_ubuntu_pro_client_version = self.version_comparator.extract_version_from_os_version_nums(ubuntu_pro_client_version)
6161

6262
self.composite_logger.log_debug("Ubuntu Pro Client current version: [ClientVersion={0}]".format(str(extracted_ubuntu_pro_client_version)))
6363

6464
# use custom comparator output 0 (equal), -1 (less), +1 (greater)
65-
is_minimum_ubuntu_pro_version_installed = self.version_comparator.compare_version_nums(extracted_ubuntu_pro_client_version, Constants.UbuntuProClientSettings.MINIMUM_CLIENT_VERSION) >= 0
65+
is_minimum_ubuntu_pro_version_installed = self.version_comparator.compare_versions(extracted_ubuntu_pro_client_version, Constants.UbuntuProClientSettings.MINIMUM_CLIENT_VERSION) >= 0
6666

6767
if ubuntu_pro_client_version is not None and is_minimum_ubuntu_pro_version_installed:
6868
is_ubuntu_pro_client_working = True

src/core/tests/Test_UbuntuProClient.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ def mock_to_below_minimum_version(self):
5757
def mock_version_raise_exception(self):
5858
raise
5959

60+
def mock_pro_version(self):
61+
return MockVersionResult("34~18.004.01")
62+
6063
def mock_import_uaclient_version_module(self, mock_name, method_name):
6164
if sys.version_info[0] == 3:
6265
sys.modules['uaclient.api.u.pro.version.v1'] = types.ModuleType('version_module')
@@ -185,6 +188,15 @@ def test_is_pro_working_success(self):
185188

186189
obj.mock_unimport_uaclient_version_module()
187190

191+
def test_is_actual_pro_version_working_success(self):
192+
obj = MockVersionResult()
193+
obj.mock_import_uaclient_version_module('version', 'mock_pro_version')
194+
195+
package_manager = self.container.get('package_manager')
196+
self.assertTrue(package_manager.ubuntu_pro_client.is_pro_working())
197+
198+
obj.mock_unimport_uaclient_version_module()
199+
188200
def test_is_pro_working_failure_when_minimum_version_required_is_false(self):
189201
obj = MockVersionResult()
190202
obj.mock_import_uaclient_version_module('version', 'mock_to_below_minimum_version')

src/core/tests/Test_VersionComparator.py

Lines changed: 28 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -24,54 +24,35 @@ class TestVersionComparator(unittest.TestCase):
2424
def setUp(self):
2525
self.version_comparator = VersionComparator()
2626

27-
def test_linux_version_comparator(self):
28-
# Test extract version logic
29-
self.assertEqual(self.version_comparator.extract_version_nums("Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25"), "1.2.25")
30-
self.assertEqual(self.version_comparator.extract_version_nums("Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25-abc"), "1.2.25")
31-
self.assertEqual(self.version_comparator.extract_version_nums("Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25+abc.123"), "1.2.25")
32-
self.assertEqual(self.version_comparator.extract_version_nums("Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25-abc+def.123"), "1.2.25")
33-
self.assertEqual(self.version_comparator.extract_version_nums("Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001"), "1.21.1001")
34-
self.assertEqual(self.version_comparator.extract_version_nums("Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100"), "1.6.100")
35-
self.assertEqual(self.version_comparator.extract_version_nums("Microsoft.CPlat.Core.LinuxPatchExtension-1.6.99"), "1.6.99")
36-
self.assertEqual(self.version_comparator.extract_version_nums("Microsoft.CPlat.Core.LinuxPatchExtension-1.6."), "")
37-
self.assertEqual(self.version_comparator.extract_version_nums("Microsoft.CPlat.Core.LinuxPatchExtension-a.b.c"), "")
27+
def test_extract_version_from_os_version_nums(self):
28+
""" Test extract version logic on Ubuntuproclient version """
29+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34"), "34")
30+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34~18"), "34")
31+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34.~18.04"), "34")
32+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34.a+18.04.1"), "34")
33+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34abc-18.04"), "34")
34+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("abc34~18.04"), "34")
35+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("abc34~18.04.123"), "34")
36+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34~25.1.2-18.04.1"), "34")
37+
38+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34.1~18.04.1"), "34.1")
39+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34.13.4"), "34.13.4")
40+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34.13.4~18.04.1"), "34.13.4")
41+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34.13.4-ab+18.04.1"), "34.13.4")
42+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("34.13.4abc-18.04.1"), "34.13.4")
43+
self.assertEqual(self.version_comparator.extract_version_from_os_version_nums("abc.34.13.4!@abc"), "34.13.4")
44+
45+
def test_linux_os_version_comparison(self):
46+
""" Test compare versions logic Ubuntuproclient version with existing vm version """
47+
test_extracted_good_version = self.version_comparator.extract_version_from_os_version_nums("34.13.4~18.04.1") # return 34
48+
49+
self.assertEqual(self.version_comparator.compare_versions(test_extracted_good_version, "34.13.4"), 0) # equal 34.13.4 == 34.13.4
50+
self.assertEqual(self.version_comparator.compare_versions(test_extracted_good_version, "34.13.3"), 1) # greater 34.13.4 > 34.13.3
51+
self.assertEqual(self.version_comparator.compare_versions(test_extracted_good_version, "34.13.5"), -1) # less 34.13.4 < 34.13.5
52+
53+
test_extracted_bad_version = self.version_comparator.extract_version_from_os_version_nums("abc~18.04.1") # return ""
54+
self.assertEqual(self.version_comparator.compare_versions(test_extracted_bad_version, "34.13.4"), -1) # less "" < 34.13.4
3855

39-
expected_extracted_version = "27.13.4"
40-
test_extracted_v1 = self.version_comparator.extract_version_nums("27.13.4~18.04.1")
41-
test_extracted_v2 = self.version_comparator.extract_version_nums("27.13.4+18.04.1")
42-
test_extracted_v3 = self.version_comparator.extract_version_nums("27.13.4-18.04.1")
43-
44-
self.assertEqual(test_extracted_v1, expected_extracted_version)
45-
self.assertEqual(test_extracted_v2, expected_extracted_version)
46-
self.assertEqual(test_extracted_v3, expected_extracted_version)
47-
48-
# Test compare versions logic
49-
self.assertEqual(self.version_comparator.compare_version_nums(test_extracted_v1, "27.13.4"), 0) # equal
50-
self.assertEqual(self.version_comparator.compare_version_nums(test_extracted_v2, "27.13.3"), 1) # greater
51-
self.assertEqual(self.version_comparator.compare_version_nums(test_extracted_v3, "27.13.5"), -1) # less
52-
53-
# Test sort versions logic
54-
unsorted_path_versions = [
55-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25-abc+def.123",
56-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001",
57-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100",
58-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.6.99",
59-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.21.100",
60-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25-abc",
61-
]
62-
63-
expected_sorted_path_versions = [
64-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001",
65-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.21.100",
66-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100",
67-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.6.99",
68-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25-abc+def.123",
69-
"Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25-abc"
70-
]
71-
72-
# valid versions
73-
self.assertEqual(self.version_comparator.sort_versions_desc_order(unsorted_path_versions), expected_sorted_path_versions)
7456

7557
if __name__ == '__main__':
7658
unittest.main()
77-

src/extension/src/ActionHandler.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@
2323
from extension.src.Constants import Constants
2424
from extension.src.EnableCommandHandler import EnableCommandHandler
2525
from extension.src.InstallCommandHandler import InstallCommandHandler
26-
from extension.src.Utility import Utility
27-
from extension.src.VersionComparatorHandler import VersionComparatorHandler
26+
from extension.src.ExtVersionComparator import ExtVersionComparator
2827
from extension.src.local_loggers.StdOutFileMirror import StdOutFileMirror
2928

3029

@@ -49,7 +48,7 @@ def __init__(self, logger, env_layer, telemetry_writer, utility, runtime_context
4948
self.file_logger = None
5049
self.operation_id_substitute_for_all_actions_in_telemetry = str((datetime.datetime.utcnow()).strftime(Constants.UTC_DATETIME_FORMAT))
5150
self.seq_no = self.ext_config_settings_handler.get_seq_no_from_env_var()
52-
self.version_comparator_handler = VersionComparatorHandler()
51+
self.ext_version_comparator = ExtVersionComparator()
5352

5453
def determine_operation(self, command):
5554
switcher = {
@@ -228,7 +227,7 @@ def update(self):
228227
self.logger.log("Fetching the extension version preceding current from all available versions...")
229228

230229
# use custom sort logic to sort path based on version numbers
231-
sorted_versions = self.version_comparator_handler.sort_versions_desc_order(paths_to_all_versions)
230+
sorted_versions = self.ext_version_comparator.sort_ext_paths_desc_order(paths_to_all_versions)
232231
self.logger.log_debug("List of extension versions in descending order: [SortedVersion={0}]".format(sorted_versions))
233232

234233
preceding_version_path = sorted_versions[1]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright 2024 Microsoft Corporation
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# Requires Python 2.7+
16+
import os.path
17+
import re
18+
19+
20+
class ExtVersionComparator(object):
21+
22+
def sort_ext_paths_desc_order(self, ext_paths_with_versions):
23+
# type (list[str]) -> list[str]
24+
"""
25+
Sort paths based on version numbers extracted from paths.
26+
Lpe input:
27+
["/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001",
28+
"/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100",
29+
"/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.21.100"]
30+
Return:
31+
["/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001",
32+
"/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.21.100",
33+
"/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100"]
34+
"""
35+
36+
return sorted(ext_paths_with_versions, key=self.__version_key, reverse=True)
37+
38+
@staticmethod
39+
def __extract_lpe_path_version_num(lpe_path):
40+
# type (str) -> str
41+
"""
42+
Extract the version part from a given lpe path.
43+
Input Extracted Version
44+
/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25 "1.2.25"
45+
/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.250 "1.2.250"
46+
/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.21.2501 "1.21.2501"
47+
/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25. "1.2.25"
48+
/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25.. "1.2.25"
49+
/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25abc "1.2.25"
50+
/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25.abc "1.2.25"
51+
/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25+abc.123 "1.2.25"
52+
/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.25-abc+def.123 "1.2.25"
53+
/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-a.b.c ""
54+
"""
55+
56+
lpe_filename = os.path.basename(lpe_path) # Microsoft.CPlat.Core.LinuxPatchExtension-x.x.xx
57+
lpe_version = re.search(r'(\d+(?:\.\d+)*)', lpe_filename) # extract numbers with optional dot-separated parts
58+
return lpe_version.group(1).rstrip('.') if lpe_version else ""
59+
60+
def __version_key(self, version_input):
61+
# type (str) -> (int)
62+
""" Extract version number from input and return int tuple.
63+
Input: "/var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100"
64+
Return: (1.6.100)
65+
"""
66+
67+
version_numbers = self.__extract_lpe_path_version_num(lpe_path=version_input)
68+
return tuple(map(int, version_numbers.split('.'))) if version_numbers else (0, 0, 0)

src/extension/src/VersionComparatorHandler.py

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)