Merge "Add LDAP-related actions in application lifecycle"

This commit is contained in:
Zuul 2023-07-17 13:38:15 +00:00 committed by Gerrit Code Review
commit a98e6464f6
13 changed files with 609 additions and 89 deletions

View File

@ -107,3 +107,5 @@ CEPH_POOL_VOLUMES_CHUNK_SIZE = 512
CEPH_POOL_BACKUP_APP_NAME = 'cinder-backup' CEPH_POOL_BACKUP_APP_NAME = 'cinder-backup'
CEPH_POOL_BACKUP_CHUNK_SIZE = 256 CEPH_POOL_BACKUP_CHUNK_SIZE = 256
OPENSTACK_VOLUME_MOUNT_DIR = "/var/opt/openstack"

View File

@ -0,0 +1,185 @@
#
# Copyright (c) 2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# All Rights Reserved.
#
import subprocess
from typing import List
from oslo_log import log as logging
from sysinv.common import utils as cutils
LOG = logging.getLogger(__name__)
def check_group(group: str) -> bool:
"""Check if group exists.
:returns: bool -- Returns `True` if group exists.
Otherwise, returns `False`.
"""
# First, run `ldapsearch`.
cmd_p1 = [
"ldapsearch",
"-x",
"-b",
"ou=Group,dc=cgcs,dc=local",
f"(cn={group})",
]
p1 = subprocess.Popen(
cmd_p1, stdin=subprocess.PIPE, stdout=subprocess.PIPE
)
# Second, verify if the `ldapsearch` output contains the word `numEntries`.
# If it does, it means that the group exists.
cmd_p2 = ["grep", "numEntries"]
p2 = subprocess.Popen(cmd_p2, stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
p2.communicate()
if p2.returncode == 0:
return True
return False
def add_group(group: str) -> None:
"""Add group.
:param group: The group name.
"""
cmd = ["ldapaddgroup", group]
_, stderr = cutils.trycmd(*cmd, run_as_root=True)
if stderr:
LOG.warning(f"Failed to add group `{group}`: {stderr}")
def delete_group(group: str) -> None:
"""Delete group.
:param group: The group name.
"""
members = list_group_members(group)
for member in members:
delete_group_member(member, group)
cmd = ["ldapdeletegroup", group]
_, stderr = cutils.trycmd(*cmd, run_as_root=True)
if stderr:
LOG.warning(f"Failed to delete group `{group}`: {stderr}")
def check_group_member(member: str, group: str) -> bool:
"""Check if group member exists.
:param member: The member name.
:param group: The group name.
:returns: bool -- Returns `True` if group member exists.
Otherwise, returns `False`.
"""
# First, run `ldapsearch`.
cmd_p1 = [
"ldapsearch",
"-x",
"-b",
"ou=Group,dc=cgcs,dc=local",
f"(cn={group})",
]
p1 = subprocess.Popen(
cmd_p1, stdin=subprocess.PIPE, stdout=subprocess.PIPE
)
# Second, verify if the `ldapsearch` output contains the word `memberUid`.
# If it does, it means that the group not only exists, but also contains
# members.
cmd_p2 = ["grep", f"memberUid: {member}"]
p2 = subprocess.Popen(cmd_p2, stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
p2.communicate()
if p2.returncode == 0:
return True
return False
def add_group_member(member: str, group: str) -> None:
"""Add group member.
:param member: The member name.
:param group: The group name.
"""
cmd = ["ldapaddusertogroup", member, group]
_, stderr = cutils.trycmd(*cmd, run_as_root=True)
if stderr:
LOG.warning(
f"Failed to add user `{member}` to group `{group}`: {stderr}"
)
def delete_group_member(member: str, group: str) -> None:
"""Delete group member.
:param member: The member name.
:param group: The group name.
"""
cmd = ["ldapdeleteuserfromgroup", member, group]
_, stderr = cutils.trycmd(*cmd, run_as_root=True)
if stderr:
LOG.warning(
f"Failed to delete user `{member}` from group `{group}`: {stderr}"
)
def list_group_members(group: str) -> List[str]:
"""List group members.
:param group: The group name.
:returns: List[str] -- The list of members belonging to
the specified group.
"""
members = []
# First, run `ldapsearch`.
cmd_p1 = [
"ldapsearch",
"-x",
"-b",
"ou=Group,dc=cgcs,dc=local",
f"(cn={group})",
]
p1 = subprocess.Popen(
cmd_p1, stdin=subprocess.PIPE, stdout=subprocess.PIPE
)
# Second, verify if the `ldapsearch` output contains the word `memberUid`.
# If it does, it means that the group not only exists, but also contains
# members.
cmd_p2 = ["grep", "-Poh", "(?<=memberUid: )(.*)"]
p2 = subprocess.Popen(cmd_p2, stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
stdout, _ = p2.communicate()
if p2.returncode == 0:
for user in stdout.decode().split():
if user:
members.append(user)
return members

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021 Wind River Systems, Inc. # Copyright (c) 2023 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -18,6 +18,8 @@ from sysinv.helm import lifecycle_utils as lifecycle_utils
from sysinv.helm.lifecycle_constants import LifecycleConstants from sysinv.helm.lifecycle_constants import LifecycleConstants
from k8sapp_openstack import utils as app_utils from k8sapp_openstack import utils as app_utils
from k8sapp_openstack.common import constants as app_constants
from k8sapp_openstack.helpers import ldap
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -97,6 +99,8 @@ class OpenstackAppLifecycleOperator(base.AppLifecycleOperator):
""" """
hook_info[LifecycleConstants.EXTRA][self.WAS_APPLIED] = app.active hook_info[LifecycleConstants.EXTRA][self.WAS_APPLIED] = app.active
self._pre_apply_ldap_actions()
def post_apply(self, context, conductor_obj, app, hook_info): def post_apply(self, context, conductor_obj, app, hook_info):
""" Post apply actions """ Post apply actions
@ -156,6 +160,8 @@ class OpenstackAppLifecycleOperator(base.AppLifecycleOperator):
conductor_obj._update_vim_config(context) conductor_obj._update_vim_config(context)
conductor_obj._update_radosgw_config(context) conductor_obj._update_radosgw_config(context)
self._post_remove_ldap_actions()
def _delete_app_specific_resources_post_remove(self, app_op, app, hook_info): def _delete_app_specific_resources_post_remove(self, app_op, app, hook_info):
"""Delete application specific resources. """Delete application specific resources.
@ -291,3 +297,26 @@ class OpenstackAppLifecycleOperator(base.AppLifecycleOperator):
not installed. Otherwise, False. not installed. Otherwise, False.
""" """
return app_utils.https_enabled() and not app_utils.is_openstack_https_certificates_ready() return app_utils.https_enabled() and not app_utils.is_openstack_https_certificates_ready()
def _pre_apply_ldap_actions(self):
"""Perform pre apply LDAP-related actions."""
# Create `openstack` group.
has_group = ldap.check_group(app_constants.HELM_NS_OPENSTACK)
if not has_group:
ldap.add_group(app_constants.HELM_NS_OPENSTACK)
# Create the volume mount directory.
app_utils.create_openstack_volume_mount()
def _post_remove_ldap_actions(self):
"""Perform post remove LDAP-related actions."""
# Try to delete the volume mount directory.
# If successful, delete `openstack` group.
# Otherwise, do nothing.
deleted = app_utils.delete_openstack_volume_mount()
if deleted:
has_group = ldap.check_group(app_constants.HELM_NS_OPENSTACK)
if has_group:
ldap.delete_group(app_constants.HELM_NS_OPENSTACK)

View File

@ -1,12 +1,21 @@
# #
# Copyright (c) 2022 Wind River Systems, Inc. # Copyright (c) 2023 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
from pathlib import Path
import shutil
from oslo_log import log as logging
from sysinv.common import constants from sysinv.common import constants
from sysinv.common import utils as cutils
from sysinv.db import api as dbapi from sysinv.db import api as dbapi
from k8sapp_openstack.common import constants as app_constants
LOG = logging.getLogger(__name__)
def https_enabled(): def https_enabled():
db = dbapi.get_instance() db = dbapi.get_instance()
@ -47,3 +56,156 @@ def is_openstack_https_ready():
installed in the system. installed in the system.
""" """
return https_enabled() and is_openstack_https_certificates_ready() return https_enabled() and is_openstack_https_certificates_ready()
def change_file_group_ownership(
file: str,
group: str,
recursive: bool = False
) -> None:
"""Change file's group ownership.
:param file: The file path.
:param group: The group name.
:param recursive: bool -- The flag that indicates whether permissions
should be changed recursively or not.
"""
cmd = ["chgrp", group, file]
if recursive:
cmd.insert(1, "-R")
_, stderr = cutils.trycmd(*cmd, run_as_root=True)
if stderr:
LOG.warning(
f"Failed to change group ownership of `{file}` "
f"to `{group}`: {stderr}"
)
def change_file_owner(
file: str,
user: str = "",
group: str = "",
recursive: bool = False
) -> None:
"""Change file's owner (chown).
:param file: The file path.
:param user: The desired user.
:param group: The desired group.
:param recursive: bool -- The flag that indicates whether ownerships
should be changed recursively or not.
"""
ownership = ""
if user:
ownership += user
if group:
ownership += f":{group}"
if not ownership:
return
cmd = ["chown", ownership, file]
if recursive:
cmd.insert(1, "-R")
_, stderr = cutils.trycmd(*cmd, run_as_root=True)
if stderr:
LOG.warning(
f"Failed to change ownership of `{file}` "
f"to `{ownership}`: {stderr}"
)
def change_file_mode(
file: str,
mode: str,
recursive: bool = False
) -> None:
"""Change file's mode (chmod).
:param file: The file path.
:param mode: The desired mode.
:param recursive: bool -- The flag that indicates whether modes should be
changed recursively or not.
"""
cmd = ["chmod", mode, file]
if recursive:
cmd.insert(1, "-R")
_, stderr = cutils.trycmd(*cmd, run_as_root=True)
if stderr:
LOG.warning(
f"Failed to change mode of `{file}` to `{mode}`: {stderr}"
)
def create_openstack_volume_mount() -> None:
"""Create OpenStack volume mount directory."""
p = Path(app_constants.OPENSTACK_VOLUME_MOUNT_DIR)
p.mkdir(exist_ok=True)
# Change modes of the volume mount directory.
change_file_mode(
str(p),
mode="770",
recursive=True
)
# Change ownership of the volume mount directory.
change_file_owner(
str(p),
user="sysadmin",
group=app_constants.HELM_NS_OPENSTACK,
recursive=True
)
def delete_openstack_volume_mount() -> bool:
"""Delete OpenStack volume mount.
:returns: bool -- True, if volume mount directory was successfully deleted.
False, if otherwise.
"""
# Search for additional files that might have been created by users.
directories = [app_constants.OPENSTACK_VOLUME_MOUNT_DIR]
while directories:
p = Path(directories.pop(0))
for pathname in p.glob("*"):
if pathname.is_dir():
directories.append(str(pathname))
continue
else:
# Ignore files in the root directory.
if str(p) == app_constants.OPENSTACK_VOLUME_MOUNT_DIR:
continue
# If there is at least one file created by users outside the
# root directory, that is, in a user subdirectory, it means
# that we can't remove the volume mount directory.
LOG.warning(
f"Unable to delete OpenStack volume mount directory "
f"`{app_constants.OPENSTACK_VOLUME_MOUNT_DIR}`. "
f"There are one or more user files in subdirectories."
)
return False
shutil.rmtree(
app_constants.OPENSTACK_VOLUME_MOUNT_DIR, ignore_errors=True
)
return True

View File

@ -1,19 +1,20 @@
#!/bin/bash #!/bin/bash
#
# Copyright (c) 2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# Clears OpenStack service aliases.
#
{{/* SERVICES=(
Copyright (c) 2023 Wind River Systems, Inc.
SPDX-License-Identifier: Apache-2.0
*/}}
SERVICES="
openstack
nova
cinder cinder
glance glance
heat heat
" nova
openstack
)
for service in ${SERVICES}; do for service in "${SERVICES[@]}"; do
unalias "${service}" 2> /dev/null unalias "${service}" 2> /dev/null
done done

View File

@ -1,21 +1,68 @@
#!/bin/bash #!/bin/bash
#
{{/* # Copyright (c) 2023 Wind River Systems, Inc.
Copyright (c) 2023 Wind River Systems, Inc. #
# SPDX-License-Identifier: Apache-2.0
SPDX-License-Identifier: Apache-2.0 #
*/}} # Copies setup scripts to the volume mount directory and creates an openrc
# file for admin access to the OpenStack clients container.
#
set -ex set -ex
TMP_DIR=/tmp
OPENSTACK_DIR=/var/opt/openstack OPENSTACK_DIR=/var/opt/openstack
OPENSTACK_SCRIPTS=( OPENSTACK_SETUP_SCRIPTS=(
/tmp/clear-aliases.sh clear-aliases.sh
/tmp/setup-aliases.sh setup-aliases.sh
/tmp/wrapper.sh clients-wrapper.sh
local_openstackrc
) )
mkdir -p ${OPENSTACK_DIR}/sysadmin # Store ownership of the volume mount directory to use it later on other files.
cp ${OPENSTACK_SCRIPTS[@]} ${OPENSTACK_DIR} ownership=$(ls -nd "${OPENSTACK_DIR}" | awk '{print $3":"$4}')
chmod -R 755 ${OPENSTACK_DIR}
# Copy setup scripts to volume mount directory and adjust their mode/ownership
# to make them only usable by their corresponding owners and/or groups.
for setup_script in "${OPENSTACK_SETUP_SCRIPTS[@]}"; do
cp "${TMP_DIR}/${setup_script}" "${OPENSTACK_DIR}"
chmod 550 "${OPENSTACK_DIR}/${setup_script}"
chown "${ownership}" "${OPENSTACK_DIR}/${setup_script}"
done
# Create openrc file for admin access.
ADMIN_OPENRC="${OPENSTACK_DIR}/admin-openrc"
touch "${ADMIN_OPENRC}"
chmod 600 "${ADMIN_OPENRC}"
chown "${ownership}" "${ADMIN_OPENRC}"
cat << EOF >> "${ADMIN_OPENRC}"
source /etc/platform/openrc --no_credentials
if [[ "$?" -ne 0 ]]; then
return 1
fi
source "${OPENSTACK_DIR}/setup-aliases.sh"
if [[ "$?" -ne 0 ]]; then
return 1
fi
export OS_USERNAME={{ .Values.endpoints.identity.auth.admin.username }}
export OS_PASSWORD={{ .Values.endpoints.identity.auth.admin.password }}
export OS_AUTH_URL=\
{{ .Values.endpoints.identity.scheme.default }}://\
{{ .Values.endpoints.identity.name }}.openstack.svc.\
{{ .Values.endpoints.cluster_domain_suffix }}\
{{ .Values.endpoints.identity.path.default }}
export PS1='[\u@\h \W(keystone_\$OS_USERNAME)]\$ '
return 0
EOF

View File

@ -0,0 +1,69 @@
#!/bin/bash -i
#
# Copyright (c) 2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# OpenStack clients wrapper responsible for executing commands
# passed as arguments in a containerized environment.
#
OPENSTACK_DIR=/var/opt/openstack
OPENSTACK_VARIABLES=(
OS_AUTH_TYPE
OS_AUTH_URL
OS_CACERT
OS_IDENTITY_API_SERVICE
OS_INTERFACE
OS_PASSWORD
OS_PROJECT_DOMAIN_ID
OS_PROJECT_DOMAIN_NAME
OS_PROJECT_ID
OS_PROJECT_NAME
OS_REGION_NAME
OS_USERNAME
OS_USER_DOMAIN_NAME
)
if [[ -z "${KUBECONFIG}" ]]; then
KUBECONFIG=/etc/kubernetes/admin.conf
fi
ENV_ARGUMENTS=()
for variable in "${OPENSTACK_VARIABLES[@]}"; do
if [[ ! -z "$(printenv ${variable})" ]]; then
ENV_ARGUMENTS+=("${variable}=$(printenv ${variable})")
fi
done
CONTROLLER=$(echo "${PS1@P}" | grep -Po 'controller-\d+' | cut -d $'\n' -f 1)
if [[ -z "${CONTROLLER}" ]]; then
echo "OpenStack CLIs can only be accessed from a controller node."
exit 1
fi
POD=$(
kubectl --kubeconfig "${KUBECONFIG}" -n openstack get pods \
| grep -i "clients-${CONTROLLER}.*Running" | awk '{print $1}'
)
if [[ -z "${POD}" ]]; then
echo "Could not find \`clients\` pod in ${CONTROLLER}."
echo "Make sure the pod is running and try again."
exit 1
fi
if grep -q "^${USER}:" /etc/passwd; then
kubectl --kubeconfig "${KUBECONFIG}" -n openstack exec -it "${POD}" \
-c clients -- env ${ENV_ARGUMENTS[@]} /bin/bash -c "$*"
else
if [[ ! -d "${OPENSTACK_DIR}/${USER}" ]]; then
mkdir -p "${OPENSTACK_DIR}/${USER}"
chgrp -R openstack "${OPENSTACK_DIR}/${USER}"
fi
kubectl --kubeconfig "${KUBECONFIG}" -n openstack exec -it "${POD}" \
-c clients -- env ${ENV_ARGUMENTS[@]} /bin/bash -c "cd ${USER}; $*"
fi

View File

@ -0,0 +1,60 @@
#!/bin/bash
#
# Copyright (c) 2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# Creates and/or loads local file "~/$USER-openrc-openstack".
#
# Assumes the Keystone username is the same as the logged in username.
#
OPENSTACK_DIR=/var/opt/openstack
OPENSTACK_OPENRC=${HOME}/${USER}-openrc-openstack
# Check if local openrc file exists.
if [[ -e "${OPENSTACK_OPENRC}" ]]; then
# If it does, source it.
source "${OPENSTACK_OPENRC}"
return $?
fi
# Otherwise, create and source it.
read -s -p "Enter password for Keystone user \`${USER}\`: " password
touch "${OPENSTACK_OPENRC}"
chmod 600 "${OPENSTACK_OPENRC}"
cat << EOF >> "${OPENSTACK_OPENRC}"
source /etc/platform/openrc --no_credentials
if [[ "$?" -ne 0 ]]; then
return 1
fi
source "${OPENSTACK_DIR}/setup-aliases.sh"
if [[ "$?" -ne 0 ]]; then
return 1
fi
export OS_USERNAME="${USER}"
export OS_PASSWORD="${password}"
export OS_AUTH_URL=\
{{ .Values.endpoints.identity.scheme.default }}://\
{{ .Values.endpoints.identity.name }}.openstack.svc.\
{{ .Values.endpoints.cluster_domain_suffix }}\
{{ .Values.endpoints.identity.path.default }}
export PS1='[\u@\h \W(keystone_\$OS_USERNAME)]\$ '
return 0
EOF
echo
echo "Created file \`${OPENSTACK_OPENRC}\`."
source "${OPENSTACK_OPENRC}"
return $?

View File

@ -1,25 +1,29 @@
#!/bin/bash #!/bin/bash
#
{{/* # Copyright (c) 2023 Wind River Systems, Inc.
Copyright (c) 2023 Wind River Systems, Inc. #
# SPDX-License-Identifier: Apache-2.0
SPDX-License-Identifier: Apache-2.0 #
*/}} # Creates OpenStack service aliases.
#
# All aliases created redirect OpenStack commands to a wrapper script,
# which executes them in a containerized environment.
#
if [[ ${BASH_SOURCE} = '/'* ]]; then if [[ ${BASH_SOURCE} = '/'* ]]; then
PATH_TO_SCRIPT=$(dirname ${BASH_SOURCE}) PATH_TO_SCRIPT=$(dirname "${BASH_SOURCE}")
else else
PATH_TO_SCRIPT=$(pwd)/$(dirname ${BASH_SOURCE}) PATH_TO_SCRIPT=$(pwd)/$(dirname "${BASH_SOURCE}")
fi fi
SERVICES=" SERVICES=(
openstack
nova
cinder cinder
glance glance
heat heat
" nova
openstack
)
for service in ${SERVICES}; do for service in "${SERVICES[@]}"; do
alias "${service}"="${PATH_TO_SCRIPT}/wrapper.sh ${service}" alias "${service}"="${PATH_TO_SCRIPT}/clients-wrapper.sh ${service}"
done done

View File

@ -1,45 +0,0 @@
#!/bin/bash -i
{{/*
Copyright (c) 2023 Wind River Systems, Inc.
SPDX-License-Identifier: Apache-2.0
*/}}
OPENSTACK_VARIABLES="
OS_AUTH_TYPE
OS_AUTH_URL
OS_CACERT
OS_IDENTITY_API_SERVICE
OS_INTERFACE
OS_PASSWORD
OS_PROJECT_DOMAIN_ID
OS_PROJECT_DOMAIN_NAME
OS_PROJECT_ID
OS_PROJECT_NAME
OS_REGION_NAME
OS_USERNAME
OS_USER_DOMAIN_NAME
"
ENV_ARGUMENTS=()
for variable in ${OPENSTACK_VARIABLES}; do
if [[ ! -z "$(printenv ${variable})" ]]; then
ENV_ARGUMENTS+=("${variable}=$(printenv ${variable})")
fi
done
CONTROLLER=$(echo ${PS1@P} | grep -Po 'controller-\d+')
if [[ -z "${CONTROLLER}" ]]; then
echo "OpenStack CLIs can only be accessed from a controller node."
exit 1
fi
POD=$(kubectl -n openstack get pods | grep -i "clients-${CONTROLLER}.*Running" | awk '{print $1}')
if [[ -z "${POD}" ]]; then
echo "Could not find \`clients\` pod in ${CONTROLLER}."
echo "Make sure the pod is running and try again."
exit 1
fi
kubectl -n openstack exec -it ${POD} -c clients -- env ${ENV_ARGUMENTS[@]} $*

View File

@ -17,12 +17,14 @@ metadata:
data: data:
clients-init.sh: | clients-init.sh: |
{{ tuple "bin/_clients-init.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} {{ tuple "bin/_clients-init.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
clients-wrapper.sh: |
{{ tuple "bin/_clients-wrapper.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
clear-aliases.sh: | clear-aliases.sh: |
{{ tuple "bin/_clear-aliases.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} {{ tuple "bin/_clear-aliases.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
setup-aliases.sh: | setup-aliases.sh: |
{{ tuple "bin/_setup-aliases.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} {{ tuple "bin/_setup-aliases.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
wrapper.sh: | local_openstackrc: |
{{ tuple "bin/_wrapper.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} {{ tuple "bin/_local_openstackrc.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
{{- end }} {{- end }}
{{- end }} {{- end }}

View File

@ -53,6 +53,10 @@ spec:
mountPath: /tmp/clients-init.sh mountPath: /tmp/clients-init.sh
subPath: clients-init.sh subPath: clients-init.sh
readOnly: true readOnly: true
- name: clients-bin
mountPath: /tmp/clients-wrapper.sh
subPath: clients-wrapper.sh
readOnly: true
- name: clients-bin - name: clients-bin
mountPath: /tmp/clear-aliases.sh mountPath: /tmp/clear-aliases.sh
subPath: clear-aliases.sh subPath: clear-aliases.sh
@ -62,8 +66,8 @@ spec:
subPath: setup-aliases.sh subPath: setup-aliases.sh
readOnly: true readOnly: true
- name: clients-bin - name: clients-bin
mountPath: /tmp/wrapper.sh mountPath: /tmp/local_openstackrc
subPath: wrapper.sh subPath: local_openstackrc
readOnly: true readOnly: true
- name: host-var-opt - name: host-var-opt
mountPath: /var/opt mountPath: /var/opt