test_proxmox.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. """
  2. :codeauthor: Tyler Johnson <tjohnson@saltstack.com>
  3. """
  4. # Import Salt Libs
  5. # Import Salt Libs
  6. from salt.cloud.clouds import proxmox
  7. # Import Salt Testing Libs
  8. from tests.support.mixins import LoaderModuleMockMixin
  9. from tests.support.mock import ANY, MagicMock, patch
  10. from tests.support.unit import TestCase
  11. class ProxmoxTest(TestCase, LoaderModuleMockMixin):
  12. def setup_loader_modules(self):
  13. return {
  14. proxmox: {
  15. "__utils__": {
  16. "cloud.fire_event": MagicMock(),
  17. "cloud.filter_event": MagicMock(),
  18. "cloud.bootstrap": MagicMock(),
  19. },
  20. "__opts__": {
  21. "sock_dir": True,
  22. "transport": True,
  23. "providers": {"my_proxmox": {}},
  24. "profiles": {"my_proxmox": {}},
  25. },
  26. "__active_provider_name__": "my_proxmox:proxmox",
  27. }
  28. }
  29. def setUp(self):
  30. self.vm_ = {
  31. "profile": "my_proxmox",
  32. "name": "vm4",
  33. "driver": "proxmox",
  34. "technology": "qemu",
  35. "host": "127.0.0.1",
  36. "clone": True,
  37. "ide0": "data",
  38. "sata0": "data",
  39. "scsi0": "data",
  40. "net0": "a=b,c=d",
  41. }
  42. def tearDown(self):
  43. del self.vm_
  44. def test__stringlist_to_dictionary(self):
  45. result = proxmox._stringlist_to_dictionary("")
  46. self.assertEqual(result, {})
  47. result = proxmox._stringlist_to_dictionary(
  48. "foo=bar, ignored_space=bar,internal space=bar"
  49. )
  50. self.assertEqual(
  51. result, {"foo": "bar", "ignored_space": "bar", "internal space": "bar"}
  52. )
  53. # Negative cases
  54. self.assertRaises(ValueError, proxmox._stringlist_to_dictionary, "foo=bar,foo")
  55. self.assertRaises(
  56. ValueError,
  57. proxmox._stringlist_to_dictionary,
  58. "foo=bar,totally=invalid=assignment",
  59. )
  60. def test__dictionary_to_stringlist(self):
  61. result = proxmox._dictionary_to_stringlist({})
  62. self.assertEqual(result, "")
  63. result = proxmox._dictionary_to_stringlist({"a": "a"})
  64. self.assertEqual(result, "a=a")
  65. result = proxmox._dictionary_to_stringlist({"a": "a", "b": "b"})
  66. self.assertEqual(result, "a=a,b=b")
  67. def test__reconfigure_clone(self):
  68. # The return_value is for the net reconfigure assertions, it is irrelevant for the rest
  69. with patch.object(
  70. proxmox, "query", return_value={"net0": "c=overwritten,g=h"}
  71. ) as query:
  72. # Test a vm that lacks the required attributes
  73. proxmox._reconfigure_clone({}, 0)
  74. query.assert_not_called()
  75. # Test a fully mocked vm
  76. proxmox._reconfigure_clone(self.vm_, 0)
  77. # net reconfigure
  78. query.assert_any_call("get", "nodes/127.0.0.1/qemu/0/config")
  79. query.assert_any_call(
  80. "post", "nodes/127.0.0.1/qemu/0/config", {"net0": "a=b,c=d,g=h"}
  81. )
  82. # hdd reconfigure
  83. query.assert_any_call(
  84. "post", "nodes/127.0.0.1/qemu/0/config", {"ide0": "data"}
  85. )
  86. query.assert_any_call(
  87. "post", "nodes/127.0.0.1/qemu/0/config", {"sata0": "data"}
  88. )
  89. query.assert_any_call(
  90. "post", "nodes/127.0.0.1/qemu/0/config", {"scsi0": "data"}
  91. )
  92. def test_clone(self):
  93. """
  94. Test that an integer value for clone_from
  95. """
  96. mock_query = MagicMock(return_value="")
  97. with patch(
  98. "salt.cloud.clouds.proxmox._get_properties", MagicMock(return_value=[])
  99. ), patch("salt.cloud.clouds.proxmox.query", mock_query):
  100. vm_ = {
  101. "technology": "qemu",
  102. "name": "new2",
  103. "host": "myhost",
  104. "clone": True,
  105. "clone_from": 123,
  106. }
  107. # CASE 1: Numeric ID
  108. result = proxmox.create_node(vm_, ANY)
  109. mock_query.assert_called_once_with(
  110. "post", "nodes/myhost/qemu/123/clone", {"newid": ANY},
  111. )
  112. assert result == {}
  113. # CASE 2: host:ID notation
  114. mock_query.reset_mock()
  115. vm_["clone_from"] = "otherhost:123"
  116. result = proxmox.create_node(vm_, ANY)
  117. mock_query.assert_called_once_with(
  118. "post", "nodes/otherhost/qemu/123/clone", {"newid": ANY},
  119. )
  120. assert result == {}
  121. def test__authenticate_with_custom_port(self):
  122. """
  123. Test the use of a custom port for Proxmox connection
  124. """
  125. get_cloud_config_mock = [
  126. "proxmox.connection.url",
  127. "9999",
  128. "fakeuser",
  129. "secretpassword",
  130. True,
  131. ]
  132. requests_post_mock = MagicMock()
  133. with patch(
  134. "salt.config.get_cloud_config_value",
  135. autospec=True,
  136. side_effect=get_cloud_config_mock,
  137. ), patch("requests.post", requests_post_mock):
  138. proxmox._authenticate()
  139. requests_post_mock.assert_called_with(
  140. "https://proxmox.connection.url:9999/api2/json/access/ticket",
  141. verify=True,
  142. data={"username": ("fakeuser",), "password": "secretpassword"},
  143. )