2459832a02
Include: -added automated test case for k8s stx monitor -refactored cluster health check Story: 2007406 Task: 39010 Change-Id: Id1b1b7f71fb2a5c49aa2ee80a47fc20faa55d676 Author: Kristine Bujold <kristine.bujold@windriver.com> Co-Authored-By: Yvonne Ding <yvonne.ding@windriver.com> Signed-off-by: Yvonne Ding <yvonne.ding@windriver.com>
880 lines
27 KiB
Python
880 lines
27 KiB
Python
#
|
|
# Copyright (c) 2019, 2020 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
|
|
|
|
"""
|
|
Container/Application related helper functions for non-kubectl commands.
|
|
For example:
|
|
- docker commands
|
|
- system application-xxx commands
|
|
- helm commands
|
|
|
|
"""
|
|
|
|
import os
|
|
import time
|
|
import yaml
|
|
|
|
from utils import cli, exceptions, table_parser
|
|
from utils.tis_log import LOG
|
|
from utils.clients.ssh import ControllerClient
|
|
from consts.auth import Tenant
|
|
from consts.proj_vars import ProjVar
|
|
from consts.stx import AppStatus, Prompt, EventLogID, Container
|
|
from consts.filepaths import StxPath
|
|
from keywords import system_helper, host_helper
|
|
|
|
|
|
def exec_helm_upload_cmd(tarball, repo=None, timeout=120, con_ssh=None,
|
|
fail_ok=False):
|
|
if not con_ssh:
|
|
con_ssh = ControllerClient.get_active_controller()
|
|
|
|
if not repo:
|
|
repo = 'starlingx'
|
|
cmd = 'helm-upload {} {}'.format(repo, tarball)
|
|
con_ssh.send(cmd)
|
|
pw_prompt = Prompt.PASSWORD_PROMPT
|
|
prompts = [con_ssh.prompt, pw_prompt]
|
|
|
|
index = con_ssh.expect(prompts, timeout=timeout, searchwindowsize=100,
|
|
fail_ok=fail_ok)
|
|
if index == 1:
|
|
con_ssh.send(con_ssh.password)
|
|
prompts.remove(pw_prompt)
|
|
con_ssh.expect(prompts, timeout=timeout, searchwindowsize=100,
|
|
fail_ok=fail_ok)
|
|
|
|
code, output = con_ssh._process_exec_result(rm_date=True,
|
|
get_exit_code=True)
|
|
if code != 0 and not fail_ok:
|
|
raise exceptions.SSHExecCommandFailed(
|
|
"Non-zero return code for cmd: {}. Output: {}".
|
|
format(cmd, output))
|
|
|
|
return code, output
|
|
|
|
|
|
def exec_docker_cmd(sub_cmd, args, timeout=120, con_ssh=None, fail_ok=False):
|
|
if not con_ssh:
|
|
con_ssh = ControllerClient.get_active_controller()
|
|
|
|
cmd = 'docker {} {}'.format(sub_cmd, args)
|
|
code, output = con_ssh.exec_sudo_cmd(cmd, expect_timeout=timeout,
|
|
fail_ok=fail_ok)
|
|
|
|
return code, output
|
|
|
|
|
|
def upload_helm_charts(tar_file, repo=None, delete_first=False, con_ssh=None,
|
|
timeout=120, fail_ok=False):
|
|
"""
|
|
Upload helm charts via helm-upload cmd
|
|
Args:
|
|
tar_file:
|
|
repo
|
|
delete_first:
|
|
con_ssh:
|
|
timeout:
|
|
fail_ok:
|
|
|
|
Returns (tuple):
|
|
(0, <path_to_charts>)
|
|
(1, <std_err>)
|
|
(2, <hostname for host that does not have helm charts in expected dir>)
|
|
|
|
"""
|
|
if not con_ssh:
|
|
con_ssh = ControllerClient.get_active_controller()
|
|
|
|
helm_dir = os.path.normpath(StxPath.HELM_CHARTS_DIR)
|
|
if not repo:
|
|
repo = 'starlingx'
|
|
file_path = os.path.join(helm_dir, repo, os.path.basename(tar_file))
|
|
current_host = con_ssh.get_hostname()
|
|
controllers = [current_host]
|
|
if not system_helper.is_aio_simplex(con_ssh=con_ssh):
|
|
con_name = 'controller-1' if controllers[
|
|
0] == 'controller-0' else \
|
|
'controller-0'
|
|
controllers.append(con_name)
|
|
|
|
if delete_first:
|
|
for host in controllers:
|
|
with host_helper.ssh_to_host(hostname=host,
|
|
con_ssh=con_ssh) as host_ssh:
|
|
if host_ssh.file_exists(file_path):
|
|
host_ssh.exec_sudo_cmd('rm -f {}'.format(file_path))
|
|
|
|
code, output = exec_helm_upload_cmd(tarball=tar_file, repo=repo,
|
|
timeout=timeout, con_ssh=con_ssh,
|
|
fail_ok=fail_ok)
|
|
if code != 0:
|
|
return 1, output
|
|
|
|
file_exist = con_ssh.file_exists(file_path)
|
|
if not file_exist:
|
|
raise exceptions.ContainerError(
|
|
"{} not found on {} after helm-upload".format(file_path,
|
|
current_host))
|
|
|
|
LOG.info("Helm charts {} uploaded successfully".format(file_path))
|
|
return 0, file_path
|
|
|
|
|
|
def upload_app(tar_file, app_name=None, app_version=None, check_first=True,
|
|
fail_ok=False, uploaded_timeout=300,
|
|
con_ssh=None, auth_info=Tenant.get('admin_platform')):
|
|
"""
|
|
Upload an application via 'system application-upload'
|
|
Args:
|
|
app_name:
|
|
app_version:
|
|
tar_file:
|
|
check_first
|
|
fail_ok:
|
|
uploaded_timeout:
|
|
con_ssh:
|
|
auth_info:
|
|
|
|
Returns:
|
|
|
|
"""
|
|
if check_first and get_apps(application=app_name, con_ssh=con_ssh,
|
|
auth_info=auth_info):
|
|
msg = '{} already exists. Do nothing.'.format(app_name)
|
|
LOG.info(msg)
|
|
return -1, msg
|
|
|
|
args = ''
|
|
if app_name:
|
|
args += '-n {} '.format(app_name)
|
|
if app_version:
|
|
args += '-v {} '.format(app_version)
|
|
args = '{}{}'.format(args, tar_file)
|
|
code, output = cli.system('application-upload', args, ssh_client=con_ssh,
|
|
fail_ok=fail_ok, auth_info=auth_info)
|
|
|
|
if code > 0:
|
|
return 1, output
|
|
|
|
res = wait_for_apps_status(apps=app_name, status=AppStatus.UPLOADED,
|
|
timeout=uploaded_timeout,
|
|
con_ssh=con_ssh, auth_info=auth_info,
|
|
fail_ok=fail_ok)[0]
|
|
if not res:
|
|
return 2, "{} failed to upload".format(app_name)
|
|
|
|
msg = '{} uploaded successfully'.format(app_name)
|
|
LOG.info(msg)
|
|
return 0, msg
|
|
|
|
|
|
def get_apps(field='status', application=None, con_ssh=None,
|
|
auth_info=Tenant.get('admin_platform'),
|
|
rtn_dict=False, **kwargs):
|
|
"""
|
|
Get applications values for give apps and fields via system application-list
|
|
Args:
|
|
application (str|list|tuple):
|
|
field (str|list|tuple):
|
|
con_ssh:
|
|
auth_info:
|
|
rtn_dict:
|
|
**kwargs: extra filters other than application
|
|
|
|
Returns (list|dict):
|
|
list of list, or
|
|
dict with app name(str) as key and values(list) for given fields for
|
|
each app as value
|
|
|
|
"""
|
|
table_ = table_parser.table(
|
|
cli.system('application-list', ssh_client=con_ssh, auth_info=auth_info)[
|
|
1])
|
|
if application:
|
|
kwargs['application'] = application
|
|
|
|
return table_parser.get_multi_values(table_, fields=field,
|
|
rtn_dict=rtn_dict, zip_values=True,
|
|
**kwargs)
|
|
|
|
|
|
def get_app_values(app_name, fields, con_ssh=None,
|
|
auth_info=Tenant.get('admin_platform')):
|
|
"""
|
|
Get values from system application-show
|
|
Args:
|
|
app_name:
|
|
fields (str|list|tuple):
|
|
con_ssh:
|
|
auth_info:
|
|
|
|
Returns:
|
|
|
|
"""
|
|
if isinstance(fields, str):
|
|
fields = [fields]
|
|
|
|
table_ = table_parser.table(
|
|
cli.system('application-show', app_name, ssh_client=con_ssh,
|
|
auth_info=auth_info)[1],
|
|
combine_multiline_entry=True)
|
|
values = table_parser.get_multi_values_two_col_table(table_, fields=fields)
|
|
return values
|
|
|
|
|
|
def wait_for_apps_status(apps, status, timeout=360, check_interval=5,
|
|
fail_ok=False, con_ssh=None,
|
|
auth_info=Tenant.get('admin_platform')):
|
|
"""
|
|
Wait for applications to reach expected status via system application-list
|
|
Args:
|
|
apps:
|
|
status:
|
|
timeout:
|
|
check_interval:
|
|
fail_ok:
|
|
con_ssh:
|
|
auth_info:
|
|
|
|
Returns (tuple):
|
|
|
|
"""
|
|
status = '' if not status else status
|
|
if isinstance(apps, str):
|
|
apps = [apps]
|
|
apps_to_check = list(apps)
|
|
check_failed = []
|
|
end_time = time.time() + timeout
|
|
|
|
LOG.info(
|
|
"Wait for {} application(s) to reach status: {}".format(apps, status))
|
|
while time.time() < end_time:
|
|
apps_status = get_apps(application=apps_to_check,
|
|
field=('application', 'status'), con_ssh=con_ssh,
|
|
auth_info=auth_info)
|
|
apps_status = {item[0]: item[1] for item in apps_status if item}
|
|
|
|
checked = []
|
|
for app in apps_to_check:
|
|
current_app_status = apps_status.get(app, '')
|
|
if current_app_status == status:
|
|
checked.append(app)
|
|
elif current_app_status.endswith('ed'):
|
|
check_failed.append(app)
|
|
checked.append(app)
|
|
|
|
apps_to_check = list(set(apps_to_check) - set(checked))
|
|
if not apps_to_check:
|
|
if check_failed:
|
|
msg = '{} failed to reach status - {}'.format(check_failed,
|
|
status)
|
|
LOG.warning(msg)
|
|
if fail_ok:
|
|
return False, check_failed
|
|
else:
|
|
raise exceptions.ContainerError(msg)
|
|
|
|
LOG.info("{} reached expected status {}".format(apps, status))
|
|
return True, None
|
|
|
|
time.sleep(check_interval)
|
|
|
|
check_failed += apps_to_check
|
|
msg = '{} did not reach status {} within {}s'.format(check_failed, status,
|
|
timeout)
|
|
LOG.warning(msg)
|
|
if fail_ok:
|
|
return False, check_failed
|
|
raise exceptions.ContainerError(msg)
|
|
|
|
|
|
def apply_app(app_name, check_first=False, fail_ok=False, applied_timeout=300,
|
|
check_interval=10,
|
|
wait_for_alarm_gone=True, con_ssh=None,
|
|
auth_info=Tenant.get('admin_platform')):
|
|
"""
|
|
Apply/Re-apply application via system application-apply. Check for status
|
|
reaches 'applied'.
|
|
Args:
|
|
app_name (str):
|
|
check_first:
|
|
fail_ok:
|
|
applied_timeout:
|
|
check_interval:
|
|
con_ssh:
|
|
wait_for_alarm_gone (bool):
|
|
auth_info:
|
|
|
|
Returns (tuple):
|
|
(-1, "<app_name> is already applied. Do nothing.") # only returns
|
|
if check_first=True.
|
|
(0, "<app_name> (re)applied successfully")
|
|
(1, <std_err>) # cli rejected
|
|
(2, "<app_name> failed to apply") # did not reach applied status
|
|
after apply.
|
|
|
|
"""
|
|
if check_first:
|
|
app_status = get_apps(application=app_name, field='status',
|
|
con_ssh=con_ssh, auth_info=auth_info)
|
|
if app_status and app_status[0] == AppStatus.APPLIED:
|
|
msg = '{} is already applied. Do nothing.'.format(app_name)
|
|
LOG.info(msg)
|
|
return -1, msg
|
|
|
|
LOG.info("Apply application: {}".format(app_name))
|
|
code, output = cli.system('application-apply', app_name, ssh_client=con_ssh,
|
|
fail_ok=fail_ok, auth_info=auth_info)
|
|
if code > 0:
|
|
return 1, output
|
|
|
|
res = wait_for_apps_status(apps=app_name, status=AppStatus.APPLIED,
|
|
timeout=applied_timeout,
|
|
check_interval=check_interval, con_ssh=con_ssh,
|
|
auth_info=auth_info, fail_ok=fail_ok)[0]
|
|
if not res:
|
|
return 2, "{} failed to apply".format(app_name)
|
|
|
|
if wait_for_alarm_gone:
|
|
alarm_id = EventLogID.CONFIG_OUT_OF_DATE
|
|
if system_helper.wait_for_alarm(alarm_id=alarm_id,
|
|
entity_id='controller',
|
|
timeout=15, fail_ok=True,
|
|
auth_info=auth_info,
|
|
con_ssh=con_ssh)[0]:
|
|
system_helper.wait_for_alarm_gone(alarm_id=alarm_id,
|
|
entity_id='controller',
|
|
timeout=120,
|
|
check_interval=10,
|
|
con_ssh=con_ssh,
|
|
auth_info=auth_info)
|
|
|
|
msg = '{} (re)applied successfully'.format(app_name)
|
|
LOG.info(msg)
|
|
return 0, msg
|
|
|
|
|
|
def delete_app(app_name, check_first=True, fail_ok=False, applied_timeout=300,
|
|
con_ssh=None,
|
|
auth_info=Tenant.get('admin_platform')):
|
|
"""
|
|
Delete an application via system application-delete. Verify application
|
|
no longer listed.
|
|
Args:
|
|
app_name:
|
|
check_first:
|
|
fail_ok:
|
|
applied_timeout:
|
|
con_ssh:
|
|
auth_info:
|
|
|
|
Returns (tuple):
|
|
(-1, "<app_name> does not exist. Do nothing.")
|
|
(0, "<app_name> deleted successfully")
|
|
(1, <std_err>)
|
|
(2, "<app_name> failed to delete")
|
|
|
|
"""
|
|
|
|
if check_first:
|
|
app_vals = get_apps(application=app_name, field='status',
|
|
con_ssh=con_ssh, auth_info=auth_info)
|
|
if not app_vals:
|
|
msg = '{} does not exist. Do nothing.'.format(app_name)
|
|
LOG.info(msg)
|
|
return -1, msg
|
|
|
|
code, output = cli.system('application-delete', app_name,
|
|
ssh_client=con_ssh, fail_ok=fail_ok,
|
|
auth_info=auth_info)
|
|
if code > 0:
|
|
return 1, output
|
|
|
|
res = wait_for_apps_status(apps=app_name, status=None,
|
|
timeout=applied_timeout,
|
|
con_ssh=con_ssh, auth_info=auth_info,
|
|
fail_ok=fail_ok)[
|
|
0]
|
|
if not res:
|
|
return 2, "{} failed to delete".format(app_name)
|
|
|
|
msg = '{} deleted successfully'.format(app_name)
|
|
LOG.info(msg)
|
|
return 0, msg
|
|
|
|
|
|
def remove_app(app_name, check_first=True, fail_ok=False, applied_timeout=300,
|
|
con_ssh=None,
|
|
auth_info=Tenant.get('admin_platform')):
|
|
"""
|
|
Remove applied application via system application-remove. Verify it is in
|
|
'uploaded' status.
|
|
Args:
|
|
app_name (str):
|
|
check_first:
|
|
fail_ok:
|
|
applied_timeout:
|
|
con_ssh:
|
|
auth_info:
|
|
|
|
Returns (tuple):
|
|
(-1, "<app_name> is not applied. Do nothing.")
|
|
(0, "<app_name> removed successfully")
|
|
(1, <std_err>)
|
|
(2, "<app_name> failed to remove") # Did not reach uploaded status
|
|
|
|
"""
|
|
|
|
if check_first:
|
|
app_vals = get_apps(application=app_name, field='status',
|
|
con_ssh=con_ssh, auth_info=auth_info)
|
|
if not app_vals or app_vals[0] in (AppStatus.UPLOADED,
|
|
AppStatus.UPLOAD_FAILED):
|
|
msg = '{} is not applied. Do nothing.'.format(app_name)
|
|
LOG.info(msg)
|
|
return -1, msg
|
|
|
|
code, output = cli.system('application-remove', app_name,
|
|
ssh_client=con_ssh, fail_ok=fail_ok,
|
|
auth_info=auth_info)
|
|
if code > 0:
|
|
return 1, output
|
|
|
|
res = wait_for_apps_status(apps=app_name, status=AppStatus.UPLOADED,
|
|
timeout=applied_timeout,
|
|
con_ssh=con_ssh, auth_info=auth_info,
|
|
fail_ok=fail_ok)[0]
|
|
if not res:
|
|
return 2, "{} failed to remove".format(app_name)
|
|
|
|
msg = '{} removed successfully'.format(app_name)
|
|
LOG.info(msg)
|
|
return 0, msg
|
|
|
|
|
|
def get_docker_reg_addr(con_ssh=None):
|
|
"""
|
|
Get local docker registry ip address in docker conf file.
|
|
Args:
|
|
con_ssh:
|
|
|
|
Returns (str):
|
|
|
|
"""
|
|
if not con_ssh:
|
|
con_ssh = ControllerClient.get_active_controller()
|
|
|
|
output = con_ssh.exec_cmd(
|
|
'grep --color=never "addr: " {}'.format(StxPath.DOCKER_CONF),
|
|
fail_ok=False)[1]
|
|
reg_addr = output.split('addr: ')[1].strip()
|
|
return reg_addr
|
|
|
|
|
|
def pull_docker_image(name, tag=None, digest=None, con_ssh=None, timeout=300,
|
|
fail_ok=False):
|
|
"""
|
|
Pull docker image via docker image pull. Verify image is listed in docker
|
|
image list.
|
|
Args:
|
|
name:
|
|
tag:
|
|
digest:
|
|
con_ssh:
|
|
timeout:
|
|
fail_ok:
|
|
|
|
Returns (tuple):
|
|
(0, <docker image ID>)
|
|
(1, <std_err>)
|
|
|
|
"""
|
|
|
|
args = '{}'.format(name.strip())
|
|
if tag:
|
|
args += ':{}'.format(tag)
|
|
elif digest:
|
|
args += '@{}'.format(digest)
|
|
|
|
LOG.info("Pull docker image {}".format(args))
|
|
code, out = exec_docker_cmd('image pull', args, timeout=timeout,
|
|
fail_ok=fail_ok, con_ssh=con_ssh)
|
|
if code != 0:
|
|
return 1, out
|
|
|
|
image_id = get_docker_images(repo=name, tag=tag, field='IMAGE ID',
|
|
con_ssh=con_ssh, fail_ok=False)[0]
|
|
LOG.info(
|
|
'docker image {} successfully pulled. ID: {}'.format(args, image_id))
|
|
|
|
return 0, image_id
|
|
|
|
|
|
def login_to_docker(registry=None, user=None, password=None, con_ssh=None,
|
|
fail_ok=False):
|
|
"""
|
|
Login to docker registry
|
|
Args:
|
|
registry (str|None): default docker registry will be used when None
|
|
user (str|None): admin user will be used when None
|
|
password (str|None): admin password will be used when None
|
|
con_ssh (SSHClient|None):
|
|
fail_ok (bool):
|
|
|
|
Returns (tuple):
|
|
(0, <cmd_args>(str)) # login succeeded
|
|
(1, <std_err>(str)) # login failed
|
|
|
|
"""
|
|
if not user:
|
|
user = 'admin'
|
|
if not password:
|
|
password = Tenant.get('admin_platform').get('password')
|
|
if not registry:
|
|
registry = Container.LOCAL_DOCKER_REG
|
|
|
|
args = '-u {} -p {} {}'.format(user, password, registry)
|
|
LOG.info("Login to docker registry {}".format(registry))
|
|
code, out = exec_docker_cmd('login', args, timeout=60, fail_ok=fail_ok,
|
|
con_ssh=con_ssh)
|
|
if code != 0:
|
|
return 1, out
|
|
|
|
LOG.info('Logged into docker registry successfully: {}'.format(registry))
|
|
return 0, args
|
|
|
|
|
|
def push_docker_image(name, tag=None, login_registry=None, con_ssh=None,
|
|
timeout=300, fail_ok=False):
|
|
"""
|
|
Push docker image via docker image push.
|
|
Args:
|
|
name:
|
|
tag:
|
|
login_registry (str|None): when set, login to given docker registry
|
|
before push
|
|
con_ssh:
|
|
timeout:
|
|
fail_ok:
|
|
|
|
Returns (tuple):
|
|
(0, <args_used>)
|
|
(1, <std_err>)
|
|
|
|
"""
|
|
args = '{}'.format(name.strip())
|
|
if tag:
|
|
args += ':{}'.format(tag)
|
|
|
|
if login_registry:
|
|
login_to_docker(registry=login_registry, con_ssh=con_ssh)
|
|
|
|
LOG.info("Push docker image: {}".format(args))
|
|
code, out = exec_docker_cmd('image push', args, timeout=timeout,
|
|
fail_ok=fail_ok, con_ssh=con_ssh)
|
|
if code != 0:
|
|
return 1, out
|
|
|
|
LOG.info('docker image {} successfully pushed.'.format(args))
|
|
return 0, args
|
|
|
|
|
|
def tag_docker_image(source_image, target_name, source_tag=None,
|
|
target_tag=None, con_ssh=None, timeout=300,
|
|
fail_ok=False):
|
|
"""
|
|
Tag docker image via docker image tag. Verify image is tagged via docker
|
|
image list.
|
|
Args:
|
|
source_image:
|
|
target_name:
|
|
source_tag:
|
|
target_tag:
|
|
con_ssh:
|
|
timeout:
|
|
fail_ok:
|
|
|
|
Returns:
|
|
(0, <target_args>)
|
|
(1, <std_err>)
|
|
|
|
"""
|
|
source_args = source_image.strip()
|
|
if source_tag:
|
|
source_args += ':{}'.format(source_tag)
|
|
|
|
target_args = target_name.strip()
|
|
if target_tag:
|
|
target_args += ':{}'.format(target_tag)
|
|
|
|
LOG.info("Tag docker image {} as {}".format(source_args, target_args))
|
|
args = '{} {}'.format(source_args, target_args)
|
|
code, out = exec_docker_cmd('image tag', args, timeout=timeout,
|
|
fail_ok=fail_ok, con_ssh=con_ssh)
|
|
if code != 0:
|
|
return 1, out
|
|
|
|
if not get_docker_images(repo=target_name, tag=target_tag, con_ssh=con_ssh,
|
|
fail_ok=False):
|
|
raise exceptions.ContainerError(
|
|
"Docker image {} is not listed after tagging {}".format(
|
|
target_name, source_image))
|
|
|
|
LOG.info('docker image {} successfully tagged as {}.'.format(source_args,
|
|
target_args))
|
|
return 0, target_args
|
|
|
|
|
|
def remove_docker_images_with_pattern(pattern, con_ssh=None, timeout=300):
|
|
"""
|
|
Remove docker image(s) via docker image rm matching 'pattern'
|
|
Args:
|
|
pattern:
|
|
con_ssh:
|
|
timeout:
|
|
|
|
Returns (tuple):
|
|
(0, <std_out>)
|
|
(1, <std_err>)
|
|
|
|
"""
|
|
|
|
LOG.info("Remove docker images matching pattern: {}".format(pattern))
|
|
|
|
args = " | grep " + pattern + " | awk '{print $3}' "
|
|
code, out = exec_docker_cmd("images", args, timeout=timeout, fail_ok=True, con_ssh=con_ssh)
|
|
|
|
if out:
|
|
image_list = out.splitlines()
|
|
code, out = remove_docker_images(image_list, force=True, con_ssh=con_ssh)
|
|
|
|
return code, out
|
|
|
|
|
|
def remove_docker_images(images, force=False, con_ssh=None, timeout=300,
|
|
fail_ok=False):
|
|
"""
|
|
Remove docker image(s) via docker image rm
|
|
Args:
|
|
images (str|tuple|list):
|
|
force (bool):
|
|
con_ssh:
|
|
timeout:
|
|
fail_ok:
|
|
|
|
Returns (tuple):
|
|
(0, <std_out>)
|
|
(1, <std_err>)
|
|
|
|
"""
|
|
if isinstance(images, str):
|
|
images = (images,)
|
|
|
|
LOG.info("Remove docker images: {}".format(images))
|
|
args = ' '.join(images)
|
|
if force:
|
|
args = '--force {}'.format(args)
|
|
|
|
code, out = exec_docker_cmd('image rm', args, timeout=timeout,
|
|
fail_ok=fail_ok, con_ssh=con_ssh)
|
|
return code, out
|
|
|
|
|
|
def get_docker_images(repo=None, tag=None, field='IMAGE ID', con_ssh=None,
|
|
fail_ok=False):
|
|
"""
|
|
get values for given docker image via 'docker image ls <repo>'
|
|
Args:
|
|
repo (str):
|
|
tag (str|None):
|
|
field (str|tuple|list):
|
|
con_ssh:
|
|
fail_ok
|
|
|
|
Returns (list|None): return None if no docker images returned at all due
|
|
to cmd failure
|
|
|
|
"""
|
|
args = None
|
|
if repo:
|
|
args = repo
|
|
if tag:
|
|
args += ':{}'.format(tag)
|
|
code, output = exec_docker_cmd(sub_cmd='image ls', args=args,
|
|
fail_ok=fail_ok, con_ssh=con_ssh)
|
|
if code != 0:
|
|
return None
|
|
|
|
table_ = table_parser.table_kube(output)
|
|
if not table_['values']:
|
|
if fail_ok:
|
|
return None
|
|
else:
|
|
raise exceptions.ContainerError(
|
|
"docker image {} does not exist".format(args))
|
|
|
|
values = table_parser.get_multi_values(table_, fields=field,
|
|
zip_values=True)
|
|
|
|
return values
|
|
|
|
|
|
def get_helm_overrides(field='overrides namespaces', app_name='stx-openstack',
|
|
charts=None,
|
|
auth_info=Tenant.get('admin_platform'), con_ssh=None):
|
|
"""
|
|
Get helm overrides values via system helm-override-list
|
|
Args:
|
|
field (str):
|
|
app_name
|
|
charts (None|str|list|tuple):
|
|
auth_info:
|
|
con_ssh:
|
|
|
|
Returns (list):
|
|
|
|
"""
|
|
table_ = table_parser.table(
|
|
cli.system('helm-override-list', app_name, ssh_client=con_ssh,
|
|
auth_info=auth_info)[1])
|
|
|
|
if charts:
|
|
table_ = table_parser.filter_table(table_, **{'chart name': charts})
|
|
|
|
vals = table_parser.get_multi_values(table_, fields=field, evaluate=True)
|
|
|
|
return vals
|
|
|
|
|
|
def get_helm_override_values(chart, namespace, app_name='stx-openstack',
|
|
fields=('combined_overrides',),
|
|
auth_info=Tenant.get('admin_platform'),
|
|
con_ssh=None):
|
|
"""
|
|
Get helm-override values for given chart via system helm-override-show
|
|
Args:
|
|
chart (str):
|
|
namespace (str):
|
|
app_name (str)
|
|
fields (str|tuple|list):
|
|
auth_info:
|
|
con_ssh:
|
|
|
|
Returns (list): list of parsed yaml formatted output. e.g., list of dict,
|
|
list of list, list of str
|
|
|
|
"""
|
|
args = '{} {} {}'.format(app_name, chart, namespace)
|
|
table_ = table_parser.table(
|
|
cli.system('helm-override-show', args, ssh_client=con_ssh,
|
|
auth_info=auth_info)[1],
|
|
rstrip_value=True)
|
|
|
|
if isinstance(fields, str):
|
|
fields = (fields,)
|
|
|
|
values = []
|
|
for field in fields:
|
|
value = table_parser.get_value_two_col_table(table_, field=field,
|
|
merge_lines=False)
|
|
values.append(yaml.load('\n'.join(value)))
|
|
|
|
return values
|
|
|
|
|
|
def __convert_kv(k, v):
|
|
if '.' not in k:
|
|
return {k: v}
|
|
new_key, new_val = k.rsplit('.', maxsplit=1)
|
|
return __convert_kv(new_key, {new_val: v})
|
|
|
|
|
|
def update_helm_override(chart, namespace, app_name='stx-openstack',
|
|
yaml_file=None, kv_pairs=None,
|
|
reset_vals=False, reuse_vals=False,
|
|
auth_info=Tenant.get('admin_platform'),
|
|
con_ssh=None, fail_ok=False):
|
|
"""
|
|
Update helm_override values for given chart
|
|
Args:
|
|
chart:
|
|
namespace:
|
|
app_name
|
|
yaml_file:
|
|
kv_pairs:
|
|
reset_vals:
|
|
reuse_vals:
|
|
fail_ok
|
|
con_ssh
|
|
auth_info
|
|
|
|
Returns (tuple):
|
|
(0, <overrides>(str|list|dict)) # cmd accepted.
|
|
(1, <std_err>) # system helm-override-update cmd rejected
|
|
|
|
"""
|
|
args = '{} {} {}'.format(app_name, chart, namespace)
|
|
if reset_vals:
|
|
args = '--reset-values {}'.format(args)
|
|
if reuse_vals:
|
|
args = '--reuse-values {}'.format(args)
|
|
if yaml_file:
|
|
args = '--values {} {}'.format(yaml_file, args)
|
|
if kv_pairs:
|
|
cmd_overrides = ','.join(
|
|
['{}={}'.format(k, v) for k, v in kv_pairs.items()])
|
|
args = '--set {} {}'.format(cmd_overrides, args)
|
|
|
|
code, output = cli.system('helm-override-update', args, ssh_client=con_ssh,
|
|
fail_ok=fail_ok, auth_info=auth_info)
|
|
if code != 0:
|
|
return 1, output
|
|
|
|
table_ = table_parser.table(output, rstrip_value=True)
|
|
overrides = table_parser.get_value_two_col_table(table_, 'user_overrides')
|
|
overrides = yaml.load('\n'.join(overrides))
|
|
# yaml.load converts str to bool, int, float; but does not convert
|
|
# None type. Updates are not verified here since it is rather complicated
|
|
# to verify properly.
|
|
LOG.info("Helm-override updated : {}".format(overrides))
|
|
|
|
return 0, overrides
|
|
|
|
|
|
def is_stx_openstack_deployed(applied_only=False, con_ssh=None,
|
|
auth_info=Tenant.get('admin_platform'),
|
|
force_check=False):
|
|
"""
|
|
Whether stx-openstack application is deployed.
|
|
Args:
|
|
applied_only (bool): if True, then only return True when application
|
|
is in applied state
|
|
con_ssh:
|
|
auth_info:
|
|
force_check:
|
|
|
|
Returns (bool):
|
|
|
|
"""
|
|
openstack_deployed = ProjVar.get_var('OPENSTACK_DEPLOYED')
|
|
if not applied_only and not force_check and openstack_deployed is not None:
|
|
return openstack_deployed
|
|
|
|
openstack_status = get_apps(application='stx-openstack', field='status',
|
|
con_ssh=con_ssh, auth_info=auth_info)
|
|
|
|
LOG.info("{}".format(openstack_status))
|
|
|
|
res = False
|
|
if openstack_status and 'appl' in openstack_status[0].lower():
|
|
res = True
|
|
if applied_only and openstack_status[0] != AppStatus.APPLIED:
|
|
res = False
|
|
|
|
return res
|