mirror of
https://github.com/kubevirt/kubevirt.core.git
synced 2026-03-26 19:03:16 +00:00
cleanup(inventory): Drop support for multiple connections
The support for connections to multiple clusters in the inventory plugin is dropped to better align with user expectations and how other inventories work. If inventories of multiple clusters are needed the inventory can be run multiple times with different configurations. This also helps to clean up the code and make it simpler. For now this adds a compatibility helper so that configurations with a single connection entry remain supported and a warning is emitted. Signed-off-by: Felix Matouschek <fmatouschek@redhat.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
---
|
||||
plugin: kubevirt.core.kubevirt
|
||||
connections:
|
||||
- name: test
|
||||
namespaces:
|
||||
- default
|
||||
create_groups: true
|
||||
name: test
|
||||
namespaces:
|
||||
- default
|
||||
create_groups: true
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
plugin: kubevirt.core.kubevirt
|
||||
connections:
|
||||
- namespaces:
|
||||
- default
|
||||
create_groups: true
|
||||
label_selector: app=test
|
||||
namespaces:
|
||||
- default
|
||||
create_groups: true
|
||||
label_selector: app=test
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
plugin: kubevirt.core.kubevirt
|
||||
connections:
|
||||
- namespaces:
|
||||
- default
|
||||
create_groups: true
|
||||
network_name: bridge-network
|
||||
namespaces:
|
||||
- default
|
||||
create_groups: true
|
||||
network_name: bridge-network
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
plugin: kubevirt.core.kubevirt
|
||||
connections:
|
||||
- namespaces:
|
||||
- default
|
||||
network_name: bridge-network
|
||||
namespaces:
|
||||
- default
|
||||
network_name: bridge-network
|
||||
|
||||
@@ -206,29 +206,6 @@ def test_is_windows(guest_os_info, annotations, expected):
|
||||
assert InventoryModule.is_windows(guest_os_info, annotations) == expected
|
||||
|
||||
|
||||
def test_parse(mocker, inventory):
|
||||
path = "/testpath"
|
||||
cache_prefix = "test-prefix"
|
||||
host_format = "test-format"
|
||||
config_data = {"host_format": host_format}
|
||||
cache = True
|
||||
|
||||
get_cache_prefix = mocker.patch.object(
|
||||
inventory, "_get_cache_prefix", return_value=cache_prefix
|
||||
)
|
||||
read_config_data = mocker.patch.object(
|
||||
inventory, "_read_config_data", return_value=config_data
|
||||
)
|
||||
setup = mocker.patch.object(inventory, "setup")
|
||||
|
||||
inventory.parse(None, None, path, cache)
|
||||
|
||||
get_cache_prefix.assert_called_once_with(path)
|
||||
read_config_data.assert_called_once_with(path)
|
||||
setup.assert_called_once_with(config_data, cache, cache_prefix)
|
||||
assert inventory.host_format == host_format
|
||||
|
||||
|
||||
def test_get_cluster_domain(inventory, client):
|
||||
assert inventory.get_cluster_domain(client) == DEFAULT_BASE_DOMAIN
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2024 Red Hat, Inc.
|
||||
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
|
||||
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
|
||||
KubeVirtInventoryException,
|
||||
)
|
||||
|
||||
|
||||
def test_config_data_without_connections_ignored(inventory):
|
||||
config_data = {
|
||||
"name": "connection-1",
|
||||
"namespaces": ["default"],
|
||||
"network_name": "bridge-network",
|
||||
"label_selector": "app=test",
|
||||
}
|
||||
|
||||
inventory.connections_compatibility(config_data)
|
||||
|
||||
assert config_data["name"] == "connection-1"
|
||||
assert config_data["namespaces"] == ["default"]
|
||||
assert config_data["network_name"] == "bridge-network"
|
||||
assert config_data["label_selector"] == "app=test"
|
||||
|
||||
|
||||
def test_single_connection_supported(inventory):
|
||||
config_data = {
|
||||
"connections": [
|
||||
{
|
||||
"name": "connection-1",
|
||||
"namespaces": ["default"],
|
||||
"network_name": "bridge-network",
|
||||
"label_selector": "app=test",
|
||||
}
|
||||
],
|
||||
"namespaces": ["something"],
|
||||
"network_name": "some-network",
|
||||
"label_selector": "app=something",
|
||||
}
|
||||
|
||||
inventory.connections_compatibility(config_data)
|
||||
|
||||
assert config_data["name"] == "connection-1"
|
||||
assert config_data["namespaces"] == ["default"]
|
||||
assert config_data["network_name"] == "bridge-network"
|
||||
assert config_data["label_selector"] == "app=test"
|
||||
|
||||
|
||||
def test_multiple_connections_not_supported(inventory):
|
||||
with pytest.raises(
|
||||
AnsibleError, match="Split your connections into multiple configuration files."
|
||||
):
|
||||
inventory.connections_compatibility(
|
||||
{
|
||||
"connections": [
|
||||
{
|
||||
"name": "connection-1",
|
||||
},
|
||||
{
|
||||
"name": "connection-2",
|
||||
},
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"config_data,expected",
|
||||
[
|
||||
({"connections": "test"}, "Expecting connections to be a list."),
|
||||
(
|
||||
{"connections": [["test", "test"]]},
|
||||
"Expecting connection to be a dictionary.",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_connections_exceptions(inventory, config_data, expected):
|
||||
with pytest.raises(KubeVirtInventoryException, match=expected):
|
||||
inventory.connections_compatibility(config_data)
|
||||
@@ -11,7 +11,6 @@ import pytest
|
||||
|
||||
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
|
||||
InventoryOptions,
|
||||
KubeVirtInventoryException,
|
||||
)
|
||||
|
||||
from ansible_collections.kubevirt.core.tests.unit.plugins.inventory.constants import (
|
||||
@@ -22,135 +21,97 @@ from ansible_collections.kubevirt.core.plugins.inventory import kubevirt
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"connections,expected",
|
||||
"config_data,expected",
|
||||
[
|
||||
(
|
||||
None,
|
||||
[
|
||||
{
|
||||
"name": "default-hostname",
|
||||
"namespace": DEFAULT_NAMESPACE,
|
||||
"opts": InventoryOptions(),
|
||||
},
|
||||
],
|
||||
{
|
||||
"name": "default-hostname",
|
||||
"namespaces": [DEFAULT_NAMESPACE],
|
||||
"opts": InventoryOptions(),
|
||||
},
|
||||
),
|
||||
(
|
||||
[
|
||||
{
|
||||
"name": "test",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
"name": "test",
|
||||
"namespace": DEFAULT_NAMESPACE,
|
||||
"opts": InventoryOptions(),
|
||||
},
|
||||
],
|
||||
{
|
||||
"name": "test",
|
||||
},
|
||||
{
|
||||
"name": "test",
|
||||
"namespaces": [DEFAULT_NAMESPACE],
|
||||
"opts": InventoryOptions(),
|
||||
},
|
||||
),
|
||||
(
|
||||
[
|
||||
{"name": "test", "namespaces": ["test"]},
|
||||
],
|
||||
[
|
||||
{"name": "test", "namespace": "test", "opts": InventoryOptions()},
|
||||
],
|
||||
{"name": "test", "namespaces": ["test"]},
|
||||
{"name": "test", "namespaces": ["test"], "opts": InventoryOptions()},
|
||||
),
|
||||
(
|
||||
[
|
||||
{
|
||||
"name": "test",
|
||||
"namespaces": ["test"],
|
||||
"use_service": True,
|
||||
"create_groups": True,
|
||||
"append_base_domain": True,
|
||||
"base_domain": "test-domain",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
"name": "test",
|
||||
"namespace": "test",
|
||||
"opts": InventoryOptions(
|
||||
use_service=True,
|
||||
create_groups=True,
|
||||
append_base_domain=True,
|
||||
base_domain="test-domain",
|
||||
),
|
||||
},
|
||||
],
|
||||
{
|
||||
"name": "test",
|
||||
"namespaces": ["test"],
|
||||
"use_service": True,
|
||||
"create_groups": True,
|
||||
"append_base_domain": True,
|
||||
"base_domain": "test-domain",
|
||||
},
|
||||
{
|
||||
"name": "test",
|
||||
"namespaces": ["test"],
|
||||
"opts": InventoryOptions(
|
||||
use_service=True,
|
||||
create_groups=True,
|
||||
append_base_domain=True,
|
||||
base_domain="test-domain",
|
||||
),
|
||||
},
|
||||
),
|
||||
(
|
||||
[
|
||||
{
|
||||
"name": "test",
|
||||
"namespaces": ["test"],
|
||||
"use_service": True,
|
||||
"create_groups": True,
|
||||
"append_base_domain": True,
|
||||
"base_domain": "test-domain",
|
||||
"network_name": "test-network",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
"name": "test",
|
||||
"namespace": "test",
|
||||
"opts": InventoryOptions(
|
||||
use_service=True,
|
||||
create_groups=True,
|
||||
append_base_domain=True,
|
||||
base_domain="test-domain",
|
||||
network_name="test-network",
|
||||
),
|
||||
},
|
||||
],
|
||||
{
|
||||
"name": "test",
|
||||
"namespaces": ["test"],
|
||||
"use_service": True,
|
||||
"create_groups": True,
|
||||
"append_base_domain": True,
|
||||
"base_domain": "test-domain",
|
||||
"network_name": "test-network",
|
||||
},
|
||||
{
|
||||
"name": "test",
|
||||
"namespaces": ["test"],
|
||||
"opts": InventoryOptions(
|
||||
use_service=True,
|
||||
create_groups=True,
|
||||
append_base_domain=True,
|
||||
base_domain="test-domain",
|
||||
network_name="test-network",
|
||||
),
|
||||
},
|
||||
),
|
||||
(
|
||||
[
|
||||
{
|
||||
"name": "test",
|
||||
"namespaces": ["test"],
|
||||
"use_service": True,
|
||||
"create_groups": True,
|
||||
"append_base_domain": True,
|
||||
"base_domain": "test-domain",
|
||||
"interface_name": "test-interface",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
"name": "test",
|
||||
"namespace": "test",
|
||||
"opts": InventoryOptions(
|
||||
use_service=True,
|
||||
create_groups=True,
|
||||
append_base_domain=True,
|
||||
base_domain="test-domain",
|
||||
network_name="test-interface",
|
||||
),
|
||||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
[
|
||||
{
|
||||
"name": "test",
|
||||
},
|
||||
{"name": "test", "namespaces": ["test"]},
|
||||
],
|
||||
[
|
||||
{
|
||||
"name": "test",
|
||||
"namespace": DEFAULT_NAMESPACE,
|
||||
"opts": InventoryOptions(),
|
||||
},
|
||||
{"name": "test", "namespace": "test", "opts": InventoryOptions()},
|
||||
],
|
||||
{
|
||||
"name": "test",
|
||||
"namespaces": ["test"],
|
||||
"use_service": True,
|
||||
"create_groups": True,
|
||||
"append_base_domain": True,
|
||||
"base_domain": "test-domain",
|
||||
"interface_name": "test-interface",
|
||||
},
|
||||
{
|
||||
"name": "test",
|
||||
"namespaces": ["test"],
|
||||
"opts": InventoryOptions(
|
||||
use_service=True,
|
||||
create_groups=True,
|
||||
append_base_domain=True,
|
||||
base_domain="test-domain",
|
||||
network_name="test-interface",
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_fetch_objects(mocker, inventory, connections, expected):
|
||||
def test_fetch_objects(mocker, inventory, config_data, expected):
|
||||
mocker.patch.object(kubevirt, "get_api_client")
|
||||
mocker.patch.object(
|
||||
inventory, "get_default_host_name", return_value="default-hostname"
|
||||
@@ -158,8 +119,7 @@ def test_fetch_objects(mocker, inventory, connections, expected):
|
||||
|
||||
cluster_domain = "test.com"
|
||||
mocker.patch.object(inventory, "get_cluster_domain", return_value=cluster_domain)
|
||||
for e in expected:
|
||||
e["opts"].base_domain = e["opts"].base_domain or cluster_domain
|
||||
expected["opts"].base_domain = expected["opts"].base_domain or cluster_domain
|
||||
|
||||
get_available_namespaces = mocker.patch.object(
|
||||
inventory, "get_available_namespaces", return_value=[DEFAULT_NAMESPACE]
|
||||
@@ -168,26 +128,16 @@ def test_fetch_objects(mocker, inventory, connections, expected):
|
||||
inventory, "populate_inventory_from_namespace"
|
||||
)
|
||||
|
||||
inventory.fetch_objects(connections)
|
||||
inventory.fetch_objects(config_data)
|
||||
|
||||
if config_data and "namespaces" in config_data:
|
||||
get_available_namespaces.assert_not_called()
|
||||
else:
|
||||
get_available_namespaces.assert_called()
|
||||
|
||||
get_available_namespaces.assert_has_calls(
|
||||
[mocker.call(mocker.ANY) for c in connections or [{}] if "namespaces" not in c]
|
||||
)
|
||||
populate_inventory_from_namespace.assert_has_calls(
|
||||
[
|
||||
mocker.call(mocker.ANY, e["name"], e["namespace"], e["opts"])
|
||||
for e in expected
|
||||
mocker.call(mocker.ANY, expected["name"], namespace, expected["opts"])
|
||||
for namespace in expected["namespaces"]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"connections,expected",
|
||||
[
|
||||
("test", "Expecting connections to be a list."),
|
||||
(["test", "test"], "Expecting connection to be a dictionary."),
|
||||
],
|
||||
)
|
||||
def test_fetch_objects_exceptions(inventory, connections, expected):
|
||||
with pytest.raises(KubeVirtInventoryException, match=expected):
|
||||
inventory.fetch_objects(connections)
|
||||
|
||||
@@ -24,20 +24,28 @@ from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
|
||||
False,
|
||||
],
|
||||
)
|
||||
def test_cache_is_used(mocker, inventory, cache):
|
||||
connections = [{"test-conn": {}}]
|
||||
config_data = {"connections": connections}
|
||||
cache_key = "test-prefix"
|
||||
def test_parse(mocker, inventory, cache):
|
||||
path = "/testpath"
|
||||
cache_prefix = "test-prefix"
|
||||
config_data = {"host_format": "test-format"}
|
||||
|
||||
mocker.patch.dict(inventory._cache, {cache_key: {"test-key": "test-value"}})
|
||||
mocker.patch.dict(inventory._cache, {cache_prefix: {"test-key": "test-value"}})
|
||||
get_cache_prefix = mocker.patch.object(
|
||||
inventory, "_get_cache_prefix", return_value=cache_prefix
|
||||
)
|
||||
read_config_data = mocker.patch.object(
|
||||
inventory, "_read_config_data", return_value=config_data
|
||||
)
|
||||
fetch_objects = mocker.patch.object(inventory, "fetch_objects")
|
||||
|
||||
inventory.setup(config_data, cache, cache_key)
|
||||
inventory.parse(None, None, path, cache)
|
||||
|
||||
get_cache_prefix.assert_called_once_with(path)
|
||||
read_config_data.assert_called_once_with(path)
|
||||
if cache:
|
||||
fetch_objects.assert_not_called()
|
||||
else:
|
||||
fetch_objects.assert_called_once_with(connections)
|
||||
fetch_objects.assert_called_once_with(config_data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -49,15 +57,17 @@ def test_cache_is_used(mocker, inventory, cache):
|
||||
)
|
||||
def test_k8s_client_missing(mocker, inventory, present):
|
||||
mocker.patch.object(kubevirt, "HAS_K8S_MODULE_HELPER", present)
|
||||
mocker.patch.object(inventory, "_get_cache_prefix")
|
||||
mocker.patch.object(inventory, "_read_config_data")
|
||||
fetch_objects = mocker.patch.object(inventory, "fetch_objects")
|
||||
|
||||
if present:
|
||||
inventory.setup({}, False, "test")
|
||||
inventory.parse(None, None, "", False)
|
||||
fetch_objects.assert_called_once()
|
||||
else:
|
||||
with pytest.raises(
|
||||
KubeVirtInventoryException,
|
||||
match="This module requires the Kubernetes Python client. Try `pip install kubernetes`. Detail: None",
|
||||
):
|
||||
inventory.setup({}, False, "test")
|
||||
inventory.parse(None, None, "", False)
|
||||
fetch_objects.assert_not_called()
|
||||
Reference in New Issue
Block a user