Implement background ping from the POD
This patch implements possibility to run tobiko commands from the POD. First command which can be run that way is `tobiko ping` which is used in the background ping test. Closes: #TOBIKO-100 Change-Id: I2c2d627aed18e6aa924b4afda7da3163363a4f11
This commit is contained in:
parent
5f9f85ad19
commit
40286134b8
@ -18,6 +18,7 @@ from oslo_log import log
|
|||||||
|
|
||||||
import tobiko
|
import tobiko
|
||||||
from tobiko import config
|
from tobiko import config
|
||||||
|
from tobiko.shell import ping
|
||||||
from tobiko.shell import sh
|
from tobiko.shell import sh
|
||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
@ -41,12 +42,23 @@ EDPM_OTHER_GROUP = 'edpm-other'
|
|||||||
|
|
||||||
_IS_OC_CLIENT_AVAILABLE = None
|
_IS_OC_CLIENT_AVAILABLE = None
|
||||||
_IS_BM_CRD_AVAILABLE = None
|
_IS_BM_CRD_AVAILABLE = None
|
||||||
|
_TOBIKO_PROJECT_EXISTS = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import openshift_client as oc
|
import openshift_client as oc
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
_IS_OC_CLIENT_AVAILABLE = False
|
_IS_OC_CLIENT_AVAILABLE = False
|
||||||
|
|
||||||
|
# NOTE(slaweq): This path is "hardcoded" in the tobiko.shell.ping._ping
|
||||||
|
# module currently so lets use it here like that as well. Maybe in the
|
||||||
|
# future there will be need to make it configurable but for now it is
|
||||||
|
# not needed.
|
||||||
|
PING_RESULTS_DIR = 'tobiko_ping_results'
|
||||||
|
# Also directory where results are stored inside the POD is hardcoded,
|
||||||
|
# It is in the $HOME/{PING_RESULTS_DIR}/ and $HOME inside the tobiko container
|
||||||
|
# is "/var/lib/tobiko"
|
||||||
|
POD_PING_RESULTS_DIR = f"/var/lib/tobiko/{PING_RESULTS_DIR}"
|
||||||
|
|
||||||
|
|
||||||
def _is_oc_client_available() -> bool:
|
def _is_oc_client_available() -> bool:
|
||||||
# pylint: disable=global-statement
|
# pylint: disable=global-statement
|
||||||
@ -268,3 +280,121 @@ def get_pod_count(labels=None):
|
|||||||
def delete_pods(labels=None):
|
def delete_pods(labels=None):
|
||||||
with oc.project(CONF.tobiko.podified.osp_project):
|
with oc.project(CONF.tobiko.podified.osp_project):
|
||||||
return oc.selector('pods', labels=labels).delete()
|
return oc.selector('pods', labels=labels).delete()
|
||||||
|
|
||||||
|
|
||||||
|
def _project_exists(name):
|
||||||
|
projects_selector = oc.selector(f"projects/{name}")
|
||||||
|
return not len(projects_selector.objects()) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_project_exists(name):
|
||||||
|
# pylint: disable=global-statement
|
||||||
|
global _TOBIKO_PROJECT_EXISTS
|
||||||
|
if not _TOBIKO_PROJECT_EXISTS and not _project_exists(name):
|
||||||
|
project_def = {
|
||||||
|
'apiVersion': 'v1',
|
||||||
|
'kind': 'Namespace',
|
||||||
|
'metadata': {
|
||||||
|
'name': name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oc.create(project_def)
|
||||||
|
_TOBIKO_PROJECT_EXISTS = True
|
||||||
|
|
||||||
|
|
||||||
|
def tobiko_project_context():
|
||||||
|
_ensure_project_exists(CONF.tobiko.podified.background_tasks_project)
|
||||||
|
return oc.project(CONF.tobiko.podified.background_tasks_project)
|
||||||
|
|
||||||
|
|
||||||
|
def check_or_start_tobiko_ping_command(server_ip):
|
||||||
|
cmd_args = ['ping', server_ip]
|
||||||
|
pod_name = f'tobiko-ping-{server_ip}'.replace('.', '-')
|
||||||
|
return check_or_start_tobiko_command(
|
||||||
|
cmd_args, pod_name, _check_ping_results)
|
||||||
|
|
||||||
|
|
||||||
|
def check_or_start_tobiko_command(cmd_args, pod_name, check_function):
|
||||||
|
pod_obj = _get_tobiko_command_pod(pod_name)
|
||||||
|
if pod_obj:
|
||||||
|
# in any case test is still running, check for failures:
|
||||||
|
# execute process check i.e. go over results file
|
||||||
|
# truncate the log file and restart the POD with background
|
||||||
|
# command
|
||||||
|
LOG.info('running a check function: '
|
||||||
|
f'on results of processes: {pod_name}')
|
||||||
|
check_function(pod_obj)
|
||||||
|
with tobiko_project_context():
|
||||||
|
pod_obj.delete(ignore_not_found=True)
|
||||||
|
LOG.info('checked and stopped previous tobiko command '
|
||||||
|
f'POD {pod_name}; starting a new POD.')
|
||||||
|
else:
|
||||||
|
# First time the test is run:
|
||||||
|
# if POD by specific name is not present start one:
|
||||||
|
LOG.info('No previous tobiko command POD found: '
|
||||||
|
f'{pod_name}, starting a new POD '
|
||||||
|
f'of function: {cmd_args}')
|
||||||
|
|
||||||
|
pod_obj = _start_tobiko_command_pod(cmd_args, pod_name)
|
||||||
|
# check test is not failing from the beginning
|
||||||
|
check_function(pod_obj)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_tobiko_command_pod(pod_name):
|
||||||
|
with tobiko_project_context():
|
||||||
|
pod_sel = oc.selector(f'pod/{pod_name}')
|
||||||
|
if len(pod_sel.objects()) > 1:
|
||||||
|
raise tobiko.MultipleObjectsFound(pod_sel.objects())
|
||||||
|
if not pod_sel.objects():
|
||||||
|
return
|
||||||
|
return pod_sel.objects()[0]
|
||||||
|
|
||||||
|
|
||||||
|
def _start_tobiko_command_pod(cmd_args, pod_name):
|
||||||
|
pod_def = {
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Pod",
|
||||||
|
"metadata": {
|
||||||
|
"name": pod_name,
|
||||||
|
"namespace": CONF.tobiko.podified.background_tasks_project
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [{
|
||||||
|
"name": pod_name,
|
||||||
|
"image": CONF.tobiko.podified.tobiko_image,
|
||||||
|
"command": ["tobiko"],
|
||||||
|
"args": cmd_args,
|
||||||
|
}],
|
||||||
|
"restartPolicy": "Never"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with tobiko_project_context():
|
||||||
|
pod_sel = oc.create(pod_def)
|
||||||
|
with oc.timeout(CONF.tobiko.podified.tobiko_start_pod_timeout):
|
||||||
|
success, pod_objs, _ = pod_sel.until_all(
|
||||||
|
success_func=lambda pod:
|
||||||
|
pod.as_dict()['status']['phase'] == 'Running'
|
||||||
|
)
|
||||||
|
if success:
|
||||||
|
return pod_objs[0]
|
||||||
|
|
||||||
|
|
||||||
|
def _check_ping_results(pod):
|
||||||
|
# NOTE(slaweq): we have to put ping log files in the directory
|
||||||
|
# as defined below because it is expected to be like that by the
|
||||||
|
# tobiko.shell.ping._ping module so we can use those existing
|
||||||
|
# functions to check results
|
||||||
|
ping_results_dest = f'{sh.get_user_home_dir()}/{PING_RESULTS_DIR}'
|
||||||
|
cp = oc.oc_action(
|
||||||
|
pod.context,
|
||||||
|
'cp',
|
||||||
|
[f"{pod.name()}:{POD_PING_RESULTS_DIR}", ping_results_dest]
|
||||||
|
)
|
||||||
|
if cp.status == 0:
|
||||||
|
ping.check_ping_statistics()
|
||||||
|
# here we should probably move those files inside the pod to some other
|
||||||
|
# location, or maybe simply delete them
|
||||||
|
else:
|
||||||
|
tobiko.fail("Failed to copy ping log files from the POD "
|
||||||
|
f"{pod.name()}. Error: {cp.err}")
|
||||||
|
@ -174,6 +174,11 @@ class PodifiedTopology(rhosp.RhospTopology):
|
|||||||
node_type=EDPM_NODE)
|
node_type=EDPM_NODE)
|
||||||
assert isinstance(node, EdpmNode)
|
assert isinstance(node, EdpmNode)
|
||||||
|
|
||||||
|
def check_or_start_background_vm_ping(self, server_ip):
|
||||||
|
_openshift.check_or_start_tobiko_ping_command(
|
||||||
|
server_ip=server_ip
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EdpmNode(rhosp.RhospNode):
|
class EdpmNode(rhosp.RhospNode):
|
||||||
|
|
||||||
|
@ -32,6 +32,23 @@ OPTIONS = [
|
|||||||
cfg.StrOpt('osp_project',
|
cfg.StrOpt('osp_project',
|
||||||
default='openstack',
|
default='openstack',
|
||||||
help="Openshift project that includes the Openstack resources"),
|
help="Openshift project that includes the Openstack resources"),
|
||||||
|
cfg.StrOpt('background_tasks_project',
|
||||||
|
default='tobiko',
|
||||||
|
help='Name of the OpenShift project which will be used to run '
|
||||||
|
'PODs with tobiko background commands, like e.g.'
|
||||||
|
'`tobiko ping`'),
|
||||||
|
cfg.StrOpt('tobiko_image',
|
||||||
|
default='quay.io/podified-antelope-centos9/openstack-tobiko:current-podified', # noqa
|
||||||
|
help='Contaniner image used to run background tobiko commands '
|
||||||
|
'like e.g. `tobiko ping` in the POD.'),
|
||||||
|
cfg.IntOpt('tobiko_start_pod_timeout',
|
||||||
|
default=60,
|
||||||
|
help='Defines how long Tobiko will wait until POD with the '
|
||||||
|
'background command (like tobiko ping) will be `Running`. '
|
||||||
|
'In most cases, if tobiko image is already in the local '
|
||||||
|
'registry it will need just few seconds to start POD but '
|
||||||
|
'if image is not yet cached locally it may take a bit '
|
||||||
|
'longer time to download it.'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user