mirror of
https://opendev.org/openstack/heat.git
synced 2026-01-17 07:10:27 +00:00
As a result of fixing OSSA-2025-002, ec2tokens API in Keystone
now by default requires authentication.
The config section `[ec2authtoken]` is now expected to have
auth information for Heat to be able to use this API.
In multicloud configuration keystone auth credentials are
required for each cloud. These can be configured using the new clouds
option and the ``[ec2authtoken.{cloud}]`` sections.
NOTE:
Disables test_software_config.ParallelDeploymentsTest in
grenade. Should follow up to re-enable once fix has been
backported.
Related-Bug: #2119646
Change-Id: Ib41f76c1ba56005b6c4233424cca5768657a7686
Co-Authored-By: Adrian Jarvis <adrian.jarvis@catalystcloud.nz>
Co-Authored-By: Takashi Kajinami <kajinamit@oss.nttdata.com>
Signed-off-by: Pavlo Shchelokovskyy <shchelokovskyy@gmail.com>
386 lines
16 KiB
Bash
386 lines
16 KiB
Bash
#!/bin/bash
|
|
#
|
|
# lib/heat
|
|
# Install and start **Heat** service
|
|
|
|
# To enable, add the following to localrc
|
|
#
|
|
# ENABLED_SERVICES+=,heat,h-api,h-api-cfn,h-eng
|
|
|
|
# Dependencies:
|
|
# (none)
|
|
|
|
# stack.sh
|
|
# ---------
|
|
# - install_heatclient
|
|
# - install_heat
|
|
# - configure_heatclient
|
|
# - configure_heat
|
|
# - init_heat
|
|
# - start_heat
|
|
# - stop_heat
|
|
# - cleanup_heat
|
|
|
|
# Save trace setting
|
|
_XTRACE_HEAT=$(set +o | grep xtrace)
|
|
set +o xtrace
|
|
|
|
# Defaults
|
|
# --------
|
|
|
|
# set up default directories
|
|
GITDIR["python-heatclient"]=$DEST/python-heatclient
|
|
|
|
# python heat client library
|
|
GITREPO["python-heatclient"]=${HEATCLIENT_REPO:-${GIT_BASE}/openstack/python-heatclient.git}
|
|
GITBRANCH["python-heatclient"]=${HEATCLIENT_BRANCH:-master}
|
|
|
|
HEAT_DIR=$DEST/heat
|
|
|
|
HEAT_STANDALONE=$(trueorfalse False HEAT_STANDALONE)
|
|
HEAT_ENABLE_ADOPT_ABANDON=$(trueorfalse False HEAT_ENABLE_ADOPT_ABANDON)
|
|
HEAT_CONF_DIR=/etc/heat
|
|
HEAT_CONF=$HEAT_CONF_DIR/heat.conf
|
|
HEAT_ENV_DIR=$HEAT_CONF_DIR/environment.d
|
|
HEAT_TEMPLATES_DIR=$HEAT_CONF_DIR/templates
|
|
HEAT_API_HOST=${HEAT_API_HOST:-$SERVICE_HOST}
|
|
HEAT_API_CFN_HOST=${HEAT_API_CFN_HOST:-$SERVICE_HOST}
|
|
HEAT_SERVICE_USER=${HEAT_SERVICE_USER:-heat}
|
|
HEAT_TRUSTEE_USER=${HEAT_TRUSTEE_USER:-$HEAT_SERVICE_USER}
|
|
HEAT_TRUSTEE_PASSWORD=${HEAT_TRUSTEE_PASSWORD:-$SERVICE_PASSWORD}
|
|
HEAT_TRUSTEE_DOMAIN=${HEAT_TRUSTEE_DOMAIN:-default}
|
|
|
|
# Support entry points installation of console scripts
|
|
HEAT_BIN_DIR=$(get_python_exec_prefix)
|
|
HEAT_API_UWSGI_CONF=$HEAT_CONF_DIR/heat-api-uwsgi.ini
|
|
HEAT_CFN_API_UWSGI_CONF=$HEAT_CONF_DIR/heat-api-cfn-uwsgi.ini
|
|
HEAT_API_UWSGI=heat.wsgi.api:application
|
|
HEAT_CFN_API_UWSGI=heat.wsgi.cfn:application
|
|
|
|
# Flag to set the oslo_policy.enforce_scope and oslo_policy.enforce_new_defaults.
|
|
# This is used to disable the compute API policies scope and new defaults.
|
|
# By Default, it is True.
|
|
# For more detail: https://docs.openstack.org/oslo.policy/latest/configuration/index.html#oslo_policy.enforce_scope
|
|
HEAT_ENFORCE_SCOPE=$(trueorfalse True HEAT_ENFORCE_SCOPE)
|
|
|
|
# other default options
|
|
if [[ "$HEAT_STANDALONE" == "True" ]]; then
|
|
# for standalone, use defaults which require no service user
|
|
HEAT_STACK_DOMAIN=$(trueorfalse False HEAT_STACK_DOMAIN)
|
|
HEAT_DEFERRED_AUTH=${HEAT_DEFERRED_AUTH:-password}
|
|
if [[ ${HEAT_DEFERRED_AUTH} != "password" ]]; then
|
|
# Heat does not support keystone trusts when deployed in
|
|
# standalone mode
|
|
die $LINENO \
|
|
'HEAT_DEFERRED_AUTH can only be set to "password" when HEAT_STANDALONE is True.'
|
|
fi
|
|
else
|
|
HEAT_STACK_DOMAIN=$(trueorfalse True HEAT_STACK_DOMAIN)
|
|
HEAT_DEFERRED_AUTH=${HEAT_DEFERRED_AUTH:-}
|
|
fi
|
|
HEAT_PLUGIN_DIR=${HEAT_PLUGIN_DIR:-$DATA_DIR/heat/plugins}
|
|
ENABLE_HEAT_PLUGINS=${ENABLE_HEAT_PLUGINS:-}
|
|
HEAT_ENGINE_WORKERS=${HEAT_ENGINE_WORKERS:=$(( ($(nproc)/4)<2 ? 2 : ($(nproc)/4) ))}
|
|
|
|
# Functions
|
|
# ---------
|
|
|
|
# Test if any Heat services are enabled
|
|
# is_heat_enabled
|
|
function is_heat_enabled {
|
|
[[ ,${ENABLED_SERVICES} =~ ,"h-" ]] && return 0
|
|
return 1
|
|
}
|
|
|
|
# cleanup_heat() - Remove residual data files, anything left over from previous
|
|
# runs that a clean run would need to clean up
|
|
function cleanup_heat {
|
|
remove_uwsgi_config "$HEAT_API_UWSGI_CONF" "$HEAT_API_UWSGI"
|
|
remove_uwsgi_config "$HEAT_CFN_API_UWSGI_CONF" "$HEAT_CFN_API_UWSGI"
|
|
sudo rm -rf $HEAT_ENV_DIR
|
|
sudo rm -rf $HEAT_TEMPLATES_DIR
|
|
sudo rm -rf $HEAT_CONF_DIR
|
|
}
|
|
|
|
# configure_heat() - Set config files, create data dirs, etc
|
|
function configure_heat {
|
|
|
|
sudo install -d -o $STACK_USER $HEAT_CONF_DIR
|
|
# remove old config files
|
|
rm -f $HEAT_CONF_DIR/heat-*.conf
|
|
|
|
HEAT_API_PASTE_FILE=$HEAT_CONF_DIR/api-paste.ini
|
|
|
|
cp $HEAT_DIR/etc/heat/api-paste.ini $HEAT_API_PASTE_FILE
|
|
|
|
# common options
|
|
iniset_rpc_backend heat $HEAT_CONF
|
|
iniset $HEAT_CONF DEFAULT heat_metadata_server_url http://$HEAT_API_CFN_HOST/heat-api-cfn
|
|
iniset $HEAT_CONF DEFAULT heat_waitcondition_server_url http://$HEAT_API_CFN_HOST/heat-api-cfn/v1/waitcondition
|
|
|
|
iniset $HEAT_CONF database connection `database_connection_url heat`
|
|
# we are using a hardcoded auth_encryption_key as it has to be the same for
|
|
# multinode deployment.
|
|
iniset $HEAT_CONF DEFAULT auth_encryption_key "767c3ed056cbaa3b9dfedb8c6f825bf0"
|
|
|
|
iniset $HEAT_CONF DEFAULT region_name_for_services "$REGION_NAME"
|
|
|
|
# logging
|
|
iniset $HEAT_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
|
|
|
|
# reduce Heat engine workers
|
|
iniset $HEAT_CONF DEFAULT num_engine_workers "$HEAT_ENGINE_WORKERS"
|
|
|
|
# Format logging
|
|
setup_logging $HEAT_CONF
|
|
|
|
if [[ ! -z "$HEAT_DEFERRED_AUTH" ]]; then
|
|
iniset $HEAT_CONF DEFAULT deferred_auth_method $HEAT_DEFERRED_AUTH
|
|
fi
|
|
|
|
write_uwsgi_config "$HEAT_API_UWSGI_CONF" "$HEAT_API_UWSGI" "/heat-api" "" "heat-api"
|
|
# configure threads for h-api to avoid IO wait and messaging timeout. We use
|
|
# 'nproc/4' to calculate API workers, hence, 4 would be probably correct
|
|
# approximation.
|
|
iniset "$HEAT_API_UWSGI_CONF" uwsgi threads 4
|
|
write_uwsgi_config "$HEAT_CFN_API_UWSGI_CONF" "$HEAT_CFN_API_UWSGI" "/heat-api-cfn" "" "heat-api-cfn"
|
|
|
|
if [[ "$HEAT_STANDALONE" = "True" ]]; then
|
|
iniset $HEAT_CONF paste_deploy flavor standalone
|
|
iniset $HEAT_CONF clients_heat url "$SERVICE_PROTOCOL://$HEAT_API_HOST/heat-api/v1/%(tenant_id)s"
|
|
else
|
|
configure_keystone_authtoken_middleware $HEAT_CONF heat
|
|
configure_keystone_authtoken_middleware $HEAT_CONF heat ec2authtoken
|
|
fi
|
|
|
|
# If HEAT_DEFERRED_AUTH is unset or explicitly set to trusts, configure
|
|
# the section for the client plugin associated with the trustee
|
|
if [ -z "$HEAT_DEFERRED_AUTH" -o "trusts" == "$HEAT_DEFERRED_AUTH" ]; then
|
|
iniset $HEAT_CONF trustee auth_type password
|
|
iniset $HEAT_CONF trustee auth_url $KEYSTONE_AUTH_URI
|
|
iniset $HEAT_CONF trustee username $HEAT_TRUSTEE_USER
|
|
iniset $HEAT_CONF trustee password $HEAT_TRUSTEE_PASSWORD
|
|
iniset $HEAT_CONF trustee user_domain_id $HEAT_TRUSTEE_DOMAIN
|
|
fi
|
|
|
|
# clients_keystone
|
|
iniset $HEAT_CONF clients_keystone auth_uri $KEYSTONE_AUTH_URI
|
|
|
|
if is_service_enabled tls-proxy; then
|
|
iniset $HEAT_CONF clients_keystone ca_file $SSL_BUNDLE_FILE
|
|
iniset $HEAT_CONF clients_nova ca_file $SSL_BUNDLE_FILE
|
|
iniset $HEAT_CONF clients_cinder ca_file $SSL_BUNDLE_FILE
|
|
iniset $HEAT_CONF clients_neutron ca_file $SSL_BUNDLE_FILE
|
|
iniset $HEAT_CONF clients_glance ca_file $SSL_BUNDLE_FILE
|
|
iniset $HEAT_CONF clients_swift ca_file $SSL_BUNDLE_FILE
|
|
fi
|
|
|
|
if [[ "$HEAT_ENABLE_ADOPT_ABANDON" = "True" ]]; then
|
|
iniset $HEAT_CONF DEFAULT enable_stack_adopt true
|
|
iniset $HEAT_CONF DEFAULT enable_stack_abandon true
|
|
fi
|
|
|
|
iniset $HEAT_CONF cache enabled "True"
|
|
iniset $HEAT_CONF cache backend "dogpile.cache.memory"
|
|
|
|
if ! is_service_enabled c-bak; then
|
|
iniset $HEAT_CONF volumes backups_enabled false
|
|
fi
|
|
|
|
if [[ "$HEAT_ENFORCE_SCOPE" == True || "$ENFORCE_SCOPE" == True ]] ; then
|
|
iniset $HEAT_CONF oslo_policy enforce_scope true
|
|
iniset $HEAT_CONF oslo_policy enforce_new_defaults true
|
|
else
|
|
iniset $HEAT_CONF oslo_policy enforce_scope false
|
|
iniset $HEAT_CONF oslo_policy enforce_new_defaults false
|
|
fi
|
|
|
|
sudo install -d -o $STACK_USER $HEAT_ENV_DIR $HEAT_TEMPLATES_DIR
|
|
|
|
# copy the default environment
|
|
cp $HEAT_DIR/etc/heat/environment.d/* $HEAT_ENV_DIR/
|
|
|
|
# copy the default templates
|
|
cp $HEAT_DIR/etc/heat/templates/* $HEAT_TEMPLATES_DIR/
|
|
|
|
# Enable heat plugins.
|
|
# NOTE(nic): The symlink nonsense is necessary because when
|
|
# plugins are installed in "developer mode", the final component
|
|
# of their target directory is always "resources", which confuses
|
|
# Heat's plugin loader into believing that all plugins are named
|
|
# "resources", and therefore are all the same plugin; so it
|
|
# will only load one of them. Linking them all to a common
|
|
# location with unique names avoids that type of collision,
|
|
# while still allowing the plugins to be edited in-tree.
|
|
local err_count=0
|
|
|
|
if [[ -n "$ENABLE_HEAT_PLUGINS" ]]; then
|
|
mkdir -p $HEAT_PLUGIN_DIR
|
|
# Clean up cruft from any previous runs
|
|
rm -f $HEAT_PLUGIN_DIR/*
|
|
iniset $HEAT_CONF DEFAULT plugin_dirs $HEAT_PLUGIN_DIR
|
|
fi
|
|
|
|
for heat_plugin in $ENABLE_HEAT_PLUGINS; do
|
|
if [[ -d $HEAT_DIR/contrib/$heat_plugin ]]; then
|
|
setup_package $HEAT_DIR/contrib/$heat_plugin -e
|
|
ln -s $HEAT_DIR/contrib/$heat_plugin/$heat_plugin/resources $HEAT_PLUGIN_DIR/$heat_plugin
|
|
else
|
|
: # clear retval on the test so that we can roll up errors
|
|
err $LINENO "Requested Heat plugin(${heat_plugin}) not found."
|
|
err_count=$(($err_count + 1))
|
|
fi
|
|
done
|
|
[ $err_count -eq 0 ] || die $LINENO "$err_count of the requested Heat plugins could not be installed."
|
|
}
|
|
|
|
# init_heat() - Initialize database
|
|
function init_heat {
|
|
# recreate db only if one of the db services is enabled
|
|
if is_service_enabled $DATABASE_BACKENDS; then
|
|
# (re)create heat database
|
|
recreate_database heat
|
|
$HEAT_BIN_DIR/heat-manage db_sync
|
|
fi
|
|
}
|
|
|
|
|
|
# install_heatclient() - Collect source and prepare
|
|
function install_heatclient {
|
|
if use_library_from_git "python-heatclient"; then
|
|
git_clone_by_name "python-heatclient"
|
|
setup_dev_lib "python-heatclient"
|
|
sudo install -D -m 0644 -o $STACK_USER {${GITDIR["python-heatclient"]}/tools/,/etc/bash_completion.d/}heat.bash_completion
|
|
fi
|
|
}
|
|
|
|
# install_heat() - Collect source and prepare
|
|
function install_heat {
|
|
setup_develop $HEAT_DIR
|
|
if [[ "$GLOBAL_VENV" == "True" ]] ; then
|
|
# TODO(tkajinam): find a better solution for this
|
|
sudo ln -sf $HEAT_BIN_DIR/heat-manage /usr/local/bin
|
|
fi
|
|
}
|
|
|
|
# start_heat() - Start running processes, including screen
|
|
function start_heat {
|
|
run_process h-eng "$HEAT_BIN_DIR/heat-engine --config-file=$HEAT_CONF"
|
|
|
|
# If the site is not enabled then we are in a grenade scenario
|
|
run_process h-api "$(which uwsgi) --ini $HEAT_API_UWSGI_CONF" ""
|
|
run_process h-api-cfn "$(which uwsgi) --ini $HEAT_CFN_API_UWSGI_CONF" ""
|
|
}
|
|
|
|
# stop_heat() - Stop running processes
|
|
function stop_heat {
|
|
# Kill the screen windows
|
|
stop_process h-api
|
|
stop_process h-api-cfn
|
|
stop_process h-eng
|
|
}
|
|
|
|
# create_heat_accounts() - Set up common required heat accounts
|
|
function create_heat_accounts {
|
|
if [[ "$HEAT_STANDALONE" != "True" ]]; then
|
|
create_service_user "heat" "admin"
|
|
get_or_create_service "heat" "orchestration" "Heat Orchestration Service"
|
|
get_or_create_endpoint \
|
|
"orchestration" \
|
|
"$REGION_NAME" \
|
|
"$SERVICE_PROTOCOL://$HEAT_API_HOST/heat-api/v1/\$(project_id)s"
|
|
|
|
get_or_create_service "heat-cfn" "cloudformation" "Heat CloudFormation Service"
|
|
get_or_create_endpoint \
|
|
"cloudformation" \
|
|
"$REGION_NAME" \
|
|
"$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST/heat-api-cfn/v1"
|
|
|
|
# heat_stack_user role is for users created by Heat
|
|
get_or_create_role "heat_stack_user"
|
|
fi
|
|
|
|
if [[ "$HEAT_STACK_DOMAIN" == "True" ]]; then
|
|
# domain -> heat and user -> heat_domain_admin
|
|
domain_id=$(get_or_create_domain heat 'Owns users and projects created by heat')
|
|
iniset $HEAT_CONF DEFAULT stack_user_domain_id ${domain_id}
|
|
get_or_create_user heat_domain_admin $SERVICE_PASSWORD heat
|
|
get_or_add_user_domain_role admin heat_domain_admin heat
|
|
iniset $HEAT_CONF DEFAULT stack_domain_admin heat_domain_admin
|
|
iniset $HEAT_CONF DEFAULT stack_domain_admin_password $SERVICE_PASSWORD
|
|
fi
|
|
}
|
|
|
|
# configure_tempest_for_heat()
|
|
# NOTE (gmann): Configure all the Tempest setting for Heat service in
|
|
# this function.
|
|
function configure_tempest_for_heat {
|
|
# Skip SoftwareConfigIntegrationTest because it requires a custom image
|
|
SKIP_SCENARIO_TEST_LIST='SoftwareConfigIntegrationTest'
|
|
SKIP_SCENARIO_TEST_LIST+=',AodhAlarmTest'
|
|
# Skip CfnInitIntegrationTest as latest fedora images don't have heat-cfntools
|
|
SKIP_SCENARIO_TEST_LIST+=',CfnInitIntegrationTest'
|
|
iniset $TEMPEST_CONFIG heat_plugin skip_scenario_test_list $SKIP_SCENARIO_TEST_LIST
|
|
|
|
SKIP_FUNCTIONAL_TEST_LIST='NotificationTest'
|
|
iniset $TEMPEST_CONFIG heat_plugin skip_functional_test_list $SKIP_FUNCTIONAL_TEST_LIST
|
|
|
|
openstack flavor show m1.heat_int || openstack flavor create m1.heat_int --ram 1024 --vcpus 2 --disk 10
|
|
openstack flavor show m1.heat_micro || openstack flavor create m1.heat_micro --ram 128 --disk 1
|
|
|
|
export OS_CLOUD=devstack
|
|
openstack network show heat-net || openstack network create heat-net
|
|
openstack subnet show heat-subnet || openstack subnet create heat-subnet --network heat-net --subnet-range 10.0.5.0/24
|
|
openstack router add subnet router1 heat-subnet
|
|
|
|
# NOTE(ianw) OpenDev infra only keeps the latest two Fedora's
|
|
# around; prefer the mirror but allow fallback
|
|
if [[ -e /etc/ci/mirror_info.sh ]]; then
|
|
source /etc/ci/mirror_info.sh
|
|
fi
|
|
HEAT_TEST_FEDORA_IMAGE_UPSTREAM=https://download.fedoraproject.org/pub/fedora/linux
|
|
HEAT_TEST_FEDORA_IMAGE_UPSTREAM_ARCHIVE=https://download.fedoraproject.org/pub/archive/fedora/linux/
|
|
HEAT_TEST_FEDORA_IMAGE_PATH=releases/37/Cloud/x86_64/images/Fedora-Cloud-Base-37-1.7.x86_64.qcow2
|
|
if curl --location --output /dev/null --silent --head --fail "${NODEPOOL_FEDORA_MIRROR}/${HEAT_TEST_FEDORA_IMAGE_PATH}"; then
|
|
export HEAT_TEST_FEDORA_IMAGE="${NODEPOOL_FEDORA_MIRROR}/${HEAT_TEST_FEDORA_IMAGE_PATH}"
|
|
elif curl --location --output /dev/null --silent --head --fail "${HEAT_TEST_FEDORA_IMAGE_UPSTREAM}/${HEAT_TEST_FEDORA_IMAGE_PATH}"; then
|
|
export HEAT_TEST_FEDORA_IMAGE="${HEAT_TEST_FEDORA_IMAGE_UPSTREAM}/${HEAT_TEST_FEDORA_IMAGE_PATH}"
|
|
else
|
|
export HEAT_TEST_FEDORA_IMAGE="${HEAT_TEST_FEDORA_IMAGE_UPSTREAM_ARCHIVE}/${HEAT_TEST_FEDORA_IMAGE_PATH}"
|
|
fi
|
|
TOKEN=$(openstack token issue -c id -f value)
|
|
local image_exists=$( openstack image list | grep "Fedora-Cloud-Base-37-1.7.x86_64" )
|
|
if [[ -z $image_exists ]]; then
|
|
if is_service_enabled g-api; then
|
|
upload_image $HEAT_TEST_FEDORA_IMAGE $TOKEN
|
|
fi
|
|
fi
|
|
|
|
if is_service_enabled tls-proxy; then
|
|
iniset $TEMPEST_CONFIG heat_plugin ca_file $SSL_BUNDLE_FILE
|
|
fi
|
|
# add application credential and secret to support test multi-cloud
|
|
app_cred_id=$(openstack application credential show heat_multicloud || openstack application credential create heat_multicloud \
|
|
--secret secret --unrestricted -c id -f value)
|
|
export OS_CREDENTIAL_SECRET_ID=$(openstack secret store -n heat-multi-cloud-test-cred --payload \
|
|
'{"auth_type": "v3applicationcredential", "auth": {"auth_url": $OS_AUTH_URL, "application_credential_id": $app_cred_id, "application_credential_secret": "secret"}}'\
|
|
-c "Secret href" -f value)
|
|
source $TOP_DIR/openrc demo demo
|
|
iniset $TEMPEST_CONFIG heat_plugin username $OS_USERNAME
|
|
iniset $TEMPEST_CONFIG heat_plugin password $OS_PASSWORD
|
|
iniset $TEMPEST_CONFIG heat_plugin project_name $OS_PROJECT_NAME
|
|
iniset $TEMPEST_CONFIG heat_plugin auth_url $OS_AUTH_URL
|
|
iniset $TEMPEST_CONFIG heat_plugin user_domain_id $OS_USER_DOMAIN_ID
|
|
iniset $TEMPEST_CONFIG heat_plugin project_domain_id $OS_PROJECT_DOMAIN_ID
|
|
iniset $TEMPEST_CONFIG heat_plugin user_domain_name $OS_USER_DOMAIN_NAME
|
|
iniset $TEMPEST_CONFIG heat_plugin project_domain_name $OS_PROJECT_DOMAIN_NAME
|
|
iniset $TEMPEST_CONFIG heat_plugin region $OS_REGION_NAME
|
|
|
|
source $TOP_DIR/openrc admin admin
|
|
iniset $TEMPEST_CONFIG heat_plugin admin_username $OS_USERNAME
|
|
iniset $TEMPEST_CONFIG heat_plugin admin_password $OS_PASSWORD
|
|
export OS_CLOUD=devstack-admin
|
|
}
|
|
|
|
# Restore xtrace
|
|
$_XTRACE_HEAT
|