Add functions to parse tripleo RHOSP release

Change-Id: Ifa7bad7af07e0ab517d76a9d386f986f175bf643
This commit is contained in:
Federico Ressi 2022-07-18 08:23:03 +02:00
parent ff0c3d84fd
commit 3b56760264
8 changed files with 127 additions and 20 deletions

View File

@ -204,13 +204,17 @@ class UnknowOpenStackContainerNameError(tobiko.TobikoException):
"topology class '{topology_class}'") "topology class '{topology_class}'")
class OpenStackTopologyNode(object): class OpenStackTopologyNode:
_docker_client = None _docker_client = None
_podman_client = None _podman_client = None
def __init__(self, topology, name: str, ssh_client: ssh.SSHClientFixture, def __init__(self,
addresses: typing.Iterable[netaddr.IPAddress], hostname: str): topology: 'OpenStackTopology',
name: str,
ssh_client: ssh.SSHClientFixture,
addresses: typing.Iterable[netaddr.IPAddress],
hostname: str):
self._topology = weakref.ref(topology) self._topology = weakref.ref(topology)
self.name = name self.name = name
self.ssh_client = ssh_client self.ssh_client = ssh_client
@ -411,7 +415,8 @@ class OpenStackTopology(tobiko.SharedFixture):
hostname: typing.Optional[str] = None, hostname: typing.Optional[str] = None,
address: typing.Optional[str] = None, address: typing.Optional[str] = None,
group: typing.Optional[str] = None, group: typing.Optional[str] = None,
ssh_client: typing.Optional[ssh.SSHClientFixture] = None) \ ssh_client: typing.Optional[ssh.SSHClientFixture] = None,
**create_params) \
-> OpenStackTopologyNode: -> OpenStackTopologyNode:
if ssh_client is not None: if ssh_client is not None:
# detect all global addresses from remote server # detect all global addresses from remote server
@ -434,7 +439,8 @@ class OpenStackTopology(tobiko.SharedFixture):
except _exception.NoSuchOpenStackTopologyNode: except _exception.NoSuchOpenStackTopologyNode:
node = self._add_node(addresses=addresses, node = self._add_node(addresses=addresses,
hostname=hostname, hostname=hostname,
ssh_client=ssh_client) ssh_client=ssh_client,
**create_params)
if group: if group:
# Add group anyway even if the node hasn't been added # Add group anyway even if the node hasn't been added
@ -448,7 +454,8 @@ class OpenStackTopology(tobiko.SharedFixture):
def _add_node(self, def _add_node(self,
addresses: typing.List[netaddr.IPAddress], addresses: typing.List[netaddr.IPAddress],
hostname: str = None, hostname: str = None,
ssh_client: typing.Optional[ssh.SSHClientFixture] = None): ssh_client: ssh.SSHClientFixture = None,
**create_params):
if ssh_client is None: if ssh_client is None:
ssh_client = self._ssh_connect(hostname=hostname, ssh_client = self._ssh_connect(hostname=hostname,
addresses=addresses) addresses=addresses)
@ -467,7 +474,8 @@ class OpenStackTopology(tobiko.SharedFixture):
self._names[name] = node = self.create_node(name=name, self._names[name] = node = self.create_node(name=name,
hostname=hostname, hostname=hostname,
ssh_client=ssh_client, ssh_client=ssh_client,
addresses=addresses) addresses=addresses,
**create_params)
for address in addresses: for address in addresses:
address_node = self._addresses.setdefault(address, node) address_node = self._addresses.setdefault(address, node)

View File

@ -14,6 +14,7 @@
from __future__ import absolute_import from __future__ import absolute_import
import os import os
import unittest
import netaddr import netaddr
import pandas as pd import pandas as pd
@ -146,3 +147,11 @@ class OvercloudProcessesTest(testtools.TestCase):
def test_overcloud_processes(self): def test_overcloud_processes(self):
ops = processes.OvercloudProcessesStatus() ops = processes.OvercloudProcessesStatus()
self.assertTrue(ops.basic_overcloud_processes_running) self.assertTrue(ops.basic_overcloud_processes_running)
class OvercloudVersionTest(unittest.TestCase):
@tripleo.skip_if_missing_undercloud
def test_overcloud_version(self):
version = tripleo.overcloud_version()
self.assertTrue(tobiko.match_version(version, min_version='13.0.0'))

View File

