Add topology which represents Podified RHOSP deployment
Topology class can now discover EDPM nodes based on the data from the OCP cluster. There are also basic functional tests for new Topology class implemented. Unfortunately those tests can't be run in the upstream CI as it required OCP (CRC at least) and OSP deployment on top of that OCP cluster. And this requires too much resources for the upstream CI infra. Related-Jira: #OSP-22166 Change-Id: I60385f52f01ca0dc4742ed105b14338c1317075e
This commit is contained in:
parent
683a4299f7
commit
e1105c97b7
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
ansi2html # LGPLv3+
|
ansi2html # LGPLv3+
|
||||||
dpkt # BSD
|
dpkt # BSD
|
||||||
|
openshift-client # Apache-2.0
|
||||||
pandas # BSD
|
pandas # BSD
|
||||||
podman==4.7.0 # Apache-2.0
|
podman==4.7.0 # Apache-2.0
|
||||||
pytest-cov # MIT
|
pytest-cov # MIT
|
||||||
|
@ -42,6 +42,8 @@ CONFIG_MODULES = ['tobiko.common._case',
|
|||||||
'tobiko.shell.iperf3.config',
|
'tobiko.shell.iperf3.config',
|
||||||
'tobiko.shell.sh.config',
|
'tobiko.shell.sh.config',
|
||||||
'tobiko.shiftstack.config',
|
'tobiko.shiftstack.config',
|
||||||
|
'tobiko.rhosp.config',
|
||||||
|
'tobiko.podified.config',
|
||||||
'tobiko.tripleo.config']
|
'tobiko.tripleo.config']
|
||||||
|
|
||||||
|
|
||||||
|
24
tobiko/podified/__init__.py
Normal file
24
tobiko/podified/__init__.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Copyright 2023 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
|
||||||
|
|
||||||
|
from tobiko.podified import _topology
|
||||||
|
from tobiko.podified import _openshift
|
||||||
|
|
||||||
|
|
||||||
|
PodifiedTopology = _topology.PodifiedTopology
|
||||||
|
|
||||||
|
skip_if_not_podified = _topology.skip_if_not_podified
|
||||||
|
|
||||||
|
get_dataplane_ssh_keypair = _openshift.get_dataplane_ssh_keypair
|
126
tobiko/podified/_edpm.py
Normal file
126
tobiko/podified/_edpm.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
|
||||||
|
# Copyright 2023 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 base64
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
|
||||||
|
import tobiko
|
||||||
|
from tobiko import config
|
||||||
|
from tobiko.podified import _openshift
|
||||||
|
from tobiko.shell import ssh
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
def edpm_host_config(node=None,
|
||||||
|
ip_version: int = None,
|
||||||
|
key_filename: str = None):
|
||||||
|
node = node or {}
|
||||||
|
host_config = EdpmHostConfig(
|
||||||
|
host=node.get('host'),
|
||||||
|
hostname=node.get('hostname'),
|
||||||
|
ip_version=ip_version,
|
||||||
|
key_filename=key_filename,
|
||||||
|
port=node.get('port'),
|
||||||
|
username=node.get('username'))
|
||||||
|
return tobiko.setup_fixture(host_config)
|
||||||
|
|
||||||
|
|
||||||
|
def edpm_ssh_client(ip_version: int = None,
|
||||||
|
host_config=None,
|
||||||
|
node=None):
|
||||||
|
if host_config is None:
|
||||||
|
host_config = edpm_host_config(node=node,
|
||||||
|
ip_version=ip_version)
|
||||||
|
tobiko.check_valid_type(host_config.host, str)
|
||||||
|
return ssh.ssh_client(host=host_config.host,
|
||||||
|
**host_config.connect_parameters)
|
||||||
|
|
||||||
|
|
||||||
|
class EdpmSshKeyFileFixture(tobiko.SharedFixture):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def key_filename(self):
|
||||||
|
return tobiko.tobiko_config_path(
|
||||||
|
CONF.tobiko.podified.edpm_ssh_key_filename)
|
||||||
|
|
||||||
|
def setup_fixture(self):
|
||||||
|
self.setup_key_file()
|
||||||
|
|
||||||
|
def setup_key_file(self):
|
||||||
|
priv_key_filename = self.key_filename
|
||||||
|
pub_key_filename = priv_key_filename + ".pub"
|
||||||
|
key_dirname = os.path.dirname(priv_key_filename)
|
||||||
|
tobiko.makedirs(key_dirname, mode=0o700)
|
||||||
|
|
||||||
|
private_key, public_key = _openshift.get_dataplane_ssh_keypair()
|
||||||
|
if private_key:
|
||||||
|
with io.open(priv_key_filename, 'wb') as fd:
|
||||||
|
fd.write(base64.b64decode(private_key))
|
||||||
|
os.chmod(priv_key_filename, 0o600)
|
||||||
|
if public_key:
|
||||||
|
with io.open(pub_key_filename, 'wb') as fd:
|
||||||
|
fd.write(base64.b64decode(public_key))
|
||||||
|
os.chmod(pub_key_filename, 0o600)
|
||||||
|
|
||||||
|
|
||||||
|
class EdpmHostConfig(tobiko.SharedFixture):
|
||||||
|
|
||||||
|
key_file = tobiko.required_fixture(EdpmSshKeyFileFixture)
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
host: str,
|
||||||
|
hostname: str = None,
|
||||||
|
ip_version: int = None,
|
||||||
|
key_filename: str = None,
|
||||||
|
port: int = None,
|
||||||
|
username: str = None,
|
||||||
|
**kwargs):
|
||||||
|
super(EdpmHostConfig, self).__init__()
|
||||||
|
self.host = host
|
||||||
|
self.hostname = self._get_hostname(hostname)
|
||||||
|
self.ip_version = ip_version
|
||||||
|
self.key_filename = key_filename
|
||||||
|
self.port = port
|
||||||
|
self.username = username
|
||||||
|
self._connect_parameters = ssh.gather_ssh_connect_parameters(**kwargs)
|
||||||
|
|
||||||
|
def setup_fixture(self):
|
||||||
|
if self.port is None:
|
||||||
|
# TODO(slaweq): add config option
|
||||||
|
self.port = 22
|
||||||
|
if self.username is None:
|
||||||
|
# TODO(slaweq): add config option
|
||||||
|
self.username = 'cloud-admin'
|
||||||
|
if self.key_filename is None:
|
||||||
|
self.key_filename = self.key_file.key_filename
|
||||||
|
|
||||||
|
def _get_hostname(self, hostname):
|
||||||
|
try:
|
||||||
|
socket.gethostbyname(hostname)
|
||||||
|
return hostname
|
||||||
|
except socket.gaierror:
|
||||||
|
return self.host
|
||||||
|
|
||||||
|
@property
|
||||||
|
def connect_parameters(self):
|
||||||
|
parameters = ssh.ssh_host_config(
|
||||||
|
host=str(self.hostname)).connect_parameters
|
||||||
|
parameters.update(ssh.gather_ssh_connect_parameters(self))
|
||||||
|
parameters.update(self._connect_parameters)
|
||||||
|
return parameters
|
82
tobiko/podified/_openshift.py
Normal file
82
tobiko/podified/_openshift.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# Copyright 2023 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 openshift as oc
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
|
from tobiko.shell import sh
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
OSP_CONTROLPLANE = 'openstackcontrolplane'
|
||||||
|
OSP_DP_NODESET = 'openstackdataplanenodeset'
|
||||||
|
DP_SSH_SECRET_NAME = 'secret/dataplane-ansible-ssh-private-key-secret'
|
||||||
|
|
||||||
|
|
||||||
|
def _is_oc_client_available() -> bool:
|
||||||
|
try:
|
||||||
|
if sh.execute('which oc').exit_status == 0:
|
||||||
|
return True
|
||||||
|
except sh.ShellCommandFailed:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def has_podified_cp() -> bool:
|
||||||
|
if not _is_oc_client_available():
|
||||||
|
LOG.debug("Openshift CLI client isn't installed.")
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
return bool(oc.selector(OSP_CONTROLPLANE).objects())
|
||||||
|
except oc.OpenShiftPythonException:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_dataplane_ssh_keypair():
|
||||||
|
private_key = ""
|
||||||
|
public_key = ""
|
||||||
|
try:
|
||||||
|
secret_object = oc.selector(DP_SSH_SECRET_NAME).object()
|
||||||
|
private_key = secret_object.as_dict()['data']['ssh-privatekey']
|
||||||
|
public_key = secret_object.as_dict()['data']['ssh-publickey']
|
||||||
|
except oc.OpenShiftPythonException as err:
|
||||||
|
LOG.error("Error while trying to get Dataplane secret SSH Key: %s",
|
||||||
|
err)
|
||||||
|
return private_key, public_key
|
||||||
|
|
||||||
|
|
||||||
|
def list_edpm_nodes():
|
||||||
|
nodes = []
|
||||||
|
nodeset_sel = oc.selector(OSP_DP_NODESET)
|
||||||
|
for nodeset in nodeset_sel.objects():
|
||||||
|
node_template = nodeset.as_dict()['spec']['nodeTemplate']
|
||||||
|
nodeset_nodes = nodeset.as_dict()['spec']['nodes']
|
||||||
|
for node in nodeset_nodes.values():
|
||||||
|
node_dict = {
|
||||||
|
'hostname': node.get('hostName'),
|
||||||
|
'host': node['ansible']['ansibleHost'],
|
||||||
|
'port': (
|
||||||
|
node.get('ansible', {}).get('ansiblePort') or
|
||||||
|
node_template.get('ansible', {}).get('ansiblePort')),
|
||||||
|
'username': (
|
||||||
|
node.get('ansible', {}).get('ansibleUser') or
|
||||||
|
node_template.get('ansible', {}).get('ansibleUser')),
|
||||||
|
}
|
||||||
|
nodes.append(node_dict)
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
|
def list_ocp_workers():
|
||||||
|
pass
|
95
tobiko/podified/_topology.py
Normal file
95
tobiko/podified/_topology.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# Copyright 2023 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
|
||||||
|
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
|
import tobiko
|
||||||
|
from tobiko.openstack import neutron
|
||||||
|
from tobiko.openstack import topology
|
||||||
|
from tobiko import rhosp
|
||||||
|
from tobiko.podified import _edpm
|
||||||
|
from tobiko.podified import _openshift
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
skip_if_not_podified = tobiko.skip_unless(
|
||||||
|
"Podified deployment not configured", _openshift.has_podified_cp
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PodifiedTopology(rhosp.RhospTopology):
|
||||||
|
|
||||||
|
# NOTE(slaweq): those service names are only valid for the EDPM nodes
|
||||||
|
agent_to_service_name_mappings = {
|
||||||
|
neutron.DHCP_AGENT: 'tripleo_neutron_dhcp',
|
||||||
|
neutron.OVN_METADATA_AGENT: 'tripleo_ovn_metadata_agent',
|
||||||
|
neutron.NEUTRON_OVN_METADATA_AGENT: 'tripleo_ovn_metadata_agent',
|
||||||
|
neutron.OVN_CONTROLLER: 'tripleo_ovn_controller',
|
||||||
|
neutron.OVN_BGP_AGENT: 'tripleo_ovn_bgp_agent',
|
||||||
|
neutron.FRR: 'tripleo_frr'
|
||||||
|
}
|
||||||
|
|
||||||
|
# NOTE(slaweq): those container names are only valid for the EDPM nodes
|
||||||
|
agent_to_container_name_mappings = {
|
||||||
|
neutron.DHCP_AGENT: 'neutron_dhcp',
|
||||||
|
neutron.OVN_METADATA_AGENT: 'ovn_metadata_agent',
|
||||||
|
neutron.NEUTRON_OVN_METADATA_AGENT: 'ovn_metadata_agent',
|
||||||
|
neutron.OVN_CONTROLLER: 'ovn_controller',
|
||||||
|
neutron.OVN_BGP_AGENT: 'ovn_bgp_agent',
|
||||||
|
neutron.FRR: 'frr'
|
||||||
|
}
|
||||||
|
|
||||||
|
def create_node(self, name, ssh_client, **kwargs):
|
||||||
|
return EdpmNode(topology=self,
|
||||||
|
name=name,
|
||||||
|
ssh_client=ssh_client,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
def discover_nodes(self):
|
||||||
|
self.discover_ssh_proxy_jump_node()
|
||||||
|
self.discover_ocp_worker_nodes()
|
||||||
|
self.discover_edpm_nodes()
|
||||||
|
|
||||||
|
def discover_ssh_proxy_jump_node(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def discover_ocp_worker_nodes(self):
|
||||||
|
# TODO(slaweq): discover OCP nodes where OpenStack CP is running
|
||||||
|
pass
|
||||||
|
|
||||||
|
def discover_edpm_nodes(self):
|
||||||
|
for node in _openshift.list_edpm_nodes():
|
||||||
|
LOG.debug(f"Found EDPM node {node['hostname']} "
|
||||||
|
f"(IP: {node['host']})")
|
||||||
|
host_config = _edpm.edpm_host_config(node)
|
||||||
|
ssh_client = _edpm.edpm_ssh_client(host_config=host_config)
|
||||||
|
node = self.add_node(address=host_config.host,
|
||||||
|
group='compute',
|
||||||
|
ssh_client=ssh_client)
|
||||||
|
assert isinstance(node, EdpmNode)
|
||||||
|
|
||||||
|
|
||||||
|
class EdpmNode(rhosp.RhospNode):
|
||||||
|
|
||||||
|
def power_on_node(self):
|
||||||
|
LOG.debug(f"Ensuring EDPM node {self.name} power is on...")
|
||||||
|
|
||||||
|
def power_off_node(self):
|
||||||
|
LOG.debug(f"Ensuring EDPM node {self.name} power is off...")
|
||||||
|
|
||||||
|
|
||||||
|
def setup_podified_topology():
|
||||||
|
topology.set_default_openstack_topology_class(PodifiedTopology)
|
23
tobiko/podified/config.py
Normal file
23
tobiko/podified/config.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Copyright 2023 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
|
||||||
|
|
||||||
|
|
||||||
|
def setup_tobiko_config(conf):
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
from tobiko.podified import _openshift
|
||||||
|
from tobiko.podified import _topology
|
||||||
|
|
||||||
|
if _openshift.has_podified_cp():
|
||||||
|
_topology.setup_podified_topology()
|
23
tobiko/rhosp/__init__.py
Normal file
23
tobiko/rhosp/__init__.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Copyright 2023 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
|
||||||
|
|
||||||
|
from tobiko.rhosp import _version_utils
|
||||||
|
from tobiko.rhosp import _topology
|
||||||
|
|
||||||
|
RhospTopology = _topology.RhospTopology
|
||||||
|
RhospNode = _topology.RhospNode
|
||||||
|
|
||||||
|
get_rhosp_release = _version_utils.get_rhosp_release
|
||||||
|
get_rhosp_version = _version_utils.get_rhosp_version
|
117
tobiko/rhosp/_topology.py
Normal file
117
tobiko/rhosp/_topology.py
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# Copyright 2023 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 typing
|
||||||
|
|
||||||
|
import netaddr
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
|
import tobiko
|
||||||
|
from tobiko.openstack import nova
|
||||||
|
from tobiko.openstack import topology
|
||||||
|
from tobiko.rhosp import _version_utils
|
||||||
|
from tobiko.shell import ssh
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class RhospTopology(topology.OpenStackTopology):
|
||||||
|
|
||||||
|
"""Base topology for Red Hat OpenStack deployments.
|
||||||
|
|
||||||
|
This is base topology which represents common parts between Tripleo and
|
||||||
|
Podified deployments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
has_containers = True
|
||||||
|
|
||||||
|
|
||||||
|
class RhospNode(topology.OpenStackTopologyNode):
|
||||||
|
|
||||||
|
"""Base RHOSP Node
|
||||||
|
|
||||||
|
This class represents common parts between Overcloud nodes and EDPM nodes
|
||||||
|
in Red Hat OpenStack deployments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
topology: topology.OpenStackTopology,
|
||||||
|
name: str,
|
||||||
|
ssh_client: ssh.SSHClientFixture,
|
||||||
|
addresses: typing.Iterable[netaddr.IPAddress],
|
||||||
|
hostname: str,
|
||||||
|
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._rhosp_version = rhosp_version
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rhosp_version(self) -> tobiko.Version:
|
||||||
|
if self._rhosp_version is None:
|
||||||
|
self._rhosp_version = self._get_rhosp_version()
|
||||||
|
return self._rhosp_version
|
||||||
|
|
||||||
|
def _get_rhosp_version(self) -> tobiko.Version:
|
||||||
|
return _version_utils.get_rhosp_version(connection=self.connection)
|
||||||
|
|
||||||
|
def power_on_node(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def power_off_node(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def reboot_node(self, reactivate_servers=True):
|
||||||
|
"""Reboot node
|
||||||
|
|
||||||
|
This method reboots a node and may start every Nova
|
||||||
|
server which is not in SHUTOFF status before restarting.
|
||||||
|
|
||||||
|
:param reactivate_servers: whether or not to re-start the servers which
|
||||||
|
are hosted on the compute node after the reboot
|
||||||
|
"""
|
||||||
|
|
||||||
|
running_servers: typing.List[nova.NovaServer] = []
|
||||||
|
if reactivate_servers:
|
||||||
|
running_servers = self.list_running_servers()
|
||||||
|
LOG.debug(f'Servers to restart after reboot: {running_servers}')
|
||||||
|
|
||||||
|
self.power_off_node()
|
||||||
|
self.power_on_node()
|
||||||
|
|
||||||
|
if running_servers:
|
||||||
|
LOG.info(f'Restart servers after rebooting compute node '
|
||||||
|
f'{self.name}...')
|
||||||
|
for server in running_servers:
|
||||||
|
nova.wait_for_server_status(server=server.id,
|
||||||
|
status='SHUTOFF')
|
||||||
|
LOG.debug(f'Re-activate server {server.name} with ID '
|
||||||
|
f'{server.id}')
|
||||||
|
nova.activate_server(server=server)
|
||||||
|
LOG.debug(f'Server {server.name} with ID {server.id} has '
|
||||||
|
f'been reactivated')
|
||||||
|
|
||||||
|
def list_running_servers(self) -> typing.List[nova.NovaServer]:
|
||||||
|
running_servers = list()
|
||||||
|
for server in nova.list_servers():
|
||||||
|
if server.status != 'SHUTOFF':
|
||||||
|
hypervisor_name = nova.get_server_hypervisor(server,
|
||||||
|
short=True)
|
||||||
|
if self.name == hypervisor_name:
|
||||||
|
running_servers.append(server)
|
||||||
|
return running_servers
|
0
tobiko/rhosp/_utils.py
Normal file
0
tobiko/rhosp/_utils.py
Normal file
110
tobiko/rhosp/config.py
Normal file
110
tobiko/rhosp/config.py
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# Copyright 2019 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 itertools
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
|
||||||
|
TRIPLEO_GROUP_NAME = 'tripleo'
|
||||||
|
TRIPLEO_OPTIONS = [
|
||||||
|
# Undercloud options
|
||||||
|
cfg.StrOpt('undercloud_ssh_hostname',
|
||||||
|
default='undercloud-0',
|
||||||
|
help="hostname or IP address to be used to connect to "
|
||||||
|
"undercloud host"),
|
||||||
|
cfg.IntOpt('undercloud_ssh_port',
|
||||||
|
default=None,
|
||||||
|
help="TCP port of SSH server on undercloud host"),
|
||||||
|
cfg.StrOpt('undercloud_ssh_username',
|
||||||
|
default='stack',
|
||||||
|
help="Username with access to stackrc and overcloudrc files"),
|
||||||
|
cfg.StrOpt('undercloud_ssh_key_filename',
|
||||||
|
default=None,
|
||||||
|
help="SSH key filename used to login to Undercloud node"),
|
||||||
|
cfg.ListOpt('undercloud_rcfile',
|
||||||
|
default=['~/stackrc'],
|
||||||
|
help="Undercloud RC filename"),
|
||||||
|
cfg.StrOpt('undercloud_cloud_name',
|
||||||
|
default='undercloud',
|
||||||
|
help='undercloud cloud name to be used for loading credentials '
|
||||||
|
'from the undercloud clouds files'),
|
||||||
|
cfg.StrOpt('undercloud_cacert_file',
|
||||||
|
default='/etc/pki/tls/certs/ca-bundle.trust.crt',
|
||||||
|
help='Path to cacert file that can be used to send https '
|
||||||
|
'request from the undercloud'),
|
||||||
|
|
||||||
|
# TODO(slaweq): those options may be also applicable for edpm nodes so
|
||||||
|
# maybe we will need to rename them to use in both topologies
|
||||||
|
# Overcloud options
|
||||||
|
cfg.IntOpt('overcloud_ssh_port',
|
||||||
|
default=None,
|
||||||
|
help="TCP port of SSH server on overcloud hosts"),
|
||||||
|
cfg.StrOpt('overcloud_ssh_username',
|
||||||
|
default=None,
|
||||||
|
help="Default username used to connect to overcloud nodes"),
|
||||||
|
cfg.StrOpt('overcloud_ssh_key_filename',
|
||||||
|
default='~/.ssh/id_overcloud',
|
||||||
|
help="SSH key filename used to login to Overcloud nodes"),
|
||||||
|
cfg.ListOpt('overcloud_rcfile',
|
||||||
|
default=['~/overcloudrc', '~/qe-Cloud-0rc'],
|
||||||
|
help="Overcloud RC filenames"),
|
||||||
|
cfg.StrOpt('overcloud_cloud_name',
|
||||||
|
default='overcloud',
|
||||||
|
help='overcloud cloud name to be used for loading credentials '
|
||||||
|
'from the overcloud clouds files'),
|
||||||
|
cfg.IntOpt('overcloud_ip_version',
|
||||||
|
help=("Default IP address version to be used to connect to "
|
||||||
|
"overcloud nodes ")),
|
||||||
|
cfg.StrOpt('overcloud_network_name',
|
||||||
|
help="Name of network used to connect to overcloud nodes"),
|
||||||
|
cfg.DictOpt('overcloud_groups_dict',
|
||||||
|
help='Dictionary with the node groups corresponding to '
|
||||||
|
'different hostname prefixes',
|
||||||
|
default={'ctrl': 'controller', 'cmp': 'compute'}),
|
||||||
|
|
||||||
|
# NOTE(slaweq): same here
|
||||||
|
# Other options
|
||||||
|
cfg.StrOpt('inventory_file',
|
||||||
|
default='.ansible/inventory/tripleo.yaml',
|
||||||
|
help="path to where to export tripleo inventory file"),
|
||||||
|
|
||||||
|
cfg.BoolOpt('has_external_load_balancer',
|
||||||
|
default=False,
|
||||||
|
help="OSP env was done with an external load balancer"),
|
||||||
|
|
||||||
|
cfg.BoolOpt('ceph_rgw',
|
||||||
|
default=False,
|
||||||
|
help="whether Ceph RGW is deployed"),
|
||||||
|
]
|
||||||
|
|
||||||
|
PODIFIED_GROUP_NAME = "podified"
|
||||||
|
PODIFIED_OPTIONS = [
|
||||||
|
cfg.StrOpt('edpm_ssh_key_filename',
|
||||||
|
default='~/.ssh/id_podified_edpm',
|
||||||
|
help="SSH key filename used to login to EDPM nodes"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def register_tobiko_options(conf):
|
||||||
|
conf.register_opts(group=cfg.OptGroup(TRIPLEO_GROUP_NAME),
|
||||||
|
opts=TRIPLEO_OPTIONS)
|
||||||
|
conf.register_opts(group=cfg.OptGroup(PODIFIED_GROUP_NAME),
|
||||||
|
opts=PODIFIED_OPTIONS)
|
||||||
|
|
||||||
|
|
||||||
|
def list_options():
|
||||||
|
return [(TRIPLEO_GROUP_NAME, itertools.chain(TRIPLEO_OPTIONS)),
|
||||||
|
(PODIFIED_GROUP_NAME, itertools.chain(PODIFIED_OPTIONS))]
|
@ -825,7 +825,7 @@ def test_controllers_shutdown():
|
|||||||
LOG.info("Ensure all controller nodes are running: "
|
LOG.info("Ensure all controller nodes are running: "
|
||||||
f"{all_node_names}")
|
f"{all_node_names}")
|
||||||
for node in all_nodes:
|
for node in all_nodes:
|
||||||
node.power_on_overcloud_node()
|
node.power_on_node()
|
||||||
topology.assert_reachable_nodes(all_nodes)
|
topology.assert_reachable_nodes(all_nodes)
|
||||||
|
|
||||||
LOG.debug('Check VM is running while all controllers nodes are on')
|
LOG.debug('Check VM is running while all controllers nodes are on')
|
||||||
@ -840,8 +840,8 @@ def test_controllers_shutdown():
|
|||||||
LOG.info(f"Power off {quorum_level} random controller nodes: "
|
LOG.info(f"Power off {quorum_level} random controller nodes: "
|
||||||
f"{node_names}")
|
f"{node_names}")
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
node.power_off_overcloud_node()
|
node.power_off_node()
|
||||||
test_case.addCleanup(node.power_on_overcloud_node)
|
test_case.addCleanup(node.power_on_node)
|
||||||
topology.assert_unreachable_nodes(nodes, retry_count=1)
|
topology.assert_unreachable_nodes(nodes, retry_count=1)
|
||||||
topology.assert_reachable_nodes(node
|
topology.assert_reachable_nodes(node
|
||||||
for node in all_nodes
|
for node in all_nodes
|
||||||
@ -860,7 +860,7 @@ def test_controllers_shutdown():
|
|||||||
random.shuffle(nodes)
|
random.shuffle(nodes)
|
||||||
LOG.info(f"Power on controller nodes: {node_names}")
|
LOG.info(f"Power on controller nodes: {node_names}")
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
node.power_on_overcloud_node()
|
node.power_on_node()
|
||||||
|
|
||||||
LOG.debug("Check all controller nodes are running again: "
|
LOG.debug("Check all controller nodes are running again: "
|
||||||
f"{all_node_names}")
|
f"{all_node_names}")
|
||||||
|
@ -90,7 +90,7 @@ class OctaviaBasicFaultTest(testtools.TestCase):
|
|||||||
LOG.debug('Rebooting compute node...')
|
LOG.debug('Rebooting compute node...')
|
||||||
|
|
||||||
# Reboot Amphora's compute node will initiate a failover
|
# Reboot Amphora's compute node will initiate a failover
|
||||||
amphora_compute_host.reboot_overcloud_node()
|
amphora_compute_host.reboot_node()
|
||||||
|
|
||||||
LOG.debug('Compute node has been rebooted')
|
LOG.debug('Compute node has been rebooted')
|
||||||
|
|
||||||
|
0
tobiko/tests/functional/podified/__init__.py
Normal file
0
tobiko/tests/functional/podified/__init__.py
Normal file
32
tobiko/tests/functional/podified/test_topology.py
Normal file
32
tobiko/tests/functional/podified/test_topology.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Copyright (c) 2023 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 tobiko
|
||||||
|
from tobiko.tests.functional.openstack import test_topology
|
||||||
|
from tobiko import podified
|
||||||
|
|
||||||
|
|
||||||
|
@podified.skip_if_not_podified
|
||||||
|
class PodifiedTopologyTest(test_topology.OpenStackTopologyTest):
|
||||||
|
|
||||||
|
@property
|
||||||
|
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.")
|
@ -15,7 +15,6 @@ 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
|
||||||
from tobiko.tripleo import containers
|
from tobiko.tripleo import containers
|
||||||
@ -56,9 +55,6 @@ get_overcloud_ssh_username = overcloud.get_overcloud_ssh_username
|
|||||||
skip_if_ceph_rgw = containers.skip_if_ceph_rgw
|
skip_if_ceph_rgw = containers.skip_if_ceph_rgw
|
||||||
get_container_runtime_name = containers.get_container_runtime_name
|
get_container_runtime_name = containers.get_container_runtime_name
|
||||||
|
|
||||||
get_rhosp_release = _rhosp.get_rhosp_release
|
|
||||||
get_rhosp_version = _rhosp.get_rhosp_version
|
|
||||||
|
|
||||||
TripleoTopology = topology.TripleoTopology
|
TripleoTopology = topology.TripleoTopology
|
||||||
|
|
||||||
UndercloudKeystoneCredentialsFixture = \
|
UndercloudKeystoneCredentialsFixture = \
|
||||||
|
@ -25,18 +25,18 @@ from tobiko import config
|
|||||||
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 import rhosp
|
||||||
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.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
|
||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TripleoTopology(topology.OpenStackTopology):
|
class TripleoTopology(rhosp.RhospTopology):
|
||||||
|
|
||||||
agent_to_service_name_mappings = {
|
agent_to_service_name_mappings = {
|
||||||
neutron.DHCP_AGENT: 'tripleo_neutron_dhcp',
|
neutron.DHCP_AGENT: 'tripleo_neutron_dhcp',
|
||||||
@ -63,8 +63,6 @@ class TripleoTopology(topology.OpenStackTopology):
|
|||||||
neutron.FRR: 'frr'
|
neutron.FRR: 'frr'
|
||||||
}
|
}
|
||||||
|
|
||||||
has_containers = True
|
|
||||||
|
|
||||||
config_file_mappings = {
|
config_file_mappings = {
|
||||||
'ml2_conf.ini': '/var/lib/config-data/puppet-generated/neutron'
|
'ml2_conf.ini': '/var/lib/config-data/puppet-generated/neutron'
|
||||||
'/etc/neutron/plugins/ml2/ml2_conf.ini',
|
'/etc/neutron/plugins/ml2/ml2_conf.ini',
|
||||||
@ -154,7 +152,7 @@ class TripleoTopology(topology.OpenStackTopology):
|
|||||||
return subgroups
|
return subgroups
|
||||||
|
|
||||||
|
|
||||||
class TripleoTopologyNode(topology.OpenStackTopologyNode):
|
class TripleoTopologyNode(rhosp.RhospNode):
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
topology: topology.OpenStackTopology,
|
topology: topology.OpenStackTopology,
|
||||||
@ -186,37 +184,6 @@ class TripleoTopologyNode(topology.OpenStackTopologyNode):
|
|||||||
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')
|
||||||
|
|
||||||
def reboot_overcloud_node(self,
|
|
||||||
reactivate_servers=True):
|
|
||||||
"""Reboot overcloud node
|
|
||||||
|
|
||||||
This method reboots an overcloud node and may start every Nova
|
|
||||||
server which is not in SHUTOFF status before restarting.
|
|
||||||
|
|
||||||
:param reactivate_servers: whether or not to re-start the servers which
|
|
||||||
are hosted on the compute node after the reboot
|
|
||||||
"""
|
|
||||||
|
|
||||||
running_servers: typing.List[nova.NovaServer] = []
|
|
||||||
if reactivate_servers:
|
|
||||||
running_servers = self.list_running_servers()
|
|
||||||
LOG.debug(f'Servers to restart after reboot: {running_servers}')
|
|
||||||
|
|
||||||
self.power_off_overcloud_node()
|
|
||||||
self.power_on_overcloud_node()
|
|
||||||
|
|
||||||
if running_servers:
|
|
||||||
LOG.info(f'Restart servers after rebooting overcloud compute node '
|
|
||||||
f'{self.name}...')
|
|
||||||
for server in running_servers:
|
|
||||||
nova.wait_for_server_status(server=server.id,
|
|
||||||
status='SHUTOFF')
|
|
||||||
LOG.debug(f'Re-activate server {server.name} with ID '
|
|
||||||
f'{server.id}')
|
|
||||||
nova.activate_server(server=server)
|
|
||||||
LOG.debug(f'Server {server.name} with ID {server.id} has '
|
|
||||||
f'been reactivated')
|
|
||||||
|
|
||||||
def list_running_servers(self) -> typing.List[nova.NovaServer]:
|
def list_running_servers(self) -> typing.List[nova.NovaServer]:
|
||||||
running_servers = list()
|
running_servers = list()
|
||||||
for server in nova.list_servers():
|
for server in nova.list_servers():
|
||||||
@ -227,7 +194,7 @@ class TripleoTopologyNode(topology.OpenStackTopologyNode):
|
|||||||
running_servers.append(server)
|
running_servers.append(server)
|
||||||
return running_servers
|
return running_servers
|
||||||
|
|
||||||
def power_on_overcloud_node(self):
|
def power_on_node(self):
|
||||||
if self.overcloud_instance is None:
|
if self.overcloud_instance is None:
|
||||||
raise TypeError(f"Node {self.name} is not and Overcloud server")
|
raise TypeError(f"Node {self.name} is not and Overcloud server")
|
||||||
self.ssh_client.close()
|
self.ssh_client.close()
|
||||||
@ -237,7 +204,7 @@ class TripleoTopologyNode(topology.OpenStackTopologyNode):
|
|||||||
LOG.debug(f"Overcloud node {self.name} power is on ("
|
LOG.debug(f"Overcloud node {self.name} power is on ("
|
||||||
f"hostname={hostname})")
|
f"hostname={hostname})")
|
||||||
|
|
||||||
def power_off_overcloud_node(self):
|
def power_off_node(self):
|
||||||
if self.overcloud_instance is None:
|
if self.overcloud_instance is None:
|
||||||
raise TypeError(f"Node {self.name} is not and Overcloud server")
|
raise TypeError(f"Node {self.name} is not and Overcloud server")
|
||||||
self.ssh_client.close()
|
self.ssh_client.close()
|
||||||
@ -245,9 +212,6 @@ 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:
|
||||||
|
@ -23,9 +23,9 @@ from oslo_log import log
|
|||||||
import tobiko
|
import tobiko
|
||||||
from tobiko import config
|
from tobiko import config
|
||||||
from tobiko.openstack import keystone
|
from tobiko.openstack import keystone
|
||||||
|
from tobiko import rhosp
|
||||||
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
|
||||||
@ -218,7 +218,7 @@ def undercloud_keystone_credentials() -> keystone.KeystoneCredentialsFixture:
|
|||||||
@functools.lru_cache()
|
@functools.lru_cache()
|
||||||
def undercloud_version() -> tobiko.Version:
|
def undercloud_version() -> tobiko.Version:
|
||||||
ssh_client = undercloud_ssh_client()
|
ssh_client = undercloud_ssh_client()
|
||||||
return _rhosp.get_rhosp_version(connection=ssh_client)
|
return rhosp.get_rhosp_version(connection=ssh_client)
|
||||||
|
|
||||||
|
|
||||||
def check_undercloud(min_version: tobiko.Version = None,
|
def check_undercloud(min_version: tobiko.Version = None,
|
||||||
|
@ -13,89 +13,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import itertools
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
|
|
||||||
|
|
||||||
GROUP_NAME = 'tripleo'
|
|
||||||
OPTIONS = [
|
|
||||||
# Undercloud options
|
|
||||||
cfg.StrOpt('undercloud_ssh_hostname',
|
|
||||||
default='undercloud-0',
|
|
||||||
help="hostname or IP address to be used to connect to "
|
|
||||||
"undercloud host"),
|
|
||||||
cfg.IntOpt('undercloud_ssh_port',
|
|
||||||
default=None,
|
|
||||||
help="TCP port of SSH server on undercloud host"),
|
|
||||||
cfg.StrOpt('undercloud_ssh_username',
|
|
||||||
default='stack',
|
|
||||||
help="Username with access to stackrc and overcloudrc files"),
|
|
||||||
cfg.StrOpt('undercloud_ssh_key_filename',
|
|
||||||
default=None,
|
|
||||||
help="SSH key filename used to login to Undercloud node"),
|
|
||||||
cfg.ListOpt('undercloud_rcfile',
|
|
||||||
default=['~/stackrc'],
|
|
||||||
help="Undercloud RC filename"),
|
|
||||||
cfg.StrOpt('undercloud_cloud_name',
|
|
||||||
default='undercloud',
|
|
||||||
help='undercloud cloud name to be used for loading credentials '
|
|
||||||
'from the undercloud clouds files'),
|
|
||||||
cfg.StrOpt('undercloud_cacert_file',
|
|
||||||
default='/etc/pki/tls/certs/ca-bundle.trust.crt',
|
|
||||||
help='Path to cacert file that can be used to send https '
|
|
||||||
'request from the undercloud'),
|
|
||||||
|
|
||||||
|
|
||||||
# Overcloud options
|
|
||||||
cfg.IntOpt('overcloud_ssh_port',
|
|
||||||
default=None,
|
|
||||||
help="TCP port of SSH server on overcloud hosts"),
|
|
||||||
cfg.StrOpt('overcloud_ssh_username',
|
|
||||||
default=None,
|
|
||||||
help="Default username used to connect to overcloud nodes"),
|
|
||||||
cfg.StrOpt('overcloud_ssh_key_filename',
|
|
||||||
default='~/.ssh/id_overcloud',
|
|
||||||
help="SSH key filename used to login to Overcloud nodes"),
|
|
||||||
cfg.ListOpt('overcloud_rcfile',
|
|
||||||
default=['~/overcloudrc', '~/qe-Cloud-0rc'],
|
|
||||||
help="Overcloud RC filenames"),
|
|
||||||
cfg.StrOpt('overcloud_cloud_name',
|
|
||||||
default='overcloud',
|
|
||||||
help='overcloud cloud name to be used for loading credentials '
|
|
||||||
'from the overcloud clouds files'),
|
|
||||||
cfg.IntOpt('overcloud_ip_version',
|
|
||||||
help=("Default IP address version to be used to connect to "
|
|
||||||
"overcloud nodes ")),
|
|
||||||
cfg.StrOpt('overcloud_network_name',
|
|
||||||
help="Name of network used to connect to overcloud nodes"),
|
|
||||||
cfg.DictOpt('overcloud_groups_dict',
|
|
||||||
help='Dictionary with the node groups corresponding to '
|
|
||||||
'different hostname prefixes',
|
|
||||||
default={'ctrl': 'controller', 'cmp': 'compute'}),
|
|
||||||
|
|
||||||
# Other options
|
|
||||||
cfg.StrOpt('inventory_file',
|
|
||||||
default='.ansible/inventory/tripleo.yaml',
|
|
||||||
help="path to where to export tripleo inventory file"),
|
|
||||||
|
|
||||||
cfg.BoolOpt('has_external_load_balancer',
|
|
||||||
default=False,
|
|
||||||
help="OSP env was done with an external load balancer"),
|
|
||||||
|
|
||||||
cfg.BoolOpt('ceph_rgw',
|
|
||||||
default=False,
|
|
||||||
help="whether Ceph RGW is deployed"),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def register_tobiko_options(conf):
|
|
||||||
conf.register_opts(group=cfg.OptGroup(GROUP_NAME), opts=OPTIONS)
|
|
||||||
|
|
||||||
|
|
||||||
def list_options():
|
|
||||||
return [(GROUP_NAME, itertools.chain(OPTIONS))]
|
|
||||||
|
|
||||||
|
|
||||||
def setup_tobiko_config(conf):
|
def setup_tobiko_config(conf):
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
|
Loading…
Reference in New Issue
Block a user