diff --git a/tests/pytests/unit/cloud/clouds/test_digitalocean.py b/tests/pytests/unit/cloud/clouds/test_digitalocean.py new file mode 100644 index 000000000000..576264864d13 --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/test_digitalocean.py @@ -0,0 +1,27 @@ +""" + :codeauthor: `Gareth J. Greenaway ` + + tests.unit.cloud.clouds.digitalocean_test + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" + + +import logging + +import pytest + +from salt.cloud.clouds import digitalocean +from salt.exceptions import SaltCloudSystemExit + +log = logging.getLogger(__name__) + + +def test_reboot_no_call(): + """ + Tests that a SaltCloudSystemExit is raised when + kwargs that are provided do not include an action. + """ + with pytest.raises(SaltCloudSystemExit) as excinfo: + digitalocean.reboot(name="fake_name") + + assert "The reboot action must be called with -a or --action." == str(excinfo.value) diff --git a/tests/pytests/unit/cloud/clouds/test_dimensiondata.py b/tests/pytests/unit/cloud/clouds/test_dimensiondata.py new file mode 100644 index 000000000000..830bb69241a1 --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/test_dimensiondata.py @@ -0,0 +1,192 @@ +""" + :codeauthor: `Anthony Shaw ` + + tests.unit.cloud.clouds.dimensiondata_test + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" + +import pytest + +from salt.cloud.clouds import dimensiondata +from salt.exceptions import SaltCloudSystemExit +from salt.utils.versions import LooseVersion +from tests.support.mock import MagicMock +from tests.support.mock import __version__ as mock_version +from tests.support.mock import patch + +try: + import libcloud.security + + HAS_LIBCLOUD = True +except ImportError: + HAS_LIBCLOUD = False + +# Use certifi if installed +try: + if HAS_LIBCLOUD: + # This work-around for Issue #32743 is no longer needed for libcloud >= + # 1.4.0. However, older versions of libcloud must still be supported + # with this work-around. This work-around can be removed when the + # required minimum version of libcloud is 2.0.0 (See PR #40837 - which + # is implemented in Salt 2018.3.0). + if LooseVersion(libcloud.__version__) < LooseVersion("1.4.0"): + import certifi + + libcloud.security.CA_CERTS_PATH.append(certifi.where()) +except (ImportError, NameError): + pass + + +@pytest.fixture +def vm_name(): + return "winterfell" + + +def _preferred_ip(ip_set, preferred=None): + """ + Returns a function that reacts which ip is preferred + :param ip_set: + :param private: + :return: + """ + + def _ip_decider(vm, ips): + for ip in ips: + if ip in preferred: + return ip + return False + + return _ip_decider + + +@pytest.fixture +def configure_loader_modules(): + return { + dimensiondata: { + "__active_provider_name__": "", + "__opts__": { + "providers": { + "my-dimensiondata-cloud": { + "dimensiondata": { + "driver": "dimensiondata", + "region": "dd-au", + "user_id": "jon_snow", + "key": "IKnowNothing", + } + } + } + }, + } + } + + +def test_avail_images_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call avail_images + with --action or -a. + """ + with pytest.raises(SaltCloudSystemExit): + dimensiondata.avail_images(call="action") + + +def test_avail_locations_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call avail_locations + with --action or -a. + """ + with pytest.raises(SaltCloudSystemExit): + dimensiondata.avail_locations(call="action") + + +def test_avail_sizes_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call avail_sizes + with --action or -a. + """ + with pytest.raises(SaltCloudSystemExit): + dimensiondata.avail_sizes(call="action") + + +def test_list_nodes_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes + with --action or -a. + """ + with pytest.raises(SaltCloudSystemExit): + dimensiondata.list_nodes(call="action") + + +def test_destroy_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call destroy + with --function or -f. + """ + with pytest.raises(SaltCloudSystemExit): + dimensiondata.destroy(name=vm_name, call="function") + + +@pytest.mark.skipif( + HAS_LIBCLOUD is False, reason="Install 'libcloud' to be able to run this unit test." +) +def test_avail_sizes(): + """ + Tests that avail_sizes returns an empty dictionary. + """ + sizes = dimensiondata.avail_sizes(call="foo") + assert len(sizes) == 1 + assert sizes["default"]["name"] == "default" + + +def test_import(): + """ + Test that the module picks up installed deps + """ + with patch("salt.config.check_driver_dependencies", return_value=True) as p: + get_deps = dimensiondata.get_dependencies() + assert get_deps is True + if LooseVersion(mock_version) >= LooseVersion("2.0.0"): + assert p.call_count >= 1 + + +def test_provider_matches(): + """ + Test that the first configured instance of a dimensiondata driver is matched + """ + p = dimensiondata.get_configured_provider() + assert p is not None + + +def test_query_node_data_filter_preferred_ip_addresses(): + """ + Test if query node data is filtering out unpreferred IP addresses. + """ + zero_ip = "0.0.0.0" + private_ips = [zero_ip, "1.1.1.1", "2.2.2.2"] + vm = {"name": None} + data = MagicMock() + data.public_ips = [] + # pylint: disable=blacklisted-unmocked-patching + dimensiondata.NodeState = MagicMock() + # pylint: enable=blacklisted-unmocked-patching + dimensiondata.NodeState.RUNNING = True + + with patch( + "salt.cloud.clouds.dimensiondata.show_instance", + MagicMock( + return_value={ + "state": True, + "name": "foo", + "public_ips": [], + "private_ips": private_ips, + } + ), + ): + with patch( + "salt.cloud.clouds.dimensiondata.preferred_ip", + _preferred_ip(private_ips, [zero_ip]), + ): + with patch( + "salt.cloud.clouds.dimensiondata.ssh_interface", + MagicMock(return_value="private_ips"), + ): + assert dimensiondata._query_node_data(vm, data).public_ips == [zero_ip] diff --git a/tests/pytests/unit/cloud/clouds/test_ec2.py b/tests/pytests/unit/cloud/clouds/test_ec2.py index 78df49c5d976..d538bff06b96 100644 --- a/tests/pytests/unit/cloud/clouds/test_ec2.py +++ b/tests/pytests/unit/cloud/clouds/test_ec2.py @@ -1,12 +1,21 @@ import pytest +import salt.crypt +import salt.utils.files from salt.cloud.clouds import ec2 +from salt.exceptions import SaltCloudSystemExit +from tests.support.mock import PropertyMock, patch pytestmark = [ pytest.mark.windows_whitelisted, ] +@pytest.fixture +def configure_loader_modules(): + return {ec2: {"__opts__": {}}} + + def test__load_params_size(): """ Test that "Size" is added to params @@ -158,3 +167,208 @@ def test_create_volume_missing_iops_io2(): kwargs = {"zone": "us-west-2", "type": "io1"} ret = ec2.create_volume(kwargs=kwargs, call="function") assert ret is False + + +def test__validate_key_path_and_mode(): + # Key file exists + with patch("os.path.exists", return_value=True): + with patch("os.stat") as patched_stat: + type(patched_stat.return_value).st_mode = PropertyMock(return_value=0o644) + with pytest.raises(SaltCloudSystemExit): + ec2._validate_key_path_and_mode("key_file") + + type(patched_stat.return_value).st_mode = PropertyMock(return_value=0o600) + assert ec2._validate_key_path_and_mode("key_file") is True + + type(patched_stat.return_value).st_mode = PropertyMock(return_value=0o400) + assert ec2._validate_key_path_and_mode("key_file") is True + + # Key file does not exist + with patch("os.path.exists", return_value=False): + with pytest.raises(SaltCloudSystemExit): + ec2._validate_key_path_and_mode("key_file") + + +@pytest.mark.skipif( + not salt.crypt.HAS_M2 and not salt.crypt.HAS_CRYPTO, reason="Needs crypto library" +) +def test_get_password_data(tmp_path): + key_file = str(tmp_path / "keyfile.pem") + + pass_data = ( + b"qOjCKDlBdcNEbJ/J8eRl7sH+bYIIm4cvHHY86gh2NEUnufFlFo0gGVTZR05Fj0cw3n/w7gR" + b"urNXz5JoeSIHVuNI3YTwzL9yEAaC0kuy8EbOlO2yx8yPGdfml9BRwOV7A6b8UFo9co4H7fz" + b"DdScMKU2yzvRYvp6N6Q2cJGBmPsemnXWWusb+1vZVWxcRAQmG3ogF6Z5rZSYAYH0N4rqJgH" + b"mQfzuyb+jrBvV/IOoV1EdO9jGSH9338aS47NjrmNEN/SpnS6eCWZUwwyHbPASuOvWiY4QH/" + b"0YZC6EGccwiUmt0ZOxIynk+tEyVPTkiS0V8RcZK6YKqMWHpKmPtLBzfuoA==" + ) + + privkey_data = ( + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpAIBAAKCAQEA75GR6ZTv5JOv90Vq8tKhKC7YQnhDIo2hM0HVziTEk5R4UQBW\n" + "a0CKytFMbTONY2msEDwX9iA0x7F5Lgj0X8eD4ZMsYqLzqjWMekLC8bjhxc+EuPo9\n" + "Dygu3mJ2VgRC7XhlFpmdo5NN8J2E7B/CNB3R4hOcMMZNZdi0xLtFoTfwU61UPfFX\n" + "14mV2laqLbvDEfQLJhUTDeFFV8EN5Z4H1ttLP3sMXJvc3EvM0JiDVj4l1TWFUHHz\n" + "eFgCA1Im0lv8i7PFrgW7nyMfK9uDSsUmIp7k6ai4tVzwkTmV5PsriP1ju88Lo3MB\n" + "4/sUmDv/JmlZ9YyzTO3Po8Uz3Aeq9HJWyBWHAQIDAQABAoIBAGOzBzBYZUWRGOgl\n" + "IY8QjTT12dY/ymC05GM6gMobjxuD7FZ5d32HDLu/QrknfS3kKlFPUQGDAbQhbbb0\n" + "zw6VL5NO9mfOPO2W/3FaG1sRgBQcerWonoSSSn8OJwVBHMFLG3a+U1Zh1UvPoiPK\n" + "S734swIM+zFpNYivGPvOm/muF/waFf8tF/47t1cwt/JGXYQnkG/P7z0vp47Irpsb\n" + "Yjw7vPe4BnbY6SppSxscW3KoV7GtJLFKIxAXbxsuJMF/rYe3O3w2VKJ1Sug1VDJl\n" + "/GytwAkSUer84WwP2b07Wn4c5pCnmLslMgXCLkENgi1NnJMhYVOnckxGDZk54hqP\n" + "9RbLnkkCgYEA/yKuWEvgdzYRYkqpzB0l9ka7Y00CV4Dha9Of6GjQi9i4VCJ/UFVr\n" + "UlhTo5y0ZzpcDAPcoZf5CFZsD90a/BpQ3YTtdln2MMCL/Kr3QFmetkmDrt+3wYnX\n" + "sKESfsa2nZdOATRpl1antpwyD4RzsAeOPwBiACj4fkq5iZJBSI0bxrMCgYEA8GFi\n" + "qAjgKh81/Uai6KWTOW2kX02LEMVRrnZLQ9VPPLGid4KZDDk1/dEfxjjkcyOxX1Ux\n" + "Klu4W8ZEdZyzPcJrfk7PdopfGOfrhWzkREK9C40H7ou/1jUecq/STPfSOmxh3Y+D\n" + "ifMNO6z4sQAHx8VaHaxVsJ7SGR/spr0pkZL+NXsCgYEA84rIgBKWB1W+TGRXJzdf\n" + "yHIGaCjXpm2pQMN3LmP3RrcuZWm0vBt94dHcrR5l+u/zc6iwEDTAjJvqdU4rdyEr\n" + "tfkwr7v6TNlQB3WvpWanIPyVzfVSNFX/ZWSsAgZvxYjr9ixw6vzWBXOeOb/Gqu7b\n" + "cvpLkjmJ0wxDhbXtyXKhZA8CgYBZyvcQb+hUs732M4mtQBSD0kohc5TsGdlOQ1AQ\n" + "McFcmbpnzDghkclyW8jzwdLMk9uxEeDAwuxWE/UEvhlSi6qdzxC+Zifp5NBc0fVe\n" + "7lMx2mfJGxj5CnSqQLVdHQHB4zSXkAGB6XHbBd0MOUeuvzDPfs2voVQ4IG3FR0oc\n" + "3/znuwKBgQChZGH3McQcxmLA28aUwOVbWssfXKdDCsiJO+PEXXlL0maO3SbnFn+Q\n" + "Tyf8oHI5cdP7AbwDSx9bUfRPjg9dKKmATBFr2bn216pjGxK0OjYOCntFTVr0psRB\n" + "CrKg52Qrq71/2l4V2NLQZU40Dr1bN9V+Ftd9L0pvpCAEAWpIbLXGDw==\n" + "-----END RSA PRIVATE KEY-----" + ) + + with patch( + "salt.cloud.clouds.ec2._get_node", return_value={"instanceId": "i-abcdef"} + ): + with patch("salt.cloud.clouds.ec2.get_location", return_value="us-west2"): + with patch("salt.cloud.clouds.ec2.get_provider", return_value="ec2"): + with patch( + "salt.utils.aws.query", return_value=[{"passwordData": pass_data}] + ): + with salt.utils.files.fopen(key_file, "w") as fp: + fp.write(privkey_data) + ret = ec2.get_password_data( + name="i-abcddef", kwargs={"key_file": key_file}, call="action" + ) + assert ret["passwordData"] == pass_data + assert ret["password"] == "testp4ss!" + + +def test_get_imageid(): + """ + test querying imageid function + """ + vm = {} + ami = "ami-1234" + with patch("salt.cloud.clouds.ec2.get_location", return_value="us-west2"): + with patch("salt.cloud.clouds.ec2.get_provider", return_value="ec2"): + with patch( + "salt.cloud.clouds.ec2.aws.query", return_value=[{"imageId": ami}] + ) as aws_query: + with patch( + "salt.cloud.clouds.ec2.config.get_cloud_config_value", + return_value="test/*", + ): + # test image filter + assert ec2.get_imageid(vm) == ami + + with patch( + "salt.cloud.clouds.ec2.config.get_cloud_config_value", + return_value=ami, + ): + # test ami-image + assert ec2.get_imageid(vm) == ami + # we should have only ran aws.query once when testing the aws filter + aws_query.assert_called_once() + + +def test_termination_protection(): + """ + Verify that `set_termination_protection` updates the right parameters + """ + vm = {"name": "taco"} + set_del_root_vol_on_destroy = "yes" + termination_protection = True + config_side_effect = ( + [None] * 2 + + ["test/*"] + + [None] * 13 + + [set_del_root_vol_on_destroy, termination_protection] + ) + with patch( + "salt.cloud.clouds.ec2.config.get_cloud_config_value", + side_effect=config_side_effect, + ): + with patch("salt.cloud.clouds.ec2.get_location", return_value="us-west2"): + with patch( + "salt.cloud.clouds.ec2.get_availability_zone", return_value=None + ): + with patch("salt.cloud.clouds.ec2.get_provider", return_value="ec2"): + with patch( + "salt.cloud.clouds.ec2.get_spot_config", return_value=None + ): + with patch( + "salt.cloud.clouds.ec2._param_from_config" + ) as _param_from_config: + with patch( + "salt.cloud.clouds.ec2.securitygroupid", + return_value=None, + ): + with pytest.raises( + salt.exceptions.SaltCloudConfigError + ): + ec2.request_instance(vm) + _param_from_config.assert_called_once_with( + "DisableApiTermination", True + ) + + +def test_termination_protection_exception(): + """ + Verify improper `set_termination_protection` parameters raises an exception + """ + vm = {"name": "taco"} + termination_protection = "not a bool" + config_side_effect = ( + [None] * 2 + ["test/*"] + [None] * 14 + [termination_protection] + ) + with patch( + "salt.cloud.clouds.ec2.config.get_cloud_config_value", + side_effect=config_side_effect, + ): + with patch("salt.cloud.clouds.ec2.get_location", return_value="us-west2"): + with patch( + "salt.cloud.clouds.ec2.get_availability_zone", return_value=None + ): + with patch("salt.cloud.clouds.ec2.get_provider", return_value="ec2"): + with patch( + "salt.cloud.clouds.ec2.get_spot_config", return_value=None + ): + with patch( + "salt.cloud.clouds.ec2.securitygroupid", return_value=None + ): + with pytest.raises(salt.exceptions.SaltCloudConfigError): + ec2.request_instance(vm) + + +def test_get_subnetname_id(): + """ + test querying subnetid function + """ + vm = {} + subnetid = "subnet-5678" + subnetname = "valid-subnet-with-name" + aws_query_return_value = [ + {"subnetId": "subnet-1234"}, + { + "subnetId": subnetid, + "tagSet": {"item": {"key": "Name", "value": subnetname}}, + }, + ] + with patch( + "salt.cloud.clouds.ec2.config.get_cloud_config_value", return_value=subnetname + ): + with patch("salt.cloud.clouds.ec2.get_location", return_value="us-west-2"): + with patch("salt.cloud.clouds.ec2.get_provider", return_value="ec2"): + with patch( + "salt.cloud.clouds.ec2.aws.query", + return_value=aws_query_return_value, + ): + # test for returns that include subnets with missing Name tags, see Issue 44330 + assert ec2._get_subnetname_id(subnetname) == subnetid diff --git a/tests/pytests/unit/cloud/clouds/test_joyent.py b/tests/pytests/unit/cloud/clouds/test_joyent.py new file mode 100644 index 000000000000..6931b16159e0 --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/test_joyent.py @@ -0,0 +1,93 @@ +""" + :codeauthor: Eric Radman +""" + +import pytest + +from salt.cloud.clouds import joyent +from tests.support.mock import MagicMock, patch + +pytestmark = [ + pytest.mark.skipif( + joyent.HAS_REQUIRED_CRYPTO is False, + reason="PyCrypto or Cryptodome not installed", + ) +] + + +def _fake_wait_for_ip( + check_for_ip_fn, interval=None, timeout=None, interval_multiplier=None +): + """ + Callback that returns immediately instead of waiting + """ + assert isinstance(interval, int) + assert isinstance(timeout, int) + assert isinstance(interval_multiplier, int) + return check_for_ip_fn() + + +@pytest.fixture +def configure_loader_modules(): + with patch("salt.utils.cloud.wait_for_ip", _fake_wait_for_ip): + yield { + joyent: { + "__utils__": { + "cloud.fire_event": MagicMock(), + "cloud.bootstrap": MagicMock(), + }, + "__opts__": { + "sock_dir": True, + "transport": True, + "providers": {"my_joyent": {}}, + "profiles": {"my_joyent": {}}, + }, + "__active_provider_name__": "my_joyent:joyent", + } + } + + +@pytest.fixture +def vm_(): + return { + "profile": "my_joyent", + "name": "vm3", + "driver": "joyent", + "size": "k4-highcpu-kvm-750M", + "image": "freebsd10", + "location": "us-east-1", + } + + +def test_query_instance_init(vm_): + """ + Initial provisioning, no IP assigned + """ + # Not yet reachable + reply = (200, {"state": "provisioning"}) + with patch.object(joyent, "show_instance", return_value=reply): + result = joyent.query_instance(vm_) + joyent.__utils__["cloud.fire_event"].assert_called_once() + assert result is None + + +def test_query_instance_has_ip(vm_): + """ + IP address assigned but not yet ready + """ + reply = (200, {"primaryIp": "1.1.1.1", "state": "provisioning"}) + with patch.object(joyent, "show_instance", return_value=reply): + result = joyent.query_instance(vm_) + joyent.__utils__["cloud.fire_event"].assert_called_once() + assert result is None + + +def test_query_instance_ready(vm_): + """ + IP address assigned, and VM is ready + """ + reply = (200, {"primaryIp": "1.1.1.1", "state": "running"}) + with patch.object(joyent, "show_instance", return_value=reply): + result = joyent.query_instance(vm_) + joyent.__utils__["cloud.fire_event"].assert_called_once() + assert result == "1.1.1.1" diff --git a/tests/pytests/unit/cloud/clouds/test_linode.py b/tests/pytests/unit/cloud/clouds/test_linode.py new file mode 100644 index 000000000000..45934e4f362c --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/test_linode.py @@ -0,0 +1,98 @@ +""" + :codeauthor: Nicole Thomas +""" + +import pytest + +from salt.cloud.clouds import linode + + +@pytest.fixture +def configure_loader_modules(): + return {linode: {}} + + +# _validate_name tests + + +def test_validate_name_first_character_invalid(): + """ + Tests when name starts with an invalid character. + """ + # Test when name begins with a hyphen + assert linode._validate_name("-foo") is False + + # Test when name begins with an underscore + assert linode._validate_name("_foo") is False + + +def test_validate_name_last_character_invalid(): + """ + Tests when name ends with an invalid character. + """ + # Test when name ends with a hyphen + assert linode._validate_name("foo-") is False + + # Test when name ends with an underscore + assert linode._validate_name("foo_") is False + + +def test_validate_name_too_short(): + """ + Tests when name has less than three letters. + """ + # Test when name is an empty string + assert linode._validate_name("") is False + + # Test when name is two letters long + assert linode._validate_name("ab") is False + + # Test when name is three letters long (valid) + assert linode._validate_name("abc") is True + + +def test_validate_name_too_long(): + """ + Tests when name has more than 48 letters. + """ + long_name = "1111-2222-3333-4444-5555-6666-7777-8888-9999-111" + # Test when name is 48 letters long (valid) + assert len(long_name) == 48 + assert linode._validate_name(long_name) is True + + # Test when name is more than 48 letters long + long_name += "1" + assert len(long_name) == 49 + assert linode._validate_name(long_name) is False + + +def test_validate_name_invalid_characters(): + """ + Tests when name contains invalid characters. + """ + # Test when name contains an invalid character + assert linode._validate_name("foo;bar") is False + + # Test when name contains non-ascii letters + assert linode._validate_name("fooàààààbar") is False + + # Test when name contains spaces + assert linode._validate_name("foo bar") is False + + +def test_validate_name_valid_characters(): + """ + Tests when name contains valid characters. + """ + # Test when name contains letters and numbers + assert linode._validate_name("foo123bar") is True + + # Test when name contains hyphens + assert linode._validate_name("foo-bar") is True + + # Test when name contains underscores + assert linode._validate_name("foo_bar") is True + + # Test when name start and end with numbers + assert linode._validate_name("1foo") is True + assert linode._validate_name("foo0") is True diff --git a/tests/pytests/unit/cloud/clouds/test_opennebula.py b/tests/pytests/unit/cloud/clouds/test_opennebula.py new file mode 100644 index 000000000000..3fd277c9e2ba --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/test_opennebula.py @@ -0,0 +1,1817 @@ +""" + :codeauthor: Nicole Thomas +""" + +import pytest + +from salt.cloud.clouds import opennebula +from salt.exceptions import SaltCloudNotFound, SaltCloudSystemExit +from tests.support.mock import MagicMock, patch + +try: + from lxml import etree # pylint: disable=unused-import + + HAS_XML_LIBS = True +except ImportError: + HAS_XML_LIBS = False + +VM_NAME = "my-vm" + + +@pytest.fixture +def configure_loader_modules(): + return { + opennebula: { + "__utils__": {"cloud.cache_node": MagicMock()}, + "__active_provider_name__": "", + } + } + + +def test_avail_images_action(): + """ + Tests that a SaltCloudSystemExit error is raised when trying to call + avail_images with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.avail_images, "action") + + +def test_avail_locations_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call avail_locations + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.avail_locations, "action") + + +def test_avail_sizes_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call avail_sizes + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.avail_sizes, "action") + + +def test_avail_sizes(): + """ + Tests that avail_sizes returns an empty dictionary. + """ + assert opennebula.avail_sizes(call="foo") == {} + + +def test_list_clusters_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_clusters + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.list_clusters, "action") + + +def test_list_datastores_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_datastores + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.list_datastores, "action") + + +def test_list_hosts_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_datastores + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.list_hosts, "action") + + +def test_list_nodes_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.list_nodes, "action") + + +def test_list_nodes_full_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_full + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.list_nodes_full, "action") + + +def test_list_nodes_select_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_full + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.list_nodes_select, "action") + + +def test_list_security_groups_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call + list_security_groups with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.list_security_groups, "action") + + +def test_list_templates_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_templates + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.list_templates, "action") + + +def test_list_vns_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_vns + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.list_vns, "action") + + +def test_reboot_error(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call reboot + with anything other that --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.reboot, "my-vm", "foo") + + +def test_start_error(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call start + with anything other that --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.start, "my-vm", "foo") + + +def test_stop_error(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call stop + with anything other that --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.stop, "my-vm", "foo") + + +def test_get_cluster_id_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call + get_cluster_id with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_cluster_id, call="action") + + +def test_get_cluster_id_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_cluster_id, None, call="foo") + + +def test_get_cluster_id_not_found(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + with patch( + "salt.cloud.clouds.opennebula.list_clusters", + MagicMock(return_value={"foo": {"id": "bar"}}), + ): + pytest.raises( + SaltCloudSystemExit, + opennebula.get_cluster_id, + kwargs={"name": "test"}, + call="function", + ) + + +def test_get_cluster_id_success(): + """ + Tests that the function returns successfully. + """ + with patch( + "salt.cloud.clouds.opennebula.list_clusters", + MagicMock(return_value={"test-cluster": {"id": "100"}}), + ): + mock_id = "100" + mock_kwargs = {"name": "test-cluster"} + assert opennebula.get_cluster_id(mock_kwargs, "foo") == mock_id + + +def test_get_datastore_id_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call + get_datastore_id with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_datastore_id, call="action") + + +def test_get_datastore_id_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_datastore_id, None, call="foo") + + +def test_get_datastore_id_not_found(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + with patch( + "salt.cloud.clouds.opennebula.list_datastores", + MagicMock(return_value={"test-datastore": {"id": "100"}}), + ): + pytest.raises( + SaltCloudSystemExit, + opennebula.get_datastore_id, + kwargs={"name": "test"}, + call="function", + ) + + +def test_get_datastore_id_success(): + """ + Tests that the function returns successfully. + """ + with patch( + "salt.cloud.clouds.opennebula.list_datastores", + MagicMock(return_value={"test-datastore": {"id": "100"}}), + ): + mock_id = "100" + mock_kwargs = {"name": "test-datastore"} + assert opennebula.get_datastore_id(mock_kwargs, "foo") == mock_id + + +def test_get_host_id_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call + get_host_id with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_host_id, call="action") + + +def test_get_host_id_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_host_id, None, call="foo") + + +def test_get_host_id_not_found(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + with patch( + "salt.cloud.clouds.opennebula.avail_locations", + MagicMock(return_value={"test-host": {"id": "100"}}), + ): + pytest.raises( + SaltCloudSystemExit, + opennebula.get_host_id, + kwargs={"name": "test"}, + call="function", + ) + + +def test_get_host_id_success(): + """ + Tests that the function returns successfully. + """ + with patch( + "salt.cloud.clouds.opennebula.avail_locations", + MagicMock(return_value={"test-host": {"id": "100"}}), + ): + mock_id = "100" + mock_kwargs = {"name": "test-host"} + assert opennebula.get_host_id(mock_kwargs, "foo") == mock_id + + +def test_get_image_not_found(): + """ + Tests that a SaltCloudNotFound is raised when the image doesn't exist. + """ + with patch("salt.cloud.clouds.opennebula.avail_images", MagicMock(return_value={})): + with patch("salt.config.get_cloud_config_value", MagicMock(return_value="foo")): + pytest.raises(SaltCloudNotFound, opennebula.get_image, "my-vm") + + +def test_get_image_success(): + """ + Tests that the image is returned successfully. + """ + with patch( + "salt.cloud.clouds.opennebula.avail_images", + MagicMock(return_value={"my-vm": {"name": "my-vm", "id": 0}}), + ): + with patch( + "salt.config.get_cloud_config_value", MagicMock(return_value="my-vm") + ): + assert opennebula.get_image("my-vm") == 0 + + +def test_get_image_id_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call + get_image_id with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_image_id, call="action") + + +def test_get_image_id_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_image_id, None, call="foo") + + +def test_get_image_id_not_found(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + with patch( + "salt.cloud.clouds.opennebula.avail_images", + MagicMock(return_value={"test-image": {"id": "100"}}), + ): + pytest.raises( + SaltCloudSystemExit, + opennebula.get_image_id, + kwargs={"name": "test"}, + call="function", + ) + + +def test_get_image_id_success(): + """ + Tests that the function returns successfully. + """ + with patch( + "salt.cloud.clouds.opennebula.avail_images", + MagicMock(return_value={"test-image": {"id": "100"}}), + ): + mock_id = "100" + mock_kwargs = {"name": "test-image"} + assert opennebula.get_image_id(mock_kwargs, "foo") == mock_id + + +def test_get_location_not_found(): + """ + Tests that a SaltCloudNotFound is raised when the location doesn't exist. + """ + with patch( + "salt.cloud.clouds.opennebula.avail_locations", MagicMock(return_value={}) + ): + with patch("salt.config.get_cloud_config_value", MagicMock(return_value="foo")): + pytest.raises(SaltCloudNotFound, opennebula.get_location, "my-vm") + + +def test_get_location_success(): + """ + Tests that the image is returned successfully. + """ + with patch( + "salt.cloud.clouds.opennebula.avail_locations", + MagicMock(return_value={"my-host": {"name": "my-host", "id": 0}}), + ): + with patch( + "salt.config.get_cloud_config_value", MagicMock(return_value="my-host") + ): + assert opennebula.get_location("my-host") == 0 + + +def test_get_secgroup_id_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call + get_host_id with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_secgroup_id, call="action") + + +def test_get_secgroup_id_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_secgroup_id, None, call="foo") + + +def test_get_secgroup_id_not_found(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + with patch( + "salt.cloud.clouds.opennebula.list_security_groups", + MagicMock(return_value={"test-security-group": {"id": "100"}}), + ): + pytest.raises( + SaltCloudSystemExit, + opennebula.get_secgroup_id, + kwargs={"name": "test"}, + call="function", + ) + + +def test_get_secgroup_id_success(): + """ + Tests that the function returns successfully. + """ + with patch( + "salt.cloud.clouds.opennebula.list_security_groups", + MagicMock(return_value={"test-secgroup": {"id": "100"}}), + ): + mock_id = "100" + mock_kwargs = {"name": "test-secgroup"} + assert opennebula.get_secgroup_id(mock_kwargs, "foo") == mock_id + + +def test_get_template_id_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call + get_template_id with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_template_id, call="action") + + +def test_get_template_id_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_template_id, None, call="foo") + + +def test_get_template_id_not_found(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + with patch( + "salt.cloud.clouds.opennebula.list_templates", + MagicMock(return_value={"test-template": {"id": "100"}}), + ): + pytest.raises( + SaltCloudSystemExit, + opennebula.get_template_id, + kwargs={"name": "test"}, + call="function", + ) + + +def test_get_template_id_success(): + """ + Tests that the function returns successfully. + """ + with patch( + "salt.cloud.clouds.opennebula.list_templates", + MagicMock(return_value={"test-template": {"id": "100"}}), + ): + mock_id = "100" + mock_kwargs = {"name": "test-template"} + assert opennebula.get_template_id(mock_kwargs, "foo") == mock_id + + +def test_get_vm_id_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call + get_vm_id with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_vm_id, call="action") + + +def test_get_vm_id_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_vm_id, None, call="foo") + + +def test_get_vm_id_not_found(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + with patch( + "salt.cloud.clouds.opennebula.list_nodes", + MagicMock(return_value={"test-vm": {"id": "100"}}), + ): + pytest.raises( + SaltCloudSystemExit, + opennebula.get_vm_id, + kwargs={"name": "test"}, + call="function", + ) + + +def test_get_vm_id_success(): + """ + Tests that the function returns successfully. + """ + with patch( + "salt.cloud.clouds.opennebula.list_nodes", + MagicMock(return_value={"test-vm": {"id": "100"}}), + ): + mock_id = "100" + mock_kwargs = {"name": "test-vm"} + assert opennebula.get_vm_id(mock_kwargs, "foo") == mock_id + + +def test_get_vn_id_action(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call + get_vn_id with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_vn_id, call="action") + + +def test_get_vn_id_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.get_vn_id, None, call="foo") + + +def test_get_vn_id_not_found(): + """ + Tests that a SaltCloudSystemExit is raised when no name is provided. + """ + with patch( + "salt.cloud.clouds.opennebula.list_vns", + MagicMock(return_value={"test-vn": {"id": "100"}}), + ): + pytest.raises( + SaltCloudSystemExit, + opennebula.get_vn_id, + kwargs={"name": "test"}, + call="function", + ) + + +def test_get_vn_id_success(): + """ + Tests that the function returns successfully. + """ + with patch( + "salt.cloud.clouds.opennebula.list_vns", + MagicMock(return_value={"test-vn": {"id": "100"}}), + ): + mock_id = "100" + mock_kwargs = {"name": "test-vn"} + assert opennebula.get_vn_id(mock_kwargs, "foo") == mock_id + + +# TODO: Write tests for create function + + +def test_destroy_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.destroy, "my-vm", "function") + + +def test_image_allocate_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_allocate, "foo") + + +def test_image_allocate_no_name_or_datastore_id(): + """ + Tests that a SaltCloudSystemExit is raised when a neither a datastore_id + nor a datastore_name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_allocate, "function") + + +def test_image_allocate_no_path_or_data(): + """ + Tests that a SaltCloudSystemExit is raised when neither the path nor data args + are provided. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_allocate, + "function", + kwargs={"datastore_id": "5"}, + ) + + +def test_image_clone_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_clone, "foo") + + +def test_image_clone_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when a name isn't provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_clone, "function") + + +def test_image_clone_no_image_id_or_image_name(): + """ + Tests that a SaltCloudSystemExit is raised when neither the image_id nor + the image_name args are provided. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_clone, + "function", + kwargs={"name": "test"}, + ) + + +@pytest.mark.skipif( + True, reason="Need to figure out how to mock calls to the O.N. API first." +) +def test_image_clone_success(): + """ + Tests that image_clone returns successfully + """ + with patch("image.clone", MagicMock(return_value=[True, 11, 0])): + name = "test-image" + expected = { + "action": "image.clone", + "cloned": "True", + "cloned_image_id": "11", + "cloned_image_name": name, + "error_code": "0", + } + ret = opennebula.image_clone("function", kwargs={"name": name, "image_id": 1}) + assert expected == ret + + +def test_image_delete_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_delete, "foo") + + +def test_image_delete_no_name_or_image_id(): + """ + Tests that a SaltCloudSystemExit is raised when a neither an image_id + nor a name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_delete, "function") + + +def test_image_info_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_info, "foo") + + +def test_image_info_no_image_id_or_image_name(): + """ + Tests that a SaltCloudSystemExit is raised when a neither an image_id + nor a name is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_info, "function") + + +def test_image_persist_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_persistent, "foo") + + +def test_image_persist_no_persist(): + """ + Tests that a SaltCloudSystemExit is raised when the persist kwarg is missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_persistent, "function") + + +def test_image_persist_no_name_or_image_id(): + """ + Tests that a SaltCloudSystemExit is raised when a neither an image_id + nor a name is provided. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_delete, + "function", + kwargs={"persist": False}, + ) + + +def test_image_snapshot_delete_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_snapshot_delete, call="foo") + + +def test_image_snapshot_delete_no_snapshot_id(): + """ + Tests that a SaltCloudSystemExit is raised when the snapshot_id kwarg is + missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_snapshot_delete, + call="function", + kwargs=None, + ) + + +def test_image_snapshot_delete_no_image_name_or_image_id(): + """ + Tests that a SaltCloudSystemExit is raised when the image_id and image_name + kwargs are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_snapshot_delete, + call="function", + kwargs={"snapshot_id": 0}, + ) + + +def test_image_snapshot_revert_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_snapshot_revert, call="foo") + + +def test_image_snapshot_revert_no_snapshot_id(): + """ + Tests that a SaltCloudSystemExit is raised when the snapshot_id kwarg is + missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_snapshot_revert, + call="function", + kwargs=None, + ) + + +def test_image_snapshot_revert_no_image_name_or_image_id(): + """ + Tests that a SaltCloudSystemExit is raised when the image_id and image_name + kwargs are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_snapshot_revert, + call="function", + kwargs={"snapshot_id": 0}, + ) + + +def test_image_snapshot_flatten_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_snapshot_flatten, call="foo") + + +def test_image_snapshot_flatten_no_snapshot_id(): + """ + Tests that a SaltCloudSystemExit is raised when the snapshot_id kwarg is + missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_snapshot_flatten, + call="function", + kwargs=None, + ) + + +def test_image_snapshot_flatten_no_image_name_or_image_id(): + """ + Tests that a SaltCloudSystemExit is raised when the image_id and image_name + kwargs are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_snapshot_flatten, + call="function", + kwargs={"snapshot_id": 0}, + ) + + +def test_image_update_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_update, "foo") + + +def test_image_update_no_update_type(): + """ + Tests that a SaltCloudSystemExit is raised when the update_type kwarg is + missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.image_update, "function") + + +def test_image_update_bad_update_type_value(): + """ + Tests that a SaltCloudSystemExit is raised when the update_type kwarg is + not a valid value. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_update, + "function", + kwargs={"update_type": "foo"}, + ) + + +def test_image_update_no_image_id_or_image_name(): + """ + Tests that a SaltCloudSystemExit is raised when the image_id and image_name + kwargs are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_update, + "function", + kwargs={"update_type": "merge"}, + ) + + +def test_image_update_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and path + kwargs are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.image_update, + "function", + kwargs={"update_type": "merge", "image_id": "0"}, + ) + + +def test_show_instance_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.show_instance, VM_NAME, call="foo") + + +def test_show_instance_success(): + """ + Tests that the node was found successfully. + """ + with patch( + "salt.cloud.clouds.opennebula._get_node", + MagicMock(return_value={"my-vm": {"name": "my-vm", "id": 0}}), + ): + ret = {"my-vm": {"name": "my-vm", "id": 0}} + assert opennebula.show_instance("my-vm", call="action") == ret + + +def test_secgroup_allocate_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.secgroup_allocate, "foo") + + +def test_secgroup_allocate_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and path + kwargs are missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.secgroup_allocate, "function") + + +def test_secgroup_clone_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.secgroup_clone, "foo") + + +def test_secgroup_clone_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when the name kwarg is + missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.secgroup_clone, "function") + + +def test_secgroup_clone_no_secgroup_id_or_secgroup_name(): + """ + Tests that a SaltCloudSystemExit is raised when the secgroup_id and + secgroup_name kwargs are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.secgroup_clone, + "function", + kwargs={"name": "test"}, + ) + + +def test_secgroup_delete_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.secgroup_delete, "foo") + + +def test_secgroup_delete_no_secgroup_id_or_name(): + """ + Tests that a SaltCloudSystemExit is raised when the secgroup_id and + name kwargs are missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.secgroup_clone, "function") + + +def test_secgroup_info_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.secgroup_info, "foo") + + +def test_secgroup_info_no_secgroup_id_or_name(): + """ + Tests that a SaltCloudSystemExit is raised when the secgroup_id and + name kwargs are missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.secgroup_info, "function") + + +def test_secgroup_update_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.secgroup_update, "foo") + + +def test_secgroup_update_no_update_type(): + """ + Tests that a SaltCloudSystemExit is raised when the update_type arg is + missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.secgroup_update, "function") + + +def test_secgroup_update_bad_update_type_value(): + """ + Tests that a SaltCloudSystemExit is raised when the update_type contains + an invalid value. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.secgroup_update, + "function", + kwargs={"update_type": "foo"}, + ) + + +def test_secgroup_update_no_secgroup_id_or_secgroup_name(): + """ + Tests that a SaltCloudSystemExit is raised when the secgroup_id and + secgroup_name kwargs are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.secgroup_update, + "function", + kwargs={"update_type": "merge"}, + ) + + +def test_secgroup_update_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and + path kwargs are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.secgroup_update, + "function", + kwargs={"update_type": "merge", "secgroup_id": "0"}, + ) + + +def test_template_allocate_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.template_allocate, "foo") + + +def test_template_allocate_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and + path kwargs are missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.template_allocate, "function") + + +def test_template_clone_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.template_clone, "foo") + + +def test_template_clone_no_name(): + """ + Tests that a SaltCloudSystemExit is raised when the name arg is missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.template_clone, "function") + + +def test_template_clone_no_template_name_or_template_id(): + """ + Tests that a SaltCloudSystemExit is raised when the template_name and + template_id args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.template_clone, + "function", + kwargs={"name": "foo"}, + ) + + +def test_template_delete_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.template_delete, "foo") + + +def test_template_delete_no_name_or_template_id(): + """ + Tests that a SaltCloudSystemExit is raised when the name and + template_id args are missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.template_delete, "function") + + +def test_template_instantiate_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.template_instantiate, "foo") + + +def test_template_instantiate_no_vm_name(): + """ + Tests that a SaltCloudSystemExit is raised when the vm_name arg is missing. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.template_instantiate, "function", None + ) + + +def test_template_instantiate_no_template_id_or_template_name(): + """ + Tests that a SaltCloudSystemExit is raised when the template_name and + template_id args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.template_instantiate, + "function", + kwargs={"vm_name": "test"}, + ) + + +def test_template_update_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.template_update, call="foo") + + +def test_template_update_bad_update_type_value(): + """ + Tests that a SaltCloudSystemExit is raised when the update_type contains + and invalid value. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.template_update, + call="function", + kwargs={"update_type": "foo"}, + ) + + +def test_template_update_no_template_id_or_template_name(): + """ + Tests that a SaltCloudSystemExit is raised when the template_id and the + template_name args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.template_update, + call="function", + kwargs={"update_type": "merge"}, + ) + + +def test_template_update_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and the + path args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.template_update, + call="function", + kwargs={"update_type": "merge", "template_id": "0"}, + ) + + +def test_vm_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_action, VM_NAME, call="foo") + + +def test_vm_action_no_action(): + """ + Tests that a SaltCloudSystemExit is raised when the action arg is missing + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_action, VM_NAME, call="action") + + +def test_vm_allocate_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_allocate, "foo") + + +def test_vm_allocate_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and + path kwargs are missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_allocate, "function") + + +def test_vm_attach_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_attach, VM_NAME, call="foo") + + +def test_vm_attach_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and + path kwargs are missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_attach, VM_NAME, call="action") + + +def test_vm_attach_nic_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_attach_nic, VM_NAME, call="foo") + + +def test_vm_attach_nic_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and + path kwargs are missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_attach_nic, VM_NAME, call="action") + + +def test_vm_deploy_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_deploy, VM_NAME, call="foo") + + +def test_vm_deploy_no_host_id_or_host_name(): + """ + Tests that a SaltCloudSystemExit is raised when the host_id and the + host_name args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_deploy, + VM_NAME, + call="action", + kwargs=None, + ) + + +def test_vm_detach_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_detach, VM_NAME, call="foo") + + +def test_vm_detach_no_disk_id(): + """ + Tests that a SaltCloudSystemExit is raised when the disk_id ar is missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_detach, VM_NAME, call="action") + + +def test_vm_detach_nic_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_detach_nic, VM_NAME, call="foo") + + +def test_vm_detach_nic_no_nic_id(): + """ + Tests that a SaltCloudSystemExit is raised when the nic_id arg is missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_detach_nic, VM_NAME, call="action") + + +def test_vm_disk_save_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_disk_save, VM_NAME, call="foo") + + +def test_vm_disk_save_no_disk_id(): + """ + Tests that a SaltCloudSystemExit is raised when the disk_id arg is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_disk_save, + VM_NAME, + call="action", + kwargs={"image_name": "foo"}, + ) + + +def test_vm_disk_save_no_image_name(): + """ + Tests that a SaltCloudSystemExit is raised when the image_name arg is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_disk_save, + VM_NAME, + call="action", + kwargs={"disk_id": "0"}, + ) + + +def test_vm_disk_snapshot_create_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vm_disk_snapshot_create, VM_NAME, call="foo" + ) + + +def test_vm_disk_snapshot_create_no_disk_id(): + """ + Tests that a SaltCloudSystemExit is raised when the disk_id arg is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_disk_snapshot_create, + VM_NAME, + call="action", + kwargs={"description": "foo"}, + ) + + +def test_vm_disk_snapshot_create_no_description(): + """ + Tests that a SaltCloudSystemExit is raised when the image_name arg is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_disk_snapshot_create, + VM_NAME, + call="action", + kwargs={"disk_id": "0"}, + ) + + +def test_vm_disk_snapshot_delete_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vm_disk_snapshot_delete, VM_NAME, call="foo" + ) + + +def test_vm_disk_snapshot_delete_no_disk_id(): + """ + Tests that a SaltCloudSystemExit is raised when the disk_id arg is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_disk_snapshot_delete, + VM_NAME, + call="action", + kwargs={"snapshot_id": "0"}, + ) + + +def test_vm_disk_snapshot_delete_no_snapshot_id(): + """ + Tests that a SaltCloudSystemExit is raised when the snapshot_id arg is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_disk_snapshot_delete, + VM_NAME, + call="action", + kwargs={"disk_id": "0"}, + ) + + +def test_vm_disk_snapshot_revert_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vm_disk_snapshot_revert, VM_NAME, call="foo" + ) + + +def test_vm_disk_snapshot_revert_no_disk_id(): + """ + Tests that a SaltCloudSystemExit is raised when the disk_id arg is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_disk_snapshot_revert, + VM_NAME, + call="action", + kwargs={"snapshot_id": "0"}, + ) + + +def test_vm_disk_snapshot_revert_no_snapshot_id(): + """ + Tests that a SaltCloudSystemExit is raised when the snapshot_id arg is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_disk_snapshot_revert, + VM_NAME, + call="action", + kwargs={"disk_id": "0"}, + ) + + +def test_vm_info_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_info, VM_NAME, call="foo") + + +def test_vm_migrate_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_migrate, VM_NAME, call="foo") + + +def test_vm_migrate_no_datastore_id_or_datastore_name(): + """ + Tests that a SaltCLoudSystemExit is raised when the datastore_id and the + datastore_name args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_migrate, + VM_NAME, + call="action", + kwargs=None, + ) + + +def test_vm_migrate_no_host_id_or_host_name(): + """ + Tests that a SaltCloudSystemExit is raised when the host_id and the + host_name args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_migrate, + VM_NAME, + call="action", + kwargs={"datastore_id": "0"}, + ) + + +def test_vm_monitoring_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_monitoring, VM_NAME, call="foo") + + +def test_vm_resize_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_resize, VM_NAME, call="foo") + + +def test_vm_resize_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and path args + are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_resize, + VM_NAME, + call="action", + kwargs=None, + ) + + +def test_vm_snapshot_create_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vm_snapshot_create, VM_NAME, call="foo" + ) + + +def test_vm_snapshot_create_no_snapshot_name(): + """ + Tests that a SaltCloudSystemExit is raised when the snapshot_name arg + is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_snapshot_create, + VM_NAME, + call="action", + kwargs=None, + ) + + +def test_vm_snapshot_delete_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vm_snapshot_delete, VM_NAME, call="foo" + ) + + +def test_vm_snapshot_delete_no_snapshot_id(): + """ + Tests that a SaltCloudSystemExit is raised when the snapshot_id arg + is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_snapshot_delete, + VM_NAME, + call="action", + kwargs=None, + ) + + +def test_vm_snapshot_revert_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vm_snapshot_revert, VM_NAME, call="foo" + ) + + +def test_vm_snapshot_revert_no_snapshot_id(): + """ + Tests that a SaltCloudSystemExit is raised when the snapshot_id arg + is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_snapshot_revert, + VM_NAME, + call="action", + kwargs=None, + ) + + +def test_vm_update_action_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --action or -a is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vm_update, VM_NAME, call="foo") + + +def test_vm_update_no_update_type(): + """ + Tests that a SaltCloudSystemExit is raised when the update_type arg + is missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_update, + VM_NAME, + call="action", + kwargs=None, + ) + + +def test_vm_update_bad_update_type_value(): + """ + Tests that a SaltCloudSystemExit is raised when the update_type kwarg is + not a valid value. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_update, + VM_NAME, + call="action", + kwargs={"update_type": "foo"}, + ) + + +def test_vm_update_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and path args + are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vm_update, + VM_NAME, + call="action", + kwargs={"update_type": "merge"}, + ) + + +def test_vn_add_ar_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vn_add_ar, call="foo") + + +def test_vn_add_ar_no_vn_id_or_vn_name(): + """ + Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name + args are missing. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vn_add_ar, call="function", kwargs=None + ) + + +def test_vn_add_ar_no_path_or_data(): + """ + Tests that a SaltCloudSystemExit is raised when the path and data + args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vn_add_ar, + call="function", + kwargs={"vn_id": "0"}, + ) + + +def test_vn_allocate_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vn_allocate, call="foo") + + +def test_vn_allocate_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the path and data + args are missing. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vn_allocate, call="function", kwargs=None + ) + + +def test_vn_delete_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vn_delete, call="foo") + + +def test_vn_delete_no_vn_id_or_name(): + """ + Tests that a SaltCloudSystemExit is raised when the vn_id and name + args are missing. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vn_delete, call="function", kwargs=None + ) + + +def test_vn_free_ar_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vn_free_ar, call="foo") + + +def test_vn_free_ar_no_ar_id(): + """ + Tests that a SaltCloudSystemExit is raised when the ar_id is missing. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vn_free_ar, call="function", kwargs=None + ) + + +def test_vn_free_ar_no_vn_id_or_vn_name(): + """ + Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name + args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vn_free_ar, + call="function", + kwargs={"ar_id": "0"}, + ) + + +def test_vn_hold_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vn_hold, call="foo") + + +def test_vn_hold_no_vn_id_or_vn_name(): + """ + Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name + args are missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vn_hold, call="function", kwargs=None) + + +def test_vn_hold_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and path + args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vn_hold, + call="function", + kwargs={"vn_id": "0"}, + ) + + +def test_vn_info_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vn_info, call="foo") + + +def test_vn_info_no_vn_id_or_vn_name(): + """ + Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name + args are missing. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vn_info, call="function", kwargs=None) + + +def test_vn_release_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vn_release, call="foo") + + +def test_vn_release_no_vn_id_or_vn_name(): + """ + Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name + args are missing. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vn_release, call="function", kwargs=None + ) + + +def test_vn_release_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and path + args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vn_release, + call="function", + kwargs={"vn_id": "0"}, + ) + + +def test_vn_reserve_function_error(): + """ + Tests that a SaltCloudSystemExit is raised when something other than + --function or -f is provided. + """ + pytest.raises(SaltCloudSystemExit, opennebula.vn_reserve, call="foo") + + +def test_vn_reserve_no_vn_id_or_vn_name(): + """ + Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name + args are missing. + """ + pytest.raises( + SaltCloudSystemExit, opennebula.vn_reserve, call="function", kwargs=None + ) + + +def test_vn_reserve_no_data_or_path(): + """ + Tests that a SaltCloudSystemExit is raised when the data and path + args are missing. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula.vn_reserve, + call="function", + kwargs={"vn_id": "0"}, + ) + + +@pytest.mark.skipif(not HAS_XML_LIBS, reason="cannot find lxml python library") +def test__get_xml(): + """ + Tests that invalid XML raises SaltCloudSystemExit. + """ + pytest.raises( + SaltCloudSystemExit, + opennebula._get_xml, + "[VirtualMachinePoolInfo] User couldn't be authenticated, aborting call.", + ) diff --git a/tests/pytests/unit/cloud/clouds/test_openstack.py b/tests/pytests/unit/cloud/clouds/test_openstack.py index 788b942dad52..f78935c14499 100644 --- a/tests/pytests/unit/cloud/clouds/test_openstack.py +++ b/tests/pytests/unit/cloud/clouds/test_openstack.py @@ -1,12 +1,65 @@ import pytest import salt.cloud.clouds.openstack as openstack -from tests.support.mock import call, patch +from salt.utils import dictupdate +from tests.support.mock import MagicMock, call, patch + +# pylint: disable=confusing-with-statement + + +class MockImage: + name = "image name" + id = "image id" + + +class MockNode: + name = "node name" + id = "node id" + flavor = MockImage() + status = "node status" + + def __init__(self, image): + self.image = image + + def __iter__(self): + return iter(()) + + +class MockConn: + def __init__(self, image): + self.node = MockNode(image) + + def get_image(self, *args, **kwargs): + return self.node.image + + def get_flavor(self, *args, **kwargs): + return self.node.flavor + + def get_server(self, *args, **kwargs): + return self.node + + def list_servers(self, *args, **kwargs): + return [self.node] @pytest.fixture def configure_loader_modules(): - return {openstack: {"__opts__": {}}} + return { + openstack: { + "__active_provider_name__": "", + "__opts__": { + "providers": { + "my-openstack-cloud": { + "openstack": { + "auth": "daenerys", + "region_name": "westeros", + "cloud": "openstack", + } + } + } + }, + } + } @pytest.fixture @@ -105,3 +158,213 @@ def test_preferred_ip_function_returns_expected( result = openstack.preferred_ip("fnord", example_ips) assert result is expected + + +def test_get_configured_provider_bad(): + with patch.dict(openstack.__opts__, {"providers": {}}): + result = openstack.get_configured_provider() + assert result is False + + +def test_get_configured_provider_auth(): + config = { + "region_name": "westeros", + "auth": "daenerys", + } + with patch.dict( + openstack.__opts__, + {"providers": {"my-openstack-cloud": {"openstack": config}}}, + ): + result = openstack.get_configured_provider() + assert config == result + + +def test_get_configured_provider_cloud(): + config = { + "region_name": "westeros", + "cloud": "foo", + } + with patch.dict( + openstack.__opts__, + {"providers": {"my-openstack-cloud": {"openstack": config}}}, + ): + result = openstack.get_configured_provider() + assert config == result + + +def test_get_dependencies(): + HAS_SHADE = (True, "Please install newer version of shade: >= 1.19.0") + with patch("salt.cloud.clouds.openstack.HAS_SHADE", HAS_SHADE): + result = openstack.get_dependencies() + assert result is True + + +def test_get_dependencies_no_shade(): + HAS_SHADE = (False, "Install pypi module shade >= 1.19.0") + with patch("salt.cloud.clouds.openstack.HAS_SHADE", HAS_SHADE): + result = openstack.get_dependencies() + assert result is False + + +def test_list_nodes_full_image_str(): + node_image = "node image" + conn = MockConn(node_image) + with patch("salt.cloud.clouds.openstack._get_ips", return_value=[]): + ret = openstack.list_nodes_full(conn=conn) + assert ret[conn.node.name]["image"] == node_image + + +def test_list_nodes_full_image_obj(): + conn = MockConn(MockImage()) + with patch("salt.cloud.clouds.openstack._get_ips", return_value=[]): + ret = openstack.list_nodes_full(conn=conn) + assert ret[conn.node.name]["image"] == MockImage.name + + +def test_show_instance(): + conn = MockConn(MockImage()) + with patch("salt.cloud.clouds.openstack._get_ips", return_value=[]): + ret = openstack.show_instance(conn.node.name, conn=conn, call="action") + assert ret["image"] == MockImage.name + + +def test_request_instance_should_use_provided_connection_if_not_None(): + fake_conn = MagicMock() + + patch_get_conn = patch("salt.cloud.clouds.openstack.get_conn", autospec=True) + patch_utils = patch.dict( + openstack.__utils__, + {"cloud.check_name": MagicMock(), "dictupdate.update": dictupdate.update}, + ) + patch_shade = patch.object( + openstack, "shade.exc.OpenStackCloudException", Exception, create=True + ) + + with patch_get_conn as fake_get_conn, patch_utils, patch_shade: + openstack.request_instance( + vm_={"name": "fnord", "driver": "fnord"}, conn=fake_conn + ) + + fake_get_conn.assert_not_called() + + +def test_request_instance_should_create_conn_if_provided_is_None(): + none_conn = None + + patch_get_conn = patch("salt.cloud.clouds.openstack.get_conn", autospec=True) + patch_utils = patch.dict( + openstack.__utils__, + {"cloud.check_name": MagicMock(), "dictupdate.update": dictupdate.update}, + ) + patch_shade = patch.object( + openstack, "shade.exc.OpenStackCloudException", Exception, create=True + ) + + with patch_get_conn as fake_get_conn, patch_utils, patch_shade: + openstack.request_instance( + vm_={"name": "fnord", "driver": "fnord"}, conn=none_conn + ) + + fake_get_conn.assert_called_once_with() + + +# According to +# https://docs.openstack.org/shade/latest/user/usage.html#shade.OpenStackCloud.create_server +# the `network` parameter can be: +# (optional) Network dict or name or ID to attach the server to. +# Mutually exclusive with the nics parameter. Can also be be a list of +# network names or IDs or network dicts. +# +# Here we're testing a normal dictionary +def test_request_instance_should_be_able_to_provide_a_dictionary_for_network(): + fake_conn = MagicMock() + expected_network = {"foo": "bar"} + vm_ = {"name": "fnord", "driver": "fnord", "network": expected_network} + patch_utils = patch.dict( + openstack.__utils__, + {"cloud.check_name": MagicMock(), "dictupdate.update": dictupdate.update}, + ) + with patch_utils: + openstack.request_instance(vm_=vm_, conn=fake_conn) + + call_kwargs = fake_conn.create_server.mock_calls[0][-1] + assert call_kwargs["network"] == expected_network + + +# Here we're testing the list of dictionaries +def test_request_instance_should_be_able_to_provide_a_list_of_dictionaries_for_network(): + fake_conn = MagicMock() + expected_network = [{"foo": "bar"}, {"bang": "quux"}] + vm_ = {"name": "fnord", "driver": "fnord", "network": expected_network} + patch_utils = patch.dict( + openstack.__utils__, + {"cloud.check_name": MagicMock(), "dictupdate.update": dictupdate.update}, + ) + with patch_utils: + openstack.request_instance(vm_=vm_, conn=fake_conn) + + call_kwargs = fake_conn.create_server.mock_calls[0][-1] + assert call_kwargs["network"] == expected_network + + +# Here we're testing for names/IDs +def test_request_instance_should_be_able_to_provide_a_list_of_single_ids_or_names_for_network(): + fake_conn = MagicMock() + expected_network = ["foo", "bar", "bang", "fnord1", "fnord2"] + vm_ = {"name": "fnord", "driver": "fnord", "network": expected_network} + patch_utils = patch.dict( + openstack.__utils__, + {"cloud.check_name": MagicMock(), "dictupdate.update": dictupdate.update}, + ) + with patch_utils: + openstack.request_instance(vm_=vm_, conn=fake_conn) + + call_kwargs = fake_conn.create_server.mock_calls[0][-1] + assert call_kwargs["network"] == expected_network + + +# Testing that we get a dict that we expect for create_server +def test__clean_create_kwargs(): + params = { + "name": "elmer", + "image": "mirrormirror", + "flavor": "chocolate", + "auto_ip": True, + "ips": ["hihicats"], + "ip_pool": "olympic", + "root_volume": "iamgroot", + "boot_volume": "pussnboots", + "terminate_volume": False, + "volumes": ["lots", "of", "books"], + "meta": {"full": "meta"}, + "files": {"shred": "this"}, + "reservation_id": "licenseandregistration", + "security_groups": ["wanna", "play", "repeat"], + "key_name": "clortho", + "availability_zone": "callmemaybe", + "block_device_mapping": [{"listof": "dicts"}], + "block_device_mapping_v2": [{"listof": "dicts"}], + "nics": ["thats", "me"], + "scheduler_hints": {"so": "many"}, + "config_drive": True, + "disk_config": "donkey", + "admin_pass": "password", + "wait": False, + "timeout": 30, + "reuse_ips": True, + "network": ["also", "a", "dict"], + "boot_from_volume": True, + "volume_size": 30, + "nat_destination": "albuquerque", + "group": "ledzeppelin", + "userdata": "needmoreinput", + "thisgetsdropped": "yup", + } + patch_utils = patch.dict( + openstack.__utils__, + {"dictupdate.update": dictupdate.update}, + ) + with patch_utils: + ret = openstack._clean_create_kwargs(**params) + params.pop("thisgetsdropped") + assert params == ret diff --git a/tests/pytests/unit/cloud/clouds/test_proxmox.py b/tests/pytests/unit/cloud/clouds/test_proxmox.py new file mode 100644 index 000000000000..1d1823a8035e --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/test_proxmox.py @@ -0,0 +1,520 @@ +""" + :codeauthor: Tyler Johnson +""" + +import io +import textwrap +import urllib + +import pytest +import requests + +from salt import config +from salt.cloud.clouds import proxmox +from tests.support.mock import ANY, MagicMock, call, patch + + +@pytest.fixture +def profile(): + return { + "my_proxmox": { + "provider": "my_proxmox", + "image": "local:some_image.tgz", + } + } + + +@pytest.fixture +def provider_config(profile): + return { + "my_proxmox": { + "proxmox": { + "driver": "proxmox", + "url": "pve@domain.com", + "user": "cloud@pve", + "password": "verybadpass", + "profiles": profile, + } + } + } + + +@pytest.fixture +def vm(): + return { + "profile": "my_proxmox", + "name": "vm4", + "driver": "proxmox", + "technology": "qemu", + "host": "127.0.0.1", + "clone": True, + "ide0": "data", + "sata0": "data", + "scsi0": "data", + "net0": "a=b,c=d", + } + + +@pytest.fixture +def configure_loader_modules(profile, provider_config): + return { + proxmox: { + "__utils__": { + "cloud.fire_event": MagicMock(), + "cloud.filter_event": MagicMock(), + "cloud.bootstrap": MagicMock(), + }, + "__opts__": { + "sock_dir": True, + "transport": True, + "providers": provider_config, + "profiles": profile, + }, + "__active_provider_name__": "my_proxmox:proxmox", + } + } + + +def test__stringlist_to_dictionary(): + result = proxmox._stringlist_to_dictionary("") + assert result == {} + + result = proxmox._stringlist_to_dictionary( + "foo=bar, ignored_space=bar,internal space=bar" + ) + assert result == {"foo": "bar", "ignored_space": "bar", "internal space": "bar"} + + # Negative cases + pytest.raises(ValueError, proxmox._stringlist_to_dictionary, "foo=bar,foo") + pytest.raises( + ValueError, + proxmox._stringlist_to_dictionary, + "foo=bar,totally=invalid=assignment", + ) + + +def test__dictionary_to_stringlist(): + result = proxmox._dictionary_to_stringlist({}) + assert result == "" + + result = proxmox._dictionary_to_stringlist({"a": "a"}) + assert result == "a=a" + + result = proxmox._dictionary_to_stringlist({"a": "a", "b": "b"}) + assert result == "a=a,b=b" + + +def test__reconfigure_clone_net_hdd(vm): + # The return_value is for the net reconfigure assertions, it is irrelevant for the rest + with patch( + "salt.cloud.clouds.proxmox._get_properties", + MagicMock(return_value=["net0", "ide0", "sata0", "scsi0"]), + ), patch.object( + proxmox, "query", return_value={"net0": "c=overwritten,g=h"} + ) as query: + # Test a vm that lacks the required attributes + proxmox._reconfigure_clone({}, 0) + query.assert_not_called() + + # Test a fully mocked vm + proxmox._reconfigure_clone(vm, 0) + + # net reconfigure + query.assert_any_call("get", "nodes/127.0.0.1/qemu/0/config") + query.assert_any_call( + "post", "nodes/127.0.0.1/qemu/0/config", {"net0": "a=b,c=d,g=h"} + ) + + # hdd reconfigure + query.assert_any_call("post", "nodes/127.0.0.1/qemu/0/config", {"ide0": "data"}) + query.assert_any_call( + "post", "nodes/127.0.0.1/qemu/0/config", {"sata0": "data"} + ) + query.assert_any_call( + "post", "nodes/127.0.0.1/qemu/0/config", {"scsi0": "data"} + ) + + +def test__reconfigure_clone_params(): + """ + Test cloning a VM with parameters to be reconfigured. + """ + vmid = 201 + properties = { + "ide2": "cdrom", + "sata1": "satatest", + "scsi0": "bootvol", + "net0": "model=virtio", + "agent": "1", + "args": "argsvalue", + "balloon": "128", + "ciuser": "root", + "cores": "2", + "description": "desc", + "memory": "256", + "name": "new2", + "onboot": "0", + "sshkeys": "ssh-rsa ABCDEF user@host\n", + } + query_calls = [call("get", "nodes/myhost/qemu/{}/config".format(vmid))] + for key, value in properties.items(): + if key == "sshkeys": + value = urllib.parse.quote(value, safe="") + query_calls.append( + call( + "post", + "nodes/myhost/qemu/{}/config".format(vmid), + {key: value}, + ) + ) + + mock_query = MagicMock(return_value="") + with patch( + "salt.cloud.clouds.proxmox._get_properties", + MagicMock(return_value=list(properties.keys())), + ), patch("salt.cloud.clouds.proxmox.query", mock_query): + vm_ = { + "profile": "my_proxmox", + "driver": "proxmox", + "technology": "qemu", + "name": "new2", + "host": "myhost", + "clone": True, + "clone_from": 123, + "ip_address": "10.10.10.10", + } + vm_.update(properties) + + proxmox._reconfigure_clone(vm_, vmid) + mock_query.assert_has_calls(query_calls, any_order=True) + + +def test_clone(): + """ + Test that an integer value for clone_from + """ + mock_query = MagicMock(return_value="") + with patch( + "salt.cloud.clouds.proxmox._get_properties", MagicMock(return_value=[]) + ), patch("salt.cloud.clouds.proxmox.query", mock_query): + vm_ = { + "technology": "qemu", + "name": "new2", + "host": "myhost", + "clone": True, + "clone_from": 123, + } + + # CASE 1: Numeric ID + result = proxmox.create_node(vm_, ANY) + mock_query.assert_called_once_with( + "post", + "nodes/myhost/qemu/123/clone", + {"newid": ANY}, + ) + assert result == {"vmid": ANY} + + # CASE 2: host:ID notation + mock_query.reset_mock() + vm_["clone_from"] = "otherhost:123" + result = proxmox.create_node(vm_, ANY) + mock_query.assert_called_once_with( + "post", + "nodes/otherhost/qemu/123/clone", + {"newid": ANY}, + ) + assert result == {"vmid": ANY} + + +def test_clone_pool(): + """ + Test that cloning a VM passes the pool parameter if present + """ + mock_query = MagicMock(return_value="") + with patch( + "salt.cloud.clouds.proxmox._get_properties", MagicMock(return_value=[]) + ), patch("salt.cloud.clouds.proxmox.query", mock_query): + vm_ = { + "technology": "qemu", + "name": "new2", + "host": "myhost", + "clone": True, + "clone_from": 123, + "pool": "mypool", + } + + result = proxmox.create_node(vm_, ANY) + mock_query.assert_called_once_with( + "post", + "nodes/myhost/qemu/123/clone", + {"newid": ANY, "pool": "mypool"}, + ) + assert result == {"vmid": ANY} + + +def test_clone_id(): + """ + Test cloning a VM with a specified vmid. + """ + next_vmid = 101 + explicit_vmid = 201 + upid = "UPID:myhost:00123456:12345678:9ABCDEF0:qmclone:123:root@pam:" + + def mock_query_response(conn_type, option, post_data=None): + if conn_type == "get" and option == "cluster/tasks": + return [{"upid": upid, "status": "OK"}] + if conn_type == "post" and option.endswith("/clone"): + return upid + return None + + mock_wait_for_state = MagicMock(return_value=True) + with patch( + "salt.cloud.clouds.proxmox._get_properties", + MagicMock(return_value=["vmid"]), + ), patch( + "salt.cloud.clouds.proxmox._get_next_vmid", + MagicMock(return_value=next_vmid), + ), patch( + "salt.cloud.clouds.proxmox.start", MagicMock(return_value=True) + ), patch( + "salt.cloud.clouds.proxmox.wait_for_state", mock_wait_for_state + ), patch( + "salt.cloud.clouds.proxmox.query", side_effect=mock_query_response + ): + vm_ = { + "profile": "my_proxmox", + "driver": "proxmox", + "technology": "qemu", + "name": "new2", + "host": "myhost", + "clone": True, + "clone_from": 123, + "ip_address": "10.10.10.10", + } + + # CASE 1: No vmid specified in profile (previous behavior) + proxmox.create(vm_) + mock_wait_for_state.assert_called_with( + next_vmid, + "running", + ) + + # CASE 2: vmid specified in profile + vm_["vmid"] = explicit_vmid + proxmox.create(vm_) + mock_wait_for_state.assert_called_with( + explicit_vmid, + "running", + ) + + +def test_find_agent_ips(): + """ + Test find_agent_ip will return an IP + """ + + with patch( + "salt.cloud.clouds.proxmox.query", + return_value={ + "result": [ + { + "name": "eth0", + "ip-addresses": [ + {"ip-address": "1.2.3.4", "ip-address-type": "ipv4"}, + {"ip-address": "2001::1:2", "ip-address-type": "ipv6"}, + ], + }, + { + "name": "eth1", + "ip-addresses": [ + {"ip-address": "2.3.4.5", "ip-address-type": "ipv4"}, + ], + }, + { + "name": "dummy", + }, + ] + }, + ) as mock_query: + vm_ = { + "technology": "qemu", + "host": "myhost", + "driver": "proxmox", + "ignore_cidr": "1.0.0.0/8", + } + + # CASE 1: Test ipv4 and ignore_cidr + result = proxmox._find_agent_ip(vm_, ANY) + mock_query.assert_any_call( + "get", "nodes/myhost/qemu/{}/agent/network-get-interfaces".format(ANY) + ) + + assert result == "2.3.4.5" + + # CASE 2: Test ipv6 + + vm_["protocol"] = "ipv6" + result = proxmox._find_agent_ip(vm_, ANY) + mock_query.assert_any_call( + "get", "nodes/myhost/qemu/{}/agent/network-get-interfaces".format(ANY) + ) + + assert result == "2001::1:2" + + +def test__authenticate_with_custom_port(): + """ + Test the use of a custom port for Proxmox connection + """ + get_cloud_config_mock = [ + "proxmox.connection.url", + "9999", + "fakeuser", + "secretpassword", + True, + ] + requests_post_mock = MagicMock() + with patch( + "salt.config.get_cloud_config_value", + autospec=True, + side_effect=get_cloud_config_mock, + ), patch("requests.post", requests_post_mock): + proxmox._authenticate() + requests_post_mock.assert_called_with( + "https://proxmox.connection.url:9999/api2/json/access/ticket", + verify=True, + data={"username": ("fakeuser",), "password": "secretpassword"}, + ) + + +def _test__import_api(response): + """ + Test _import_api recognition of varying Proxmox VE responses. + """ + requests_get_mock = MagicMock() + requests_get_mock.return_value.status_code = 200 + requests_get_mock.return_value.text = response + with patch("requests.get", requests_get_mock): + proxmox._import_api() + assert proxmox.api == [{"info": {}}] + return + + +def test__import_api_v6(): + """ + Test _import_api handling of a Proxmox VE 6 response. + """ + response = textwrap.dedent( + """\ + var pveapi = [ + { + "info" : { + } + } + ] + ; + """ + ) + _test__import_api(response) + + +def test__import_api_v7(): + """ + Test _import_api handling of a Proxmox VE 7 response. + """ + response = textwrap.dedent( + """\ + const apiSchema = [ + { + "info" : { + } + } + ] + ; + """ + ) + _test__import_api(response) + + +def test__authenticate_success(): + response = requests.Response() + response.status_code = 200 + response.reason = "OK" + response.raw = io.BytesIO( + b"""{"data":{"CSRFPreventionToken":"01234567:dG9rZW4=","ticket":"PVE:cloud@pve:01234567::dGlja2V0"}}""" + ) + with patch("requests.post", return_value=response): + proxmox._authenticate() + assert proxmox.csrf and proxmox.ticket + return + + +def test__authenticate_failure(): + """ + Confirm that authentication failure raises an exception. + """ + response = requests.Response() + response.status_code = 401 + response.reason = "authentication failure" + response.raw = io.BytesIO(b"""{"data":null}""") + with patch("requests.post", return_value=response): + pytest.raises(requests.exceptions.HTTPError, proxmox._authenticate) + return + + +def test_creation_failure_logging(caplog): + """ + Test detailed logging on HTTP errors during VM creation. + """ + vm_ = { + "profile": "my_proxmox", + "name": "vm4", + "technology": "lxc", + "host": "127.0.0.1", + "image": "local:some_image.tgz", + "onboot": True, + } + assert ( + config.is_profile_configured( + proxmox.__opts__, "my_proxmox:proxmox", "my_proxmox", vm_=vm_ + ) + is True + ) + + response = requests.Response() + response.status_code = 400 + response.reason = "Parameter verification failed." + response.raw = io.BytesIO( + b"""{"data":null,"errors":{"onboot":"type check ('boolean') failed - got 'True'"}}""" + ) + + def mock_query_response(conn_type, option, post_data=None): + if conn_type == "get" and option == "cluster/nextid": + return 104 + if conn_type == "post" and option == "nodes/127.0.0.1/lxc": + response.raise_for_status() + return response + return None + + with patch.object(proxmox, "query", side_effect=mock_query_response), patch.object( + proxmox, "_get_properties", return_value=set() + ): + assert proxmox.create(vm_) is False + + # Search for these messages in a multi-line log entry. + missing = { + "{} Client Error: {} for url:".format( + response.status_code, response.reason + ), + response.text, + } + for required in list(missing): + for record in caplog.records: + if required in record.message: + missing.remove(required) + break + if missing: + raise AssertionError( + "Did not find error messages: {}".format(sorted(list(missing))) + ) + return diff --git a/tests/pytests/unit/cloud/clouds/test_qingcloud.py b/tests/pytests/unit/cloud/clouds/test_qingcloud.py new file mode 100644 index 000000000000..8f281688ea2b --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/test_qingcloud.py @@ -0,0 +1,48 @@ +import pytest + +from salt.cloud.clouds import qingcloud +from tests.support.mock import MagicMock, patch + + +@pytest.fixture +def configure_loader_modules(): + return { + qingcloud: { + "__opts__": { + "providers": { + "qingcloud": { + "qingcloud": { + "access_key_id": "key_1234", + "secret_access_key": "1234", + "zone": "test_zone", + "key_filename": "/testfilename", + "driver": "qingcloud", + } + } + }, + "profiles": {"qingcloud": {}}, + }, + "__active_provider_name__": "qingcloud:qingcloud", + }, + } + + +def test_qingcloud_verify_ssl(): + """ + test qinglcoud when using verify_ssl + """ + patch_sig = patch("salt.cloud.clouds.qingcloud._compute_signature", MagicMock()) + + for verify in [True, False, None]: + mock_requests = MagicMock() + mock_requests.return_value.status_code = 200 + mock_requests.return_value.text = '{"ret_code": 0}' + patch_requests = patch("requests.get", mock_requests) + with patch.dict( + qingcloud.__opts__["providers"]["qingcloud"]["qingcloud"], + {"verify_ssl": verify}, + ): + with patch_sig, patch_requests: + ret = qingcloud.query() + assert ret["ret_code"] == 0 + assert mock_requests.call_args_list[0].kwargs["verify"] == verify diff --git a/tests/pytests/unit/cloud/clouds/test_saltify.py b/tests/pytests/unit/cloud/clouds/test_saltify.py new file mode 100644 index 000000000000..8dd0359185a1 --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/test_saltify.py @@ -0,0 +1,229 @@ +""" + :codeauthor: Alexander Schwartz +""" +import pytest + +import salt.client +from salt.cloud.clouds import saltify +from tests.support.mock import ANY, MagicMock, patch + + +@pytest.fixture +def configure_loader_modules(): + test_profiles = { + "testprofile1": NotImplemented, + "testprofile2": { # this profile is used in test_saltify_destroy() + "ssh_username": "fred", + "remove_config_on_destroy": False, # expected for test + "shutdown_on_destroy": True, # expected value for test + }, + "testprofile3": { # this profile is used in test_create_wake_on_lan() + "wake_on_lan_mac": "aa-bb-cc-dd-ee-ff", + "wol_sender_node": "friend1", + "wol_boot_wait": 0.01, # we want the wait to be very short + }, + } + + return { + saltify: { + "__active_provider_name__": "", + "__utils__": { + "cloud.bootstrap": MagicMock(), + "cloud.fire_event": MagicMock(), + }, + "__opts__": { + "providers": { + "sfy1": { + "saltify": {"driver": "saltify", "profiles": test_profiles} + }, + }, + "profiles": test_profiles, + "sock_dir": "/var/sockxxx", + "transport": "tcp", + }, + } + } + + +def test_create_no_deploy(): + """ + Test if deployment fails. This is the most basic test as saltify doesn't contain much logic + """ + with patch("salt.cloud.clouds.saltify._verify", MagicMock(return_value=True)): + vm = {"deploy": False, "driver": "saltify", "name": "dummy"} + assert saltify.create(vm) + + +def test_create_and_deploy(): + """ + Test if deployment can be done. + """ + mock_cmd = MagicMock(return_value=True) + with patch.dict( + "salt.cloud.clouds.saltify.__utils__", {"cloud.bootstrap": mock_cmd} + ): + vm_ = { + "deploy": True, + "driver": "saltify", + "name": "new2", + "profile": "testprofile2", + } + result = saltify.create(vm_) + mock_cmd.assert_called_once_with(vm_, ANY) + assert result + + +def test_create_no_ssh_host(): + """ + Test that ssh_host is set to the vm name if not defined + """ + mock_cmd = MagicMock(return_value=True) + with patch.dict( + "salt.cloud.clouds.saltify.__utils__", {"cloud.bootstrap": mock_cmd} + ): + vm_ = { + "deploy": True, + "driver": "saltify", + "name": "new2", + "profile": "testprofile2", + } + result = saltify.create(vm_) + mock_cmd.assert_called_once_with(vm_, ANY) + assert result + # Make sure that ssh_host was added to the vm. Note that this is + # done in two asserts so that the failure is more explicit about + # what is wrong. If ssh_host wasn't inserted in the vm_ dict, the + # failure would be a KeyError, which would be harder to + # troubleshoot. + assert "ssh_host" in vm_ + assert vm_["ssh_host"] == "new2" + + +def test_create_wake_on_lan(): + """ + Test if wake on lan works + """ + mock_sleep = MagicMock() + mock_cmd = MagicMock(return_value=True) + mm_cmd = MagicMock(return_value={"friend1": True}) + with salt.client.LocalClient() as lcl: + lcl.cmd = mm_cmd + with patch("time.sleep", mock_sleep): + with patch("salt.client.LocalClient", return_value=lcl): + with patch.dict( + "salt.cloud.clouds.saltify.__utils__", + {"cloud.bootstrap": mock_cmd}, + ): + vm_ = { + "deploy": True, + "driver": "saltify", + "name": "new1", + "profile": "testprofile3", + } + result = saltify.create(vm_) + mock_cmd.assert_called_once_with(vm_, ANY) + mm_cmd.assert_called_with( + "friend1", "network.wol", ["aa-bb-cc-dd-ee-ff"] + ) + # The test suite might call time.sleep, look for any call + # that has the expected wait time. + mock_sleep.assert_any_call(0.01) + assert result + + +def test_avail_locations(): + """ + Test the avail_locations will always return {} + """ + assert saltify.avail_locations() == {} + + +def test_avail_sizes(): + """ + Test the avail_sizes will always return {} + """ + assert saltify.avail_sizes() == {} + + +def test_avail_images(): + """ + Test the avail_images will return profiles + """ + testlist = list(saltify.__opts__["profiles"].keys()) + assert saltify.avail_images()["Profiles"].sort() == testlist.sort() + + +def test_list_nodes(): + """ + Test list_nodes will return required fields only + """ + testgrains = { + "nodeX1": { + "id": "nodeX1", + "ipv4": ["127.0.0.1", "192.1.2.22", "172.16.17.18"], + "ipv6": ["::1", "fdef:bad:add::f00", "3001:DB8::F00D"], + "salt-cloud": { + "driver": "saltify", + "provider": "saltyfy", + "profile": "testprofile2", + }, + "extra_stuff": "does not belong", + } + } + expected_result = { + "nodeX1": { + "id": "nodeX1", + "image": "testprofile2", + "private_ips": ["172.16.17.18", "fdef:bad:add::f00"], + "public_ips": ["192.1.2.22", "3001:DB8::F00D"], + "size": "", + "state": "running", + } + } + mm_cmd = MagicMock(return_value=testgrains) + with salt.client.LocalClient() as lcl: + lcl.cmd = mm_cmd + with patch("salt.client.LocalClient", return_value=lcl): + assert saltify.list_nodes() == expected_result + + +def test_saltify_reboot(): + mm_cmd = MagicMock(return_value=True) + with salt.client.LocalClient() as lcl: + lcl.cmd = mm_cmd + with patch("salt.client.LocalClient", return_value=lcl): + result = saltify.reboot("nodeS1", "action") + mm_cmd.assert_called_with("nodeS1", "system.reboot") + assert result + + +def test_saltify_destroy(): + # destroy calls local.cmd several times and expects + # different results, so we will provide a list of + # results. Each call will get the next value. + # NOTE: this assumes that the call order never changes, + # so to keep things simple, we will not use remove_config... + result_list = [ + { + "nodeS1": { # first call is grains.get + "driver": "saltify", + "provider": "saltify", + "profile": "testprofile2", + } + }, + # Note: + # testprofile2 has remove_config_on_destroy: False + # and shutdown_on_destroy: True + { + "nodeS1": ( # last call shuts down the minion + "a system.shutdown worked message" + ) + }, + ] + mm_cmd = MagicMock(side_effect=result_list) + with salt.client.LocalClient() as lcl: + lcl.cmd = mm_cmd + with patch("salt.client.LocalClient", return_value=lcl): + result = saltify.destroy("nodeS1", "action") + mm_cmd.assert_called_with("nodeS1", "system.shutdown") + assert result diff --git a/tests/pytests/unit/cloud/clouds/test_scaleway.py b/tests/pytests/unit/cloud/clouds/test_scaleway.py new file mode 100644 index 000000000000..273461291216 --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/test_scaleway.py @@ -0,0 +1,124 @@ +import copy + +import pytest + +import salt.utils.json +from salt.cloud.clouds import scaleway +from tests.support.mock import MagicMock, patch + + +class DummyRequest: + def __init__(self, status_code, **response): + self.status_code = status_code + self.response = response + + def __getitem__(self, item): + if item == "status": + return self.status_code + elif item in self.response: + return self.response[item] + raise KeyError(item) + + +@pytest.fixture +def configure_loader_modules(): + return { + scaleway: { + "__utils__": {}, + "__opts__": { + "providers": {"my_scaleway": {}}, + "profiles": {"my_scaleway": {}}, + }, + } + } + + +@pytest.fixture +def profile(): + return { + "profile": "my_scaleway", + "name": "foo", + "driver": "scaleway", + "token": "foobarbaz", + } + + +def test_query(profile): + """ + Confirm that using a different root affects the HTTP query made + """ + body = '{"result": "success"}' + server_id = "foo" + expected = salt.utils.json.loads(body) + http_query = MagicMock(return_value=DummyRequest(200, body=body)) + utils_dunder = {"http.query": http_query} + + with patch.dict(scaleway.__utils__, utils_dunder): + # Case 1: use default api_root + profile = copy.copy(profile) + with patch.object(scaleway, "get_configured_provider", lambda: profile): + result = scaleway.query(server_id=server_id) + assert result == expected, result + http_query.assert_called_once_with( + "https://cp-par1.scaleway.com/servers/foo/", + data="{}", + headers={ + "X-Auth-Token": "foobarbaz", + "User-Agent": "salt-cloud", + "Content-Type": "application/json", + }, + method="GET", + ) + + # Case 2: api_root overridden in profile + http_query.reset_mock() + profile = copy.copy(profile) + profile["api_root"] = "https://my.api.root" + with patch.object(scaleway, "get_configured_provider", lambda: profile): + result = scaleway.query(server_id=server_id) + assert result == expected, result + http_query.assert_called_once_with( + "https://my.api.root/servers/foo/", + data="{}", + headers={ + "X-Auth-Token": "foobarbaz", + "User-Agent": "salt-cloud", + "Content-Type": "application/json", + }, + method="GET", + ) + + # Case 3: use default alternative root + http_query.reset_mock() + profile = copy.copy(profile) + with patch.object(scaleway, "get_configured_provider", lambda: profile): + result = scaleway.query(server_id=server_id, root="alt_root") + assert result == expected, result + http_query.assert_called_once_with( + "https://api-marketplace.scaleway.com/servers/foo/", + data="{}", + headers={ + "X-Auth-Token": "foobarbaz", + "User-Agent": "salt-cloud", + "Content-Type": "application/json", + }, + method="GET", + ) + + # Case 4: use alternative root specified in profile + http_query.reset_mock() + profile = copy.copy(profile) + profile["alt_root"] = "https://my.alt.api.root" + with patch.object(scaleway, "get_configured_provider", lambda: profile): + result = scaleway.query(server_id=server_id, root="alt_root") + assert result == expected, result + http_query.assert_called_once_with( + "https://my.alt.api.root/servers/foo/", + data="{}", + headers={ + "X-Auth-Token": "foobarbaz", + "User-Agent": "salt-cloud", + "Content-Type": "application/json", + }, + method="GET", + ) diff --git a/tests/pytests/unit/cloud/clouds/test_vultrpy.py b/tests/pytests/unit/cloud/clouds/test_vultrpy.py new file mode 100644 index 000000000000..a388ba7f2a51 --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/test_vultrpy.py @@ -0,0 +1,203 @@ +import logging + +import pytest + +from salt.cloud.clouds import vultrpy as vultr +from tests.support.mock import MagicMock, patch + + +@pytest.fixture +def configure_loader_modules(): + return { + vultr: { + "__utils__": { + "cloud.fire_event": MagicMock(), + "cloud.filter_event": MagicMock(), + "cloud.wait_for_fun": MagicMock(), + "cloud.bootstrap": MagicMock(), + }, + "__opts__": { + "providers": { + "vultr01": { + "vultr": { + "api_key": "super_secret_key", + "driver": "vultr", + }, + }, + }, + "sock_dir": "/tmp/sock_dir", + "transport": "tcp", + }, + "__active_provider_name__": "my_vultr:vultr", + } + } + + +def test_show_keypair_no_keyname(caplog): + """ + test salt.cloud.clouds.vultr.show_keypair + when keyname is not in kwargs + """ + with caplog.at_level(logging.INFO): + assert not vultr.show_keypair({}) + assert "A keyname is required." in caplog.text + + +def test_show_keypair(): + """ + test salt.cloud.clouds.vultr.show_keypair + when keyname provided + """ + with patch( + "salt.cloud.clouds.vultrpy._query", return_value={"test": {"SSHKEYID": "keyID"}} + ): + kwargs = {"keyname": "test"} + assert vultr.show_keypair(kwargs) == {"SSHKEYID": "keyID"} + + +def test_create_firewall_ssh(): + """ + Test create when setting firewall_group_id and + ssh_key_names. + """ + kwargs = { + "provider": "vultr", + "enable_private_network": True, + "ssh_key_names": "key1,key2,key3", + "startup_script_id": "test_id", + "firewall_group_id": "f_id", + "image": 223, + "size": 13, + "location": 1, + "name": "test-vm", + } + patch_scripts = patch( + "salt.cloud.clouds.vultrpy.avail_scripts", + MagicMock(return_value=["test_id"]), + ) + + patch_firewall = patch( + "salt.cloud.clouds.vultrpy.avail_firewall_groups", + MagicMock(return_value=["f_id"]), + ) + + patch_keys = patch( + "salt.cloud.clouds.vultrpy.avail_keys", + MagicMock(return_value=["key3", "key2", "key1"]), + ) + + patch_vultrid = patch( + "salt.cloud.clouds.vultrpy._lookup_vultrid", + MagicMock(return_value="test_id"), + ) + + mock_query = MagicMock(return_value={"status": 200}) + patch_query = patch("salt.cloud.clouds.vultrpy._query", mock_query) + + patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) + + with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: + vultr.create(kwargs) + query_ret = mock_query.call_args.kwargs["data"] + assert "SSHKEYID=key1%2Ckey2%2Ckey3" in query_ret + assert "FIREWALLGROUPID=f_id" in query_ret + + +def test_create_firewall_doesnotexist(caplog): + """ + Test create when setting firewall_group_id to a firewall + that does not exist + """ + kwargs = { + "provider": "vultr", + "enable_private_network": True, + "startup_script_id": "test_id", + "firewall_group_id": "doesnotexist", + "image": 223, + "size": 13, + "location": 1, + "name": "test-vm", + } + patch_scripts = patch( + "salt.cloud.clouds.vultrpy.avail_scripts", + MagicMock(return_value=["test_id"]), + ) + + patch_firewall = patch( + "salt.cloud.clouds.vultrpy.avail_firewall_groups", + MagicMock(return_value=["f_id"]), + ) + + patch_keys = patch( + "salt.cloud.clouds.vultrpy.avail_keys", + MagicMock(return_value=["key3", "key2", "key1"]), + ) + + patch_vultrid = patch( + "salt.cloud.clouds.vultrpy._lookup_vultrid", + MagicMock(return_value="test_id"), + ) + + mock_query = MagicMock(return_value={"status": 200}) + patch_query = patch("salt.cloud.clouds.vultrpy._query", mock_query) + + patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) + + with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: + with caplog.at_level(logging.INFO): + ret = vultr.create(kwargs) + assert ( + "Your Vultr account does not have a firewall group with ID doesnotexist" + in caplog.text + ) + assert ret is False + + +def test_create_ssh_key_ids_doesnotexist(caplog): + """ + Test create when setting ssh_key_ids that do not + exist + """ + kwargs = { + "provider": "vultr", + "enable_private_network": True, + "startup_script_id": "test_id", + "ssh_key_names": "doesnotexist", + "image": 223, + "size": 13, + "location": 1, + "name": "test-vm", + } + patch_scripts = patch( + "salt.cloud.clouds.vultrpy.avail_scripts", + MagicMock(return_value=["test_id"]), + ) + + patch_firewall = patch( + "salt.cloud.clouds.vultrpy.avail_firewall_groups", + MagicMock(return_value=["f_id"]), + ) + + patch_keys = patch( + "salt.cloud.clouds.vultrpy.avail_keys", + MagicMock(return_value=["key3", "key2", "key1"]), + ) + + patch_vultrid = patch( + "salt.cloud.clouds.vultrpy._lookup_vultrid", + MagicMock(return_value="test_id"), + ) + + mock_query = MagicMock(return_value={"status": 200}) + patch_query = patch("salt.cloud.clouds.vultrpy._query", mock_query) + + patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) + + with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: + with caplog.at_level(logging.INFO): + ret = vultr.create(kwargs) + assert ( + "Your Vultr account does not have a key with ID doesnotexist" + in caplog.text + ) + assert ret is False diff --git a/tests/pytests/unit/cloud/clouds/vmware/__init__.py b/tests/pytests/unit/cloud/clouds/vmware/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/pytests/unit/cloud/clouds/vmware/test_clone_from_snapshot.py b/tests/pytests/unit/cloud/clouds/vmware/test_clone_from_snapshot.py new file mode 100644 index 000000000000..856d3fb2191f --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/vmware/test_clone_from_snapshot.py @@ -0,0 +1,109 @@ +""" + :codeauthor: `Nitin Madhok ` + + tests.unit.cloud.clouds.vmware_test + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" + +import pytest + +from salt.cloud.clouds import vmware +from salt.exceptions import SaltCloudSystemExit +from tests.support.mock import MagicMock + +# Attempt to import pyVim and pyVmomi libs +HAS_LIBS = True +# pylint: disable=import-error,no-name-in-module,unused-import +try: + from pyVim.connect import Disconnect, SmartConnect + from pyVmomi import vim, vmodl +except ImportError: + HAS_LIBS = False +# pylint: enable=import-error,no-name-in-module,unused-import + + +def _test_clone_type(clone_type): + """ + Assertions for checking that a certain clone type + works + """ + obj_ref = MagicMock() + obj_ref.snapshot = vim.vm.Snapshot(None, None) + obj_ref.snapshot.currentSnapshot = vim.vm.Snapshot(None, None) + clone_spec = vmware.handle_snapshot( + vim.vm.ConfigSpec(), + obj_ref, + vim.vm.RelocateSpec(), + False, + {"snapshot": {"disk_move_type": clone_type}}, + ) + assert clone_spec.location.diskMoveType == clone_type + + obj_ref2 = MagicMock() + obj_ref2.snapshot = vim.vm.Snapshot(None, None) + obj_ref2.snapshot.currentSnapshot = vim.vm.Snapshot(None, None) + + clone_spec2 = vmware.handle_snapshot( + vim.vm.ConfigSpec(), + obj_ref2, + vim.vm.RelocateSpec(), + True, + {"snapshot": {"disk_move_type": clone_type}}, + ) + + assert clone_spec2.location.diskMoveType == clone_type + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_quick_linked_clone(): + """ + Test that disk move type is + set to createNewChildDiskBacking + """ + _test_clone_type(vmware.QUICK_LINKED_CLONE) + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_current_state_linked_clone(): + """ + Test that disk move type is + set to moveChildMostDiskBacking + """ + _test_clone_type(vmware.CURRENT_STATE_LINKED_CLONE) + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_copy_all_disks_full_clone(): + """ + Test that disk move type is + set to moveAllDiskBackingsAndAllowSharing + """ + _test_clone_type(vmware.COPY_ALL_DISKS_FULL_CLONE) + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_flatten_all_all_disks_full_clone(): + """ + Test that disk move type is + set to moveAllDiskBackingsAndDisallowSharing + """ + _test_clone_type(vmware.FLATTEN_DISK_FULL_CLONE) + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_raises_error_for_invalid_disk_move_type(): + """ + Test that invalid disk move type + raises error + """ + pytest.raises(SaltCloudSystemExit, _test_clone_type, "foobar") diff --git a/tests/pytests/unit/cloud/clouds/vmware/test_vmware.py b/tests/pytests/unit/cloud/clouds/vmware/test_vmware.py new file mode 100644 index 000000000000..0912c28f0b22 --- /dev/null +++ b/tests/pytests/unit/cloud/clouds/vmware/test_vmware.py @@ -0,0 +1,1235 @@ +""" + :codeauthor: `Nitin Madhok ` + + tests.unit.cloud.clouds.vmware_test + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" + +import pytest + +from salt import config +from salt.cloud.clouds import vmware +from salt.exceptions import SaltCloudSystemExit +from tests.support.mock import MagicMock, Mock, patch + +# Attempt to import pyVim and pyVmomi libs +HAS_LIBS = True +# pylint: disable=import-error,no-name-in-module,unused-import +try: + from pyVim.connect import Disconnect, SmartConnect + from pyVmomi import vim, vmodl +except ImportError: + HAS_LIBS = False +# pylint: enable=import-error,no-name-in-module,unused-import + + +pytestmark = [ + pytest.mark.skipif( + not HAS_LIBS, reason="Install pyVmomi to be able to run this test." + ) +] + + +@pytest.fixture +def vm_name(): + return "test-vm" + + +@pytest.fixture +def profile(): + return { + "base-gold": { + "provider": "vcenter01:vmware", + "datastore": "Datastore1", + "resourcepool": "Resources", + "folder": "vm", + } + } + + +@pytest.fixture +def configure_loader_modules(profile): + return { + vmware: { + "__active_provider_name__": "", + "__opts__": { + "providers": { + "vcenter01": { + "vmware": { + "driver": "vmware", + "url": "vcenter01.domain.com", + "user": "DOMAIN\\user", + "password": "verybadpass", + "profiles": profile, + } + } + } + }, + } + } + + +def test_test_vcenter_connection_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call test_vcenter_connection + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.test_vcenter_connection, call="action") + + +def test_get_vcenter_version_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call get_vcenter_version + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.get_vcenter_version, call="action") + + +def test_avail_images_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call avail_images + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.avail_images, call="action") + + +def test_avail_locations_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call avail_locations + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.avail_locations, call="action") + + +def test_avail_sizes_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call avail_sizes + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.avail_sizes, call="action") + + +def test_list_datacenters_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_datacenters + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_datacenters, call="action") + + +def test_list_clusters_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_clusters + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_clusters, call="action") + + +def test_list_datastore_clusters_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_datastore_clusters + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_datastore_clusters, call="action") + + +def test_list_datastores_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_datastores + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_datastores, call="action") + + +def test_list_hosts_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_hosts + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_hosts, call="action") + + +def test_list_resourcepools_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_resourcepools + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_resourcepools, call="action") + + +def test_list_networks_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_networks + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_networks, call="action") + + +def test_list_nodes_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_nodes, call="action") + + +def test_list_nodes_min_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_min + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_nodes_min, call="action") + + +def test_list_nodes_full_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_full + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_nodes_full, call="action") + + +def test_list_nodes_select_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_full + with --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_nodes_select, call="action") + + +def test_list_folders_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_folders + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_folders, call="action") + + +def test_list_snapshots_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_snapshots + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_snapshots, call="action") + + +def test_list_hosts_by_cluster_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_hosts_by_cluster + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_hosts_by_cluster, call="action") + + +def test_list_clusters_by_datacenter_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_clusters_by_datacenter + with anything other than --function or -f. + """ + pytest.raises( + SaltCloudSystemExit, vmware.list_clusters_by_datacenter, call="action" + ) + + +def test_list_hosts_by_datacenter_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_hosts_by_datacenter + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_hosts_by_datacenter, call="action") + + +def test_list_hbas_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_hbas + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_hbas, call="action") + + +def test_list_dvs_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_dvs + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_dvs, call="action") + + +def test_list_vapps_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_vapps + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_vapps, call="action") + + +def test_list_templates_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call list_templates + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.list_templates, call="action") + + +def test_create_datacenter_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call create_datacenter + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.create_datacenter, call="action") + + +def test_create_cluster_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call create_cluster + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.create_cluster, call="action") + + +def test_rescan_hba_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call rescan_hba + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.rescan_hba, call="action") + + +def test_upgrade_tools_all_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call upgrade_tools_all + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.upgrade_tools_all, call="action") + + +def test_enter_maintenance_mode_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call enter_maintenance_mode + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.enter_maintenance_mode, call="action") + + +def test_exit_maintenance_mode_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call exit_maintenance_mode + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.exit_maintenance_mode, call="action") + + +def test_create_folder_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call create_folder + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.create_folder, call="action") + + +def test_add_host_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call add_host + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.add_host, call="action") + + +def test_remove_host_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call remove_host + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.remove_host, call="action") + + +def test_connect_host_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call connect_host + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.connect_host, call="action") + + +def test_disconnect_host_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call disconnect_host + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.disconnect_host, call="action") + + +def test_reboot_host_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call reboot_host + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.reboot_host, call="action") + + +def test_create_datastore_cluster_call(): + """ + Tests that a SaltCloudSystemExit is raised when trying to call create_datastore_cluster + with anything other than --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.create_datastore_cluster, call="action") + + +def test_show_instance_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call show_instance + with anything other than --action or -a. + """ + pytest.raises( + SaltCloudSystemExit, vmware.show_instance, name=vm_name, call="function" + ) + + +def test_start_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call start + with anything other than --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.start, name=vm_name, call="function") + + +def test_stop_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call stop + with anything other than --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.stop, name=vm_name, call="function") + + +def test_suspend_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call suspend + with anything other than --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.suspend, name=vm_name, call="function") + + +def test_reset_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call reset + with anything other than --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.reset, name=vm_name, call="function") + + +def test_terminate_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call terminate + with anything other than --action or -a. + """ + pytest.raises(SaltCloudSystemExit, vmware.terminate, name=vm_name, call="function") + + +def test_destroy_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call destroy + with --function or -f. + """ + pytest.raises(SaltCloudSystemExit, vmware.destroy, name=vm_name, call="function") + + +def test_shutdown_host_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call convert_to_template + with anything other than --action or -a. + """ + with patch.object(vmware, "_get_si", Mock()), patch( + "salt.utils.vmware.get_mor_by_property", Mock() + ): + pytest.raises( + SaltCloudSystemExit, + vmware.shutdown_host, + kwargs={"host": vm_name}, + call="action", + ) + + +def test_upgrade_tools_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call upgrade_tools + with anything other than --action or -a. + """ + pytest.raises( + SaltCloudSystemExit, vmware.upgrade_tools, name=vm_name, call="function" + ) + + +def test_create_snapshot_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call create_snapshot + with anything other than --action or -a. + """ + pytest.raises( + SaltCloudSystemExit, vmware.create_snapshot, name=vm_name, call="function" + ) + + +def test_revert_to_snapshot_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call revert_to_snapshot + with anything other than --action or -a. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.revert_to_snapshot, + name=vm_name, + call="function", + ) + + +def test_remove_snapshot_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call remove_snapshot + with anything other than --action or -a. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.remove_snapshot, + name=vm_name, + kwargs={"snapshot_name": "mySnapshot"}, + call="function", + ) + + +def test_remove_snapshot_call_no_snapshot_name_in_kwargs(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when name is not present in kwargs. + """ + pytest.raises( + SaltCloudSystemExit, vmware.remove_snapshot, name=vm_name, call="action" + ) + + +def test_remove_all_snapshots_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call remove_all_snapshots + with anything other than --action or -a. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.remove_all_snapshots, + name=vm_name, + call="function", + ) + + +def test_convert_to_template_call(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when trying to call convert_to_template + with anything other than --action or -a. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.convert_to_template, + name=vm_name, + call="function", + ) + + +def test_avail_sizes(): + """ + Tests that avail_sizes returns an empty dictionary. + """ + assert vmware.avail_sizes(call="foo") == {} + + +def test_create_datacenter_no_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when no kwargs are provided to + create_datacenter. + """ + pytest.raises( + SaltCloudSystemExit, vmware.create_datacenter, kwargs=None, call="function" + ) + + +def test_create_datacenter_no_name_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when name is not present in + kwargs that are provided to create_datacenter. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_datacenter, + kwargs={"foo": "bar"}, + call="function", + ) + + +def test_create_datacenter_name_too_short(): + """ + Tests that a SaltCloudSystemExit is raised when name is present in kwargs + that are provided to create_datacenter but is an empty string. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_datacenter, + kwargs={"name": ""}, + call="function", + ) + + +def test_create_datacenter_name_too_long(): + """ + Tests that a SaltCloudSystemExit is raised when name is present in kwargs + that are provided to create_datacenter but is a string with length <= 80. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_datacenter, + kwargs={ + "name": "cCD2GgJGPG1DUnPeFBoPeqtdmUxIWxDoVFbA14vIG0BPoUECkgbRMnnY6gaUPBvIDCcsZ5HU48ubgQu5c" + }, + call="function", + ) + + +def test_create_cluster_no_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when no kwargs are provided to + create_cluster. + """ + pytest.raises( + SaltCloudSystemExit, vmware.create_cluster, kwargs=None, call="function" + ) + + +def test_create_cluster_no_name_no_datacenter_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when neither the name nor the + datacenter is present in kwargs that are provided to create_cluster. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_cluster, + kwargs={"foo": "bar"}, + call="function", + ) + + +def test_create_cluster_no_datacenter_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when the name is present but the + datacenter is not present in kwargs that are provided to create_cluster. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_cluster, + kwargs={"name": "my-cluster"}, + call="function", + ) + + +def test_create_cluster_no_name_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when the datacenter is present + but the name is not present in kwargs that are provided to create_cluster. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_cluster, + kwargs={"datacenter": "my-datacenter"}, + call="function", + ) + + +def test_rescan_hba_no_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when no kwargs are provided to + rescan_hba. + """ + pytest.raises(SaltCloudSystemExit, vmware.rescan_hba, kwargs=None, call="function") + + +def test_rescan_hba_no_host_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when host is not present in + kwargs that are provided to rescan_hba. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.rescan_hba, + kwargs={"foo": "bar"}, + call="function", + ) + + +def test_create_snapshot_no_kwargs(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when no kwargs are provided to + create_snapshot. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_snapshot, + name=vm_name, + kwargs=None, + call="action", + ) + + +def test_create_snapshot_no_snapshot_name_in_kwargs(vm_name): + """ + Tests that a SaltCloudSystemExit is raised when snapshot_name is not present + in kwargs that are provided to create_snapshot. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_snapshot, + name=vm_name, + kwargs={"foo": "bar"}, + call="action", + ) + + +def test_add_host_no_esxi_host_user_in_config(): + """ + Tests that a SaltCloudSystemExit is raised when esxi_host_user is not + specified in the cloud provider configuration when calling add_host. + """ + with pytest.raises( + SaltCloudSystemExit, + match="You must specify the ESXi host username in your providers config.", + ): + vmware.add_host(kwargs=None, call="function") + + +def test_add_host_no_esxi_host_password_in_config(): + """ + Tests that a SaltCloudSystemExit is raised when esxi_host_password is not + specified in the cloud provider configuration when calling add_host. + """ + with patch.dict( + vmware.__opts__["providers"]["vcenter01"]["vmware"], + {"esxi_host_user": "root"}, + clean=True, + ): + with pytest.raises( + SaltCloudSystemExit, + match="You must specify the ESXi host password in your providers config.", + ): + vmware.add_host(kwargs=None, call="function") + + +def test_no_clonefrom_just_image(profile): + """ + Tests that the profile is configured correctly when deploying using an image + """ + + profile_additions = {"image": "some-image.iso"} + vm_ = {"profile": profile} + with patch.dict( + vmware.__opts__["providers"]["vcenter01"]["vmware"]["profiles"]["base-gold"], + profile_additions, + clean=True, + ): + assert ( + config.is_profile_configured( + vmware.__opts__, "vcenter01:vmware", "base-gold", vm_=vm_ + ) + is True + ) + + +def test_just_clonefrom(profile): + """ + Tests that the profile is configured correctly when deploying by cloning from a template + """ + + profile_additions = { + "clonefrom": "test-template", + "image": "should ignore image", + } + vm_ = {"profile": profile} + with patch.dict( + vmware.__opts__["providers"]["vcenter01"]["vmware"]["profiles"]["base-gold"], + profile_additions, + clean=True, + ): + assert ( + config.is_profile_configured( + vmware.__opts__, "vcenter01:vmware", "base-gold", vm_=vm_ + ) + is True + ) + + +def test_just_Instantclonefrom(vm_name): + """ + Tests that the profile is configured correctly when deploying by instant cloning from a running VM + """ + + profile_additions = { + "clonefrom": vm_name, + "instant_clone": True, + } + vm_ = {"profile": profile} + with patch.dict( + vmware.__opts__["providers"]["vcenter01"]["vmware"]["profiles"]["base-gold"], + profile_additions, + clean=True, + ): + assert ( + config.is_profile_configured( + vmware.__opts__, "vcenter01:vmware", "base-gold", vm_=vm_ + ) + is True + ) + + +def test_add_new_ide_controller_helper(): + """ + Tests that creating a new controller, ensuring that it will generate a controller key + if one is not provided + """ + with patch("salt.cloud.clouds.vmware.randint", return_value=101) as randint_mock: + controller_label = "Some label" + bus_number = 1 + spec = vmware._add_new_ide_controller_helper(controller_label, None, bus_number) + assert spec.device.key == randint_mock.return_value + + spec = vmware._add_new_ide_controller_helper(controller_label, 200, bus_number) + assert spec.device.key == 200 + + assert spec.device.busNumber == bus_number + assert spec.device.deviceInfo.label == controller_label + assert spec.device.deviceInfo.summary == controller_label + + +def test_manage_devices_just_cd(): + """ + Tests that when adding IDE/CD drives, controller keys will be in the apparent + safe-range on ESX 5.5 but randomly generated on other versions (i.e. 6) + """ + device_map = { + "ide": {"IDE 0": {}, "IDE 1": {}}, + "cd": {"CD/DVD Drive 1": {"controller": "IDE 0"}}, + } + with patch( + "salt.cloud.clouds.vmware.get_vcenter_version", + return_value="VMware ESXi 5.5.0", + ): + specs = vmware._manage_devices(device_map, vm=None)["device_specs"] + + assert specs[0].device.key == vmware.SAFE_ESX_5_5_CONTROLLER_KEY_INDEX + assert specs[1].device.key == vmware.SAFE_ESX_5_5_CONTROLLER_KEY_INDEX + 1 + assert specs[2].device.controllerKey == vmware.SAFE_ESX_5_5_CONTROLLER_KEY_INDEX + + with patch( + "salt.cloud.clouds.vmware.get_vcenter_version", return_value="VMware ESXi 6" + ): + with patch("salt.cloud.clouds.vmware.randint", return_value=100) as first_key: + specs = vmware._manage_devices(device_map, vm=None)["device_specs"] + + assert specs[0].device.key == first_key.return_value + assert specs[2].device.controllerKey == first_key.return_value + + +def test_add_host_no_host_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when host is not present in + kwargs that are provided to add_host. + """ + provider_config_additions = { + "esxi_host_user": "root", + "esxi_host_password": "myhostpassword", + } + with patch.dict( + vmware.__opts__["providers"]["vcenter01"]["vmware"], + provider_config_additions, + clean=True, + ): + with pytest.raises( + SaltCloudSystemExit, + match="You must specify either the IP or DNS name of the host system.", + ): + vmware.add_host(kwargs={"foo": "bar"}, call="function") + + +def test_add_host_both_cluster_and_datacenter_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when both cluster and datacenter + are present in kwargs that are provided to add_host. + """ + provider_config_additions = { + "esxi_host_user": "root", + "esxi_host_password": "myhostpassword", + } + with patch.dict( + vmware.__opts__["providers"]["vcenter01"]["vmware"], + provider_config_additions, + clean=True, + ): + with pytest.raises( + SaltCloudSystemExit, + match="You must specify either the cluster name or the datacenter name.", + ): + vmware.add_host( + kwargs={ + "host": "my-esxi-host", + "datacenter": "my-datacenter", + "cluster": "my-cluster", + }, + call="function", + ) + + +def test_add_host_neither_cluster_nor_datacenter_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when neither cluster nor + datacenter is present in kwargs that are provided to add_host. + """ + provider_config_additions = { + "esxi_host_user": "root", + "esxi_host_password": "myhostpassword", + } + with patch.dict( + vmware.__opts__["providers"]["vcenter01"]["vmware"], + provider_config_additions, + clean=True, + ): + with pytest.raises( + SaltCloudSystemExit, + match="You must specify either the cluster name or the datacenter name.", + ): + vmware.add_host(kwargs={"host": "my-esxi-host"}, call="function") + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_add_host_cluster_not_exists(): + """ + Tests that a SaltCloudSystemExit is raised when the specified cluster present + in kwargs that are provided to add_host does not exist in the VMware + environment. + """ + with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): + with patch( + "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) + ): + provider_config_additions = { + "esxi_host_user": "root", + "esxi_host_password": "myhostpassword", + } + + with patch.dict( + vmware.__opts__["providers"]["vcenter01"]["vmware"], + provider_config_additions, + clean=True, + ): + with pytest.raises( + SaltCloudSystemExit, match="Specified cluster does not exist." + ): + vmware.add_host( + kwargs={"host": "my-esxi-host", "cluster": "my-cluster"}, + call="function", + ) + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_add_host_datacenter_not_exists(): + """ + Tests that a SaltCloudSystemExit is raised when the specified datacenter + present in kwargs that are provided to add_host does not exist in the VMware + environment. + """ + with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): + with patch( + "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) + ): + provider_config_additions = { + "esxi_host_user": "root", + "esxi_host_password": "myhostpassword", + } + with patch.dict( + vmware.__opts__["providers"]["vcenter01"]["vmware"], + provider_config_additions, + clean=True, + ): + with pytest.raises( + SaltCloudSystemExit, match="Specified datacenter does not exist." + ): + vmware.add_host( + kwargs={"host": "my-esxi-host", "datacenter": "my-datacenter"}, + call="function", + ) + + +def test_remove_host_no_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when no kwargs are provided to + remove_host. + """ + pytest.raises(SaltCloudSystemExit, vmware.remove_host, kwargs=None, call="function") + + +def test_remove_host_no_host_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when host is not present in + kwargs that are provided to remove_host. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.remove_host, + kwargs={"foo": "bar"}, + call="function", + ) + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_remove_host_not_exists(): + """ + Tests that a SaltCloudSystemExit is raised when the specified host present + in kwargs that are provided to remove_host does not exist in the VMware + environment. + """ + with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): + with patch( + "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) + ): + pytest.raises( + SaltCloudSystemExit, + vmware.remove_host, + kwargs={"host": "my-host"}, + call="function", + ) + + +def test_connect_host_no_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when no kwargs are provided to + connect_host. + """ + pytest.raises( + SaltCloudSystemExit, vmware.connect_host, kwargs=None, call="function" + ) + + +def test_connect_host_no_host_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when host is not present in + kwargs that are provided to connect_host. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.connect_host, + kwargs={"foo": "bar"}, + call="function", + ) + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_connect_host_not_exists(): + """ + Tests that a SaltCloudSystemExit is raised when the specified host present + in kwargs that are provided to connect_host does not exist in the VMware + environment. + """ + with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): + with patch( + "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) + ): + pytest.raises( + SaltCloudSystemExit, + vmware.connect_host, + kwargs={"host": "my-host"}, + call="function", + ) + + +def test_disconnect_host_no_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when no kwargs are provided to + disconnect_host. + """ + pytest.raises( + SaltCloudSystemExit, vmware.disconnect_host, kwargs=None, call="function" + ) + + +def test_disconnect_host_no_host_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when host is not present in + kwargs that are provided to disconnect_host. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.disconnect_host, + kwargs={"foo": "bar"}, + call="function", + ) + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_disconnect_host_not_exists(): + """ + Tests that a SaltCloudSystemExit is raised when the specified host present + in kwargs that are provided to disconnect_host does not exist in the VMware + environment. + """ + with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): + with patch( + "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) + ): + pytest.raises( + SaltCloudSystemExit, + vmware.disconnect_host, + kwargs={"host": "my-host"}, + call="function", + ) + + +def test_reboot_host_no_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when no kwargs are provided to + reboot_host. + """ + pytest.raises(SaltCloudSystemExit, vmware.reboot_host, kwargs=None, call="function") + + +def test_reboot_host_no_host_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when host is not present in + kwargs that are provided to reboot_host. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.reboot_host, + kwargs={"foo": "bar"}, + call="function", + ) + + +@pytest.mark.skipif( + HAS_LIBS is False, reason="Install pyVmomi to be able to run this unit test." +) +def test_reboot_host_not_exists(): + """ + Tests that a SaltCloudSystemExit is raised when the specified host present + in kwargs that are provided to connect_host does not exist in the VMware + environment. + """ + with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): + with patch( + "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) + ): + pytest.raises( + SaltCloudSystemExit, + vmware.reboot_host, + kwargs={"host": "my-host"}, + call="function", + ) + + +def test_create_datastore_cluster_no_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when no kwargs are provided to + create_datastore_cluster. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_datastore_cluster, + kwargs=None, + call="function", + ) + + +def test_create_datastore_cluster_no_name_in_kwargs(): + """ + Tests that a SaltCloudSystemExit is raised when name is not present in + kwargs that are provided to create_datastore_cluster. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_datastore_cluster, + kwargs={"foo": "bar"}, + call="function", + ) + + +def test_create_datastore_cluster_name_too_short(): + """ + Tests that a SaltCloudSystemExit is raised when name is present in kwargs + that are provided to create_datastore_cluster but is an empty string. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_datastore_cluster, + kwargs={"name": ""}, + call="function", + ) + + +def test_create_datastore_cluster_name_too_long(): + """ + Tests that a SaltCloudSystemExit is raised when name is present in kwargs + that are provided to create_datastore_cluster but is a string with length <= 80. + """ + pytest.raises( + SaltCloudSystemExit, + vmware.create_datastore_cluster, + kwargs={ + "name": "cCD2GgJGPG1DUnPeFBoPeqtdmUxIWxDoVFbA14vIG0BPoUECkgbRMnnY6gaUPBvIDCcsZ5HU48ubgQu5c" + }, + call="function", + ) + + +def test__add_new_hard_disk_helper(): + with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): + with patch( + "salt.utils.vmware.get_mor_using_container_view", + side_effect=[None, None], + ): + pytest.raises( + SaltCloudSystemExit, + vmware._add_new_hard_disk_helper, + disk_label="test", + size_gb=100, + unit_number=0, + datastore="whatever", + ) + with patch( + "salt.utils.vmware.get_mor_using_container_view", + side_effect=["Datastore", None], + ): + pytest.raises( + AttributeError, + vmware._add_new_hard_disk_helper, + disk_label="test", + size_gb=100, + unit_number=0, + datastore="whatever", + ) + vmware.salt.utils.vmware.get_mor_using_container_view.assert_called_with( + None, vim.Datastore, "whatever" + ) + with patch( + "salt.utils.vmware.get_mor_using_container_view", + side_effect=[None, "Cluster"], + ): + pytest.raises( + AttributeError, + vmware._add_new_hard_disk_helper, + disk_label="test", + size_gb=100, + unit_number=0, + datastore="whatever", + ) + vmware.salt.utils.vmware.get_mor_using_container_view.assert_called_with( + None, vim.StoragePod, "whatever" + ) diff --git a/tests/pytests/unit/cloud/test_cloud.py b/tests/pytests/unit/cloud/test_cloud.py index 34300225c375..3e6f54f4dfbb 100644 --- a/tests/pytests/unit/cloud/test_cloud.py +++ b/tests/pytests/unit/cloud/test_cloud.py @@ -72,3 +72,58 @@ def test_cloud_create_attempt_sync_after_install( ret = cloud.create(vm_config, sync_sleep=0) assert ret fake_client.cmd.assert_called_with("test", expected_func, timeout=5) + + +@pytest.mark.slow_test +def test_vm_config_merger(): + """ + Validate the vm's config is generated correctly. + + https://github.com/saltstack/salt/issues/49226 + """ + main = { + "minion": {"master": "172.31.39.213"}, + "log_file": "var/log/salt/cloud.log", + "pool_size": 10, + } + provider = { + "private_key": "dwoz.pem", + "grains": {"foo1": "bar", "foo2": "bang"}, + "availability_zone": "us-west-2b", + "driver": "ec2", + "ssh_interface": "private_ips", + "ssh_username": "admin", + "location": "us-west-2", + } + profile = { + "profile": "default", + "grains": {"meh2": "bar", "meh1": "foo"}, + "provider": "ec2-default:ec2", + "ssh_username": "admin", + "image": "ami-0a1fbca0e5b419fd1", + "size": "t2.micro", + } + expected = { + "minion": {"master": "172.31.39.213"}, + "log_file": "var/log/salt/cloud.log", + "pool_size": 10, + "private_key": "dwoz.pem", + "grains": { + "foo1": "bar", + "foo2": "bang", + "meh2": "bar", + "meh1": "foo", + }, + "availability_zone": "us-west-2b", + "driver": "ec2", + "ssh_interface": "private_ips", + "ssh_username": "admin", + "location": "us-west-2", + "profile": "default", + "provider": "ec2-default:ec2", + "image": "ami-0a1fbca0e5b419fd1", + "size": "t2.micro", + "name": "test_vm", + } + vm = salt.cloud.Cloud.vm_config("test_vm", main, provider, profile, {}) + assert expected == vm diff --git a/tests/unit/cloud/__init__.py b/tests/unit/cloud/__init__.py deleted file mode 100644 index e96033e8910b..000000000000 --- a/tests/unit/cloud/__init__.py +++ /dev/null @@ -1,66 +0,0 @@ -""" - tests.unit.cloud - ~~~~~~~~~~~~~~~~ -""" -import pytest - -import salt.cloud -from tests.support.unit import TestCase - - -class CloudTest(TestCase): - @pytest.mark.slow_test - def test_vm_config_merger(self): - """ - Validate the vm's config is generated correctly. - - https://github.com/saltstack/salt/issues/49226 - """ - main = { - "minion": {"master": "172.31.39.213"}, - "log_file": "var/log/salt/cloud.log", - "pool_size": 10, - } - provider = { - "private_key": "dwoz.pem", - "grains": {"foo1": "bar", "foo2": "bang"}, - "availability_zone": "us-west-2b", - "driver": "ec2", - "ssh_interface": "private_ips", - "ssh_username": "admin", - "location": "us-west-2", - } - profile = { - "profile": "default", - "grains": {"meh2": "bar", "meh1": "foo"}, - "provider": "ec2-default:ec2", - "ssh_username": "admin", - "image": "ami-0a1fbca0e5b419fd1", - "size": "t2.micro", - } - vm = salt.cloud.Cloud.vm_config("test_vm", main, provider, profile, {}) - self.assertEqual( - { - "minion": {"master": "172.31.39.213"}, - "log_file": "var/log/salt/cloud.log", - "pool_size": 10, - "private_key": "dwoz.pem", - "grains": { - "foo1": "bar", - "foo2": "bang", - "meh2": "bar", - "meh1": "foo", - }, - "availability_zone": "us-west-2b", - "driver": "ec2", - "ssh_interface": "private_ips", - "ssh_username": "admin", - "location": "us-west-2", - "profile": "default", - "provider": "ec2-default:ec2", - "image": "ami-0a1fbca0e5b419fd1", - "size": "t2.micro", - "name": "test_vm", - }, - vm, - ) diff --git a/tests/unit/cloud/clouds/__init__.py b/tests/unit/cloud/clouds/__init__.py deleted file mode 100644 index 61d77b2cb973..000000000000 --- a/tests/unit/cloud/clouds/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -def _preferred_ip(ip_set, preferred=None): - """ - Returns a function that reacts which ip is preferred - :param ip_set: - :param private: - :return: - """ - - def _ip_decider(vm, ips): - for ip in ips: - if ip in preferred: - return ip - return False - - return _ip_decider diff --git a/tests/unit/cloud/clouds/test_digitalocean.py b/tests/unit/cloud/clouds/test_digitalocean.py deleted file mode 100644 index 5ebcc4931012..000000000000 --- a/tests/unit/cloud/clouds/test_digitalocean.py +++ /dev/null @@ -1,39 +0,0 @@ -""" - :codeauthor: `Gareth J. Greenaway ` - - tests.unit.cloud.clouds.digitalocean_test - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -""" - - -import logging - -from salt.cloud.clouds import digitalocean -from salt.exceptions import SaltCloudSystemExit -from tests.support.unit import TestCase - -log = logging.getLogger(__name__) - - -class DigitalOceanTestCase(TestCase): - """ - Unit TestCase for salt.cloud.clouds.digitalocean module. - """ - - def test_reboot_no_call(self): - """ - Tests that a SaltCloudSystemExit is raised when - kwargs that are provided do not include an action. - """ - self.assertRaises( - SaltCloudSystemExit, - digitalocean.reboot, - name="fake_name", - ) - - with self.assertRaises(SaltCloudSystemExit) as excinfo: - ret = digitalocean.reboot(name="fake_name") - self.assertEqual( - "The reboot action must be called with -a or --action.", - excinfo.exception.strerror, - ) diff --git a/tests/unit/cloud/clouds/test_dimensiondata.py b/tests/unit/cloud/clouds/test_dimensiondata.py deleted file mode 100644 index 10310b9d9a63..000000000000 --- a/tests/unit/cloud/clouds/test_dimensiondata.py +++ /dev/null @@ -1,186 +0,0 @@ -""" - :codeauthor: `Anthony Shaw ` - - tests.unit.cloud.clouds.dimensiondata_test - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -""" - -from salt.cloud.clouds import dimensiondata -from salt.exceptions import SaltCloudSystemExit -from salt.utils.versions import LooseVersion -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock -from tests.support.mock import __version__ as mock_version -from tests.support.mock import patch -from tests.support.unit import TestCase, skipIf -from tests.unit.cloud.clouds import _preferred_ip - -try: - import libcloud.security - - HAS_LIBCLOUD = True -except ImportError: - HAS_LIBCLOUD = False - - -VM_NAME = "winterfell" - -# Use certifi if installed -try: - if HAS_LIBCLOUD: - # This work-around for Issue #32743 is no longer needed for libcloud >= - # 1.4.0. However, older versions of libcloud must still be supported - # with this work-around. This work-around can be removed when the - # required minimum version of libcloud is 2.0.0 (See PR #40837 - which - # is implemented in Salt 2018.3.0). - if LooseVersion(libcloud.__version__) < LooseVersion("1.4.0"): - import certifi - - libcloud.security.CA_CERTS_PATH.append(certifi.where()) -except (ImportError, NameError): - pass - - -class ExtendedTestCase(TestCase): - """ - Extended TestCase class containing additional helper methods. - """ - - def assertRaisesWithMessage(self, exc_type, exc_msg, func, *args, **kwargs): - try: - func(*args, **kwargs) - self.assertFail() - except Exception as exc: # pylint: disable=broad-except - self.assertEqual(type(exc), exc_type) - self.assertEqual(exc.message, exc_msg) - - -class DimensionDataTestCase(ExtendedTestCase, LoaderModuleMockMixin): - """ - Unit TestCase for salt.cloud.clouds.dimensiondata module. - """ - - def setup_loader_modules(self): - return { - dimensiondata: { - "__active_provider_name__": "", - "__opts__": { - "providers": { - "my-dimensiondata-cloud": { - "dimensiondata": { - "driver": "dimensiondata", - "region": "dd-au", - "user_id": "jon_snow", - "key": "IKnowNothing", - } - } - } - }, - } - } - - def test_avail_images_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call avail_images - with --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, dimensiondata.avail_images, call="action" - ) - - def test_avail_locations_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call avail_locations - with --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, dimensiondata.avail_locations, call="action" - ) - - def test_avail_sizes_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call avail_sizes - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, dimensiondata.avail_sizes, call="action") - - def test_list_nodes_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_nodes - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, dimensiondata.list_nodes, call="action") - - def test_destroy_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call destroy - with --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, dimensiondata.destroy, name=VM_NAME, call="function" - ) - - @skipIf( - HAS_LIBCLOUD is False, "Install 'libcloud' to be able to run this unit test." - ) - def test_avail_sizes(self): - """ - Tests that avail_sizes returns an empty dictionary. - """ - sizes = dimensiondata.avail_sizes(call="foo") - self.assertEqual(len(sizes), 1) - self.assertEqual(sizes["default"]["name"], "default") - - def test_import(self): - """ - Test that the module picks up installed deps - """ - with patch("salt.config.check_driver_dependencies", return_value=True) as p: - get_deps = dimensiondata.get_dependencies() - self.assertEqual(get_deps, True) - if LooseVersion(mock_version) >= LooseVersion("2.0.0"): - self.assertTrue(p.call_count >= 1) - - def test_provider_matches(self): - """ - Test that the first configured instance of a dimensiondata driver is matched - """ - p = dimensiondata.get_configured_provider() - self.assertNotEqual(p, None) - - def test_query_node_data_filter_preferred_ip_addresses(self): - """ - Test if query node data is filtering out unpreferred IP addresses. - """ - zero_ip = "0.0.0.0" - private_ips = [zero_ip, "1.1.1.1", "2.2.2.2"] - vm = {"name": None} - data = MagicMock() - data.public_ips = [] - # pylint: disable=blacklisted-unmocked-patching - dimensiondata.NodeState = MagicMock() - # pylint: enable=blacklisted-unmocked-patching - dimensiondata.NodeState.RUNNING = True - - with patch( - "salt.cloud.clouds.dimensiondata.show_instance", - MagicMock( - return_value={ - "state": True, - "name": "foo", - "public_ips": [], - "private_ips": private_ips, - } - ), - ): - with patch( - "salt.cloud.clouds.dimensiondata.preferred_ip", - _preferred_ip(private_ips, [zero_ip]), - ): - with patch( - "salt.cloud.clouds.dimensiondata.ssh_interface", - MagicMock(return_value="private_ips"), - ): - self.assertEqual( - dimensiondata._query_node_data(vm, data).public_ips, [zero_ip] - ) diff --git a/tests/unit/cloud/clouds/test_ec2.py b/tests/unit/cloud/clouds/test_ec2.py deleted file mode 100644 index a2d5e0410dad..000000000000 --- a/tests/unit/cloud/clouds/test_ec2.py +++ /dev/null @@ -1,211 +0,0 @@ -import os -import tempfile - -import salt.crypt -import salt.utils.files -from salt.cloud.clouds import ec2 -from salt.exceptions import SaltCloudSystemExit -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import PropertyMock, patch -from tests.support.runtests import RUNTIME_VARS -from tests.support.unit import TestCase, skipIf -from tests.unit.test_crypt import PRIVKEY_DATA - -PASS_DATA = ( - b"qOjCKDlBdcNEbJ/J8eRl7sH+bYIIm4cvHHY86gh2NEUnufFlFo0gGVTZR05Fj0cw3n/w7gR" - b"urNXz5JoeSIHVuNI3YTwzL9yEAaC0kuy8EbOlO2yx8yPGdfml9BRwOV7A6b8UFo9co4H7fz" - b"DdScMKU2yzvRYvp6N6Q2cJGBmPsemnXWWusb+1vZVWxcRAQmG3ogF6Z5rZSYAYH0N4rqJgH" - b"mQfzuyb+jrBvV/IOoV1EdO9jGSH9338aS47NjrmNEN/SpnS6eCWZUwwyHbPASuOvWiY4QH/" - b"0YZC6EGccwiUmt0ZOxIynk+tEyVPTkiS0V8RcZK6YKqMWHpKmPtLBzfuoA==" -) - - -class EC2TestCase(TestCase, LoaderModuleMockMixin): - """ - Unit TestCase for salt.cloud.clouds.ec2 module. - """ - - def setUp(self): - super().setUp() - with tempfile.NamedTemporaryFile( - dir=RUNTIME_VARS.TMP, suffix=".pem", delete=True - ) as fp: - self.key_file = fp.name - - def tearDown(self): - super().tearDown() - if os.path.exists(self.key_file): - os.remove(self.key_file) - - def setup_loader_modules(self): - return {ec2: {"__opts__": {}}} - - def test__validate_key_path_and_mode(self): - # Key file exists - with patch("os.path.exists", return_value=True): - with patch("os.stat") as patched_stat: - type(patched_stat.return_value).st_mode = PropertyMock( - return_value=0o644 - ) - self.assertRaises( - SaltCloudSystemExit, ec2._validate_key_path_and_mode, "key_file" - ) - - type(patched_stat.return_value).st_mode = PropertyMock( - return_value=0o600 - ) - self.assertTrue(ec2._validate_key_path_and_mode("key_file")) - - type(patched_stat.return_value).st_mode = PropertyMock( - return_value=0o400 - ) - self.assertTrue(ec2._validate_key_path_and_mode("key_file")) - - # Key file does not exist - with patch("os.path.exists", return_value=False): - self.assertRaises( - SaltCloudSystemExit, ec2._validate_key_path_and_mode, "key_file" - ) - - @skipIf(not salt.crypt.HAS_M2 and not salt.crypt.HAS_CRYPTO, "Needs crypto library") - @patch("salt.cloud.clouds.ec2._get_node") - @patch("salt.cloud.clouds.ec2.get_location") - @patch("salt.cloud.clouds.ec2.get_provider") - @patch("salt.utils.aws.query") - def test_get_password_data(self, query, get_provider, get_location, _get_node): - query.return_value = [{"passwordData": PASS_DATA}] - _get_node.return_value = {"instanceId": "i-abcdef"} - get_location.return_value = "us-west2" - get_provider.return_value = "ec2" - with salt.utils.files.fopen(self.key_file, "w") as fp: - fp.write(PRIVKEY_DATA) - ret = ec2.get_password_data( - name="i-abcddef", kwargs={"key_file": self.key_file}, call="action" - ) - assert ret["passwordData"] == PASS_DATA - assert ret["password"] == "testp4ss!" - - @patch("salt.cloud.clouds.ec2.config.get_cloud_config_value") - @patch("salt.cloud.clouds.ec2.get_location") - @patch("salt.cloud.clouds.ec2.get_provider") - @patch("salt.cloud.clouds.ec2.aws.query") - def test_get_imageid(self, aws_query, get_provider, get_location, config): - """ - test querying imageid function - """ - vm = {} - ami = "ami-1234" - config.return_value = "test/*" - get_location.return_value = "us-west2" - get_provider.return_value = "ec2" - aws_query.return_value = [{"imageId": ami}] - - # test image filter - self.assertEqual(ec2.get_imageid(vm), ami) - - # test ami-image - config.return_value = ami - self.assertEqual(ec2.get_imageid(vm), ami) - - # we should have only ran aws.query once when testing the aws filter - aws_query.assert_called_once() - - @patch("salt.cloud.clouds.ec2.config.get_cloud_config_value") - @patch("salt.cloud.clouds.ec2.get_location") - @patch("salt.cloud.clouds.ec2.get_availability_zone") - @patch("salt.cloud.clouds.ec2.get_provider") - @patch("salt.cloud.clouds.ec2.get_spot_config") - @patch("salt.cloud.clouds.ec2._param_from_config") - @patch("salt.cloud.clouds.ec2.securitygroupid") - def test_termination_protection( - self, - securitygroupid, - _param_from_config, - get_spot_config, - get_provider, - get_availability_zone, - get_location, - config, - ): - """ - Verify that `set_termination_protection` updates the right parameters - """ - vm = {"name": "taco"} - set_del_root_vol_on_destroy = "yes" - termination_protection = True - config.side_effect = ( - [None] * 2 - + ["test/*"] - + [None] * 13 - + [set_del_root_vol_on_destroy, termination_protection] - ) - get_location.return_value = "us-west2" - get_availability_zone.return_value = None - get_provider.return_value = "ec2" - get_spot_config.return_value = None - securitygroupid.return_value = None - - self.assertRaises( - salt.exceptions.SaltCloudConfigError, ec2.request_instance, vm - ) - _param_from_config.assert_called_once_with("DisableApiTermination", True) - - @patch("salt.cloud.clouds.ec2.config.get_cloud_config_value") - @patch("salt.cloud.clouds.ec2.get_location") - @patch("salt.cloud.clouds.ec2.get_availability_zone") - @patch("salt.cloud.clouds.ec2.get_provider") - @patch("salt.cloud.clouds.ec2.get_spot_config") - @patch("salt.cloud.clouds.ec2.securitygroupid") - def test_termination_protection_exception( - self, - securitygroupid, - get_spot_config, - get_provider, - get_availability_zone, - get_location, - config, - ): - """ - Verify improper `set_termination_protection` parameters raises an exception - """ - vm = {"name": "taco"} - termination_protection = "not a bool" - config.side_effect = ( - [None] * 2 + ["test/*"] + [None] * 14 + [termination_protection] - ) - get_location.return_value = "us-west2" - get_availability_zone.return_value = None - get_provider.return_value = "ec2" - get_spot_config.return_value = None - securitygroupid.return_value = None - - self.assertRaises( - salt.exceptions.SaltCloudConfigError, ec2.request_instance, vm - ) - - @patch("salt.cloud.clouds.ec2.config.get_cloud_config_value") - @patch("salt.cloud.clouds.ec2.get_location") - @patch("salt.cloud.clouds.ec2.get_provider") - @patch("salt.cloud.clouds.ec2.aws.query") - def test_get_subnetname_id(self, aws_query, get_provider, get_location, config): - """ - test querying subnetid function - """ - vm = {} - subnetid = "subnet-5678" - subnetname = "valid-subnet-with-name" - config.return_value = subnetname - get_location.return_value = "us-west-2" - get_provider.return_value = "ec2" - - # test for returns that include subnets with missing Name tags, see Issue 44330 - aws_query.return_value = [ - {"subnetId": "subnet-1234"}, - { - "subnetId": subnetid, - "tagSet": {"item": {"key": "Name", "value": subnetname}}, - }, - ] - - # test subnetname lookup - self.assertEqual(ec2._get_subnetname_id(subnetname), subnetid) diff --git a/tests/unit/cloud/clouds/test_joyent.py b/tests/unit/cloud/clouds/test_joyent.py deleted file mode 100644 index 3b826576ce00..000000000000 --- a/tests/unit/cloud/clouds/test_joyent.py +++ /dev/null @@ -1,95 +0,0 @@ -""" - :codeauthor: Eric Radman -""" - - -from salt.cloud.clouds import joyent -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock, patch -from tests.support.unit import TestCase, skipIf - - -# Stubs -def fake_wait_for_ip( - check_for_ip_fn, interval=None, timeout=None, interval_multiplier=None -): - """ - Callback that returns immediately instead of waiting - """ - assert isinstance(interval, int) - assert isinstance(timeout, int) - assert isinstance(interval_multiplier, int) - return check_for_ip_fn() - - -@skipIf( - joyent.HAS_REQUIRED_CRYPTO is False, reason="PyCrypto or Cryptodome not installed" -) -class JoyentTestCase(TestCase, LoaderModuleMockMixin): - """ - Unit TestCase for the salt.cloud.clouds.joyent module - """ - - def setup_loader_modules(self): - patcher = patch("salt.utils.cloud.wait_for_ip", fake_wait_for_ip) - patcher.start() - self.addCleanup(patcher.stop) - return { - joyent: { - "__utils__": { - "cloud.fire_event": MagicMock(), - "cloud.bootstrap": MagicMock(), - }, - "__opts__": { - "sock_dir": True, - "transport": True, - "providers": {"my_joyent": {}}, - "profiles": {"my_joyent": {}}, - }, - "__active_provider_name__": "my_joyent:joyent", - } - } - - def setUp(self): - self.vm_ = { - "profile": "my_joyent", - "name": "vm3", - "driver": "joyent", - "size": "k4-highcpu-kvm-750M", - "image": "freebsd10", - "location": "us-east-1", - } - - def tearDown(self): - del self.vm_ - - def test_query_instance_init(self): - """ - Initial provisioning, no IP assigned - """ - # Not yet reachable - reply = (200, {"state": "provisioning"}) - with patch.object(joyent, "show_instance", return_value=reply): - result = joyent.query_instance(self.vm_) - self.assertTrue(joyent.__utils__["cloud.fire_event"].called_once()) - self.assertEqual(result, None) - - def test_query_instance_has_ip(self): - """ - IP address assigned but not yet ready - """ - reply = (200, {"primaryIp": "1.1.1.1", "state": "provisioning"}) - with patch.object(joyent, "show_instance", return_value=reply): - result = joyent.query_instance(self.vm_) - self.assertTrue(joyent.__utils__["cloud.fire_event"].called_once()) - self.assertEqual(result, None) - - def test_query_instance_ready(self): - """ - IP address assigned, and VM is ready - """ - reply = (200, {"primaryIp": "1.1.1.1", "state": "running"}) - with patch.object(joyent, "show_instance", return_value=reply): - result = joyent.query_instance(self.vm_) - self.assertTrue(joyent.__utils__["cloud.fire_event"].called_once()) - self.assertEqual(result, "1.1.1.1") diff --git a/tests/unit/cloud/clouds/test_linode.py b/tests/unit/cloud/clouds/test_linode.py deleted file mode 100644 index fa1adcff07a9..000000000000 --- a/tests/unit/cloud/clouds/test_linode.py +++ /dev/null @@ -1,96 +0,0 @@ -""" - :codeauthor: Nicole Thomas -""" - - -from salt.cloud.clouds import linode -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.unit import TestCase - - -class LinodeTestCase(TestCase, LoaderModuleMockMixin): - """ - Unit TestCase for the salt.cloud.clouds.linode module. - """ - - def setup_loader_modules(self): - return {linode: {}} - - # _validate_name tests - - def test_validate_name_first_character_invalid(self): - """ - Tests when name starts with an invalid character. - """ - # Test when name begins with a hyphen - self.assertFalse(linode._validate_name("-foo")) - - # Test when name begins with an underscore - self.assertFalse(linode._validate_name("_foo")) - - def test_validate_name_last_character_invalid(self): - """ - Tests when name ends with an invalid character. - """ - # Test when name ends with a hyphen - self.assertFalse(linode._validate_name("foo-")) - - # Test when name ends with an underscore - self.assertFalse(linode._validate_name("foo_")) - - def test_validate_name_too_short(self): - """ - Tests when name has less than three letters. - """ - # Test when name is an empty string - self.assertFalse(linode._validate_name("")) - - # Test when name is two letters long - self.assertFalse(linode._validate_name("ab")) - - # Test when name is three letters long (valid) - self.assertTrue(linode._validate_name("abc")) - - def test_validate_name_too_long(self): - """ - Tests when name has more than 48 letters. - """ - long_name = "1111-2222-3333-4444-5555-6666-7777-8888-9999-111" - # Test when name is 48 letters long (valid) - self.assertEqual(len(long_name), 48) - self.assertTrue(linode._validate_name(long_name)) - - # Test when name is more than 48 letters long - long_name += "1" - self.assertEqual(len(long_name), 49) - self.assertFalse(linode._validate_name(long_name)) - - def test_validate_name_invalid_characters(self): - """ - Tests when name contains invalid characters. - """ - # Test when name contains an invalid character - self.assertFalse(linode._validate_name("foo;bar")) - - # Test when name contains non-ascii letters - self.assertFalse(linode._validate_name("fooàààààbar")) - - # Test when name contains spaces - self.assertFalse(linode._validate_name("foo bar")) - - def test_validate_name_valid_characters(self): - """ - Tests when name contains valid characters. - """ - # Test when name contains letters and numbers - self.assertTrue(linode._validate_name("foo123bar")) - - # Test when name contains hyphens - self.assertTrue(linode._validate_name("foo-bar")) - - # Test when name contains underscores - self.assertTrue(linode._validate_name("foo_bar")) - - # Test when name start and end with numbers - self.assertTrue(linode._validate_name("1foo")) - self.assertTrue(linode._validate_name("foo0")) diff --git a/tests/unit/cloud/clouds/test_opennebula.py b/tests/unit/cloud/clouds/test_opennebula.py deleted file mode 100644 index 5dd96939251c..000000000000 --- a/tests/unit/cloud/clouds/test_opennebula.py +++ /dev/null @@ -1,1712 +0,0 @@ -""" - :codeauthor: Nicole Thomas -""" - -from salt.cloud.clouds import opennebula -from salt.exceptions import SaltCloudNotFound, SaltCloudSystemExit -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock, patch -from tests.support.unit import TestCase, skipIf - -try: - from lxml import etree # pylint: disable=unused-import - - HAS_XML_LIBS = True -except ImportError: - HAS_XML_LIBS = False - -VM_NAME = "my-vm" - - -class OpenNebulaTestCase(TestCase, LoaderModuleMockMixin): - """ - Unit TestCase for salt.cloud.clouds.opennebula module. - """ - - def setup_loader_modules(self): - return { - opennebula: { - "__utils__": {"cloud.cache_node": MagicMock()}, - "__active_provider_name__": "", - } - } - - def test_avail_images_action(self): - """ - Tests that a SaltCloudSystemExit error is raised when trying to call - avail_images with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.avail_images, "action") - - def test_avail_locations_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call avail_locations - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.avail_locations, "action") - - def test_avail_sizes_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call avail_sizes - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.avail_sizes, "action") - - def test_avail_sizes(self): - """ - Tests that avail_sizes returns an empty dictionary. - """ - self.assertEqual(opennebula.avail_sizes(call="foo"), {}) - - def test_list_clusters_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_clusters - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.list_clusters, "action") - - def test_list_datastores_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_datastores - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.list_datastores, "action") - - def test_list_hosts_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_datastores - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.list_hosts, "action") - - def test_list_nodes_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_nodes - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.list_nodes, "action") - - def test_list_nodes_full_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_full - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.list_nodes_full, "action") - - def test_list_nodes_select_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_full - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.list_nodes_select, "action") - - def test_list_security_groups_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call - list_security_groups with --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.list_security_groups, "action" - ) - - def test_list_templates_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_templates - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.list_templates, "action") - - def test_list_vns_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_vns - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.list_vns, "action") - - def test_reboot_error(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call reboot - with anything other that --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.reboot, "my-vm", "foo") - - def test_start_error(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call start - with anything other that --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.start, "my-vm", "foo") - - def test_stop_error(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call stop - with anything other that --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.stop, "my-vm", "foo") - - def test_get_cluster_id_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call - get_cluster_id with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.get_cluster_id, call="action") - - def test_get_cluster_id_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.get_cluster_id, None, call="foo" - ) - - def test_get_cluster_id_not_found(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - with patch( - "salt.cloud.clouds.opennebula.list_clusters", - MagicMock(return_value={"foo": {"id": "bar"}}), - ): - self.assertRaises( - SaltCloudSystemExit, - opennebula.get_cluster_id, - kwargs={"name": "test"}, - call="function", - ) - - def test_get_cluster_id_success(self): - """ - Tests that the function returns successfully. - """ - with patch( - "salt.cloud.clouds.opennebula.list_clusters", - MagicMock(return_value={"test-cluster": {"id": "100"}}), - ): - mock_id = "100" - mock_kwargs = {"name": "test-cluster"} - self.assertEqual(opennebula.get_cluster_id(mock_kwargs, "foo"), mock_id) - - def test_get_datastore_id_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call - get_datastore_id with --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.get_datastore_id, call="action" - ) - - def test_get_datastore_id_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.get_datastore_id, None, call="foo" - ) - - def test_get_datastore_id_not_found(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - with patch( - "salt.cloud.clouds.opennebula.list_datastores", - MagicMock(return_value={"test-datastore": {"id": "100"}}), - ): - self.assertRaises( - SaltCloudSystemExit, - opennebula.get_datastore_id, - kwargs={"name": "test"}, - call="function", - ) - - def test_get_datastore_id_success(self): - """ - Tests that the function returns successfully. - """ - with patch( - "salt.cloud.clouds.opennebula.list_datastores", - MagicMock(return_value={"test-datastore": {"id": "100"}}), - ): - mock_id = "100" - mock_kwargs = {"name": "test-datastore"} - self.assertEqual(opennebula.get_datastore_id(mock_kwargs, "foo"), mock_id) - - def test_get_host_id_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call - get_host_id with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.get_host_id, call="action") - - def test_get_host_id_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.get_host_id, None, call="foo") - - def test_get_host_id_not_found(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - with patch( - "salt.cloud.clouds.opennebula.avail_locations", - MagicMock(return_value={"test-host": {"id": "100"}}), - ): - self.assertRaises( - SaltCloudSystemExit, - opennebula.get_host_id, - kwargs={"name": "test"}, - call="function", - ) - - def test_get_host_id_success(self): - """ - Tests that the function returns successfully. - """ - with patch( - "salt.cloud.clouds.opennebula.avail_locations", - MagicMock(return_value={"test-host": {"id": "100"}}), - ): - mock_id = "100" - mock_kwargs = {"name": "test-host"} - self.assertEqual(opennebula.get_host_id(mock_kwargs, "foo"), mock_id) - - def test_get_image_not_found(self): - """ - Tests that a SaltCloudNotFound is raised when the image doesn't exist. - """ - with patch( - "salt.cloud.clouds.opennebula.avail_images", MagicMock(return_value={}) - ): - with patch( - "salt.config.get_cloud_config_value", MagicMock(return_value="foo") - ): - self.assertRaises(SaltCloudNotFound, opennebula.get_image, "my-vm") - - def test_get_image_success(self): - """ - Tests that the image is returned successfully. - """ - with patch( - "salt.cloud.clouds.opennebula.avail_images", - MagicMock(return_value={"my-vm": {"name": "my-vm", "id": 0}}), - ): - with patch( - "salt.config.get_cloud_config_value", MagicMock(return_value="my-vm") - ): - self.assertEqual(opennebula.get_image("my-vm"), 0) - - def test_get_image_id_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call - get_image_id with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.get_image_id, call="action") - - def test_get_image_id_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.get_image_id, None, call="foo" - ) - - def test_get_image_id_not_found(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - with patch( - "salt.cloud.clouds.opennebula.avail_images", - MagicMock(return_value={"test-image": {"id": "100"}}), - ): - self.assertRaises( - SaltCloudSystemExit, - opennebula.get_image_id, - kwargs={"name": "test"}, - call="function", - ) - - def test_get_image_id_success(self): - """ - Tests that the function returns successfully. - """ - with patch( - "salt.cloud.clouds.opennebula.avail_images", - MagicMock(return_value={"test-image": {"id": "100"}}), - ): - mock_id = "100" - mock_kwargs = {"name": "test-image"} - self.assertEqual(opennebula.get_image_id(mock_kwargs, "foo"), mock_id) - - def test_get_location_not_found(self): - """ - Tests that a SaltCloudNotFound is raised when the location doesn't exist. - """ - with patch( - "salt.cloud.clouds.opennebula.avail_locations", MagicMock(return_value={}) - ): - with patch( - "salt.config.get_cloud_config_value", MagicMock(return_value="foo") - ): - self.assertRaises(SaltCloudNotFound, opennebula.get_location, "my-vm") - - def test_get_location_success(self): - """ - Tests that the image is returned successfully. - """ - with patch( - "salt.cloud.clouds.opennebula.avail_locations", - MagicMock(return_value={"my-host": {"name": "my-host", "id": 0}}), - ): - with patch( - "salt.config.get_cloud_config_value", MagicMock(return_value="my-host") - ): - self.assertEqual(opennebula.get_location("my-host"), 0) - - def test_get_secgroup_id_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call - get_host_id with --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.get_secgroup_id, call="action" - ) - - def test_get_secgroup_id_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.get_secgroup_id, None, call="foo" - ) - - def test_get_secgroup_id_not_found(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - with patch( - "salt.cloud.clouds.opennebula.list_security_groups", - MagicMock(return_value={"test-security-group": {"id": "100"}}), - ): - self.assertRaises( - SaltCloudSystemExit, - opennebula.get_secgroup_id, - kwargs={"name": "test"}, - call="function", - ) - - def test_get_secgroup_id_success(self): - """ - Tests that the function returns successfully. - """ - with patch( - "salt.cloud.clouds.opennebula.list_security_groups", - MagicMock(return_value={"test-secgroup": {"id": "100"}}), - ): - mock_id = "100" - mock_kwargs = {"name": "test-secgroup"} - self.assertEqual(opennebula.get_secgroup_id(mock_kwargs, "foo"), mock_id) - - def test_get_template_id_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call - get_template_id with --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.get_template_id, call="action" - ) - - def test_get_template_id_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.get_template_id, None, call="foo" - ) - - def test_get_template_id_not_found(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - with patch( - "salt.cloud.clouds.opennebula.list_templates", - MagicMock(return_value={"test-template": {"id": "100"}}), - ): - self.assertRaises( - SaltCloudSystemExit, - opennebula.get_template_id, - kwargs={"name": "test"}, - call="function", - ) - - def test_get_template_id_success(self): - """ - Tests that the function returns successfully. - """ - with patch( - "salt.cloud.clouds.opennebula.list_templates", - MagicMock(return_value={"test-template": {"id": "100"}}), - ): - mock_id = "100" - mock_kwargs = {"name": "test-template"} - self.assertEqual(opennebula.get_template_id(mock_kwargs, "foo"), mock_id) - - def test_get_vm_id_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call - get_vm_id with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.get_vm_id, call="action") - - def test_get_vm_id_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.get_vm_id, None, call="foo") - - def test_get_vm_id_not_found(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - with patch( - "salt.cloud.clouds.opennebula.list_nodes", - MagicMock(return_value={"test-vm": {"id": "100"}}), - ): - self.assertRaises( - SaltCloudSystemExit, - opennebula.get_vm_id, - kwargs={"name": "test"}, - call="function", - ) - - def test_get_vm_id_success(self): - """ - Tests that the function returns successfully. - """ - with patch( - "salt.cloud.clouds.opennebula.list_nodes", - MagicMock(return_value={"test-vm": {"id": "100"}}), - ): - mock_id = "100" - mock_kwargs = {"name": "test-vm"} - self.assertEqual(opennebula.get_vm_id(mock_kwargs, "foo"), mock_id) - - def test_get_vn_id_action(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call - get_vn_id with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.get_vn_id, call="action") - - def test_get_vn_id_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.get_vn_id, None, call="foo") - - def test_get_vn_id_not_found(self): - """ - Tests that a SaltCloudSystemExit is raised when no name is provided. - """ - with patch( - "salt.cloud.clouds.opennebula.list_vns", - MagicMock(return_value={"test-vn": {"id": "100"}}), - ): - self.assertRaises( - SaltCloudSystemExit, - opennebula.get_vn_id, - kwargs={"name": "test"}, - call="function", - ) - - def test_get_vn_id_success(self): - """ - Tests that the function returns successfully. - """ - with patch( - "salt.cloud.clouds.opennebula.list_vns", - MagicMock(return_value={"test-vn": {"id": "100"}}), - ): - mock_id = "100" - mock_kwargs = {"name": "test-vn"} - self.assertEqual(opennebula.get_vn_id(mock_kwargs, "foo"), mock_id) - - # TODO: Write tests for create function - - def test_destroy_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.destroy, "my-vm", "function") - - def test_image_allocate_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_allocate, "foo") - - def test_image_allocate_no_name_or_datastore_id(self): - """ - Tests that a SaltCloudSystemExit is raised when a neither a datastore_id - nor a datastore_name is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_allocate, "function") - - def test_image_allocate_no_path_or_data(self): - """ - Tests that a SaltCloudSystemExit is raised when neither the path nor data args - are provided. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_allocate, - "function", - kwargs={"datastore_id": "5"}, - ) - - def test_image_clone_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_clone, "foo") - - def test_image_clone_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when a name isn't provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_clone, "function") - - def test_image_clone_no_image_id_or_image_name(self): - """ - Tests that a SaltCloudSystemExit is raised when neither the image_id nor - the image_name args are provided. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_clone, - "function", - kwargs={"name": "test"}, - ) - - @skipIf(True, "Need to figure out how to mock calls to the O.N. API first.") - def test_image_clone_success(self): - """ - Tests that image_clone returns successfully - """ - with patch("image.clone", MagicMock(return_value=[True, 11, 0])): - name = "test-image" - expected = { - "action": "image.clone", - "cloned": "True", - "cloned_image_id": "11", - "cloned_image_name": name, - "error_code": "0", - } - ret = opennebula.image_clone( - "function", kwargs={"name": name, "image_id": 1} - ) - self.assertEqual(expected, ret) - - def test_image_delete_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_delete, "foo") - - def test_image_delete_no_name_or_image_id(self): - """ - Tests that a SaltCloudSystemExit is raised when a neither an image_id - nor a name is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_delete, "function") - - def test_image_info_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_info, "foo") - - def test_image_info_no_image_id_or_image_name(self): - """ - Tests that a SaltCloudSystemExit is raised when a neither an image_id - nor a name is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_info, "function") - - def test_image_persist_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_persistent, "foo") - - def test_image_persist_no_persist(self): - """ - Tests that a SaltCloudSystemExit is raised when the persist kwarg is missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_persistent, "function") - - def test_image_persist_no_name_or_image_id(self): - """ - Tests that a SaltCloudSystemExit is raised when a neither an image_id - nor a name is provided. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_delete, - "function", - kwargs={"persist": False}, - ) - - def test_image_snapshot_delete_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.image_snapshot_delete, call="foo" - ) - - def test_image_snapshot_delete_no_snapshot_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the snapshot_id kwarg is - missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_snapshot_delete, - call="function", - kwargs=None, - ) - - def test_image_snapshot_delete_no_image_name_or_image_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the image_id and image_name - kwargs are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_snapshot_delete, - call="function", - kwargs={"snapshot_id": 0}, - ) - - def test_image_snapshot_revert_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.image_snapshot_revert, call="foo" - ) - - def test_image_snapshot_revert_no_snapshot_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the snapshot_id kwarg is - missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_snapshot_revert, - call="function", - kwargs=None, - ) - - def test_image_snapshot_revert_no_image_name_or_image_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the image_id and image_name - kwargs are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_snapshot_revert, - call="function", - kwargs={"snapshot_id": 0}, - ) - - def test_image_snapshot_flatten_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.image_snapshot_flatten, call="foo" - ) - - def test_image_snapshot_flatten_no_snapshot_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the snapshot_id kwarg is - missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_snapshot_flatten, - call="function", - kwargs=None, - ) - - def test_image_snapshot_flatten_no_image_name_or_image_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the image_id and image_name - kwargs are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_snapshot_flatten, - call="function", - kwargs={"snapshot_id": 0}, - ) - - def test_image_update_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_update, "foo") - - def test_image_update_no_update_type(self): - """ - Tests that a SaltCloudSystemExit is raised when the update_type kwarg is - missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.image_update, "function") - - def test_image_update_bad_update_type_value(self): - """ - Tests that a SaltCloudSystemExit is raised when the update_type kwarg is - not a valid value. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_update, - "function", - kwargs={"update_type": "foo"}, - ) - - def test_image_update_no_image_id_or_image_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the image_id and image_name - kwargs are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_update, - "function", - kwargs={"update_type": "merge"}, - ) - - def test_image_update_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and path - kwargs are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.image_update, - "function", - kwargs={"update_type": "merge", "image_id": "0"}, - ) - - def test_show_instance_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.show_instance, VM_NAME, call="foo" - ) - - def test_show_instance_success(self): - """ - Tests that the node was found successfully. - """ - with patch( - "salt.cloud.clouds.opennebula._get_node", - MagicMock(return_value={"my-vm": {"name": "my-vm", "id": 0}}), - ): - ret = {"my-vm": {"name": "my-vm", "id": 0}} - self.assertEqual(opennebula.show_instance("my-vm", call="action"), ret) - - def test_secgroup_allocate_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.secgroup_allocate, "foo") - - def test_secgroup_allocate_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and path - kwargs are missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.secgroup_allocate, "function") - - def test_secgroup_clone_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.secgroup_clone, "foo") - - def test_secgroup_clone_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the name kwarg is - missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.secgroup_clone, "function") - - def test_secgroup_clone_no_secgroup_id_or_secgroup_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the secgroup_id and - secgroup_name kwargs are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.secgroup_clone, - "function", - kwargs={"name": "test"}, - ) - - def test_secgroup_delete_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.secgroup_delete, "foo") - - def test_secgroup_delete_no_secgroup_id_or_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the secgroup_id and - name kwargs are missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.secgroup_clone, "function") - - def test_secgroup_info_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.secgroup_info, "foo") - - def test_secgroup_info_no_secgroup_id_or_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the secgroup_id and - name kwargs are missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.secgroup_info, "function") - - def test_secgroup_update_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.secgroup_update, "foo") - - def test_secgroup_update_no_update_type(self): - """ - Tests that a SaltCloudSystemExit is raised when the update_type arg is - missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.secgroup_update, "function") - - def test_secgroup_update_bad_update_type_value(self): - """ - Tests that a SaltCloudSystemExit is raised when the update_type contains - an invalid value. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.secgroup_update, - "function", - kwargs={"update_type": "foo"}, - ) - - def test_secgroup_update_no_secgroup_id_or_secgroup_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the secgroup_id and - secgroup_name kwargs are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.secgroup_update, - "function", - kwargs={"update_type": "merge"}, - ) - - def test_secgroup_update_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and - path kwargs are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.secgroup_update, - "function", - kwargs={"update_type": "merge", "secgroup_id": "0"}, - ) - - def test_template_allocate_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.template_allocate, "foo") - - def test_template_allocate_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and - path kwargs are missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.template_allocate, "function") - - def test_template_clone_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.template_clone, "foo") - - def test_template_clone_no_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the name arg is missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.template_clone, "function") - - def test_template_clone_no_template_name_or_template_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the template_name and - template_id args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.template_clone, - "function", - kwargs={"name": "foo"}, - ) - - def test_template_delete_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.template_delete, "foo") - - def test_template_delete_no_name_or_template_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the name and - template_id args are missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.template_delete, "function") - - def test_template_instantiate_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.template_instantiate, "foo") - - def test_template_instantiate_no_vm_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the vm_name arg is missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.template_instantiate, "function", None - ) - - def test_template_instantiate_no_template_id_or_template_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the template_name and - template_id args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.template_instantiate, - "function", - kwargs={"vm_name": "test"}, - ) - - def test_template_update_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.template_update, call="foo") - - def test_template_update_bad_update_type_value(self): - """ - Tests that a SaltCloudSystemExit is raised when the update_type contains - and invalid value. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.template_update, - call="function", - kwargs={"update_type": "foo"}, - ) - - def test_template_update_no_template_id_or_template_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the template_id and the - template_name args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.template_update, - call="function", - kwargs={"update_type": "merge"}, - ) - - def test_template_update_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and the - path args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.template_update, - call="function", - kwargs={"update_type": "merge", "template_id": "0"}, - ) - - def test_vm_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_action, VM_NAME, call="foo" - ) - - def test_vm_action_no_action(self): - """ - Tests that a SaltCloudSystemExit is raised when the action arg is missing - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_action, VM_NAME, call="action" - ) - - def test_vm_allocate_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vm_allocate, "foo") - - def test_vm_allocate_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and - path kwargs are missing. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vm_allocate, "function") - - def test_vm_attach_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_attach, VM_NAME, call="foo" - ) - - def test_vm_attach_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and - path kwargs are missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_attach, VM_NAME, call="action" - ) - - def test_vm_attach_nic_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_attach_nic, VM_NAME, call="foo" - ) - - def test_vm_attach_nic_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and - path kwargs are missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_attach_nic, VM_NAME, call="action" - ) - - def test_vm_deploy_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_deploy, VM_NAME, call="foo" - ) - - def test_vm_deploy_no_host_id_or_host_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the host_id and the - host_name args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_deploy, - VM_NAME, - call="action", - kwargs=None, - ) - - def test_vm_detach_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_detach, VM_NAME, call="foo" - ) - - def test_vm_detach_no_disk_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the disk_id ar is missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_detach, VM_NAME, call="action" - ) - - def test_vm_detach_nic_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_detach_nic, VM_NAME, call="foo" - ) - - def test_vm_detach_nic_no_nic_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the nic_id arg is missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_detach_nic, VM_NAME, call="action" - ) - - def test_vm_disk_save_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_disk_save, VM_NAME, call="foo" - ) - - def test_vm_disk_save_no_disk_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the disk_id arg is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_disk_save, - VM_NAME, - call="action", - kwargs={"image_name": "foo"}, - ) - - def test_vm_disk_save_no_image_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the image_name arg is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_disk_save, - VM_NAME, - call="action", - kwargs={"disk_id": "0"}, - ) - - def test_vm_disk_snapshot_create_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_disk_snapshot_create, VM_NAME, call="foo" - ) - - def test_vm_disk_snapshot_create_no_disk_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the disk_id arg is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_disk_snapshot_create, - VM_NAME, - call="action", - kwargs={"description": "foo"}, - ) - - def test_vm_disk_snapshot_create_no_description(self): - """ - Tests that a SaltCloudSystemExit is raised when the image_name arg is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_disk_snapshot_create, - VM_NAME, - call="action", - kwargs={"disk_id": "0"}, - ) - - def test_vm_disk_snapshot_delete_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_disk_snapshot_delete, VM_NAME, call="foo" - ) - - def test_vm_disk_snapshot_delete_no_disk_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the disk_id arg is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_disk_snapshot_delete, - VM_NAME, - call="action", - kwargs={"snapshot_id": "0"}, - ) - - def test_vm_disk_snapshot_delete_no_snapshot_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the snapshot_id arg is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_disk_snapshot_delete, - VM_NAME, - call="action", - kwargs={"disk_id": "0"}, - ) - - def test_vm_disk_snapshot_revert_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_disk_snapshot_revert, VM_NAME, call="foo" - ) - - def test_vm_disk_snapshot_revert_no_disk_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the disk_id arg is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_disk_snapshot_revert, - VM_NAME, - call="action", - kwargs={"snapshot_id": "0"}, - ) - - def test_vm_disk_snapshot_revert_no_snapshot_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the snapshot_id arg is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_disk_snapshot_revert, - VM_NAME, - call="action", - kwargs={"disk_id": "0"}, - ) - - def test_vm_info_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vm_info, VM_NAME, call="foo") - - def test_vm_migrate_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_migrate, VM_NAME, call="foo" - ) - - def test_vm_migrate_no_datastore_id_or_datastore_name(self): - """ - Tests that a SaltCLoudSystemExit is raised when the datastore_id and the - datastore_name args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_migrate, - VM_NAME, - call="action", - kwargs=None, - ) - - def test_vm_migrate_no_host_id_or_host_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the host_id and the - host_name args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_migrate, - VM_NAME, - call="action", - kwargs={"datastore_id": "0"}, - ) - - def test_vm_monitoring_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_monitoring, VM_NAME, call="foo" - ) - - def test_vm_resize_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_resize, VM_NAME, call="foo" - ) - - def test_vm_resize_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and path args - are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_resize, - VM_NAME, - call="action", - kwargs=None, - ) - - def test_vm_snapshot_create_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_snapshot_create, VM_NAME, call="foo" - ) - - def test_vm_snapshot_create_no_snapshot_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the snapshot_name arg - is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_snapshot_create, - VM_NAME, - call="action", - kwargs=None, - ) - - def test_vm_snapshot_delete_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_snapshot_delete, VM_NAME, call="foo" - ) - - def test_vm_snapshot_delete_no_snapshot_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the snapshot_id arg - is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_snapshot_delete, - VM_NAME, - call="action", - kwargs=None, - ) - - def test_vm_snapshot_revert_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_snapshot_revert, VM_NAME, call="foo" - ) - - def test_vm_snapshot_revert_no_snapshot_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the snapshot_id arg - is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_snapshot_revert, - VM_NAME, - call="action", - kwargs=None, - ) - - def test_vm_update_action_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --action or -a is provided. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vm_update, VM_NAME, call="foo" - ) - - def test_vm_update_no_update_type(self): - """ - Tests that a SaltCloudSystemExit is raised when the update_type arg - is missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_update, - VM_NAME, - call="action", - kwargs=None, - ) - - def test_vm_update_bad_update_type_value(self): - """ - Tests that a SaltCloudSystemExit is raised when the update_type kwarg is - not a valid value. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_update, - VM_NAME, - call="action", - kwargs={"update_type": "foo"}, - ) - - def test_vm_update_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and path args - are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vm_update, - VM_NAME, - call="action", - kwargs={"update_type": "merge"}, - ) - - def test_vn_add_ar_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vn_add_ar, call="foo") - - def test_vn_add_ar_no_vn_id_or_vn_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vn_add_ar, call="function", kwargs=None - ) - - def test_vn_add_ar_no_path_or_data(self): - """ - Tests that a SaltCloudSystemExit is raised when the path and data - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vn_add_ar, - call="function", - kwargs={"vn_id": "0"}, - ) - - def test_vn_allocate_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vn_allocate, call="foo") - - def test_vn_allocate_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the path and data - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vn_allocate, call="function", kwargs=None - ) - - def test_vn_delete_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vn_delete, call="foo") - - def test_vn_delete_no_vn_id_or_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the vn_id and name - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vn_delete, call="function", kwargs=None - ) - - def test_vn_free_ar_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vn_free_ar, call="foo") - - def test_vn_free_ar_no_ar_id(self): - """ - Tests that a SaltCloudSystemExit is raised when the ar_id is missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vn_free_ar, call="function", kwargs=None - ) - - def test_vn_free_ar_no_vn_id_or_vn_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vn_free_ar, - call="function", - kwargs={"ar_id": "0"}, - ) - - def test_vn_hold_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vn_hold, call="foo") - - def test_vn_hold_no_vn_id_or_vn_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vn_hold, call="function", kwargs=None - ) - - def test_vn_hold_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and path - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vn_hold, - call="function", - kwargs={"vn_id": "0"}, - ) - - def test_vn_info_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vn_info, call="foo") - - def test_vn_info_no_vn_id_or_vn_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vn_info, call="function", kwargs=None - ) - - def test_vn_release_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vn_release, call="foo") - - def test_vn_release_no_vn_id_or_vn_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vn_release, call="function", kwargs=None - ) - - def test_vn_release_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and path - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vn_release, - call="function", - kwargs={"vn_id": "0"}, - ) - - def test_vn_reserve_function_error(self): - """ - Tests that a SaltCloudSystemExit is raised when something other than - --function or -f is provided. - """ - self.assertRaises(SaltCloudSystemExit, opennebula.vn_reserve, call="foo") - - def test_vn_reserve_no_vn_id_or_vn_name(self): - """ - Tests that a SaltCloudSystemExit is raised when the vn_id and vn_name - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, opennebula.vn_reserve, call="function", kwargs=None - ) - - def test_vn_reserve_no_data_or_path(self): - """ - Tests that a SaltCloudSystemExit is raised when the data and path - args are missing. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula.vn_reserve, - call="function", - kwargs={"vn_id": "0"}, - ) - - @skipIf(not HAS_XML_LIBS, "cannot find lxml python library") - def test__get_xml(self): - """ - Tests that invalid XML raises SaltCloudSystemExit. - """ - self.assertRaises( - SaltCloudSystemExit, - opennebula._get_xml, - "[VirtualMachinePoolInfo] User couldn't be authenticated, aborting call.", - ) diff --git a/tests/unit/cloud/clouds/test_openstack.py b/tests/unit/cloud/clouds/test_openstack.py deleted file mode 100644 index e17d21b5bc25..000000000000 --- a/tests/unit/cloud/clouds/test_openstack.py +++ /dev/null @@ -1,274 +0,0 @@ -""" - :codeauthor: `Tyler Johnson ` - - tests.unit.cloud.clouds.openstack_test - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -""" - - -from salt.cloud.clouds import openstack -from salt.utils import dictupdate -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock, patch -from tests.support.unit import TestCase - -# pylint: disable=confusing-with-statement - - -class MockImage: - name = "image name" - id = "image id" - - -class MockNode: - name = "node name" - id = "node id" - flavor = MockImage() - status = "node status" - - def __init__(self, image): - self.image = image - - def __iter__(self): - return iter(()) - - -class MockConn: - def __init__(self, image): - self.node = MockNode(image) - - def get_image(self, *args, **kwargs): - return self.node.image - - def get_flavor(self, *args, **kwargs): - return self.node.flavor - - def get_server(self, *args, **kwargs): - return self.node - - def list_servers(self, *args, **kwargs): - return [self.node] - - -class OpenstackTestCase(TestCase, LoaderModuleMockMixin): - """ - Unit TestCase for salt.cloud.clouds.openstack module. - """ - - def setup_loader_modules(self): - return { - openstack: { - "__active_provider_name__": "", - "__opts__": { - "providers": { - "my-openstack-cloud": { - "openstack": { - "auth": "daenerys", - "region_name": "westeros", - "cloud": "openstack", - } - } - } - }, - } - } - - def test_get_configured_provider_bad(self): - with patch.dict(openstack.__opts__, {"providers": {}}): - result = openstack.get_configured_provider() - self.assertEqual(result, False) - - def test_get_configured_provider_auth(self): - config = { - "region_name": "westeros", - "auth": "daenerys", - } - with patch.dict( - openstack.__opts__, - {"providers": {"my-openstack-cloud": {"openstack": config}}}, - ): - result = openstack.get_configured_provider() - self.assertEqual(config, result) - - def test_get_configured_provider_cloud(self): - config = { - "region_name": "westeros", - "cloud": "foo", - } - with patch.dict( - openstack.__opts__, - {"providers": {"my-openstack-cloud": {"openstack": config}}}, - ): - result = openstack.get_configured_provider() - self.assertEqual(config, result) - - def test_get_dependencies(self): - HAS_SHADE = (True, "Please install newer version of shade: >= 1.19.0") - with patch("salt.cloud.clouds.openstack.HAS_SHADE", HAS_SHADE): - result = openstack.get_dependencies() - self.assertEqual(result, True) - - def test_get_dependencies_no_shade(self): - HAS_SHADE = (False, "Install pypi module shade >= 1.19.0") - with patch("salt.cloud.clouds.openstack.HAS_SHADE", HAS_SHADE): - result = openstack.get_dependencies() - self.assertEqual(result, False) - - def test_list_nodes_full_image_str(self): - node_image = "node image" - conn = MockConn(node_image) - with patch("salt.cloud.clouds.openstack._get_ips", return_value=[]): - ret = openstack.list_nodes_full(conn=conn) - self.assertEqual(ret[conn.node.name]["image"], node_image) - - def test_list_nodes_full_image_obj(self): - conn = MockConn(MockImage()) - with patch("salt.cloud.clouds.openstack._get_ips", return_value=[]): - ret = openstack.list_nodes_full(conn=conn) - self.assertEqual(ret[conn.node.name]["image"], MockImage.name) - - def test_show_instance(self): - conn = MockConn(MockImage()) - with patch("salt.cloud.clouds.openstack._get_ips", return_value=[]): - ret = openstack.show_instance(conn.node.name, conn=conn, call="action") - self.assertEqual(ret["image"], MockImage.name) - - def test_request_instance_should_use_provided_connection_if_not_None(self): - fake_conn = MagicMock() - - patch_get_conn = patch("salt.cloud.clouds.openstack.get_conn", autospec=True) - patch_utils = patch.dict( - openstack.__utils__, - {"cloud.check_name": MagicMock(), "dictupdate.update": dictupdate.update}, - ) - patch_shade = patch.object( - openstack, "shade.exc.OpenStackCloudException", Exception, create=True - ) - - with patch_get_conn as fake_get_conn, patch_utils, patch_shade: - openstack.request_instance( - vm_={"name": "fnord", "driver": "fnord"}, conn=fake_conn - ) - - fake_get_conn.assert_not_called() - - def test_request_instance_should_create_conn_if_provided_is_None(self): - none_conn = None - - patch_get_conn = patch("salt.cloud.clouds.openstack.get_conn", autospec=True) - patch_utils = patch.dict( - openstack.__utils__, - {"cloud.check_name": MagicMock(), "dictupdate.update": dictupdate.update}, - ) - patch_shade = patch.object( - openstack, "shade.exc.OpenStackCloudException", Exception, create=True - ) - - with patch_get_conn as fake_get_conn, patch_utils, patch_shade: - openstack.request_instance( - vm_={"name": "fnord", "driver": "fnord"}, conn=none_conn - ) - - fake_get_conn.assert_called_once_with() - - # According to - # https://docs.openstack.org/shade/latest/user/usage.html#shade.OpenStackCloud.create_server - # the `network` parameter can be: - # (optional) Network dict or name or ID to attach the server to. - # Mutually exclusive with the nics parameter. Can also be be a list of - # network names or IDs or network dicts. - # - # Here we're testing a normal dictionary - def test_request_instance_should_be_able_to_provide_a_dictionary_for_network(self): - fake_conn = MagicMock() - expected_network = {"foo": "bar"} - vm_ = {"name": "fnord", "driver": "fnord", "network": expected_network} - patch_utils = patch.dict( - openstack.__utils__, - {"cloud.check_name": MagicMock(), "dictupdate.update": dictupdate.update}, - ) - with patch_utils: - openstack.request_instance(vm_=vm_, conn=fake_conn) - - call_kwargs = fake_conn.create_server.mock_calls[0][-1] - self.assertDictEqual(call_kwargs["network"], expected_network) - - # Here we're testing the list of dictionaries - def test_request_instance_should_be_able_to_provide_a_list_of_dictionaries_for_network( - self, - ): - fake_conn = MagicMock() - expected_network = [{"foo": "bar"}, {"bang": "quux"}] - vm_ = {"name": "fnord", "driver": "fnord", "network": expected_network} - patch_utils = patch.dict( - openstack.__utils__, - {"cloud.check_name": MagicMock(), "dictupdate.update": dictupdate.update}, - ) - with patch_utils: - openstack.request_instance(vm_=vm_, conn=fake_conn) - - call_kwargs = fake_conn.create_server.mock_calls[0][-1] - assert call_kwargs["network"] == expected_network - - # Here we're testing for names/IDs - def test_request_instance_should_be_able_to_provide_a_list_of_single_ids_or_names_for_network( - self, - ): - fake_conn = MagicMock() - expected_network = ["foo", "bar", "bang", "fnord1", "fnord2"] - vm_ = {"name": "fnord", "driver": "fnord", "network": expected_network} - patch_utils = patch.dict( - openstack.__utils__, - {"cloud.check_name": MagicMock(), "dictupdate.update": dictupdate.update}, - ) - with patch_utils: - openstack.request_instance(vm_=vm_, conn=fake_conn) - - call_kwargs = fake_conn.create_server.mock_calls[0][-1] - assert call_kwargs["network"] == expected_network - - # Testing that we get a dict that we expect for create_server - def test__clean_create_kwargs(self): - params = { - "name": "elmer", - "image": "mirrormirror", - "flavor": "chocolate", - "auto_ip": True, - "ips": ["hihicats"], - "ip_pool": "olympic", - "root_volume": "iamgroot", - "boot_volume": "pussnboots", - "terminate_volume": False, - "volumes": ["lots", "of", "books"], - "meta": {"full": "meta"}, - "files": {"shred": "this"}, - "reservation_id": "licenseandregistration", - "security_groups": ["wanna", "play", "repeat"], - "key_name": "clortho", - "availability_zone": "callmemaybe", - "block_device_mapping": [{"listof": "dicts"}], - "block_device_mapping_v2": [{"listof": "dicts"}], - "nics": ["thats", "me"], - "scheduler_hints": {"so": "many"}, - "config_drive": True, - "disk_config": "donkey", - "admin_pass": "password", - "wait": False, - "timeout": 30, - "reuse_ips": True, - "network": ["also", "a", "dict"], - "boot_from_volume": True, - "volume_size": 30, - "nat_destination": "albuquerque", - "group": "ledzeppelin", - "userdata": "needmoreinput", - "thisgetsdropped": "yup", - } - patch_utils = patch.dict( - openstack.__utils__, - {"dictupdate.update": dictupdate.update}, - ) - with patch_utils: - ret = openstack._clean_create_kwargs(**params) - params.pop("thisgetsdropped") - self.assertDictEqual(params, ret) diff --git a/tests/unit/cloud/clouds/test_proxmox.py b/tests/unit/cloud/clouds/test_proxmox.py deleted file mode 100644 index f479b71c06fd..000000000000 --- a/tests/unit/cloud/clouds/test_proxmox.py +++ /dev/null @@ -1,507 +0,0 @@ -""" - :codeauthor: Tyler Johnson -""" - -import io -import textwrap -import urllib - -import requests - -from salt import config -from salt.cloud.clouds import proxmox -from tests.support.helpers import TstSuiteLoggingHandler -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import ANY, MagicMock, call, patch -from tests.support.unit import TestCase - -PROFILE = { - "my_proxmox": { - "provider": "my_proxmox", - "image": "local:some_image.tgz", - } -} -PROVIDER_CONFIG = { - "my_proxmox": { - "proxmox": { - "driver": "proxmox", - "url": "pve@domain.com", - "user": "cloud@pve", - "password": "verybadpass", - "profiles": PROFILE, - } - } -} - - -class ProxmoxTest(TestCase, LoaderModuleMockMixin): - def setup_loader_modules(self): - return { - proxmox: { - "__utils__": { - "cloud.fire_event": MagicMock(), - "cloud.filter_event": MagicMock(), - "cloud.bootstrap": MagicMock(), - }, - "__opts__": { - "sock_dir": True, - "transport": True, - "providers": PROVIDER_CONFIG, - "profiles": PROFILE, - }, - "__active_provider_name__": "my_proxmox:proxmox", - } - } - - def setUp(self): - self.vm_ = { - "profile": "my_proxmox", - "name": "vm4", - "driver": "proxmox", - "technology": "qemu", - "host": "127.0.0.1", - "clone": True, - "ide0": "data", - "sata0": "data", - "scsi0": "data", - "net0": "a=b,c=d", - } - - def tearDown(self): - del self.vm_ - - def test__stringlist_to_dictionary(self): - result = proxmox._stringlist_to_dictionary("") - self.assertEqual(result, {}) - - result = proxmox._stringlist_to_dictionary( - "foo=bar, ignored_space=bar,internal space=bar" - ) - self.assertEqual( - result, {"foo": "bar", "ignored_space": "bar", "internal space": "bar"} - ) - - # Negative cases - self.assertRaises(ValueError, proxmox._stringlist_to_dictionary, "foo=bar,foo") - self.assertRaises( - ValueError, - proxmox._stringlist_to_dictionary, - "foo=bar,totally=invalid=assignment", - ) - - def test__dictionary_to_stringlist(self): - result = proxmox._dictionary_to_stringlist({}) - self.assertEqual(result, "") - - result = proxmox._dictionary_to_stringlist({"a": "a"}) - self.assertEqual(result, "a=a") - - result = proxmox._dictionary_to_stringlist({"a": "a", "b": "b"}) - self.assertEqual(result, "a=a,b=b") - - def test__reconfigure_clone_net_hdd(self): - # The return_value is for the net reconfigure assertions, it is irrelevant for the rest - with patch( - "salt.cloud.clouds.proxmox._get_properties", - MagicMock(return_value=["net0", "ide0", "sata0", "scsi0"]), - ), patch.object( - proxmox, "query", return_value={"net0": "c=overwritten,g=h"} - ) as query: - # Test a vm that lacks the required attributes - proxmox._reconfigure_clone({}, 0) - query.assert_not_called() - - # Test a fully mocked vm - proxmox._reconfigure_clone(self.vm_, 0) - - # net reconfigure - query.assert_any_call("get", "nodes/127.0.0.1/qemu/0/config") - query.assert_any_call( - "post", "nodes/127.0.0.1/qemu/0/config", {"net0": "a=b,c=d,g=h"} - ) - - # hdd reconfigure - query.assert_any_call( - "post", "nodes/127.0.0.1/qemu/0/config", {"ide0": "data"} - ) - query.assert_any_call( - "post", "nodes/127.0.0.1/qemu/0/config", {"sata0": "data"} - ) - query.assert_any_call( - "post", "nodes/127.0.0.1/qemu/0/config", {"scsi0": "data"} - ) - - def test__reconfigure_clone_params(self): - """ - Test cloning a VM with parameters to be reconfigured. - """ - vmid = 201 - properties = { - "ide2": "cdrom", - "sata1": "satatest", - "scsi0": "bootvol", - "net0": "model=virtio", - "agent": "1", - "args": "argsvalue", - "balloon": "128", - "ciuser": "root", - "cores": "2", - "description": "desc", - "memory": "256", - "name": "new2", - "onboot": "0", - "sshkeys": "ssh-rsa ABCDEF user@host\n", - } - query_calls = [call("get", "nodes/myhost/qemu/{}/config".format(vmid))] - for key, value in properties.items(): - if key == "sshkeys": - value = urllib.parse.quote(value, safe="") - query_calls.append( - call( - "post", - "nodes/myhost/qemu/{}/config".format(vmid), - {key: value}, - ) - ) - - mock_query = MagicMock(return_value="") - with patch( - "salt.cloud.clouds.proxmox._get_properties", - MagicMock(return_value=list(properties.keys())), - ), patch("salt.cloud.clouds.proxmox.query", mock_query): - vm_ = { - "profile": "my_proxmox", - "driver": "proxmox", - "technology": "qemu", - "name": "new2", - "host": "myhost", - "clone": True, - "clone_from": 123, - "ip_address": "10.10.10.10", - } - vm_.update(properties) - - proxmox._reconfigure_clone(vm_, vmid) - mock_query.assert_has_calls(query_calls, any_order=True) - - def test_clone(self): - """ - Test that an integer value for clone_from - """ - mock_query = MagicMock(return_value="") - with patch( - "salt.cloud.clouds.proxmox._get_properties", MagicMock(return_value=[]) - ), patch("salt.cloud.clouds.proxmox.query", mock_query): - vm_ = { - "technology": "qemu", - "name": "new2", - "host": "myhost", - "clone": True, - "clone_from": 123, - } - - # CASE 1: Numeric ID - result = proxmox.create_node(vm_, ANY) - mock_query.assert_called_once_with( - "post", - "nodes/myhost/qemu/123/clone", - {"newid": ANY}, - ) - assert result == {"vmid": ANY} - - # CASE 2: host:ID notation - mock_query.reset_mock() - vm_["clone_from"] = "otherhost:123" - result = proxmox.create_node(vm_, ANY) - mock_query.assert_called_once_with( - "post", - "nodes/otherhost/qemu/123/clone", - {"newid": ANY}, - ) - assert result == {"vmid": ANY} - - def test_clone_pool(self): - """ - Test that cloning a VM passes the pool parameter if present - """ - mock_query = MagicMock(return_value="") - with patch( - "salt.cloud.clouds.proxmox._get_properties", MagicMock(return_value=[]) - ), patch("salt.cloud.clouds.proxmox.query", mock_query): - vm_ = { - "technology": "qemu", - "name": "new2", - "host": "myhost", - "clone": True, - "clone_from": 123, - "pool": "mypool", - } - - result = proxmox.create_node(vm_, ANY) - mock_query.assert_called_once_with( - "post", - "nodes/myhost/qemu/123/clone", - {"newid": ANY, "pool": "mypool"}, - ) - assert result == {"vmid": ANY} - - def test_clone_id(self): - """ - Test cloning a VM with a specified vmid. - """ - next_vmid = 101 - explicit_vmid = 201 - upid = "UPID:myhost:00123456:12345678:9ABCDEF0:qmclone:123:root@pam:" - - def mock_query_response(conn_type, option, post_data=None): - if conn_type == "get" and option == "cluster/tasks": - return [{"upid": upid, "status": "OK"}] - if conn_type == "post" and option.endswith("/clone"): - return upid - return None - - mock_wait_for_state = MagicMock(return_value=True) - with patch( - "salt.cloud.clouds.proxmox._get_properties", - MagicMock(return_value=["vmid"]), - ), patch( - "salt.cloud.clouds.proxmox._get_next_vmid", - MagicMock(return_value=next_vmid), - ), patch( - "salt.cloud.clouds.proxmox.start", MagicMock(return_value=True) - ), patch( - "salt.cloud.clouds.proxmox.wait_for_state", mock_wait_for_state - ), patch( - "salt.cloud.clouds.proxmox.query", side_effect=mock_query_response - ): - vm_ = { - "profile": "my_proxmox", - "driver": "proxmox", - "technology": "qemu", - "name": "new2", - "host": "myhost", - "clone": True, - "clone_from": 123, - "ip_address": "10.10.10.10", - } - - # CASE 1: No vmid specified in profile (previous behavior) - proxmox.create(vm_) - mock_wait_for_state.assert_called_with( - next_vmid, - "running", - ) - - # CASE 2: vmid specified in profile - vm_["vmid"] = explicit_vmid - proxmox.create(vm_) - mock_wait_for_state.assert_called_with( - explicit_vmid, - "running", - ) - - def test_find_agent_ips(self): - """ - Test find_agent_ip will return an IP - """ - - with patch( - "salt.cloud.clouds.proxmox.query", - return_value={ - "result": [ - { - "name": "eth0", - "ip-addresses": [ - {"ip-address": "1.2.3.4", "ip-address-type": "ipv4"}, - {"ip-address": "2001::1:2", "ip-address-type": "ipv6"}, - ], - }, - { - "name": "eth1", - "ip-addresses": [ - {"ip-address": "2.3.4.5", "ip-address-type": "ipv4"}, - ], - }, - { - "name": "dummy", - }, - ] - }, - ) as mock_query: - vm_ = { - "technology": "qemu", - "host": "myhost", - "driver": "proxmox", - "ignore_cidr": "1.0.0.0/8", - } - - # CASE 1: Test ipv4 and ignore_cidr - result = proxmox._find_agent_ip(vm_, ANY) - mock_query.assert_any_call( - "get", "nodes/myhost/qemu/{}/agent/network-get-interfaces".format(ANY) - ) - - assert result == "2.3.4.5" - - # CASE 2: Test ipv6 - - vm_["protocol"] = "ipv6" - result = proxmox._find_agent_ip(vm_, ANY) - mock_query.assert_any_call( - "get", "nodes/myhost/qemu/{}/agent/network-get-interfaces".format(ANY) - ) - - assert result == "2001::1:2" - - def test__authenticate_with_custom_port(self): - """ - Test the use of a custom port for Proxmox connection - """ - get_cloud_config_mock = [ - "proxmox.connection.url", - "9999", - "fakeuser", - "secretpassword", - True, - ] - requests_post_mock = MagicMock() - with patch( - "salt.config.get_cloud_config_value", - autospec=True, - side_effect=get_cloud_config_mock, - ), patch("requests.post", requests_post_mock): - proxmox._authenticate() - requests_post_mock.assert_called_with( - "https://proxmox.connection.url:9999/api2/json/access/ticket", - verify=True, - data={"username": ("fakeuser",), "password": "secretpassword"}, - ) - - def test__import_api_v6(self): - """ - Test _import_api handling of a Proxmox VE 6 response. - """ - response = textwrap.dedent( - """\ - var pveapi = [ - { - "info" : { - } - } - ] - ; - """ - ) - self._test__import_api(response) - - def test__import_api_v7(self): - """ - Test _import_api handling of a Proxmox VE 7 response. - """ - response = textwrap.dedent( - """\ - const apiSchema = [ - { - "info" : { - } - } - ] - ; - """ - ) - self._test__import_api(response) - - def _test__import_api(self, response): - """ - Test _import_api recognition of varying Proxmox VE responses. - """ - requests_get_mock = MagicMock() - requests_get_mock.return_value.status_code = 200 - requests_get_mock.return_value.text = response - with patch("requests.get", requests_get_mock): - proxmox._import_api() - self.assertEqual(proxmox.api, [{"info": {}}]) - return - - def test__authenticate_success(self): - response = requests.Response() - response.status_code = 200 - response.reason = "OK" - response.raw = io.BytesIO( - b"""{"data":{"CSRFPreventionToken":"01234567:dG9rZW4=","ticket":"PVE:cloud@pve:01234567::dGlja2V0"}}""" - ) - with patch("requests.post", return_value=response): - proxmox._authenticate() - assert proxmox.csrf and proxmox.ticket - return - - def test__authenticate_failure(self): - """ - Confirm that authentication failure raises an exception. - """ - response = requests.Response() - response.status_code = 401 - response.reason = "authentication failure" - response.raw = io.BytesIO(b"""{"data":null}""") - with patch("requests.post", return_value=response): - self.assertRaises(requests.exceptions.HTTPError, proxmox._authenticate) - return - - def test_creation_failure_logging(self): - """ - Test detailed logging on HTTP errors during VM creation. - """ - vm_ = { - "profile": "my_proxmox", - "name": "vm4", - "technology": "lxc", - "host": "127.0.0.1", - "image": "local:some_image.tgz", - "onboot": True, - } - self.assertEqual( - config.is_profile_configured( - proxmox.__opts__, "my_proxmox:proxmox", "my_proxmox", vm_=vm_ - ), - True, - ) - - response = requests.Response() - response.status_code = 400 - response.reason = "Parameter verification failed." - response.raw = io.BytesIO( - b"""{"data":null,"errors":{"onboot":"type check ('boolean') failed - got 'True'"}}""" - ) - - def mock_query_response(conn_type, option, post_data=None): - if conn_type == "get" and option == "cluster/nextid": - return 104 - if conn_type == "post" and option == "nodes/127.0.0.1/lxc": - response.raise_for_status() - return response - return None - - with patch.object( - proxmox, "query", side_effect=mock_query_response - ), patch.object( - proxmox, "_get_properties", return_value=set() - ), TstSuiteLoggingHandler() as log_handler: - self.assertEqual(proxmox.create(vm_), False) - - # Search for these messages in a multi-line log entry. - missing = { - "{} Client Error: {} for url:".format( - response.status_code, response.reason - ), - response.text, - } - for required in list(missing): - for message in log_handler.messages: - if required in message: - missing.remove(required) - break - if missing: - raise AssertionError( - "Did not find error messages: {}".format(sorted(list(missing))) - ) - return diff --git a/tests/unit/cloud/clouds/test_qingcloud.py b/tests/unit/cloud/clouds/test_qingcloud.py deleted file mode 100644 index de7da60951d9..000000000000 --- a/tests/unit/cloud/clouds/test_qingcloud.py +++ /dev/null @@ -1,59 +0,0 @@ -import copy - -from salt.cloud.clouds import qingcloud -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock, patch -from tests.support.unit import TestCase - - -class QingCloudTestCase(TestCase, LoaderModuleMockMixin): - """ - Unit TestCase for salt.cloud.clouds.qingcloud module. - """ - - def setUp(self): - self.provider = { - "providers": { - "qingcloud": { - "qingcloud": { - "access_key_id": "key_1234", - "secret_access_key": "1234", - "zone": "test_zone", - "key_filename": "/testfilename", - "driver": "qingcloud", - } - } - } - } - - def setup_loader_modules(self): - return { - qingcloud: { - "__opts__": { - "providers": {"qingcloud": {}}, - "profiles": {"qingcloud": {}}, - }, - "__active_provider_name__": "qingcloud:qingcloud", - }, - } - - def test_qingcloud_verify_ssl(self): - """ - test qinglcoud when using verify_ssl - """ - patch_sig = patch("salt.cloud.clouds.qingcloud._compute_signature", MagicMock()) - - for verify in [True, False, None]: - mock_requests = MagicMock() - mock_requests.return_value.status_code = 200 - mock_requests.return_value.text = '{"ret_code": 0}' - patch_requests = patch("requests.get", mock_requests) - opts = copy.deepcopy(self.provider) - opts["providers"]["qingcloud"]["qingcloud"]["verify_ssl"] = verify - patch_opts = patch.dict(qingcloud.__opts__, opts) - with patch_sig, patch_requests, patch_opts: - ret = qingcloud.query() - self.assertEqual(ret["ret_code"], 0) - self.assertEqual( - mock_requests.call_args_list[0].kwargs["verify"], verify - ) diff --git a/tests/unit/cloud/clouds/test_saltify.py b/tests/unit/cloud/clouds/test_saltify.py deleted file mode 100644 index 04d11d10f35b..000000000000 --- a/tests/unit/cloud/clouds/test_saltify.py +++ /dev/null @@ -1,224 +0,0 @@ -""" - :codeauthor: Alexander Schwartz -""" - -import salt.client -from salt.cloud.clouds import saltify -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import ANY, MagicMock, patch -from tests.support.unit import TestCase - -TEST_PROFILES = { - "testprofile1": NotImplemented, - "testprofile2": { # this profile is used in test_saltify_destroy() - "ssh_username": "fred", - "remove_config_on_destroy": False, # expected for test - "shutdown_on_destroy": True, # expected value for test - }, - "testprofile3": { # this profile is used in test_create_wake_on_lan() - "wake_on_lan_mac": "aa-bb-cc-dd-ee-ff", - "wol_sender_node": "friend1", - "wol_boot_wait": 0.01, # we want the wait to be very short - }, -} -TEST_PROFILE_NAMES = ["testprofile1", "testprofile2", "testprofile3"] - - -class SaltifyTestCase(TestCase, LoaderModuleMockMixin): - """ - Test cases for salt.cloud.clouds.saltify - """ - - LOCAL_OPTS = { - "providers": { - "sfy1": {"saltify": {"driver": "saltify", "profiles": TEST_PROFILES}}, - }, - "profiles": TEST_PROFILES, - "sock_dir": "/var/sockxxx", - "transport": "tcp", - } - - def setup_loader_modules(self): - saltify_globals = { - "__active_provider_name__": "", - "__utils__": { - "cloud.bootstrap": MagicMock(), - "cloud.fire_event": MagicMock(), - }, - "__opts__": self.LOCAL_OPTS, - } - return {saltify: saltify_globals} - - def test_create_no_deploy(self): - """ - Test if deployment fails. This is the most basic test as saltify doesn't contain much logic - """ - with patch("salt.cloud.clouds.saltify._verify", MagicMock(return_value=True)): - vm = {"deploy": False, "driver": "saltify", "name": "dummy"} - self.assertTrue(saltify.create(vm)) - - def test_create_and_deploy(self): - """ - Test if deployment can be done. - """ - mock_cmd = MagicMock(return_value=True) - with patch.dict( - "salt.cloud.clouds.saltify.__utils__", {"cloud.bootstrap": mock_cmd} - ): - vm_ = { - "deploy": True, - "driver": "saltify", - "name": "new2", - "profile": "testprofile2", - } - result = saltify.create(vm_) - mock_cmd.assert_called_once_with(vm_, ANY) - self.assertTrue(result) - - def test_create_no_ssh_host(self): - """ - Test that ssh_host is set to the vm name if not defined - """ - mock_cmd = MagicMock(return_value=True) - with patch.dict( - "salt.cloud.clouds.saltify.__utils__", {"cloud.bootstrap": mock_cmd} - ): - vm_ = { - "deploy": True, - "driver": "saltify", - "name": "new2", - "profile": "testprofile2", - } - result = saltify.create(vm_) - mock_cmd.assert_called_once_with(vm_, ANY) - assert result - # Make sure that ssh_host was added to the vm. Note that this is - # done in two asserts so that the failure is more explicit about - # what is wrong. If ssh_host wasn't inserted in the vm_ dict, the - # failure would be a KeyError, which would be harder to - # troubleshoot. - assert "ssh_host" in vm_ - assert vm_["ssh_host"] == "new2" - - def test_create_wake_on_lan(self): - """ - Test if wake on lan works - """ - mock_sleep = MagicMock() - mock_cmd = MagicMock(return_value=True) - mm_cmd = MagicMock(return_value={"friend1": True}) - with salt.client.LocalClient() as lcl: - lcl.cmd = mm_cmd - with patch("time.sleep", mock_sleep): - with patch("salt.client.LocalClient", return_value=lcl): - with patch.dict( - "salt.cloud.clouds.saltify.__utils__", - {"cloud.bootstrap": mock_cmd}, - ): - vm_ = { - "deploy": True, - "driver": "saltify", - "name": "new1", - "profile": "testprofile3", - } - result = saltify.create(vm_) - mock_cmd.assert_called_once_with(vm_, ANY) - mm_cmd.assert_called_with( - "friend1", "network.wol", ["aa-bb-cc-dd-ee-ff"] - ) - # The test suite might call time.sleep, look for any call - # that has the expected wait time. - mock_sleep.assert_any_call(0.01) - self.assertTrue(result) - - def test_avail_locations(self): - """ - Test the avail_locations will always return {} - """ - self.assertEqual(saltify.avail_locations(), {}) - - def test_avail_sizes(self): - """ - Test the avail_sizes will always return {} - """ - self.assertEqual(saltify.avail_sizes(), {}) - - def test_avail_images(self): - """ - Test the avail_images will return profiles - """ - testlist = list(TEST_PROFILE_NAMES) # copy - self.assertEqual(saltify.avail_images()["Profiles"].sort(), testlist.sort()) - - def test_list_nodes(self): - """ - Test list_nodes will return required fields only - """ - testgrains = { - "nodeX1": { - "id": "nodeX1", - "ipv4": ["127.0.0.1", "192.1.2.22", "172.16.17.18"], - "ipv6": ["::1", "fdef:bad:add::f00", "3001:DB8::F00D"], - "salt-cloud": { - "driver": "saltify", - "provider": "saltyfy", - "profile": "testprofile2", - }, - "extra_stuff": "does not belong", - } - } - expected_result = { - "nodeX1": { - "id": "nodeX1", - "image": "testprofile2", - "private_ips": ["172.16.17.18", "fdef:bad:add::f00"], - "public_ips": ["192.1.2.22", "3001:DB8::F00D"], - "size": "", - "state": "running", - } - } - mm_cmd = MagicMock(return_value=testgrains) - with salt.client.LocalClient() as lcl: - lcl.cmd = mm_cmd - with patch("salt.client.LocalClient", return_value=lcl): - self.assertEqual(saltify.list_nodes(), expected_result) - - def test_saltify_reboot(self): - mm_cmd = MagicMock(return_value=True) - with salt.client.LocalClient() as lcl: - lcl.cmd = mm_cmd - with patch("salt.client.LocalClient", return_value=lcl): - result = saltify.reboot("nodeS1", "action") - mm_cmd.assert_called_with("nodeS1", "system.reboot") - self.assertTrue(result) - - def test_saltify_destroy(self): - # destroy calls local.cmd several times and expects - # different results, so we will provide a list of - # results. Each call will get the next value. - # NOTE: this assumes that the call order never changes, - # so to keep things simple, we will not use remove_config... - result_list = [ - { - "nodeS1": { # first call is grains.get - "driver": "saltify", - "provider": "saltify", - "profile": "testprofile2", - } - }, - # Note: - # testprofile2 has remove_config_on_destroy: False - # and shutdown_on_destroy: True - { - "nodeS1": ( # last call shuts down the minion - "a system.shutdown worked message" - ) - }, - ] - mm_cmd = MagicMock(side_effect=result_list) - with salt.client.LocalClient() as lcl: - lcl.cmd = mm_cmd - with patch("salt.client.LocalClient", return_value=lcl): - result = saltify.destroy("nodeS1", "action") - mm_cmd.assert_called_with("nodeS1", "system.shutdown") - self.assertTrue(result) diff --git a/tests/unit/cloud/clouds/test_scaleway.py b/tests/unit/cloud/clouds/test_scaleway.py deleted file mode 100644 index 221e309b952d..000000000000 --- a/tests/unit/cloud/clouds/test_scaleway.py +++ /dev/null @@ -1,125 +0,0 @@ -import copy - -import salt.utils.json -from salt.cloud.clouds import scaleway -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock, patch -from tests.support.unit import TestCase - - -class DummyRequest: - def __init__(self, status_code, **response): - self.status_code = status_code - self.response = response - - def __getitem__(self, item): - if item == "status": - return self.status_code - elif item in self.response: - return self.response[item] - raise KeyError(item) - - -class ScalewayTestCase(TestCase, LoaderModuleMockMixin): - """ - Test cases for salt.cloud.clouds.scaleway - """ - - _profile = { - "profile": "my_scaleway", - "name": "foo", - "driver": "scaleway", - "token": "foobarbaz", - } - - def setup_loader_modules(self): - return { - scaleway: { - "__utils__": {}, - "__opts__": { - "providers": {"my_scaleway": {}}, - "profiles": {"my_scaleway": {}}, - }, - } - } - - def test_query(self): - """ - Confirm that using a different root affects the HTTP query made - """ - body = '{"result": "success"}' - server_id = "foo" - expected = salt.utils.json.loads(body) - http_query = MagicMock(return_value=DummyRequest(200, body=body)) - utils_dunder = {"http.query": http_query} - - with patch.dict(scaleway.__utils__, utils_dunder): - - # Case 1: use default api_root - profile = copy.copy(self._profile) - with patch.object(scaleway, "get_configured_provider", lambda: profile): - result = scaleway.query(server_id=server_id) - assert result == expected, result - http_query.assert_called_once_with( - "https://cp-par1.scaleway.com/servers/foo/", - data="{}", - headers={ - "X-Auth-Token": "foobarbaz", - "User-Agent": "salt-cloud", - "Content-Type": "application/json", - }, - method="GET", - ) - - # Case 2: api_root overridden in profile - http_query.reset_mock() - profile = copy.copy(self._profile) - profile["api_root"] = "https://my.api.root" - with patch.object(scaleway, "get_configured_provider", lambda: profile): - result = scaleway.query(server_id=server_id) - assert result == expected, result - http_query.assert_called_once_with( - "https://my.api.root/servers/foo/", - data="{}", - headers={ - "X-Auth-Token": "foobarbaz", - "User-Agent": "salt-cloud", - "Content-Type": "application/json", - }, - method="GET", - ) - - # Case 3: use default alternative root - http_query.reset_mock() - profile = copy.copy(self._profile) - with patch.object(scaleway, "get_configured_provider", lambda: profile): - result = scaleway.query(server_id=server_id, root="alt_root") - assert result == expected, result - http_query.assert_called_once_with( - "https://api-marketplace.scaleway.com/servers/foo/", - data="{}", - headers={ - "X-Auth-Token": "foobarbaz", - "User-Agent": "salt-cloud", - "Content-Type": "application/json", - }, - method="GET", - ) - - # Case 4: use alternative root specified in profile - http_query.reset_mock() - profile = copy.copy(self._profile) - profile["alt_root"] = "https://my.alt.api.root" - with patch.object(scaleway, "get_configured_provider", lambda: profile): - result = scaleway.query(server_id=server_id, root="alt_root") - assert result == expected, result - http_query.assert_called_once_with( - "https://my.alt.api.root/servers/foo/", - data="{}", - headers={ - "X-Auth-Token": "foobarbaz", - "User-Agent": "salt-cloud", - "Content-Type": "application/json", - }, - method="GET", - ) diff --git a/tests/unit/cloud/clouds/test_vmware.py b/tests/unit/cloud/clouds/test_vmware.py deleted file mode 100644 index baf517d796aa..000000000000 --- a/tests/unit/cloud/clouds/test_vmware.py +++ /dev/null @@ -1,1278 +0,0 @@ -""" - :codeauthor: `Nitin Madhok ` - - tests.unit.cloud.clouds.vmware_test - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -""" - -import copy - -from salt import config -from salt.cloud.clouds import vmware -from salt.exceptions import SaltCloudSystemExit -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock, Mock, patch -from tests.support.unit import TestCase, skipIf - -# Attempt to import pyVim and pyVmomi libs -HAS_LIBS = True -# pylint: disable=import-error,no-name-in-module,unused-import -try: - from pyVim.connect import Disconnect, SmartConnect - from pyVmomi import vim, vmodl -except ImportError: - HAS_LIBS = False -# pylint: enable=import-error,no-name-in-module,unused-import - -# Global Variables -PROVIDER_CONFIG = { - "vcenter01": { - "vmware": { - "driver": "vmware", - "url": "vcenter01.domain.com", - "user": "DOMAIN\\user", - "password": "verybadpass", - } - } -} -VM_NAME = "test-vm" -PROFILE = { - "base-gold": { - "provider": "vcenter01:vmware", - "datastore": "Datastore1", - "resourcepool": "Resources", - "folder": "vm", - } -} - - -class ExtendedTestCase(TestCase, LoaderModuleMockMixin): - """ - Extended TestCase class containing additional helper methods. - """ - - def setup_loader_modules(self): - return {vmware: {"__active_provider_name__": ""}} - - def assertRaisesWithMessage(self, exc_type, exc_msg, func, *args, **kwargs): - try: - func(*args, **kwargs) - self.assertFail() - except Exception as exc: # pylint: disable=broad-except - self.assertEqual(type(exc), exc_type) - self.assertEqual(exc.message, exc_msg) - - -@skipIf(not HAS_LIBS, "Install pyVmomi to be able to run this test.") -class VMwareTestCase(ExtendedTestCase): - """ - Unit TestCase for salt.cloud.clouds.vmware module. - """ - - def test_test_vcenter_connection_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call test_vcenter_connection - with anything other than --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.test_vcenter_connection, call="action" - ) - - def test_get_vcenter_version_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call get_vcenter_version - with anything other than --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.get_vcenter_version, call="action" - ) - - def test_avail_images_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call avail_images - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, vmware.avail_images, call="action") - - def test_avail_locations_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call avail_locations - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, vmware.avail_locations, call="action") - - def test_avail_sizes_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call avail_sizes - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, vmware.avail_sizes, call="action") - - def test_list_datacenters_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_datacenters - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_datacenters, call="action") - - def test_list_clusters_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_clusters - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_clusters, call="action") - - def test_list_datastore_clusters_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_datastore_clusters - with anything other than --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.list_datastore_clusters, call="action" - ) - - def test_list_datastores_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_datastores - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_datastores, call="action") - - def test_list_hosts_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_hosts - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_hosts, call="action") - - def test_list_resourcepools_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_resourcepools - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_resourcepools, call="action") - - def test_list_networks_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_networks - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_networks, call="action") - - def test_list_nodes_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_nodes - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_nodes, call="action") - - def test_list_nodes_min_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_min - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_nodes_min, call="action") - - def test_list_nodes_full_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_full - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_nodes_full, call="action") - - def test_list_nodes_select_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_full - with --action or -a. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_nodes_select, call="action") - - def test_list_folders_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_folders - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_folders, call="action") - - def test_list_snapshots_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_snapshots - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_snapshots, call="action") - - def test_list_hosts_by_cluster_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_hosts_by_cluster - with anything other than --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.list_hosts_by_cluster, call="action" - ) - - def test_list_clusters_by_datacenter_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_clusters_by_datacenter - with anything other than --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.list_clusters_by_datacenter, call="action" - ) - - def test_list_hosts_by_datacenter_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_hosts_by_datacenter - with anything other than --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.list_hosts_by_datacenter, call="action" - ) - - def test_list_hbas_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_hbas - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_hbas, call="action") - - def test_list_dvs_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_dvs - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_dvs, call="action") - - def test_list_vapps_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_vapps - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_vapps, call="action") - - def test_list_templates_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call list_templates - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.list_templates, call="action") - - def test_create_datacenter_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call create_datacenter - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.create_datacenter, call="action") - - def test_create_cluster_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call create_cluster - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.create_cluster, call="action") - - def test_rescan_hba_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call rescan_hba - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.rescan_hba, call="action") - - def test_upgrade_tools_all_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call upgrade_tools_all - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.upgrade_tools_all, call="action") - - def test_enter_maintenance_mode_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call enter_maintenance_mode - with anything other than --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.enter_maintenance_mode, call="action" - ) - - def test_exit_maintenance_mode_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call exit_maintenance_mode - with anything other than --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.exit_maintenance_mode, call="action" - ) - - def test_create_folder_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call create_folder - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.create_folder, call="action") - - def test_add_host_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call add_host - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.add_host, call="action") - - def test_remove_host_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call remove_host - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.remove_host, call="action") - - def test_connect_host_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call connect_host - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.connect_host, call="action") - - def test_disconnect_host_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call disconnect_host - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.disconnect_host, call="action") - - def test_reboot_host_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call reboot_host - with anything other than --function or -f. - """ - self.assertRaises(SaltCloudSystemExit, vmware.reboot_host, call="action") - - def test_create_datastore_cluster_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call create_datastore_cluster - with anything other than --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.create_datastore_cluster, call="action" - ) - - def test_show_instance_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call show_instance - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.show_instance, name=VM_NAME, call="function" - ) - - def test_start_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call start - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.start, name=VM_NAME, call="function" - ) - - def test_stop_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call stop - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.stop, name=VM_NAME, call="function" - ) - - def test_suspend_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call suspend - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.suspend, name=VM_NAME, call="function" - ) - - def test_reset_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call reset - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.reset, name=VM_NAME, call="function" - ) - - def test_terminate_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call terminate - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.terminate, name=VM_NAME, call="function" - ) - - def test_destroy_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call destroy - with --function or -f. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.destroy, name=VM_NAME, call="function" - ) - - def test_shutdown_host_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call convert_to_template - with anything other than --action or -a. - """ - with patch.object(vmware, "_get_si", Mock()), patch( - "salt.utils.vmware.get_mor_by_property", Mock() - ): - self.assertRaises( - SaltCloudSystemExit, - vmware.shutdown_host, - kwargs={"host": VM_NAME}, - call="action", - ) - - def test_upgrade_tools_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call upgrade_tools - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.upgrade_tools, name=VM_NAME, call="function" - ) - - def test_create_snapshot_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call create_snapshot - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.create_snapshot, name=VM_NAME, call="function" - ) - - def test_revert_to_snapshot_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call revert_to_snapshot - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.revert_to_snapshot, - name=VM_NAME, - call="function", - ) - - def test_remove_snapshot_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call remove_snapshot - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.remove_snapshot, - name=VM_NAME, - kwargs={"snapshot_name": "mySnapshot"}, - call="function", - ) - - def test_remove_snapshot_call_no_snapshot_name_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when name is not present in kwargs. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.remove_snapshot, name=VM_NAME, call="action" - ) - - def test_remove_all_snapshots_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call remove_all_snapshots - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.remove_all_snapshots, - name=VM_NAME, - call="function", - ) - - def test_convert_to_template_call(self): - """ - Tests that a SaltCloudSystemExit is raised when trying to call convert_to_template - with anything other than --action or -a. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.convert_to_template, - name=VM_NAME, - call="function", - ) - - def test_avail_sizes(self): - """ - Tests that avail_sizes returns an empty dictionary. - """ - self.assertEqual(vmware.avail_sizes(call="foo"), {}) - - def test_create_datacenter_no_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when no kwargs are provided to - create_datacenter. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.create_datacenter, kwargs=None, call="function" - ) - - def test_create_datacenter_no_name_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when name is not present in - kwargs that are provided to create_datacenter. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_datacenter, - kwargs={"foo": "bar"}, - call="function", - ) - - def test_create_datacenter_name_too_short(self): - """ - Tests that a SaltCloudSystemExit is raised when name is present in kwargs - that are provided to create_datacenter but is an empty string. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_datacenter, - kwargs={"name": ""}, - call="function", - ) - - def test_create_datacenter_name_too_long(self): - """ - Tests that a SaltCloudSystemExit is raised when name is present in kwargs - that are provided to create_datacenter but is a string with length <= 80. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_datacenter, - kwargs={ - "name": "cCD2GgJGPG1DUnPeFBoPeqtdmUxIWxDoVFbA14vIG0BPoUECkgbRMnnY6gaUPBvIDCcsZ5HU48ubgQu5c" - }, - call="function", - ) - - def test_create_cluster_no_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when no kwargs are provided to - create_cluster. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.create_cluster, kwargs=None, call="function" - ) - - def test_create_cluster_no_name_no_datacenter_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when neither the name nor the - datacenter is present in kwargs that are provided to create_cluster. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_cluster, - kwargs={"foo": "bar"}, - call="function", - ) - - def test_create_cluster_no_datacenter_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when the name is present but the - datacenter is not present in kwargs that are provided to create_cluster. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_cluster, - kwargs={"name": "my-cluster"}, - call="function", - ) - - def test_create_cluster_no_name_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when the datacenter is present - but the name is not present in kwargs that are provided to create_cluster. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_cluster, - kwargs={"datacenter": "my-datacenter"}, - call="function", - ) - - def test_rescan_hba_no_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when no kwargs are provided to - rescan_hba. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.rescan_hba, kwargs=None, call="function" - ) - - def test_rescan_hba_no_host_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when host is not present in - kwargs that are provided to rescan_hba. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.rescan_hba, - kwargs={"foo": "bar"}, - call="function", - ) - - def test_create_snapshot_no_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when no kwargs are provided to - create_snapshot. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_snapshot, - name=VM_NAME, - kwargs=None, - call="action", - ) - - def test_create_snapshot_no_snapshot_name_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when snapshot_name is not present - in kwargs that are provided to create_snapshot. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_snapshot, - name=VM_NAME, - kwargs={"foo": "bar"}, - call="action", - ) - - def test_add_host_no_esxi_host_user_in_config(self): - """ - Tests that a SaltCloudSystemExit is raised when esxi_host_user is not - specified in the cloud provider configuration when calling add_host. - """ - with patch.dict(vmware.__opts__, {"providers": PROVIDER_CONFIG}, clean=True): - self.assertRaisesWithMessage( - SaltCloudSystemExit, - "You must specify the ESXi host username in your providers config.", - vmware.add_host, - kwargs=None, - call="function", - ) - - def test_add_host_no_esxi_host_password_in_config(self): - """ - Tests that a SaltCloudSystemExit is raised when esxi_host_password is not - specified in the cloud provider configuration when calling add_host. - """ - provider_config_additions = { - "esxi_host_user": "root", - } - - provider_config = copy.deepcopy(PROVIDER_CONFIG) - provider_config["vcenter01"]["vmware"].update(provider_config_additions) - - with patch.dict(vmware.__opts__, {"providers": provider_config}, clean=True): - self.assertRaisesWithMessage( - SaltCloudSystemExit, - "You must specify the ESXi host password in your providers config.", - vmware.add_host, - kwargs=None, - call="function", - ) - - def test_no_clonefrom_just_image(self): - """ - Tests that the profile is configured correctly when deploying using an image - """ - - profile_additions = {"image": "some-image.iso"} - - provider_config = copy.deepcopy(PROVIDER_CONFIG) - profile = copy.deepcopy(PROFILE) - profile["base-gold"].update(profile_additions) - - provider_config_additions = {"profiles": profile} - provider_config["vcenter01"]["vmware"].update(provider_config_additions) - vm_ = {"profile": profile} - with patch.dict(vmware.__opts__, {"providers": provider_config}, clean=True): - self.assertEqual( - config.is_profile_configured( - vmware.__opts__, "vcenter01:vmware", "base-gold", vm_=vm_ - ), - True, - ) - - def test_just_clonefrom(self): - """ - Tests that the profile is configured correctly when deploying by cloning from a template - """ - - profile_additions = { - "clonefrom": "test-template", - "image": "should ignore image", - } - - provider_config = copy.deepcopy(PROVIDER_CONFIG) - profile = copy.deepcopy(PROFILE) - profile["base-gold"].update(profile_additions) - - provider_config_additions = {"profiles": profile} - provider_config["vcenter01"]["vmware"].update(provider_config_additions) - vm_ = {"profile": profile} - with patch.dict(vmware.__opts__, {"providers": provider_config}, clean=True): - self.assertEqual( - config.is_profile_configured( - vmware.__opts__, "vcenter01:vmware", "base-gold", vm_=vm_ - ), - True, - ) - - def test_just_Instantclonefrom(self): - """ - Tests that the profile is configured correctly when deploying by instant cloning from a running VM - """ - - profile_additions = { - "clonefrom": VM_NAME, - "instant_clone": True, - } - - provider_config = copy.deepcopy(PROVIDER_CONFIG) - profile = copy.deepcopy(PROFILE) - profile["base-gold"].update(profile_additions) - - provider_config_additions = {"profiles": profile} - provider_config["vcenter01"]["vmware"].update(provider_config_additions) - vm_ = {"profile": profile} - with patch.dict(vmware.__opts__, {"providers": provider_config}, clean=True): - self.assertEqual( - config.is_profile_configured( - vmware.__opts__, "vcenter01:vmware", "base-gold", vm_=vm_ - ), - True, - ) - - def test_add_new_ide_controller_helper(self): - """ - Tests that creating a new controller, ensuring that it will generate a controller key - if one is not provided - """ - with patch( - "salt.cloud.clouds.vmware.randint", return_value=101 - ) as randint_mock: - controller_label = "Some label" - bus_number = 1 - spec = vmware._add_new_ide_controller_helper( - controller_label, None, bus_number - ) - self.assertEqual(spec.device.key, randint_mock.return_value) - - spec = vmware._add_new_ide_controller_helper( - controller_label, 200, bus_number - ) - self.assertEqual(spec.device.key, 200) - - self.assertEqual(spec.device.busNumber, bus_number) - self.assertEqual(spec.device.deviceInfo.label, controller_label) - self.assertEqual(spec.device.deviceInfo.summary, controller_label) - - def test_manage_devices_just_cd(self): - """ - Tests that when adding IDE/CD drives, controller keys will be in the apparent - safe-range on ESX 5.5 but randomly generated on other versions (i.e. 6) - """ - device_map = { - "ide": {"IDE 0": {}, "IDE 1": {}}, - "cd": {"CD/DVD Drive 1": {"controller": "IDE 0"}}, - } - with patch( - "salt.cloud.clouds.vmware.get_vcenter_version", - return_value="VMware ESXi 5.5.0", - ): - specs = vmware._manage_devices(device_map, vm=None)["device_specs"] - - self.assertEqual( - specs[0].device.key, vmware.SAFE_ESX_5_5_CONTROLLER_KEY_INDEX - ) - self.assertEqual( - specs[1].device.key, vmware.SAFE_ESX_5_5_CONTROLLER_KEY_INDEX + 1 - ) - self.assertEqual( - specs[2].device.controllerKey, vmware.SAFE_ESX_5_5_CONTROLLER_KEY_INDEX - ) - - with patch( - "salt.cloud.clouds.vmware.get_vcenter_version", return_value="VMware ESXi 6" - ): - with patch( - "salt.cloud.clouds.vmware.randint", return_value=100 - ) as first_key: - specs = vmware._manage_devices(device_map, vm=None)["device_specs"] - - self.assertEqual(specs[0].device.key, first_key.return_value) - self.assertEqual(specs[2].device.controllerKey, first_key.return_value) - - def test_add_host_no_host_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when host is not present in - kwargs that are provided to add_host. - """ - provider_config_additions = { - "esxi_host_user": "root", - "esxi_host_password": "myhostpassword", - } - - provider_config = copy.deepcopy(PROVIDER_CONFIG) - provider_config["vcenter01"]["vmware"].update(provider_config_additions) - - with patch.dict(vmware.__opts__, {"providers": provider_config}, clean=True): - self.assertRaisesWithMessage( - SaltCloudSystemExit, - "You must specify either the IP or DNS name of the host system.", - vmware.add_host, - kwargs={"foo": "bar"}, - call="function", - ) - - def test_add_host_both_cluster_and_datacenter_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when both cluster and datacenter - are present in kwargs that are provided to add_host. - """ - provider_config_additions = { - "esxi_host_user": "root", - "esxi_host_password": "myhostpassword", - } - - provider_config = copy.deepcopy(PROVIDER_CONFIG) - provider_config["vcenter01"]["vmware"].update(provider_config_additions) - - with patch.dict(vmware.__opts__, {"providers": provider_config}, clean=True): - self.assertRaisesWithMessage( - SaltCloudSystemExit, - "You must specify either the cluster name or the datacenter name.", - vmware.add_host, - kwargs={ - "host": "my-esxi-host", - "datacenter": "my-datacenter", - "cluster": "my-cluster", - }, - call="function", - ) - - def test_add_host_neither_cluster_nor_datacenter_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when neither cluster nor - datacenter is present in kwargs that are provided to add_host. - """ - provider_config_additions = { - "esxi_host_user": "root", - "esxi_host_password": "myhostpassword", - } - - provider_config = copy.deepcopy(PROVIDER_CONFIG) - provider_config["vcenter01"]["vmware"].update(provider_config_additions) - - with patch.dict(vmware.__opts__, {"providers": provider_config}, clean=True): - self.assertRaisesWithMessage( - SaltCloudSystemExit, - "You must specify either the cluster name or the datacenter name.", - vmware.add_host, - kwargs={"host": "my-esxi-host"}, - call="function", - ) - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_add_host_cluster_not_exists(self): - """ - Tests that a SaltCloudSystemExit is raised when the specified cluster present - in kwargs that are provided to add_host does not exist in the VMware - environment. - """ - with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): - with patch( - "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) - ): - provider_config_additions = { - "esxi_host_user": "root", - "esxi_host_password": "myhostpassword", - } - - provider_config = copy.deepcopy(PROVIDER_CONFIG) - provider_config["vcenter01"]["vmware"].update(provider_config_additions) - - with patch.dict( - vmware.__opts__, {"providers": provider_config}, clean=True - ): - self.assertRaisesWithMessage( - SaltCloudSystemExit, - "Specified cluster does not exist.", - vmware.add_host, - kwargs={"host": "my-esxi-host", "cluster": "my-cluster"}, - call="function", - ) - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_add_host_datacenter_not_exists(self): - """ - Tests that a SaltCloudSystemExit is raised when the specified datacenter - present in kwargs that are provided to add_host does not exist in the VMware - environment. - """ - with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): - with patch( - "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) - ): - provider_config_additions = { - "esxi_host_user": "root", - "esxi_host_password": "myhostpassword", - } - - provider_config = copy.deepcopy(PROVIDER_CONFIG) - provider_config["vcenter01"]["vmware"].update(provider_config_additions) - - with patch.dict( - vmware.__opts__, {"providers": provider_config}, clean=True - ): - self.assertRaisesWithMessage( - SaltCloudSystemExit, - "Specified datacenter does not exist.", - vmware.add_host, - kwargs={"host": "my-esxi-host", "datacenter": "my-datacenter"}, - call="function", - ) - - def test_remove_host_no_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when no kwargs are provided to - remove_host. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.remove_host, kwargs=None, call="function" - ) - - def test_remove_host_no_host_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when host is not present in - kwargs that are provided to remove_host. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.remove_host, - kwargs={"foo": "bar"}, - call="function", - ) - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_remove_host_not_exists(self): - """ - Tests that a SaltCloudSystemExit is raised when the specified host present - in kwargs that are provided to remove_host does not exist in the VMware - environment. - """ - with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): - with patch( - "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) - ): - self.assertRaises( - SaltCloudSystemExit, - vmware.remove_host, - kwargs={"host": "my-host"}, - call="function", - ) - - def test_connect_host_no_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when no kwargs are provided to - connect_host. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.connect_host, kwargs=None, call="function" - ) - - def test_connect_host_no_host_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when host is not present in - kwargs that are provided to connect_host. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.connect_host, - kwargs={"foo": "bar"}, - call="function", - ) - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_connect_host_not_exists(self): - """ - Tests that a SaltCloudSystemExit is raised when the specified host present - in kwargs that are provided to connect_host does not exist in the VMware - environment. - """ - with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): - with patch( - "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) - ): - self.assertRaises( - SaltCloudSystemExit, - vmware.connect_host, - kwargs={"host": "my-host"}, - call="function", - ) - - def test_disconnect_host_no_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when no kwargs are provided to - disconnect_host. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.disconnect_host, kwargs=None, call="function" - ) - - def test_disconnect_host_no_host_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when host is not present in - kwargs that are provided to disconnect_host. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.disconnect_host, - kwargs={"foo": "bar"}, - call="function", - ) - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_disconnect_host_not_exists(self): - """ - Tests that a SaltCloudSystemExit is raised when the specified host present - in kwargs that are provided to disconnect_host does not exist in the VMware - environment. - """ - with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): - with patch( - "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) - ): - self.assertRaises( - SaltCloudSystemExit, - vmware.disconnect_host, - kwargs={"host": "my-host"}, - call="function", - ) - - def test_reboot_host_no_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when no kwargs are provided to - reboot_host. - """ - self.assertRaises( - SaltCloudSystemExit, vmware.reboot_host, kwargs=None, call="function" - ) - - def test_reboot_host_no_host_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when host is not present in - kwargs that are provided to reboot_host. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.reboot_host, - kwargs={"foo": "bar"}, - call="function", - ) - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_reboot_host_not_exists(self): - """ - Tests that a SaltCloudSystemExit is raised when the specified host present - in kwargs that are provided to connect_host does not exist in the VMware - environment. - """ - with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): - with patch( - "salt.utils.vmware.get_mor_by_property", MagicMock(return_value=None) - ): - self.assertRaises( - SaltCloudSystemExit, - vmware.reboot_host, - kwargs={"host": "my-host"}, - call="function", - ) - - def test_create_datastore_cluster_no_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when no kwargs are provided to - create_datastore_cluster. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_datastore_cluster, - kwargs=None, - call="function", - ) - - def test_create_datastore_cluster_no_name_in_kwargs(self): - """ - Tests that a SaltCloudSystemExit is raised when name is not present in - kwargs that are provided to create_datastore_cluster. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_datastore_cluster, - kwargs={"foo": "bar"}, - call="function", - ) - - def test_create_datastore_cluster_name_too_short(self): - """ - Tests that a SaltCloudSystemExit is raised when name is present in kwargs - that are provided to create_datastore_cluster but is an empty string. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_datastore_cluster, - kwargs={"name": ""}, - call="function", - ) - - def test_create_datastore_cluster_name_too_long(self): - """ - Tests that a SaltCloudSystemExit is raised when name is present in kwargs - that are provided to create_datastore_cluster but is a string with length <= 80. - """ - self.assertRaises( - SaltCloudSystemExit, - vmware.create_datastore_cluster, - kwargs={ - "name": "cCD2GgJGPG1DUnPeFBoPeqtdmUxIWxDoVFbA14vIG0BPoUECkgbRMnnY6gaUPBvIDCcsZ5HU48ubgQu5c" - }, - call="function", - ) - - def test__add_new_hard_disk_helper(self): - with patch("salt.cloud.clouds.vmware._get_si", MagicMock(return_value=None)): - with patch( - "salt.utils.vmware.get_mor_using_container_view", - side_effect=[None, None], - ): - self.assertRaises( - SaltCloudSystemExit, - vmware._add_new_hard_disk_helper, - disk_label="test", - size_gb=100, - unit_number=0, - datastore="whatever", - ) - with patch( - "salt.utils.vmware.get_mor_using_container_view", - side_effect=["Datastore", None], - ): - self.assertRaises( - AttributeError, - vmware._add_new_hard_disk_helper, - disk_label="test", - size_gb=100, - unit_number=0, - datastore="whatever", - ) - vmware.salt.utils.vmware.get_mor_using_container_view.assert_called_with( - None, vim.Datastore, "whatever" - ) - with patch( - "salt.utils.vmware.get_mor_using_container_view", - side_effect=[None, "Cluster"], - ): - self.assertRaises( - AttributeError, - vmware._add_new_hard_disk_helper, - disk_label="test", - size_gb=100, - unit_number=0, - datastore="whatever", - ) - vmware.salt.utils.vmware.get_mor_using_container_view.assert_called_with( - None, vim.StoragePod, "whatever" - ) - - -class CloneFromSnapshotTest(TestCase): - """ - Test functionality to clone from snapshot - """ - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_quick_linked_clone(self): - """ - Test that disk move type is - set to createNewChildDiskBacking - """ - self._test_clone_type(vmware.QUICK_LINKED_CLONE) - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_current_state_linked_clone(self): - """ - Test that disk move type is - set to moveChildMostDiskBacking - """ - self._test_clone_type(vmware.CURRENT_STATE_LINKED_CLONE) - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_copy_all_disks_full_clone(self): - """ - Test that disk move type is - set to moveAllDiskBackingsAndAllowSharing - """ - self._test_clone_type(vmware.COPY_ALL_DISKS_FULL_CLONE) - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_flatten_all_all_disks_full_clone(self): - """ - Test that disk move type is - set to moveAllDiskBackingsAndDisallowSharing - """ - self._test_clone_type(vmware.FLATTEN_DISK_FULL_CLONE) - - @skipIf(HAS_LIBS is False, "Install pyVmomi to be able to run this unit test.") - def test_raises_error_for_invalid_disk_move_type(self): - """ - Test that invalid disk move type - raises error - """ - with self.assertRaises(SaltCloudSystemExit): - self._test_clone_type("foobar") - - def _test_clone_type(self, clone_type): - """ - Assertions for checking that a certain clone type - works - """ - obj_ref = MagicMock() - obj_ref.snapshot = vim.vm.Snapshot(None, None) - obj_ref.snapshot.currentSnapshot = vim.vm.Snapshot(None, None) - clone_spec = vmware.handle_snapshot( - vim.vm.ConfigSpec(), - obj_ref, - vim.vm.RelocateSpec(), - False, - {"snapshot": {"disk_move_type": clone_type}}, - ) - self.assertEqual(clone_spec.location.diskMoveType, clone_type) - - obj_ref2 = MagicMock() - obj_ref2.snapshot = vim.vm.Snapshot(None, None) - obj_ref2.snapshot.currentSnapshot = vim.vm.Snapshot(None, None) - - clone_spec2 = vmware.handle_snapshot( - vim.vm.ConfigSpec(), - obj_ref2, - vim.vm.RelocateSpec(), - True, - {"snapshot": {"disk_move_type": clone_type}}, - ) - - self.assertEqual(clone_spec2.location.diskMoveType, clone_type) diff --git a/tests/unit/cloud/clouds/test_vultrpy.py b/tests/unit/cloud/clouds/test_vultrpy.py deleted file mode 100644 index 5ef0808c43ba..000000000000 --- a/tests/unit/cloud/clouds/test_vultrpy.py +++ /dev/null @@ -1,201 +0,0 @@ -from salt.cloud.clouds import vultrpy as vultr -from tests.support.helpers import TstSuiteLoggingHandler -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock, patch -from tests.support.unit import TestCase - - -class VultrTestCase(TestCase, LoaderModuleMockMixin): - """ - Unit TestCase for salt.cloud.clouds.vultr module. - """ - - def setup_loader_modules(self): - provider_info = { - "vultr01": {"vultr": {"api_key": "super_secret_key", "driver": "vultr"}} - } - - opts = {"providers": provider_info} - - return { - vultr: { - "__utils__": { - "cloud.fire_event": MagicMock(), - "cloud.filter_event": MagicMock(), - "cloud.wait_for_fun": MagicMock(), - "cloud.bootstrap": MagicMock(), - }, - "__opts__": { - "providers": provider_info, - "sock_dir": "/tmp/sock_dir", - "transport": "tcp", - }, - "__active_provider_name__": "my_vultr:vultr", - } - } - - def test_show_keypair_no_keyname(self): - """ - test salt.cloud.clouds.vultr.show_keypair - when keyname is not in kwargs - """ - kwargs = {} - with TstSuiteLoggingHandler() as handler: - assert not vultr.show_keypair(kwargs) - assert "ERROR:A keyname is required." in handler.messages - - @patch("salt.cloud.clouds.vultrpy._query") - def test_show_keypair(self, _query): - """ - test salt.cloud.clouds.vultr.show_keypair - when keyname provided - """ - _query.return_value = {"test": {"SSHKEYID": "keyID"}} - kwargs = {"keyname": "test"} - assert vultr.show_keypair(kwargs) == {"SSHKEYID": "keyID"} - - def test_create_firewall_ssh(self): - """ - Test create when setting firewall_group_id and - ssh_key_names. - """ - kwargs = { - "provider": "vultr", - "enable_private_network": True, - "ssh_key_names": "key1,key2,key3", - "startup_script_id": "test_id", - "firewall_group_id": "f_id", - "image": 223, - "size": 13, - "location": 1, - "name": "test-vm", - } - patch_scripts = patch( - "salt.cloud.clouds.vultrpy.avail_scripts", - MagicMock(return_value=["test_id"]), - ) - - patch_firewall = patch( - "salt.cloud.clouds.vultrpy.avail_firewall_groups", - MagicMock(return_value=["f_id"]), - ) - - patch_keys = patch( - "salt.cloud.clouds.vultrpy.avail_keys", - MagicMock(return_value=["key3", "key2", "key1"]), - ) - - patch_vultrid = patch( - "salt.cloud.clouds.vultrpy._lookup_vultrid", - MagicMock(return_value="test_id"), - ) - - mock_query = MagicMock(return_value={"status": 200}) - patch_query = patch("salt.cloud.clouds.vultrpy._query", mock_query) - - patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) - - with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: - vultr.create(kwargs) - query_ret = mock_query.call_args.kwargs["data"] - self.assertIn("SSHKEYID=key1%2Ckey2%2Ckey3", query_ret) - self.assertIn("FIREWALLGROUPID=f_id", query_ret) - - def test_create_firewall_doesnotexist(self): - """ - Test create when setting firewall_group_id to a firewall - that does not exist - """ - kwargs = { - "provider": "vultr", - "enable_private_network": True, - "startup_script_id": "test_id", - "firewall_group_id": "doesnotexist", - "image": 223, - "size": 13, - "location": 1, - "name": "test-vm", - } - patch_scripts = patch( - "salt.cloud.clouds.vultrpy.avail_scripts", - MagicMock(return_value=["test_id"]), - ) - - patch_firewall = patch( - "salt.cloud.clouds.vultrpy.avail_firewall_groups", - MagicMock(return_value=["f_id"]), - ) - - patch_keys = patch( - "salt.cloud.clouds.vultrpy.avail_keys", - MagicMock(return_value=["key3", "key2", "key1"]), - ) - - patch_vultrid = patch( - "salt.cloud.clouds.vultrpy._lookup_vultrid", - MagicMock(return_value="test_id"), - ) - - mock_query = MagicMock(return_value={"status": 200}) - patch_query = patch("salt.cloud.clouds.vultrpy._query", mock_query) - - patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) - - with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: - with TstSuiteLoggingHandler() as handler: - ret = vultr.create(kwargs) - self.assertIn( - "ERROR:Your Vultr account does not have a firewall group with ID" - " doesnotexist", - handler.messages, - ) - self.assertFalse(ret) - - def test_create_ssh_key_ids_doesnotexist(self): - """ - Test create when setting ssh_key_ids that do not - exist - """ - kwargs = { - "provider": "vultr", - "enable_private_network": True, - "startup_script_id": "test_id", - "ssh_key_names": "doesnotexist", - "image": 223, - "size": 13, - "location": 1, - "name": "test-vm", - } - patch_scripts = patch( - "salt.cloud.clouds.vultrpy.avail_scripts", - MagicMock(return_value=["test_id"]), - ) - - patch_firewall = patch( - "salt.cloud.clouds.vultrpy.avail_firewall_groups", - MagicMock(return_value=["f_id"]), - ) - - patch_keys = patch( - "salt.cloud.clouds.vultrpy.avail_keys", - MagicMock(return_value=["key3", "key2", "key1"]), - ) - - patch_vultrid = patch( - "salt.cloud.clouds.vultrpy._lookup_vultrid", - MagicMock(return_value="test_id"), - ) - - mock_query = MagicMock(return_value={"status": 200}) - patch_query = patch("salt.cloud.clouds.vultrpy._query", mock_query) - - patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) - - with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: - with TstSuiteLoggingHandler() as handler: - ret = vultr.create(kwargs) - self.assertIn( - "ERROR:Your Vultr account does not have a key with ID doesnotexist", - handler.messages, - ) - self.assertFalse(ret)