Skip to content

Commit 951b7ce

Browse files
committed
Merge remote-tracking branch 'origin/dev' into vm-diagnostics-migration
2 parents ab92c3b + bfaf1d4 commit 951b7ce

339 files changed

Lines changed: 18707 additions & 16045 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/azure-cli-core/azure/cli/core/__init__.py

Lines changed: 202 additions & 97 deletions
Large diffs are not rendered by default.

src/azure-cli-core/azure/cli/core/commands/__init__.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,22 +1134,17 @@ def _load_command_loader(loader, args, name, prefix):
11341134
logger.debug("Module '%s' is missing `get_command_loader` entry.", name)
11351135

11361136
command_table = {}
1137+
command_loader = None
11371138

11381139
if loader_cls:
11391140
command_loader = loader_cls(cli_ctx=loader.cli_ctx)
1140-
loader.loaders.append(command_loader) # This will be used by interactive
11411141
if command_loader.supported_resource_type():
11421142
command_table = command_loader.load_command_table(args)
1143-
if command_table:
1144-
for cmd in list(command_table.keys()):
1145-
# TODO: If desired to for extension to patch module, this can be uncommented
1146-
# if loader.cmd_to_loader_map.get(cmd):
1147-
# loader.cmd_to_loader_map[cmd].append(command_loader)
1148-
# else:
1149-
loader.cmd_to_loader_map[cmd] = [command_loader]
11501143
else:
11511144
logger.debug("Module '%s' is missing `COMMAND_LOADER_CLS` entry.", name)
1152-
return command_table, command_loader.command_group_table
1145+
1146+
group_table = command_loader.command_group_table if command_loader else {}
1147+
return command_table, group_table, command_loader
11531148

11541149

11551150
def _load_extension_command_loader(loader, args, ext):

src/azure-cli-core/azure/cli/core/tests/test_command_registration.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def load_command_table(self, args):
230230
if command_table:
231231
module_command_table.update(command_table)
232232
loader.loaders.append(command_loader) # this will be used later by the load_arguments method
233-
return module_command_table, command_loader.command_group_table
233+
return module_command_table, command_loader.command_group_table, command_loader
234234

235235
expected_command_index = {'hello': ['azure.cli.command_modules.hello', 'azext_hello2', 'azext_hello1'],
236236
'extra': ['azure.cli.command_modules.extra']}
@@ -260,6 +260,41 @@ def test_register_command_from_extension(self):
260260
self.assertTrue(isinstance(hello_overridden_cmd.command_source, ExtensionCommandSource))
261261
self.assertTrue(hello_overridden_cmd.command_source.overrides_command)
262262

263+
@mock.patch('importlib.import_module', _mock_import_lib)
264+
@mock.patch('pkgutil.iter_modules', _mock_iter_modules)
265+
@mock.patch('azure.cli.core.commands._load_command_loader', _mock_load_command_loader)
266+
@mock.patch('azure.cli.core.extension.get_extension_modname', _mock_get_extension_modname)
267+
@mock.patch('azure.cli.core.extension.get_extensions', _mock_get_extensions)
268+
def test_cmd_to_loader_map_populated_after_parallel_loading(self):
269+
"""
270+
Validates that all commands in command_table have corresponding entries in cmd_to_loader_map.
271+
"""
272+
cli = DummyCli()
273+
loader = cli.commands_loader
274+
275+
# Load all commands (triggers parallel module loading)
276+
cmd_tbl = loader.load_command_table(None)
277+
278+
# Verify EVERY command in command_table has an entry in cmd_to_loader_map
279+
# This is exactly what azdev does before it hits KeyError
280+
for cmd_name in cmd_tbl:
281+
# This should NOT raise KeyError
282+
self.assertIn(cmd_name, loader.cmd_to_loader_map,
283+
f"Command '{cmd_name}' missing from cmd_to_loader_map - "
284+
f"would cause KeyError in azdev command-change meta-export")
285+
286+
# Verify the entry is a list with at least one loader
287+
loaders = loader.cmd_to_loader_map[cmd_name]
288+
self.assertIsInstance(loaders, list,
289+
f"cmd_to_loader_map['{cmd_name}'] should be a list")
290+
self.assertGreater(len(loaders), 0,
291+
f"cmd_to_loader_map['{cmd_name}'] should have at least one loader")
292+
293+
# Verify all expected commands are present
294+
expected_commands = {'hello mod-only', 'hello overridden', 'extra final', 'hello ext-only'}
295+
actual_commands = set(cmd_tbl.keys())
296+
self.assertEqual(expected_commands, actual_commands)
297+
263298
@mock.patch('importlib.import_module', _mock_import_lib)
264299
@mock.patch('pkgutil.iter_modules', _mock_iter_modules)
265300
@mock.patch('azure.cli.core.commands._load_command_loader', _mock_load_command_loader)
@@ -432,12 +467,12 @@ def test_command_index_positional_argument(self):
432467
# Test command index is built for command with positional argument
433468
cmd_tbl = loader.load_command_table(["extra", "extra", "positional_argument"])
434469
self.assertDictEqual(INDEX[CommandIndex._COMMAND_INDEX], self.expected_command_index)
435-
self.assertEqual(list(cmd_tbl), ['hello mod-only', 'hello overridden', 'extra final', 'hello ext-only'])
470+
self.assertSetEqual(set(cmd_tbl), {'hello mod-only', 'hello overridden', 'extra final', 'hello ext-only'})
436471