@ -13,8 +13,11 @@
# under the License. # under the License.
from __future__ import absolute_import from __future__ import absolute_import
import unittest
import testtools import testtools
import tobiko
from tobiko import config from tobiko import config
from tobiko.shell import sh from tobiko.shell import sh
from tobiko.openstack import keystone from tobiko.openstack import keystone
@ -69,3 +72,11 @@ class UndercloudKeystoneClientTest(testtools.TestCase):
client = tripleo.undercloud_keystone_client() client = tripleo.undercloud_keystone_client()
services = keystone.list_services(client=client) services = keystone.list_services(client=client)
self.assertTrue(services) self.assertTrue(services)
class UndercloudVersionTest(unittest.TestCase):
@tripleo.skip_if_missing_undercloud
def test_undercloud_version(self):
version = tripleo.undercloud_version()
self.assertTrue(tobiko.match_version(version, min_version='13.0.0'))

View File

@ -15,6 +15,7 @@ from __future__ import absolute_import
from tobiko.tripleo import _ansible from tobiko.tripleo import _ansible
from tobiko.tripleo import _overcloud as overcloud from tobiko.tripleo import _overcloud as overcloud
from tobiko.tripleo import _rhosp
from tobiko.tripleo import _topology as topology from tobiko.tripleo import _topology as topology
from tobiko.tripleo import _undercloud as undercloud from tobiko.tripleo import _undercloud as undercloud
@ -40,8 +41,12 @@ load_overcloud_rcfile = overcloud.load_overcloud_rcfile
overcloud_host_config = overcloud.overcloud_host_config overcloud_host_config = overcloud.overcloud_host_config
overcloud_node_ip_address = overcloud.overcloud_node_ip_address overcloud_node_ip_address = overcloud.overcloud_node_ip_address
overcloud_ssh_client = overcloud.overcloud_ssh_client overcloud_ssh_client = overcloud.overcloud_ssh_client
overcloud_version = overcloud.overcloud_version
skip_if_missing_overcloud = overcloud.skip_if_missing_overcloud skip_if_missing_overcloud = overcloud.skip_if_missing_overcloud
get_rhosp_release = _rhosp.get_rhosp_release
get_rhosp_version = _rhosp.get_rhosp_version
TripleoTopology = topology.TripleoTopology TripleoTopology = topology.TripleoTopology
load_undercloud_rcfile = undercloud.load_undercloud_rcfile load_undercloud_rcfile = undercloud.load_undercloud_rcfile
@ -52,3 +57,4 @@ undercloud_keystone_client = undercloud.undercloud_keystone_client
undercloud_keystone_credentials = undercloud.undercloud_keystone_credentials undercloud_keystone_credentials = undercloud.undercloud_keystone_credentials
undercloud_keystone_session = undercloud.undercloud_keystone_session undercloud_keystone_session = undercloud.undercloud_keystone_session
undercloud_ssh_client = undercloud.undercloud_ssh_client undercloud_ssh_client = undercloud.undercloud_ssh_client
undercloud_version = undercloud.undercloud_version

View File

