mirror of
https://github.com/kubevirt/kubevirt.core.git
synced 2026-07-25 00:44:35 +00:00
Merge pull request #240 from jcanocan/win-ansible-connection
feat(inventory): add `win_ansible_connection` option
This commit is contained in:
@@ -83,6 +83,21 @@ options:
|
||||
- Append the base domain of the cluster to host names constructed from SSH C(Services) of type C(NodePort).
|
||||
type: bool
|
||||
default: False
|
||||
default_win_ansible_connection:
|
||||
description:
|
||||
- Set the default value of C(ansible_connection) when a Windows virtual machines is detected.
|
||||
- Common values include V(winrm), V(ansible.builtin.winrm), V(psrp), V(ansible.builtin.psrp), V(ssh), and V(ansible.builtin.ssh).
|
||||
- When set to V(ssh) or V(ansible.builtin.ssh), the service port lookup uses SSH port (22) instead of WinRM/PSRP ports (5986/5985).
|
||||
type: str
|
||||
choices:
|
||||
- winrm
|
||||
- ansible.builtin.winrm
|
||||
- psrp
|
||||
- ansible.builtin.psrp
|
||||
- ssh
|
||||
- ansible.builtin.ssh
|
||||
default: "winrm"
|
||||
version_added: 2.3.0
|
||||
api_version:
|
||||
description:
|
||||
- Specify the used KubeVirt API version.
|
||||
@@ -183,8 +198,8 @@ TYPE_LOADBALANCER = "LoadBalancer"
|
||||
TYPE_NODEPORT = "NodePort"
|
||||
ID_MSWINDOWS = "mswindows"
|
||||
SERVICE_TARGET_PORT_SSH = 22
|
||||
SERVICE_TARGET_PORT_WINRM_HTTP = 5985
|
||||
SERVICE_TARGET_PORT_WINRM_HTTPS = 5986
|
||||
SERVICE_TARGET_PORT_WIN_MGMT_HTTP = 5985
|
||||
SERVICE_TARGET_PORT_WIN_MGMT_HTTPS = 5986
|
||||
|
||||
|
||||
class KubeVirtInventoryException(Exception):
|
||||
@@ -208,6 +223,7 @@ class InventoryOptions:
|
||||
create_groups: Optional[bool] = None
|
||||
base_domain: Optional[str] = None
|
||||
append_base_domain: Optional[bool] = None
|
||||
default_win_ansible_connection: Optional[str] = None
|
||||
host_format: Optional[str] = None
|
||||
namespaces: Optional[List[str]] = None
|
||||
name: Optional[str] = None
|
||||
@@ -263,6 +279,11 @@ class InventoryOptions:
|
||||
if self.append_base_domain is not None
|
||||
else config_data.get("append_base_domain", False)
|
||||
)
|
||||
self.default_win_ansible_connection = (
|
||||
self.default_win_ansible_connection
|
||||
if self.default_win_ansible_connection is not None
|
||||
else config_data.get("default_win_ansible_connection", "winrm")
|
||||
)
|
||||
self.host_format = (
|
||||
self.host_format
|
||||
if self.host_format is not None
|
||||
@@ -657,8 +678,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
or ports[0].get("targetPort")
|
||||
not in [
|
||||
SERVICE_TARGET_PORT_SSH,
|
||||
SERVICE_TARGET_PORT_WINRM_HTTP,
|
||||
SERVICE_TARGET_PORT_WINRM_HTTPS,
|
||||
SERVICE_TARGET_PORT_WIN_MGMT_HTTP,
|
||||
SERVICE_TARGET_PORT_WIN_MGMT_HTTPS,
|
||||
]
|
||||
):
|
||||
continue
|
||||
@@ -790,23 +811,36 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
)
|
||||
|
||||
# Set up the connection
|
||||
service = None
|
||||
if self._is_windows(
|
||||
ansible_connection = (
|
||||
self.inventory.get_host(hostname).get_vars().get("ansible_connection")
|
||||
)
|
||||
if ansible_connection is None and self._is_windows(
|
||||
vmi["status"].get("guestOSInfo", {}),
|
||||
vmi["metadata"].get("annotations", {}),
|
||||
):
|
||||
self.inventory.set_variable(hostname, "ansible_connection", "winrm")
|
||||
service = self._find_service_with_target_port(
|
||||
_services, SERVICE_TARGET_PORT_WINRM_HTTPS
|
||||
ansible_connection = opts.default_win_ansible_connection
|
||||
self.inventory.set_variable(
|
||||
hostname, "ansible_connection", ansible_connection
|
||||
)
|
||||
if service is None:
|
||||
service = self._find_service_with_target_port(
|
||||
_services, SERVICE_TARGET_PORT_WINRM_HTTP
|
||||
)
|
||||
else:
|
||||
|
||||
service = None
|
||||
if ansible_connection in (None, "ssh", "ansible.builtin.ssh"):
|
||||
service = self._find_service_with_target_port(
|
||||
_services, SERVICE_TARGET_PORT_SSH
|
||||
)
|
||||
elif ansible_connection in (
|
||||
"winrm",
|
||||
"ansible.builtin.winrm",
|
||||
"psrp",
|
||||
"ansible.builtin.psrp",
|
||||
):
|
||||
service = self._find_service_with_target_port(
|
||||
_services, SERVICE_TARGET_PORT_WIN_MGMT_HTTPS
|
||||
)
|
||||
if service is None:
|
||||
service = self._find_service_with_target_port(
|
||||
_services, SERVICE_TARGET_PORT_WIN_MGMT_HTTP
|
||||
)
|
||||
|
||||
self._set_ansible_host_and_port(
|
||||
vmi,
|
||||
|
||||
@@ -78,23 +78,54 @@ SVC_LB_WINRM_HTTPS = {
|
||||
},
|
||||
"status": {"loadBalancer": {"ingress": [{"ip": "192.168.1.100"}]}},
|
||||
}
|
||||
SVC_LB_SSH = merge_dicts(
|
||||
SVC_LB_WINRM_HTTPS,
|
||||
{
|
||||
"metadata": {
|
||||
"name": "test-lb-ssh",
|
||||
"uid": "33a31042-f58c-5044-cf78-ef211cedb1d4",
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"protocol": "TCP",
|
||||
"port": 12345,
|
||||
"targetPort": 22,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"vmi,expected,use_service",
|
||||
"vmi,expected,use_service,default_win_ansible_connection,services",
|
||||
[
|
||||
(BASE_VMI, False, False),
|
||||
(WINDOWS_VMI_1, True, True),
|
||||
(WINDOWS_VMI_2, True, True),
|
||||
(WINDOWS_VMI_3, True, True),
|
||||
(WINDOWS_VMI_4, True, True),
|
||||
(WINDOWS_VMI_1, True, False),
|
||||
(WINDOWS_VMI_2, True, False),
|
||||
(WINDOWS_VMI_3, True, False),
|
||||
(WINDOWS_VMI_4, True, False),
|
||||
(BASE_VMI, False, False, "winrm", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_1, True, True, "winrm", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_2, True, True, "winrm", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_3, True, True, "winrm", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_4, True, True, "winrm", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_1, True, False, "winrm", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_2, True, False, "winrm", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_3, True, False, "winrm", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_4, True, False, "winrm", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_1, True, True, "psrp", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_1, True, False, "psrp", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_2, True, True, "ansible.builtin.psrp", [SVC_LB_WINRM_HTTPS]),
|
||||
(WINDOWS_VMI_3, True, False, "ssh", [SVC_LB_SSH]),
|
||||
(WINDOWS_VMI_4, True, True, "ansible.builtin.ssh", [SVC_LB_SSH]),
|
||||
],
|
||||
)
|
||||
def test_ansible_connection_winrm(inventory, hosts, vmi, expected, use_service):
|
||||
def test_default_win_ansible_connection(
|
||||
inventory,
|
||||
hosts,
|
||||
vmi,
|
||||
expected,
|
||||
use_service,
|
||||
default_win_ansible_connection,
|
||||
services,
|
||||
):
|
||||
inventory._populate_inventory(
|
||||
{
|
||||
"default_hostname": "test",
|
||||
@@ -103,16 +134,19 @@ def test_ansible_connection_winrm(inventory, hosts, vmi, expected, use_service):
|
||||
"default": {
|
||||
"vms": [],
|
||||
"vmis": [vmi],
|
||||
"services": {"testdomain": [SVC_LB_WINRM_HTTPS]},
|
||||
"services": {"testdomain": services},
|
||||
}
|
||||
},
|
||||
},
|
||||
InventoryOptions(use_service=use_service),
|
||||
InventoryOptions(
|
||||
use_service=use_service,
|
||||
default_win_ansible_connection=default_win_ansible_connection,
|
||||
),
|
||||
)
|
||||
|
||||
host = f"{DEFAULT_NAMESPACE}-{vmi['metadata']['name']}"
|
||||
if expected:
|
||||
assert hosts[host]["ansible_connection"] == "winrm"
|
||||
assert hosts[host]["ansible_connection"] == default_win_ansible_connection
|
||||
else:
|
||||
assert "ansible_connection" not in hosts[host]
|
||||
if use_service:
|
||||
@@ -22,6 +22,7 @@ def test_inventory_options_defaults():
|
||||
assert opts.create_groups is False
|
||||
assert opts.base_domain is None
|
||||
assert opts.append_base_domain is False
|
||||
assert opts.default_win_ansible_connection == "winrm"
|
||||
assert opts.host_format == "{namespace}-{name}"
|
||||
|
||||
|
||||
@@ -35,6 +36,7 @@ def test_inventory_options_override_defaults():
|
||||
create_groups = True
|
||||
base_domain = "test-domain.com"
|
||||
append_base_domain = True
|
||||
default_win_ansible_connection = "psrp"
|
||||
host_format = "{name}-testhost"
|
||||
|
||||
opts = InventoryOptions(
|
||||
@@ -47,6 +49,7 @@ def test_inventory_options_override_defaults():
|
||||
create_groups=create_groups,
|
||||
base_domain=base_domain,
|
||||
append_base_domain=append_base_domain,
|
||||
default_win_ansible_connection=default_win_ansible_connection,
|
||||
host_format=host_format,
|
||||
)
|
||||
assert opts.api_version == api_version
|
||||
@@ -58,4 +61,5 @@ def test_inventory_options_override_defaults():
|
||||
assert opts.create_groups == create_groups
|
||||
assert opts.base_domain == base_domain
|
||||
assert opts.append_base_domain == append_base_domain
|
||||
assert opts.default_win_ansible_connection == default_win_ansible_connection
|
||||
assert opts.host_format == host_format
|
||||
|
||||
@@ -86,17 +86,38 @@ def test_ignore_vmi_without_named_interface(mocker, inventory):
|
||||
set_ansible_host_and_port.assert_not_called()
|
||||
|
||||
|
||||
def test_set_winrm_if_windows(mocker, inventory):
|
||||
@pytest.mark.parametrize(
|
||||
"default_win_ansible_connection",
|
||||
[
|
||||
"winrm",
|
||||
"ansible.builtin.winrm",
|
||||
"psrp",
|
||||
"ansible.builtin.psrp",
|
||||
"ssh",
|
||||
"ansible.builtin.ssh",
|
||||
],
|
||||
)
|
||||
def test_set_connection_if_windows(mocker, inventory, default_win_ansible_connection):
|
||||
mocker.patch.object(inventory, "_set_common_vars")
|
||||
mocker.patch.object(inventory, "_is_windows", return_value=True)
|
||||
mocker.patch.object(inventory, "_set_ansible_host_and_port")
|
||||
mocker.patch.object(
|
||||
inventory.inventory,
|
||||
"get_host",
|
||||
return_value=mocker.Mock(get_vars=mocker.Mock(return_value={})),
|
||||
)
|
||||
set_variable = mocker.patch.object(inventory.inventory, "set_variable")
|
||||
|
||||
hostname = "default-testvm"
|
||||
vmi = {"metadata": {}, "status": {"interfaces": [{"ipAddress": "1.1.1.1"}]}}
|
||||
inventory._set_vars_from_vmi(hostname, vmi, {}, InventoryOptions())
|
||||
opts = InventoryOptions(
|
||||
default_win_ansible_connection=default_win_ansible_connection
|
||||
)
|
||||
inventory._set_vars_from_vmi(hostname, vmi, {}, opts)
|
||||
|
||||
set_variable.assert_called_once_with(hostname, "ansible_connection", "winrm")
|
||||
set_variable.assert_called_once_with(
|
||||
hostname, "ansible_connection", default_win_ansible_connection
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -110,6 +131,11 @@ def test_set_winrm_if_windows(mocker, inventory):
|
||||
def test_service_lookup(mocker, inventory, is_windows, target_port):
|
||||
mocker.patch.object(inventory, "_set_common_vars")
|
||||
mocker.patch.object(inventory, "_is_windows", return_value=is_windows)
|
||||
mocker.patch.object(
|
||||
inventory.inventory,
|
||||
"get_host",
|
||||
return_value=mocker.Mock(get_vars=mocker.Mock(return_value={})),
|
||||
)
|
||||
set_ansible_host_and_port = mocker.patch.object(
|
||||
inventory, "_set_ansible_host_and_port"
|
||||
)
|
||||
@@ -144,6 +170,11 @@ def test_service_ignore_not_matching_connection(
|
||||
):
|
||||
mocker.patch.object(inventory, "_set_common_vars")
|
||||
mocker.patch.object(inventory, "_is_windows", return_value=is_windows)
|
||||
mocker.patch.object(
|
||||
inventory.inventory,
|
||||
"get_host",
|
||||
return_value=mocker.Mock(get_vars=mocker.Mock(return_value={})),
|
||||
)
|
||||
set_ansible_host_and_port = mocker.patch.object(
|
||||
inventory, "_set_ansible_host_and_port"
|
||||
)
|
||||
@@ -168,6 +199,11 @@ def test_service_ignore_not_matching_connection(
|
||||
def test_service_prefer_winrm_https(mocker, inventory):
|
||||
mocker.patch.object(inventory, "_set_common_vars")
|
||||
mocker.patch.object(inventory, "_is_windows", return_value=True)
|
||||
mocker.patch.object(
|
||||
inventory.inventory,
|
||||
"get_host",
|
||||
return_value=mocker.Mock(get_vars=mocker.Mock(return_value={})),
|
||||
)
|
||||
set_ansible_host_and_port = mocker.patch.object(
|
||||
inventory, "_set_ansible_host_and_port"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user