437472
# Test command index is used by command with positional argument
438473
cmd_tbl = loader.load_command_table(["hello", "mod-only", "positional_argument"])
439474
self.assertDictEqual(INDEX[CommandIndex._COMMAND_INDEX], self.expected_command_index)
440-
self.assertEqual(list(cmd_tbl), ['hello mod-only', 'hello overridden', 'hello ext-only'])
475+
self.assertSetEqual(set(cmd_tbl), {'hello mod-only', 'hello overridden', 'hello ext-only'})
441476

442477
# Test command index is used by command with positional argument
443478
cmd_tbl = loader.load_command_table(["extra", "final", "positional_argument2"])
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
6+
import unittest
7+
8+
from azure.cli.core.mock import DummyCli
9+
from azure.cli.core import MainCommandsLoader
10+
11+
12+
class CommandTableIntegrityTest(unittest.TestCase):
13+
14+
def setUp(self):
15+
self.cli_ctx = DummyCli()
16+
17+
def test_command_table_integrity(self):
18+
"""Test command table loading produces valid, complete results."""
19+
20+
# Load command table using current implementation
21+
loader = MainCommandsLoader(self.cli_ctx)
22+
loader.load_command_table([])
23+
24+
# Test invariants that should always hold:
25+
26+
# 1. No corruption/duplicates
27+
command_names = list(loader.command_table.keys())
28+
unique_command_names = set(command_names)
29+
self.assertEqual(len(unique_command_names), len(command_names), "No duplicate commands")
30+
31+
# 2. Core functionality exists (high-level groups that should always exist)
32+
core_groups = ['vm', 'network', 'resource', 'account', 'group']
33+
existing_groups = {cmd.split()[0] for cmd in loader.command_table.keys() if ' ' in cmd}
34+
missing_core = [group for group in core_groups if group not in existing_groups]
35+
self.assertEqual(len(missing_core), 0, f"Missing core command groups: {missing_core}")
36+
37+
# 3. Structural integrity
38+
commands_without_source = []
39+
for cmd_name, cmd_obj in loader.command_table.items():
40+
if not hasattr(cmd_obj, 'command_source') or not cmd_obj.command_source:
41+
commands_without_source.append(cmd_name)
42+
43+
self.assertEqual(len(commands_without_source), 0,
44+
f"Commands missing source: {commands_without_source[:5]}...")
45+
46+
# 4. Basic sanity - we loaded SOMETHING
47+
self.assertGreater(len(loader.command_table), 0, "Commands were loaded")
48+
self.assertGreater(len(loader.command_group_table), 0, "Groups were loaded")
49+
50+
# 5. Verify core groups are properly represented
51+
found_core_groups = sorted(existing_groups & set(core_groups))
52+
self.assertGreaterEqual(len(found_core_groups), 3,
53+
f"At least 3 core command groups should be present, found: {found_core_groups}")
54+
55+
56+
if __name__ == '__main__':
57+
unittest.main()

src/azure-cli-core/azure/cli/core/tests/test_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def load_command_table(self, args):
188188
if command_table:
189189
module_command_table.update(command_table)
190190
loader.loaders.append(command_loader) # this will be used later by the load_arguments method
191-
return module_command_table, command_loader.command_group_table
191+
return module_command_table, command_loader.command_group_table, command_loader
192192

193193
@mock.patch('importlib.import_module', _mock_import_lib)
194194
@mock.patch('pkgutil.iter_modules', _mock_iter_modules)

src/azure-cli/azure/cli/command_modules/acs/addonconfiguration.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,28 @@
185185
"ussecwest": "ussecwest",
186186
}
187187

188+
# mapping for azure bleu cloud
189+
AzureBleuLocationToOmsRegionCodeMap = {
190+
"bleufrancecentral": "BLEUC",
191+
"bleufrancesouth": "BLEUS",
192+
}
193+
194+
AzureBleuRegionToOmsRegionMap = {
195+
"bleufrancecentral": "bleufrancecentral",
196+
"bleufrancesouth": "bleufrancesouth",
197+
}
198+
199+
# mapping for azure delos cloud
200+
AzureDelosLocationToOmsRegionCodeMap = {
201+
"deloscloudgermanycentral": "DELOSC",
202+
"deloscloudgermanynorth": "DELOSN",
203+
}
204+
205+
AzureDelosRegionToOmsRegionMap = {
206+
"deloscloudgermanycentral": "deloscloudgermanycentral",
207+
"deloscloudgermanynorth": "deloscloudgermanynorth",
208+
}
209+
188210
ContainerInsightsStreams = [
189211
"Microsoft-ContainerLog",
190212
"Microsoft-ContainerLogV2-HighScale",
@@ -245,7 +267,20 @@ def ensure_default_log_analytics_workspace_for_monitoring(
245267
workspace_region_code = AzureUSSecLocationToOmsRegionCodeMap.get(
246268
workspace_region, "USSW"
247269
)
248-
270+
elif cloud_name.lower() == "azurebleucloud":
271+
workspace_region = AzureBleuRegionToOmsRegionMap.get(
272+
rg_location, "bleufrancecentral"
273+
)
274+
workspace_region_code = AzureBleuLocationToOmsRegionCodeMap.get(
275+
workspace_region, "BLEUC"
276+
)
277+
elif cloud_name.lower() == "azuredeloscloud":
278+
workspace_region = AzureDelosRegionToOmsRegionMap.get(
279+
rg_location, "deloscloudgermanycentral"
280+
)
281+
workspace_region_code = AzureDelosLocationToOmsRegionCodeMap.get(
282+
workspace_region, "DELOSC"
283+
)
249284
else:
250285
logger.error(
251286
"AKS Monitoring addon not supported in cloud : %s", cloud_name

0 commit comments

Comments
 (0)