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

View File

@ -14,6 +14,7 @@
from __future__ import absolute_import
import os
import unittest
import netaddr
import pandas as pd
@ -146,3 +147,11 @@ class OvercloudProcessesTest(testtools.TestCase):
def test_overcloud_processes(self):
ops = processes.OvercloudProcessesStatus()
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.
from __future__ import absolute_import
import unittest
import testtools
import tobiko
from tobiko import config
from tobiko.shell import sh
from tobiko.openstack import keystone
@ -69,3 +72,11 @@ class UndercloudKeystoneClientTest(testtools.TestCase):
client = tripleo.undercloud_keystone_client()
services = keystone.list_services(client=client)
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 _overcloud as overcloud
from tobiko.tripleo import _rhosp
from tobiko.tripleo import _topology as topology
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_node_ip_address = overcloud.overcloud_node_ip_address
overcloud_ssh_client = overcloud.overcloud_ssh_client
overcloud_version = overcloud.overcloud_version
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
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_session = undercloud.undercloud_keystone_session
undercloud_ssh_client = undercloud.undercloud_ssh_client
undercloud_version = undercloud.undercloud_version

View File

@ -13,7 +13,6 @@
# under the License.
from __future__ import absolute_import
import functools
import io
import os
import typing
@ -41,19 +40,18 @@ def has_overcloud(min_version: str = None,
return False
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,
max_version=max_version):
return False
return True
@functools.lru_cache()
def get_overcloud_version() -> tobiko.VersionType:
ssh_client = topology.find_openstack_node(group='controller').ssh_client
release = sh.execute('cat /etc/rhosp-release',
ssh_client=ssh_client).stdout
return tobiko.parse_version(release)
def overcloud_version() -> tobiko.Version:
from tobiko.tripleo import _topology
node = topology.find_openstack_node(group='overcloud')
assert isinstance(node, _topology.TripleoTopologyNode)
return node.rhosp_version
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 metalsmith
import netaddr
from oslo_log import log
import tobiko
from tobiko.openstack import neutron
from tobiko.openstack import nova
from tobiko.openstack import topology
from tobiko.shell import files
from tobiko.shell import sh
from tobiko.shell import ssh
from tobiko.tripleo import _overcloud
from tobiko.tripleo import _rhosp
from tobiko.tripleo import _undercloud
LOG = log.getLogger(__name__)
@ -89,7 +92,7 @@ class TripleoTopology(topology.OpenStackTopology):
ssh_client=ssh_client)
def discover_overcloud_nodes(self):
if _overcloud.has_overcloud():
if _undercloud.has_undercloud():
for instance in _overcloud.list_overcloud_nodes():
try:
_overcloud.power_on_overcloud_node(instance)
@ -103,9 +106,9 @@ class TripleoTopology(topology.OpenStackTopology):
host_config=host_config)
node = self.add_node(address=host_config.hostname,
group='overcloud',
ssh_client=ssh_client)
ssh_client=ssh_client,
overcloud_instance=instance)
assert isinstance(node, TripleoTopologyNode)
node.overcloud_instance = instance
self.discover_overcloud_node_subgroups(node)
def discover_overcloud_node_subgroups(self, node):
@ -138,7 +141,32 @@ class TripleoTopology(topology.OpenStackTopology):
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 = (
'/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)
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):
if not group_name:

View File

@ -13,6 +13,7 @@
# under the License.
from __future__ import absolute_import
import functools
import json
import os
import typing
@ -24,6 +25,8 @@ from tobiko import config
from tobiko.openstack import keystone
from tobiko.shell import ssh
from tobiko.shell import sh
from tobiko.tripleo import _rhosp
CONF = config.CONF
@ -197,3 +200,9 @@ def undercloud_keystone_session():
def undercloud_keystone_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)