@ -13,7 +13,6 @@
# under the License. # under the License.
from __future__ import absolute_import from __future__ import absolute_import
import functools
import io import io
import os import os
import typing import typing
@ -41,19 +40,18 @@ def has_overcloud(min_version: str = None,
return False return False
if min_version or max_version: if min_version or max_version:
if not tobiko.match_version(get_overcloud_version(), if not tobiko.match_version(overcloud_version(),
min_version=min_version, min_version=min_version,
max_version=max_version): max_version=max_version):
return False return False
return True return True
@functools.lru_cache() def overcloud_version() -> tobiko.Version:
def get_overcloud_version() -> tobiko.VersionType: from tobiko.tripleo import _topology
ssh_client = topology.find_openstack_node(group='controller').ssh_client node = topology.find_openstack_node(group='overcloud')
release = sh.execute('cat /etc/rhosp-release', assert isinstance(node, _topology.TripleoTopologyNode)
ssh_client=ssh_client).stdout return node.rhosp_version
return tobiko.parse_version(release)
def load_overcloud_rcfile() -> typing.Dict[str, str]: def load_overcloud_rcfile() -> typing.Dict[str, str]:

35
tobiko/tripleo/_rhosp.py Normal file
View File

@ -0,0 +1,35 @@
# Copyright 2022 Red Hat
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import
import functools
import tobiko
from tobiko.shell import sh
@functools.lru_cache()
def get_rhosp_release(connection: sh.ShellConnectionType = None) \
-> str:
connection = sh.shell_connection(connection)
with connection.open_file('/etc/rhosp-release', 'r') as fd:
rhosp_release = fd.read().strip()
if isinstance(rhosp_release, bytes):
rhosp_release = rhosp_release.decode('UTF-8', 'ignore')
return rhosp_release
def get_rhosp_version(connection: sh.ShellConnectionType = None) \
-> tobiko.Version:
return tobiko.parse_version(get_rhosp_release(connection))

View File

@ -17,17 +17,20 @@ import re
import typing import typing
import metalsmith import metalsmith
import netaddr
from oslo_log import log from oslo_log import log
import tobiko
from tobiko.openstack import neutron from tobiko.openstack import neutron
from tobiko.openstack import nova from tobiko.openstack import nova
from tobiko.openstack import topology from tobiko.openstack import topology
from tobiko.shell import files from tobiko.shell import files
from tobiko.shell import sh from tobiko.shell import sh
from tobiko.shell import ssh
from tobiko.tripleo import _overcloud from tobiko.tripleo import _overcloud
from tobiko.tripleo import _rhosp
from tobiko.tripleo import _undercloud from tobiko.tripleo import _undercloud
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ -89,7 +92,7 @@ class TripleoTopology(topology.OpenStackTopology):
ssh_client=ssh_client) ssh_client=ssh_client)
def discover_overcloud_nodes(self): def discover_overcloud_nodes(self):
if _overcloud.has_overcloud(): if _undercloud.has_undercloud():
for instance in _overcloud.list_overcloud_nodes(): for instance in _overcloud.list_overcloud_nodes():
try: try:
_overcloud.power_on_overcloud_node(instance) _overcloud.power_on_overcloud_node(instance)
@ -103,9 +106,9 @@ class TripleoTopology(topology.OpenStackTopology):
host_config=host_config) host_config=host_config)
node = self.add_node(address=host_config.hostname, node = self.add_node(address=host_config.hostname,
group='overcloud', group='overcloud',
ssh_client=ssh_client) ssh_client=ssh_client,
overcloud_instance=instance)
assert isinstance(node, TripleoTopologyNode) assert isinstance(node, TripleoTopologyNode)
node.overcloud_instance = instance
self.discover_overcloud_node_subgroups(node) self.discover_overcloud_node_subgroups(node)
def discover_overcloud_node_subgroups(self, node): def discover_overcloud_node_subgroups(self, node):
@ -138,7 +141,32 @@ class TripleoTopology(topology.OpenStackTopology):
class TripleoTopologyNode(topology.OpenStackTopologyNode): class TripleoTopologyNode(topology.OpenStackTopologyNode):
overcloud_instance: typing.Optional[metalsmith.Instance] = None def __init__(self,
topology: topology.OpenStackTopology,
name: str,
ssh_client: ssh.SSHClientFixture,
addresses: typing.Iterable[netaddr.IPAddress],
hostname: str,
overcloud_instance: metalsmith.Instance = None,
rhosp_version: tobiko.Version = None):
# pylint: disable=redefined-outer-name
super().__init__(topology=topology,
name=name,
ssh_client=ssh_client,
addresses=addresses,
hostname=hostname)
self._overcloud_instance = overcloud_instance
self._rhosp_version = rhosp_version
@property
def overcloud_instance(self) -> typing.Optional[metalsmith.Instance]:
return self.overcloud_instance
@property
def rhosp_version(self) -> tobiko.Version:
if self._rhosp_version is None:
self._rhosp_version = self._get_rhosp_version()
return self._rhosp_version
l3_agent_conf_path = ( l3_agent_conf_path = (
'/var/lib/config-data/neutron/etc/neutron/l3_agent.ini') '/var/lib/config-data/neutron/etc/neutron/l3_agent.ini')
@ -202,6 +230,9 @@ class TripleoTopologyNode(topology.OpenStackTopologyNode):
_overcloud.power_off_overcloud_node(instance=self.overcloud_instance) _overcloud.power_off_overcloud_node(instance=self.overcloud_instance)
LOG.debug(f"Overcloud server node {self.name} power is off.") LOG.debug(f"Overcloud server node {self.name} power is off.")
def _get_rhosp_version(self) -> tobiko.Version:
return _rhosp.get_rhosp_version(connection=self.connection)
def is_valid_overcloud_group_name(group_name: str, node_name: str = None): def is_valid_overcloud_group_name(group_name: str, node_name: str = None):
if not group_name: if not group_name:

View File

@ -13,6 +13,7 @@
# under the License. # under the License.
from __future__ import absolute_import from __future__ import absolute_import
import functools
import json import json
import os import os
import typing import typing
@ -24,6 +25,8 @@ from tobiko import config
from tobiko.openstack import keystone from tobiko.openstack import keystone
from tobiko.shell import ssh from tobiko.shell import ssh
from tobiko.shell import sh from tobiko.shell import sh
from tobiko.tripleo import _rhosp
CONF = config.CONF CONF = config.CONF
@ -197,3 +200,9 @@ def undercloud_keystone_session():
def undercloud_keystone_credentials(): def undercloud_keystone_credentials():
return tobiko.setup_fixture(_get_keystone_credentials()).credentials return tobiko.setup_fixture(_get_keystone_credentials()).credentials
@functools.lru_cache()
def undercloud_version() -> tobiko.Version:
ssh_client = undercloud_ssh_client()
return _rhosp.get_rhosp_version(connection=ssh_client)