|
18 | 18 | from pathlib import Path
|
19 | 19 | from tempfile import NamedTemporaryFile
|
20 | 20 | from typing import TYPE_CHECKING, Any
|
| 21 | +from unittest import mock |
21 | 22 |
|
| 23 | +import ansible.inventory.manager |
| 24 | +from ansible.config.manager import ConfigManager |
22 | 25 | from ansible.errors import AnsibleError
|
| 26 | +from ansible.parsing.dataloader import DataLoader |
23 | 27 | from ansible.parsing.splitter import split_args
|
24 | 28 | from ansible.parsing.yaml.constructor import AnsibleMapping
|
25 | 29 | from ansible.plugins.loader import add_all_plugin_dirs
|
@@ -340,13 +344,16 @@ def _get_ansible_syntax_check_matches(
|
340 | 344 | playbook_path = fh.name
|
341 | 345 | else:
|
342 | 346 | playbook_path = str(lintable.path.expanduser())
|
343 |
| - # To avoid noisy warnings we pass localhost as current inventory: |
344 |
| - # [WARNING]: No inventory was parsed, only implicit localhost is available |
345 |
| - # [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' |
346 | 347 | cmd = [
|
347 | 348 | "ansible-playbook",
|
348 |
| - "-i", |
349 |
| - "localhost,", |
| 349 | + *[ |
| 350 | + inventory_opt |
| 351 | + for inventory_opts in [ |
| 352 | + ("-i", inventory_file) |
| 353 | + for inventory_file in self._get_inventory_files(app) |
| 354 | + ] |
| 355 | + for inventory_opt in inventory_opts |
| 356 | + ], |
350 | 357 | "--syntax-check",
|
351 | 358 | playbook_path,
|
352 | 359 | ]
|
@@ -451,6 +458,62 @@ def _get_ansible_syntax_check_matches(
|
451 | 458 | fh.close()
|
452 | 459 | return results
|
453 | 460 |
|
| 461 | + def _get_inventory_files(self, app: App) -> list[str]: |
| 462 | + config_mgr = ConfigManager() |
| 463 | + ansible_cfg_inventory = config_mgr.get_config_value( |
| 464 | + "DEFAULT_HOST_LIST", |
| 465 | + ) |
| 466 | + if app.options.inventory or ansible_cfg_inventory != [ |
| 467 | + config_mgr.get_configuration_definitions()["DEFAULT_HOST_LIST"].get( |
| 468 | + "default", |
| 469 | + ), |
| 470 | + ]: |
| 471 | + inventory_files = [ |
| 472 | + inventory_file |
| 473 | + for inventory_list in [ |
| 474 | + # creates nested inventory list |
| 475 | + (inventory.split(",") if "," in inventory else [inventory]) |
| 476 | + for inventory in ( |
| 477 | + app.options.inventory |
| 478 | + if app.options.inventory |
| 479 | + else ansible_cfg_inventory |
| 480 | + ) |
| 481 | + ] |
| 482 | + for inventory_file in inventory_list |
| 483 | + ] |
| 484 | + |
| 485 | + # silence noise when using parse_source |
| 486 | + with mock.patch.object( |
| 487 | + ansible.inventory.manager, |
| 488 | + "display", |
| 489 | + mock.Mock(), |
| 490 | + ): |
| 491 | + for inventory_file in inventory_files: |
| 492 | + if not Path(inventory_file).exists(): |
| 493 | + _logger.warning( |
| 494 | + "Unable to use %s as an inventory source: no such file or directory", |
| 495 | + inventory_file, |
| 496 | + ) |
| 497 | + elif os.access( |
| 498 | + inventory_file, |
| 499 | + os.R_OK, |
| 500 | + ) and not ansible.inventory.manager.InventoryManager( |
| 501 | + DataLoader(), |
| 502 | + ).parse_source( |
| 503 | + inventory_file, |
| 504 | + ): |
| 505 | + _logger.warning( |
| 506 | + "Unable to parse %s as an inventory source", |
| 507 | + inventory_file, |
| 508 | + ) |
| 509 | + else: |
| 510 | + # To avoid noisy warnings we pass localhost as current inventory: |
| 511 | + # [WARNING]: No inventory was parsed, only implicit localhost is available |
| 512 | + # [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' |
| 513 | + inventory_files = ["localhost"] |
| 514 | + |
| 515 | + return inventory_files |
| 516 | + |
454 | 517 | def _filter_excluded_matches(self, matches: list[MatchError]) -> list[MatchError]:
|
455 | 518 | return [
|
456 | 519 | match
|
|
0 commit comments