/
githubmirror
/
salt
Обзор
Документация
Войти
/
githubmirror
/
salt
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tests/pytests/unit/cloud/test_map.py
306 строк
11 KB
Daniel A. Wozniak
Fix salt-cloud AttributeError on startup with a map file
06 июн 2026, 05:08
06 июн 2026, 05:08
db50ac8
Код
Авторство
О чём код?
""" :codeauthor: Eric Radman <ericshane@eradman.com> Validate evaluation of salt-cloud map configuration """ import logging import os import subprocess import sys import textwrap import pytest import salt.cloud import salt.config from tests.support.mock import MagicMock, patch EXAMPLE_PROVIDERS = { "nyc_vcenter": { "vmware": { "driver": "vmware", "password": "123456", "url": "vca1.localhost", "minion": {"master": "providermaster", "grains": {"providergrain": True}}, "profiles": {}, "user": "root", } }, "nj_vcenter": { "vmware": { "driver": "vmware", "password": "333", "profiles": {}, "minion": {"master": "providermaster", "grains": {"providergrain": True}}, "image": "rhel6_64prod", "url": "vca2.localhost", "user": "root", } }, } EXAMPLE_PROFILES = { "nyc-vm": { "cluster": "nycvirt", "datastore": "datastore1", "devices": { "disk": {"Hard disk 1": {"controller": "SCSI controller 1", "size": 20}}, "network": { "Network Adapter 1": { "mac": "88:88:88:88:88:42", "name": "vlan50", "switch_type": "standard", } }, "scsi": {"SCSI controller 1": {"type": "paravirtual"}}, }, "extra_config": {"mem.hotadd": "yes"}, "folder": "coreinfra", "image": "rhel6_64Guest", "minion": {"master": "profilemaster", "grains": {"profilegrain": True}}, "memory": "8GB", "num_cpus": 2, "power_on": True, "profile": "nyc-vm", "provider": "nyc_vcenter:vmware", "resourcepool": "Resources", }, "nj-vm": { "cluster": "njvirt", "folder": "coreinfra", "image": "rhel6_64Guest", "memory": "8GB", "num_cpus": 2, "power_on": True, "profile": "nj-vm", "provider": "nj_vcenter:vmware", "resourcepool": "Resources", }, } EXAMPLE_MAP = { "nyc-vm": { "db1": { "cpus": 4, "devices": { "disk": {"Hard disk 1": {"size": 40}}, "network": {"Network Adapter 1": {"mac": "22:4a:b2:92:b3:eb"}}, }, "memory": "16GB", "minion": {"master": "mapmaster", "grains": {"mapgrain": True}}, "name": "db1", }, "db2": {"name": "db2", "password": "456", "provider": "nj_vcenter:vmware"}, }, "nj-vm": {"db3": {"name": "db3", "password": "789"}}, } @pytest.fixture(scope="module") def salt_cloud_config_file(salt_master_factory): return os.path.join(salt_master_factory.config_dir, "cloud") # The cloud map merge uses python's multiprocessing manager which authenticates using HMAC and MD5 @pytest.mark.skip("GREAT MODULE MIGRATION") @pytest.mark.skip_on_fips_enabled_platform def test_cloud_map_merge_conf(salt_cloud_config_file): """ Ensure that nested values can be selectivly overridden in a map file """ with patch( "salt.config.check_driver_dependencies", MagicMock(return_value=True) ), patch("salt.cloud.Map.read", MagicMock(return_value=EXAMPLE_MAP)): opts = salt.config.cloud_config(salt_cloud_config_file) opts.update( { "optimization_order": [0, 1, 2], "providers": EXAMPLE_PROVIDERS, "profiles": EXAMPLE_PROFILES, } ) cloud_map = salt.cloud.Map(opts) merged_profile = { "create": { "db1": { "cluster": "nycvirt", "cpus": 4, "datastore": "datastore1", "devices": { "disk": { "Hard disk 1": { "controller": "SCSI controller 1", "size": 40, } }, "network": { "Network Adapter 1": { "mac": "22:4a:b2:92:b3:eb", "name": "vlan50", "switch_type": "standard", } }, "scsi": {"SCSI controller 1": {"type": "paravirtual"}}, }, "driver": "vmware", "extra_config": {"mem.hotadd": "yes"}, "folder": "coreinfra", "image": "rhel6_64Guest", "memory": "16GB", "minion": { "grains": { "mapgrain": True, "profilegrain": True, "providergrain": True, }, "master": "mapmaster", }, "name": "db1", "num_cpus": 2, "password": "123456", "power_on": True, "profile": "nyc-vm", "provider": "nyc_vcenter:vmware", "resourcepool": "Resources", "url": "vca1.localhost", "user": "root", }, "db2": { "cluster": "nycvirt", "datastore": "datastore1", "devices": { "disk": { "Hard disk 1": { "controller": "SCSI controller 1", "size": 20, } }, "network": { "Network Adapter 1": { "mac": "88:88:88:88:88:42", "name": "vlan50", "switch_type": "standard", } }, "scsi": {"SCSI controller 1": {"type": "paravirtual"}}, }, "driver": "vmware", "extra_config": {"mem.hotadd": "yes"}, "folder": "coreinfra", "image": "rhel6_64Guest", "memory": "8GB", "minion": { "grains": {"profilegrain": True, "providergrain": True}, "master": "profilemaster", }, "name": "db2", "num_cpus": 2, "password": "456", "power_on": True, "profile": "nyc-vm", "provider": "nj_vcenter:vmware", "resourcepool": "Resources", "url": "vca2.localhost", "user": "root", }, "db3": { "cluster": "njvirt", "driver": "vmware", "folder": "coreinfra", "image": "rhel6_64Guest", "memory": "8GB", "minion": { "grains": {"providergrain": True}, "master": "providermaster", }, "name": "db3", "num_cpus": 2, "password": "789", "power_on": True, "profile": "nj-vm", "provider": "nj_vcenter:vmware", "resourcepool": "Resources", "url": "vca2.localhost", "user": "root", }, } } # what we assert above w.r.t db2 using nj_vcenter:vmware provider: # - url is from the overridden nj_vcenter provider, not nyc_vcenter # - image from provider is still overridden by the nyc-vm profile # - password from map override is still overriding both the provider and profile password # # what we assert above about grain handling ( and provider/profile/map data in general ) # - provider grains are able to be overridden by profile data # - provider grain sare overridden by map data # - profile data is overridden by map data # ie, the provider->profile->map inheritance works as expected map_data = cloud_map.map_data() assert map_data == merged_profile def test_salt_minion_imported_when_loading_cloud_module(): """ Regression test for #69281. ``salt.cloud.Map.read`` references ``salt.minion.MasterMinion`` but the ``salt.cloud`` module did not explicitly ``import salt.minion``. Whether the reference resolved depended on other modules transitively importing ``salt.minion`` first, which broke ``salt-cloud`` startup on 3008.0. Verify in a fresh interpreter that simply importing ``salt.cloud`` makes ``salt.minion`` available, so ``salt.cloud.Map(...)`` can call ``salt.minion.MasterMinion(...)`` without raising ``AttributeError``. """ script = textwrap.dedent( """ import salt.cloud assert hasattr(salt.cloud.salt, "minion"), ( "salt.cloud must import salt.minion; " "salt.cloud.Map.read uses salt.minion.MasterMinion" ) # Confirm the attribute is the real module, not something else. import types assert isinstance(salt.cloud.salt.minion, types.ModuleType) """ ) result = subprocess.run( [sys.executable, "-c", script], capture_output=True, text=True, check=False, ) assert result.returncode == 0, ( "Importing salt.cloud failed to make salt.minion accessible.\n" f"stdout: {result.stdout}\nstderr: {result.stderr}" ) def test_cloud_map_delete_non_existing_profile(salt_cloud_config_file, caplog): """ Ensure proper behavior when deleting instances from a cloud map when the profile does not exist """ bad_map = {"nyc-vm-bad": EXAMPLE_MAP["nyc-vm"].copy()} with patch( "salt.config.check_driver_dependencies", MagicMock(return_value=True) ), patch("salt.cloud.Map.read", MagicMock(return_value=bad_map)): opts = salt.config.cloud_config(salt_cloud_config_file) opts.update( { "optimization_order": [0, 1, 2], "providers": EXAMPLE_PROVIDERS, "profiles": EXAMPLE_PROFILES, } ) cloud_map = salt.cloud.Map(opts) with caplog.at_level(logging.INFO): try: cloud_map.delete_map() except AttributeError: pytest.fail("Deleting map raised AttributeError") assert ( "No provider for the mapped 'nyc-vm-bad' profile was found" in caplog.text )