[Podified] Implement way to discover OCP workers
In podified topology OCP workers are actually OpenStack control plane nodes. Currently we don't do ssh to those nodes in Tobiko but in some cases, like e.g. in some tests from the tobiko.tests.faults.neutron.test_agents module we need to filter such nodes out as Tobiko tries to ssh to every node which it founds in the "neutron agent-list" output and there is at least one ovn-controller running on the controller node (OCP workers). To workaround that issue this patch adds discoverability of the OCP workers but without trying to create ssh_client for those nodes. Related-Jira: #OSP-22166 Change-Id: Ib52d6b1a88046017081db30ece8969a20ead73c1
This commit is contained in:
parent
d85945a608
commit
cf666804ef
@ -217,7 +217,7 @@ class OpenStackTopologyNode:
|
||||
def __init__(self,
|
||||
topology: 'OpenStackTopology',
|
||||
name: str,
|
||||
ssh_client: ssh.SSHClientFixture,
|
||||
ssh_client: typing.Optional[ssh.SSHClientFixture],
|
||||
addresses: typing.Iterable[netaddr.IPAddress],
|
||||
hostname: str):
|
||||
self._topology = weakref.ref(topology)
|
||||
@ -474,8 +474,9 @@ class OpenStackTopology(tobiko.SharedFixture):
|
||||
addresses: typing.List[netaddr.IPAddress],
|
||||
hostname: str = None,
|
||||
ssh_client: ssh.SSHClientFixture = None,
|
||||
create_ssh_client: bool = True,
|
||||
**create_params):
|
||||
if ssh_client is None:
|
||||
if ssh_client is None and create_ssh_client:
|
||||
ssh_client = self._ssh_connect(hostname=hostname,
|
||||
addresses=addresses)
|
||||
addresses.extend(self._list_addresses_from_host(ssh_client=ssh_client))
|
||||
@ -485,10 +486,12 @@ class OpenStackTopology(tobiko.SharedFixture):
|
||||
try:
|
||||
node = self._names[name]
|
||||
except KeyError:
|
||||
ssh_login = (
|
||||
ssh_client.login if ssh_client else "No SSH Client configured")
|
||||
LOG.debug("Add topology node:\n"
|
||||
f" - name: {name}\n"
|
||||
f" - hostname: {hostname}\n"
|
||||
f" - login: {ssh_client.login}\n"
|
||||
f" - login: {ssh_login}\n"
|
||||
f" - addresses: {addresses}\n")
|
||||
self._names[name] = node = self.create_node(name=name,
|
||||
hostname=hostname,
|
||||
@ -622,7 +625,11 @@ class OpenStackTopology(tobiko.SharedFixture):
|
||||
ip_version = self.config.conf.ip_version
|
||||
return ip_version and int(ip_version) or None
|
||||
|
||||
def _list_addresses_from_host(self, ssh_client: ssh.SSHClientFixture):
|
||||
def _list_addresses_from_host(
|
||||
self,
|
||||
ssh_client: typing.Optional[ssh.SSHClientFixture]):
|
||||
if not ssh_client:
|
||||
return tobiko.Selection()
|
||||
return ip.list_ip_addresses(ssh_client=ssh_client,
|
||||
ip_version=self.ip_version,
|
||||
scope='global')
|
||||
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import netaddr
|
||||
import openshift as oc
|
||||
from oslo_log import log
|
||||
|
||||
@ -23,6 +24,7 @@ LOG = log.getLogger(__name__)
|
||||
OSP_CONTROLPLANE = 'openstackcontrolplane'
|
||||
OSP_DP_NODESET = 'openstackdataplanenodeset'
|
||||
DP_SSH_SECRET_NAME = 'secret/dataplane-ansible-ssh-private-key-secret'
|
||||
OCP_WORKERS = 'nodes'
|
||||
|
||||
OVN_DP_SERVICE_NAME = 'ovn'
|
||||
COMPUTE_DP_SERVICE_NAMES = ['nova', 'nova-custom']
|
||||
@ -50,6 +52,19 @@ def _get_group(services):
|
||||
return EDPM_OTHER_GROUP
|
||||
|
||||
|
||||
def _get_ocp_worker_hostname(worker):
|
||||
for address in worker.get('status', {}).get('addresses', []):
|
||||
if address.get('type') == 'Hostname':
|
||||
return address['address']
|
||||
|
||||
|
||||
def _get_ocp_worker_addresses(worker):
|
||||
return [
|
||||
netaddr.IPAddress(address['address']) for
|
||||
address in worker.get('status', {}).get('addresses', [])
|
||||
if address.get('type') != 'Hostname']
|
||||
|
||||
|
||||
def has_podified_cp() -> bool:
|
||||
if not _is_oc_client_available():
|
||||
LOG.debug("Openshift CLI client isn't installed.")
|
||||
@ -98,4 +113,12 @@ def list_edpm_nodes():
|
||||
|
||||
|
||||
def list_ocp_workers():
|
||||
pass
|
||||
nodes_sel = oc.selector(OCP_WORKERS)
|
||||
ocp_workers = []
|
||||
for node in nodes_sel.objects():
|
||||
node_dict = node.as_dict()
|
||||
ocp_workers.append({
|
||||
'hostname': _get_ocp_worker_hostname(node_dict),
|
||||
'addresses': _get_ocp_worker_addresses(node_dict)
|
||||
})
|
||||
return ocp_workers
|
||||
|
@ -41,6 +41,8 @@ COMPUTE_GROUPS = [
|
||||
_openshift.EDPM_OTHER_GROUP
|
||||
]
|
||||
ALL_COMPUTES_GROUP_NAME = 'compute'
|
||||
OCP_WORKER = 'ocp_worker'
|
||||
EDPM_NODE = 'edpm_node'
|
||||
|
||||
|
||||
class PodifiedTopology(rhosp.RhospTopology):
|
||||
@ -65,6 +67,10 @@ class PodifiedTopology(rhosp.RhospTopology):
|
||||
neutron.FRR: 'frr'
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
super(PodifiedTopology, self).__init__()
|
||||
self.ocp_workers = {}
|
||||
|
||||
def add_node(self,
|
||||
hostname: typing.Optional[str] = None,
|
||||
address: typing.Optional[str] = None,
|
||||
@ -89,10 +95,13 @@ class PodifiedTopology(rhosp.RhospTopology):
|
||||
return node
|
||||
|
||||
def create_node(self, name, ssh_client, **kwargs):
|
||||
return EdpmNode(topology=self,
|
||||
name=name,
|
||||
ssh_client=ssh_client,
|
||||
**kwargs)
|
||||
node_type = kwargs.pop('node_type')
|
||||
if node_type == OCP_WORKER:
|
||||
return OcpWorkerNode(topology=self, name=name, ssh_client=None,
|
||||
**kwargs)
|
||||
else:
|
||||
return EdpmNode(topology=self, name=name, ssh_client=ssh_client,
|
||||
**kwargs)
|
||||
|
||||
def discover_nodes(self):
|
||||
self.discover_ssh_proxy_jump_node()
|
||||
@ -103,8 +112,23 @@ class PodifiedTopology(rhosp.RhospTopology):
|
||||
pass
|
||||
|
||||
def discover_ocp_worker_nodes(self):
|
||||
# TODO(slaweq): discover OCP nodes where OpenStack CP is running
|
||||
pass
|
||||
# NOTE(slaweq): For now this will only discover nodes but there will be
|
||||
# no ssh_client created to ssh to those nodes. Getting
|
||||
# ssh_client to those nodes may be implemented in the future if that
|
||||
# will be needed, but this may be hard e.g. for the CRC environments as
|
||||
# in that case internal OCP worker's IP address is not accessible from
|
||||
# outside at all
|
||||
for worker_data in _openshift.list_ocp_workers():
|
||||
node = self._add_node(
|
||||
addresses=worker_data['addresses'],
|
||||
hostname=worker_data['hostname'],
|
||||
ssh_client=None,
|
||||
create_ssh_client=False,
|
||||
node_type=OCP_WORKER)
|
||||
group_nodes = self.add_group(group='controller')
|
||||
if node not in group_nodes:
|
||||
group_nodes.append(node)
|
||||
node.add_group(group='controller')
|
||||
|
||||
def discover_edpm_nodes(self):
|
||||
for node in _openshift.list_edpm_nodes():
|
||||
@ -115,7 +139,8 @@ class PodifiedTopology(rhosp.RhospTopology):
|
||||
ssh_client = _edpm.edpm_ssh_client(host_config=host_config)
|
||||
node = self.add_node(address=host_config.host,
|
||||
group=group,
|
||||
ssh_client=ssh_client)
|
||||
ssh_client=ssh_client,
|
||||
node_type=EDPM_NODE)
|
||||
assert isinstance(node, EdpmNode)
|
||||
|
||||
|
||||
@ -128,5 +153,9 @@ class EdpmNode(rhosp.RhospNode):
|
||||
LOG.debug(f"Ensuring EDPM node {self.name} power is off...")
|
||||
|
||||
|
||||
class OcpWorkerNode(rhosp.RhospNode):
|
||||
pass
|
||||
|
||||
|
||||
def setup_podified_topology():
|
||||
topology.set_default_openstack_topology_class(PodifiedTopology)
|
||||
|
@ -656,7 +656,14 @@ class OvnControllerTest(BaseAgentTest):
|
||||
self.skipTest(f"Missing container(s): '{self.container_name}'")
|
||||
|
||||
for host in hosts:
|
||||
ssh_client = topology.get_openstack_node(hostname=host).ssh_client
|
||||
node = topology.get_openstack_node(hostname=host)
|
||||
if not node.ssh_client:
|
||||
LOG.debug(f'Host {host} is probably an OCP worker in '
|
||||
f'the Podified environment. SSH to that kind of '
|
||||
f'nodes is currently not supported.')
|
||||
continue
|
||||
|
||||
ssh_client = node.ssh_client
|
||||
pid = self._get_ovn_controller_pid(ssh_client)
|
||||
self.assertIsNotNone(pid)
|
||||
LOG.debug(f'Killing process {pid} from container '
|
||||
|
@ -16,6 +16,8 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import tobiko
|
||||
from tobiko.shell import ping
|
||||
from tobiko.shell import sh
|
||||
from tobiko.tests.functional.openstack import test_topology
|
||||
from tobiko import podified
|
||||
|
||||
@ -27,6 +29,17 @@ class PodifiedTopologyTest(test_topology.OpenStackTopologyTest):
|
||||
def topology(self) -> podified.PodifiedTopology:
|
||||
return tobiko.setup_fixture(podified.PodifiedTopology)
|
||||
|
||||
def test_controller_group(self):
|
||||
self.skipTest("Discovery of the OCP workers is "
|
||||
"not implemented yet.")
|
||||
def test_ping_node(self):
|
||||
# NOTE(slaweq): in podified topology we expect connectivity only to the
|
||||
# edpm nodes, not to the OCP workers
|
||||
for node in self.topology.get_group("compute"):
|
||||
ping.ping(node.public_ip, count=1, timeout=5.).assert_replied()
|
||||
|
||||
def test_ssh_client(self):
|
||||
# NOTE(slaweq): in podified topology we expect connectivity only to the
|
||||
# edpm nodes, not to the OCP workers
|
||||
for node in self.topology.get_group("compute"):
|
||||
self.assertIsNotNone(node.ssh_client)
|
||||
hostname = sh.ssh_hostname(
|
||||
ssh_client=node.ssh_client).split('.')[0]
|
||||
self.assertEqual(node.name, hostname)
|
||||
|
Loading…
Reference in New Issue
Block a user